The Allegro Wiki is undergoing maintenance, please be patient.

Running Allegro applications on Android

From Allegro Wiki
Jump to: navigation, search

This guide is based on using the Linux platform using the command line. It describes the steps required to run the Allegro demos and examples on an Android device.

The latest Android Studio IDE supports the NDK now. However, this is not covered on this wiki page.


Prerequisites

You need to install ant, which you can usually get from the repo of your distribution.

Then you need the JDK from Oracle. Some distributions just offer OpenJDK in their repo, but for Android development you need the JDK from Oracle.

So download that here:

http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html


Downloading the Android development tools

You also need the Android SDK. Download it from here:

http://developer.android.com/sdk/index.html#Other

Unpack the SDK archive into a directory called e.g. android-sdk-linux

For Allegro you also need the NDK (Native development kit) from:

http://developer.android.com/ndk/downloads/index.html

The NDK package is a self-extracting binary. To unpack it, follow this procedure:

  • Open a terminal window.
  • Go to the directory to which you downloaded the package.
  • Run chmod a+x on the downloaded package.
  • Execute the package. For example:
   chmod a+x android-ndk-r10e-linux-x86_64.bin
   ./android-ndk-r10e-linux-x86_64.bin

The folder containing the NDK, e.g. "android-ndk-r10e", extracts itself into the current directory. From there you should move it into your home directory.

It is important to do it this way, because other extraction utilities, e.g. 7zip may not generate the included symlinks properly and CMake will not run with the installed package.

Android apps are typically written in Java. The NDK, the Native Development Kit, supports C/C++ code to be called from a Java application. The C/C++ code is compiled into a library which is loaded by the Java code. This way Allegro can be used on the Android platform.


Setup the Android SDK development environment

Get into your android-sdk-linux directory and execute the "tools/android" script. This will start the Android SDK Manager and allow you to download and install tools and packages. Allegro needs at least the API 12 SDK platform, so download at least that or any newer. Here are the packages used for this wiki page:

Tools

  • Android SDK Tools
  • Android SDK Platform-tools
  • Android SDK Build-tools

Android 6.0 (API 23)

  • SDK Platform
  • ARM EABI v7a System Image
  • Google APIs
  • Google APIs ARM EABI v7a System Image

Android 4.0.3 (API 15)

  • SDK Platform
  • Samples for SDK
  • ARM EABI v7a System Image
  • Google APIs
  • Google APIs ARM EABI v7a System Image

Extras

  • Android Support Library


Specify required environment Variables

You could make a script called start.sh which contains the following lines. Make sure to run that with the dot command like ". ./start.sh" to avoid that it runs in subshell.

Better yet, set them in your ~/.bashrc or ~/.bash_profile file.

#let Android find the JDK
export JAVA_HOME=/usr/java/jdk1.8.0_60

#let Android find the NDK
export ANDROID_NDK_ROOT=/home/georg/android-ndk-r10e

#set the path to the SDK
export PATH=$PATH:/home/georg/android-sdk-linux/tools

#set the path to the NDK
export PATH=$PATH:/home/georg/android-ndk-r10e

#set  a variable containing the standalone toolchain
export TC=/home/georg/android-toolchain

#set path to arm-linux-androideabi-gcc and friends
export PATH=$PATH:$TC/bin

#help the emulator find its ini files (optional)
export ANDROID_AVD_HOME=/home/georg/.android/avd

Allegro expects the path to be extended as described to be able to run the tools without specifying the path for them. All are self-contained so they can be executed from any directory.


Generate a standalone toolchain

Get into your NDK directory and enter the following on the command line or write a little script to execute the command:

/home/georg/android-ndk-r10e/build/tools/make-standalone-toolchain.sh --platform=android-15 \
--install-dir=$TC --stl=stlport --arch=arm

If you installed API version 15 when running the Android SDK Manager, specify platform=android-15 on the command line. You can execute the "android list targets" command to see which Android targets you got installed.

This will generate the standalone toolchain in the directory specified in the TC variable which you already set above.


Compile Allegro for Android

Get into your Allegro directory and make a new directory called "build" or "buildandroid":

 mkdir buildandroid

Get into that directory:

 cd buildandroid

and execute:

cmake .. -DANDROID_NDK_TOOLCHAIN_ROOT=$TC -DWANT_ANDROID=on -DCMAKE_BUILD_TYPE=Debug -DANDROID_TARGET=android-15 

CMake will generate the required Makefiles now. It will also make a demos and a examples directory and prepare for each example a project directory. E.g for the "ex_bitmap" example it will generate an "ex_bitmap.project" directory in the examples directory.

Then enter "make" on the command line:

This will generate liballegro-*.so libraries, this are liballegro-debug.so, liballegro_acodec-debug.so, liballegro_audio-debug.so, liballegro_font-debug.so, liballegro_image-debug.so, liballegro_memfile-debug.so, liballegro_primitives-debug.so and the examples as *.so files such as libex_bitmap.so. It also generates an Allegro5.jar file in the lib subdirectory.

You may observe that there is no liballegro_ttf-debug.so listed. This library requires to cross-compile freetype for Android first since liballegro_ttf depends on that.

For each example the required libraries from this list are loaded using the file Activity.java in addition to the library the example code was compiled into.

So far everything gets compiled in debug mode and not in release mode. Applications compiled in release mode would need to be signed before being able to run on an Android device.

Make will also setup the mentioned project directories for the examples as well as the demos and in there generate the following subdirectories:

  • assets/
  • bin/
  • gen/
  • jni/
  • libs/
  • obj/
  • res/drawable/
  • res/layout/
  • res/values/
  • src/

The src/ directory will hold java code and other source files in a package structure common for java projects. The res/ directory will hold user provided resources like text strings, images, menues, layouts etc. The obj/ directory will contain .class files and other secondary files produced by the Java tools. The lib/ directory should hold 3rd-party .jar files the project depends on. The bin/ directory will hold intermediate and final executables produced.

