Tuesday, June 21, 2011

Supporting Honeycomb pt2: Updating the Ultimate Stopwatch

For most developers, taking advantage of the features of Honeycomb is also going to involve ensuring their app runs on tablets. It is one thing to do this right from the inception of an app or game, but often a much harder task to upgrade an already complete project to look great on larger screens.

If your app has multiple views then you can utilise fragments to show more than one of them at the same time. If not then you can think about any other data or views that may be able to augment it, or possibly increase the size of some elements.

In the case of the Ultimate Stopwatch the counting digits clearly need to be larger, then the remaining screen space can be used to include an easier to access list of lap times and split times. I mocked up some wire frames and settled on the following design.


So how do you make this magic happen? Well, as the Ultimate Stopwatch uses a SurfaceView and I spent so long getting the small screen UI right, I didn't really want to mess with it, so I'm going to leave it alone and just add new layouts for x-large devices. For many apps, especially those using standard layouts, it is less of an issue and the Android Compatibility package is the best option for a consistent application. I am however going to use fragments for the new layouts, to give me the best control over the larger screen whilst keeping my class files smaller. I'll have a fragment for the animated stopwatch view, one for the counter digits and one for the lap times.

1. In your project properties set the Android Build Target to 11

2. Tell Android that your app is optimised for Honeycomb by updating the androidmanifest.xml by adding <uses-sdk android:targetSdkVersion="11" /> as per my last post, which also shows how to enable hardware acceleration for good measure.

3. To totally segment my previous code I created a new Activity which decides which version of the app to launch based on OS version and screen size, not forgetting to update the AndroidManifest.xml.

4. I've done custom layouts for both landscape and portrait to give optimal experiences. As I'd used fragments it made the portrait view much easier, it only took a couple of minutes.

5. Another thing to remember is that your menu items will now appear in the Action Bar. It is good practice to let Android know which items it can hide under the overflow button if necessary by appending android:showAsAction="ifRoom" in to the item in your Menu.xml.

6. When building the layouts and activities, be mindful of the fragment lifecycle, making sure to inflate your views in the onCreateView() method.

7. To add a little more Honeycomb goodness I also used ObjectAnimator to do a 180 degree animation on the lap times fragment when switching to Countdown Mode and back again, this hides the times and informs the user of the mode the app is in. I also freshened up the Countdown time select dialog with the new NumberPicker.


Launching this update was also a great opportunity to refresh the Android Market listing, adding new screenshots, featured image and descriptions.

The full source of the Ultimate Stopwatch & Timer is available at http://code.google.com/p/android-ultimatestopwatch/

For those of you who want to know how USW looked in landscape on a tablet before this overhaul, prepare yourselves:


Follow me on twitter for further Android related updates.

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.

Tuesday, December 21, 2010

Android Nexus 1 Flashing - assert failed: write_raw_image("/tmp/boot.img", "boot") - solved

NOTE: I've since noticed that WiFi doesn't work with the method outlined below, however it does work with "fastboot boot boot.img" so further investigation is required. Some other users are saying that reflashing the hboot helps, but there are drawbacks to that as well.... Still if you are having this error and want to try gingerbread asap then the solution below is good:

It is a fun error isn't it, thousands of Nexus 1 users are happily flashing the latest ROMs onto their devices with no issues and when you try it you get something a little like this:

Installing update...
assert failed: write_raw_image("/tmp/boot.img", "boot")
E:Error in /sdcard/update.zip
(Status 7)
Installation aborted.


Same here, however there is light at the end of the tunnel. The problem is a lack of space to flash the new boot image, the cause could be one of two things:

1) You have some corrupted memory in the boot space, shrinking the size of the available boot partition and not allowing larger boot images to reside there.
2) This is a guess and I'd be interested in feedback: The Nexus 1 I use for custom ROMs is from the very very first Google seeding back in late 2009. I wonder if these devices had slightly smaller boot partitions.

Either way, there is a solution! The boot partition and the recovery partition are physically very similar, so after flashing the latest Gingerbread ROM (Gingerbread-Rooted-Gapps-v.06-signed.zip in this case, from the awesome XDA forums), I do this:

1) Extract boot.img from the ROMs zip file
2) Connect my N1 to my PC via USB
3) Boot the N1 into Fastboot by holding down the trackball when turning it on.
4) Flash the boot.img into the recovery partition:
"fastboot flash recovery boot.img" (fastboot is in the platform-tools directory of the SDK these days)

Now when I boot my Nexus 1 I hold down the trackball to get to Fastboot and then choose recovery mode, et voila Gingerbread launches.

If you need to get back to a real recovery mode you can either boot into Fastboot then boot a recovery image from your PC e.g. "fastboot boot recovery-RA-nexus-v2.0.0-CM.img"
Or reflash a recovery image, do your thing and then reflash the boot image.

I found this trick out at XDA Forums (where else?), here http://forum.xda-developers.com/showthread.php?t=731657

Wednesday, December 01, 2010

1 day into a relationship with the SonyEricsson LiveView

I absolutely love its geekiness. I'm running it with a stock Nexus 1 on 2.2.1. Yes It does disconnect all the time and I spend quite a lot of time turning it off and on again, re-pairing the bluetooth and generally willing it into life. But, I'll definitely knock a couple of apps up for it in the hope that SonyEricsson make a second generation device with a higher res screen, full touch support and a longer battery life. Some say the battery life is pathetic, but that is an understatement, a watch that doesn't get through half a day is crazy.

So far the best use for it is remote controlling the music players, i've had no problem with the built in Music remote control and my Nexus 1. It supports play/pause, volume control, next/previous track. The Where Am I plugin is ok, brings up a map of your current location on the LiveView. The GMail and SMS plugins don't seem particularly reliable, but I'll keep persisting.

Tuesday, August 24, 2010

Providing your Android Activity with a Theme

I've recently been asked a couple of times by new Android developers how 'Tech Buzz Widget' manages to overlay itself ontop of the desktop, allowing your wallpaper to show through. Assuming that it is easier to Google the answer than ask me, it may be somethiing that there isn't enough detail on already. So here is my 10 cents.

The main detail is to set the correct android:theme for your activity in the AndroidManifest.xml. For Tech Buzz Widget we used android:theme="@android:style/Theme.Translucent.NoTitleBar"

So the activity looked like this:

<activity android:name=".FullArticleView" class=".FullArticleView"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:configChanges="orientation|keyboardHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>


Once you've done that you you'll see that any elements of your layout that are transparent or unfilled will show through onto the underlying application or desktop. To make this more obvious in Tech Buzz we put a margin around the entire layout.

The exact details of all the activity themes available in the current Android platform are available in the Android source here: http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=core/res/res/values/themes.xml

Search for Theme.Translucent and you'll get the idea. There are fullscreen themes as well if you want to get rid of the notification bar. You can also define your own themes in a similar way.