docs/README-android.md
author Sam Lantinga
Sat, 12 Jan 2019 12:11:06 -0800
changeset 12532 8db358c7a09a
parent 12487 b2422f30f0a6
child 12693 d311fcb8066a
permissions -rw-r--r--
Updated minimum supported Android version to API 16, to match latest NDK toolchain
slouken@10486
     1
Android
gabomdq@9023
     2
================================================================================
gabomdq@9023
     3
slouken@11328
     4
Matt Styles wrote a tutorial on building SDL for Android with Visual Studio:
slouken@11328
     5
http://trederia.blogspot.de/2017/03/building-sdl2-for-android-with-visual.html
slouken@11328
     6
slouken@11659
     7
The rest of this README covers the Android gradle style build process.
slouken@11659
     8
slouken@11659
     9
If you are using the older ant build process, it is no longer officially
slouken@11659
    10
supported, but you can use the "android-project-ant" directory as a template.
slouken@11647
    11
slouken@11328
    12
slouken@11328
    13
================================================================================
slouken@11328
    14
 Requirements
slouken@11328
    15
================================================================================
gabomdq@9023
    16
slouken@12141
    17
Android SDK (version 26 or later)
icculus@10891
    18
https://developer.android.com/sdk/index.html
gabomdq@9023
    19
slouken@12141
    20
Android NDK r15c or later
icculus@10891
    21
https://developer.android.com/tools/sdk/ndk/index.html
gabomdq@9023
    22
slouken@12532
    23
Minimum API level supported by SDL: 16 (Android 4.1)
gabomdq@9023
    24
slouken@11647
    25
gabomdq@9023
    26
================================================================================
gabomdq@9023
    27
 How the port works
gabomdq@9023
    28
================================================================================
gabomdq@9023
    29
gabomdq@9023
    30
- Android applications are Java-based, optionally with parts written in C
gabomdq@9023
    31
- As SDL apps are C-based, we use a small Java shim that uses JNI to talk to 
philipp@9066
    32
  the SDL library
gabomdq@9023
    33
- This means that your application C code must be placed inside an Android 
philipp@9066
    34
  Java project, along with some C support code that communicates with Java
gabomdq@9023
    35
- This eventually produces a standard Android .apk package
gabomdq@9023
    36
gabomdq@9023
    37
The Android Java code implements an "Activity" and can be found in:
slouken@11647
    38
android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
gabomdq@9023
    39
gabomdq@9023
    40
The Java code loads your game code, the SDL shared library, and
gabomdq@9023
    41
dispatches to native functions implemented in the SDL library:
gabomdq@9023
    42
src/core/android/SDL_android.c
gabomdq@9023
    43
gabomdq@9023
    44
gabomdq@9023
    45
================================================================================
gabomdq@9023
    46
 Building an app
gabomdq@9023
    47
================================================================================
gabomdq@9023
    48
gabomdq@9023
    49
For simple projects you can use the script located at build-scripts/androidbuild.sh
gabomdq@9023
    50
gabomdq@9023
    51
There's two ways of using it:
gabomdq@9023
    52
philipp@9066
    53
    androidbuild.sh com.yourcompany.yourapp < sources.list
philipp@9066
    54
    androidbuild.sh com.yourcompany.yourapp source1.c source2.c ...sourceN.c
gabomdq@9023
    55
gabomdq@9023
    56
sources.list should be a text file with a source file name in each line
gabomdq@9023
    57
Filenames should be specified relative to the current directory, for example if
gabomdq@9023
    58
you are in the build-scripts directory and want to create the testgles.c test, you'll
gabomdq@9023
    59
run:
philipp@9066
    60
philipp@9066
    61
    ./androidbuild.sh org.libsdl.testgles ../test/testgles.c
gabomdq@9023
    62
gabomdq@9023
    63
One limitation of this script is that all sources provided will be aggregated into
gabomdq@9023
    64
a single directory, thus all your source files should have a unique name.
gabomdq@9023
    65
gabomdq@9023
    66
Once the project is complete the script will tell you where the debug APK is located.
gabomdq@9023
    67
If you want to create a signed release APK, you can use the project created by this
gabomdq@9023
    68
utility to generate it.
gabomdq@9023
    69
gabomdq@9023
    70
Finally, a word of caution: re running androidbuild.sh wipes any changes you may have
gabomdq@9023
    71
done in the build directory for the app!
gabomdq@9023
    72
gabomdq@9023
    73
gabomdq@9023
    74
