Friday, April 20, 2012

More on the AIR 3.2 orientation bug(s)

Back again with another fix...

In my last post Fixing the fullscreen orientation bug in AIR 3.x I mentioned how to fix the fullscreen AIR issue when changing orientation.

What has now come to light is that while that issue is fixed, there are still issues with orientation changes.

The problem I found is that an orientation change from portrait to landscape works, but orientation back to portrait fails indeterminately: sometimes the app would re-orient and sometimes not.

After a significant amount of research I discovered that a missing value in the android:configChanges attribute on the main Activity seems to be the cause of this.

From Android 3.2 an additional value: "screenSize" is available and should be responded to if your are handling config changes yourself with respect to screen orientation.

To fix this, follow the steps in the previous post but also change the android:configChanges attribute to:

android:configChanges="keyboardHidden|orientation|screenSize"


Additionally it seems that APKTool can be unreliable in repacking the APK.
A work around for this follows:
  1. Unpack using APKTool.
  2. Make appropriate manifest changes.
  3. Re-pack to a temporary apk.
  4. Remove the AndroidManifest.xml from your original APK.
  5. Remove the contents of the root/META-INF folder from your original APK.
  6. Extract the fixed AndroidManifest.xml from the re-packed APK and add it to the root of the original APK.
  7. Re-sign the original APK as per the previous post.

This will preserve all resources, effectively just swapping out the manifest.
These fixes seems to have reliably solved the orientation bugs.

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.