diff --git a/framework/assets/js/geolocation.js b/framework/assets/js/geolocation.js old mode 100644 new mode 100755 index fec7b884c..40f06da4e --- a/framework/assets/js/geolocation.js +++ b/framework/assets/js/geolocation.js @@ -3,85 +3,152 @@ * @constructor */ function Geolocation() { - /** - * The last known GPS position. - */ + + // The last known GPS position. this.lastPosition = null; - this.lastError = null; - this.listeners = null; + + // Geolocation listeners + this.listeners = {}; }; -var geoListeners = []; - -Geolocation.prototype.getCurrentPosition = function(successCallback, errorCallback, options) -{ - var position = Geo.getCurrentLocation(); - this.global_success = successCallback; - this.fail = errorCallback; -} - -// Run the global callback -Geolocation.prototype.gotCurrentPosition = function(lat, lng, alt, altacc, head, vel, stamp) -{ - if (lat == "undefined" || lng == "undefined") - { - this.fail(); - } - else - { - coords = new Coordinates(lat, lng, alt, acc, head, vel); - loc = new Position(coords, stamp); - this.lastPosition = loc; - this.global_success(loc); - } -} - -/* -* This turns on the GeoLocator class, which has two listeners. -* The listeners have their own timeouts, and run independently of this process -* In this case, we return the key to the watch hash -*/ - -Geolocation.prototype.watchPosition = function(successCallback, errorCallback, options) -{ - var frequency = (options != undefined)? options.frequency : 10000; - - var key = geoListeners.push( {"success" : successCallback, "fail" : errorCallback }) - 1; - - // TO-DO: Get the names of the method and pass them as strings to the Java. - return Geo.start(frequency, key); -} - -/* - * Retrieve and stop this listener from listening to the GPS +/** + * Position error object * + * @param code + * @param message */ -Geolocation.prototype.success = function(key, lat, lng, alt, altacc, head, vel, stamp) -{ - var coords = new Coordinates(lat, lng, alt, acc, head, vel); - var loc = new Position(coords, stamp); - geoListeners[key].success(loc); +function PositionError(code, message) { + this.code = code; + this.message = message; +}; + +PositionError.PERMISSION_DENIED = 1; +PositionError.POSITION_UNAVAILABLE = 2; +PositionError.TIMEOUT = 3; + +/** + * Asynchronously aquires the current position. + * + * @param {Function} successCallback The function to call when the position data is available + * @param {Function} errorCallback The function to call when there is an error getting the heading position. (OPTIONAL) + * @param {PositionOptions} options The options for getting the position data. (OPTIONAL) + */ +Geolocation.prototype.getCurrentPosition = function(successCallback, errorCallback, options) { + if (navigator._geo.listeners["global"]) { + console.log("Geolocation Error: Still waiting for previous getCurrentPosition() request."); + try { + errorCallback(new PositionError(PositionError.TIMEOUT, "Geolocation Error: Still waiting for previous getCurrentPosition() request.")); + } catch (e) { + } + return; + } + navigator._geo.listeners["global"] = {"success" : successCallback, "fail" : errorCallback }; + PhoneGap.execAsync(null, null, "Geolocation", "getCurrentLocation", []); } -Geolocation.prototype.fail = function(key) -{ - geoListeners[key].fail(); -} - -Geolocation.prototype.clearWatch = function(watchId) -{ - Geo.stop(watchId); -} +/** + * Asynchronously watches the geolocation for changes to geolocation. When a change occurs, + * the successCallback is called with the new location. + * + * @param {Function} successCallback The function to call each time the location data is available + * @param {Function} errorCallback The function to call when there is an error getting the location data. (OPTIONAL) + * @param {PositionOptions} options The options for getting the location data such as frequency. (OPTIONAL) + * @return String The watch id that must be passed to #clearWatch to stop watching. + */ +Geolocation.prototype.watchPosition = function(successCallback, errorCallback, options) { + var frequency = (options != undefined)? options.frequency : 10000; + var id = PhoneGap.createUUID(); + navigator._geo.listeners[id] = {"success" : successCallback, "fail" : errorCallback }; + PhoneGap.execAsync(null, null, "Geolocation", "start", [frequency, id]); + return id; +}; + +/* + * Native callback when watch position has a new position. + * + * @param {String} id + * @param {Number} lat + * @param {Number} lng + * @param {Number} alt + * @param {Number} altacc + * @param {Number} head + * @param {Number} vel + * @param {Number} stamp + */ +Geolocation.prototype.success = function(id, lat, lng, alt, altacc, head, vel, stamp) { + var coords = new Coordinates(lat, lng, alt, altacc, head, vel); + var loc = new Position(coords, stamp); + try { + if (lat == "undefined" || lng == "undefined") { + navigator._geo.listeners[id].fail(new PositionError(PositionError.POSITION_UNAVAILABLE, "Lat/Lng are undefined.")); + } + else { + navigator._geo.lastPosition = loc; + navigator._geo.listeners[id].success(loc); + } + } + catch (e) { + console.log("Geolocation Error: Error calling success callback function."); + } + + if (id == "global") { + delete navigator._geo.listeners["global"]; + } +}; + +/** + * Native callback when watch position has an error. + * + * @param {String} id The ID of the watch + * @param {Number} code The error code + * @param {String} msg The error message + */ +Geolocation.prototype.fail = function(id, code, msg) { + try { + navigator._geo.listeners[id].fail(new PositionError(code, msg)); + } + catch (e) { + console.log("Geolocation Error: Error calling error callback function."); + } +}; + +/** + * Clears the specified heading watch. + * + * @param {String} id The ID of the watch returned from #watchPosition + */ +Geolocation.prototype.clearWatch = function(id) { + PhoneGap.execAsync(null, null, "Geolocation", "stop", [id]); + delete navigator._geo.listeners[id]; +}; + +/** + * Force the PhoneGap geolocation to be used instead of built-in. + */ +Geolocation.usingPhoneGap = false; +Geolocation.usePhoneGap = function() { + if (Geolocation.usingPhoneGap) { + return; + } + Geolocation.usingPhoneGap = true; + + // Set built-in geolocation methods to our own implementations + // (Cannot replace entire geolocation, but can replace individual methods) + navigator.geolocation.setLocation = navigator._geo.setLocation; + navigator.geolocation.getCurrentPosition = navigator._geo.getCurrentPosition; + navigator.geolocation.watchPosition = navigator._geo.watchPosition; + navigator.geolocation.clearWatch = navigator._geo.clearWatch; + navigator.geolocation.start = navigator._geo.start; + navigator.geolocation.stop = navigator._geo.stop; +}; PhoneGap.addConstructor(function() { - // Taken from Jesse's geo fix (similar problem) in PhoneGap iPhone. Go figure, same browser! - function __proxyObj(origObj, proxyObj, funkList) { - for (var v in funkList) { - origObj[funkList[v]] = proxyObj[funkList[v]]; - } - } - // In the case of Android, we can use the Native Geolocation Object if it exists, so only load this on 1.x devices - if (typeof navigator.geolocation == 'undefined') { - navigator.geolocation = new Geolocation(); - } + navigator._geo = new Geolocation(); + + // No native geolocation object for Android 1.x, so use PhoneGap geolocation + if (typeof navigator.geolocation == 'undefined') { + navigator.geolocation = navigator._geo; + Geolocation.usingPhoneGap = true; + } }); + diff --git a/framework/src/com/phonegap/DroidGap.java b/framework/src/com/phonegap/DroidGap.java index 56eeb0e78..70d153283 100755 --- a/framework/src/com/phonegap/DroidGap.java +++ b/framework/src/com/phonegap/DroidGap.java @@ -282,10 +282,10 @@ public class DroidGap extends Activity { Storage cupcakeStorage = (Storage)this.pluginManager.addPlugin("com.phonegap.Storage"); cupcakeStorage.setStorage(appPackage); - this.pluginManager.addPlugin("com.phonegap.GeoBroker"); } + this.addService("Geolocation", "com.phonegap.GeoBroker"); this.addService("Device", "com.phonegap.Device"); this.addService("Accelerometer", "com.phonegap.AccelListener"); this.addService("Compass", "com.phonegap.CompassListener"); diff --git a/framework/src/com/phonegap/GeoBroker.java b/framework/src/com/phonegap/GeoBroker.java old mode 100644 new mode 100755 index 0ea4645af..e799f50c3 --- a/framework/src/com/phonegap/GeoBroker.java +++ b/framework/src/com/phonegap/GeoBroker.java @@ -1,6 +1,7 @@ package com.phonegap; import java.util.HashMap; +import java.util.Map.Entry; import org.json.JSONArray; import org.json.JSONException; @@ -22,6 +23,7 @@ public class GeoBroker implements Plugin { WebView webView; // WebView object DroidGap ctx; // DroidGap object + // List of gGeolocation listeners private HashMap geoListeners; private GeoListener global; @@ -87,7 +89,8 @@ public class GeoBroker implements Plugin { * @return T=returns value */ public boolean isSynch(String action) { - return false; + // Starting listeners is easier to run on main thread, so don't run async. + return true; } /** @@ -103,10 +106,22 @@ public class GeoBroker implements Plugin { } /** - * Called by AccelBroker when listener is to be shut down. + * Called when the activity is to be shut down. * Stop listener. */ - public void onDestroy() { + public void onDestroy() { + java.util.Set> s = this.geoListeners.entrySet(); + java.util.Iterator> it = s.iterator(); + while (it.hasNext()) { + Entry entry = it.next(); + GeoListener listener = entry.getValue(); + listener.destroy(); + } + this.geoListeners.clear(); + if (this.global != null) { + this.global.destroy(); + } + this.global = null; } /** @@ -125,23 +140,51 @@ public class GeoBroker implements Plugin { // LOCAL METHODS //-------------------------------------------------------------------------- - public void getCurrentLocation() { - //It's supposed to run async! - if (global == null) { - global = new GeoListener("global", this.ctx, 10000, this.webView); + /** + * Get current location. + * The result is returned to JavaScript via a callback. + */ + public void getCurrentLocation() { + + // Create a geolocation listener just for getCurrentLocation and call it "global" + if (this.global == null) { + this.global = new GeoListener("global", this.ctx, 10000, this.webView); } else { - global.start(10000); + this.global.start(10000); } } + /** + * Start geolocation listener and add to listener list. + * + * @param freq Period to retrieve geolocation + * @param key The listener id + * @return + */ public String start(int freq, String key) { - GeoListener listener = new GeoListener(key, this.ctx, freq, this.webView); - geoListeners.put(key, listener); + + // Make sure this listener doesn't already exist + GeoListener listener = geoListeners.get(key); + if (listener == null) { + listener = new GeoListener(key, this.ctx, freq, this.webView); + geoListeners.put(key, listener); + } + + // Start it + listener.start(freq); return key; } + /** + * Stop geolocation listener and remove from listener list. + * + * @param key The listener id + */ public void stop(String key) { - GeoListener geo = geoListeners.get(key); + GeoListener listener = geoListeners.remove(key); + if (listener != null) { + listener.stop(); + } } } diff --git a/framework/src/com/phonegap/GeoListener.java b/framework/src/com/phonegap/GeoListener.java old mode 100644 new mode 100755 index 86d79c8f4..b78f6fb13 --- a/framework/src/com/phonegap/GeoListener.java +++ b/framework/src/com/phonegap/GeoListener.java @@ -6,83 +6,112 @@ import android.location.LocationManager; import android.webkit.WebView; public class GeoListener { - String id; - String successCallback; + public static int PERMISSION_DENIED = 1; + public static int POSITION_UNAVAILABLE = 2; + public static int TIMEOUT = 3; + + String id; // Listener ID + String successCallback; // String failCallback; - GpsListener mGps; - NetworkListener mNetwork; - LocationManager mLocMan; - private DroidGap mCtx; - private WebView mAppView; + GpsListener mGps; // GPS listener + NetworkListener mNetwork; // Network listener + LocationManager mLocMan; // Location manager + + private DroidGap ctx; // DroidGap object + @SuppressWarnings("unused") + private WebView mAppView; // Webview object int interval; - GeoListener(String i, DroidGap ctx, int time, WebView appView) { - id = i; - interval = time; - mCtx = ctx; - mGps = null; - mNetwork = null; - mLocMan = (LocationManager) mCtx.getSystemService(Context.LOCATION_SERVICE); + /** + * Constructor. + * + * @param id Listener id + * @param ctx + * @param time Sampling period in msec + * @param appView + */ + GeoListener(String id, DroidGap ctx, int time, WebView appView) { + this.id = id; + this.interval = time; + this.ctx = ctx; + this.mGps = null; + this.mNetwork = null; + this.mLocMan = (LocationManager) ctx.getSystemService(Context.LOCATION_SERVICE); - if (mLocMan.getProvider(LocationManager.GPS_PROVIDER) != null) { - mGps = new GpsListener(mCtx, interval, this); + // If GPS provider, then create and start GPS listener + if (this.mLocMan.getProvider(LocationManager.GPS_PROVIDER) != null) { + this.mGps = new GpsListener(ctx, time, this); } - if (mLocMan.getProvider(LocationManager.NETWORK_PROVIDER) != null) { - mNetwork = new NetworkListener(mCtx, interval, this); + + // If network provider, then create and start network listener + if (this.mLocMan.getProvider(LocationManager.NETWORK_PROVIDER) != null) { + this.mNetwork = new NetworkListener(ctx, time, this); } - mAppView = appView; + this.mAppView = appView; } + /** + * Destroy listener. + */ + public void destroy() { + this.stop(); + } + + /** + * Location found. Send location back to JavaScript. + * + * @param loc + */ void success(Location loc) { - /* - * We only need to figure out what we do when we succeed! - */ - String params; - /* - * Build the giant string to send back to Javascript! - */ - params = loc.getLatitude() + "," + loc.getLongitude() + ", " + loc.getAltitude() + "," + loc.getAccuracy() + "," + loc.getBearing(); - params += "," + loc.getSpeed() + "," + loc.getTime(); - if (id != "global") { - mCtx.sendJavascript("navigator._geo.success(" + id + "," + params + ");"); - } - else { - mCtx.sendJavascript("navigator.geolocation.gotCurrentPosition(" + params + ");"); + String params = loc.getLatitude() + "," + loc.getLongitude() + ", " + loc.getAltitude() + + "," + loc.getAccuracy() + "," + loc.getBearing() + + "," + loc.getSpeed() + "," + loc.getTime(); + + if (id == "global") { this.stop(); } + this.ctx.sendJavascript("navigator._geo.success('" + id + "'," + params + ");"); } - void fail() { - // Do we need to know why? How would we handle this? - if (id != "global") { - mCtx.sendJavascript("navigator._geo.fail(" + id + ");"); - } else { - mCtx.sendJavascript("navigator._geo.fail();"); - } + /** + * Location failed. Send error back to JavaScript. + * + * @param code The error code + * @param msg The error message + */ + void fail(int code, String msg) { + this.ctx.sendJavascript("navigator._geo.fail('" + this.id + "', " + ", " + code + ", '" + msg + "');"); + this.stop(); } + /** + * Start retrieving location. + * + * @param interval + */ void start(int interval) { - if (mGps != null) { - mGps.start(interval); + if (this.mGps != null) { + this.mGps.start(interval); } - if (mNetwork != null) { - mNetwork.start(interval); + if (this.mNetwork != null) { + this.mNetwork.start(interval); } - if (mNetwork == null && mGps == null) { - // Really, how were you going to get the location??? - mCtx.sendJavascript("navigator._geo.fail();"); + if (this.mNetwork == null && this.mGps == null) { + this.fail(POSITION_UNAVAILABLE, "No location providers available."); } } - // This stops the listener + /** + * Stop listening for location. + */ void stop() { - if (mGps != null) { - mGps.stop(); + if (this.mGps != null) { + this.mGps.stop(); } - if (mNetwork != null) { - mNetwork.stop(); + if (this.mNetwork != null) { + this.mNetwork.stop(); } } diff --git a/framework/src/com/phonegap/GpsListener.java b/framework/src/com/phonegap/GpsListener.java old mode 100644 new mode 100755 index a236f5637..96326f4e1 --- a/framework/src/com/phonegap/GpsListener.java +++ b/framework/src/com/phonegap/GpsListener.java @@ -26,81 +26,138 @@ import android.location.Location; import android.location.LocationManager; import android.location.LocationListener; import android.os.Bundle; -import android.util.Log; +/** + * This class handles requests for GPS location services. + * + */ public class GpsListener implements LocationListener { - private Context mCtx; - private Location cLoc; - private LocationManager mLocMan; - private static final String LOG_TAG = "PhoneGap"; - private GeoListener owner; - private boolean hasData = false; + private DroidGap mCtx; // DroidGap object - public GpsListener(Context ctx, int interval, GeoListener m) - { - owner = m; - mCtx = ctx; + private LocationManager mLocMan; // Location manager object + private GeoListener owner; // Geolistener object (parent) + private boolean hasData = false; // Flag indicates if location data is available in cLoc + private Location cLoc; // Last recieved location + private boolean running = false; // Flag indicates if listener is running + + /** + * Constructor. + * Automatically starts listening. + * + * @param ctx + * @param interval + * @param m + */ + public GpsListener(DroidGap ctx, int interval, GeoListener m) { + this.owner = m; + this.mCtx = ctx; + this.mLocMan = (LocationManager) this.mCtx.getSystemService(Context.LOCATION_SERVICE); + this.running = false; this.start(interval); } - public Location getLocation() - { - cLoc = mLocMan.getLastKnownLocation(LocationManager.GPS_PROVIDER); - hasData = true; - return cLoc; + /** + * Get last location. + * + * @return Location object + */ + public Location getLocation() { + this.cLoc = this.mLocMan.getLastKnownLocation(LocationManager.GPS_PROVIDER); + if (this.cLoc != null) { + this.hasData = true; + } + return this.cLoc; } + /** + * Called when the provider is disabled by the user. + * + * @param provider + */ public void onProviderDisabled(String provider) { - // TODO Auto-generated method stub - Log.d(LOG_TAG, "The provider " + provider + " is disabled"); - owner.fail(); + this.owner.fail(GeoListener.POSITION_UNAVAILABLE, "GPS provider disabled."); } + /** + * Called when the provider is enabled by the user. + * + * @param provider + */ public void onProviderEnabled(String provider) { - // TODO Auto-generated method stub - Log.d(LOG_TAG, "The provider "+ provider + " is enabled"); + System.out.println("GpsListener: The provider "+ provider + " is enabled"); } - + /** + * Called when the provider status changes. This method is called when a + * provider is unable to fetch a location or if the provider has recently + * become available after a period of unavailability. + * + * @param provider + * @param status + * @param extras + */ public void onStatusChanged(String provider, int status, Bundle extras) { - // TODO Auto-generated method stub - Log.d(LOG_TAG, "The status of the provider " + provider + " has changed"); - if(status == 0) - { - Log.d(LOG_TAG, provider + " is OUT OF SERVICE"); - owner.fail(); + System.out.println("GpsListener: The status of the provider " + provider + " has changed"); + if (status == 0) { + System.out.println("GpsListener: " + provider + " is OUT OF SERVICE"); + this.owner.fail(GeoListener.POSITION_UNAVAILABLE, "GPS out of service."); } - else if(status == 1) - { - Log.d(LOG_TAG, provider + " is TEMPORARILY_UNAVAILABLE"); + else if (status == 1) { + System.out.println("GpsListener: " + provider + " is TEMPORARILY_UNAVAILABLE"); } - else - { - Log.d(LOG_TAG, provider + " is Available"); + else { + System.out.println("GpsListener: " + provider + " is Available"); } } - + /** + * Called when the location has changed. + * + * @param location + */ public void onLocationChanged(Location location) { - Log.d(LOG_TAG, "The location has been updated!"); - owner.success(location); + System.out.println("GpsListener: The location has been updated!"); + this.hasData = true; + this.cLoc = location; + this.owner.success(location); } + /** + * Determine if location data is available. + * + * @return + */ public boolean hasLocation() { - return hasData; + return this.hasData; } - public void start(int interval) - { - mLocMan = (LocationManager) mCtx.getSystemService(Context.LOCATION_SERVICE); - mLocMan.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval, 0, this); - cLoc = mLocMan.getLastKnownLocation(LocationManager.GPS_PROVIDER); + /** + * Start requesting location updates. + * + * @param interval + */ + public void start(int interval) { + if (!this.running) { + this.running = true; + this.mLocMan.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval, 0, this); + this.getLocation(); + + // If GPS provider has data, then send now + if (this.hasData) { + this.owner.success(this.cLoc); + } + } } - public void stop() - { - mLocMan.removeUpdates(this); + /** + * Stop receiving location updates. + */ + public void stop() { + if (this.running) { + this.mLocMan.removeUpdates(this); + } + this.running = false; } } diff --git a/framework/src/com/phonegap/NetworkListener.java b/framework/src/com/phonegap/NetworkListener.java old mode 100644 new mode 100755 index 4b0ecda4d..0941f08b2 --- a/framework/src/com/phonegap/NetworkListener.java +++ b/framework/src/com/phonegap/NetworkListener.java @@ -26,82 +26,129 @@ import android.location.Location; import android.location.LocationManager; import android.location.LocationListener; import android.os.Bundle; -import android.util.Log; public class NetworkListener implements LocationListener { - - private Context mCtx; - private Location cLoc; - private LocationManager mLocMan; - private static final String LOG_TAG = "PhoneGap"; - GeoListener owner; - public NetworkListener(Context ctx, int interval, GeoListener m) - { - owner = m; - mCtx = ctx; + private DroidGap mCtx; // DroidGap object + + private LocationManager mLocMan; // Location manager object + private GeoListener owner; // Geolistener object (parent) + private boolean hasData = false; // Flag indicates if location data is available in cLoc + private Location cLoc; // Last recieved location + private boolean running = false; // Flag indicates if listener is running + + /** + * Constructor. + * Automatically starts listening. + * + * @param ctx + * @param interval + * @param m + */ + public NetworkListener(DroidGap ctx, int interval, GeoListener m) { + this.owner = m; + this.mCtx = ctx; + this.mLocMan = (LocationManager) this.mCtx.getSystemService(Context.LOCATION_SERVICE); + this.running = false; this.start(interval); } - public Location getLocation() - { - cLoc = mLocMan.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); - return cLoc; + /** + * Get last location. + * + * @return Location object + */ + public Location getLocation() { + this.cLoc = this.mLocMan.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); + if (this.cLoc != null) { + this.hasData = true; + } + return this.cLoc; } + /** + * Called when the provider is disabled by the user. + * + * @param provider + */ public void onProviderDisabled(String provider) { - // TODO Auto-generated method stub - Log.d(LOG_TAG, "The provider " + provider + " is disabled"); + System.out.println("NetworkListener: The provider " + provider + " is disabled"); } - + /** + * Called when the provider is enabled by the user. + * + * @param provider + */ public void onProviderEnabled(String provider) { - // TODO Auto-generated method stub - Log.d(LOG_TAG, "The provider "+ provider + " is enabled"); + System.out.println("NetworkListener: The provider "+ provider + " is enabled"); } - + /** + * Called when the provider status changes. This method is called when a + * provider is unable to fetch a location or if the provider has recently + * become available after a period of unavailability. + * + * @param provider + * @param status + * @param extras + */ public void onStatusChanged(String provider, int status, Bundle extras) { - // TODO Auto-generated method stub - Log.d(LOG_TAG, "The status of the provider " + provider + " has changed"); - if(status == 0) - { - Log.d(LOG_TAG, provider + " is OUT OF SERVICE"); + System.out.println("NetworkListener: The status of the provider " + provider + " has changed"); + if (status == 0) { + System.out.println("NetworkListener: " + provider + " is OUT OF SERVICE"); } - else if(status == 1) - { - Log.d(LOG_TAG, provider + " is TEMPORARILY_UNAVAILABLE"); + else if (status == 1) { + System.out.println("NetworkListener: " + provider + " is TEMPORARILY_UNAVAILABLE"); } - else - { - Log.d(LOG_TAG, provider + " is Available"); + else { + System.out.println("NetworkListener: " + provider + " is Available"); } } - - /* - * The GPS is the primary form of Geolocation in PhoneGap. Only fire the success variables if the GPS is down - * for some reason + /** + * Called when the location has changed. + * + * @param location */ public void onLocationChanged(Location location) { - Log.d(LOG_TAG, "The location has been updated!"); - if (!owner.mGps.hasLocation()) - { - owner.success(location); + System.out.println("NetworkListener: The location has been updated!"); + this.hasData = true; + this.cLoc = location; + + // The GPS is the primary form of Geolocation in PhoneGap. + // Only fire the success variables if the GPS is down for some reason. + if (!this.owner.mGps.hasLocation()) { + this.owner.success(location); } - cLoc = location; } - public void start(int interval) - { - mLocMan = (LocationManager) mCtx.getSystemService(Context.LOCATION_SERVICE); - mLocMan.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, interval, 0, this); - cLoc = mLocMan.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); + /** + * Start requesting location updates. + * + * @param interval + */ + public void start(int interval) { + if (!this.running) { + this.running = true; + this.mLocMan.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, interval, 0, this); + this.getLocation(); + + // If Network provider has data but GPS provider doesn't, then send ours + if (this.hasData && !this.owner.mGps.hasLocation()) { + this.owner.success(this.cLoc); + } + } } - public void stop() - { - mLocMan.removeUpdates(this); + /** + * Stop receiving location updates. + */ + public void stop() { + if (this.running) { + this.mLocMan.removeUpdates(this); + } + this.running = false; } }