Make will also generate the following files in each project directory (among others):

  • AndroidManifest.xml
  • jni/Android.mk
  • src/org/liballeg/examples/Activity.java
  • build.xml
  • res/values/strings.xml

These files contain references to each particular example.

It is not required now if you want to run the demos, but "make install" will install headers and libraries into the toolchain directory.


Connect your Android device to your PC

To execute the demo applications on your tablet or phone connect that with your USB cable that you got to the PC. The PC will recognize the device as a USB mass storage device at first.

Now you have to enable USB debugging on your device.

On most devices running Android 3.2 or older, you can find the option under "Settings > Applications > Development".

However, On Android 4.2 and newer, Developer options is hidden by default. To make it available, go to "Settings > About phone" and tap "Build number" seven times (no kidding). After a few taps a little window will appear telling you how many taps are left. Then return to the previous screen to find a new "Developer options" entry in the menu now.

In this Developer options submenu you have to check "USB-Debugging" to allow the PC to send its applications to the device and execute them on it.

A windows will appear asking if it is always OK if the device is connected to this PC. Answer yes, as long as this window appears you cannot install an application on the device as you will do in the next step.

To check whether your device is available now, enter

  adb devices

and see if your device is reported.


Run the examples on your connected Android device

Everything is arranged now to compile the demos and examples that come with the Allegro5 package for the Android device. E.g. if you enter "make run_speed" this demo will be compiled and make will install the resulting demos/speed/speed.project/bin/speed-debug.apk file on the Android device and start it there. "run_speed" is a target in the Makefile that will do all that for you automagically.

You can then just select another target on the command line and the existing application will be stopped and the new one will be installed and executed. Other targets for examples you may try are:

  • run_ex_bitmap, run_ex_rotate, run_ex_bitmap_flip, run_ex_shader, run_ex_blend, run_ex_skater,
  • run_ex_lines, run_ex_font, run_ex_blit, run_ex_touch_input (shows circles where tapped), run_ex_transform,
  • run_ex_palette, run_ex_polygon, run_ex_mixer_pp (including sound), run_ex_audio_timer,
  • run_ex_audio_props (allows slider input), run_ex_draw, run_ex_draw_bitmap, run_ex_camera,
  • run_ex_fs_window, run_ex_fs_resize, run_ex_lockbitmap, run_ex_premulalpha, run_ex_saw.

These examples were written to support a PC with mouse and keyboard which is not available as such on the Android device. As you may have expected most examples do not or just minimally accept input and therefore cannot be used on an Android device. Many will not work at all.

The examples are executed by the Makefile using the adb (Android debug bridge) utility.

You can also terminate the adb server by opening a new terminal window and entering "ps aux|grep adb" and then "kill 2345" where 2345 is the process number you found. This will not stop the example on the device.

The Makefile is setup to run the examples on a real Android device connected via USB cable.

Google distributed an Update in September 2015 after that several examples no longer work properly. Use the emulator to test these for now.


Run the examples with the emulator

The Android SDK includes a Android phone emulator which you can use to run the examples without connecting a device via an USB cable.

Open a new terminal window and make sure the environment Variables and the path is set as described above.

Then check what virtual devices are installed by entering on the command line:

 android list avd

This will list the available virtual devices. You can install further virtual devices by running the avd manager:

 android avd 

Then start one of the avds:

 emulator @Nexus_One_API_23

It will take very long till the emulator is fully loaded. Allow for up to 15 minutes (but see the section below). You have to wait until "charging" appears. Then you have to swipe vertically with the mouse over the screen to activate it. Check that you can navigate with the mouse on this emulated phone and select different screens. Once loaded the emulator will run the application at an acceptable speed.

You do not need to open it in a separate window if you use "&" to load it: "emulator @Nexus_One_API_23&"

Now return to the terminal window you had opened before to run CMake and make.

Start the adb server now:

 adb start-server

If you want to run the "ex_bitmap" example get into the examples/ex_bitmap.project directory. In there enter:

  android update project -p . --target android-15
  ndk-build
  ant clean debug install

Eventually ant will have the "ex_bitmap" application installed on the emulator. Select the applications screen icon on the emulated phone and once in there select the icon with the name "ex_bitmap". This will start this Allegro example in the emulator. Other examples allow you to simulate a touch input with the mouse and enter a few keys on the keyboard if the application requests that.

You can also get into "settings->apps" and select your application to stop or remove it from via that menu.


You can also run examples in the emulator that were compiled as described above to run on an real Android device. Please disconnect your device first because this will not work if a real device is still connected. You may even have to restart your PC then.

Then start the emulator in a separate terminal window as described above.

After that start the adb server:

 adb start-server

If you want to run the "ex_draw_bitmap" example get into the

"$HOME/allegro-5.1.11/buildandroid/examples/run_ex_draw_bitmap.project" directory. This is the root directory of the ex_draw_bitmap example. Enter there:

 ant clean debug install

Again, ant will install the ex_draw_bitmap application on the emulator. Select the icon with the name "ex_draw_bitmap" on the application screen of the emulated phone.

Entering:

 ant uninstall 

will stop and remove the application from the device.

Making the emulator faster

You can make the emulator *much* faster by using KVM in Linux (similar things exist for Windows and OSX). However this only works if the native code uses x86_64 architecture. Recompile Allegro and dependencies (freetype, ogg, vorbis, ...) for the x86_64 architecture instead of arm. The easiest way will be to have a separate build folder of everything just for x86_64 and create another standalone android toolchain for x86_64.

The steps could be like this:

# create a separate shell script with a different toolchain path:
export TC=/home/georg/android-toolchain_x86_64
export PATH=$PATH:$TC/bin

# run the script (I named it android-x86_64.sh)
. android-x86_64.sh

# create the x86_64 toolchain
/android-ndk-r10e/build/tools/make-standalone-toolchain.sh --platform=android-15 --install-dir=$TC --stl=stlport --arch=x86_64

