08 July 2009

Differentiate Emulator from Device & Unique IDs

I am working on a game which uses various of the sensors. There is a bug in the Cupcake 1.5 emulator (at least through r2) which causes the Sensor Manager to hang. The advice from the Google Developer Groups moderators is to debug on devices since you can't get sensor information from the emulator. (But look into OI Intents which has a sensor emulator for the emulator. I have not yet looked into it.)

As a long time embedded systems developer this advice is absurd. There is all kinds of development work that can be accomplished without actual inputs, especially on a device with a GUI like the Android.

Additionally, it just isn't convenient reaching over to my G1 to see what it is doing and to manipulate it to check orientation changes, etc. Hitting ctrl-F11 to change orientation on the emulator is much easier.

I started wondering how to detect if the emulator or a device were running an application. This would allow skipping over the buggy Sensor Manager on the emulator to avoid the hang. Putting some conditional coding around sensor code might then allow development on the emulator.

My investigation found two sets of information to differentiate the device and emulator. This information would also allow differentiating among devices so has some use in all applications.

The first set of information is from the OS build. There are a number of fields available. All you need is the import and reading of the available fields. The comments after the code are from my emulator and the G1.

import android.os.Build;
// ...
Log.d(TAG, "config" + "\n " + Build.BOARD + "\n " + Build.BRAND + "\n" + Build.DEVICE + "\n" + Build.DISPLAY + "\n" + Build.FINGERPRINT + "\n" + Build.HOST + "\n" + Build.ID + "\n" + Build.MODEL + "\n" + Build.PRODUCT + "\n" + Build.TAGS + "\n" + Build.TIME + "\n" + Build.TYPE + "\n" + Build.USER);

// trout
// tmobile
// dream
// CRB43
// tmobile/kila/dream/trout:1.5/CRB43/148830:user/ota-rel-keys,release-keys
// undroid11.mtv.corp.google.com
// CRB43
// T-Mobile G1
// kila
// ota-rel-keys,test-keys
// 1242268990000
// user
// android-build


// unknown
// generic
// generic
// sdk-eng 1.5 CUPCAKE 148875 test-keys
// generic/sdk/generic/:1.5/CUPCAKE/148875:eng/test-keys
// e-honda.mtv.corp.google.com
// CUPCAKE
// sdk
// sdk
// test-keys
// 1242347389000
// eng
// android-build



The second differentiator is the Android ID which may be unique to each device. The emulator returns null while the device returns a string. Again, after the code is my results, although I did corrupt my G1's ID since with proper permissions the value can be changed.

Log.d(TAG, "and id " + Settings.Secure.getString(this.getContentResolver(), Settings.Secure.ANDROID_ID));

// G1: 200xxxxxd4cca5x
// Emulator: null




03 July 2009

Android Activity Analysis

I have been looking at the details of the life cycle of an Android Activity. There are many web sites that discuss this and many examples. But none of the example addressed all the onXXX() methods of Activity. I also found problems with some of the examples. In one case, the GUI update thread could be left running after the Activity supposedly was stopped.

I was trying to determine when the GUI update thread should be created, stopped, paused, etc that initiated this effort. I have a game underway (doesn't everyone?) and figuring out all the Activity infrastructure was giving me fits. Each example did it in a different manner and while there may be no one correct manner most of them seemed a little off. Usually they seemed to omit some of the steps needed to pause, stop, or destroy everything properly.

A number of discussions presented the life cycle as a state machine, as an alternative to the Google flow chart (or here). [I don't mean to single out Eric Burke of StuffThatHappens by using his chart to illustrate my point. He has good Android material on his site.] Like the examples, they didn't seem as well thought-out as possible. For example, notice in Eric's state chart how many places onResume() appears. That indicates to me that the representation of the state machine is needs more work.

I offer the chart below as a simpler representation which eliminates the redundant calls to onResume() and other routines. This diagram is simplified by the introduction of the Pause state reached by onStart() and onPause(). There may be another state after onCreate() and onRestart() are called but my work so far does not show it as important.


From Mystic Lake Software

The file accompaning this page, TemplateSurfaceView.zip, contains a skeleton application for an Android Activity using a SurfaceView as the drawing surface. The application doesn't do anything except report current state to LogCat.

In the TemplateSurvaceView (TSV), the Activity onXXX() routines are mimicked with corresponding doXXX() methods in the TSV class.

doStart() - create thread
doPause - pause thread
doResume - resume thread
doStop() - kill thread

It becomes clear that the onXXX() routines are nicely symmetrical with each pair being able to setup and tear down the parts needed for the application. The one misleading, oddball is onRestart(). At first thought it might somehow pair with doStart(), but this is not the case. The doStart() method is paired with doStop(). The doRestart90 appears to be available to duplicate some of the work done by onCreate() that may have been undone during onStop().

Once I had the diagram figured out the requirements became apparent and the TSV code was generally straightforward. Not so obvious was how to handle the Thread since many of the obvious Thread methods that would be used are deprecated due to deadlock problems. I won't go into the details here because this is a Java issue, not specific to Android. But read the article Why Are Thread.stop, Thread.suspend, Thread.resume and Runtime.runFinalizersOnExit Deprecated? for more information.

Introduction

Actually a place holder for an introduction. I have an Android article I want to post but don't want it as the first blog entry.

I edited the following on StackOverflow in an attempt for it to pass review so I could answer the question. The question had many comments s...