For more complex projects, follow these instructions:
gabomdq@9023
    75
    
gabomdq@9023
    76
1. Copy the android-project directory wherever you want to keep your projects
gabomdq@9023
    77
   and rename it to the name of your project.
slouken@11647
    78
2. Move or symlink this SDL directory into the "<project>/app/jni" directory
slouken@11647
    79
3. Edit "<project>/app/jni/src/Android.mk" to include your source files
gabomdq@9023
    80
slouken@12364
    81
4a. If you want to use Android Studio, simply open your <project> directory and start building.
philipp@9066
    82
slouken@12364
    83
4b. If you want to build manually, run './gradlew installDebug' in the project directory. This compiles the .java, creates an .apk with the native code embedded, and installs it on any connected Android device
gabomdq@9023
    84
gabomdq@9023
    85
Here's an explanation of the files in the Android project, so you can customize them:
gabomdq@9023
    86
slouken@11647
    87
    android-project/app
slouken@11647
    88
        build.gradle            - build info including the application version and SDK
slouken@12364
    89
        src/main/AndroidManifest.xml	- package manifest. Among others, it contains the class name of the main Activity and the package name of the application.
philipp@9055
    90
        jni/			- directory holding native code
slouken@11647
    91
        jni/Application.mk	- Application JNI settings, including target platform and STL library
slouken@11647
    92
        jni/Android.mk		- Android makefile that can call recursively the Android.mk files in all subdirectories
philipp@9055
    93
        jni/SDL/		- (symlink to) directory holding the SDL library files
philipp@9055
    94
        jni/SDL/Android.mk	- Android makefile for creating the SDL shared library
philipp@9055
    95
        jni/src/		- directory holding your C/C++ source
slouken@11647
    96
        jni/src/Android.mk	- Android makefile that you should customize to include your source code and any library references
slouken@11647
    97
        src/main/assets/	- directory holding asset files for your application
slouken@11647
    98
        src/main/res/		- directory holding resources for your application
slouken@11647
    99
        src/main/res/mipmap-*	- directories holding icons for different phone hardware
slouken@11647
   100
        src/main/res/values/strings.xml	- strings used in your application, including the application name
slouken@11647
   101
        src/main/java/org/libsdl/app/SDLActivity.java - the Java class handling the initialization and binding to SDL. Be very careful changing this, as the SDL library relies on this implementation. You should instead subclass this for your application.
gabomdq@9023
   102
gabomdq@9023
   103
gabomdq@9023
   104
================================================================================
gabomdq@9023
   105
 Customizing your application name
gabomdq@9023
   106
================================================================================
gabomdq@9023
   107
gabomdq@9023
   108
To customize your application name, edit AndroidManifest.xml and replace
gabomdq@9023
   109
"org.libsdl.app" with an identifier for your product package.
gabomdq@9023
   110
gabomdq@9023
   111
Then create a Java class extending SDLActivity and place it in a directory
gabomdq@9023
   112
under src matching your package, e.g.
philipp@9055
   113
philipp@9066
   114
    src/com/gamemaker/game/MyGame.java
gabomdq@9023
   115
gabomdq@9023
   116
Here's an example of a minimal class file:
gabomdq@9023
   117
philipp@9050
   118
    --- MyGame.java --------------------------
philipp@9050
   119
    package com.gamemaker.game;
philipp@9050
   120
    
philipp@9050
   121
    import org.libsdl.app.SDLActivity; 
philipp@9050
   122
    
philipp@9065
   123
    /**
philipp@9050
   124
     * A sample wrapper class that just calls SDLActivity 
philipp@9050
   125
     */ 
philipp@9050
   126
    
philipp@9050
   127
    public class MyGame extends SDLActivity { }
philipp@9050
   128
    
philipp@9050
   129
    ------------------------------------------
gabomdq@9023
   130
gabomdq@9023
   131
Then replace "SDLActivity" in AndroidManifest.xml with the name of your
gabomdq@9023
   132
class, .e.g. "MyGame"
gabomdq@9023
   133
slouken@11647
   134
gabomdq@9023
   135
================================================================================
gabomdq@9023
   136
 Customizing your application icon
gabomdq@9023
   137
================================================================================
gabomdq@9023
   138
gabomdq@9023
   139
Conceptually changing your icon is just replacing the "ic_launcher.png" files in
slouken@11647
   140
the drawable directories under the res directory. There are several directories
slouken@11647
   141
for different screen sizes.
gabomdq@9023
   142
gabomdq@9023
   143
gabomdq@9023
   144
