Reading the Accelerometer State

A very interesting input option for games is the accelerometer. All Android devices are required to contain a three-axis accelerometer. We talked about accelerometers in the last chapter a little bit. We'll generally only poll the state of the accelerometer.

So how do we get that accelerometer information? You guessed correctly, by registering a listener. The interface we need to implement is called SensorEventListener, which has two methods:

public void onSensorChanged(SensorEvent event);

public void onAccuracyChanged(Sensor sensor, int accuracy);

The first method is called when a new accelerometer event arrives. The second method is called when the accuracy of the accelerometer changes. We can safely ignore the second method for our purposes.

So where do we register our SensorEventListener? For this we have to do a little bit of work. First we need to check whether there actually is an accelerometer installed in the device. Now, I just told you that all Android devices must contain an accelerometer. This is still true, but might change in the future. We therefore want to make 100 percent sure that that input method is available to us.

The first thing we need to do is get an instance of the so-called SensorManager. That guy will tell us whether an accelerometer is installed, and is also where we register our listener. To get the SensorManager we use a method of the Context interface:

SensorManager manager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);

The SensorManager is a so-called system service that is provided by the Android system. Android is composed of multiple system services, each serving different pieces of system information to anyone who asks nicely.

Once we have the manager, we can check whether the accelerometer is available: boolean hasAccel = manager.getSensorList(Sensor.TYPE_ACCELEROMETER).size() > 0;

With this bit of code we poll the manager for all the installed sensors that have the type accelerometer. While this implies that a device can have multiple accelerometers, in reality this will only ever return one accelerometer sensor, though.

If an accelerometer is installed, we can fetch it from the SensorManager and register the SensorEventListener with it as follows:

Sensor sensor = manager.getSensorList(Sensor.TYPE_ACCELEROMETER).get(0); boolean success = manager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_GAME);

The argument SensorManager.SENSOR_DELAY_GAME specifies how often the listener should be updated with the latest state of the accelerometer. This is a special constant that is specifically designed for games, so we happily use that. Notice that the SensorManager.registerListener() method returns a boolean indicating whether the registration process worked or not. That means we have to check the boolean afterward to make sure we'll actually get any events from the sensor.

Once we have registered the listener, we'll receive SensorEvents in the SensorEventListener.onSensorChanged() method. The method name implies that it is only called when the sensor state has changed. This is a little bit confusing, as the accelerometer state is changed constantly. When we register the listener, we actually specify the frequency with which we want to get sensor state updates.

So how do we process the SensorEvent? That's rather easy. The SensorEvent has a public float array member called SensorEvent.values that holds the current acceleration values of each of the three axes of the accelerometer. SensorEvent.values[o] holds the value of the x-axis, SensorEvent.values[l] holds the value of the y-axis, and SensorEvent.values[2] holds the value of the z-axis. We discussed what these values mean in Chapter 3, so if you forgot that, go and check out the "Input" section again.

With this information we can write a simple test activity. All we want to do is output the accelerometer values for each accelerometer axis in a TextView. Listing 4-6 shows you how to do this.

Listing 4-6. AccelerometerTest.java; Testing the Accelerometer API package com.badlogic.androidgames;

import android.app.Activity; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.os.Bundle; import android.widget.TextView;

public class AccelerometerTest extends Activity implements SensorEventListener { TextView textView;

StringBuilder builder = new StringBuilder(); ^Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); textView = new TextView(this); setContentView(textView);

SensorManager manager = (SensorManager) getSystemService(Context.SENS0R_SERVICE);

if (manager.getSensorList(Sensor.TYPE_ACCELEROMETER).size() == 0) {

textView.setText("No accelerometer installed"); } else {

Sensor accelerometer = manager.getSensorList(

Sensor.TYPE_ACCELER0METER).get(0); if (!manager.registerListener(this, accelerometer, SensorManager.SENS0R_DELAY_GAME)) { textView.setText("Couldn't register sensor listener");

^Override public void onSensorChanged(SensorEvent event) { builder.setLength(o); builder.append("x: "); builder.append(event.values[o]); builder.append(", y: "); builder.append(event.values[l]); builder.append(", z: "); builder.append(event.values[2]); textView.setText(builder.toString());

^Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // nothing to do here

We start with checking whether an accelerometer sensor is available. If it is, we fetch it from the SensorManager and try to register our activity, which implements the SensorEventListener interface. If any of this fails, we set the TextView to display a proper error message.

The onSensorChanged() method simply reads the axis values from the SensorEvent it gets passed and updates the TextView text accordingly.

The onAccuracyChanged() method is just there so that we fully implement the SensorEventListener interface. It serves no real other purpose.

Figure 4-9 shows you what values the axes take on in portrait mode and landscape modes when the device is held perpendicular to the ground.

Figure 4-9 shows you what values the axes take on in portrait mode and landscape modes when the device is held perpendicular to the ground.

Figure 4-9. Accelerometer axis values in portrait mode (left) and landscape mode (right) when the device is held perpendicular to the ground

Here are a few closing comments on accelerometers:

As you can see in the right screenshot in Figure 4-9, the accelerometer values might sometimes get over their specified range. This is due to small inaccuracies in the sensor, so you have to adjust for that if you need those values to be as exact as possible.

The accelerometer axes always get reported in the same order, no matter what orientation our activity is displayed in.

With this, we have discussed all the input processing-related classes of the Android API we'll need for game development.

NOTE: As the name implies, the SensorManager class grants you access to other sensors as well. This includes the compass and light sensors. If you wanted to be creative, you could come up with a game idea that uses these sensors. Processing their events is similar to how we processed the data of the accelerometer. The documentation over at the Android Developers site will give you more information.

0 0

Post a comment