Friday, March 12, 2010

Sensors

Ever since I heard that Android devices come with a wide array of sensors, I have been excited about the possibilities. I am a firm believer of the ubiquitous computing vision and all the consequences it brings, including sensors that can be accessed wirelessly. Some parts of the vision (e.g. self-powering microsensors embedded into wallpaint) are still futuristic but mobile phones can be equipped with such sensors easily. Google has a strategy about sensor-equipped mobile devices where the sensor values are processed by powerful data centers. As I did not have an Android device before, I could not play with those sensors. Not anymore! (again, many thanks to those gentle souls who managed to get this device to me).

Sensors are integral part of the Android user experience. Acceleration sensor makes sure that the screen layout changes to landscape when you turn the device (open an application that supports landscape layout, e.g. the calendar, keep the device in portrait mode, move the device swiftly sideways to the right and if you do it quick enough, you can force the display to change to landscape mode). Proximity sensor blanks the screen and switches on the keylock when the user makes a phonecall and puts the device to his or her ear so that the touchscreen is not activated accidentally. In some devices, temperature sensor monitors the temperature of the battery. The beauty of the Android programming model is that one can use all these sensors in one's application.

Click here to download the example program.

A very similar application called SensorDump can be found on Android Market. Our example program is inferior to SensorDump in many respect but has a crucial feature: it can log sensor values into a CSV file that can be analysed later on (use the menu to switch the capture feature on and off). Update: from the 0.2.0 version of SensorDump, sensor data logging into CSV file is available. This is not much important with e.g. the proximity sensor which provides binary data but I don't believe one can understand at a glance, what goes on with the e.g. accelerator sensor during a complex movement just by looking at the constantly changing numbers on the device screen.

I can see the following sensors on my Nexus One.

BMA150 - 3-axis accelerometer
AK8973 - 3-axis Magnetic field sensor
CM3602 - Light sensor

Some sensors are projected as more than one logical sensor, for example the AK8973 is also presented as an orientation sensor and the CM3602 as the proximity sensor. This is just software, however, these duplicate logical sensors use the same sensor chip but present the sensor data in different format.

Let's start with the most popular sensor, the accelerometer. This measures the device's acceleration along the 3 axis. A logical but somewhat unintuitive property of this sensor is that the zero point is in free fall - otherwise the Earth's gravity acceleration is always present. If the device is not subject to any other acceleration (the device is stationary or moves with constant speed), the sensor measures the gravity acceleration that points toward the center of the Earth. This is commonly used to measure the roll and the pitch of the device, try the excellent Labyrinth Lite game on Android Market if you want a demonstration.

The graph below shows sensor data in two scenarios (note that all the data series can be found in the download bundle under the /measurements directory). The red dots show the value of the accelerometer when the device was turned from horizontal position to its side, right edge pointing to the Earth. The green dots show the sensor values when the device was tilted toward its front edge so that at the end the upper edge pointed toward the Earth.



This is all beautiful but don't forget that the acceleration sensor eventually measures acceleration. If the device is subject to any acceleration other than the gravity acceleration (remember the experiment with the portrait-landscape mode at the beginning of the post), that acceleration is added to the gravity acceleration and distorts the sensor's data (provided that you want to measure the roll-pitch of the device). The following graph shows the accelerometer values when the device was laying on the table but I flicked it. The device accelerated on the surface of the table and the smaller blue dot shows the value the accelerometer measured when this happened. As if the device was tilted to the right.


The second sensor is the magnetic field sensor, the compass. As far as I know, this sensor is not used for anything by the base Android applications, it is all the more popular for all sorts of compass applications. The magnetic sensor measures the vector of the magnetic field of the Earth, represented in the device's coordinate system. In 3D, this points toward the magnetic north pole, into the crust of the Earth. The following graph shows the scenario when the device was laying on the table but was rotated in a full circle on the surface of the table.



Even though the magnetic sensor is not subject to some unwanted acceleration like the accelerometer, it is subject to the influence of metal objects. The following graph shows the values of the magnetic sensor when the device was laying on the table but after a while I put a small pair of scissors on top of the device. You can see that there are two clusters of sensor values: one with the scissors, one without.