# compile dependencies
# Basically use a new folder then do just like with ARM above, but replace "arm" with "x86_64"

# FreeType
./configure --host=x86_64-linux-android --disable-shared --enable-static --prefix=$TC/sysroot/usr/ --without-png --without-zlib --without-harfbuzz
make
make install

# Ogg
./configure --host=x86_64-linux-android --disable-shared --enable-static --prefix=$TC/sysroot/usr
make
make install

# Vorbis
./configure --host=x86_64-linux-android --without-ogg --disable-shared --enable-static --prefix=$TC/sysroot/usr --with-sysroot=$TC/sysroot --with-ogg=$TC/sysroot/usr --with-ogg-libraries=$TC/sysroot/usr/lib --with-ogg-includes=$TC/sysroot/usr/include
make
make install

# compile allegro for x86_64
cd $HOME/allegro
mkdir build_android_x86_64
cd build_android_x86_64
cmake .. -DANDROID_NDK_TOOLCHAIN_ROOT=$TC -DWANT_ANDROID=on -DCMAKE_BUILD_TYPE=Debug -DANDROID_TARGET=android-21 -DARM_TARGETS=x86_64
# cmake was confused about some libraries both in lib/ and lib64/ for me, so manually fix those to point to the lib64/ version

# Finally, in your android project, edit jni/Application.mk to use x86_64 instead of armeabi-v7a:
TARGET_ARCH_ABI := x86_64

Sign applications for Google Play store

So far we have always generated the applications in debug mode to simplify installing them to the device. If you want to generate them in release mode, you have to sign the application before installing them on the device.

You probably do not want to upload any of the Allegro examples to the Google Play store. However, just to describe the process how to sign an application here the "ex_bitmap" example shall now serve as an example how you can prepare an apk file for Google Play store.

First, you have to generate a private key that will be used to sign the application. For this enter on the command line:

  keytool -genkey -v -keystore allegro.keystore -alias release \
  -keyalg RSA -keysize 2048 -validity 10000

keytool is a utility that is included in the JDK. It creates a private key. Here it will prompt you for passwords for the keystore and key, and to provide the Distinguished Name fields for your key.

The -keystore argument specifies the name of the output file where the keys are stored. This is named allegro.keystore here. This keystore file is saved in the current directory where you executed the command. If you want to use it later from a different directory, specify the path to that file. Also a ".directory" is generated in the current directory by the keytool utility.

The -alias argument specifies a human readable name for the key in the keystore which can be used to refer to the key later on. The encryption algorithm is set to RSA with a keysize of 2048 bits and a validity of 10000 days. The generated keystore file should be kept safe since it identifies you for the Google Play store.

Now you can compile your application in release mode. Get into the examples/ex_bitmap.project directory. There enter on the command line:

 ant clean release

This will generate an "ex_bitmap-release-unsigned.apk" file in the "bin" directory within the project directory. Now you have to use jarsigner to sign this file:

 jarsigner -keystore allegro.keystore -digestalg SHA1 -sigalg MD5withRSA bin/ex_bitmap-release-unsigned.apk release

Jarsigner will use the previously created private key to sign the file. You will be prompted for passwords for the keystore and key. Then the APK is modified in-place to sign it. Jarsigner will issue a warning regarding a missing time stamp. This time stamp is optional, however. There is a "-tsa url" option where you could specify the url of a Time Stamping Authority (TSA).

Now you could verify that the file has been properly signed:

 jarsigner -verify bin/ex_bitmap-release-unsigned.apk

This will return "jar verified" if all went well. It will complain again regarding the time stamp though.

For the next step we need the zipalign utility. This used to be in the tools directory but now it is hidden in the build-tools directory. So first set a path to this directory, e.g.:

 export PATH=$PATH:/home/georg/android-sdk-linux/build-tools/23.0.1

Then zipalign need the libc++ library in /usr/lib. So make a link like that:

 sudo ln /usr/lib/libstdc++.so.6 /usr/lib/libc++.so

Please observe that zipalign does not need libstdc++ but libc++.

Now we can make the last step, to align the apk file:

 zipalign -v 4 bin/ex_bitmap-release-unsigned.apk bin/ex_bitmap.apk

The zipalign utility aligns the apk file to a 4-byte boundary. The ex_bitmap-release-unsigned.apk file is the name of the input file here and the ex_bitmap.apk file the aligned output file.

Zipalign ensures that all uncompressed data starts with a particular byte alignment relative to the start of the file, which reduces the amount of RAM consumed by an app. Google strongly recommends to align an APK file.

This file then can be installed on the device or could be uploaded to the Google Play store. You need a developer account for that. The full procedure is described e.g. here:

https://developer.android.com/distribute/googleplay/start.html

or here:

https://support.google.com/googleplay/android-developer/answer/113469?hl=en


Build an Allegro application for Android

Android applications are written in Java. Java, however, has JNI, the Java Native Interface. This allows Java programs to call shared libraries compiled in C/C++ or other languages.


Allegro can be compiled to a shared libary which then can be loaded by an Android Java application using the JNI. It is also possible to compile C/C++ programs, e.g. games, to a shared library and get the Java program to execute that together with the allegro shared library. Further libraries that this program depends on need to be compiled for Android and then can be loaded too. This way the existing Allegro examples were ported to the Android platform.


So you make a Java program, usually called "src/opt/liballeg/examples/ExampleActivity.java" for Android that uses JNI to load one or more C programs each compiled to a shared library together with the shared library allegro-debug.so plus its addons like allegro_primitives-debug.so.


To begin, the environment variables have to be set and the path has to be modified as described here: Running_Allegro_applications_on_Android#Specify required environment Variables.


To build your own applications start by using the "allegro-5.1-11/android/example" directory. You can use that after you did run cmake and make in your buildandroid directory.

