Accelerometer Example

This example shows how to access the accelerometer on a device, if present, and read the values it reports.

A screenshot of the application.

Not all Android devices have accelerometers, though it may be one of the more common sensors used on mobile devices. The available sensors on a device can be found by running the Sensor List example.

We begin by importing the classes and modules used or referred to in our code. The most relevant to this example are the sensor classes from the android.hardware module.

from java.lang import String
from java.util import ArrayList, List
from android.app import Activity
from android.content import Context
from android.hardware import Sensor, SensorEvent, SensorEventListener, \
                             SensorManager
import android.os
from android.view import View, ViewGroup
from android.widget import LinearLayout, TextView

We define the TextViewList class to describe an ArrayList containing TextView items. This enables us to create new lists with this type of item since we have no other way of describing it in Serpentine. The __item_types__ attribute defines the item type that instances of this class will hold and is only used at compile time.

class TextViewList(ArrayList):

    __item_types__ = [TextView]
    
    def __init__(self):
        ArrayList.__init__(self)

The AccelerometerActivity is derived from the standard Activity class and represents the application. Android will create an instance of this class when the user runs it.

class AccelerometerActivity(Activity):

    __interfaces__ = [SensorEventListener]

The class implements the SensorEventListener interface, declaring this by including it in the list of interfaces defined by the __interfaces__ attribute. Implementing this interface involves implementing two methods that are described later.

We define a field to store a list of TextView instances. This can be described either with a generic List or with the specific class that we used to represent the list. Since the list itself will be explicitly created, this declaration can be omitted.

    __fields__ = {"views": List(TextView)}
    #__fields__ = {"views": TextViewList}

The initialisation method simply calls the corresponding method in the base class.

    def __init__(self):
    
        Activity.__init__(self)

The onCreate method calls the base class's onCreate method to help set up the activity. We obtain an object that represents the accelerometer and set up the user interface.

    def onCreate(self, bundle):
    
        Activity.onCreate(self, bundle)

Information about the available sensors is obtained from the device's sensor service. This is obtained using the getSystemService method. The instance we obtain from this method needs to be cast to a suitable type so that we can access its methods.

        sensorManager = self.getSystemService(Context.SENSOR_SERVICE)
        self.sensorManager = CAST(sensorManager, SensorManager)

The accelerometer is obtained by passing the appropriate constant to the method responsible for returning the default sensor for each type. The value returned may be None, so we must check it before trying to access the sensor.

        self.accelerometer = self.sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)

We create a vertical layout in which to show labels and create a TextView to use as a name label. This will show the name of the sensor or a message in case no sensor is available.

        layout = LinearLayout(self)
        layout.setLayoutParams(ViewGroup.LayoutParams(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT))
        layout.setOrientation(LinearLayout.VERTICAL)
        
        self.views = TextViewList()
        self.nameLabel = TextView(self)
        layout.addView(self.nameLabel)

If an accelerometer was not found, we write a message in the name label and indicate that no sensor is available using an instance attribute. Otherwise, we place three empty labels in the list of TextViews we are maintaining and put them in the layout.

        if self.accelerometer == None:
            self.hasSensor = False
            self.nameLabel.setText("No suitable sensor found.")
            
        else:
            self.hasSensor = True
            
            self.views.add(TextView(self))
            self.views.add(TextView(self))
            self.views.add(TextView(self))
            
            layout.addView(self.views.get(0))
            layout.addView(self.views.get(1))
            layout.addView(self.views.get(2))

The layout is used as the main content in the activity.

        self.setContentView(layout)

When the activity starts, or the user navigates to it, the onResume method is called. Other than calling the corresponding method in the base class, we check whether we have access to an accelerometer using the value stored in the above method. If so, we show its name in the name label and register the instance of this class as a listener for it. This requires that this class implements the SensorEventListener interface.

    def onResume(self):
    
        Activity.onResume(self)
        
        if self.hasSensor:
            self.nameLabel.setText(self.accelerometer.getName())
            self.sensorManager.registerListener(self, self.accelerometer,
                SensorManager.SENSOR_DELAY_UI)

When the user navigates away from the activity the onPause method is called. We call the corresponding method in the base class and unregister the instance of this class as a listener. This prevents it from receiving updates from the sensor until it is registered again.

    def onPause(self):
    
        Activity.onPause(self)
        if self.hasSensor:
            self.sensorManager.unregisterListener(self)

The following two methods must be implemented because they are part of the SensorEventListener interface whose methods are both abstract.

The onAccuracyChanged method is used to inform the activity about changes to the accuracy of the sensor. For this simple example we ignore this and simply implement an empty method.

    def onAccuracyChanged(self, sensor, accuracy):
        pass

The onSensorChanged method is used to inform the activity about changes to the values supplied by the sensor. Since this method is only called if we registered the activity as a listener, we can simply read the values for the acceleration on each axis from the supplied event and write them to the labels that were created earlier.

    def onSensorChanged(self, event):
    
        self.views.get(0).setText(String.valueOf(event.values[0]))
        self.views.get(1).setText(String.valueOf(event.values[1]))
        self.views.get(2).setText(String.valueOf(event.values[2]))

Files