/** * Copyright (c) 2012 Nokia Corporation. All rights reserved. * Nokia and Nokia Connecting People are registered trademarks of Nokia Corporation. * Oracle and Java are trademarks or registered trademarks of Oracle and/or its * affiliates. Other product and company names mentioned herein may be trademarks * or trade names of their respective owners. * See LICENSE.TXT for license information. */ package com.nokia.example.compass.views; import com.nokia.example.compass.CompassMidlet; import com.nokia.example.compass.LandmarkManager; import com.nokia.example.compass.helpers.ImageLoader; import com.nokia.example.compass.helpers.KeyCodes; import java.io.IOException; import java.util.Timer; import java.util.TimerTask; import java.util.Vector; import javax.microedition.lcdui.Font; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Image; import javax.microedition.lcdui.game.GameCanvas; import javax.microedition.lcdui.game.Sprite; import javax.microedition.location.Criteria; import javax.microedition.location.Landmark; import javax.microedition.location.Location; import javax.microedition.location.LocationException; import javax.microedition.location.LocationListener; import javax.microedition.location.LocationProvider; import javax.microedition.location.QualifiedCoordinates; import javax.microedition.m2g.SVGImage; import javax.microedition.m2g.ScalableGraphics; import org.w3c.dom.Document; import org.w3c.dom.svg.SVGElement; import org.w3c.dom.svg.SVGMatrix; /** * * @author tkor */ public class CompassView extends GameCanvas implements LocationListener, Runnable{ private Graphics g = null; private Graphics bg = null; private ScalableGraphics sg = null; private float angle; private float old_angle; private Image back; private Image cover; private Image arrow_left; private Image arrow_right; private Image landmark_background; private Image glass; private Image gps_no_signal; private Image gps_ok_signal; private Image gps_default; private SVGImage compass; private Document compass_doc; private SVGImage navi; private Document navi_doc; private Timer mTimer; private TimerTask UIloop; private TimerTask GPSanimator; public static final Font DEFAULT_FONT = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN,Font.SIZE_LARGE); public static final Font SMALL_FONT = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL); private int currentLandmarkIndex; private boolean initialized = false; private boolean isValidGPS = false; private boolean showDefaultGPS = false; private boolean isLandscape = false; private AddLandmarkView addlandmark; private Vector landmarks; private SVGMatrix svgmatrix; private float degree = 0.0f; private float landmark_degree = 0.0f; private float old_landmark_degree = 0.0f; private double latitude = 0.0f; private double longitude = 0.0f; private QualifiedCoordinates currentCoordinates; private static final int default_anchor = Graphics.TOP|Graphics.LEFT; private Image bufferImage; private Sprite bufferSprite; private Criteria criteria; private Thread thread; private LocationProvider lp = null; public CompassView() { super(false); criteria=new Criteria(); criteria.setCostAllowed(true); criteria.setSpeedAndCourseRequired(true); criteria.setPreferredPowerConsumption(Criteria.POWER_USAGE_HIGH); thread=new Thread(this); thread.start(); loadResources(); initTasks(); addlandmark = new AddLandmarkView(this); //initial angle angle = 0; old_angle = -1; this.setFullScreenMode(true); refreshLandmarks(); sg = ScalableGraphics.createInstance(); bufferImage = Image.createImage(240, 320); bufferSprite = new Sprite(bufferImage); } public void refreshLandmarks() { currentLandmarkIndex = 0; landmarks = new LandmarkManager().getLandmarks(); }; private void loadResources() { int w = getWidth(); int h = getHeight(); System.out.println("width:" +w); System.out.println("height:" + h); try { back = ImageLoader.getInstance().loadImage("/back.png"); cover = ImageLoader.getInstance().loadImage("/cover.png"); arrow_left = ImageLoader.getInstance().loadImage("/arrow-left.png"); arrow_right = ImageLoader.getInstance().loadImage("/arrow-right.png"); landmark_background = ImageLoader.getInstance().loadImage("/background.png"); glass = ImageLoader.getInstance().loadImage("/glass.png"); compass = ImageLoader.getInstance().loadSVGImage("/compass.svg"); compass_doc = compass.getDocument(); navi = ImageLoader.getInstance().loadSVGImage("/navi.svg"); gps_no_signal = ImageLoader.getInstance().loadImage("/gps-no-signal.png"); gps_ok_signal = ImageLoader.getInstance().loadImage("/gps-ok.png"); gps_default = ImageLoader.getInstance().loadImage("/gps-default.png"); /* * The original compass image is drawn in a way that the needle center is in the top left corner of the image * Because rotation is applied using this top left corner as reference point, we can translate the needle to the * center of the screen and the rotation will now rotate the needle correctly. If the picture was drawn in a traditional * way the needle would rotate using the 0,0 point as its reference point and the needle would "fly" away from the screen. */ SVGElement svge = (SVGElement) compass_doc.getElementById("Compass"); SVGMatrix matrix = svge.getMatrixTrait("transform"); matrix = matrix.mTranslate(120,120); matrix = matrix.mScale(0.6f); svgmatrix = matrix; svge.setMatrixTrait("transform", matrix); //do the same translation to naviarrow navi_doc = navi.getDocument(); SVGElement navi_svge = (SVGElement)navi_doc.getElementById("Layer_4"); SVGMatrix navi_matrix = navi_svge.getMatrixTrait("transform"); navi_matrix.mTranslate(120,120); navi_matrix.mScale(0.6f); navi_svge.setMatrixTrait("transform", navi_matrix); }catch(IOException e) { CompassMidlet.getInstance().showAlert(e.toString()); } } private void initTasks() { UIloop = new TimerTask() { public void run() { render(bg); if(isLandscape) { System.out.println("Landscape"); bufferSprite.setRefPixelPosition(0, 239); bufferSprite.setTransform(Sprite.TRANS_ROT270); }else { bufferSprite.setRefPixelPosition(0, 0); bufferSprite.setTransform(Sprite.TRANS_NONE); } bufferSprite.paint(g); flushGraphics(); } }; GPSanimator = new TimerTask() { public void run() { if(showDefaultGPS) { showDefaultGPS = false; }else { showDefaultGPS = true; } } }; } protected void showNotify() { if (!initialized) { mTimer = new Timer(); g = getGraphics(); bg = bufferImage.getGraphics(); render(bg); if (isLandscape) { System.out.println("Landscape"); bufferSprite.setRefPixelPosition(0, 239); bufferSprite.setTransform(Sprite.TRANS_ROT270); } else { bufferSprite.setRefPixelPosition(0, 0); bufferSprite.setTransform(Sprite.TRANS_NONE); } bufferSprite.paint(g); flushGraphics(); initTasks(); mTimer.schedule(UIloop, 0, 30); mTimer.schedule(GPSanimator, 0, 1000); initialized = true; } } protected void hideNotify() { //cleanup everything mTimer.cancel(); initialized = false; } public void render(Graphics g) { g.setColor(0x000000); g.setClip(0, 0, 240, 320); g.fillRect(0, 0, getWidth(), getHeight()); drawCompass(g); drawLandmarks(g); drawSoftkeyLabels(g); addlandmark.draw(g); drawGPSStatus(g); //drawDebugData(g); } private void drawCompass(Graphics g) { g.drawImage(back, 0, 0, default_anchor); try { sg.bindTarget(g); sg.setRenderingQuality(sg.RENDERING_QUALITY_HIGH); if(angle != old_angle) { //rotate needle float rotation = angle-old_angle; rotation = (-1)*rotation; SVGElement svge = (SVGElement) compass_doc.getElementById("Compass"); SVGMatrix matrix = svgmatrix.mRotate((rotation)); old_angle = angle; svge.setMatrixTrait("transform", matrix); //rotate landmark direction float landmark_rotation = landmark_degree - old_landmark_degree; landmark_rotation = rotation + landmark_rotation; old_landmark_degree = landmark_degree; SVGElement navi_svge = (SVGElement)navi_doc.getElementById("Layer_4"); SVGMatrix navi_matrix = navi_svge.getMatrixTrait("transform"); navi_matrix.mRotate(landmark_rotation); navi_svge.setMatrixTrait("transform", navi_matrix); } sg.render(0, 0, compass); sg.render(0, 0, navi); }finally { sg.releaseTarget(); } g.drawImage(cover, 0, 0, default_anchor); } private void drawLandmarks(Graphics g) { int anchor = default_anchor; String s = ""; if (landmarks == null || landmarks.size() == 0) { s = "No landmarks."; }else { if(currentLandmarkIndex > 0) { Landmark landmark = (Landmark) landmarks.elementAt(currentLandmarkIndex -1); s = landmark.getName(); }else if(currentLandmarkIndex == 0) { s = "none"; } } int width = SMALL_FONT.stringWidth(s); int x = (240 - width) / 2; int y = 242; g.setFont(SMALL_FONT); g.setColor(0xFFFFFF); g.drawImage(landmark_background, 0, y, anchor); g.drawImage(arrow_left, 0, y, anchor); g.drawImage(arrow_right, 0, y, anchor); g.drawString(s, x, y+3, anchor); g.drawImage(glass, 0, y, anchor); } private void drawSoftkeyLabels(Graphics g) { g.setFont(SMALL_FONT); g.setColor(0xFFFFFF); g.drawString("Store Location", 0, 320, g.LEFT|g.BOTTOM); g.drawString("Exit", 240, 320, g.BOTTOM|g.RIGHT); } private void drawGPSStatus(Graphics g) { if(!isValidGPS) { if(showDefaultGPS) { g.drawImage(gps_default, 5, 5, default_anchor); }else { g.drawImage(gps_no_signal, 5, 5, default_anchor); } }else { g.drawImage(gps_ok_signal, 5, 5,default_anchor); } } private void drawDebugData(Graphics g) { g.setColor(0xFFFFFF); g.setFont(SMALL_FONT); g.drawString("" + degree, 0, 0, default_anchor); g.drawString("" + latitude, 0,SMALL_FONT.getHeight(),default_anchor); g.drawString("" + longitude, 0,SMALL_FONT.getHeight()*2,default_anchor); g.drawString(""+landmark_degree, 0, SMALL_FONT.getHeight()*3, default_anchor); } protected void keyPressed(int keyCode) { //System.out.println("key pressed:" + (keyCode)); } protected void keyReleased(int keyCode) { System.out.println("key pressed:" + (keyCode)); if (addlandmark.isShown()) { addlandmark.notifyKeyEvents(keyCode); } else { switch (keyCode) { case KeyCodes.LEFT: if (currentLandmarkIndex == 0) { currentLandmarkIndex = landmarks.size(); } else { currentLandmarkIndex--; } break; case KeyCodes.RIGHT: if (currentLandmarkIndex == (landmarks.size())) { currentLandmarkIndex = 0; } else { currentLandmarkIndex++; } break; case KeyCodes.LEFT_SOFTKEY: addlandmark.show(); break; case KeyCodes.RIGHT_SOFTKEY: CompassMidlet.getInstance().destroyApp(true); CompassMidlet.getInstance().notifyDestroyed(); break; default: break; } } } public void locationReceived(Location loc) { if(loc.isValid()) { isValidGPS = true; }else { isValidGPS = false; } float course = loc.getCourse(); QualifiedCoordinates coords = loc.getQualifiedCoordinates(); if(coords != null) { setCurrentCoordinates(coords); latitude = coords.getLatitude(); longitude = coords.getLongitude(); } //temp = 161.35f; if(!Float.isNaN(course)) { if(degree != course) { if (course != 0.0f) { degree = course; angle = degree; if (coords != null) { calculateLandmarkAngle(coords); } } } } } private void calculateLandmarkAngle(QualifiedCoordinates coordinates) { System.out.println("Calculating landmark angle"); if(landmarks.size() > 0 && currentLandmarkIndex > 0) { Landmark current = (Landmark) landmarks.elementAt(currentLandmarkIndex -1); System.out.println("current landmark:" + current.getName()); landmark_degree = coordinates.azimuthTo(current.getQualifiedCoordinates()); } } private synchronized void setCurrentCoordinates(QualifiedCoordinates newcoordinates) { currentCoordinates = newcoordinates; } public synchronized QualifiedCoordinates getCurrentCoordinates() { return currentCoordinates; } protected void sizeChanged(int w, int h) { if(w > h) {//landscape mode isLandscape = true; }else {//portrait mode isLandscape = false; } } public void locationUpdated(LocationProvider provider, Location location) { if(location.isValid()) { isValidGPS = true; float course = location.getCourse(); QualifiedCoordinates coords = location.getQualifiedCoordinates(); if(coords != null) { setCurrentCoordinates(coords); latitude = coords.getLatitude(); longitude = coords.getLongitude(); } //temp = 161.35f; if(!Float.isNaN(course)) { if(degree != course) { if (course != 0.0f) { degree = course; angle = degree; if (coords != null) { calculateLandmarkAngle(coords); } } } } } else { isValidGPS = false; } } public void providerStateChanged(LocationProvider provider, int newState) {} public void run() { try { lp = LocationProvider.getInstance(criteria); lp.setLocationListener(this, -1, -1, -1); }catch(LocationException le) { System.out.println("LOCATION ERROR:" + le.getMessage()); } } }