diff --git a/phoneClients/j2me/.gitignore b/phoneClients/j2me/.gitignore
deleted file mode 100644
index 1f773d9..0000000
--- a/phoneClients/j2me/.gitignore
+++ /dev/null
@@ -1,10 +0,0 @@
-*.class
-
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
-
-# Package Files #
-*.jar
-*.war
-*.ear
-
diff --git a/phoneClients/j2me/README.md b/phoneClients/j2me/README.md
deleted file mode 100644
index b740908..0000000
--- a/phoneClients/j2me/README.md
+++ /dev/null
@@ -1 +0,0 @@
-this is the j2me/javaMe client for gpstracker.
diff --git a/phoneClients/javaMe/.gitignore b/phoneClients/javaMe/.gitignore
new file mode 100644
index 0000000..1f773d9
--- /dev/null
+++ b/phoneClients/javaMe/.gitignore
@@ -0,0 +1,10 @@
+*.class
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+
diff --git a/phoneClients/javaMe/README.md b/phoneClients/javaMe/README.md
new file mode 100644
index 0000000..9a279e0
--- /dev/null
+++ b/phoneClients/javaMe/README.md
@@ -0,0 +1 @@
+this is the javaMe / j2me client for gpstracker.
diff --git a/phoneClients/javaMe/build.xml b/phoneClients/javaMe/build.xml
new file mode 100644
index 0000000..46a50e0
--- /dev/null
+++ b/phoneClients/javaMe/build.xml
@@ -0,0 +1,83 @@
+
+
+
+
+
+ Builds, tests, and runs the project .
+
+
+
diff --git a/phoneClients/javaMe/build/.timestamp b/phoneClients/javaMe/build/.timestamp
new file mode 100644
index 0000000..999b584
--- /dev/null
+++ b/phoneClients/javaMe/build/.timestamp
@@ -0,0 +1 @@
+ignore me
\ No newline at end of file
diff --git a/phoneClients/javaMe/build/manifest.mf b/phoneClients/javaMe/build/manifest.mf
new file mode 100644
index 0000000..bd06b7b
--- /dev/null
+++ b/phoneClients/javaMe/build/manifest.mf
@@ -0,0 +1,6 @@
+MIDlet-1: GpsTracker, , com.websmithing.gpstracker.GpsTracker
+MIDlet-Vendor: Vendor
+MIDlet-Name: GpsTracker
+MIDlet-Version: 1.0
+MicroEdition-Configuration: CLDC-1.1
+MicroEdition-Profile: MIDP-2.1
diff --git a/phoneClients/javaMe/build/preprocessed/com/websmithing/gpstracker/GpsHelper.java b/phoneClients/javaMe/build/preprocessed/com/websmithing/gpstracker/GpsHelper.java
new file mode 100644
index 0000000..2b1fc68
--- /dev/null
+++ b/phoneClients/javaMe/build/preprocessed/com/websmithing/gpstracker/GpsHelper.java
@@ -0,0 +1,164 @@
+//
+// GpsHelper.java
+// GpsTracker
+//
+// Created by Nick Fox on 12/1/13.
+// Copyright (c) 2013 Nick Fox. All rights reserved.
+//
+
+package com.websmithing.gpstracker;
+
+
+import javax.microedition.location.*;
+import java.util.Calendar;
+import java.util.Date;
+
+public class GpsHelper implements LocationListener {
+
+ private LocationProvider locationProvider = null;
+ private Coordinates oldCoordinates = null, currentCoordinates = null;
+ private float distance = 0;
+ private int azimuth = 0;
+ private String uploadWebsite;
+ private String queryString;
+ private GpsTracker midlet;
+ private int interval;
+ protected Calendar currentTime;
+ protected long sessionID;
+
+
+ public GpsHelper(GpsTracker Midlet, int Interval, String UploadWebsite){
+ currentTime = Calendar.getInstance();
+ sessionID = System.currentTimeMillis();
+ this.midlet = Midlet;
+ this.interval = Interval;
+ this.uploadWebsite = UploadWebsite;
+ }
+
+ // getting the gps location is based on an interval in seconds. for instance,
+ // the location is gotten once a minute, sent to the website to be stored in
+ // the DB (and then viewed on Google map) and used to retrieve a map tile (image)
+ // to be diplayed on the phone
+
+ public void startGPS() {
+ if (locationProvider == null) {
+ createLocationProvider();
+
+ Thread locationThread = new Thread() {
+ public void run(){
+ createLocationListener();
+ }
+ };
+ locationThread.start();
+ }
+ }
+
+ // this allows us to change how often the gps location is gotten
+ public void changeInterval(int Interval) {
+ if (locationProvider != null) {
+ locationProvider.setLocationListener(this, Interval, -1, -1);
+ }
+ }
+
+ private void createLocationProvider() {
+ Criteria cr = new Criteria();
+
+ try {
+ locationProvider = LocationProvider.getInstance(cr);
+ } catch (Exception e) {
+ midlet.log("GPS.createLocationProvider: " + e);
+ }
+ }
+
+ private void createLocationListener(){
+ // 2cd value is interval in seconds
+ try {
+ locationProvider.setLocationListener(this, interval, -1, -1);
+ } catch (Exception e) {
+ midlet.log("GPS.createLocationListener: " + e);
+ }
+ }
+
+ public void locationUpdated(LocationProvider provider, final Location location) {
+ // get new location from locationProvider
+
+ try {
+ Thread getLocationThread = new Thread(){
+ public void run(){
+ getLocation(location);
+ }
+ };
+
+ getLocationThread.start();
+ } catch (Exception e) {
+ midlet.log("GPS.locationUpdated: " + e);
+ }
+ }
+
+ public void providerStateChanged(LocationProvider provider, int newState) {}
+
+ private void getLocation(Location location){
+ float speed = 0;
+
+ try {
+ QualifiedCoordinates qualifiedCoordinates = location.getQualifiedCoordinates();
+
+ qualifiedCoordinates.getLatitude();
+
+ if (oldCoordinates == null){
+ oldCoordinates = new Coordinates(qualifiedCoordinates.getLatitude(),
+ qualifiedCoordinates.getLongitude(),
+ qualifiedCoordinates.getAltitude());
+ } else {
+ if (!Float.isNaN( qualifiedCoordinates.distance(oldCoordinates))) {
+ distance += qualifiedCoordinates.distance(oldCoordinates);
+ }
+
+ currentCoordinates = new Coordinates(qualifiedCoordinates.getLatitude(),
+ qualifiedCoordinates.getLongitude(),
+ qualifiedCoordinates.getAltitude());
+ azimuth = (int)oldCoordinates.azimuthTo(currentCoordinates);
+ oldCoordinates.setAltitude(qualifiedCoordinates.getAltitude());
+ oldCoordinates.setLatitude(qualifiedCoordinates.getLatitude());
+ oldCoordinates.setLongitude(qualifiedCoordinates.getLongitude());
+
+ }
+
+ if (qualifiedCoordinates != null){
+ Date d = new Date();
+
+ if (!Float.isNaN(location.getSpeed())) {
+ speed = location.getSpeed();
+ }
+
+ queryString = "?lat=" + String.valueOf(qualifiedCoordinates.getLatitude())
+ + "&lng=" + String.valueOf(qualifiedCoordinates.getLongitude())
+ + "&mph=" + String.valueOf((int)(speed/1609*3600))
+ + "&dir=" + String.valueOf(azimuth)
+ + "&dis=" + String.valueOf((int)(distance/1609))
+ + "&dt=" + d.toString()
+ + "&lm=" + location.getLocationMethod()
+ + "&pn=" + midlet.phoneNumber
+ + "&sid=" + String.valueOf(sessionID)
+ + "&acc=" + String.valueOf((int)(qualifiedCoordinates.getHorizontalAccuracy()*3.28))
+ + "&iv=" + String.valueOf(location.isValid())
+ + "&info=" + location.getExtraInfo("text/plain")
+ + "&zm=" + midlet.zoomLevel
+ + "&h=" + midlet.height
+ + "&w=" + midlet.width;
+
+ // with our query string built, we create a networker object to send the
+ // query to our website and get the map image and update the DB
+ NetWorker worker = new NetWorker(midlet, uploadWebsite);
+ worker.getUrl(queryString);
+
+ }
+
+ } catch (Exception e) {
+ midlet.log("GPS.getLocation: " + e);
+ }
+ }
+}
+
+
+
diff --git a/phoneClients/javaMe/build/preprocessed/com/websmithing/gpstracker/GpsTracker.java b/phoneClients/javaMe/build/preprocessed/com/websmithing/gpstracker/GpsTracker.java
new file mode 100644
index 0000000..f30f850
--- /dev/null
+++ b/phoneClients/javaMe/build/preprocessed/com/websmithing/gpstracker/GpsTracker.java
@@ -0,0 +1,285 @@
+//
+// GpsTracker.java
+// GpsTracker
+//
+// Created by Nick Fox on 12/1/13.
+// Copyright (c) 2013 Nick Fox. All rights reserved.
+//
+
+package com.websmithing.gpstracker;
+
+import javax.microedition.midlet.*;
+import javax.microedition.lcdui.*;
+import java.util.Calendar;
+
+public class GpsTracker extends MIDlet implements CommandListener, ItemStateListener {
+ private Display display;
+ private Form form;
+ private Form zoomScreen;
+ private Form settingsScreen;
+ private Command exitCmd;
+ private Command saveCmd;
+ private Command zoomCmd;
+ private Command settingsCmd;
+ private Command backCmd;
+ private TextField phoneNumberTextField;
+ private TextField uploadWebsiteTextField;
+ private Gauge zoomGauge;
+ private StringItem zoomStringItem;
+ private ChoiceGroup updateIntervalCG;
+ private String updateInterval;
+ private int[] iTimes = {60, 300, 900};
+
+ private RmsHelper rms;
+ private GpsHelper gps;
+
+ private String uploadWebsite;
+ private String defaultUploadWebsite = "http://www.websmithing.com/gpstracker/GetGoogleMap2.php";
+
+ protected String phoneNumber;
+ protected String zoomLevel;
+ protected int height, width;
+ protected Calendar currentTime;
+ protected long sessionID;
+ protected Image im = null;
+
+ public GpsTracker(){
+ form = new Form("GpsTracker");
+ display = Display.getDisplay(this);
+ exitCmd = new Command("Exit", Command.EXIT, 1);
+ zoomCmd = new Command("Zoom", Command.SCREEN, 2);
+ settingsCmd = new Command("Settings", Command.SCREEN, 3);
+
+ form.addCommand(exitCmd);
+ form.addCommand(zoomCmd);
+ form.addCommand(settingsCmd);
+ form.setCommandListener(this);
+
+ display.setCurrent(form);
+ currentTime = Calendar.getInstance();
+ sessionID = System.currentTimeMillis();
+ height = form.getHeight();
+ width = form.getWidth();
+
+ // RMS is the phone's built in storage, kind of like a database, but
+ // it only stores name-value pairs (like an associative array or hashtable).
+ // eveything is stored as a string.
+ getSettingsFromRMS();
+
+ // the phone number field is the only empty field when the application is
+ // first loaded. it does not have to be a phone number, it can be any string,
+ // but for uniqueness, it's best to use a phone number. this only has to be
+ // done once.
+ if (hasPhoneNumber()) {
+ startGPS();
+ displayInterval();
+ }
+ }
+
+ public void startApp() {
+ if ( form != null ) {
+ display.setCurrent(form);
+ }
+ }
+
+ // let the user know how often map will be updated
+ private void displayInterval() {
+ int tempTime = iTimes[Integer.parseInt(updateInterval)]/60;
+
+ display.setCurrent(form);
+ form.deleteAll();
+
+ if (tempTime == 1) {
+ log("Getting map once a minute...");
+ }
+ else {
+ log("Getting map every " + String.valueOf(tempTime) + " minutes...");
+ }
+ }
+
+ private void loadZoomScreen() {
+ zoomScreen = new Form("Zoom");
+ zoomGauge = new Gauge("Google Map Zoom", true, 17, Integer.parseInt(zoomLevel));
+ zoomStringItem = new StringItem(null, "");
+ zoomStringItem.setText("Zoom level: " + zoomGauge.getValue());
+ backCmd = new Command("Back", Command.SCREEN, 1);
+
+ zoomScreen.append(zoomGauge);
+ zoomScreen.append(zoomStringItem);
+ zoomScreen.addCommand(backCmd);
+ zoomScreen.setItemStateListener(this);
+ zoomScreen.setCommandListener(this);
+
+ display.setCurrent(zoomScreen);
+ }
+
+ // this method is called every time the zoom guage changes value. the zoom level is
+ // reset and saved
+ public void itemStateChanged(Item item) {
+ if (item == zoomGauge) {
+ zoomStringItem.setText("Zoom level: " + zoomGauge.getValue());
+ zoomLevel = String.valueOf(zoomGauge.getValue());
+
+ try {
+ rms.put("zoomLevel", zoomLevel);
+ rms.save();
+ }
+ catch (Exception e) {
+ log("GPSTracker.itemStateChanged: " + e);
+ }
+ }
+ }
+
+ private void loadSettingsScreen() {
+ settingsScreen = new Form("Settings");
+
+ phoneNumberTextField = new TextField("Phone number or user name", phoneNumber, 20, TextField.ANY);
+ uploadWebsiteTextField = new TextField("Upload website", uploadWebsite, 100, TextField.ANY);
+ settingsScreen.append(phoneNumberTextField);
+ settingsScreen.append(uploadWebsiteTextField);
+
+ String[] times = { "1 minute", "5 minutes", "15 minutes"};
+ updateIntervalCG = new ChoiceGroup("Update map how often?", ChoiceGroup.EXCLUSIVE, times, null);
+ updateIntervalCG.setSelectedIndex(Integer.parseInt(updateInterval), true);
+ settingsScreen.append(updateIntervalCG);
+
+ saveCmd = new Command("Save", Command.SCREEN, 1);
+ settingsScreen.addCommand(saveCmd);
+
+ settingsScreen.setCommandListener(this);
+ display.setCurrent(settingsScreen);
+ }
+
+ // get the settings from the phone's storage and load 4 global variables
+ public void getSettingsFromRMS() {
+ try {
+ rms = new RmsHelper(this, "GPSTracker");
+
+ phoneNumber = rms.get("phoneNumber");
+ uploadWebsite = rms.get("uploadWebsite");
+ zoomLevel = rms.get("zoomLevel");
+ updateInterval = rms.get("updateInterval");
+ }
+ catch (Exception e) {
+ log("GPSTracker.getSettingsFromRMS: " + e);
+ }
+
+ if ((uploadWebsite == null) || (uploadWebsite.trim().length() == 0)) {
+ uploadWebsite = defaultUploadWebsite;
+ }
+
+ if ((zoomLevel == null) || (zoomLevel.trim().length() == 0)) {
+ zoomLevel = "12";
+ }
+ if ((updateInterval == null) || (updateInterval.trim().length() == 0)) {
+ updateInterval = "1";
+ }
+ }
+
+ private boolean hasPhoneNumber() {
+ if ((phoneNumber == null) || (phoneNumber.trim().length() == 0)) {
+ log("Phone number required. Please go to settings.");
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+
+ // gps is started with the update interval. the interval is the time in between
+ // map updates
+ private void startGPS() {
+ if (gps == null) {
+ gps = new GpsHelper(this, iTimes[Integer.parseInt(updateInterval)], uploadWebsite);
+ gps.startGPS();
+ }
+ }
+
+ // this is called when the user changes the interval in the settings screen
+ private void changeInterval() {
+ if (gps == null) {
+ startGPS();
+ }
+ else {
+ gps.changeInterval(iTimes[Integer.parseInt(updateInterval)]);
+ }
+ }
+
+ // save settings back to phone memory
+ private void saveSettingsToRMS() {
+ try {
+ phoneNumber = phoneNumberTextField.getString();
+ uploadWebsite = uploadWebsiteTextField.getString();
+ updateInterval = String.valueOf(updateIntervalCG.getSelectedIndex());
+
+ rms.put("phoneNumber", phoneNumber);
+ rms.put("uploadWebsite", uploadWebsite);
+ rms.put("updateInterval", updateInterval);
+
+ rms.save();
+ }
+ catch (Exception e) {
+ log("GPSTracker.saveSettings: " + e);
+ }
+ display.setCurrent(form);
+ }
+
+ // this method displays the map image, it is called from the networker object
+ public void showMap(boolean flag)
+ {
+ if (flag == false) {
+ log("Map could not be downloaded.");
+ }
+ else {
+ ImageItem imageitem = new ImageItem(null, im, ImageItem.LAYOUT_DEFAULT, null);
+
+ if(form.size()!= 0) {
+ form.set(0, imageitem);
+ }
+ else {
+ form.append(imageitem);
+ }
+ }
+ }
+
+ public void log(String text) {
+ StringItem si = new StringItem(null, text);
+ si.setLayout(Item.LAYOUT_NEWLINE_AFTER);
+ form.append(si);
+ }
+
+ public void commandAction(Command cmd, Displayable screen) {
+ if (cmd == exitCmd) {
+ shutDownApp();
+ }
+ else if (cmd == saveCmd) {
+ saveSettingsToRMS();
+
+ if (hasPhoneNumber()) {
+ changeInterval();
+ displayInterval();
+ }
+ }
+ else if (cmd == settingsCmd) {
+ loadSettingsScreen();
+ }
+ else if (cmd == zoomCmd) {
+ loadZoomScreen();
+ }
+ else if (cmd == backCmd) {
+ displayInterval();
+ }
+ }
+
+ public void pauseApp() {}
+
+ public void destroyApp(boolean unconditional) {}
+
+ protected void shutDownApp() {
+ destroyApp(true);
+ notifyDestroyed();
+ }
+}
+
+
+
diff --git a/phoneClients/javaMe/build/preprocessed/com/websmithing/gpstracker/NetWorker.java b/phoneClients/javaMe/build/preprocessed/com/websmithing/gpstracker/NetWorker.java
new file mode 100644
index 0000000..8fe5191
--- /dev/null
+++ b/phoneClients/javaMe/build/preprocessed/com/websmithing/gpstracker/NetWorker.java
@@ -0,0 +1,119 @@
+//
+// NetWorker.java
+// GpsTracker
+//
+// Created by Nick Fox on 12/1/13.
+// Copyright (c) 2013 Nick Fox. All rights reserved.
+//
+
+package com.websmithing.gpstracker;
+
+import javax.microedition.io.*;
+import java.io.*;
+import javax.microedition.lcdui.Image;
+
+public class NetWorker {
+ private GpsTracker midlet;
+ private String uploadWebsite;
+ int i = 1;
+
+ public NetWorker(GpsTracker lbsMidlet, String UploadWebsite){
+ this.midlet = lbsMidlet;
+ this.uploadWebsite = UploadWebsite;
+ }
+
+ public void getUrl(String queryString) {
+ queryString = URLencodeSpaces(queryString);
+ String url = uploadWebsite + queryString;
+ HttpConnection httpConn = null;
+ InputStream inputStream = null;
+ DataInputStream iStrm = null;
+ ByteArrayOutputStream bStrm = null;
+ Image im = null;
+
+ try{
+ httpConn = (HttpConnection)Connector.open(url);
+
+ if(httpConn.getResponseCode() == HttpConnection.HTTP_OK){
+ inputStream = httpConn.openInputStream();
+ iStrm = new DataInputStream(inputStream);
+
+ byte imageData[];
+ int length = (int)httpConn.getLength();
+
+ if(length != -1) {
+ imageData = new byte[length];
+ iStrm.readFully(imageData);
+ }
+ else { //Length not available
+ bStrm = new ByteArrayOutputStream();
+ int ch;
+
+ while((ch = iStrm.read())!= -1) {
+ bStrm.write(ch);
+ }
+ imageData = bStrm.toByteArray();
+
+ }
+ im = Image.createImage(imageData, 0, imageData.length);
+ }
+ else {
+ midlet.log("NetWorker.getUrl responseCode: " + httpConn.getResponseCode());
+ }
+
+ } catch (Exception e) {
+ midlet.log("NetWorker.getUrl: " + e);
+ }
+ finally{ // Clean up
+ try{
+ if(bStrm != null)
+ bStrm.close();
+ if(iStrm != null)
+ iStrm.close();
+ if(inputStream != null)
+ inputStream.close();
+ if(httpConn != null)
+ httpConn.close();
+ }
+ catch(Exception e){}
+ }
+
+ // if we have successfully gotten a map image, then we want to display it
+ if( im == null) {
+ midlet.showMap(false);
+ }
+ else {
+ midlet.im = im;
+ midlet.showMap(true);
+ }
+
+ }
+
+ // http://forum.java.sun.com/thread.jspa?threadID=341790&messageID=1408555
+ private String URLencodeSpaces(String s)
+ {
+ if (s != null) {
+ StringBuffer tmp = new StringBuffer();
+ int i = 0;
+ try {
+ while (true) {
+ int b = (int)s.charAt(i++);
+
+ if (b != 0x20) {
+ tmp.append((char)b);
+ }
+ else {
+ tmp.append("%");
+ if (b <= 0xf) {
+ tmp.append("0");
+ }
+ tmp.append(Integer.toHexString(b));
+ }
+ }
+ }
+ catch (Exception e) {}
+ return tmp.toString();
+ }
+ return null;
+ }
+}
diff --git a/phoneClients/javaMe/build/preprocessed/com/websmithing/gpstracker/RmsHelper.java b/phoneClients/javaMe/build/preprocessed/com/websmithing/gpstracker/RmsHelper.java
new file mode 100644
index 0000000..08e624a
--- /dev/null
+++ b/phoneClients/javaMe/build/preprocessed/com/websmithing/gpstracker/RmsHelper.java
@@ -0,0 +1,88 @@
+//
+// RmsHelper.java
+// GpsTracker
+//
+// Created by Nick Fox on 12/1/13.
+// Copyright (c) 2013 Nick Fox. All rights reserved.
+//
+
+package com.websmithing.gpstracker;
+
+import java.util.*;
+import javax.microedition.rms.*;
+
+public class RmsHelper {
+ private GpsTracker midlet;
+ private String mRecordStoreName;
+ private Hashtable mHashtable;
+
+ public RmsHelper(GpsTracker Midlet, String recordStoreName) throws RecordStoreException {
+ this.midlet = Midlet;
+ this.mRecordStoreName = recordStoreName;
+ this.mHashtable = new Hashtable();
+ load();
+ }
+
+ public String get(String key) {
+ return (String)mHashtable.get(key);
+ }
+
+ public void put(String key, String value) {
+ if (value == null) value = "";
+ mHashtable.put(key, value);
+ }
+
+ private void load() throws RecordStoreException {
+ RecordStore rs = null;
+ RecordEnumeration re = null;
+
+ try {
+ rs = RecordStore.openRecordStore(mRecordStoreName, true);
+ re = rs.enumerateRecords(null, null, false);
+ while (re.hasNextElement()) {
+ byte[] raw = re.nextRecord();
+ String pref = new String(raw);
+ // Parse out the name.
+ int index = pref.indexOf('|');
+ String name = pref.substring(0, index);
+ String value = pref.substring(index + 1);
+ put(name, value);
+ }
+ }
+ finally {
+ if (re != null) re.destroy();
+ if (rs != null) rs.closeRecordStore();
+ }
+ }
+
+ public void save() throws RecordStoreException {
+ RecordStore rs = null;
+ RecordEnumeration re = null;
+ try {
+ rs = RecordStore.openRecordStore(mRecordStoreName, true);
+ re = rs.enumerateRecords(null, null, false);
+
+ // First remove all records, a little clumsy.
+ while (re.hasNextElement()) {
+ int id = re.nextRecordId();
+ rs.deleteRecord(id);
+ }
+
+ // Now save the preferences records.
+ Enumeration keys = mHashtable.keys();
+ while (keys.hasMoreElements()) {
+ String key = (String)keys.nextElement();
+ String value = get(key);
+ String pref = key + "|" + value;
+ byte[] raw = pref.getBytes();
+ rs.addRecord(raw, 0, raw.length);
+ }
+ }
+ finally {
+ if (re != null) re.destroy();
+ if (rs != null) rs.closeRecordStore();
+ }
+ }
+
+}
+
diff --git a/phoneClients/javaMe/dist/GpsTracker.jad b/phoneClients/javaMe/dist/GpsTracker.jad
new file mode 100644
index 0000000..fec3188
--- /dev/null
+++ b/phoneClients/javaMe/dist/GpsTracker.jad
@@ -0,0 +1,8 @@
+MIDlet-1: GpsTracker, , com.websmithing.gpstracker.GpsTracker
+MIDlet-Jar-Size: 12990
+MIDlet-Jar-URL: GpsTracker.jar
+MIDlet-Name: GpsTracker
+MIDlet-Vendor: Vendor
+MIDlet-Version: 1.0
+MicroEdition-Configuration: CLDC-1.1
+MicroEdition-Profile: MIDP-2.1
diff --git a/phoneClients/javaMe/dist/nbrun3504791845681826142/GpsTracker.jad b/phoneClients/javaMe/dist/nbrun3504791845681826142/GpsTracker.jad
new file mode 100644
index 0000000..fec3188
--- /dev/null
+++ b/phoneClients/javaMe/dist/nbrun3504791845681826142/GpsTracker.jad
@@ -0,0 +1,8 @@
+MIDlet-1: GpsTracker, , com.websmithing.gpstracker.GpsTracker
+MIDlet-Jar-Size: 12990
+MIDlet-Jar-URL: GpsTracker.jar
+MIDlet-Name: GpsTracker
+MIDlet-Vendor: Vendor
+MIDlet-Version: 1.0
+MicroEdition-Configuration: CLDC-1.1
+MicroEdition-Profile: MIDP-2.1
diff --git a/phoneClients/javaMe/nbproject/build-impl.xml b/phoneClients/javaMe/nbproject/build-impl.xml
new file mode 100644
index 0000000..da261d7
--- /dev/null
+++ b/phoneClients/javaMe/nbproject/build-impl.xml
@@ -0,0 +1,1250 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Classpath to J2ME Ant extension library (libs.j2me_ant_ext.classpath property) is not set. For example: location of mobility/modules/org-netbeans-mobility-antext.jar file in the IDE installation directory.
+ Platform home (platform.home property) is not set. Value of this property should be ${platform.active.description} emulator home directory location.
+ Platform boot classpath (platform.bootclasspath property) is not set. Value of this property should be ${platform.active.description} emulator boot classpath containing all J2ME classes provided by emulator.
+ Must set src.dir
+ Must set build.dir
+ Must set dist.dir
+ Must set dist.jar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set preprocessed.dir
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set build.classes.dir
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must select some files in the IDE or set javac.includes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set obfuscated.classes.dir
+
+
+
+ Must set obfuscated.classes.dir
+ Must set obfuscator.srcjar
+ Must set obfuscator.destjar
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set preverify.classes.dir
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MicroEdition-Configuration: ${platform.configuration}
+
+ MicroEdition-Configuration: ${platform.configuration}
+
+
+
+ MicroEdition-Profile: ${platform.profile}
+
+ MicroEdition-Profile: ${platform.profile}
+
+
+
+ Must set dist.jad
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${manifest.midlets}${evaluated.manifest.apipermissions}${evaluated.manifest.pushregistry}${manifest.others}${manifest.jad}
+ ${manifest.midlets}${evaluated.manifest.apipermissions}${evaluated.manifest.pushregistry}${manifest.others}${manifest.manifest}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Starting emulator with port number ${active.debug.port}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Starting emulator with port number ${active.debug.port}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Must set dist.javadoc.dir
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${all.configurations}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Property deployment.${deployment.method}.scriptfile not set. The property should point to an Ant script providing ${deployment.method} deployment.
+
+
+
+
+
+
+
+ Classpath to Ant Contrib library (libs.ant-contrib.classpath property) is not set.
+
+
+
+
+
+
+
+
+ Active project configuration: @{cfg}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Property build.root.dir is not set. By default its value should be \"build\".
+ Property dist.root.dir is not set. By default its value should be \"dist\".
+
+
+
+
+
diff --git a/phoneClients/javaMe/nbproject/genfiles.properties b/phoneClients/javaMe/nbproject/genfiles.properties
new file mode 100644
index 0000000..25e0ba6
--- /dev/null
+++ b/phoneClients/javaMe/nbproject/genfiles.properties
@@ -0,0 +1,8 @@
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+build.xml.data.CRC32=0f5fb758
+build.xml.script.CRC32=219d9ddc
+build.xml.stylesheet.CRC32=9c6a911d
+nbproject/build-impl.xml.data.CRC32=0f5fb758
+nbproject/build-impl.xml.script.CRC32=8bde2673
+nbproject/build-impl.xml.stylesheet.CRC32=051c3749
diff --git a/phoneClients/javaMe/nbproject/private/private.properties b/phoneClients/javaMe/nbproject/private/private.properties
new file mode 100644
index 0000000..2be98fe
--- /dev/null
+++ b/phoneClients/javaMe/nbproject/private/private.properties
@@ -0,0 +1,7 @@
+app-version.autoincrement=false
+config.active=
+deployment.counter=3
+deployment.number=3.0.0
+javadoc.preview=true
+netbeans.user=C:\\Users\\Nick\\AppData\\Roaming\\NetBeans\\7.4
+platform.apis.defaults=JSR179-1.0,JSR256-1.2
diff --git a/phoneClients/javaMe/nbproject/private/private.xml b/phoneClients/javaMe/nbproject/private/private.xml
new file mode 100644
index 0000000..79ec6ce
--- /dev/null
+++ b/phoneClients/javaMe/nbproject/private/private.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+ file:/C:/Users/Nick/Documents/Visual%20Studio%202012/Projects/GpsTracker/src/com/websmithing/gpstracker/NetWorker.java
+ file:/C:/Users/Nick/Documents/Visual%20Studio%202012/Projects/GpsTracker/src/com/websmithing/gpstracker/GpsTracker.java
+ file:/C:/Users/Nick/Documents/Visual%20Studio%202012/Projects/GpsTracker/src/com/websmithing/gpstracker/GpsHelper.java
+ file:/C:/Users/Nick/Documents/Visual%20Studio%202012/Projects/GpsTracker/src/com/websmithing/gpstracker/RmsHelper.java
+
+
+
diff --git a/phoneClients/javaMe/nbproject/project.properties b/phoneClients/javaMe/nbproject/project.properties
new file mode 100644
index 0000000..0be96a8
--- /dev/null
+++ b/phoneClients/javaMe/nbproject/project.properties
@@ -0,0 +1,116 @@
+abilities=MMAPI=1.2,JSR82=1.1,JSR280=1.0,JSR226=1.0,MIDP=2.1,SATSA=1.0,CLDC=1.1,JSR177=1.0,JSR179=1.0,J2MEWS=1.0,WMA=2.0,JSR172=1.0,JSR257=1.0,JSR256=1.2,OBEX=1.0,ColorScreen,JSR239=1.0,TouchScreen,JSR211=1.0,JSR234=1.0,ScreenWidth=240,JSR75=1.0,JSR184=1.1,ScreenHeight=320,ScreenColorDepth=16,
+all.configurations=\ ,JavaMEPhone1
+application.args=
+application.description=
+application.description.detail=
+application.name=
+application.vendor=Vendor
+build.classes.dir=${build.dir}/compiled
+build.classes.excludes=**/*.java,**/*.form,**/*.class,**/.nbintdb,**/*.mvd,**/*.wsclient,**/*.vmd
+build.dir=build/${config.active}
+build.root.dir=build
+configs.JavaMEPhone1.abilities=MMAPI=1.2,JSR82=1.1,JSR280=1.0,JSR226=1.0,MIDP=2.1,SATSA=1.0,CLDC=1.1,JSR177=1.0,JSR179=1.0,J2MEWS=1.0,WMA=2.0,JSR172=1.0,JSR257=1.0,JSR256=1.2,OBEX=1.0,ColorScreen,JSR239=1.0,TouchScreen,JSR211=1.0,JSR234=1.0,ScreenWidth=240,JSR75=1.0,JSR184=1.1,ScreenHeight=320,ScreenColorDepth=16,
+configs.JavaMEPhone1.platform.active=Oracle_Java_TM__Platform_Micro_Edition_SDK_3_4
+configs.JavaMEPhone1.platform.active.description=Oracle Java(TM) Platform Micro Edition SDK 3.4
+configs.JavaMEPhone1.platform.apis=JSR239-1.0,SATSA-1.0,WMA-2.0,JSR82-1.1,JSR184-1.1,JSR280-1.0,JSR172-1.0,JSR234-1.0,OBEX-1.0,JSR179-1.0,JSR75-1.0,JSR226-1.0,JSR211-1.0,JSR257-1.0,JSR177-1.0,J2ME-WS-1.0,MMAPI-1.2,JSR256-1.2
+configs.JavaMEPhone1.platform.bootclasspath=${platform.home}/lib/jsr172_1.0.jar:${platform.home}/lib/jsr234_1.0.jar:${platform.home}/lib/jsr135_1.2.jar:${platform.home}/lib/jsr239_1.0.jar:${platform.home}/lib/jsr75_1.0.jar:${platform.home}/lib/jsr211_1.0.jar:${platform.home}/lib/jsr177_1.0.jar:${platform.home}/lib/jsr257_1.0.jar:${platform.home}/lib/jsr184_1.1.jar:${platform.home}/lib/jsr226_1.0.jar:${platform.home}/lib/jsr205_2.0.jar:${platform.home}/lib/jsr082_1.1.jar:${platform.home}/lib/jsr179_1.0.jar:${platform.home}/lib/jsr256_1.2.jar:${platform.home}/lib/jsr280_1.0.jar:${platform.home}/lib/midp_2.1.jar:${platform.home}/lib/cldc_1.1.jar
+configs.JavaMEPhone1.platform.configuration=CLDC-1.1
+configs.JavaMEPhone1.platform.device=JavaMEPhone1
+configs.JavaMEPhone1.platform.profile=MIDP-2.1
+configs.JavaMEPhone1.platform.trigger=CLDC
+configs.JavaMEPhone1.platform.type=UEI-1.0.1
+debug.level=debug
+debugger.timeout=
+deployment.copy.target=deploy
+deployment.instance=default
+deployment.jarurl=${dist.jar}
+deployment.method=NONE
+deployment.override.jarurl=false
+dist.dir=dist/${config.active}
+dist.jad=GpsTracker.jad
+dist.jar=GpsTracker.jar
+dist.javadoc.dir=${dist.dir}/doc
+dist.root.dir=dist
+extra.classpath=
+file.reference.builtin.ks=${netbeans.user}/config/j2me/builtin.ks
+filter.exclude.tests=false
+filter.excludes=
+filter.more.excludes=**/overview.html,**/package.html
+filter.use.standard=true
+jar.compress=true
+javac.debug=true
+javac.deprecation=false
+javac.encoding=windows-1255
+javac.optimize=false
+javac.source=1.3
+javac.target=1.3
+javadoc.author=false
+javadoc.encoding=
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+libs.classpath=
+main.class=
+main.class.class=applet
+manifest.apipermissions=
+manifest.file=manifest.mf
+manifest.is.liblet=false
+manifest.jad=
+manifest.manifest=
+manifest.midlets=MIDlet-1: GpsTracker, , com.websmithing.gpstracker.GpsTracker\n
+manifest.others=MIDlet-Vendor: Vendor\nMIDlet-Name: GpsTracker\nMIDlet-Version: 1.0\n
+manifest.pushregistry=
+name=GpsTracker
+no.dependencies=false
+nokiaS80.application.icon=
+obfuscated.classes.dir=${build.dir}/obfuscated
+obfuscation.custom=
+obfuscation.level=0
+obfuscator.destjar=${build.dir}/obfuscated.jar
+obfuscator.srcjar=${build.dir}/before-obfuscation.jar
+platform.active=Oracle_Java_TM__Platform_Micro_Edition_SDK_3_4
+platform.active.description=Oracle Java(TM) Platform Micro Edition SDK 3.4
+platform.apis=JSR179-1.0,JSR256-1.2
+platform.bootclasspath=${platform.home}/lib/jsr179_1.0.jar:${platform.home}/lib/jsr256_1.2.jar:${platform.home}/lib/midp_2.1.jar:${platform.home}/lib/cldc_1.1.jar
+platform.configuration=CLDC-1.1
+platform.device=JavaMEPhone1
+platform.fat.jar=true
+platform.profile=MIDP-2.1
+platform.trigger=CLDC
+platform.type=UEI-1.0.1
+preprocessed.dir=${build.dir}/preprocessed
+preverify.classes.dir=${build.dir}/preverified
+preverify.sources.dir=${build.dir}/preverifysrc
+resources.dir=resources
+run.cmd.options=
+run.jvmargs=
+run.method=STANDARD
+run.security.domain=minimum
+run.use.security.domain=false
+savaje.application.icon=
+savaje.application.icon.focused=
+savaje.application.icon.small=
+savaje.application.uid=TBD
+savaje.bundle.base=
+savaje.bundle.debug=false
+savaje.bundle.debug.port=
+semc.application.caps=
+semc.application.icon=
+semc.application.icon.count=
+semc.application.icon.splash=
+semc.application.icon.splash.installonly=false
+semc.application.uid=E2454680
+semc.certificate.path=
+semc.private.key.password=
+semc.private.key.path=
+sign.alias=minimal
+sign.enabled=false
+sign.keystore=${file.reference.builtin.ks}
+src.dir=src
+use.emptyapis=true
+use.preprocessor=true
diff --git a/phoneClients/javaMe/nbproject/project.xml b/phoneClients/javaMe/nbproject/project.xml
new file mode 100644
index 0000000..ea52a38
--- /dev/null
+++ b/phoneClients/javaMe/nbproject/project.xml
@@ -0,0 +1,10 @@
+
+
+ org.netbeans.modules.kjava.j2meproject
+
+
+ GpsTracker
+ 1.6
+
+
+
diff --git a/phoneClients/javaMe/src/com/websmithing/gpstracker/GpsHelper.java b/phoneClients/javaMe/src/com/websmithing/gpstracker/GpsHelper.java
new file mode 100644
index 0000000..2b1fc68
--- /dev/null
+++ b/phoneClients/javaMe/src/com/websmithing/gpstracker/GpsHelper.java
@@ -0,0 +1,164 @@
+//
+// GpsHelper.java
+// GpsTracker
+//
+// Created by Nick Fox on 12/1/13.
+// Copyright (c) 2013 Nick Fox. All rights reserved.
+//
+
+package com.websmithing.gpstracker;
+
+
+import javax.microedition.location.*;
+import java.util.Calendar;
+import java.util.Date;
+
+public class GpsHelper implements LocationListener {
+
+ private LocationProvider locationProvider = null;
+ private Coordinates oldCoordinates = null, currentCoordinates = null;
+ private float distance = 0;
+ private int azimuth = 0;
+ private String uploadWebsite;
+ private String queryString;
+ private GpsTracker midlet;
+ private int interval;
+ protected Calendar currentTime;
+ protected long sessionID;
+
+
+ public GpsHelper(GpsTracker Midlet, int Interval, String UploadWebsite){
+ currentTime = Calendar.getInstance();
+ sessionID = System.currentTimeMillis();
+ this.midlet = Midlet;
+ this.interval = Interval;
+ this.uploadWebsite = UploadWebsite;
+ }
+
+ // getting the gps location is based on an interval in seconds. for instance,
+ // the location is gotten once a minute, sent to the website to be stored in
+ // the DB (and then viewed on Google map) and used to retrieve a map tile (image)
+ // to be diplayed on the phone
+
+ public void startGPS() {
+ if (locationProvider == null) {
+ createLocationProvider();
+
+ Thread locationThread = new Thread() {
+ public void run(){
+ createLocationListener();
+ }
+ };
+ locationThread.start();
+ }
+ }
+
+ // this allows us to change how often the gps location is gotten
+ public void changeInterval(int Interval) {
+ if (locationProvider != null) {
+ locationProvider.setLocationListener(this, Interval, -1, -1);
+ }
+ }
+
+ private void createLocationProvider() {
+ Criteria cr = new Criteria();
+
+ try {
+ locationProvider = LocationProvider.getInstance(cr);
+ } catch (Exception e) {
+ midlet.log("GPS.createLocationProvider: " + e);
+ }
+ }
+
+ private void createLocationListener(){
+ // 2cd value is interval in seconds
+ try {
+ locationProvider.setLocationListener(this, interval, -1, -1);
+ } catch (Exception e) {
+ midlet.log("GPS.createLocationListener: " + e);
+ }
+ }
+
+ public void locationUpdated(LocationProvider provider, final Location location) {
+ // get new location from locationProvider
+
+ try {
+ Thread getLocationThread = new Thread(){
+ public void run(){
+ getLocation(location);
+ }
+ };
+
+ getLocationThread.start();
+ } catch (Exception e) {
+ midlet.log("GPS.locationUpdated: " + e);
+ }
+ }
+
+ public void providerStateChanged(LocationProvider provider, int newState) {}
+
+ private void getLocation(Location location){
+ float speed = 0;
+
+ try {
+ QualifiedCoordinates qualifiedCoordinates = location.getQualifiedCoordinates();
+
+ qualifiedCoordinates.getLatitude();
+
+ if (oldCoordinates == null){
+ oldCoordinates = new Coordinates(qualifiedCoordinates.getLatitude(),
+ qualifiedCoordinates.getLongitude(),
+ qualifiedCoordinates.getAltitude());
+ } else {
+ if (!Float.isNaN( qualifiedCoordinates.distance(oldCoordinates))) {
+ distance += qualifiedCoordinates.distance(oldCoordinates);
+ }
+
+ currentCoordinates = new Coordinates(qualifiedCoordinates.getLatitude(),
+ qualifiedCoordinates.getLongitude(),
+ qualifiedCoordinates.getAltitude());
+ azimuth = (int)oldCoordinates.azimuthTo(currentCoordinates);
+ oldCoordinates.setAltitude(qualifiedCoordinates.getAltitude());
+ oldCoordinates.setLatitude(qualifiedCoordinates.getLatitude());
+ oldCoordinates.setLongitude(qualifiedCoordinates.getLongitude());
+
+ }
+
+ if (qualifiedCoordinates != null){
+ Date d = new Date();
+
+ if (!Float.isNaN(location.getSpeed())) {
+ speed = location.getSpeed();
+ }
+
+ queryString = "?lat=" + String.valueOf(qualifiedCoordinates.getLatitude())
+ + "&lng=" + String.valueOf(qualifiedCoordinates.getLongitude())
+ + "&mph=" + String.valueOf((int)(speed/1609*3600))
+ + "&dir=" + String.valueOf(azimuth)
+ + "&dis=" + String.valueOf((int)(distance/1609))
+ + "&dt=" + d.toString()
+ + "&lm=" + location.getLocationMethod()
+ + "&pn=" + midlet.phoneNumber
+ + "&sid=" + String.valueOf(sessionID)
+ + "&acc=" + String.valueOf((int)(qualifiedCoordinates.getHorizontalAccuracy()*3.28))
+ + "&iv=" + String.valueOf(location.isValid())
+ + "&info=" + location.getExtraInfo("text/plain")
+ + "&zm=" + midlet.zoomLevel
+ + "&h=" + midlet.height
+ + "&w=" + midlet.width;
+
+ // with our query string built, we create a networker object to send the
+ // query to our website and get the map image and update the DB
+ NetWorker worker = new NetWorker(midlet, uploadWebsite);
+ worker.getUrl(queryString);
+
+ }
+
+ } catch (Exception e) {
+ midlet.log("GPS.getLocation: " + e);
+ }
+ }
+}
+
+
+
diff --git a/phoneClients/javaMe/src/com/websmithing/gpstracker/GpsTracker.java b/phoneClients/javaMe/src/com/websmithing/gpstracker/GpsTracker.java
new file mode 100644
index 0000000..f30f850
--- /dev/null
+++ b/phoneClients/javaMe/src/com/websmithing/gpstracker/GpsTracker.java
@@ -0,0 +1,285 @@
+//
+// GpsTracker.java
+// GpsTracker
+//
+// Created by Nick Fox on 12/1/13.
+// Copyright (c) 2013 Nick Fox. All rights reserved.
+//
+
+package com.websmithing.gpstracker;
+
+import javax.microedition.midlet.*;
+import javax.microedition.lcdui.*;
+import java.util.Calendar;
+
+public class GpsTracker extends MIDlet implements CommandListener, ItemStateListener {
+ private Display display;
+ private Form form;
+ private Form zoomScreen;
+ private Form settingsScreen;
+ private Command exitCmd;
+ private Command saveCmd;
+ private Command zoomCmd;
+ private Command settingsCmd;
+ private Command backCmd;
+ private TextField phoneNumberTextField;
+ private TextField uploadWebsiteTextField;
+ private Gauge zoomGauge;
+ private StringItem zoomStringItem;
+ private ChoiceGroup updateIntervalCG;
+ private String updateInterval;
+ private int[] iTimes = {60, 300, 900};
+
+ private RmsHelper rms;
+ private GpsHelper gps;
+
+ private String uploadWebsite;
+ private String defaultUploadWebsite = "http://www.websmithing.com/gpstracker/GetGoogleMap2.php";
+
+ protected String phoneNumber;
+ protected String zoomLevel;
+ protected int height, width;
+ protected Calendar currentTime;
+ protected long sessionID;
+ protected Image im = null;
+
+ public GpsTracker(){
+ form = new Form("GpsTracker");
+ display = Display.getDisplay(this);
+ exitCmd = new Command("Exit", Command.EXIT, 1);
+ zoomCmd = new Command("Zoom", Command.SCREEN, 2);
+ settingsCmd = new Command("Settings", Command.SCREEN, 3);
+
+ form.addCommand(exitCmd);
+ form.addCommand(zoomCmd);
+ form.addCommand(settingsCmd);
+ form.setCommandListener(this);
+
+ display.setCurrent(form);
+ currentTime = Calendar.getInstance();
+ sessionID = System.currentTimeMillis();
+ height = form.getHeight();
+ width = form.getWidth();
+
+ // RMS is the phone's built in storage, kind of like a database, but
+ // it only stores name-value pairs (like an associative array or hashtable).
+ // eveything is stored as a string.
+ getSettingsFromRMS();
+
+ // the phone number field is the only empty field when the application is
+ // first loaded. it does not have to be a phone number, it can be any string,
+ // but for uniqueness, it's best to use a phone number. this only has to be
+ // done once.
+ if (hasPhoneNumber()) {
+ startGPS();
+ displayInterval();
+ }
+ }
+
+ public void startApp() {
+ if ( form != null ) {
+ display.setCurrent(form);
+ }
+ }
+
+ // let the user know how often map will be updated
+ private void displayInterval() {
+ int tempTime = iTimes[Integer.parseInt(updateInterval)]/60;
+
+ display.setCurrent(form);
+ form.deleteAll();
+
+ if (tempTime == 1) {
+ log("Getting map once a minute...");
+ }
+ else {
+ log("Getting map every " + String.valueOf(tempTime) + " minutes...");
+ }
+ }
+
+ private void loadZoomScreen() {
+ zoomScreen = new Form("Zoom");
+ zoomGauge = new Gauge("Google Map Zoom", true, 17, Integer.parseInt(zoomLevel));
+ zoomStringItem = new StringItem(null, "");
+ zoomStringItem.setText("Zoom level: " + zoomGauge.getValue());
+ backCmd = new Command("Back", Command.SCREEN, 1);
+
+ zoomScreen.append(zoomGauge);
+ zoomScreen.append(zoomStringItem);
+ zoomScreen.addCommand(backCmd);
+ zoomScreen.setItemStateListener(this);
+ zoomScreen.setCommandListener(this);
+
+ display.setCurrent(zoomScreen);
+ }
+
+ // this method is called every time the zoom guage changes value. the zoom level is
+ // reset and saved
+ public void itemStateChanged(Item item) {
+ if (item == zoomGauge) {
+ zoomStringItem.setText("Zoom level: " + zoomGauge.getValue());
+ zoomLevel = String.valueOf(zoomGauge.getValue());
+
+ try {
+ rms.put("zoomLevel", zoomLevel);
+ rms.save();
+ }
+ catch (Exception e) {
+ log("GPSTracker.itemStateChanged: " + e);
+ }
+ }
+ }
+
+ private void loadSettingsScreen() {
+ settingsScreen = new Form("Settings");
+
+ phoneNumberTextField = new TextField("Phone number or user name", phoneNumber, 20, TextField.ANY);
+ uploadWebsiteTextField = new TextField("Upload website", uploadWebsite, 100, TextField.ANY);
+ settingsScreen.append(phoneNumberTextField);
+ settingsScreen.append(uploadWebsiteTextField);
+
+ String[] times = { "1 minute", "5 minutes", "15 minutes"};
+ updateIntervalCG = new ChoiceGroup("Update map how often?", ChoiceGroup.EXCLUSIVE, times, null);
+ updateIntervalCG.setSelectedIndex(Integer.parseInt(updateInterval), true);
+ settingsScreen.append(updateIntervalCG);
+
+ saveCmd = new Command("Save", Command.SCREEN, 1);
+ settingsScreen.addCommand(saveCmd);
+
+ settingsScreen.setCommandListener(this);
+ display.setCurrent(settingsScreen);
+ }
+
+ // get the settings from the phone's storage and load 4 global variables
+ public void getSettingsFromRMS() {
+ try {
+ rms = new RmsHelper(this, "GPSTracker");
+
+ phoneNumber = rms.get("phoneNumber");
+ uploadWebsite = rms.get("uploadWebsite");
+ zoomLevel = rms.get("zoomLevel");
+ updateInterval = rms.get("updateInterval");
+ }
+ catch (Exception e) {
+ log("GPSTracker.getSettingsFromRMS: " + e);
+ }
+
+ if ((uploadWebsite == null) || (uploadWebsite.trim().length() == 0)) {
+ uploadWebsite = defaultUploadWebsite;
+ }
+
+ if ((zoomLevel == null) || (zoomLevel.trim().length() == 0)) {
+ zoomLevel = "12";
+ }
+ if ((updateInterval == null) || (updateInterval.trim().length() == 0)) {
+ updateInterval = "1";
+ }
+ }
+
+ private boolean hasPhoneNumber() {
+ if ((phoneNumber == null) || (phoneNumber.trim().length() == 0)) {
+ log("Phone number required. Please go to settings.");
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+
+ // gps is started with the update interval. the interval is the time in between
+ // map updates
+ private void startGPS() {
+ if (gps == null) {
+ gps = new GpsHelper(this, iTimes[Integer.parseInt(updateInterval)], uploadWebsite);
+ gps.startGPS();
+ }
+ }
+
+ // this is called when the user changes the interval in the settings screen
+ private void changeInterval() {
+ if (gps == null) {
+ startGPS();
+ }
+ else {
+ gps.changeInterval(iTimes[Integer.parseInt(updateInterval)]);
+ }
+ }
+
+ // save settings back to phone memory
+ private void saveSettingsToRMS() {
+ try {
+ phoneNumber = phoneNumberTextField.getString();
+ uploadWebsite = uploadWebsiteTextField.getString();
+ updateInterval = String.valueOf(updateIntervalCG.getSelectedIndex());
+
+ rms.put("phoneNumber", phoneNumber);
+ rms.put("uploadWebsite", uploadWebsite);
+ rms.put("updateInterval", updateInterval);
+
+ rms.save();
+ }
+ catch (Exception e) {
+ log("GPSTracker.saveSettings: " + e);
+ }
+ display.setCurrent(form);
+ }
+
+ // this method displays the map image, it is called from the networker object
+ public void showMap(boolean flag)
+ {
+ if (flag == false) {
+ log("Map could not be downloaded.");
+ }
+ else {
+ ImageItem imageitem = new ImageItem(null, im, ImageItem.LAYOUT_DEFAULT, null);
+
+ if(form.size()!= 0) {
+ form.set(0, imageitem);
+ }
+ else {
+ form.append(imageitem);
+ }
+ }
+ }
+
+ public void log(String text) {
+ StringItem si = new StringItem(null, text);
+ si.setLayout(Item.LAYOUT_NEWLINE_AFTER);
+ form.append(si);
+ }
+
+ public void commandAction(Command cmd, Displayable screen) {
+ if (cmd == exitCmd) {
+ shutDownApp();
+ }
+ else if (cmd == saveCmd) {
+ saveSettingsToRMS();
+
+ if (hasPhoneNumber()) {
+ changeInterval();
+ displayInterval();
+ }
+ }
+ else if (cmd == settingsCmd) {
+ loadSettingsScreen();
+ }
+ else if (cmd == zoomCmd) {
+ loadZoomScreen();
+ }
+ else if (cmd == backCmd) {
+ displayInterval();
+ }
+ }
+
+ public void pauseApp() {}
+
+ public void destroyApp(boolean unconditional) {}
+
+ protected void shutDownApp() {
+ destroyApp(true);
+ notifyDestroyed();
+ }
+}
+
+
+
diff --git a/phoneClients/javaMe/src/com/websmithing/gpstracker/NetWorker.java b/phoneClients/javaMe/src/com/websmithing/gpstracker/NetWorker.java
new file mode 100644
index 0000000..8fe5191
--- /dev/null
+++ b/phoneClients/javaMe/src/com/websmithing/gpstracker/NetWorker.java
@@ -0,0 +1,119 @@
+//
+// NetWorker.java
+// GpsTracker
+//
+// Created by Nick Fox on 12/1/13.
+// Copyright (c) 2013 Nick Fox. All rights reserved.
+//
+
+package com.websmithing.gpstracker;
+
+import javax.microedition.io.*;
+import java.io.*;
+import javax.microedition.lcdui.Image;
+
+public class NetWorker {
+ private GpsTracker midlet;
+ private String uploadWebsite;
+ int i = 1;
+
+ public NetWorker(GpsTracker lbsMidlet, String UploadWebsite){
+ this.midlet = lbsMidlet;
+ this.uploadWebsite = UploadWebsite;
+ }
+
+ public void getUrl(String queryString) {
+ queryString = URLencodeSpaces(queryString);
+ String url = uploadWebsite + queryString;
+ HttpConnection httpConn = null;
+ InputStream inputStream = null;
+ DataInputStream iStrm = null;
+ ByteArrayOutputStream bStrm = null;
+ Image im = null;
+
+ try{
+ httpConn = (HttpConnection)Connector.open(url);
+
+ if(httpConn.getResponseCode() == HttpConnection.HTTP_OK){
+ inputStream = httpConn.openInputStream();
+ iStrm = new DataInputStream(inputStream);
+
+ byte imageData[];
+ int length = (int)httpConn.getLength();
+
+ if(length != -1) {
+ imageData = new byte[length];
+ iStrm.readFully(imageData);
+ }
+ else { //Length not available
+ bStrm = new ByteArrayOutputStream();
+ int ch;
+
+ while((ch = iStrm.read())!= -1) {
+ bStrm.write(ch);
+ }
+ imageData = bStrm.toByteArray();
+
+ }
+ im = Image.createImage(imageData, 0, imageData.length);
+ }
+ else {
+ midlet.log("NetWorker.getUrl responseCode: " + httpConn.getResponseCode());
+ }
+
+ } catch (Exception e) {
+ midlet.log("NetWorker.getUrl: " + e);
+ }
+ finally{ // Clean up
+ try{
+ if(bStrm != null)
+ bStrm.close();
+ if(iStrm != null)
+ iStrm.close();
+ if(inputStream != null)
+ inputStream.close();
+ if(httpConn != null)
+ httpConn.close();
+ }
+ catch(Exception e){}
+ }
+
+ // if we have successfully gotten a map image, then we want to display it
+ if( im == null) {
+ midlet.showMap(false);
+ }
+ else {
+ midlet.im = im;
+ midlet.showMap(true);
+ }
+
+ }
+
+ // http://forum.java.sun.com/thread.jspa?threadID=341790&messageID=1408555
+ private String URLencodeSpaces(String s)
+ {
+ if (s != null) {
+ StringBuffer tmp = new StringBuffer();
+ int i = 0;
+ try {
+ while (true) {
+ int b = (int)s.charAt(i++);
+
+ if (b != 0x20) {
+ tmp.append((char)b);
+ }
+ else {
+ tmp.append("%");
+ if (b <= 0xf) {
+ tmp.append("0");
+ }
+ tmp.append(Integer.toHexString(b));
+ }
+ }
+ }
+ catch (Exception e) {}
+ return tmp.toString();
+ }
+ return null;
+ }
+}
diff --git a/phoneClients/javaMe/src/com/websmithing/gpstracker/RmsHelper.java b/phoneClients/javaMe/src/com/websmithing/gpstracker/RmsHelper.java
new file mode 100644
index 0000000..08e624a
--- /dev/null
+++ b/phoneClients/javaMe/src/com/websmithing/gpstracker/RmsHelper.java
@@ -0,0 +1,88 @@
+//
+// RmsHelper.java
+// GpsTracker
+//
+// Created by Nick Fox on 12/1/13.
+// Copyright (c) 2013 Nick Fox. All rights reserved.
+//
+
+package com.websmithing.gpstracker;
+
+import java.util.*;
+import javax.microedition.rms.*;
+
+public class RmsHelper {
+ private GpsTracker midlet;
+ private String mRecordStoreName;
+ private Hashtable mHashtable;
+
+ public RmsHelper(GpsTracker Midlet, String recordStoreName) throws RecordStoreException {
+ this.midlet = Midlet;
+ this.mRecordStoreName = recordStoreName;
+ this.mHashtable = new Hashtable();
+ load();
+ }
+
+ public String get(String key) {
+ return (String)mHashtable.get(key);
+ }
+
+ public void put(String key, String value) {
+ if (value == null) value = "";
+ mHashtable.put(key, value);
+ }
+
+ private void load() throws RecordStoreException {
+ RecordStore rs = null;
+ RecordEnumeration re = null;
+
+ try {
+ rs = RecordStore.openRecordStore(mRecordStoreName, true);
+ re = rs.enumerateRecords(null, null, false);
+ while (re.hasNextElement()) {
+ byte[] raw = re.nextRecord();
+ String pref = new String(raw);
+ // Parse out the name.
+ int index = pref.indexOf('|');
+ String name = pref.substring(0, index);
+ String value = pref.substring(index + 1);
+ put(name, value);
+ }
+ }
+ finally {
+ if (re != null) re.destroy();
+ if (rs != null) rs.closeRecordStore();
+ }
+ }
+
+ public void save() throws RecordStoreException {
+ RecordStore rs = null;
+ RecordEnumeration re = null;
+ try {
+ rs = RecordStore.openRecordStore(mRecordStoreName, true);
+ re = rs.enumerateRecords(null, null, false);
+
+ // First remove all records, a little clumsy.
+ while (re.hasNextElement()) {
+ int id = re.nextRecordId();
+ rs.deleteRecord(id);
+ }
+
+ // Now save the preferences records.
+ Enumeration keys = mHashtable.keys();
+ while (keys.hasMoreElements()) {
+ String key = (String)keys.nextElement();
+ String value = get(key);
+ String pref = key + "|" + value;
+ byte[] raw = pref.getBytes();
+ rs.addRecord(raw, 0, raw.length);
+ }
+ }
+ finally {
+ if (re != null) re.destroy();
+ if (rs != null) rs.closeRecordStore();
+ }
+ }
+
+}
+