You can put different source code files into the "allegro-5.1-11/android/example/csrc" directory and run make in buildandroid again to compile these. Then run the following command in the "allegro-5.1-11/android/example" directory:

 adb -d install -r bin/example-debug.apk

and start the program by selecting the icon named "Allegro example" on your Android device.

Alternatively you can get into the "allegro-5.1-11/android/example" directory and enter there:

  ndk-build
  ant debug
  adb -d install -r bin/example-debug.apk
  adb -d shell 'am start -a android.intent.action.MAIN -n org.liballeg.example/.ExampleActivity'

The "adb -d shell.." command will start the application on your device right away and show the image of alex which is located in the assets directory. You can execute these commands also by running the "run.sh" script.

These command have to be executed if you copied the example directory to a different place in your home directory to develop your application there.


For a test you can copy the touch_input.c example file together with the common.c file, which it includes, into the csrc directory. Remove the main.c file in the csrc directory and rename touch_input.c to main.c. Then run "./run.sh" again and you can make circles on the screen with your finger.

You can stop the application with:

  adb shell am force-stop org.liballeg.example


Build dependency libraries

libfreetype

For demonstration we will compile the freetype library for Android now and then compile the allegro_ttf-debug.so shared library.


First download the freetype sources from here:

http://download.savannah.gnu.org/releases/freetype/

Select e.g. version 2.6. Then add the /home/georg/android-toolchain/bin directory to the path:

 export PATH=$PATH:$TC/bin

You can also add this to a start.sh script or your ~/.bashrc or ~/.bash_profile file.

Then check if the path to this bin directory works and that arm-linux-androideabi-gcc can be found by entering:

 arm-linux-androideabi-gcc

If it returns "fatal error: no input files" you are ok. If configure does not find arm-linux-androideabi-gcc etc. it will fall back to the standard gcc and this may go unnoticed. The resulting library is not usable though.

Then get into the freetype-2.6 directory and enter:

  ./configure --host=arm-linux-androideabi --disable-shared --enable-static --prefix=$TC/sysroot/usr/ --without-png --without-zlib --without-harfbuzz
  make
  make install

This installs "libfreetype.a" and "libfreetype.la" into the "/home/georg/android-toolchain/sysroot/usr/lib" and the "freetype2" directory into the "/home/georg/android-toolchain/sysroot/usr/include" directory. Above we had defined $TC as "/home/georg/android-toolchain". To use these directories is a suggestion by Trent in 2013. This works just fine and you do not need to specify separate paths to the directories where the library and the include files are located. CMake will find them in these directories even with an old findfreetype script. Allegro uses the freetype library compiled as a static library then. This is simpler than using a shared library.


Then run cmake again in the android-5.1.11/buildandroid directory:

 cmake .. -DANDROID_NDK_TOOLCHAIN_ROOT=$TC -DWANT_ANDROID=on -DCMAKE_BUILD_TYPE=Debug -DANDROID_TARGET=android-15

After this scroll all the way back up and check if CMake has found the freetype library. If it has, it will also compile the allegro_ttf.so library.

Then enter "make". When this is finished you will see that the last step was linking the allegro_ttf.so library.

To check if this worked out you can run the ex_ttf example:

 make run_ex_ttf

This will build the ex_ttf example, install and start it on the connected Android device. Or try the run_ex_font_multiline target. There you can move the sliders with your finger and select items from the menus.

libogg

The Allegro CMakeLists.txt file will also check for the libraries libogg, libvorbis, libFLAC, OpenAL PhysFS and libdumb. If CMake finds these it will compile e.g. the allegro_physfs-debug.so library. You have to cross-compile these libraries for Android to use them with Allegro for Android. To do this we follow the instructions by Yodhe23 in this thread.

Now we will cross compile libogg. Download it from here: https://www.xiph.org/downloads/ This page also allows to download libvorbis and libtheora.

Then we get into the libogg-1.3.2 directory and enter:

 ./configure --host=arm-linux-androideabi --disable-shared --enable-static --prefix=$TC/sysroot/usr
 make
 make install

This will compile libogg and install it in "android-toolchain/sysroot/usr".

libvorbis

On to libvorbis, download that from https://www.xiph.org/downloads/ and enter in the libvorbis-1.3.5 directory:

 ./configure --host=arm-linux-androideabi --without-ogg --disable-shared --enable-static --prefix=$TC/sysroot/usr --with-sysroot=$TC/sysroot \
 --with-ogg=$TC/sysroot/usr --with-ogg-libraries=$TC/sysroot/usr/lib --with-ogg-includes=$TC/sysroot/usr/include
 make
 make install

This will compile libvorbis and install it in "android-toolchain/sysroot/usr".

libFLAC

This library can be downloaded here: http://downloads.xiph.org/releases/flac/ Unpack this and get into the "flac-1.3.1" directory. In there enter:

 ./configure --prefix=$TC/sysroot/usr --host=arm-linux-androideabi --disable-largefile --disable-thorough-tests --disable-doxygen-docs \
 --disable-xmmsplugin --disable-ogg --disable-oggtest --enable-static --disable-shared --disable-cpplibs --with-ogg=$TC/sysroot/usr \
 --with-ogg-libraries=$TC/sysroot/usr/lib --with-ogg-includes=$TC/sysroot/usr/include
 make
 make install

This will compile a static libFLAC and install it in "android-toolchain/sysroot/usr".

Testing sound

For testing sound you have to recompile Allegro for Android so it will link in the libogg, libvorbis and libFLAC libraries. First get into the buildandroid directory and enter:

 rm CMakeCache.txt
 cmake .. -DANDROID_NDK_TOOLCHAIN_ROOT=$TC -DWANT_ANDROID=on -DCMAKE_BUILD_TYPE=Debug -DANDROID_TARGET=android-15
 make clean
 make

