12. Using AJIS for Android

12.1. Creating and Building an Android Ada/Java Project

12.1.1. Audience

This document is intended for users already somewhat familiar with Eclipse, the Java Development Tools (JDT), the Android Development Tools (ADT), and GNATbench. Some familiarity with AJIS may also be useful.

12.1.2. Before You Begin

Install the Ada cross-compiler toolchain for Android.

Install AJIS for Android (remember to set the path and classpath). Make sure that the version of AJIS matches the cross-compiler date and the minimum requirements for the GNATbench AJIS integration.

Install the “make” utility if it is not already installed. Windows users can download the GNU version via the “Miscellaneous/Utils” section of the “Downloads” page on GNAT Tracker. The file to download is named “gnumake-3.79.1-pentium-mingw32msv.exe” or something similar (i.e., the version number could be different). Once downloaded, rename the file to “make.exe” and put it somewhere on your path.

Disable automatic builds, at least until the new Ada project has been fully configured. This is accomplished via the Project -> Build Automatically menu option. The option is disabled when there is no checkmark present.

Consider setting Eclipse to refresh resources on access (as of Eclipse 3.7). This is a workspace preference. It is changed via the Window -> Preferences menu; the specific property is on the General / Workspace page. Occasionally you will still need to manually refresh the Java projects that have corresponding Ada interfaces generated, but this preference can help.

12.1.2.1. Important

Before you create a new Ada project for Android, you must first create an Android project using the Android Development Tools (ADT) within Eclipse. This step is mandatory when creating Ada projects for Android, and is thus different from the native AJIS usage.

The Android project must have a “libs” folder which the ADT analyzes such that its contents are included in the “apk” file.

12.1.3. Create the Client Android Project

For the sake of this tutorial we will assume that no client Android project exists. Therefore, we will create a new Android ADT project as an “application” project using the wizard via File -> New -> Project and then selecting Android Application Project as shown below.

../../_images/android_new_project_wizard.png

This brings up the first wizard page. As shown below, we have supplied the application name, and doing so has automatically filled in the other two names.

../../_images/android_wiz_page1.png

We also chose the Android SDK versions in that dialog page. Version 4.1.2 and above are known to work. The choices indicated are arbitrary, although a Minimum Required version of 4.x is convenient in that it prevents the automatic creation of a compatibility project.

All the defaults in the subsequent dialog pages within the wizard will suffice, so simply press Next until the end is reached.

Press Finish.

If you have disabled automatic builds (as we suggest) there will be an error indicated on the project node in the Navigator. This is because the project source files reference some resources that are not generated until the build first occurs. Just build the project and the error will disappear.

../../_images/android_adt_project_created.png

You can close the “activity_main.xml” file that was automatically opened.

12.1.4. Create an Ada Project for Android

Once the client Android ADT project exists, you are ready to create the new Ada Android project.

First, open the New Project Wizard with File -> New -> Project, then select “Ada Project for Android” under the Ada category.

New Project Wizard with Android Ada project selected

In the resulting wizard page, name the new Eclipse project.

naming the new Android project

Then on the next wizard page specify the GNAT project unit name. The names can be the same but need not be. However, the GNAT project unit name must be a legal Ada identifier.

the illegal GNAT project unit name for new Android project

We thus change the project unit name to “Ada_Hello”.

the legal GNAT project unit name for new Android project

On the next page, specify the name for the dynamic library that will contain your Ada code. This dynamic library will be produced when the Ada project is built and is used by the client Java project. We have arbitrarily named the file “adahello.”

../../_images/android_wiz_libname.png

On the next page, specify the names of the folders where the AJIS-generated code will be placed. Enter two, one each for the Ada and Java code. The names may also be paths to the folders. Folders that do not exist will be created by the wizard. Relative paths are treated as subdirectories of the Eclipse project root within the workspace. The defaults are as follows.

../../_images/android_binding_dirs.png

We take the defaults and press Next.

On this next page specify the name of the Java package that will contain the generated Java code. Alternatively, you can perform this step by editing this Ada project’s properties later, after the wizard completes. We have specified “com.example” since that is always available.

../../_images/android_base_package_name.png

Then select the Android Ada cross-compiler used to build the project. If you do not see the cross-compiler listed, press the “Scan” button on the right and wait for it to appear. Selecting it will appear as shown below. Note in particular the checkmark next to the cross-compiler, and the lack of a checkmark next to any others.

../../_images/android_toolchain_selection.png

