Custom Drawn Interface/Android

From Free Pascal wiki
Jump to navigationJump to search

Go back to Custom Drawn Interface

Architecture

LCL-CustomDrawn-Android utilizes a minimal Java application which communicates with our Pascal library and sends all events to it and also obeys commands from it. The communication is done via JNI as supported by Google. The controls are not native, instead they are all drawing using TRawImage+TLazIntfImage+TLazCanvas and events and the painting are clipped using LazRegions. The drawing itself is done in Pascal using jnigraphics to draw on a Bitmap Java object which is then drawn by the minimal Java activity on a SurfaceView.

Our previous and short-lived attempt to write an LCL Interface for Android (LCL-Android) utilized a non-standard method of using native executables which communicated with a Java machine via Pipes. This method was abandoned because it was considered unsupported by Google. It is considered obsolete and people should use instead LCL-CustomDrawn-Android. This older interface was documented in Android Interface.

Roadmap

  1. Build the set of Lazarus Custom Drawn Controls
  2. Initial bindings for the Android APIs
  3. Create an application to automatically generate the bindings
  4. Start the new widgetset
  5. Implement support for JNI
  6. Merge the Lazarus Custom Drawn Controls into the LCL and use them to implement all basic controls
  7. Add text support for Android
  8. Implement control client area scrolling
  9. Add text support in X11
  10. Add DPI awareness and adaptation in the LCL

Using the Android SDK, Emulator and Phones

Android Interface/Using the Android SDK, Emulator and Phones

Android Programming

Android Interface/Android Programming

Configuring the Free Pascal Compiler for Android

Building the compiler yourself

See Setup_Cross_Compile_For_ARM and make sure to use the option OPT="-dFPC_ARMEL" for building the compiler.

Using the pre-compiled compiler

A pre-compiled compiler is provided for convenience for users. The following steps were tested in Mandriva Linux 2010.0 and 2010.1:

Required Environment

  • The latest stable FPC installed in the system via the RPM / DEB / TAR package

Step 1 - Install the cross-binutils

For Mandriva Linux the RPM package containing arm-linux-as, arm-linux-ld, etc, which are the cross-binutils can be found here: http://rpm.pbone.net/index.php3/stat/4/idpl/14252825/dir/mandriva_2010/com/cross-arm-binutils-2.20.51.0.4-2mnb2.i586.rpm.html

Just download the RPM package and install it using:

rpm -ivh cross-arm-binutils-2.20.51.0.4-2mnb2.i586.rpm 

In Mandriva Linux 2010.0 the dependencies won't match, as the package is for 2010.1, but one can simply ignore this problem and it works fine using --nodeps:

rpm -ivh --nodeps cross-arm-binutils-2.20.51.0.4-2mnb2.i586.rpm 

For other distributions use the corresponding package, or else read the instructions for building the cross-binutils yourself at Setup_Cross_Compile_For_ARM

Step 2 - Configure the cross-binutils

The assembler needs a parameter to tell it which ARM ABI to use. A choice which works good is EABI-5, which is compatible with all Android devices available as of Jan 2011. To set this, we will rename the original assembler and substitute it with a shell script which passes the desired parameter. These commands will do it:

su
mv /usr/bin/arm-linux-as /usr/bin/arm-linux-as_org
gedit /usr/bin/arm-linux-as

Now paste into the editor this code:

#!/bin/sh
/usr/bin/arm-linux-as_org -meabi=5 $@

And don't forget to then make it executable:

chmod 755 /usr/bin/arm-linux-as

Step 3 - Install the Free Pascal Cross-Compiler

At this point the pre-compiled FPC can be download from here: http://sourceforge.net/projects/p-tools/files/Free%20Pascal%20for%20ARM/

Then use these commands to install the pre-compiled Free Pascal cross-compiler into /usr:

[felipe@localhost Programas]$ ls -l
total 20664
-rw-rw-r--  1 felipe felipe 17098552 2010-10-25 08:17 fpc-2.5.1.arm-linux.tar.gz
[felipe@localhost Programas]$ su
Password: 
[root@localhost Programas]# cp fpc-2.5.1.arm-linux.tar.gz /usr/
[root@localhost Programas]# cd /usr/
[root@localhost usr]# tar -xvf fpc-2.5.1.arm-linux.tar.gz 
[root@localhost usr]# ln -s /usr/lib/fpc/2.5.1/ppcrossarm /usr/bin/ppcrossarm

Step 4 - Verify if your Cross-Compiler works

If you made no errors in the previous steps, it should work, so try to call it like this:

[felipe@localhost Programas]$ /usr/bin/ppcrossarm

If this command works and fpc shows its options, then you configured the cross-compiler correctly, if not, then try to find out if your symbolic link points to a correct location with this command:

[felipe@localhost Programas]$ ls -ls /usr/bin/ppc*

Now we are ready to compile Android applications using the Lazarus IDE! Configuring the fpc.cfg file isn't necessary, the old compiler will automatically find the new compiler and it's object files.

Compiling the example LCL Android Application

