forked from pelya/commandergenius
-
Notifications
You must be signed in to change notification settings - Fork 0
/
readme.txt
546 lines (418 loc) · 30.6 KB
/
readme.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
About
=====
This is SDL 1.2 ported to Google Android (also bunch of other libs included).
Sources or patches of the individual games are in the directory project/jni/application.
It can also build an official SDL2 Android port, with a few features on top.
Installation
============
Install latest Android SDK and NDK from http://developer.android.com/index.html
Add NDK to your PATH env variable - you should be able to run commands 'ndk-build'.
it is recommended to install OpenJDK and its development files.
On RPM based distros they are usually called java-x.x.x-openjdk and java-x.x.x-openjdk-devel.
On Debian or Ubuntu you install them like this: sudo apt-get install openjdk-8-jdk ant
The application will run on Android 4.1 and above, but will use features from Android 9 if available.
The most supported environment for this port is Linux, MacOs should be okay too.
If you're developing under Windows, you will need to install some Linux environment,
such as Bash shell on Windows 10, or Portable Ubuntu, then install Linux toolchain on it.
https://msdn.microsoft.com/en-us/commandline/wsl/install_guide
https://sourceforge.net/projects/portableubuntu/
Cygwin is not supported by the NDK.
How to compile demo application
===============================
Launch commands
git submodule update --init --recursive
./build.sh ballfield
Or in separate steps
rm project/jni/application/src
ln -s ballfield project/jni/application/src
./changeAppSettings.sh
./build.sh
Then edit file build.sh if needed to add NDK dir to your PATH, then launch it.
It will compile a bunch of libs under project/libs/,
create Android package file project/bin/MainActivity-debug.apk,
and install it to your device or emulator, if you specify option -i or -r to build.sh.
Then you can test it by launching Ballfield icon from Android applications menu.
There are other applications inside project/jni/application directory,
some of them are referenced using Git submodule mechanism, you may download them using command
Some of them may be outdated and won't compile, some contain only patch file and no sources,
so you should check out Git logs before compiling a particular app, and checkout whole repo at that date:
gitk project/jni/application/<directory>
The game enforces horizontal screen orientation, you may slide-open your keyboard if you have it
and use it for additional keys - the device will just keep current screen orientation.
Recent Android phone models like HTC Evo have no keyboard at all, on-screen keyboard built into SDL
is available for such devices - it has joystick (which can be configured as arrow buttons or analog joystick),
and 6 configurable keys, full text input is toggled with 7-th key. Both user and application may redefine
button layout and returned keycodes, and also toggle full text input - see SDL_screenkeyboard.h.
Also you can read multitouch events and accelerometer events - they are passed as joystick events.
This port also supports GL ES + SDL combo - there is GLXGears demo app in project/jni/application/glxgears,
to compile it remove project/jni/application/src symlink and make new one pointing to glxgears, and run build.sh
Note that GL ES is NOT pure OpenGL - there are no glBegin() and glEnd() call and other widely used functions,
and generally it will take a lot of effort to port OpenGL application to GL ES.
SDL2
====
To use SDL2, specify LibSdlVersion=2 inside AndroidAppSettings.cfg.
SDL2 currently supports only these options from AndroidAppSettings.cfg:
AppName
AppFullName
AppVersionCode
AppVersionName
AppDataDownloadUrl
ResetSdlConfigForThisVersion
DeleteFilesOnUpgrade
MultiABI
CompiledLibraries
CustomBuildScript
AppCflags
AppCppflags
AppLdflags
AppOverlapsSystemHeaders
AppSubdirsBuild
AppBuildExclude
AppCmdline
SDL2 does not support overlay screen buttons, you will need to draw and handle touch controls inside your own code.
Note that the library names for SDL2 are uppercase: SDL2 SDL2_image SDL2_mixer SDL2_ttf,
whereass for SDL 1.2 library names are lowercase: sdl-1.2 sdl_image sdl_mixer sdl_ttf.
Other libraries like Boost and OpenSSL are fully supported when SDL2 is used.
SDL2 will not show download/unzip progess to the user, you can use https:// links inside AppDataDownloadUrl,
but it will appear that the app is frozen on first start.
By default, SDL2 does not lock screen orientation and cha switch between portrait and landscape,
to lock screen orientation, call this code before calling SDL_CreateWindow():
SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeRight LandscapeLeft");
SDL2 will generate additional mouse events for touchscreen and touch events for mouse, to disable this you need to call:
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
SDL2 will not terminate the app process and will not unload shared libraries when your main() / SDL_main() function returns,
when the app is launched again your main() will be called twice without clearing global and static variables.
To prevent this, call exit() or _exit() instead of returning from main().
SDL2 by default does not allow internet access in the AndroidManifest.xml, to fix this copy the patch file
to your app directory and run changeAppSettings.sh:
cp project/jni/application/supertux/project.diff cp project/jni/application/src/project.diff
SDL2 does not support notch or display cutout.
SDL_GetDisplayBounds() / SDL_GetDisplayUsableBounds() / SDL_GetDisplayMode() / SDL_GetCurrentDisplayMode()
will report the screen size including the cutout, however it's not possible to draw inside the cutout area,
so you should use the size returned by SDL_GetWindowSize() and by SDL_WINDOWEVENT_RESIZED event,
and you should use fullscreen window mode.
SDL2 does not support Back button. You will need to draw back or pause button inside your app code.
Licensing issues when using gradle
==================================
cd into android-sdk-linux/tools/bin and
./sdkmanager --licenses
if that does not work you need to update
./sdkmanager --update
Accept the license with 'y'. It might download additional stuff, yet not sure, why.
Retry with
./sdkmanager --licenses
If the system tells you that the licenses were accepted, but the build system tells otherwise, it might be looking at the wrong path.
Symlinking the licenses directory might solve your problem:
ln -s $ANDROID_HOME/licenses project
If every other method fails. launch Android Studio, import 'project' directory, and try to build it once.
How to compile your own application
===================================
You may find quick Android game porting manual at http://anddev.at.ua/src/porting_manual.txt
If you're porting existing app which uses SDL 1.2 please always use SW mode:
neither SDL_SetVideoMode() call nor SDL_CreateRGBSurface() etc functions shall contain SDL_HWSURFACE flags.
The BPP in SDL_SetVideoMode() shall be set to the same value you've specified in ChangeAppSettings.sh,
and audio format - to AUDIO_S8 or AUDIO_S16. Also bear in mind that 16-bit BPP is always faster than 24 or 32-bit,
even on good devices, because most GFX chips on Android do not have separate RAM, and use system RAM instead,
so with 16 bit color mode you'll get lesser memory copying operations.
The native Android 16-bit pixel format is RGB_565, even for OpenGL, not BGR_565 as all other OpenGL implementations have.
Colorkey surfaces and alpha surfaces are supported, SDL_RLEACCEL is not supported.
To compile your own app, put your app sources into project/jni/application dir (or create symlink to them),
and change symlink "src" to point to your app:
cp -r /path/to/my/app project/jni/application/myapp
or
ln -s /path/to/my/app project/jni/application/myapp
then
rm project/jni/application/src
ln -s myapp project/jni/application/src
(the second one should be relative link without slashes)
Also your main() function name should be redefined to SDL_main(), include SDL.h so it will be done automatically.
Then launch script ChangeAppSettings.sh - it will ask few questions and modify several file in the project -
there's no way around such external configure script, because Java does not support preprocessor,
and the Java code is a part of SDL lib, the application generally should not care about it.
You may take AndroidAppSettings.cfg file from some other application to get sane defaults,
you may launch ChangeAppSettings.sh with -a or -v parameter to skip questions altogether or to ask only version code.
The C++ files shall have .cpp extension to be compiled, rename them if necessary.
Also you have to create an icon image file at project/jni/application/src/icon.png, and you may create a file
project/jni/application/src/AndroidData/logo.png to be used as a splash screen image.
Then you may launch build.sh.
To compile C++ code, add "c++_shared" to CompiledLibraries inside AndroidAppSettings.cfg.
C++ RTTI and exceptions give very slight memory overhead, if you need them -
add "-frtti -fexceptions" to the AppCflags inside AndroidAppSettings.cfg
If you use autoconf/automake/configure scripts with setEnvironment.sh, you may write
env CXXFLAGS='-frtti -fexceptions' ../setEnvironment.sh ./configure
Application data may be bundled with app itself, or downloaded from the internet on the first run -
if you want to put app data inside .apk file - create a .zip archive and put it into the directory
project/jni/application/src/AndroidData (create it if it doesn't exist), then run ChangeAppSettings.sh
and specify the file name there. If the data files are more than 150 Mb then it's a good idea to put them
on public HTTP server - you may specify URL in AppDataDownloadUrl in AndroidAppSettings.cfg, also you may specify several files.
If you'll release new version of data files you should change download URL or data file name and update your app as well -
the app will re-download the data if URL does not match the saved URL from previous download.
AppDataDownloadUrl can have several URLs in the form "Description|URL|MirrorURL^Description2|URL2|MirrorURL2^..."
If you'll start Description with '!' symbol it will be enabled by default, '!!' will also hide the entry from the menu, so it cannot be disabled.
If the URL in in the form ':dir/file.dat:http://URL/' it will be downloaded as binary BLOB to the application dir and not unzipped.
If the URL does not contain 'http://' or 'https://', it is treated as file from 'project/jni/application/src/AndroidData' dir -
these files are put inside .apk package by the build system.
Android app bundles do not support .obb files, they use asset packs instead.
This app project includes one pre-configured install-time asset pack.
To put your data into asset pack, copy it to the directory AndroidData/assetpack
and run changeAppSettings.sh. The asset pack zip archive path will be returned by
getenv("ANDROID_ASSET_PACK_PATH"), this call will return NULL if the asset pack is not installed.
You can put "assetpack" keyword to AppDataDownloadUrl, the code will check
if the asset pack is installed and will not download the data from other URLs.
You can extract files from the asset pack the same way you extract files from the app assets.
AppDataDownloadUrl="!!Game data|assetpack|https://yourserver.xyz/gamedata.zip"
All devices have different screen resolutions, you may toggle automatic screen resizing
in ChangeAppSettings.sh and draw to virtual 640x480 screen - it will be HW accelerated
and will not impact performance. Automatic screen resizing does not work in SDL 1.3/2.0.
SDL_GetVideoInfo() or SDL_ListModes(NULL, 0)[0] will always return native screen resolution.
Also make sure that your HW textures are not wider than 1024 pixels, or it will fail to allocate such
texture on HTC G1, and other low-end devices. Software surfaces may be of any size of course.
If you want HW acceleration - just use OpenGL, that's the easiest and most cross-platform way,
however if you'll use on-screen keyboard (even the text input button) the OpenGL state will get
messed up after each frame - after each SDL_GL_SwapBuffers() you'll need to restore following GL state:
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glClientActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, your_texture_id);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glEnable(GL_BLEND);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnableClientState(GL_COLOR_ARRAY);
Previously I've got the code to save/restore OpenGL state, but it doens't work on every device -
you may wish to uncomment it inside file SDL_touchscreenkeyboard.c in functions beginDrawingTex() and endDrawingTex().
If you don't use on-screen keyboard you don't need to reinit OpenGL state - set following in AndroidAppSettings.cfg:
AppNeedsArrowKeys=n
AppNeedsTextInput=n
AppTouchscreenKeyboardKeysAmount=0
SDL 1.2 supports HW acceleration, however it has many limitations:
You should use 16-bit color depth.
You cannot blit SW surface to screen, it should be only HW surface.
You can use colorkey, per-surface alpha and per-pixel alpha with HW surfaces.
If you're using SDL 1.3 always use SDL_Texture, if you'll be using SDL_Surface or call SDL_SetVideoMode()
with SDL 1.3 it will automatically switch to SW mode.
Also the screen is always double-buffered, and after each SDL_Flip() there is garbage in pixel buffer,
so forget about dirty rects and partial screen updates - you have to re-render whole picture each frame.
Calling SDL_UpdateRects() just calls SDL_Flip() internally, updating the whole screen at once.
Single-buffer rendering might be possible with techniques like glFramebufferTexture2D(),
however it is not present on all devices, so I won't do that.
Basically your code should be like this for SDL 1.2 (also set SwVideoMode=n in AndroidAppSetings.cfg):
// ----- HW-accelerated video output for Android example
// Init HW-accelerated video
SDL_SetVideoMode( 640, 480, 16, SDL_DOUBLEBUF | SDL_HWSURFACE );
// Load graphics
SDL_Surface *sprite = IMG_Load( "sprite.png" );
SDL_Surface * hwSprite;
if( sprite->format->Amask )
{
// Surface contains per-pixel alpha, convert it to HW-accelerated format
hwSprite = SDL_DisplayFormatAlpha(sprite);
}
else
{
// Set pink color as transparent
SDL_SetColorKey( sprite, SDL_SRCCOLORKEY, SDL_MapRGB(sprite->format, 255, 0, 255) );
// Create HW-accelerated surface
hwSprite = SDL_DisplayFormat(sprite);
// Set per-surface alpha, if necessary
SDL_SetAlpha( hwSprite, SDL_SRCALPHA, 128 );
}
// Blit it in HW-accelerated way
SDL_BlitSurface(hwSprite, sourceRect, SDL_GetVideoSurface(), &targetRect);
// Render the resulting video frame to device screen
SDL_Flip(SDL_GetVideoSurface());
// Supported, but VERY slow (slower than blitting in SW mode)
SDL_BlitSurface(sprite, sourceRect, SDL_GetVideoSurface(), &targetRect);
// Supported, but VERY slow (use in cases where you need to take a screenshot)
SDL_BlitSurface(SDL_GetVideoSurface(), sourceRect, sprite, &targetRect);
// ----- End of example
To get HW acceleration in SDL 1.3/2.0 just follow the instructions on libsdl.org
If you'll add new libs - add them to project/jni/, copy Android.mk from existing lib, and
add libname to project/jni/<yourapp>/Android.mk
Also you'll need to move all include files to <libname>/include dir.
If lib contains "configure" script - go to lib dir and execute command "../launchConfigureLib.sh" - it will
launch "configure" with appropriate environment and will create the "config.h" file at least, though linking
will most probably fail because of ranlib - just edit Android.mk to compile lib sources and remove all tools and tests.
MIDI support can be emulated via SDL_mixer lib (it uses Timidity internally)- download file
http://www.libsdl.org/projects/mixer/timidity/timidity.tar.gz
unpack it and put "timidity" dir into your game data zipfile.
Or you may paste this URL directly as an optional download in ChangeAppSettings.sh:
MIDI music support (18 Mb)|http://sourceforge.net/projects/libsdl-android/files/timidity.zip/download
SDL by default listens to the Volume Up and Volume Down hardware keys, and sends them to the application,
instead of changing volume. Most users expect those keys to actually change volume, instead of performing some in-game action.
To make SDL ignore those keys, and let the Android framework handle them instead, set
RedefinedKeys="XXX YYY NO_REMAP NO_REMAP ZZZ BBB CCC" inside AndroidAppSettings.cfg, that is,
the third and fourth keycode should be a special value "NO_REMAP" instead of SDL keycode.
XXX, YYY and ZZZ are placeholders for SDL keycodes of other hardware keys -
XXX is sent when user touches the screen and app is not using mouse or multitouch,
YYY is for DPAD_CENTER/SEARCH keys, ZZZ is for MENU key, BBB is for BACK key, CCC is for CAMERA key.
The ARM architecture has some limitations which you have to be aware about -
if you'll access integer that's not 4-byte aligned you'll get garbage instead of correct value,
and it's processor-model specific - it may work on some devices and do not work on another ones -
you may wish to check your code in Android 1.6 emulator from time to time to catch such bugs.
char * p = 0x13; // Non-4 byte aligned pointer
int i = (int *) p; // We have garbage inside i now
memcpy( &i, p, sizeof(int) ); // The correct way to dereference a non-aligned pointer
This compiler flags will catch most obvious errors, you may add them to AppCflags var in settings:
-Wstrict-aliasing -Wcast-align -Wpointer-arith -Waddress
Also beware of the NDK - some system headers contain the code that triggers that warnings.
SDL supports AdMob advertisements, you need to set your publisher ID inside AndroidAppSettings.cfg,
see project test-advertisements for details.
Also you can hide or reposition your ad from C code, check out file SDL_android.h for details.
SDL reports several joysticks, which are used to pass accelerometer and multitouch events.
On-screen joystick events are sent as SDL_JOYAXISMOTION in event.jaxis.jalue, scaled from -32767 to 32767,
with event.jaxis.which == 0 and event.jaxis.axis from 0 to 1, you will need to set AppUsesJoystick=y
in AndroidAppSettings.cfg and call SDL_JoystickOpen(0) in your code.
If you specify AppUsesSecondJoystick=y in AndroidAppSettings.cfg, there will be second on-screen joystick,
it will send events with event.jaxis.which == 0 and event.jaxis.axis from 2 to 3.
Multitouch events are sent as SDL_JOYBALLMOTION in event.jball.xrel and event.jball.yrel, scaled to screen size,
with event.jball.which == 0 and e.jball.ball from 0 to 15, you will need to set AppUsesMultitouch=y
in AndroidAppSettings.cfg and call SDL_JoystickOpen(0). SDL_JOYBUTTONDOWN and SDL_JOYBUTTONUP events
are sent when the screen is touched or released, with e.jbutton.which == 0 and e.jbutton.button from 0 to 15.
Additionally, the touch pressure is sent as SDL_JOYAXISMOTION, scaled from 0 to 32767,
with event.jaxis.which == 0 and event.jaxis.axis from 4 to 19.
Accelerometer events are sent as SDL_JOYAXISMOTION, with event.jaxis.which == 1 and event.jaxis.axis from 0 to 1,
scaled from -32767 to 32767, denoting the device tilt angles from the horizontal.
Raw accelerometer events are sent with event.jaxis.axis from 5 to 7, with Earth gravity having a value 9800.
You will need to set AppUsesAccelerometer=y in AndroidAppSettings.cfg, and call SDL_JoystickOpen(1) in your code.
Gyroscope events are sent as SDL_JOYAXISMOTION, with event.jaxis.which == 1 and event.jaxis.axis from 2 to 4,
with value 32767 equal to 0.25 rad/s. Multiple events will be sent at once, if the device is rapidly rotated.
You will need to set AppUsesGyroscope=y in AndroidAppSettings.cfg to use it, and call SDL_JoystickOpen(1).
Gyroscope hardware is much more precise and less noisy than accelerometer, it is present on newer devices
starting from Galaxy S II, but older devices do no have it - it is emulated with accelerometer + compass.
SDL also supports gamepads - you can plug PS3/Xbox gamepad to almost any tablet, some devices have built-in gamepad.
Gamepad stick events are sent as SDL_JOYAXISMOTION, with event.jaxis.which from 2 to 5 and event.jaxis.axis from 0 to 3.
Gamepad analog L1/R1 buttons are sent as SDL_JOYAXISMOTION, with event.jaxis.which from 2 to 5 and event.jaxis.axis from 4 to 5.
The gamepad where any button was pressed becomes the first gamepad. Maximum 4 gamepads are supported.
Other gamepad buttons generate key events, which are taken from RedefinedKeysGamepad in AndroidAppSettings.cfg.
How to compile your own application using automake/configure scripts
====================================================================
There is limited support for "configure" scripts, I'm compiling scummvm and openttd this way,
though ./configure scripts tend to have stupid bugs in various places, and ranlib command never works.
You should enable custom build script in ChangeAppSettings.sh, and you should create script
AndroidBuild.sh and put it under project/jni/application/src dir. The AndroidBuild.sh script should
generate file project/jni/application/src/libapplication.so, which will be copied into .apk file by build system.
There is helper script project/jni/application/setEnvironment.sh which will set CFLAGS and LDFLAGS
for configure script and makefile, see AndroidBuild.sh in project/jni/application/scummvm dir for reference.
Signing your application
==========================================================
You can use scripts sign.sh and signBundle.sh to sign your app.
Set environment variables ANDROID_KEYSTORE_FILE and ANDROID_KEYSTORE_ALIAS
to your app signing certificate path and certificate alias,
and if you don't want the script asking you for a password, set variable
ANDROID_KEYSTORE_PASS_FILE to a file containing your certificate password.
If you are using app bundles, set envirnment variables
ANDROID_UPLOAD_KEYSTORE_FILE, ANDROID_UPLOAD_KEYSTORE_ALIAS, and ANDROID_UPLOAD_KEYSTORE_PASS_FILE
to your app bundle signing certificate in a similar way.
Android application sleep/resume support
========================================
Application may be put to background at any time, for example if user gets phone call onto the device.
The application will lose OpenGL context then, and has to re-create it when put to foreground.
The application is not allowed to do any GFX output without OpenGL context (or it will crash),
that's why SDL_Flip() call will block until we're re-acquired context.
The event SDL_ACTIVEEVENT with flag SDL_APPACTIVE will be sent when that happens,
also SDL_VIDEORESIZE event will be sent (the same behavior as in MacOsX SDL implementation).
If you're seeing black screen, and the video thread stucks, when your app is restored from background,
this may happen because you do not call SDL_Flip() when app is put to background.
If your app does not call SDL_Flip() at least once per second, you have to call it on SDL_APPACTIVE event.
If you're using OpenAL it will be paused automatically when your app goes to background.
If you're using pure SDL 1.2 API (with or without HW acceleration) you don't need to worry about anything -
the SDL itself will re-create GL textures and fill them with pixel data from existing SDL HW surfaces,
so you may leave the callbacks to defaults.
If you're using SDL 1.3 API and using SDL_Texture, then the textures pixeldata is lost - you will need
to call SDL_UpdateTexture() to refill texture pixeldata from appRestored() callback for all your textures.
If you're using compatibility API with SDL_Surfaces you don't have to worry about that.
If you're using SDL with OpenGL with either SDL 1.2 or SDL 1.3, the situation is even more grim -
not only all your GL textures are lost, but all GL matrices, blend modes, etc. has to be re-created.
OS may decide there's too little free RAM left on device, and kill background applications
without notice, so it vill be good to create temporary savegame etc. from appPutToBackground() callback.
Also it's a good practice to pause any application audio, especially if the user gets phone call,
and if you won't set your own callbacks the default callbacks will do exactly that.
There are circumstances when you want to avoid that, for example if the application is audio player,
or if application gets some notification over network (for example you're running a game server,
and want a beep when someone connects to you) - you may unpause audio for some short time,
that will require another thread to watch the network, because main thread will be blocked inside SDL_Flip().
The SDL provides function
SDL_ANDROID_SetApplicationPutToBackgroundCallback( callback_t appPutToBackground, callback_t appRestored );
where callback_t is function pointer of type "void (*) void".
The default callbacks will call another Android-specific functions:
SDL_ANDROID_PauseAudioPlayback() and SDL_ANDROID_ResumeAudioPlayback()
which will pause and resume audio from HW layer, so application does not need to destroy and re-init audio,
and in general you don't need to redefine those functions, unless you want to play audio in background.
The callbacks will be called from inside SDL_Flip().
The whole idea behind callbacks is that the existing application should not be modified to
operate correctly - the whole time in background will just look to app as one very long SDL_Flip(),
so it's good idea to implement some maximum time cap on game frame, so it won't process
the game to the end level 'till the app is in background, or calculate the difference in time
between appPutToBackground() and appRestored() and update game time variables.
Quick guide to debug native code
================================
You need compile your app with debug enabled to be able to debug native code:
./build.sh debug
To debug your application - launch it, go to "project" dir and launch command
ndk-gdb
then you can run usual GDB commands, like:
cont - continue execution.
info threads - list all threads, there will usually be like 11 of them with thread 10 being your main thread.
bt - list stack trace / call hierarchy
up / down - go up / down in the call hierarchy
print var - print the value of variable "var"
You can also debug by adding extensive logs to your app:
__android_log_print(ANDROID_LOG_INFO, "My App", "We somehow reached execution point #224");
and then watching "adb logcat" output.
Android does not print app stdout/stderr streams to logcat, so printf() will not work,
but you can redefine printf() and fprintf(stderr) in your app to write to Android log by adding this to AppCflags:
-include jni/application/android_debug.h
If your application crashed, you should use following steps:
1. Gather the crash report from "adb logcat" - it should contain stack trace, if it does not then you're unlucky,
I/DEBUG ( 51): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG ( 51): Build fingerprint: 'sprint/htc_supersonic/supersonic/supersonic:2.1-update1/ERE27/194487:userdebug/test-keys'
I/DEBUG ( 51): pid: 915, tid: 924 >>> de.schwardtnet.alienblaster <<<
I/DEBUG ( 51): signal 11 (SIGSEGV), fault addr deadbaad
I/DEBUG ( 51): r0 00000000 r1 afe133f1 r2 00000027 r3 00000058
I/DEBUG ( 51): r4 afe3ae08 r5 00000000 r6 00000000 r7 70477020
I/DEBUG ( 51): r8 000000b0 r9 ffffff20 10 48552868 fp 00000234
I/DEBUG ( 51): ip 00002ee4 sp 485527f8 lr deadbaad pc afe10aac cpsr 60000030
I/DEBUG ( 51): #00 pc 00010aac /system/lib/libc.so
I/DEBUG ( 51): #01 pc 0000c00e /system/lib/libc.so
I/DEBUG ( 51): #02 pc 0000c0a4 /system/lib/libc.so
I/DEBUG ( 51): #03 pc 0002ca00 /data/data/de.schwardtnet.alienblaster/lib/libsdl.so
I/DEBUG ( 51): #04 pc 00028b6e /data/data/de.schwardtnet.alienblaster/lib/libsdl.so
I/DEBUG ( 51): #05 pc 0002d080 /data/data/de.schwardtnet.alienblaster/lib/libsdl.so
2. Go to project/bin/ndk/local/armeabi or armeabi-v7a dir, find there the library mentioned in stacktrace
(libsdl.so in our example), copy the address of the first line of stacktrace (0002ca00), and execute command
<your NDK path>/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gdb libsdl.so -ex "list *0x0002ca00" -ex "list *0x00028b6e" -ex "list *0x0002d080"
It will output the exact line in your source where the application crashed, and some stack trace if available.
You may also try to use ndk-stack script to do that for you.
If your application does not work for unknown reasons, there may be the case when it exports some symbol
that clash with exports from system libraries - run checkExports.sh to check this.
Also there are some symbols that are present in the NDK but are not on the device - run checkMissing.sh to check.
If your application fails to load past startup SDL logo with error
I/dalvikvm( 3401): Unable to dlopen(/data/data/com.svc/lib/libapplication.so): Cannot load library: alloc_mem_region[847]: OOPS: 1268 cannot map library 'libapplication.so'. no vspace available.
that means you're allocating huge data buffer in heap (that may be C static or global buffer variable) -
run checkStaticDataSize.sh to see the size of all static symbols inside your application,
heap memory limit on most phones is 24 Mb.
If the error string is like this:
I/dalvikvm(18105): Unable to dlopen(/data/data/net.olofson.kobodl/lib/libapplication.so): Cannot load library: link_image[1995]: failed to link libapplication.so
that means your application contains undefined symbols, absent in the system libraries,
you may check for all missing symbols by running script checkMissing.sh .
That typically happens because of linking to the dynamic libstdc++ which is not included into the .apk file -
specify "-lgnustl_static" in the linker flags to fix that.
License information
===================
The SDL 1.2 port is licensed under LGPL, so you may use it for commercial purposes
without releasing source code, however to fullfill LGPL requirements you'll have to publish
the file AndroidAppSettings.cfg to allow linking other version of libsdl-1.2.so with the libraries
in the binary package you're distributing - typically libapplication.so and other
closed-source libraries in your .apk file.
The SDL 1.3 port and Java source files are licensed under zlib license, which means
you may modify them as you like without releasing source code.
The libraries under project/jni have their own license, I've tried to compile all LGPL-ed libs
as shared libs but you should anyway inspect the licenses of the libraries you're linking to.
libmad and liblzo2 are licensed under GPL, so if you're planning to make commercial app you should avoid
using them, otherwise you'll have to release your whole application sources under GPL too.
The "Ultimate Droid" on-screen keyboard theme by Sean Stieber is licensed under Creative Commons - Attribution license.
The "Simple Theme" on-screen keyboard theme by Dmitry Matveev is licensed under zlib license.
The "Sun" on-screen keyboard theme by Sirea (Martina Smejkalova) is licensed under Creative Commons - Attribution license.
The "Keen" on-screen keyboard theme by Gerstrong (Gerhard Stein) is licensed under GPL 2.0.