Next select the existing client Android ADT project that will use the Ada dynamic library created by this new Ada project.

../../_images/android_client_project_empty.png

Click “Select Project” to open a project selection dialog and choose an open Android ADT project in the current workspace. Then press OK.

The selected project will then appear in the wizard dialog page. We have chosen the Android ADT project “Ada Java Demo” created earlier.

../../_images/android_client_project_selected.png

Press Finish and the wizard will complete. The new Ada project will appear as shown below. We have expanded all the folders to show the new content.

../../_images/android_new_project_in_explorer.png

Do not delete any of these files. Those that can be modified contain a comment to that effect.

At this point, the new Ada project is almost, but not quite, ready to be built. Ada sources must be specified so that the corresponding Java interfaces can be generated by AJIS. These Ada sources don’t necessarily exist yet – certainly not within the project we just created – so we specify them after the wizard completes.

12.1.5. Final Project Setup Steps

The last steps to be taken are to 1) populate the project with Ada sources, and 2) select a subset of them to be used as interfaces for the client Java code. These interface packages will be passed to AJIS (ada2java) during the Ada project build so that corresponding Java code is produced to call the Ada code.

12.1.5.1. Populating with Ada Sources

The wizard creates an empty directory named “src” to contain Ada source files. Use of this directory is optional; you could use others, or just use the project root. We suggest using explicit source directories, however, for the sake of keeping everything simple. New source directories can be created via the GNATbench New Source Folder toolbar button. Using that facility will automatically update the GNAT project file contents so that the resulting source directories are known to the builder.

Once the source folders are to your liking you may use the editor to create the Ada source files. Alternatively, existing source directories and files outside the workspace may be imported through the Eclipse Import wizard. Imported source directories must be specified manually in the GNAT project file since the New Source Folder wizard is not used to create them.

For the purposes of this simple tutorial we will write the code directly, so we will use the Ada perspective for convenience. (Selecting perspectives is accomplished via the Window -> Open Perspective menu or the “Open Perspective” icon on the toolbar at the upper right.) The perspective controls the menu entries available.

To create a new Ada source file, right-click on the “src” folder in the Explorer and select the New -> Ada Source File menu entry. Invoking it that way will fill in the “src” folder as the container for the new file.

../../_images/android_new_ada_source_file_dialog.png

We have named the file “ada_hello.ads” in the text entry field. Press Finish and the editor will be opened.

In the following image we have entered the text of an Ada package declaration that exports a function.

../../_images/android_new_ada_source_spec_editor.png

If you want to use the same code you can copy the following into the editor:

package Ada_Hello is
   function Msg return String;
end Ada_Hello;

Repeat the above file creation steps to create a new source file for the package body. Name the second new file “ada_hello.adb” as per the GNAT default naming scheme. We have entered the text shown below.

../../_images/android_new_ada_source_body_editor.png

If you want to use the same code you can copy the following into the editor:

with Ada.Calendar.Formatting;

package body Ada_Hello is

   use Ada.Calendar;
   use Ada.Calendar.Formatting;

   function Msg return String is
   begin
      return "Hello from Ada at " & Image (Clock);
   end Msg;

end Ada_Hello;

This one package will suffice for the Ada portion of the demonstration.

12.1.5.2. Selecting Interface Files

The user must select the Ada specification files that will be used by the Java application in the client ADT project. The AJIS tools create Java source files corresponding to the selected Ada specification files. Select only the files which are needed directly in Java.

To do so, open the Project Properties for the project. (Right-Click -> Properties or Alt+Enter). Expand the category “GNATbench Properties” and select “Ada/Java Interface Files”.

../../_images/android_no_interfaces_selected.png

Click “Add File” and an operating-system-dependent file selection dialog will appear. Navigate to the location of the Ada specification files.

../../_images/android_interfaces_browsing.png

Select one or more files and press “OK”. The selected files will appear in the list.

../../_images/android_one_interface_file.png

Press OK when all the files are specified. Our one Ada package declaration will suffice here.

At least one Ada interface file must be selected before the project can be successfully built.

12.1.6. Building the Ada Project

Open an Ada-specific Eclipse view named the “Scenario Variables” view, if it is not already visible. By default you will be in the Java perspective when doing Android development so the view will not be open automatically. You may want to leave this view open since you will want it whenever setting up new Ada for Android projects. To open this view, do the following:

  1. Select “Window -> Show View -> Other...”
  2. Expand the “Ada” category
  3. Select the “Scenario Variables” view
  4. Press OK

