Saturday, May 21, 2011

Supporting Honeycomb pt1: targetSdkVersion=11



Since the day I started at Google I've been trying to find the time to update all of my Android apps to support Honeycomb. However, I'm into my 3rd month and various distractions, like the awesome I/O, have meant that I haven't touched any of them.

So, here we go, part 1, Honeycomb support for 3 of the 9 apps I have live in the Android Market. I'll confess now that I've chosen the easiest 3, in fact they are all so easy that there is just one line to change. The apps are Auto Bright, Dimmer (Night Mode) and The Cleaner.

These apps all run in compatibility mode on Honeycomb, which means it shows the 'menu button' in the system bar to the right of the previous tasks, home and back buttons. To sort this out all you have to do is update the AndroidManifest to ensure it includes:

<uses-sdk android:targetSdkVersion="11"/>

Now that extra compatibility icon will vanish and technically these apps will support Honeycomb, perfect!

For the sake of completeness I've taken this opportunity to also furnish 'The Cleaner' with support for Honeycomb's Lights out Mode. This mode reduces the system bar elements on a Honeycomb device to small dots, making them less distracting. It is usually used for immersive experiences in games, video players, image galleries, etc...

To set Lights Out Mode on a view, just set the system UI visibility to STATUS_BAR_HIDDEN.

v.setSystemUiVisibility(View.STATUS_BAR_HIDDEN);


--- Updated 24/05/2011 ---
As WarGoth points out there is no need to use reflection to maintain backwards compatibility, simply wrapping the code in an android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.HONEYCOMB check is sufficient. Clarification in the comments from Weeds that this only applies to Android 2.0+, the class loader would throw a java.lang.VerifyError on 1.5/1.6.

if(android.os.Build.VERSION.SDK_INT>=android.os.Build.VERSION_CODES.HONEYCOMB) {
    v.setSystemUiVisibility(View.STATUS_BAR_HIDDEN);
}

--- End ---

I did it slightly differently by using reflection to maintain compatibility with older versions of Android without duplicating classes:

Class classView = Class.forName("android.view.View");
Method methodSetSystemUIVisibility = classView.getDeclaredMethod("setSystemUiVisibility", int.class);
methodSetSystemUIVisibility.invoke(v,1);



The full source of these apps is available on Google Code

Part 2 of this series will take on converting one of my more complicated applications.

12 comments:

WarGoth said...

Thank you for the post. I learned about compatibility mode :)

Couple of notes.

- View.STATUS_BAR_HIDDEN is a constant, which means it will be substituted in compile time and value will be available for any android version
- v.setSystemUiVisibility() can be hidden from incompatible SDKs using any version check condition.

Thus you can avoid using reflections and improve readability of the code.

Look forward part two

Unknown said...

Thank you WarGoth, you are right and I've updated the post accordingly.

Weeds said...

You may still need to use reflection if you want to be compatible with Android 1.6 or 1.5.

On these versions loading the class containing Honeycomb (or Froyo/Eclair) functions will throw a java.lang.VerifyError.

You can verify this on the emulator, and I've seen this happening on the HTC Tattoo

Unknown said...

Thanks Weeds, I'd seen that before as well, infact I was a little surprised to see it didn't throw on 2.0+ and is the reason I chose reflection to start with. But as I'm using the WallpaperManager I'm only targeting 2.0+, so it seems like a reasonable case for version checking instead.

Anonymous said...

Hi - I am certainly happy to find this. great job!

Anonymous said...

Do not write this way:

if(android.os.Build.VERSION.SDK_INT>=11)

this is unlean and bit cryptic (now you know what 11 is, but later?). Good programmers :) would write this way:

if(android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)

which make this line perfectly self-explanatory. The only "disadventage" is that you need to set your project's target to at least Honeycomb to have HONEYCOMB constant defined.

Unknown said...

good point, code updated as appropriate, thanks.

Anonymous said...

Hey man, sorry for comment on this post, but how do you did the battery widget ? I want to do a music widget but i don't know nothing... It's to difficult ? Can I make in the App Inventor ? Thanks (:

Sorry again for comment here, the post of the battery widget is very old.

Unknown said...

battery widget is open source at http://batterywidget.googlecode.com just check it out and have a look

Anonymous said...

Hey - I am definitely delighted to find this. cool job!

Anonymous said...

Really good post!

Anonymous said...

Hey - I am really happy to discover this. cool job!