================================================================================
gabomdq@9023
   145
 Loading assets
gabomdq@9023
   146
================================================================================
gabomdq@9023
   147
slouken@11647
   148
Any files you put in the "app/src/main/assets" directory of your project
slouken@11647
   149
directory will get bundled into the application package and you can load
slouken@11647
   150
them using the standard functions in SDL_rwops.h.
gabomdq@9023
   151
gabomdq@9023
   152
There are also a few Android specific functions that allow you to get other
gabomdq@9023
   153
useful paths for saving and loading data:
philipp@9066
   154
* SDL_AndroidGetInternalStoragePath()
philipp@9066
   155
* SDL_AndroidGetExternalStorageState()
philipp@9066
   156
* SDL_AndroidGetExternalStoragePath()
gabomdq@9023
   157
gabomdq@9023
   158
See SDL_system.h for more details on these functions.
gabomdq@9023
   159
gabomdq@9023
   160
The asset packaging system will, by default, compress certain file extensions.
gabomdq@9023
   161
SDL includes two asset file access mechanisms, the preferred one is the so
gabomdq@9023
   162
called "File Descriptor" method, which is faster and doesn't involve the Dalvik
gabomdq@9023
   163
GC, but given this method does not work on compressed assets, there is also the
gabomdq@9023
   164
"Input Stream" method, which is automatically used as a fall back by SDL. You
gabomdq@9023
   165
may want to keep this fact in mind when building your APK, specially when large
gabomdq@9023
   166
files are involved.
gabomdq@9023
   167
For more information on which extensions get compressed by default and how to
gabomdq@9023
   168
disable this behaviour, see for example:
gabomdq@9023
   169
    
gabomdq@9023
   170
http://ponystyle.com/blog/2010/03/26/dealing-with-asset-compression-in-android-apps/
gabomdq@9023
   171
slouken@11647
   172
gabomdq@9023
   173
================================================================================
gabomdq@9023
   174
 Pause / Resume behaviour
gabomdq@9023
   175
================================================================================
gabomdq@9023
   176
gabomdq@9023
   177
If SDL is compiled with SDL_ANDROID_BLOCK_ON_PAUSE defined (the default),
gabomdq@9023
   178
the event loop will block itself when the app is paused (ie, when the user
gabomdq@9023
   179
returns to the main Android dashboard). Blocking is better in terms of battery
gabomdq@9023
   180
use, and it allows your app to spring back to life instantaneously after resume
gabomdq@9023
   181
(versus polling for a resume message).
gabomdq@9023
   182
gabomdq@9023
   183
Upon resume, SDL will attempt to restore the GL context automatically.
gabomdq@9023
   184
In modern devices (Android 3.0 and up) this will most likely succeed and your
gabomdq@9023
   185
app can continue to operate as it was.
gabomdq@9023
   186
gabomdq@9023
   187
However, there's a chance (on older hardware, or on systems under heavy load),
gabomdq@9023
   188
where the GL context can not be restored. In that case you have to listen for
gabomdq@9023
   189
a specific message, (which is not yet implemented!) and restore your textures
gabomdq@9023
   190
manually or quit the app (which is actually the kind of behaviour you'll see
gabomdq@9023
   191
under iOS, if the OS can not restore your GL context it will just kill your app)
gabomdq@9023
   192
slouken@11647
   193
gabomdq@9023
   194
================================================================================
gabomdq@9023
   195
 Threads and the Java VM
gabomdq@9023
   196
================================================================================
gabomdq@9023
   197
gabomdq@9023
   198
For a quick tour on how Linux native threads interoperate with the Java VM, take
icculus@10891
   199
a look here: https://developer.android.com/guide/practices/jni.html
philipp@9066
   200
gabomdq@9023
   201
If you want to use threads in your SDL app, it's strongly recommended that you
gabomdq@9023
   202
do so by creating them using SDL functions. This way, the required attach/detach
gabomdq@9023
   203
handling is managed by SDL automagically. If you have threads created by other
gabomdq@9023
   204
means and they make calls to SDL functions, make sure that you call
philipp@9065
   205
Android_JNI_SetupThread() before doing anything else otherwise SDL will attach
gabomdq@9023
   206
your thread automatically anyway (when you make an SDL call), but it'll never
gabomdq@9023
   207
detach it.
gabomdq@9023
   208
slouken@11647
   209
gabomdq@9023
   210
================================================================================
gabomdq@9023
   211
 Using STL
gabomdq@9023
   212
================================================================================
gabomdq@9023
   213