In the newly-opened Scenario Variables view there will be a list of Ada projects and their corresponding variables (if any). Your Ada for Android project will show three or four of these variables. A little pull-down list control will appear next to any given value if you click on it, showing all the possible values. Just select the desired value and it will be applied.

AJIS for Android installation contains the ajis library binaries for the arm-linux-android platform. If building the Ada project, you get “i-java.ads or ajis.ads must be compiled” error messages, set the scenario variable name “External_Build” to “false.” This setting will allow the AJIS library to be rebuilt if necessary. Once it is rebuilt with the right toolchain you can set the scenario variable back to “true” or just leave it set to “false” all the time; it will only be rebuilt if necessary.

The Scenario Variable view is shown below, with the initial value for External_Build (i.e., “true”). Note that the default location for the Scenario Variables view is in the same group as the Problems view. We moved it underneath the Explorer and Navigator for convenience.

If you want to debug the application select “Debug” for the “Build” scenario variable. For this tutorial we will leave it set to “Production.”

Now the project is ready to be built, e.g., with Project -> Build Project. Doing so will invoke AJIS to generate the Java sources corresponding to the Ada packages you specified in the wizard, compile the Ada code as usual, and generate the dynamic library. It will then copy that library into the ADT project so that the library will be included in the “apk” file deployed.

A successful first-time build will appear in the Console as follows. Later builds will only compile what is necessary so they may contain less. Note the last line that copies the library into the ADT project.

../../_images/android_successful_build_console.png

If we expand the binding/generated_ada/lib directory we will see the “libadahello.so” dynamic library we just built.

../../_images/android_new_lib_in_explorer.png

Next, refresh the ADT project, whose linked resources have been changed by the Ada build. (This can be accomplished by selecting the project in the Navigator or Explorer and pressing F5.)

In the “generated_java” source folder of the ADT project there are now several packages, some of which correspond to the Ada packages selected as interfaces files (in this example, the Java package com.example.Ada_Hello). The others are always created and are responsible for loading the library and interfacing between Ada and Java. The source file “Ada_Hello_Package.java” contains the class used by the client Java code to call the Ada code for our demonstration.

../../_images/android_adt_refreshed.png

We can also see that the Ada library has been copied to a subdirectory of the Android ADT project “libs” directory.

../../_images/android_new_lib_in_adt.png

At this point a Java application can be written with some sources referencing the Ada code through the generated Java interface code.

The Android code to be modified for our tutorial is the “MainActivity.java” file. We need to import the Java code interfacing to Ada using the normal Java “import” statement. The usual JDT tools can facilitate that, as ususal.

../../_images/android_mainactivity_import.png

In our example, we will add this code to the “onCreate” function:

TextView view = new TextView(this);
view.setText(Ada_Hello_Package.Msg().toString());
setContentView(view);

This Java code calls the Ada code to get a message and then displays it on the Android screen.

You will need to resolve the TextView reference, easily accomplished via the JDT ctrl-shift-O command shortcut.

The code will appear as follows, once completed.

../../_images/android_mainactivity_completed.png

The Java ADT project can now be built using the standard Eclipse menus.

To run the new Android app, select Run -> Run Configurations and create a new launch configuration (or simply use an existing launch configuration if you already have one for the project). In the following, we have done so and then selected the “Android Application” category.

../../_images/android_new_launch_config_1.png

We then create a new configuration of this kind by clicking on the “New” icon. Then we fill in the name of the configuration, arbitrarily naming it “Ada Java Demo,” and press the Browse button for the “Project:” entry pane.

../../_images/android_new_launch_config_2.png

Clicking on the “Target” tab shows the following fields. We have already created an Android simulator using the ADT, named “myDroid”.

../../_images/android_new_launch_config_target.png

Take these default selections and press Run. Be prepared to wait because the simulator can take a while to initialize.

When run on the simulator, the application appears as follows. If the simulator appears to be initialized and running but the demo program does not appear, press the Menu button on the simulator.

../../_images/android_demo_execution.png

Congratulations! You have created and built an Ada/Java application for Android platforms.

12.2. Usage Notes

An Ada Project for Android adds support for Android applications to the Ada Project for AJIS functionality. For the most part, use and operation is identical to that of the AJIS integration. What follows are the differences specific to Android applications.

12.2.1. Before You Begin

In addition to the native compiler, the Ada Android cross-compiler must also be installed.

