This example MIDlet consists of only one class, called ArrowKeys
. For complete source code, see section Mobile sensors - ArrowKeys.
Create the ArrowKeys
class file.
Import the required classes. This example uses the four main Mobile Sensor API classes required for opening and using sensors:
import java.io.IOException; import javax.microedition.io.Connector; import javax.microedition.lcdui.*; import javax.microedition.midlet.MIDlet; import javax.microedition.sensor.ChannelInfo; import javax.microedition.sensor.Data; import javax.microedition.sensor.DataListener; import javax.microedition.sensor.SensorInfo; import javax.microedition.sensor.SensorConnection; import javax.microedition.sensor.SensorManager;
Create the main class and initial parameters to be used in the example.
public class ArrowKeys extends MIDlet implements CommandListener, DataListener { private static final int BUFFER_SIZE = 1; private static final boolean IS_TRIGGERING_EVENT_ALWAYS = false; private static StringItem arrow; private static int exEvent = -1; private static Command exitCommand = new Command("Exit", Command.EXIT, 1); private static boolean isStopped = false;
Add an exit
command, a command listener, and the StringItem
that will be set to indicate the device orientation.
public ArrowKeys() { Form form = new Form("ArrowKeys"); form.addCommand(exitCommand); form.setCommandListener(this); arrow = new StringItem("Direction",""); form.append(arrow); Display.getDisplay(this).setCurrent(form); }
Open the sensor
connection inside the startApp
method. The openSensor
method used here is defined
at a later time. The sensor connection remains open as long as the
MIDlet is running (isStopped
returns false
). When the MIDlet stops, the sensor connection is
closed with the close
method.
public void startApp() { SensorConnection sensor = openSensor(); if (sensor==null) return; sensor.setDataListener(this, BUFFER_SIZE); while(!isStopped()){ try{ wait(); }catch(InterruptedException ie){} } sensor.removeDataListener(); try{ sensor.close(); }catch(IOException ioe){ ioe.printStackTrace(); } }
Add the rest of the mandatory methods.
public void destroyApp(boolean par) {} public void pauseApp() {}
Create a method
to open the sensor connection. This is called in startApp
.
private SensorConnection openSensor(){ SensorInfo infos[] = SensorManager.findSensors("acceleration", null); if (infos.length == 0) return null; try{ return (SensorConnection)Connector.open(infos[0].getUrl()); }catch(SecurityException se){ se.printStackTrace(); return null; } catch(IOException ioe){ ioe.printStackTrace(); System.out.println("Couldn't open sensor : " + infos[0].getUrl()+"!"); return null; } catch(IllegalArgumentException iae) { iae.printStackTrace(); return null; } }
Assign the exit command to close the MIDlet and set the sensor connection to be closed.
public void commandAction(Command command, Displayable screen) { // exit command if (command == exitCommand){ setStopped(true); destroyApp(false); notifyDestroyed(); } }
Add methods to mark the sensor connection to be
closed when the MIDlet is shut down. These are used in the startApp
method.
private static synchronized boolean isStopped() { return isStopped; } private synchronized void setStopped(boolean isStopped){ ArrowKeys.isStopped = isStopped; notify(); }
Create a method
to compare the absolute values of axis_x
and axis_y
. The comparison
indicates whether the device is more tilted to the x or y axis direction.
x
defines LEFT-RIGHT
axis
y
defines UP-DOWN
axis
/** * The method returns an action event (UP,DOWN,LEFT,RIGHT) that * corresponds to the given axis x and y accelerations. * @param axis_x * @param axis_y * @return the corresponding action key */ private static int getActionKey(double axis_x, double axis_y){ // axis_x: LEFT or RIGHT if (Math.abs(axis_x)>Math.abs(axis_y)){ return axis_x<0?Canvas.RIGHT:Canvas.LEFT; } // axis_y: UP or DOWN return axis_y<0?Canvas.UP:Canvas.DOWN; }
Create a method
to listen and parse the accelerometer values. In this example, the data2actionEvents
method distinguishes between the two
accelerometer modes (raw values are returned as an integer and m/s^2
values are returned as a double). If the received
data does not conform to ChannelInfo.TYPE_INT
, it is assumed to
be double.
/** * The method returns action events that * corresponds to the given acceleration data. * Valid return values are: * Canvas.UP * Canvas.DOWN * Canvas.RIGHT * Canvas.LEFT * @param data the acceleration data * @return the action event array */ private static int[] data2actionEvents(Data[] data){ ChannelInfo cInfo = data[0].getChannelInfo(); boolean isInts = cInfo.getDataType() == ChannelInfo.TYPE_INT? true: false; int[] events = new int[BUFFER_SIZE]; if (isInts){ int[][] ints = new int[2][BUFFER_SIZE]; for (int i=0; i<2; i++){ ints[i] = data[i].getIntValues(); } for (int i=0; i<BUFFER_SIZE; i++){ events[i] = getActionKey(ints[0][i], ints[1][i]); } return events; } double[][] doubles = new double[2][BUFFER_SIZE]; for (int i=0; i<2; i++){ doubles[i] = data[i].getDoubleValues(); } for (int i=0; i<BUFFER_SIZE; i++){ events[i] = getActionKey(doubles[0][i], doubles[1][i]); } return events; }
Use the dataReceived
method to listen to accelerometer
events. The data is received in the returned value events
from the data2actionEvents
method. In data2actionEvents
, the accelerometer values are mapped
to key presses (Canvas.UP
, Canvas.DOWN
, Canvas.LEFT
and Canvas.RIGHT
). To illustrate the key press values, they are mapped to the arrow StringItem
.
public void dataReceived(SensorConnection sensor, Data[] d, boolean isDataLost) { int[] events = data2actionEvents(d); for (int i=0; i<BUFFER_SIZE; i++){ if (events[i] == exEvent && !IS_TRIGGERING_EVENT_ALWAYS) continue; exEvent = events[i]; switch(events[i]){ case Canvas.UP: arrow.setText("^"); break; case Canvas.DOWN: arrow.setText("v"); break; case Canvas.LEFT: arrow.setText("<"); break; case Canvas.RIGHT: arrow.setText(">"); break; default: arrow.setText(""); } } } }