Import the required
classes. This example uses the common MIDlet and some LCDUI classes, plus
a number of Mobile Sensor-specific imports. DeviceControl
from
Nokia UI API is used to keep the backlight on continuously.
import java.io.IOException; import javax.microedition.io.Connector; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Image; import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException; import javax.microedition.sensor.ChannelInfo; import javax.microedition.sensor.Data; import javax.microedition.sensor.DataListener; import javax.microedition.sensor.SensorConnection; import javax.microedition.sensor.SensorInfo; import javax.microedition.sensor.SensorManager; import com.nokia.mid.ui.DeviceControl;
Create the main class
and initial parameters to be used in the example. iCanvas
is
an instance of PanoramaCanvas
, which is created later.
public class Panorama extends MIDlet implements DataListener, PanoramaCanvas.ExitIf { static final int BUFFER_SIZE = 3; private static PanoramaCanvas iCanvas; private static SensorConnection iConnection; private static final String PHOTO_NAME = "/for_more_see_roundus_dot_com.jpg"; public Panorama() { }
Create the data listening
method. Note the reference to setPosition
method, which is created in PanoramaCanvas
.
public void dataReceived( SensorConnection con, Data[] aData, boolean aMissed) { iCanvas.setPosition(aData); }
Create a method for
exiting the application. This is received from PanoramaCanvas.ExitIf
method
that was extended in step
1.
public void exit() { try { destroyApp( true ); } catch (MIDletStateChangeException e) { e.printStackTrace(); } notifyDestroyed(); }
Create the mandatory
MIDlet methods. startApp
initializes PanoramaCanvas
and
sets it as the current Display
, opens the sensor connection,
and avoids backlight fadeout is by using DeviceControl.setLights
.
protected void startApp() throws MIDletStateChangeException { DeviceControl.setLights( 0, 100 ); Display disp = Display.getDisplay( this ); try { iCanvas = new PanoramaCanvas( Image.createImage(PHOTO_NAME), this ); disp.setCurrent( iCanvas ); iConnection = openAccelerationSensor(); if (iConnection != null) iConnection.setDataListener( this, BUFFER_SIZE ); } catch (IOException e) { e.printStackTrace(); } } protected void pauseApp() { } protected void destroyApp(boolean arg0) throws MIDletStateChangeException { try { if (iConnection!=null) iConnection.close(); } catch (IOException e) { e.printStackTrace(); } }
Create a method for
opening the sensor connection. As devices based on the Symbian platform have
two data return formats for acceleration sensors, the following method selects
the correct one by its data format (integer in this case) with the ChannelInfo.TYPE_INT
parameter.
private SensorConnection openAccelerationSensor(){ SensorInfo[] infos = SensorManager.findSensors("acceleration", null); if (infos.length==0) return null; // INT data type is preferred int i=0; for (i=0; i<infos.length && infos[i].getChannelInfos()[0].getDataType()!=ChannelInfo.TYPE_INT; i++); try{ return i==infos.length ? (SensorConnection)Connector.open(infos[0].getUrl()): (SensorConnection)Connector.open(infos[i].getUrl()); }catch (Exception e) { return null; } } }
PanoramaCanvas
determines
whether the image is in portrait or landscape orientation and calculates the
image scrolling from the orientation changes of the device. It is also possible
to traverse the image with the arrow key presses.
Import the needed classes. PanoramaCanvas
mostly
uses the LCDUI Canvas
and related classes.
import java.io.IOException; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Image; import javax.microedition.sensor.Data; import com.nokia.mid.ui.DeviceControl;
Set some required variables.
public class PanoramaCanvas extends Canvas { private static final int STEP = 5; private static ExitIf iExit; private static Image iImage; private static int iImageHeight; private static int iImageWidth; private static int x = 0; private static int y = 0; private static int ii = 0;
Continue setting values
for the parameters. Add a repaint()
method for drawing the changes on the
screen.
public PanoramaCanvas( Image aImage, ExitIf aExit) throws IOException { super(); setFullScreenMode( true ); iExit = aExit; iImage = aImage; iImageHeight = iImage.getHeight(); iImageWidth = iImage.getWidth(); y=-(iImageHeight-getHeight())/ 2; repaint(); }
Add a method to use the received accelerometer values and react to them by moving the image on the screen. In this example, full screen mode is also forced as default.
void setPosition(Data[] aData){ if (ii++%100==0){ DeviceControl.setLights(0, 100); //to keep backlight on setFullScreenMode( true ); } x = getX(x+=getX(aData)); y = getY(y+=getY(aData)); repaint(); }
Add functions to deal
with directional key presses. In this case, all key presses scroll the image
as much as is set in the STEP
variable. keyRepeated
handles
a similar function for held down keys.
/** * deal with any key presses */ protected void keyPressed(int keyCode) { System.out.println("keyCode =" +keyCode); switch(keyCode){ case -1: //up case Canvas.UP: y = getY(y+=STEP); break; case -2: //down case Canvas.DOWN: y = getY(y+=-STEP); break; case -3: //left case Canvas.LEFT: x = getX(x+=STEP); break; case -4: //right case Canvas.RIGHT: x = getX(x+=-STEP); break; default: } repaint(); } protected void keyRepeated(int keyCode){ keyPressed(keyCode); }
Create the paint method
to move the image on the Canvas
.
protected void paint( Graphics g ){ g.drawImage( iImage, x , y, Graphics.TOP | Graphics.LEFT ); if( x + iImageWidth - getWidth() < 0 ) g.drawImage( iImage, x + iImageWidth, y, Graphics.TOP | Graphics.LEFT ); }
Create a few additional
functions. Here, pointerPressed
is set to activate the
exit so that the user can exit the MIDlet by pressing on the Selection Key
or tapping on the screen and sizeChanged
is called to
center the image on the screen in cases where a size change occurs.
protected void pointerPressed(int x, int y) {iExit.exit();} protected void sizeChanged(int w, int h) { y=-(iImageHeight-getHeight())/ 2; repaint(); }
Detect image size and create the image scrolling functionality accordingly.
private int getX(Data[] aData){ int x_axis = 0; boolean isPortrait = getHeight()>getWidth(); int index= isPortrait? 0: 1; try{ for (int i=0; i<Panorama.BUFFER_SIZE; i++){ x_axis += aData[index].getIntValues()[0]; } x_axis = (int)(x_axis/Panorama.BUFFER_SIZE); }catch (IllegalStateException e) { for (int i=0; i<Panorama.BUFFER_SIZE; i++){ x_axis += (int)aData[index].getDoubleValues()[0]; } x_axis = (int)(x_axis/Panorama.BUFFER_SIZE); } return isPortrait?-x_axis%iImageWidth:x_axis%iImageWidth; } private int getY(Data[] aData){ int y_axis = 0; boolean isPortrait = getHeight()>getWidth(); int index= isPortrait? 1: 0; try{ for (int i=0; i<Panorama.BUFFER_SIZE; i++){ y_axis += aData[index].getIntValues()[0]; } y_axis = (int)(y_axis/Panorama.BUFFER_SIZE); }catch (IllegalStateException e) { for (int i=0; i<Panorama.BUFFER_SIZE; i++){ y_axis += (int)aData[index].getDoubleValues()[0]; } y_axis = (int)(y_axis/Panorama.BUFFER_SIZE); } return y_axis%iImageHeight; } private int getX(int x){ x = x>0?-iImageWidth+x:x; return x % iImageWidth; } private int getY(int y){ y = y>0?0:y; // upper limit return Math.abs(y)>iImageHeight-getHeight()?getHeight()-iImageHeight:y; //bottom limit }
Set the ExitIf
interface
to call exit(
). ExitIf
is used in Panorama.destroyApp()
method.
static interface ExitIf { public void exit(); };