The third sensor is the light sensor that doubles as proximity detector. The light sensor is more evident but the proximity detector deserves some explanation. The proximity detector is really a light sensor with binary output. If blocked, it emits 0.0, otherwise it emits 1.0. The photo belows demonstrates the location of the sensor and how to block it.

Friday, March 5, 2010

Expandable list with CWAC

I received a comment at the expandable list adapter post that I should take a look at the CommonsWare Android Components (CWAC) project. CWAC aims to provide off-the-shelf components for Android programmers which is a very interesting proposition. In particular, the EndlessAdapter does pretty much the same as my example program at the post, except that the CWAC component offers a nice API to programmers while my program is nothing more than an example from which parts can be copied into somebody else's code.

Click here to download the example program.

Still, I think it is interesting to share my experience with CWAC EndlessAdapter because I reimplemented my example program using the EndlessAdapter. The largest - and, IMHO, most annoying - difference is that EndlessAdapter does the caching from the slow data source and the updating of the list in two separate stages. This means that if an application decides to cache more than one item, those items will not appear in the list until all the items of the particular batch were loaded. If you execute the example program, you will see batches of 5 items appearing (because the code preloads 5 items at once). EndlessAdapter really leaves only one other option open: that only one item is cached. This is less user-friendly, however, because the user has to wait for each item when the list is scrolled down. So I think the component should definitely support list update while a larger batch of items is being fetched from the data source. This would require change of the component API.

The other difference is more like a matter of taste. Personally, I found combining the loading and real data widget into the same row layout and fiddling with the visibility hard to maintain. My test program used a separate row layout for the loading widget which is easier to maintain but is less efficient.

Anyway, my goal with this post was to advertise the CWAC project because I believe that the Android component market is an important. one. That's true even if Android's component support could be better.

Thursday, March 4, 2010

Two-dimensional lists

I got another question whether TableLayout can be used like a two-dimensional ListView. My initial reaction was that it cannot be done because TableLayout just arranges items, all the complicated focusing/highlighting logic in ListView is completely missing from TableLayout. I realized later on, however, that TableLayout can contain Buttons and the rest will be arranged by the general focus handling logic in ViewGroup.

Click here to download the example program.

The only exciting part of this rather simple program is the way how an array of Buttons are made to look like selectable list items. The key is that the Buttons are styled. For example (XML fragments are mangled due to blog engine limitations):

[Button android:id="@+id/button_1"
style="@style/MyButton"
android:text="1"/]

The referred style is in res/values/styles.xml. The funny part is this line:

[item name="android:background"]@android:drawable/list_selector_background[/item]

This line was copied straight from the system style of List.View and applies the ListView selector (that defines appearance of list elements in ListView in their different states) to the Button. No wonder the Button behaves like a list element.

Tuesday, March 2, 2010

Progressively loading ListViews

Again I received a mail from somebody who asked for lists with forward/backward paging option. These lists are not trivial to implement but I was more intrigued by the need why anyone would want such a clumsy UI construct. Then it turned out that the guy wanted to back the list with data from a web service. Obviously, he did not want to wait until the entire list is loaded through the network but wanted to present something to the user as soon as possible.

Such a list can be found in Android Market when the list of applications is progressively loaded from the network server. The problem is worth a simple test program to analyse because it clearly shows the power of the Android adapter concept.

Click here to download the test program.

Our test application does not actually connect to the network but simulates the slow data source. If you check the Datasource class, you will find that even though this "data source" is a simple array, the accessor method adds a 500 ms delay to every access. This simulates well the fact that loading from certain data sources takes time. The trick is in the PageAdapter class. This class adds a View to the end of the list ("Loading ..."). Android Market animates this view but the idea is the same. Whenever this View is drawn, the adapter kicks the loading thread which progressively fetches new elements from the data source, adds them to the Adapter's data set and notifies the adapter that the data set has changed. There is the usual fiddling with a Handler to make sure that notifyDataSetChanged() is invoked in the context of the UI thread. The Adapter constantly changes the value returned by the getCount() method as the items are loaded from the data source. When the whole data set is loaded, the "Loading ..." widget is not drawn anymore therefore nothing triggers the loading thread.

Here is how it looks like.



No, wait a minute, here is how it looks like.


Yes! After having blogged for more than 2 years about Android, I finally put my hands on an actual Android phone. The story is complicated but the essence is that a friend thought that I deserved that phone and gave it to me. Thanks for everyone involved!