gabomdq@9023
   214
You can use STL in your project by creating an Application.mk file in the jni
gabomdq@9023
   215
folder and adding the following line:
philipp@9066
   216
slouken@12364
   217
    APP_STL := c++_shared
gabomdq@9023
   218
slouken@12364
   219
For more information go here:
slouken@12364
   220
	https://developer.android.com/ndk/guides/cpp-support
gabomdq@9023
   221
gabomdq@9023
   222
gabomdq@9023
   223
================================================================================
gabomdq@9023
   224
 Using the emulator
gabomdq@9023
   225
================================================================================
gabomdq@9023
   226
gabomdq@9023
   227
There are some good tips and tricks for getting the most out of the
icculus@10891
   228
emulator here: https://developer.android.com/tools/devices/emulator.html
gabomdq@9023
   229
gabomdq@9023
   230
Especially useful is the info on setting up OpenGL ES 2.0 emulation.
gabomdq@9023
   231
gabomdq@9023
   232
Notice that this software emulator is incredibly slow and needs a lot of disk space.
gabomdq@9023
   233
Using a real device works better.
gabomdq@9023
   234
slouken@11647
   235
gabomdq@9023
   236
================================================================================
gabomdq@9023
   237
 Troubleshooting
gabomdq@9023
   238
================================================================================
gabomdq@9023
   239
gabomdq@9023
   240
You can see if adb can see any devices with the following command:
philipp@9055
   241
philipp@9066
   242
    adb devices
gabomdq@9023
   243
gabomdq@9023
   244
You can see the output of log messages on the default device with:
philipp@9055
   245
philipp@9066
   246
    adb logcat
gabomdq@9023
   247
gabomdq@9023
   248
You can push files to the device with:
philipp@9055
   249
philipp@9066
   250
    adb push local_file remote_path_and_file
gabomdq@9023
   251
gabomdq@9023
   252
You can push files to the SD Card at /sdcard, for example:
philipp@9055
   253
philipp@9066
   254
    adb push moose.dat /sdcard/moose.dat
gabomdq@9023
   255
gabomdq@9023
   256
You can see the files on the SD card with a shell command:
philipp@9055
   257
philipp@9066
   258
    adb shell ls /sdcard/
gabomdq@9023
   259
gabomdq@9023
   260
You can start a command shell on the default device with:
philipp@9055
   261
philipp@9066
   262
    adb shell
gabomdq@9023
   263
gabomdq@9023
   264
You can remove the library files of your project (and not the SDL lib files) with:
philipp@9055
   265
philipp@9066
   266
    ndk-build clean
gabomdq@9023
   267
gabomdq@9023
   268
You can do a build with the following command:
philipp@9055
   269
philipp@9066
   270
    ndk-build
gabomdq@9023
   271
gabomdq@9023
   272
You can see the complete command line that ndk-build is using by passing V=1 on the command line:
philipp@9055
   273
philipp@9066
   274
    ndk-build V=1
gabomdq@9023
   275
slouken@12364
   276
If your application crashes in native code, you can use ndk-stack to get a symbolic stack trace:
slouken@12364
   277
	https://developer.android.com/ndk/guides/ndk-stack
slouken@12364
   278
slouken@12364
   279
If you want to go through the process manually, you can use addr2line to convert the
gabomdq@9023
   280
addresses in the stack trace to lines in your code.
gabomdq@9023
   281
gabomdq@9023
   282
For example, if your crash looks like this:
philipp@9050
   283
philipp@9050
   284
    I/DEBUG   (   31): signal 11 (SIGSEGV), code 2 (SEGV_ACCERR), fault addr 400085d0
philipp@9050
   285
    I/DEBUG   (   31):  r0 00000000  r1 00001000  r2 00000003  r3 400085d4
philipp@9050
   286
    I/DEBUG   (   31):  r4 400085d0  r5 40008000  r6 afd41504  r7 436c6a7c
philipp@9050
   287
    I/DEBUG   (   31):  r8 436c6b30  r9 435c6fb0  10 435c6f9c  fp 4168d82c
philipp@9050
   288
    I/DEBUG   (   31):  ip 8346aff0  sp 436c6a60  lr afd1c8ff  pc afd1c902  cpsr 60000030
philipp@9050
   289
    I/DEBUG   (   31):          #00  pc 0001c902  /system/lib/libc.so
philipp@9050
   290
    I/DEBUG   (   31):          #01  pc 0001ccf6  /system/lib/libc.so
