For information about the design and functionality of the MIDlet, see section Design.
The MIDlet consists of two classes:
Cottage360 is the MIDlet main class
PanoramaCanvas implements the picture scrolling
To implement the Cottage360 class:
Create the Cottage360.java class file.
Import the required classes.
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;
Set Cottage360 to extend MIDlet and implement DataListener and the PanoramaCanvas.ExitIf interface. MIDlets use the DataListener interface to receive data from the sensors.
public class Cottage360 extends MIDlet implements DataListener, PanoramaCanvas.ExitIf {
Create the required variables and the Cottage360 class constructor.
static final int BUFFER_SIZE = 3; private static PanoramaCanvas iCanvas; private static SensorConnection iConnection; private static final String PHOTO_NAME = "/cottage360.jpg"; public Cottage360() { }
The dataReceived method is required by the DataListener interface. The method is called every time the sensor has data to send. In this class, the method only sends the data forward to the PanoramaCanvas class.
public void dataReceived( SensorConnection con, Data[] aData, boolean aMissed) { iCanvas.setPosition(aData); }
The exit method exits the MIDlet. It is received from the PanoramaCanvas.ExitIf method, which the Cottage360 class extends. The exit method calls the destroyApp method. The pauseApp method is included as part of the MIDlet lifecycle requirements.
public void exit() { try { destroyApp( true ); } catch (MIDletStateChangeException e) { e.printStackTrace(); } notifyDestroyed(); } protected void destroyApp(boolean arg0) throws MIDletStateChangeException { try { if (iConnection!=null) iConnection.close(); } catch (IOException e) { e.printStackTrace(); } } protected void pauseApp() { }
Use the startApp method to set the device display to stay on, store the current display in a variable, and create a new PanoramaCanvas instance. The method sets the current display to show the canvas and opens a new sensor connection by calling the openAccelerationSensor method. If the sensor connection is successful, the method registers the Cottage360 class as a listener to that sensor.
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(); } }
To implement the PanoramaCanvas class:
Create the PanoramaCanvas.java class file.
Import the required 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 PanoramaCanvas to extend Canvas. Create the 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;
The PanoramaCanvas class constructor sets the screen to full screen mode and saves some needed variables.
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(); }
The setPosition method is used to set the new position of the picture. It takes the accelerometer data as a parameter, and uses the getX and getY methods to calculate the new coordinates.
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(); }
As the PanoramaCanvas class extends the Canvas class, it must implement the keyPressed and keyRepeated methods. The keyPressed method takes a key code as a parameter, and based on what key was pressed, it calculates the new x or y coordinates. The keyRepeated method simply calls the keyPressed method with the received key code.
protected void keyPressed(int 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); }
The paint method draws the picture on the screen. After the x or y coordinates have changed, you must call the repaint method to update the changes on the screen.
protected void paint( Graphics g ){ g.setColor(0, 0, 0); g.fillRect(0, 0, getWidth(), getHeight()); g.drawImage( iImage, x , y, Graphics.TOP | Graphics.LEFT ); if( x + iImageWidth - getWidth() < 0 ) g.drawImage( iImage, x + iImageWidth, y, Graphics.TOP | Graphics.LEFT ); }
The pointerPressed method is set to activate the exit so that the user can exit the MIDlet by pressing the Selection Key or tapping on the screen. The sizeChanged method is called to center the picture on the screen after a size change.
protected void pointerPressed(int x, int y) {iExit.exit();} protected void sizeChanged(int w, int h) { y=-(iImageHeight-getHeight())/ 2; repaint(); }
The getX and getY methods detect the picture size and create the picture scrolling functionality.
private int getX(Data[] aData){ int x_axis = 0; boolean isPortrait = getHeight()>getWidth(); int index= isPortrait? 0: 1; try{ for (int i=0; i<3; i++){ x_axis += aData[index].getIntValues()[0]; } x_axis = (int)(x_axis/3); }catch (IllegalStateException e) { for (int i=0; i<3; i++){ x_axis += (int)aData[index].getDoubleValues()[0]; } x_axis = (int)(x_axis/3); } 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<3; i++){ y_axis += aData[index].getIntValues()[0]; } y_axis = (int)(y_axis/3); }catch (IllegalStateException e) { for (int i=0; i<3; i++){ y_axis += (int)aData[index].getDoubleValues()[0]; } y_axis = (int)(y_axis/3); } 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 //This is to center the image if the screen is higher than the image. if (iImageHeight<getHeight()) return -(iImageHeight-getHeight())/2; return Math.abs(y)>iImageHeight-getHeight()?(getHeight()-iImageHeight):y; //bottom limit }
The ExitIf interface calls the exit. The interface is used in the Cottage360.destroyApp method.
static interface ExitIf { public void exit(); }; }