Step 1 - Download the source code

The source code of the example is located in lazarus/examples/androidlcl/androidlcltest.lpi

Step 2 - Build the project using the Lazarus IDE

Configuring Lazarus to use the new compiler should not normally be necessary because fpc should be able to find the symlink created, but if you have trouble in this part you can try to hard code the compiler path to use the new crosscompiler. To hardcode the compiler path in cause of trouble go to the menu "Tools->Options" and change the "Compiler Path" to "/usr/bin/ppcrossarm"

Step 3 - Build the APK

Go to the command line and issue these commands:

 cd lazarus/examples/androidlcl/android
 ant debug

The APK will be located in lazarus/examples/androidlcl/android/bin

Step 4 - Install the APK in your phone and run it

You should see this:

Custom drawn android test1.png

How to create an LCL Android Application

To create a new LCL-CustomDrawn-Android application simply copy all of the file structure and build and java files from the example project called "androidlcl". This example can be obtained from the Lazarus source tree in lazarus/examples/androidlcl

Then you will need to modify the build files to change them to your new project name and your new Java package name.

Step 1 - Creating the LPI

You need a separate LPI at the moment for the Android version of the application but all the rest of the code can be shared. Create it using the template for a "Library" and then adapt the code from the example located in the lazarus source code in lazarus/examples/androidlcl

You need to adapt the exported JNI method names to your Android Package Name.

Step 2 - Building the library

First of all, build the Pascal executable without debug information. This debug information is not so useful in Android and makes the executable much bigger. Open the menu Project->Project Options and set the build mode, widgetset, architecture and operating system targets, as shown in these screenshots:

Android project options 1.png

Android project options 2.png

Android project options 3.png

Step 3 - Create the Android project structure

Besides the LCL project building, such as configuring a proper LPI and having a library main project file, one also needs to add all of the android project structure. Simply copy from the example project in lazarus/examples/androidlcl and adapt it to the new project. Things to change are the path to the SDK, the package name. The package name needs to be updated in the build files, in the directory structure android/src/packagename, in the activity java source code and also in the main library pascal source in the exports section.

Building an LCL Android application with debug info

It is useful to add another Android build mode which has debug info. Use all of the same options as shown above, except for the debug information:

Android project options 4.png

Oh no! My LCL Android application doesn't work

There are various reasons why the app may not work. The most important thing to do when an app doesn't work is to open the logcat and see what the log says. This can be done by running this command line command:

./adb logcat

And then test one of the hipotesis in the next subsections.

The Pascal executable was compiled for a wrong architecture, operating system and/or widgetset

This is the leading cause of executables not running. Always verify that you compiled the program to the "android" widgetset, "linux" operating system and "arm" architecture. This is done by going into the menu Project->Project Options. Then set these in the dialog all options as explained in this section:

How_to_build_an_LCL_Android_application

To check if you library is arm-linux or not, execute the following commands:

cd libs/armeabi
ls -l
file liblclapp.so
ldd liblclapp.so

If it mentions anything like 80386 or gtk, then your program was compiled for linux-x86 and gtk2, not for Android like it should.

My Pascal application crashed. How to get a stacktrace?

If a Pascal application crashes you should use the command "adb logcat" to obtain the stack

The indispensable build options

  • -Xd This build option is indispensable when cross-compiling from x86-linux to Android or else FPC will try to link the application against for example /usr/lib/libc.so instead of the libc.so in the NDK, even if you specify a -Fl library path
  • -CpARMV6 This build option is indispensable because code generated for older ARM versions is unsupported by Android and might crash in some devices. See http://groups.google.com/group/android-ndk/browse_thread/thread/ba542483f062a828
  • -dAndroid in the package LCLBase.lpk
  • -Parm -Tlinux for the process and target operating system
  • -Fl should contain the path to the NDK directory with the target link shared object, such as libc.so, liblog.so, libjni.so, etc

Free Pascal Bugs on Android Support

The following summarizes the state of Android Support in Free Pascal:

We are in contact with FPC developers to fix the situation as can be seen in: http://mantis.freepascal.org/view.php?id=20726

Development Notes

The misterious JNI Crash

See the thread: http://groups.google.com/group/android-ndk/browse_thread/thread/ba542483f062a828

The problem was that vm^^.GetEnv would crash in HTC Wildfire, Alcatel and in the emulator with SIGILL but not in Xperia Mini, HTC Desire HD, Motorola Atrix and other smartphones.

The answer was that one needs to specify -CpARMV6 when building because older instructions might fail in some devices

NDK Libraries available in Android 2.2 (API level 8)

LCL-CustomDrawn targets Android 2.2+ and in this API level the following libraries are supported by the NDK:

  1. libc.so
  2. libdl.so (linker)
  3. OpenGL ES 1
  4. OpenGL ES 2
  5. libjnigraphics.so
  6. liblog.so
  7. libm.so
  8. libz.so
  9. libthread_db.so
  10. libstdc++.so

LCL-CustomDrawn-Android uses libjnigraphics.so and liblog.so at the moment.