philipp@9050
   291
    I/DEBUG   (   31):          #02  pc 000014bc  /data/data/org.libsdl.app/lib/libmain.so
philipp@9050
   292
    I/DEBUG   (   31):          #03  pc 00001506  /data/data/org.libsdl.app/lib/libmain.so
gabomdq@9023
   293
gabomdq@9023
   294
You can see that there's a crash in the C library being called from the main code.
gabomdq@9023
   295
I run addr2line with the debug version of my code:
philipp@9055
   296
philipp@9066
   297
    arm-eabi-addr2line -C -f -e obj/local/armeabi/libmain.so
philipp@9055
   298
gabomdq@9023
   299
and then paste in the number after "pc" in the call stack, from the line that I care about:
gabomdq@9023
   300
000014bc
gabomdq@9023
   301
gabomdq@9023
   302
I get output from addr2line showing that it's in the quit function, in testspriteminimal.c, on line 23.
gabomdq@9023
   303
gabomdq@9023
   304
You can add logging to your code to help show what's happening:
gabomdq@9023
   305
philipp@9055
   306
    #include <android/log.h>
philipp@9055
   307
    
philipp@9055
   308
    __android_log_print(ANDROID_LOG_INFO, "foo", "Something happened! x = %d", x);
gabomdq@9023
   309
gabomdq@9023
   310
If you need to build without optimization turned on, you can create a file called
gabomdq@9023
   311
"Application.mk" in the jni directory, with the following line in it:
philipp@9066
   312
philipp@9066
   313
    APP_OPTIM := debug
gabomdq@9023
   314
gabomdq@9023
   315
gabomdq@9023
   316
================================================================================
gabomdq@9023
   317
 Memory debugging
gabomdq@9023
   318
================================================================================
gabomdq@9023
   319
gabomdq@9023
   320
The best (and slowest) way to debug memory issues on Android is valgrind.
gabomdq@9023
   321
Valgrind has support for Android out of the box, just grab code using:
philipp@9055
   322
philipp@9066
   323
    svn co svn://svn.valgrind.org/valgrind/trunk valgrind
philipp@9055
   324
gabomdq@9023
   325
... and follow the instructions in the file README.android to build it.
gabomdq@9023
   326
gabomdq@9023
   327
One thing I needed to do on Mac OS X was change the path to the toolchain,
gabomdq@9023
   328
and add ranlib to the environment variables:
gabomdq@9023
   329
export RANLIB=$NDKROOT/toolchains/arm-linux-androideabi-4.4.3/prebuilt/darwin-x86/bin/arm-linux-androideabi-ranlib
gabomdq@9023
   330
gabomdq@9023
   331
Once valgrind is built, you can create a wrapper script to launch your
gabomdq@9023
   332
application with it, changing org.libsdl.app to your package identifier:
philipp@9050
   333
philipp@9050
   334
    --- start_valgrind_app -------------------
philipp@9050
   335
    #!/system/bin/sh
philipp@9050
   336
    export TMPDIR=/data/data/org.libsdl.app
philipp@9050
   337
    exec /data/local/Inst/bin/valgrind --log-file=/sdcard/valgrind.log --error-limit=no $*
philipp@9050
   338
    ------------------------------------------
gabomdq@9023
   339
gabomdq@9023
   340
Then push it to the device:
philipp@9055
   341
philipp@9066
   342
    adb push start_valgrind_app /data/local
gabomdq@9023
   343
gabomdq@9023
   344
and make it executable:
philipp@9055
   345
philipp@9066
   346
    adb shell chmod 755 /data/local/start_valgrind_app
gabomdq@9023
   347
gabomdq@9023
   348
and tell Android to use the script to launch your application:
philipp@9055
   349
philipp@9066
   350
    adb shell setprop wrap.org.libsdl.app "logwrapper /data/local/start_valgrind_app"
gabomdq@9023
   351
gabomdq@9023
   352
If the setprop command says "could not set property", it's likely that
gabomdq@9023
   353
your package name is too long and you should make it shorter by changing
gabomdq@9023
   354
AndroidManifest.xml and the path to your class file in android-project/src
gabomdq@9023
   355
gabomdq@9023
   356
You can then launch your application normally and waaaaaaaiiittt for it.
gabomdq@9023
   357
You can monitor the startup process with the logcat command above, and
gabomdq@9023
   358
when it's done (or even while it's running) you can grab the valgrind
gabomdq@9023
   359
output file:
philipp@9055
   360
philipp@9066
   361
    adb pull /sdcard/valgrind.log
