Thursday, April 5, 2012

Fixing the fullscreen orientation bug in AIR 3.x

EDIT: Please see important information about jarsigner parameters below:


In my day job I lead a team that develops Android AIR applications built on the Adobe AIR runtime.

Recently Adobe have released version 3.2 of AIR for Android that brings many new exciting features (including hardware accelerated rendering) and we were keen to take advantage of these features. We were also keen to use a feature called "Captive Runtime" where the AIR runtime can be packaged with the APK file.

Our application is a full screen app and uses both landscape and portrait orientations and this is where our troubles began.

When running without the Captive Runtime on AIR 3.1 everything worked as expected, however when the captive runtime was included and the app switched orientation the Android title bar appeared. Things got worse with AIR 3.2 as the title bar appeared in both cases. Its important to note that this only seems to occur on ICS.

After an immense amount of spelunking deep into the AIR runtime support code with smali and various other tools (of which I will spare the details) I came to the conclusion that the orientation code is broken with respect to full screen and themes on ICS.

This seems to be as a result of the application of the activity theme as defined in the AndroidManifest file.


The FlashBuilder generated entry should look something like this:
<activity theme="@style/Theme.NoShadow" ... />


Unfortunately when applied this will cause the title bar to appear.
Luckily there seems to be an easy to implement fix for this behaviour that does not require byte patching of the dex file.


To do this you will need to edit the AndroidManifest.xml and change the theme of the main activity to this:

<activity theme="@android:style/Theme.NoTitleBar.Fullscreen" ... />


The AndroidManifest.xml file in the APK is a binary XML file, so the APK needs to be unpacked, fixed, repacked and then finally re-signed.

The tools to accomplish this are apktool and jarsigner.


apktool

apktool can be found at: http://code.google.com/p/android-apktool/

You will need both the windows package and the actual apktool JAR file.

As of this post these are:

apktool-install-windows-r04-brut1.tar.bz2

apktool1.4.3.tar.bz2

Unpack both of these into the same directory.

To unpack an APK you would use the following command:

apktool.bat d apk_filename.apk


This will unpack the APK into a directory of the same name as the APK e.g. apk_filename

At this point you should be able to edit the AndroidManifest.xml file and make the changes described above.

To repack the APK:

apktool.bat b unpacked_apk_directory new_apk_filename.apk

You may want to use the -f force flag to ensure that the APK is repacked.


jarsigner

jarsigner can be found in the java JDK and it is imperative that you have at least the 1.6+ JDK installed.

To resign an APK using a PKCS12 certificate (.p12 file) you would use the following command:

jarsigner.exe -storetype pkcs12 -keystore pkcs12_file_name.p12 -digestalg SHA1 -sigalg MD5withRSA new_apk_filename.apk "1"


Please note the addition of the -digestalg SHA1 and -sigalg MD5withRSA parameters. These are essential to correctly sign the APK.

The “1” indicates the alias which is the first cert in the PKCS file. This can be verified by running the keytool application (which is also available in the JDK):

keytool.exe -list -v -storetype pkcs12 -keystore pkcs12_file_name.p12


Arguably the theme attribute could be applied at the application node and removed from the activity node. I haven't tested this (it does seem that the activity node theme overrides the application theme).

I hope this helps anyone out there with the same issue.

6 comments:

  1. Thanks a lot for your post, there seems to be a lot of people having the same problem but no one else with any solutions...

    I am in the process of developing an in-store product finder and really need to remove the system buttons, to stop people quitting the app, and to make use of the whole screen.

    Can you confirm that I should be able to go full screen on an android tablet including removing the black bar at the bottom of the page?

    I have read a lot and most people think it isn't aloud by google. Is this true?

    Thanks again for the post!
    Oli

    ReplyDelete
  2. Hi,

    On a tablet the bottom bar is an OS window i.e. you have no control over it (that is not strictly true, there is a way to make a "media player" app that takes over the full screen, but the bar will re-appear when the user touches the screen).

    -(e)

    ReplyDelete
  3. Many thanks for your reply,

    Sorry to pick your brain again and slightly off topic. Is it possible to launch an app built with AIR for android when the device starts up? If so can you point me in the right direction. Or are your team available to create a native extension for me. I am pretty comfortable developing in AS3 but when it comes to java and compiling into a native extension I am a complete novice.

    Thanks again
    Oli

    ReplyDelete
  4. Hi,

    I believe that it is possible to start an app on boot, probably through a service or such (also I think there is some mechanism of registering as a boot application, can't remember where I read this though).

    Ahh it seems that this: http://stackoverflow.com/questions/5739588/android-launching-app-when-system-boot

    could help. Unfortunately I can't create a native extension for you, but if you try out the Adobe samples (and there are many resources now on the web to help) it shouldn't be too difficult.

    -(e)

    ReplyDelete
  5. I was also seeing the notification bar returning after a screen orient change and only in ICS and now JB. As a workaround, I added a stage resize event so everytime the screen rotated, it does fullscreen again. Seems to work well.

    ReplyDelete
  6. Hi,

    Hmm, I thought that I'd tried this and that it had not worked, hence the interesting journey to find the root cause!

    ReplyDelete