The date for the AJIS tools must be the same as that of the cross-compiler.

The version of gprbuild should also be no older than the cross-compiler.

Building these projects requires the “make” utility to be installed. Windows users can download the GNU version via the “Miscellaneous/Utils” section of the “Downloads” page on GNAT Tracker. The file to download is named “gnumake-3.79.1-pentium-mingw32msv.exe” or something similar (i.e., the version number could be different). Once downloaded, rename the file to “make.exe” and put it somewhere on your path.

12.2.1.1. Important

Before you create a new Ada project for Android, you must first create an Android project using the Android Development Tools (ADT) within Eclipse. This step is mandatory when creating Ada projects for Android, and is different from the native AJIS usage.

The Android project must have a “libs” folder which the ADT analyzes such that its contents are included in the “apk” file.

You must set the “OS” scenario variable to “linux” permanently. Initially, the “External_Build” variable should be set to “false.”

12.2.2. Creating the New Ada Project for Android

A new Ada project for Android development is created in almost exactly the same manner as when creating a new Ada project for native AJIS use. The differences are that 1) a different new-project wizard is invoked, 2) a cross compiler is used instead of a native compiler, 3) the client project specified to the wizard must already exist, and 4) this client project must be an Android project rather than a simple Java project.

As with AJIS projects, the new Ada project is created by invoking the New Project Wizard with File -> New -> Project, but then selecting “Ada Project for Android.” (This wizard is also under the Ada category.) Walk through the wizard pages, selecting the Android Ada cross-compiler instead of the native Ada compiler, and specifying a client Android project instead of a Java project.

Building the new Ada project is invoked as usual, via the Build Project menu entry. As before, the builder will invoke AJIS to generate the Java sources corresponding to the Ada interfaces specified to the wizard, will compile the Ada code, and will link it into a dynamic library. Unlike the AJIS project case, the builder will also copy the resulting library into a subdirectory of the “libs” folder so that the library will be included in the project “apk” file deployed to the Android device.

As usual, the builder will only perform those steps that are actually necessary, based on the state of the project.

12.2.3. Android Project and Ada Project Relationships

In addition to the application library built from the Ada project, the client Android project must include the ajis.jar file and the Java source code generated from the Ada interface files. The ajis.jar file must be included in the “libs” directory of the Android project. In contrast, the Ada application library must be located in a subfolder of the “libs” folder so that it will be included in the “apk” file.

Creating and then building the Ada project will cause these requirements to be met automatically. The ajis.jar file is automatically included in the “libs” directory when a client Android project is selected, either during the wizard execution or when set manually via the properties editor. At the same time, a new source folder is created and linked to the directory containing the generated Java. During a build of the Ada project, the resulting application library is copied into the appropriate subfolder of the “libs” directory in the client Android project.

12.2.4. Changing the Project Relationships

As with other AJIS integration projects, a previous configuration cannot be undone automatically, so the user must undo any previous configurations beforehand. Undoing the previous configurations is similar to that of any other AJIS integration project.

First, the invoke the Java Build Path dialog. There, remove the linked source folder containing the generated Java code from the path. Also remove ajis.jar from the list of libraries.

Next, the user must delete the linked source folder from the client Android project using the Navigator or other resource viewer.

Finally, unlike AJIS projects, the user also must delete the copy of ajis.jar in the “libs” folder of the Android project as well as any directories created by the Ada build (usually something matching armeabi*).

12.3. Debugging Mixed Ada-Java Android Applications

You can use Eclipse to debug applications written in a mixture of Ada and Java. This chapter explains the steps and tools required for doing so.

12.3.1. Before You Begin

We will illustrate mixed debugging using the “Lunar_Lander” Ada-Java example that comes with the Android Ada cross-compiler. The text that follows assumes prior successful build of that example, as well as execution on a simulator. See the readme file accompanying the example for the steps required. The examples is based on one that comes with the Android SDK so the SDK must be installed.

For the sake of debugging native Ada code you must also download and install the Native Development Kit (NDK). The NDK can be downloaded from the same web page used to download the SDK:

http://developer.android.com/sdk/installing/installing-adt.html

On the left of that page, use the “Download the NDK” link to download and install the NDK. Put the new installation on your path for convenience later, when invoking a script from the NDK.

You will also need to install Cygwin on Windows machines, for the sake of executing a shell script.

12.3.2. Configure the NDK

This configuration need only be performed once per NDK installation.