Then copy an ogg file, e.g. fire_7.ogg, from the "allegro-5.1.11/examples/data/haiku" directory into the "buildandroid/examples/ex_audio_props.project/assets/data" directory. If you need a FLAC file for testing, download the one here: http://download.linnrecords.com/test/flac/recit16bit.aspx and put it into the "assets/data" directory above. Then open the "allegro-5.1.11/examples/ex_audio_props.c" file and add the following lines below the line "//filename = "data/welcome.voc";":

 //filename = "data/fire_7.ogg";
 //filename = "data/recit16bit.flac";

Now in the buildandroid directory you can enter

 make run_ex_audio_props

to build this example and install and run it on your connected Android device. This will play the "welcome.wav" sound. You can then comment out "welcome.wav" and uncomment one of the other files. After that enter "make run_ex_audio_props" again and the file will be played.

For wav and voc files you do not need to link in one of the libraries above, these will play without. FLAC will only play 16bit files properly.

libopenal

Download the OpenAL library from here: http://kcat.strangesoft.net/openal.html#download Unpack that and get into the openal-soft-1.16.0 directory.

Since OpenAL uses CMake you can use a cmake toolchain file called e.g. cross.cmake that you have to specify on the command line with "-DCMAKE_TOOLCHAIN_FILE=cross.cmake". This file was made by Yodhe23. It has to be put into the openal-soft-1.16.0 directory and looks like this:

#
# this one is important
SET(CMAKE_SYSTEM_NAME Linux)
#this one not so much
SET(CMAKE_SYSTEM_VERSION 1)
 
# specify the cross compiler
SET(CMAKE_C_COMPILER   /home/georg/android-toolchain/bin/arm-linux-androideabi-gcc)
SET(CMAKE_CXX_COMPILER /home/georg/android-toolchain/bin/arm-linux-androideabi-g++)
 
# where is the target environment
SET(CMAKE_FIND_ROOT_PATH  /home/georg/android-toolchain)
 
# search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
#

Then make a buildandroid subdirectory and get into there. Then enter:

 cmake .. -DCMAKE_TOOLCHAIN_FILE=cross.cmake -DCMAKE_INSTALL_PREFIX=$TC/sysroot/usr -DLIBTYPE=STATIC
 make
 make install

This will compile a static libopenal library and install it in "android-toolchain/sysroot/usr".

libphysfs

The PhysFS library source code can be downloaded here: https://icculus.org/physfs/downloads/ Unpack that and get into the physfs-2.0.3 directory.

Since PhysFS uses CMake you can use the same cmake toolchain file you made for OpenAL. Copy this cross.cmake file from the openal-soft-1.16.0 directory into this directory.

Also you have to modify the included CMakeLists.txt file to turn off CD-ROM support and enable internal zlib support. So add these lines below "ENDIF(WINDOWS)" at line 179:

IF(EXISTS "$ENV{ANDROID_NDK_ROOT}")
    SET(PHYSFS_HAVE_CDROM_SUPPORT FALSE)
ENDIF(ANDROID_NDK_ROOT)

Then enable internal zlib which is required for making a static library by adding these lines below "ENDIF(PHYSFS_NEED_ZLIB)" at (new) line 277:

IF(EXISTS "$ENV{ANDROID_NDK_ROOT}")
  SET(PHYSFS_INTERNAL_ZLIB TRUE)
  INCLUDE_DIRECTORIES(zlib123)
  ADD_DEFINITIONS(-DZ_PREFIX=1)
  SET(PHYSFS_SRCS ${PHYSFS_SRCS} ${ZLIB_SRCS})
ENDIF(ANDROID_NDK_ROOT)

Then make a buildandroid subdirectory and get into there. Then enter:

 cmake .. -DCMAKE_TOOLCHAIN_FILE=cross.cmake -DCMAKE_INSTALL_PREFIX=$TC/sysroot/usr -DPHYSFS_BUILD_SHARED=FALSE -DPHYSFS_BUILD_STATIC=TRUE
 make
 make install

This will compile a static libphyfs library and install it in "android-toolchain/sysroot/usr".

libdumb

Now we will cross compile dumb, which you can download here: http://dumb.sourceforge.net/index.php?page=downloads Unpack the archive in your HOME directory, get into the dumb-0.9.3 directory and enter:

 make CC=$TC/bin/arm-linux-androideabi-gcc AR=$TC/bin/arm-linux-androideabi-ar PREFIX=$TC/sysroot/usr CFLAGS=" \
 -fPIC -mthumb -Wno-psabi -march=armv7-a -mfloat-abi=softfp -I./include"
 
 make install

This will compile dumb and install it in "android-toolchain/sysroot/usr".

Other libraries

Freetype supports the --host=arm-linux-androideabi parameter. If you want to cross-compile a library that does not provide support for cross-compiling setting the following variables may be required:

 CC := $TC/bin/arm-linux-androideabi-gcc
 CPP := $TC/bin/arm-linux-androideabi-g++
 AR := $TC/bin/arm-linux-androideabi-ar

You could also download the library versions Google uses for Android itself from here: https://android.googlesource.com/platform/external/


Developing applications using the example directory template

To demonstrate how to build you own applications we will move the ex_ttf example into a copy of "android/example" and make the required changes in the various files.

First copy the "allegro-5.1.11/android/example" directory to "allegro-5.1.11/android/exttf.project".

 cp -r example exttf.project

Then copy the file "allegro-5.1.11/examples/ex_ttf.c" into "allegro-5.1.11/android/exttf.project/csrc/ex_ttf.c". This file includes common.c so copy that file as well. Also copy the "allegro-5.1.11/buildandroid/examples/ex_ttf.project/assets/data" directory into the "allegro-5.1.11/android/exttf.project/assets" directory. This contains the font we will need to link with the application.

Then get into the jni directory and open android.mk. In there change the following line to point to ex_ttf.c:

 LOCAL_SRC_FILES := ../csrc/ex_ttf.c

Then add the allegro_font-debug.so and allegro_ttf-debug.so libraries as a PREBUILT_SHARED_LIBRARY and as a LOCAL_SHARED_LIBRARIES. The full snippet looks like this:

include $(CLEAR_VARS)
LOCAL_MODULE := allegro_font
LOCAL_SRC_FILES := $(RELATIVE_LIB_DIR)/lib$(LOCAL_MODULE)$(LIB_TYPE_SUFFIX).so
LOCAL_EXPORT_C_INCLUDES := $(CMAKE_SOURCE_DIR)/addons/font
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := allegro_ttf
LOCAL_SRC_FILES := $(RELATIVE_LIB_DIR)/lib$(LOCAL_MODULE)$(LIB_TYPE_SUFFIX).so
LOCAL_EXPORT_C_INCLUDES := $(CMAKE_SOURCE_DIR)/addons/ttf
include $(PREBUILT_SHARED_LIBRARY)

# Declare our application.
# Source files are relative to $(LOCAL_PATH).
include $(CLEAR_VARS)
LOCAL_MODULE    := example
LOCAL_SRC_FILES := ../csrc/ex_ttf.c
LOCAL_CFLAGS    += -W -Wall
LOCAL_SHARED_LIBRARIES := allegro
LOCAL_SHARED_LIBRARIES += allegro_image
LOCAL_SHARED_LIBRARIES += allegro_primitives
LOCAL_SHARED_LIBRARIES += allegro_font
LOCAL_SHARED_LIBRARIES += allegro_ttf
include $(BUILD_SHARED_LIBRARY)

If you want to compile all .c files in the csrc folder and don't want to specify each single one, you could do something like this (all Makefile functions can be used):