gabomdq@9023
   362
gabomdq@9023
   363
When you're done instrumenting with valgrind, you can disable the wrapper:
philipp@9055
   364
philipp@9066
   365
    adb shell setprop wrap.org.libsdl.app ""
gabomdq@9023
   366
slouken@11647
   367
gabomdq@9023
   368
================================================================================
slouken@10487
   369
 Graphics debugging
slouken@10487
   370
================================================================================
slouken@10487
   371
philipp@10543
   372
If you are developing on a compatible Tegra-based tablet, NVidia provides
slouken@11647
   373
Tegra Graphics Debugger at their website. Because SDL2 dynamically loads EGL
philipp@10543
   374
and GLES libraries, you must follow their instructions for installing the
slouken@11647
   375
interposer library on a rooted device. The non-rooted instructions are not
philipp@10543
   376
compatible with applications that use SDL2 for video.
slouken@10487
   377
slouken@10487
   378
The Tegra Graphics Debugger is available from NVidia here:
slouken@10487
   379
https://developer.nvidia.com/tegra-graphics-debugger
slouken@10487
   380
slouken@11647
   381
slouken@10487
   382
================================================================================
slouken@12532
   383
 Why is API level 16 the minimum required?
gabomdq@9023
   384
================================================================================
gabomdq@9023
   385
slouken@12532
   386
The latest NDK toolchain doesn't support targeting earlier than API level 16.
icculus@10891
   387
As of this writing, according to https://developer.android.com/about/dashboards/index.html
slouken@12532
   388
about 99% of the Android devices accessing Google Play support API level 16 or
slouken@12532
   389
higher (January 2018).
gabomdq@9023
   390
slouken@11647
   391
gabomdq@9023
   392
================================================================================
gabomdq@9023
   393
 A note regarding the use of the "dirty rectangles" rendering technique
gabomdq@9023
   394
================================================================================
gabomdq@9023
   395
gabomdq@9023
   396
If your app uses a variation of the "dirty rectangles" rendering technique,
gabomdq@9023
   397
where you only update a portion of the screen on each frame, you may notice a
gabomdq@9023
   398
variety of visual glitches on Android, that are not present on other platforms.
gabomdq@9023
   399
This is caused by SDL's use of EGL as the support system to handle OpenGL ES/ES2
gabomdq@9023
   400
contexts, in particular the use of the eglSwapBuffers function. As stated in the
gabomdq@9023
   401
documentation for the function "The contents of ancillary buffers are always 
gabomdq@9023
   402
undefined after calling eglSwapBuffers".
gabomdq@9023
   403
Setting the EGL_SWAP_BEHAVIOR attribute of the surface to EGL_BUFFER_PRESERVED
gabomdq@9023
   404
is not possible for SDL as it requires EGL 1.4, available only on the API level
gabomdq@9023
   405
17+, so the only workaround available on this platform is to redraw the entire
gabomdq@9023
   406
screen each frame.
gabomdq@9023
   407
gabomdq@9023
   408
Reference: http://www.khronos.org/registry/egl/specs/EGLTechNote0001.html
gabomdq@9023
   409
slouken@11647
   410
gabomdq@9023
   411
================================================================================
sylvain@12487
   412
 Ending your application
sylvain@12487
   413
================================================================================
sylvain@12487
   414
sylvain@12487
   415
Two legitimate ways:
sylvain@12487
   416
sylvain@12487
   417
- return from your main() function. Java side will automatically terminate the
sylvain@12487
   418
Activity by calling Activity.finish().
sylvain@12487
   419
sylvain@12487
   420
- Android OS can decide to terminate your application by calling onDestroy()
sylvain@12487
   421
(see Activity life cycle). Your application will receive a SDL_QUIT event you 
sylvain@12487
   422
can handle to save things and quit.
sylvain@12487
   423
sylvain@12487
   424
Don't call exit() as it stops the activity badly.
sylvain@12487
   425
sylvain@12487
   426
NB: "Back button" can be handled as a SDL_KEYDOWN/UP events, with Keycode
sylvain@12487
   427
SDLK_AC_BACK, for any purpose.
sylvain@12487
   428
sylvain@12487
   429
================================================================================
gabomdq@9023
   430
 Known issues
gabomdq@9023
   431
================================================================================
gabomdq@9023
   432
gabomdq@9023
   433
- The number of buttons reported for each joystick is hardcoded to be 36, which
gabomdq@9023
   434
is the current maximum number of buttons Android can report.
gabomdq@9023
   435