Make a copy of the file named “ndk-gdb” located in the root of the NDK installation directory. Name the copy “ndk-gdb-eclipse” and leave it in the NDK root as well.

Edit the new file to either comment-out, or remove entirely, the last line of the file ($GDBCLIENT -x `native_path $GDBSETUP`). That line invokes GDB but we need to launch it via Eclipse, instead.

12.3.3. Configure the Projects

Ensure your Ada project has been built with debugging information included. This is controlled via the “Build” scenario variable. If necessary, change “Build” from “Production” to “Debug” in the Scenario Variables view and rebuild the Ada project.

Ensure debugging is enabled for the Java project. This is controlled via the “Debuggable” flag located in the AndroidManifest.xml file. If necessary, set the flag to “true” via the pull-down in the manifest file editor, save the file, and rebuild the Android Java project. If the builder complains that the value should not be hard-coded you will need to change the Android Lint preferences. To do that, right-click on the project node in the Packager Explorer and select Properties from the contextual menu. In the result dialog box, select “Android Lint Preferences” on the left, to select that page. There, in the search text entry pane at the top, enter “debug” and you will see a couple of entries to mention that term. One of them is “HardcodedDebugMode” under the Security subsection. Click on that line to select that preference. Then, at the lower right, change the Severity pull-down list to be Warning, or Ignore. Finally, press the OK button to close the dialog. Now you can edit the Debug flag in the manifest and subsequent builds will not flag that as an error.

12.3.4. Debugging the Projects

(Note that these steps are required the first time you want to debug Ada code but are not required every time. See the next section for those steps that must be performed every time.)

1. Set a breakpoint on the first line of Physics_Package.Update_Vehicle() in the generated Java source code folders located (via reference) in the Java project. This breakpoint can really be set anywhere after the call to System.loadLibrary but must be hit before any Ada code you want to debug.

2. Set a breakpoint in the Ada code to be called by the Java application. For example, open the file for the “Physics” Ada package body and locate the Update_Vehicle procedure body. Set a breakpoint on the first statement of the body, i.e., the call to Compute_Heading.

3. Invoke the debugger for the Java LunarLander project and then, when ready, start the game on the simulator. You should hit the Java breakpoint in Physics_Package.Update_Vehicle().

4. From your NDK installation, copy the file named “gdbserver” located under prebuilt/android-arm/gdbserver/ to the directory libs/armeabi/ in the Java project.

  1. In the Java project, create an empty file in libs/armeabi/ named “gdb.setup”.

6. Create a “jni” directory at the root of the LunarLander Java project. Create an empty file named “Android.mk” in that jni directory. This file is essential, the script “ndk-gdb-eclipse” will fail without it.

7. In a Unix (e.g., Cygwin Bash) shell, go (“cd”) to the root of the LunarLander Java project and invoke the “ndk-gdb-eclipse” script. It should complete without any messages, errors, or warnings.

8. Create a new “Ada Remote Application” launch configuration by selecting Run->Debug Configurations..., then selecting “Ada Remote Application” and then clicking the ‘New launch configuration’ icon.

9. Set Ada Application in the main tab to obj/local/armeabi/app_process in the Java LunarLander project. The subdirs and the file “app_process” should already be present. For example: C:\workspaces\default\LunarLander\obj\local\armeabi\app_process You can use the Browse button to set the content.

10. In the Debugger tab, un-check “Stop on startup” and set the GDB value to “arm-linux-androideabi-gdb”, without the quotes. This is the Ada version of GDB supplied by AdaCore.

11. In the Shared Libraries tab, click “Add...” and add a path to libs/armeabi in the Java LunarLander project.

  1. In the Connection tab, change the port to 5039.
  2. Launch the Ada debug configuration. There will now be two debuggers running under the Eclipse debugger UI.
  3. In the Java debugger, press Run/continue from the Java breakpoint. You should now hit your Ada breakpoint.

12.3.4.1. Important

In the preceding steps you created launch configs, directories, and files. Not all those setup steps are required every time you want to debug Ada code. Some can be done once. However, the following steps must be performed every time you debug Ada code:

1. Launch the debugger on the Java LunarLander project and start the game on the simulator. You should hit the Java breakpoint in Physics_Package.Update_Vehicle().

  1. Run the ndk-gdb-eclipse script from the project directory.
  2. Launch the Ada debug configuration.
  3. Continue from the Java breakpoint. You should hit your Ada breakpoint.