LOCAL_SRC_FILES := $(wildcard $(LOCAL_PATH)/../csrc/*.c)
LOCAL_SRC_FILES := $(addprefix ../,$(LOCAL_SRC_FILES))

Then we uncomment the following line in our java program "src/org/liballeg/example/ExampleActivity.java":

 System.loadLibrary("allegro_font-debug");
 System.loadLibrary("allegro_ttf-debug");

These are dependencies which need to be loaded before the libexample.so library containing the example code. Then Android will execute the "AllegroActivity.onCreate" method which after some Allegro initialisations will call the "main()" function in the libexample.so library.

Then get into the exttf.project directory and enter:

 ndk-build
 ant debug
 adb -d install -r bin/example-debug.apk
 adb -d shell 'am start -a android.intent.action.MAIN -n org.liballeg.example/.ExampleActivity'

Since you do this for the first time you better do these commands one-by-one. You could also use the run.sh script.


If this is working ok you can proceed modifying more files as required. You can customize more files to give your application a different name than "example". If the application crashes on the Android device you'll know you made a typo.

First open the "exttf.project/AndroidManifest.xml" file and change the name of the activity to exttfActivity:

 <activity android:name="org.liballeg.example.exttfActivity"

If you change the package name, also change it it in AndroidManifest.xml. (There was a bug (https://github.com/liballeg/allegro5/issues/403) which made it difficult to change the name in early versions of the Android port but this should work fine now.)

Then rename the java file: "src/org/liballeg/example/exttfActivity.java". In there change the activity name:

 public class exttfActivity extends AllegroActivity { 

and

public exttfActivity() {
  super("libexttf.so");
}

In "jni/Android.mk" change the module name:

 LOCAL_MODULE    := exttf

In "exttf.project/build.xml" change the project name:

 <project name="exttf" default="help">

In "res/values/strings.xml" change the title of the application displayed on the android device:

 <string name="app_name">My ttf example</string>

and finally change the run.sh script to:

echo build
ndk-build
ant debug
echo install
adb -d install -r bin/exttf-debug.apk
echo start
adb -d shell 'am start -a android.intent.action.MAIN -n org.liballeg.example/.exttfActivity'

This way you can adapt the example directory to your project's name when developing your own application.

If install fails e.g. because another application of the same name is running, you can uninstall the application on the device with

  ant uninstall

When you move the example directory to a different location in your home directory, you have to adjust the settings in the "jni/localgen.mk" file and the "localgen.properties" file in the project directory.

If you want to use the same source file for Allegro on Linux and Allegro on Android you can use the following macro to compile different code depending on the target system:

 #ifdef ALLEGRO_ANDROID
 #else
 #endif

Displaying the Android keyboard

Many Allegro applications expect that a keyboard is present. Therefore you need a method to display a keyboard on the Android device when required. To demonstrate that we will use the ex_bitmap example.

First make sure that the soft keyboard is enabled. On a current Android device this will be Settings->set input method. On the emulator select Settings->Language and Input->Current keyboard->Hardware show input method.

Show the keyboard at program start

For a test you can enter the following parameter into the AndroidManifest.xml file:

 android:windowSoftInputMode="stateVisible"

This will get Android to show the keyboard when the application starts. You can get into buildandroid/examples/ex_bitmap.project and add this parameter to this line:

 <activity android:configChanges="screenLayout|uiMode|orientation" android:launchMode="singleTask" android:screenOrientation="unspecified" android:label="@string/app_name" android:windowSoftInputMode="stateVisible" android:name="Activity">

Then enter "ant clean debug install" and start the application on the device or emulator. The image of a white mouse will be displayed plus the Android soft keyboard. If you enter "+" the image will be enlarged, if you enter "-" it will shrink. Entering "1" will show the image at the original size while "f" will zoom it to the full screen width. You can remove the keyboard by selecting the Android back button but you cannot bring it back on screen then.

Show the keyboard programmatically

To be able to show and hide the keyboard programmatically you have to add methods for that to your java program and call these methods from your application which is compiled to a shared library. Lets copy our android/exttf.project directory to android/exbitmap.project and use that now. Then copy the file mysha.pcx (the mouse image) from "buildandroid/examples/ex_bitmap.project/assets/data/mysha.pcx" into the "android/exbitmap.project/assets/data" directory.


Add these lines into "src/org/liballeg/example/ExampleActivity.java", the import statements below the existing import statements and the new methods e.g. above exttfActivity():

import android.view.inputmethod.InputMethodManager;
import android.content.Context;


    public void OpenKeyBoard()
    {
	Context mContext = getApplicationContext();
        InputMethodManager imm = (InputMethodManager) mContext.getSystemService(mContext.INPUT_METHOD_SERVICE);
        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,0);
    }

    public void CloseKeyBoard()
    {
	Context mContext = getApplicationContext();
        InputMethodManager imm = (InputMethodManager) mContext.getSystemService(mContext.INPUT_METHOD_SERVICE);
        imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY,0);
    }

Then copy the ex_bitmap.c file into the csrc directory and change this line in the jni/Android.mk file to point to the new source file:

  LOCAL_SRC_FILES := ../csrc/ex_bitmap.c

and add the line:

 android:windowSoftInputMode="stateVisible"

into the AndroidManifest.xml file. If you then execute

 ndk-build
 ant clean debug install

you can run the application on your device and check if everything is working so far.


Now we will extend the ex_bitmap.c file to allow for touch input. If you'll touch the display in the upper left corner of the screen the keyboard shall be displayed and if you touch there again it will be hidden again.

First give the application a new name, in the file "res/values/strings.xml" change the title of the application displayed on the android device:

 <string name="app_name">My ex_bitmap</string>

We will not change the other files for now and thus leave the project like the exttf project.

Then add/patch the following lines into ex_bitmap.c or download the entire file [here]:

#include <allegro5/allegro_primitives.h>
#include <jni.h>

[..snip...]

JNIEnv *_al_android_get_jnienv();
void __jni_checkException(JNIEnv *env, const char *file, const char *fname, int line);
jobject _al_android_activity_object();

#define _jni_checkException(env) __jni_checkException(env, __FILE__, __FUNCTION__, __LINE__)

#define _jni_call(env, rett, method, args...) ({ \
   rett ret = (*env)->method(env, args); \
   _jni_checkException(env); \
   ret; \
})

#define _jni_callv(env, method, args...) ({ \
   (*env)->method(env, args); \
   _jni_checkException(env); \
})

#define _jni_callVoidMethodV(env, obj, name, sig, args...) ({ \
   jclass class_id = _jni_call(env, jclass, GetObjectClass, obj); \
   \
   jmethodID method_id = _jni_call(env, jmethodID, GetMethodID, class_id, name, sig); \
   if(method_id == NULL) { \
   } else { \
      _jni_callv(env, CallVoidMethod, obj, method_id, ##args); \
   } \
   \
      _jni_callv(env, DeleteLocalRef, class_id); \
})

[..snip...]
	
bool keyboard_displayed;

[..snip...]

al_init_primitives_addon();
if (!al_install_touch_input()) {
   abort_example("Could not init touch input.\n");
}

[..snip...]

al_register_event_source(queue, al_get_touch_input_event_source());

[..snip...]

       if (event.type == ALLEGRO_EVENT_TOUCH_BEGIN) {
         if ((event.touch.x<160) && (event.touch.y<160)){
	   if (!keyboard_displayed){
	      _jni_callVoidMethodV(_al_android_get_jnienv(), _al_android_activity_object(), "OpenKeyBoard", "()V");
	      keyboard_displayed=1;
	   } else {
	      _jni_callVoidMethodV(_al_android_get_jnienv(), _al_android_activity_object(), "CloseKeyBoard", "()V");
	      keyboard_displayed=0;  
	  }
	}
      }

again, enter:

 ndk-build
 ant clean debug install

and run the application on your device.

In this example the methods defined in the "src/org/liballeg/example/ExampleActivity.java" file are called from the ex_bitmap.c code using the JNI function "CallVoidMethod". The CallVoidMethod function invokes an instance method that has void return type. You pass the object, method ID and the actual arguments to CallVoidMethod. This function is wrapped into macros here. There are further functions for methods with different return types like integer, char, boolean or fully-qualified-class. Macros for these can be found [here] which is taken from [Todd Cope's project].


Log or debug applications

An apk file such as "exttf-debug.apk" is just a compressed archive that you can open with ark or 7zip. This way you can check if all the required libraries are included and if all your files in the res directory are present.

Logging with logcat

In normal C programs you can use printf to send messages to the console. On Android by default these are sent to "dev/null" and there are different options for sending messages.

Android will log all sorts of messages in a log file. You can print this log file to the console by entering "adb logcat". The logcat command will not terminate but wait for further messages being generated and print these to the screen. You have to enter CTRL-C to terminate logcat.

At first you should clear the old logfile by entering:

 adb logcat -c

if you then enter

 adb logcat

lots of messages will be printed to the screen. So you will have to filter these. Each message has a tag and a priority. You can filter for a tag by entering the tag before the colon and the priority after the colon. Wildcards which are specified with "*" are allowed too. If you enter:

 adb logcat AllegroActivity:* *:S

will filter the output of logcat to all messages that have the tag "AllegroActivity" and any priority while putting all other tags to the silent priority thus suppressing them from being printed. If you run an Allegro application before the log will contain several messages that the AllegroActivity.java program did output. You can also send the output to a file:

 adb logcat -f mylogfile

or use grep:

 adb logcat | grep -s "AllegroActivity"

If you always test for the same tags you can put these into a variable:

 export ANDROID_LOG_TAGS="AllegroActivity:* *:S"


The messages for the log file are generated differently in java programs and JNI applications. In a java program you would put the command:

 Log.d("AllegroActivity", "onStart.");

Here AllegroActivity is the message tag while onStart is the message to be printed to the log file.


To support messages in an Allegro application you have to include the liblog.so library in the jni/Android.mk file:

 LOCAL_LDFLAGS += -L/home/georg/android-toolchain/sysroot/usr/lib -llog

Then in the Allegro program you have to include the header file:

 #include <android/log.h>

and to print a message use:

 __android_log_print(ANDROID_LOG_INFO,"AllegroActivity","Hello from line 244");

or

 __android_log_print(ANDROID_LOG_INFO,"NewGameActivity","Width value is: %d",(int)width);

You will usually not use AllegroActivity as a tag name in your program but choose a different tag name to be able to filter on that.

It is possible to redirect stdout/stderr to the log file but this does not seem to work with JNI or Allegro applications.

Debugging with GDB

You can also use gdb to debug your Allegro programs. This will require the device to be rooted or to use run-as with set-uid root (see issue 58373) which does not work well. Better test your application with gdb using an emulator which does not need to be rooted. How to start the emulator has been already described in a section above.

The AndroidManifest.xml file needs the line "android:debuggable=true" which it usually already has and the application needs to be compiled with:

 ndk-build -B NDK_DEBUG=1

Now you have to install the application in the emulator:

 ant clean debug install

Then get gdb to start your application by entering in the project directory:

 ndk-gdb --start --verbose

This script will load the application in the emulator and then start gdb. The application will not start without a command entered with gdb first. So bring the application to the foreground in the emulator and the message "Waiting For Debugger" will be displayed. Then begin by setting a breakpoint to the main() function:

 break ex_bitmap.c:main

If you want to jump right to a line of interest (here 105) you can enter:

 b ex_bitmap:c:105
 or
 break ex_bitmap:c:105

This will produce the warning:

 warning: Make breakpoint pending on future shared library load? (y or [n])
 enter y

since the Allegro application which is compiled to a shared library is not loaded yet. Just enter "c" or "continue". The program will generate some warnings and run until the specified breakpoint is reached. Then you can enter "s" or "step" to have the next line executed. Usually you do not want to step into the internal Allegro functions so use "n" or "next" instead when stepping through your program.

The command "l" or "list" will display the next ten lines in the code. You can also enter "l 100" which will list the lines 100 to 120. To see the value of the "filename" variable enter "p filename". To display the value of the "argc" variable in hex enter "p /x argc".

If your program has crashed use the "bt" or "backtrace" command which will list the commands executed before the crash. This way you can see what command caused the crash.

To stop the application running in the emulator enter "kill". Then enter "q" or "quit" to exit gdb.

You can also start the application on the emulator first and then run ndk-gdb. The application will usually be in a loop waiting for events then when gdb starts. If you then set a breakpoint to a statement within this loop, you can start tracing as soon as the application has executed this command. You could remove all breakpoints entering "d" and then add a new breakpoint or step through the program with "s" or "n".

The command

 ant uninstall

will remove the application from the emulator.


Screenshots and recording sessions

adb has two additional nice features: it supports to make screenshots of the running application or to record a demonstration of the application on the device as a mp4 file.

To make a screenshot of your program use the screencap command. Just enter:

 adb shell
 screencap /data/local/tmp/screen.png
 exit
 adb pull /data/local/tmp/screen.png .

This enters the shell, lets screencap write the screenshot into the screen.png file on the emulator or device, exits the shell and then uses the pull command to copy the screen.png file from the device to the the current directory which is specified by the dot on the command line. With the adb pop command you could move files from your PC to the android device.

To record a screen session start the application on your device and enter:

 adb shell screenrecord /data/local/tmp/demo.mp4

then operate the application as intended and after that terminate the recording by entering CTRL-C. After three minutes it will terminate automatically if not changed by the --time-limit parameter. Then copy the file to the current directory (".") on your PC:

 adb pull /data/local/tmp/demo4.png .

You can increase the quality of the recording with the --bit-rate parameter and specify the desired screen size with the --size parameter:

 adb shell screenrecord --bit-rate 8000000 --size 640x480 /data/local/tmp/demo.mp4

Mouse emulation mode

If you want to port an existing Allegro application to Android you may not want to change your mouse input code. For this Allegro features "mouse emulation mode" which will translate touch input events to mouse events. Here is a snippet what you can enter into your code to enable this mode:

  #include "allegro5/allegro_android.h"
  .
  .
  .
  .
  if(!al_install_touch_input())
  {
     __android_log_print(ANDROID_LOG_INFO,"AllegroActivity","Error!, Failed to install touch_input.");	
  } else {
     __android_log_print(ANDROID_LOG_INFO,"AllegroActivity","Installed touch_input successfully.");	
     
     al_set_mouse_emulation_mode(ALLEGRO_MOUSE_EMULATION_5_0_x);
     
     a_event_queue_m = al_create_event_queue();
     if(a_event_queue_m == NULL)
     {
      __android_log_print(ANDROID_LOG_INFO,"AllegroActivity","Error!, Failed to create touch_input event queue.");	
     }    
     al_register_event_source(a_event_queue_m, al_get_touch_input_mouse_emulation_event_source());
   }

If you touch the screen with your finger, this will result in a left button click event. If you lift your finger again it will generate a left button release event. When you touch the screen and move your finger you will drag the mouse, e.g. to move a window over the screen.

References

Allegro readme file for Android
https://github.com/liballeg/allegro5/blob/5.1/README_android.txt
Android developer site
http://developer.android.com/index.html
http://developer.android.com/guide/components/fundamentals.html
http://developer.android.com/ndk/guides/index.html
ant
https://developer.android.com/tools/building/building-cmdline-ant.html
http://ant.apache.org/
adb
http://developer.android.com/tools/help/adb.html
adb shell and screenshots
http://developer.android.com/tools/help/shell.html
Reading and writing logs
http://developer.android.com/tools/debugging/debugging-log.html
ndk-gdb
https://developer.android.com/ndk/guides/ndk-gdb.html
gdb cheat sheet
http://www.givemefish.com/ArticlesAndBook/CheatSheets/GiveMeFish_CheatSheet_gdb.php
JNI
https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html
http://www.ibm.com/developerworks/java/tutorials/j-jni/j-jni.html
https://newcircle.com/bookshelf/java_fundamentals_tutorial/_java_native_interface_jni
http://imicrov.com/small-tech/android-development/jni-tutorial