Is there a point then to deal with Bluetooth given the current state of the emulator? IMHO, yes, because when the shiny new version of the emulator comes out, applications will be ready to run. At the present state of affairs this approach means that we have to live with a bit (lot!) of hacking.
For the moment, I was interested in the discovery process. Discovery in the present implementation does not work but that did not prevent me simulating it. By taking apart org.bluez.IBluetoothService and android.server.BluetoothService classes with the jad tool, it quickly became evident that the discovery process is based on 4 intent messages.
- org.bluez.intent.action.DISCOVERY_STARTED - delivered when the discovery process starts.
- org.bluez.intent.action.REMOTE_DEVICE_FOUND - delivered when one device is discovered. It has 3 parameters in the Intent's Bundle: "address" (String) is the Bluetooth address of the device, "class" (Integer) is the class of the Bluetooth device and "rssi" (Short) is the Received Signal Strength Indicator.
- org.bluez.intent.action.REMOTE_NAME_UPDATED - delivered when the user-friendly name of one device is discovered. This message follows an earlier REMOTE_DEVICE_FOUND message and carries the user-friendly name ("name" (String)) along with the Bluetooth address ("address" (String)).
- org.bluez.intent.action.DISCOVERY_COMPLETED - delivered when the discovery process finishes.
The discovery simulator itself is an interesting piece of software because of some common Android programming tricks it employs. The discovery simulator is located in the BtDetectSimulatorService class that the main activity launches with a startService call (it is therefore the other type of service, not the one seen at the service invocation entry). Normally, the discovery would just be started with a method call on org.bluez.IBluetoothService but the implementation is not that ready. The service abuses the half-implemented Bluetooth classes (like the android.server.BluetoothService class, don't ever do what I did here!), starts the Bluetooth service and sends out intent messages. These intent messages are captured by an intent receiver (BtIntentReceiver) and are used to update the UI of the main activity.
Two small details are interesting here. The intent receiver and the main activity call each other like ordinary Java objects. The code exploits the fact that the main activity is a singleton and just connects the activity and the intent receiver instances by Java references. This is possible because these two entities are part of the same package, hence they run in the same VM instance. Here is the proof (619 is the PID of the VM process):
D/BTINTENTRECEIVER( 619): org.bluez.intent.action.DISCOVERY_STARTED
D/BTDETECT( 619): Action = org.bluez.intent.action.DISCOVERY_STARTED
The other interesting bit is the way BtDetectSimulatorService delivers the events. There is a delay among the intent broadcasts (Bluetooth discovery may be a lengthy process). This delay could not be coded with the good old Thread.sleep call in onStart method because onStart would have run too long and the Android application manager would kill the process. In addition, no broadcasts would be delivered until onStart ends which means that all the broadcasts would be delivered at once. Instead, observe how an android.os.Handler instance is used to schedule Runnable tasks after a certain delay.
And at last, the fun part. The image below shows, how Android's own Phone application crashes terribly when our application stops the Bluetooth service (it was us who started it, so we stop it nicely). That characterizes pretty much the readiness of the Bluetooth support in the current emulator.