This example MIDlet consists of only one class, called ArrowKeys
.
For complete source code, see section Sensor
API source code.
Create the ArrowKeys
class
file
Import the required classes. This example uses the four main 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 stays opened 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 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 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 onto 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(""); } } } }