Create the CompassUI
class
file.
Import the required classes.
package com.nokia.example.location.tourist.ui; import java.io.IOException; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Image; import javax.microedition.location.Orientation; import com.nokia.example.location.tourist.TouristMIDlet; import com.nokia.example.location.tourist.model.ConfigurationProvider;
Create the CompassUI
class
and set it to extend Canvas
and implement CommandListener
and Runnable
.
Define the constants and commands used by this class.
/** * Viewer class representing a compass. */ public class CompassUI extends Canvas implements CommandListener, Runnable { /** Constant value for X coordinate. Used in arrays. */ private final int X = 0; /** Constant value for Y coordinate. Used in arrays. */ private final int Y = 1; /** Compass center X point */ private int centerX; /** Compass center Y point */ private int centerY; /** Constant value representing one degree. */ private final float degree = (float) (2 * Math.PI / 360.0); /** Current compass azimuth. */ private float azimuth = 0.0f; /** * Is orientation relative to the magnetic field of the Earth or true north * and gravity. */ private boolean isMagnetic; /** Flag telling is the compass update thread active */ private boolean threadActive = false; /** Sleep 1000ms during each compass update */ private final long SLEEPTIME = 1000; /** A reference to Route UI */ private Displayable route = null; /** A reference to Pitch and Roll UI */ private Displayable pitchrollUI = null; /** Command that swithes current displayable to Route UI */ private Command routeCmd = new Command("Route", Command.BACK, 1); /** Command that swithes current displayable to Pitch and Roll UI */ private Command prCmd = new Command("Pitch and Roll", Command.OK, 1); /** Compss background image. */ private Image compassImage = null;
Create a constructor for the class.
/** * Construct instance of this displayable. * * @param route * is a reference to Route UI. */ public CompassUI(Displayable route) { this.route = route; pitchrollUI = new PitchRollUI(this); loadCompassImage(); centerX = getWidth() / 2; centerY = getHeight() / 2; addCommand(routeCmd); addCommand(prCmd); setCommandListener(this); }
Create a method for loading a background image for the compass.
/** * Load compass backgound image from JAR file. */ private void loadCompassImage() { String imageName = "/compass_small.gif"; if (getWidth() > 160) { imageName = "/compass_large.gif"; } try { compassImage = Image.createImage(getClass().getResourceAsStream( imageName)); } catch (IOException e) { e.printStackTrace(); } }
Create the two below methods the VM will call, depending on the status of the Canvas' visibility.
/** * VM calls this method immediately prior to this Canvas being made visible * on the display. */ protected void showNotify() { // Actives compass update thread. threadActive = true; new Thread(this).start(); } /** * VM calls this method shortly after the Canvas has been removed from the * display. */ protected void hideNotify() { // Stops the thread. threadActive = false; }
Create a method to render the canvas.
/** * Renders the canvas. * * @param g - * the Graphics object to be used for rendering the Canvas */ protected void paint(Graphics g) { // clean up canvas g.setColor(255, 255, 255); g.fillRect(0, 0, getWidth(), getHeight()); int spikeLen = 5; int len = (compassImage.getWidth() / 2) - spikeLen; // draw compass background g.drawImage(compassImage, (getWidth() - compassImage.getWidth()) / 2, centerY, Graphics.LEFT | Graphics.VCENTER); // draw compass arrow g.setColor(0, 0, 255); drawArrow(g, degree * azimuth, len, spikeLen); // draw orientation type g.setColor(0, 0, 255); String otext = "True North"; if (!isMagnetic) { otext = "Magnetic field"; } g.drawString("Orientation: " + otext, 0, getHeight(), Graphics.BOTTOM | Graphics.LEFT); }
Create a method to draw the compass arrow.
/** * Draw a compass arrow rotated to a certain angle. * * @param g * is a reference to Graphics object. * @param angle * in degrees [0.0,360.0) * @param len * is arrows length. * @param spikeLen * is length of arrows spike. */ private void drawArrow(Graphics g, float angle, int len, int spikeLen) { int a[] = rotate(angle, 0, -(len - spikeLen)); int b[] = rotate(angle, -spikeLen, -(len - spikeLen)); int c[] = rotate(angle, 0, -len); int d[] = rotate(angle, spikeLen, -(len - spikeLen)); int e[] = rotate(angle + (degree * 180.0), 0, -len); // use red foreground color g.setColor(255, 0, 0); g.drawLine(centerX, centerY, centerX + a[X], centerY + a[Y]); g.drawLine(centerX + b[X], centerY + b[Y], centerX + d[X], centerY + d[Y]); g.drawLine(centerX + b[X], centerY + b[Y], centerX + c[X], centerY + c[Y]); g.drawLine(centerX + c[X], centerY + c[Y], centerX + d[X], centerY + d[Y]); // use black foreground color g.setColor(0, 0, 0); g.drawLine(centerX, centerY, centerX + e[X], centerY + e[Y]); }
Create the method for rotating the arrow.
/** * Rotate point (x,y) by degrees that angle parameter defines. The new * coordinate calculation is performed with a 2x2 rotate matrix. * * @param angle * to be rotated * @param x * coordinate * @param y * coordinate * @return new coordinate pair in int array format [x,y] */ private int[] rotate(double angle, int x, int y) { int rotated[] = new int[2]; rotated[X] = (int) (Math.cos(angle) * x + Math.sin(angle) * y); rotated[Y] = (int) (-Math.sin(angle) * x + Math.cos(angle) * y); return rotated; }
Create a run
method from Runnable
. Its purpose is to update the azimuth,
pitch and roll and to repaint the canvas. The isOrientationMagnetic
method
returns a boolean value that indicates whether this Orientation
is
relative to the magnetic field of the Earth or relative to true north and
gravity. The getCompassAzimuth
method returns the terminal's
horizontal compass azimuth in degrees relative to either magnetic or true
north.
For
more information, see isOrientationMagnetic
and getCompassAzimuth
in the Location API specification.
/** * run method from Runnable interface. Updates azimuth, pitch and roll * values and repaints the canvas. * * If Orientation is supported on the terminal, compass sensor is either 2D * or 3D. If the terminals compass sensor providers only compass azimuth, * pitch and roll values are Float.NaN. * * @see HideNotify() method. */ public void run() { // Keep the thread running until another displayable is set visible. // See also hideNotify() method. while (threadActive) { Orientation orientation = ConfigurationProvider.getInstance() .getOrientation(); if (orientation != null) { isMagnetic = orientation.isOrientationMagnetic(); azimuth = orientation.getCompassAzimuth(); } repaint(); try { // Pause this thread for a secord before next update. Thread.sleep(SLEEPTIME); } catch (InterruptedException e) { } } }
Create a method for detecting command button presses.
/** * Event indicating when a command button is pressed. * * @see javax.microedition.lcdui.CommandListener#commandAction(javax.microedition.lcdui.Command, * javax.microedition.lcdui.Displayable) */ public void commandAction(Command command, Displayable d) { if (command == routeCmd) { TouristMIDlet.getDisplay().setCurrent(route); } else if (command == prCmd) { TouristMIDlet.getDisplay().setCurrent(pitchrollUI); } } }
Create the LandmarkEditorUI
class
file.
Import the required classes.
package com.nokia.example.location.tourist.ui; import java.io.IOException; import java.util.Enumeration; import javax.microedition.lcdui.Alert; import javax.microedition.lcdui.AlertType; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Form; import javax.microedition.lcdui.List; import javax.microedition.lcdui.StringItem; import javax.microedition.lcdui.TextField; import javax.microedition.location.AddressInfo; import javax.microedition.location.Landmark; import javax.microedition.location.LandmarkException; import javax.microedition.location.QualifiedCoordinates; import com.nokia.example.location.tourist.TouristMIDlet; import com.nokia.example.location.tourist.Utils; import com.nokia.example.location.tourist.model.ControlPoints; import com.nokia.example.location.tourist.model.TouristData;
Create the LandmarkEditorUI
class
and set it to extend Form
and implement CommandListener
.
Define the TextField
s used by the form.
/** * Viewer class enabling landmarks address info monifications. */ class LandmarkEditorUI extends Form implements CommandListener { // Landmark fields, (*) = required field private TextField nameField = new TextField("Name (*):", "", 20, TextField.ANY); private TextField descField = new TextField("Description (*):", "", 40, TextField.ANY); // AddressInfo fields private TextField countryField = new TextField("Country:", "", 20, TextField.ANY); private TextField stateField = new TextField("State:", "", 20, TextField.ANY); private TextField cityField = new TextField("City:", "", 20, TextField.ANY); private TextField streetField = new TextField("Street:", "", 20, TextField.ANY); private TextField buildingNameField = new TextField("Building name (*):", "", 20, TextField.ANY);
Define the coordinate information StringItems
and
the commands and constants used by the Landmark selector list. The QualifiedCoordinates
class
represents coordinates as latitude-longitude-altitude values that are associated
with an accuracy value.
For
more information, see QualifiedCoordinates
in
the Location API specification.
// Coordinate information private StringItem lat = new StringItem("Lat:", ""); private StringItem lon = new StringItem("Lon:", ""); private StringItem alt = new StringItem("Alt:", ""); /** Landmark selector list */ private List list = new List("Landmarks:", List.EXCLUSIVE); private Command saveNewCmd = new Command("Save", Command.OK, 1); private Command saveUpdatedCmd = new Command("Save", Command.OK, 1); private Command updateCmd = new Command("Update", Command.OK, 1); private Command removeCmd = new Command("Remove", Command.OK, 1); private Command listCmd = new Command("List", Command.OK, 1); private Command routeCmd = new Command("Route", Command.BACK, 1); public static final int MODE_UPDATE = 0; public static final int MODE_ADDNEW = 1; private QualifiedCoordinates coord = null; private Displayable route = null; private TouristData data = null;
Create the constructor for the class.
/** * Construct Landmark Editor UI Form. * * @param route - * a reference of Route UI. * @param data - * a reference to TouristData model layer class. */ public LandmarkEditorUI(Displayable route, TouristData data) { super("Landmark Editor"); this.route = route; this.data = data; // route and list commands always available on landmark editor addCommand(routeCmd); addCommand(listCmd); setCommandListener(this); // route command always available on landmarks list list.addCommand(routeCmd); list.setCommandListener(this); }
Create a method
for initializing the UI components and showing the landmark editor. The getAltitude
method
returns the altitude component of this coordinate.
/** * Initialize UI components and show the landmark editor. */ public void showEditor(QualifiedCoordinates newCoord, int mode) { this.coord = newCoord; // initialize coordinate values lat.setText(Utils.formatDouble(newCoord.getLatitude(), 3)); lon.setText(Utils.formatDouble(newCoord.getLongitude(), 3)); alt.setText(Utils.formatDouble(newCoord.getAltitude(), 1)); // initialize editable test field values nameField.setString(""); descField.setString(""); countryField.setString(""); stateField.setString(""); cityField.setString(""); streetField.setString(""); buildingNameField.setString(""); deleteAll(); append(nameField); append(descField); append(countryField); append(stateField); append(cityField); append(streetField); append(buildingNameField); append(lat); append(lon); append(alt);
// Update existing landmark. if (mode == MODE_UPDATE) { Landmark lm = ControlPoints.getInstance().findNearestLandMark( newCoord); if (lm != null) { nameField.setString(lm.getName()); descField.setString(lm.getDescription()); AddressInfo info = lm.getAddressInfo(); if (info != null) { countryField.setString(info.getField(AddressInfo.COUNTRY)); stateField.setString(info.getField(AddressInfo.STATE)); cityField.setString(info.getField(AddressInfo.CITY)); streetField.setString(info.getField(AddressInfo.STREET)); buildingNameField.setString(info .getField(AddressInfo.BUILDING_NAME)); } } removeCommand(updateCmd); removeCommand(saveNewCmd); addCommand(saveUpdatedCmd); addCommand(listCmd); } // Add new landmark to the landmark store. else if (mode == MODE_ADDNEW) { removeCommand(updateCmd); removeCommand(saveUpdatedCmd); addCommand(saveNewCmd); addCommand(listCmd); } TouristMIDlet.getDisplay().setCurrent(this); }
Create a method for showing the landmark selector list.
/** * Show landmark selector List. Content of the list is refreshed each time * this method is called. */ public void showList() { list.deleteAll(); Landmark lm = null; Enumeration landmarks = ControlPoints.getInstance().getLandMarks(); // Check whether landmarks can be founds from the Landmark store. if (landmarks != null) { while (landmarks.hasMoreElements()) { lm = ((Landmark) landmarks.nextElement()); list.append(lm.getName(), null); } list.addCommand(updateCmd); list.addCommand(removeCmd); } // No landmarks found (list is empty) else { list.removeCommand(updateCmd); list.removeCommand(removeCmd); } TouristMIDlet.getDisplay().setCurrent(list); }
Create a method for checking that the required fields are not missing.
/** * Check whether any required fields are missing. (*) on the TextFields label * indicates that field is mandatory. * * @return Name of the missing field name or null indicating no required * fields are missing. */ private String checkRequiredFields() { if (nameField.getString().equals("")) { return "Name"; } else if (nameField.getString().equals("")) { return "Description"; } else if (buildingNameField.getString().equals("")) { return "Building name"; } return null; }
Create a method for generating a landmark from UI component values.
/** * Generate landmark from UI component values. * * @return Genereated Landmark. */ private Landmark generateLandmark() { String field = checkRequiredFields(); if (field != null) { Alert alert = new Alert("Error", "Value for required field " + field + " is missing.", null, AlertType.ERROR); alert.setTimeout(3000); // 3 secs TouristMIDlet.getDisplay().setCurrent(alert, this); return null; } AddressInfo info = new AddressInfo(); info.setField(AddressInfo.COUNTRY, countryField.getString()); info.setField(AddressInfo.STATE, stateField.getString()); info.setField(AddressInfo.CITY, cityField.getString()); info.setField(AddressInfo.STREET, streetField.getString()); info.setField(AddressInfo.BUILDING_NAME, buildingNameField.getString()); Landmark lm = new Landmark(nameField.getString(), descField.getString(), coord, info); return lm; }
Write code for detecting key presses.
/** * Event indicating when a command button is pressed. * * @see javax.microedition.lcdui.CommandListener#commandAction(javax.microedition.lcdui.Command, * javax.microedition.lcdui.Displayable) */ public void commandAction(Command command, Displayable displayable) { Landmark landmark = null; // Add new Landmark to the LandmarkStore if (command == saveNewCmd) { landmark = generateLandmark(); if (landmark != null) { try { ControlPoints.getInstance().addLandmark(landmark); data.createProximityListener(coord); } catch (IOException e) { Alert alert = new Alert("Error", "I/O Error during add operation", null, AlertType.ERROR); alert.setTimeout(3000); // 3 secs TouristMIDlet.getDisplay().setCurrent(alert); } // New landmark is available on the list showList(); } } // Update existing landmark else if (command == saveUpdatedCmd) { landmark = generateLandmark(); if (landmark != null) { try { ControlPoints.getInstance().updateLandmark(landmark); data.createProximityListener(coord); } catch (IOException e) { Alert alert = new Alert("Error", "I/O Error during update operation", null, AlertType.ERROR); alert.setTimeout(3000); // 3 secs TouristMIDlet.getDisplay().setCurrent(alert); } catch (LandmarkException e) { // Landmark instance passed as the parameter does not // belong to this LandmarkStore or does not exist in the // store any more. Alert alert = new Alert("Error", "Unexpected error: can not find landmark from " + "the landmark store.", null, AlertType.ERROR); alert.setTimeout(3000); // 3 secs TouristMIDlet.getDisplay().setCurrent(alert); } // Updated landmark is available on the list showList(); } } // Go back to the previous screen else if (command == routeCmd) { TouristMIDlet.getDisplay().setCurrent(route); } // Show landmark editor for the selected landmark. else if (command == updateCmd) { int index = list.getSelectedIndex(); landmark = ControlPoints.getInstance().findLandmark(index); showEditor(landmark.getQualifiedCoordinates(), MODE_UPDATE); } // Remove selected Landmark from LandmarkStore else if (command == removeCmd) { try { int index = list.getSelectedIndex(); landmark = ControlPoints.getInstance().findLandmark(index); ControlPoints.getInstance().removeLandmark(landmark); Alert alert = new Alert("Information", "Landmark removed successfully.", null, AlertType.INFO); alert.setTimeout(3000); // 3 secs TouristMIDlet.getDisplay().setCurrent(alert); } catch (IOException e) { Alert alert = new Alert("Error", "I/O Error during operation", null, AlertType.ERROR); alert.setTimeout(3000); // 3 secs TouristMIDlet.getDisplay().setCurrent(alert); } catch (LandmarkException le) { Alert alert = new Alert("Error", "landmark can not be found from the landmark store.", null, AlertType.ERROR); alert.setTimeout(3000); // 3 secs TouristMIDlet.getDisplay().setCurrent(alert); } showList(); } // Show the list of Landmarks else if (command == listCmd) { showList(); } } }
Create the MessageUI
class
file.
Import the required classes.
package com.nokia.example.location.tourist.ui; import javax.microedition.lcdui.Alert; import javax.microedition.lcdui.AlertType; import javax.microedition.lcdui.Gauge; import com.nokia.example.location.tourist.TouristMIDlet;
Create the MessageUI
class.
/** * Viewer class containing a general suppose Alert notification(s). */ public class MessageUI {
Create a method for showing an alert that the Location API is not supported.
/** * Shows a alert that Location API is not supported. */ public static void showApiNotSupported() { Alert alert = new Alert("Information", "Device do not support Location API", null, AlertType.INFO); TouristMIDlet.getDisplay().setCurrent(alert); }
Create a method for showing an alert that location data is unavailable.
/** * Shows a alert that Location data is not available. */ public static void showLocationDataNotAvailable() { Alert alert = new Alert("Information", "Location data is not yet available.", null, AlertType.INFO); TouristMIDlet.getDisplay().setCurrent(alert); }
Create a status dialog about the state of the location provider.
/** * Show a status dialog informing about state of location provider. */ public static void showLocationProviderState() { Gauge indicator = new Gauge(null, false, 50, 1); indicator.setValue(Gauge.CONTINUOUS_RUNNING); Alert alert = new Alert("Information", "Please wait, looking for location data....", null, AlertType.INFO); alert.setIndicator(indicator); TouristMIDlet.getDisplay().setCurrent(alert); } }
Create the PitchRollUI
class
file.
Import the required classes.
package com.nokia.example.location.tourist.ui; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Graphics; import javax.microedition.location.Orientation; import com.nokia.example.location.tourist.TouristMIDlet; import com.nokia.example.location.tourist.model.ConfigurationProvider;
Create the PitchRollUI
class
and set it to extend Canvas
and implement CommandListener
and Runnable
.
Define the constants, classes commands used by the class. Also create the
constructor.
/** * Viewer class that renders orientations pitch and roll values to meters. */ public class PitchRollUI extends Canvas implements CommandListener, Runnable { private CompassUI compass; private float pitch = Float.NaN; private float roll = Float.NaN; /** Flag telling is the compass update thread active */ private boolean threadActive = false; /** Sleep 1000ms during each compass update */ private final long SLEEPTIME = 1000; private Command compassCmd = new Command("Compass", Command.BACK, 1); public PitchRollUI(CompassUI compass) { this.compass = compass; addCommand(compassCmd); setCommandListener(this); }
Create the methods that control the compass' update thread.
/** * VM calls this method immediately prior to this Canvas being made visible * on the display. */ protected void showNotify() { // Actives compass update thread. threadActive = true; new Thread(this).start(); } /** * VM calls this method shortly after the Canvas has been removed from the * display. */ protected void hideNotify() { // Stops the thread. threadActive = false; }
Create a run
method
for the class. It needs to update the azimuth, pitch and roll values and repaint
the canvas. The getPitch
method returns the terminal's
tilt in degrees defined as an angle in the vertical plane orthogonal to the
ground, and through the longitudinal axis of the terminal, whereas the getRoll
method
returns the terminal's rotation in degrees around its own longitudinal axis.
For
more information, see getPitch
and getRoll
in the Location API specification.
/** * run method from Runnable interface. Updates azimuth, pitch and roll * values and repaints the canvas. * * If Orientation is supported on the terminal, support level may be either * 2D or 3D depending on the compass sensor. If the sensor providers only * compass azimuth, pitch and roll values are Float.NaN. */ public void run() { // Run this thread until this displayable is not visiable. // See also hideNotify() method. while (threadActive) { Orientation orientation = ConfigurationProvider.getInstance() .getOrientation(); if (orientation != null) { pitch = orientation.getPitch(); roll = orientation.getRoll(); } repaint(); try { // Pause this thread for a secord before next update. Thread.sleep(SLEEPTIME); } catch (InterruptedException e) { } } }
Create a method for rendering the canvas.
/** * Renders the canvas. * * @param g - * the Graphics object to be used for rendering the Canvas */ protected void paint(Graphics g) { // clean up canvas g.setColor(255, 255, 255); g.fillRect(0, 0, getWidth(), getHeight()); paintPitch(g); paintRoll(g); }
Create a method for drawing a meter with a scale.
/** * Draws a customized meter with a scale. */ protected void drawMeter(Graphics g, int min, int max, int smallStep, int largeStep, int baseline, int margin) { double position; double scale = 100.0; // scale value to minimize rounding error int x; g.setColor(0x0000ff); g.drawLine(margin, baseline, getWidth(), baseline); for (int i = min; i <= max; i += smallStep) { position = (((i + max) * scale * (getWidth() - margin)) / (2 * max)) / scale; x = margin + (int) position; g.drawLine(x, baseline - 3, x, baseline + 3); } for (int i = min; i <= max; i += largeStep) { position = (((i + max) * scale * (getWidth() - margin)) / (2 * max)) / scale; x = margin + (int) position; g.drawLine(x, baseline - 5, x, baseline + 5); } }
Create a method for painting the pitch meter and placing the current pitch value to it.
/** * Paint pitch meter and place the current pitch value to the meter. * * @param g - * the Graphics object to be used for rendering the Canvas */ protected void paintPitch(Graphics g) { int baseline = 10; int textAreaWidth = 50; double position; g.setColor(0x000000); g.drawString("Pitch", 0, baseline - 5, Graphics.TOP | Graphics.LEFT); g.drawString("-90", textAreaWidth + 1, baseline, Graphics.TOP | Graphics.LEFT); g.drawString("0", textAreaWidth + (getWidth() - textAreaWidth) / 2, baseline, Graphics.TOP | Graphics.HCENTER); g.drawString("+90", getWidth(), baseline, Graphics.TOP | Graphics.RIGHT); drawMeter(g, -90, 90, 10, 30, baseline, textAreaWidth); // Draw the marker only if terminals pitch is available. if (pitch != Float.NaN) { position = (((pitch + 90.0) * 100 * (getWidth() - textAreaWidth)) / (2 * 90)) / 100; g.setColor(0x000000); g.fillRect(textAreaWidth + (int) position - 3, baseline - 2, 5, 5); } }
Create a method for painting the roll meter and placing the current roll value to it.
/** * Paint roll meter and place the current pitch value to the meter. * * @param g - * the Graphics object to be used for rendering the Canvas */ protected void paintRoll(Graphics g) { int baseline = 40; int textAreaWidth = 50; double position; g.setColor(0x000000); g.drawString("Roll", 0, baseline - 5, Graphics.TOP | Graphics.LEFT); g.drawString("-180", textAreaWidth + 1, baseline, Graphics.TOP | Graphics.LEFT); g.drawString("0", textAreaWidth + (getWidth() - textAreaWidth) / 2, baseline, Graphics.TOP | Graphics.HCENTER); g.drawString("+180", getWidth(), baseline, Graphics.TOP | Graphics.RIGHT); drawMeter(g, -180, 180, 15, 60, baseline, textAreaWidth); // Draw the marker only if terminals roll is available. if (roll != Float.NaN) { position = (((roll + 180.0) * 100 * (getWidth() - textAreaWidth)) / (2 * 180)) / 100; g.setColor(0x000000); g.fillRect(textAreaWidth + (int) position - 3, baseline - 2, 5, 5); } }
Create an event for monitoring command button key presses.
/** * Event indicating when a command button is pressed. * * @see javax.microedition.lcdui.CommandListener#commandAction(javax.microedition.lcdui.Command, * javax.microedition.lcdui.Displayable) */ public void commandAction(Command command, Displayable d) { if (command == compassCmd) { TouristMIDlet.getDisplay().setCurrent(compass); } } }
Create the ProviderQueryUI
class
file.
Import the required classes.
package com.nokia.example.location.tourist.ui; import javax.microedition.lcdui.Alert; import javax.microedition.lcdui.AlertType; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Form; import javax.microedition.lcdui.StringItem; import com.nokia.example.location.tourist.TouristMIDlet;
Create the ProviderQueryUI
class.
Define the classes, constants and commands used by the class.
/** * Viewer class that is responsible for all the UI actions when the application * is seaching for the location provider. */ public class ProviderQueryUI { /** Status information Form */ private Form searchForm = new Form("Seaching location provider..."); /** StringItem showing the current status. */ private StringItem infoItem = new StringItem("Status:", ""); /** Provider cost selection command - Yes. */ private Command yesCmd = new Command("Yes", Command.OK, 1); /** Provider cost selection command - No. */ private Command noCmd = new Command("No", Command.STOP, 1); /** A boolean indicating may user allow location provider cost. */ private boolean result = false; private static final String COST_QUERY_MESSAGE = "Cost free location providers can not be found. Do you with continue " + "search with providers that cost?"; private static final String OUT_OF_SERVICE_MESSAGE = "All Location providers are currently out of service. Please unsure " + "that location-providing module is properly connected."; private static final String SEACHING_FREE_PROVIDERS = "Seaching for free location providers."; private static final String SEACHING_COST_PROVIDERS = "Seaching for providers that may cost."; private static final String NOT_FOUND_MESSAGE = "Try again after location-providing module is properly connected."; private static final String NO_FREE_SERVICE_SERVICE_MESSAGE = "Cost free location providers can not be found. Please ensure " + "that location-providing module is properly connected.";
Create the constructor for the class.
/** * Construct the UI with default values. */ public ProviderQueryUI() { infoItem.setText(SEACHING_FREE_PROVIDERS); searchForm.append(infoItem); }
Create methods for showing "out of service" and "no cost free location provider found" error messages.
/** * Show out of service error message. */ public void showOutOfService() { Alert alert = new Alert("Error", OUT_OF_SERVICE_MESSAGE, null, AlertType.ERROR); alert.setTimeout(Alert.FOREVER); TouristMIDlet.getDisplay().setCurrent(alert, searchForm); infoItem.setText(NOT_FOUND_MESSAGE); } /** * Show no cost free location provider found error message. */ public void showNoFreeServiceFound() { Alert alert = new Alert("Error", NO_FREE_SERVICE_SERVICE_MESSAGE, null, AlertType.ERROR); alert.setTimeout(Alert.FOREVER); TouristMIDlet.getDisplay().setCurrent(alert, searchForm); infoItem.setText(NOT_FOUND_MESSAGE); }
Create a method for querying the user about the cost of using the location provider.
/** * Query the user whether the use of location provider may cost. The use of * this method is locked with synchronized keyword, so only one thread can * access this method at once. * * @return a boolean indicating may user allow location provider cost. */ public synchronized boolean confirmCostProvider() { Alert alert = new Alert("Confimnation", COST_QUERY_MESSAGE, null, AlertType.CONFIRMATION); alert.addCommand(yesCmd); alert.addCommand(noCmd); alert.setTimeout(Alert.FOREVER); // Set the monitoring object to be this instance. final ProviderQueryUI hinstance = this; // Add a CommandLister as anomynous inner class alert.setCommandListener(new CommandListener() { /* * Event indicating when a command button is pressed. * * @see javax.microedition.lcdui.CommandListener#commandAction(javax.microedition.lcdui.Command, * javax.microedition.lcdui.Displayable) */ public void commandAction(Command command, Displayable d) { if (command == yesCmd) { infoItem.setText(SEACHING_COST_PROVIDERS); result = true; synchronized (hinstance) { // Wake up the monitoring object hinstance.notifyAll(); } } else if (command == noCmd) { result = false; infoItem.setText(NOT_FOUND_MESSAGE); synchronized (hinstance) { // Wake up the monitoring object hinstance.notifyAll(); } } } }); TouristMIDlet.getDisplay().setCurrent(alert, searchForm); // Wait indefinitely for notification. try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } TouristMIDlet.getDisplay().setCurrent(searchForm); return result; } }
Create the TouristUI
class
file.
Import the required classes.
package com.nokia.example.location.tourist.ui; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Command; import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.Font; import javax.microedition.lcdui.Graphics; import javax.microedition.location.AddressInfo; import javax.microedition.location.QualifiedCoordinates; import com.nokia.example.location.tourist.TouristMIDlet; import com.nokia.example.location.tourist.Utils; import com.nokia.example.location.tourist.model.ConfigurationProvider; import com.nokia.example.location.tourist.model.TouristData;
Create the TouristUI
class
and set it to extend Canvas
and implement CommandListener
.
Define the constants and commands used by the class and create the constructor.
/** * Viewer class that renders current location updates. */ public class TouristUI extends Canvas implements CommandListener { /** The current state of the location provider as a String */ private String providerState = "Unknown"; /** Proximity monitoring state. */ private String proximityState = "Waiting"; private AddressInfo info; private QualifiedCoordinates coord; private float speed; /** Command that shows compass canvas */ private Command compassCmd = new Command("Compass", Command.OK, 1); /** Command that shows Landmark editor UI */ private Command editorCmd = new Command("Editor", Command.STOP, 1); /** Rerefence to the Landmark editor UI */ private LandmarkEditorUI editorUI = null; /** Rerefence to the Compass UI */ private CompassUI compassUI = null; public TouristUI(TouristData data) { editorUI = new LandmarkEditorUI(this, data); compassUI = new CompassUI(this); checkSupportedFeatures(); addCommand(editorCmd); setCommandListener(this); }
Create a method for enabling the supported and disabling the unsupported features of the Location API on the UI.
/** * Enable supported Location API features on the UI and disable unsupported * features. */ protected void checkSupportedFeatures() { if (ConfigurationProvider.getInstance().isOrientationSupported()) { addCommand(compassCmd); } else { removeCommand(compassCmd); } }
Create methods for setting the provider and proximity states.
public void setProviderState(String state) { providerState = state; } public void setProximityState(String state) { proximityState = state; } public void setInfo(AddressInfo info, QualifiedCoordinates coord, float speed) { this.info = info; this.coord = coord; this.speed = speed; }
Create a method for rendering the canvas.
/** * Renders the canvas. * * @param g - * the Graphics object to be used for rendering the Canvas */ protected void paint(Graphics g) { Font f = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL); g.setFont(f); // use font height as a line height int lineHeight = f.getHeight(); // current line counter int line = 0; // clean the backround g.setColor(0xffffff); g.fillRect(0, 0, getWidth(), getHeight()); g.setColor(0x0000ff); g.drawString("Provider state: " + providerState, 0, lineHeight * (line++), Graphics.LEFT | Graphics.TOP); g.drawString("Proximity monitoring: " + proximityState, 0, lineHeight * (line++), Graphics.LEFT | Graphics.TOP); if (coord != null) { double lat = coord.getLatitude(); double lon = coord.getLongitude(); g.drawString("Lat, Lon (" + Utils.formatDouble(lat, 3) + ", " + Utils.formatDouble(lon, 3) + ")", 0, lineHeight * (line++), Graphics.TOP | Graphics.LEFT); g.drawString("Speed: " + Utils.formatDouble(speed, 2) + " m/s", 0, lineHeight * (line++), Graphics.TOP | Graphics.LEFT); } // Check if AddressInfo is available if (info != null) { String country = info.getField(AddressInfo.COUNTRY); String state = info.getField(AddressInfo.STATE); String city = info.getField(AddressInfo.CITY); String street = info.getField(AddressInfo.STREET); String buildingName = info.getField(AddressInfo.BUILDING_NAME); g.setColor(0x000000); if (country != null) g.drawString("Country: " + country, 0, lineHeight * (line++), Graphics.TOP | Graphics.LEFT); if (state != null) g.drawString("State: " + state, 0, lineHeight * (line++), Graphics.TOP | Graphics.LEFT); if (city != null) g.drawString("City: " + city, 0, lineHeight * (line++), Graphics.TOP | Graphics.LEFT); if (street != null) g.drawString("Street: " + street, 0, lineHeight * (line++), Graphics.TOP | Graphics.LEFT); if (buildingName != null) g.drawString("Building name: " + buildingName, 0, lineHeight * (line++), Graphics.TOP | Graphics.LEFT); } }
Create an event for detecting command key presses.
/** * Event indicating when a command button is pressed. * * @see javax.microedition.lcdui.CommandListener#commandAction(javax.microedition.lcdui.Command, * javax.microedition.lcdui.Displayable) */ public void commandAction(Command command, Displayable d) { if (command == editorCmd) { if (coord != null) { editorUI.showEditor(coord, LandmarkEditorUI.MODE_ADDNEW); } else { MessageUI.showLocationDataNotAvailable(); } } else if (command == compassCmd) { TouristMIDlet.getDisplay().setCurrent(compassUI); } } }