From b84d64912b9641512f1b34f2b57f81c1927e14f2 Mon Sep 17 00:00:00 2001 From: Fil Maj Date: Mon, 7 May 2012 16:08:28 -0700 Subject: [PATCH 01/14] comeat me lawyers --- bin/package.json | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/bin/package.json b/bin/package.json index b4231140..81d3900e 100644 --- a/bin/package.json +++ b/bin/package.json @@ -1,21 +1,3 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ { "name": "cordova-android-cli", "description": "CLI tooling for the cordova-android project", @@ -42,4 +24,3 @@ "nodeunit":"0.5.3" } } - From 6fc2a3b84e7151a7062753af16e9a27bd8a659a9 Mon Sep 17 00:00:00 2001 From: Fil Maj Date: Mon, 7 May 2012 16:09:14 -0700 Subject: [PATCH 02/14] adding node_modules to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 7bd73298..85278e2a 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ example tmp *.tmp test/libs/*.jar +bin/node_modules From 724ea49f0b4e26286fda38b380f3f5d128ad5d15 Mon Sep 17 00:00:00 2001 From: Fil Maj Date: Fri, 30 Mar 2012 01:48:12 -0700 Subject: [PATCH 03/14] restructured geolocation plugin --- .../cordova/CordovaLocationListener.java | 198 ++++++++++++++ .../src/org/apache/cordova/GeoBroker.java | 243 +++++++++--------- .../src/org/apache/cordova/GeoListener.java | 133 ---------- .../src/org/apache/cordova/GpsListener.java | 138 ++-------- .../org/apache/cordova/NetworkListener.java | 143 +---------- 5 files changed, 354 insertions(+), 501 deletions(-) create mode 100755 framework/src/org/apache/cordova/CordovaLocationListener.java delete mode 100755 framework/src/org/apache/cordova/GeoListener.java diff --git a/framework/src/org/apache/cordova/CordovaLocationListener.java b/framework/src/org/apache/cordova/CordovaLocationListener.java new file mode 100755 index 00000000..6eccfb44 --- /dev/null +++ b/framework/src/org/apache/cordova/CordovaLocationListener.java @@ -0,0 +1,198 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ +package org.apache.cordova; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.os.Bundle; +import android.util.Log; + +public class CordovaLocationListener implements LocationListener { + public static int PERMISSION_DENIED = 1; + public static int POSITION_UNAVAILABLE = 2; + public static int TIMEOUT = 3; + + protected LocationManager locationManager; + private GeoBroker owner; + protected boolean running = false; + + public HashMap watches = new HashMap(); + private List callbacks = new ArrayList(); + + private String TAG = "[Cordova Location Listener]"; + + public CordovaLocationListener(LocationManager manager, GeoBroker broker, String tag) { + this.locationManager = manager; + this.owner = broker; + this.TAG = tag; + } + + protected void fail(int code, String message) { + for (String callbackId: this.callbacks) + { + this.owner.fail(code, message, callbackId); + } + this.callbacks.clear(); + + Iterator it = this.watches.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pairs = (Map.Entry)it.next(); + this.owner.fail(code, message, (String)pairs.getValue()); + } + } + + private void win(Location loc) { + for (String callbackId: this.callbacks) + { + this.owner.win(loc, callbackId); + } + this.callbacks.clear(); + + Iterator it = this.watches.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pairs = (Map.Entry)it.next(); + this.owner.win(loc, (String)pairs.getValue()); + } + } + + /** + * Location Listener Methods + */ + + /** + * Called when the provider is disabled by the user. + * + * @param provider + */ + public void onProviderDisabled(String provider) { + Log.d(TAG, "Location provider '" + provider + "' disabled."); + this.fail(POSITION_UNAVAILABLE, "GPS provider disabled."); + } + + /** + * Called when the provider is enabled by the user. + * + * @param provider + */ + public void onProviderEnabled(String provider) { + Log.d(TAG, "Location provider "+ provider + " has been 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) { + Log.d(TAG, "The status of the provider " + provider + " has changed"); + if (status == 0) { + Log.d(TAG, provider + " is OUT OF SERVICE"); + this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "Provider " + provider + " is out of service."); + } + else if (status == 1) { + Log.d(TAG, provider + " is TEMPORARILY_UNAVAILABLE"); + } + else { + Log.d(TAG, provider + " is AVAILABLE"); + } + } + + /** + * Called when the location has changed. + * + * @param location + */ + public void onLocationChanged(Location location) { + Log.d(TAG, "The location has been updated!"); + this.win(location); + } + + // PUBLIC + + public int size() { + return this.watches.size() + this.callbacks.size(); + } + + public void addWatch(String timerId, String callbackId) { + this.watches.put(timerId, callbackId); + if (this.size() == 1) { + this.start(); + } + } + public void addCallback(String callbackId) { + this.callbacks.add(callbackId); + if (this.size() == 1) { + this.start(); + } + } + public void clearWatch(String timerId) { + if (this.watches.containsKey(timerId)) { + this.watches.remove(timerId); + } + if (this.size() == 0) { + this.stop(); + } + } + + /** + * Destroy listener. + */ + public void destroy() { + this.stop(); + } + + // LOCAL + + /** + * Start requesting location updates. + * + * @param interval + */ + private void start() { + if (!this.running) { + if (this.locationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) { + this.running = true; + this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 60000, 10, this); + } else { + this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "Network provider is not available."); + } + } + } + + /** + * Stop receiving location updates. + */ + private void stop() { + if (this.running) { + this.locationManager.removeUpdates(this); + this.running = false; + } + } +} diff --git a/framework/src/org/apache/cordova/GeoBroker.java b/framework/src/org/apache/cordova/GeoBroker.java index aa89d5a1..b8cfe4ec 100755 --- a/framework/src/org/apache/cordova/GeoBroker.java +++ b/framework/src/org/apache/cordova/GeoBroker.java @@ -18,14 +18,15 @@ */ package org.apache.cordova; -import java.util.HashMap; -import java.util.Map.Entry; - import org.apache.cordova.api.Plugin; import org.apache.cordova.api.PluginResult; import org.json.JSONArray; import org.json.JSONException; +import org.json.JSONObject; +import android.content.Context; +import android.location.Location; +import android.location.LocationManager; /* * This class is the interface to the Geolocation. It's bound to the geo object. @@ -34,132 +35,142 @@ import org.json.JSONException; */ public class GeoBroker extends Plugin { - - // List of gGeolocation listeners - private HashMap geoListeners; - private GeoListener global; + private GPSListener gpsListener; + private NetworkListener networkListener; + private LocationManager locationManager; - /** - * Constructor. - */ - public GeoBroker() { - this.geoListeners = new HashMap(); + /** + * Constructor. + */ + public GeoBroker() { + this.locationManager = (LocationManager) this.ctx.getSystemService(Context.LOCATION_SERVICE); + this.networkListener = new NetworkListener(this.locationManager, this); + this.gpsListener = new GPSListener(this.locationManager, this); + } + + /** + * Executes the request and returns PluginResult. + * + * @param action The action to execute. + * @param args JSONArry of arguments for the plugin. + * @param callbackId The callback id used when calling back into JavaScript. + * @return A PluginResult object with a status and message. + */ + public PluginResult execute(String action, JSONArray args, String callbackId) { + PluginResult.Status status = PluginResult.Status.NO_RESULT; + String message = ""; + PluginResult result = new PluginResult(status, message); + result.setKeepCallback(true); + + try { + if (action.equals("getLocation")) { + boolean enableHighAccuracy = args.getBoolean(0); + int maximumAge = args.getInt(1); + Location last = this.locationManager.getLastKnownLocation((enableHighAccuracy ? LocationManager.GPS_PROVIDER : LocationManager.NETWORK_PROVIDER)); + // Check if we can use lastKnownLocation to get a quick reading and use less battery + if ((System.currentTimeMillis() - last.getTime()) <= maximumAge) { + result = new PluginResult(PluginResult.Status.OK, GeoBroker.returnLocationJSON(last)); + } else { + this.getCurrentLocation(callbackId, enableHighAccuracy); + } + } + else if (action.equals("addWatch")) { + String id = args.getString(0); + boolean enableHighAccuracy = args.getBoolean(1); + this.addWatch(id, callbackId, enableHighAccuracy); + } + else if (action.equals("clearWatch")) { + String id = args.getString(0); + this.clearWatch(id); + } + } catch (JSONException e) { + result = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage()); + } + return result; + } + + private void clearWatch(String id) { + this.gpsListener.clearWatch(id); + this.networkListener.clearWatch(id); } - /** - * Executes the request and returns PluginResult. - * - * @param action The action to execute. - * @param args JSONArry of arguments for the plugin. - * @param callbackId The callback id used when calling back into JavaScript. - * @return A PluginResult object with a status and message. - */ - public PluginResult execute(String action, JSONArray args, String callbackId) { - PluginResult.Status status = PluginResult.Status.OK; - String result = ""; - - try { - if (action.equals("getCurrentLocation")) { - this.getCurrentLocation(args.getBoolean(0), args.getInt(1), args.getInt(2)); - } - else if (action.equals("start")) { - String s = this.start(args.getString(0), args.getBoolean(1), args.getInt(2), args.getInt(3)); - return new PluginResult(status, s); - } - else if (action.equals("stop")) { - this.stop(args.getString(0)); - } - return new PluginResult(status, result); - } catch (JSONException e) { - return new PluginResult(PluginResult.Status.JSON_EXCEPTION); + private void getCurrentLocation(String callbackId, boolean enableHighAccuracy) { + if (enableHighAccuracy) { + this.gpsListener.addCallback(callbackId); + } else { + this.networkListener.addCallback(callbackId); } } + + private void addWatch(String timerId, String callbackId, boolean enableHighAccuracy) { + if (enableHighAccuracy) { + this.gpsListener.addWatch(timerId, callbackId); + } else { + this.networkListener.addWatch(timerId, callbackId); + } + } /** - * Identifies if action to be executed returns a value and should be run synchronously. - * - * @param action The action to execute - * @return T=returns value - */ - public boolean isSynch(String action) { - // Starting listeners is easier to run on main thread, so don't run async. - return true; - } + * Identifies if action to be executed returns a value and should be run synchronously. + * + * @param action The action to execute + * @return T=returns value + */ + public boolean isSynch(String action) { + // Starting listeners is easier to run on main thread, so don't run async. + return true; + } /** * Called when the activity is to be shut down. * Stop listener. */ 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; + this.networkListener.destroy(); + this.gpsListener.destroy(); + this.networkListener = null; + this.gpsListener = null; } - //-------------------------------------------------------------------------- - // LOCAL METHODS - //-------------------------------------------------------------------------- - - /** - * Get current location. - * The result is returned to JavaScript via a callback. - * - * @param enableHighAccuracy - * @param timeout - * @param maximumAge - */ - public void getCurrentLocation(boolean enableHighAccuracy, int timeout, int maximumAge) { - - // Create a geolocation listener just for getCurrentLocation and call it "global" - if (this.global == null) { - this.global = new GeoListener(this, "global", maximumAge); - } - else { - this.global.start(maximumAge); - } - } - - /** - * Start geolocation listener and add to listener list. - * - * @param key The listener id - * @param enableHighAccuracy - * @param timeout - * @param maximumAge - * @return - */ - public String start(String key, boolean enableHighAccuracy, int timeout, int maximumAge) { - - // Make sure this listener doesn't already exist - GeoListener listener = geoListeners.get(key); - if (listener == null) { - listener = new GeoListener(this, key, maximumAge); - geoListeners.put(key, listener); - } - - // Start it - listener.start(maximumAge); - return key; - } - - /** - * Stop geolocation listener and remove from listener list. - * - * @param key The listener id - */ - public void stop(String key) { - GeoListener listener = geoListeners.remove(key); - if (listener != null) { - listener.stop(); - } - } + public static String returnLocationJSON(Location loc) { + return "{" + + "'latitude':" + loc.getLatitude() + "," + + "'longitude':" + loc.getLongitude() + "," + + "'altitude':" + (loc.hasAltitude() ? loc.getAltitude() : "null") + "," + + "'accuracy':" + loc.getAccuracy() + "," + + "'heading':" + (loc.hasBearing() ? (loc.hasSpeed() ? loc.getBearing() : "NaN") : "null") + "," + + "'speed':" + loc.getSpeed() + "," + + "'timestamp':" + loc.getTime() + + "}"; + } + public void win(Location loc, String callbackId) { + PluginResult result = new PluginResult(PluginResult.Status.OK, GeoBroker.returnLocationJSON(loc)); + this.success(result, callbackId); + } + /** + * Location failed. Send error back to JavaScript. + * + * @param code The error code + * @param msg The error message + * @throws JSONException + */ + public void fail(int code, String msg, String callbackId) { + JSONObject obj = new JSONObject(); + String backup = null; + try { + obj.put("code", code); + obj.put("message", msg); + } catch (JSONException e) { + obj = null; + backup = "{'code':" + code + ",'message':'" + msg.replaceAll("'", "\'") + "'}"; + } + PluginResult result; + if (obj != null) { + result = new PluginResult(PluginResult.Status.ERROR, obj); + } else { + result = new PluginResult(PluginResult.Status.ERROR, backup); + } + + this.error(result, callbackId); + } } diff --git a/framework/src/org/apache/cordova/GeoListener.java b/framework/src/org/apache/cordova/GeoListener.java deleted file mode 100755 index fdfcc429..00000000 --- a/framework/src/org/apache/cordova/GeoListener.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ -package org.apache.cordova; - -import android.content.Context; -import android.location.Location; -import android.location.LocationManager; -import android.webkit.WebView; - -public class GeoListener { - 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; // GPS listener - NetworkListener mNetwork; // Network listener - LocationManager mLocMan; // Location manager - - private GeoBroker broker; // GeoBroker object - - int interval; - - /** - * Constructor. - * - * @param id Listener id - * @param ctx - * @param time Sampling period in msec - * @param appView - */ - GeoListener(GeoBroker broker, String id, int time) { - this.id = id; - this.interval = time; - this.broker = broker; - this.mGps = null; - this.mNetwork = null; - this.mLocMan = (LocationManager) broker.ctx.getSystemService(Context.LOCATION_SERVICE); - - // If GPS provider, then create and start GPS listener - if (this.mLocMan.getProvider(LocationManager.GPS_PROVIDER) != null) { - this.mGps = new GpsListener(broker.ctx, time, this); - } - - // If network provider, then create and start network listener - if (this.mLocMan.getProvider(LocationManager.NETWORK_PROVIDER) != null) { - this.mNetwork = new NetworkListener(broker.ctx, time, this); - } - } - - /** - * Destroy listener. - */ - public void destroy() { - this.stop(); - } - - /** - * Location found. Send location back to JavaScript. - * - * @param loc - */ - void success(Location loc) { - - String params = loc.getLatitude() + "," + loc.getLongitude() + ", " + loc.getAltitude() + - "," + loc.getAccuracy() + "," + loc.getBearing() + - "," + loc.getSpeed() + "," + loc.getTime(); - - if (id == "global") { - this.stop(); - } - this.broker.sendJavascript("navigator._geo.success('" + id + "'," + params + ");"); - } - - /** - * Location failed. Send error back to JavaScript. - * - * @param code The error code - * @param msg The error message - */ - void fail(int code, String msg) { - this.broker.sendJavascript("navigator._geo.fail('" + this.id + "', '" + code + "', '" + msg + "');"); - this.stop(); - } - - /** - * Start retrieving location. - * - * @param interval - */ - void start(int interval) { - if (this.mGps != null) { - this.mGps.start(interval); - } - if (this.mNetwork != null) { - this.mNetwork.start(interval); - } - if (this.mNetwork == null && this.mGps == null) { - this.fail(POSITION_UNAVAILABLE, "No location providers available."); - } - } - - /** - * Stop listening for location. - */ - void stop() { - if (this.mGps != null) { - this.mGps.stop(); - } - if (this.mNetwork != null) { - this.mNetwork.stop(); - } - } - -} diff --git a/framework/src/org/apache/cordova/GpsListener.java b/framework/src/org/apache/cordova/GpsListener.java index f0006921..50107366 100755 --- a/framework/src/org/apache/cordova/GpsListener.java +++ b/framework/src/org/apache/cordova/GpsListener.java @@ -19,145 +19,37 @@ package org.apache.cordova; -import org.apache.cordova.api.CordovaInterface; - -import android.content.Context; -import android.location.Location; import android.location.LocationManager; -import android.location.LocationListener; -import android.os.Bundle; /** * This class handles requests for GPS location services. * */ -public class GpsListener implements LocationListener { - - private CordovaInterface mCtx; // CordovaActivity 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 GpsListener(CordovaInterface 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); - } - - /** - * 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) { - this.owner.fail(GeoListener.POSITION_UNAVAILABLE, "GPS provider disabled."); +public class GPSListener extends CordovaLocationListener { + public GPSListener(LocationManager locationManager, GeoBroker m) { + super(locationManager, m, "[Cordova GPSListener]"); + if (this.locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) { + // If network provider, then create and start network listener + this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 0, this); + } else { + this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "GPS provider is not available."); + } } - /** - * Called when the provider is enabled by the user. - * - * @param provider - */ - public void onProviderEnabled(String provider) { - 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) { - 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) { - System.out.println("GpsListener: " + provider + " is TEMPORARILY_UNAVAILABLE"); - } - else { - System.out.println("GpsListener: " + provider + " is Available"); - } - } - - /** - * Called when the location has changed. - * - * @param location - */ - public void onLocationChanged(Location 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 this.hasData; - } /** * Start requesting location updates. * * @param interval */ - public void start(int interval) { + public void start() { 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); + if (this.locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) { + this.running = true; + this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 0, this); + } else { + this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "GPS provider is not available."); } } } - - /** - * Stop receiving location updates. - */ - public void stop() { - if (this.running) { - this.mLocMan.removeUpdates(this); - } - this.running = false; - } - } diff --git a/framework/src/org/apache/cordova/NetworkListener.java b/framework/src/org/apache/cordova/NetworkListener.java index fd3fbd55..050560a6 100755 --- a/framework/src/org/apache/cordova/NetworkListener.java +++ b/framework/src/org/apache/cordova/NetworkListener.java @@ -16,138 +16,23 @@ specific language governing permissions and limitations under the License. */ + package org.apache.cordova; -import org.apache.cordova.api.CordovaInterface; - -import android.content.Context; -import android.location.Location; import android.location.LocationManager; -import android.location.LocationListener; -import android.os.Bundle; -public class NetworkListener implements LocationListener { - - private CordovaInterface mCtx; // CordovaActivity 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(CordovaInterface 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); +/** + * This class handles requests for GPS location services. + * + */ +public class NetworkListener extends CordovaLocationListener { + public NetworkListener(LocationManager locationManager, GeoBroker m) { + super(locationManager, m, "[Cordova NetworkListener]"); + if (this.locationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) { + // If network provider, then create and start network listener + this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 60000, 10, this); + } else { + this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "Network provider is not available."); + } } - - /** - * 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) { - 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) { - 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) { - 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) { - System.out.println("NetworkListener: " + provider + " is TEMPORARILY_UNAVAILABLE"); - } - else { - System.out.println("NetworkListener: " + provider + " is Available"); - } - } - - /** - * Called when the location has changed. - * - * @param location - */ - public void onLocationChanged(Location 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 Cordova. - // Only fire the success variables if the GPS is down for some reason. - if (!this.owner.mGps.hasLocation()) { - this.owner.success(location); - } - } - - /** - * 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); - } - } - } - - /** - * Stop receiving location updates. - */ - public void stop() { - if (this.running) { - this.mLocMan.removeUpdates(this); - } - this.running = false; - } - } From 1ee484f70d73eb392953f859772ab4c2671b3305 Mon Sep 17 00:00:00 2001 From: Fil Maj Date: Fri, 30 Mar 2012 02:32:43 -0700 Subject: [PATCH 04/14] Fixes for new geo stuff --- .../.settings/org.eclipse.jdt.core.prefs | 4 ++ .../cordova/CordovaLocationListener.java | 2 +- .../src/org/apache/cordova/GeoBroker.java | 40 ++++++++++++------- .../src/org/apache/cordova/GpsListener.java | 9 +---- .../org/apache/cordova/NetworkListener.java | 6 --- 5 files changed, 32 insertions(+), 29 deletions(-) create mode 100644 framework/.settings/org.eclipse.jdt.core.prefs diff --git a/framework/.settings/org.eclipse.jdt.core.prefs b/framework/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000..f77b31c2 --- /dev/null +++ b/framework/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,4 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 +org.eclipse.jdt.core.compiler.compliance=1.5 +org.eclipse.jdt.core.compiler.source=1.5 diff --git a/framework/src/org/apache/cordova/CordovaLocationListener.java b/framework/src/org/apache/cordova/CordovaLocationListener.java index 6eccfb44..3daa211b 100755 --- a/framework/src/org/apache/cordova/CordovaLocationListener.java +++ b/framework/src/org/apache/cordova/CordovaLocationListener.java @@ -175,7 +175,7 @@ public class CordovaLocationListener implements LocationListener { * * @param interval */ - private void start() { + protected void start() { if (!this.running) { if (this.locationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) { this.running = true; diff --git a/framework/src/org/apache/cordova/GeoBroker.java b/framework/src/org/apache/cordova/GeoBroker.java index b8cfe4ec..6a150b35 100755 --- a/framework/src/org/apache/cordova/GeoBroker.java +++ b/framework/src/org/apache/cordova/GeoBroker.java @@ -43,9 +43,6 @@ public class GeoBroker extends Plugin { * Constructor. */ public GeoBroker() { - this.locationManager = (LocationManager) this.ctx.getSystemService(Context.LOCATION_SERVICE); - this.networkListener = new NetworkListener(this.locationManager, this); - this.gpsListener = new GPSListener(this.locationManager, this); } /** @@ -57,6 +54,11 @@ public class GeoBroker extends Plugin { * @return A PluginResult object with a status and message. */ public PluginResult execute(String action, JSONArray args, String callbackId) { + if (this.locationManager == null) { + this.locationManager = (LocationManager) this.ctx.getSystemService(Context.LOCATION_SERVICE); + this.networkListener = new NetworkListener(this.locationManager, this); + this.gpsListener = new GPSListener(this.locationManager, this); + } PluginResult.Status status = PluginResult.Status.NO_RESULT; String message = ""; PluginResult result = new PluginResult(status, message); @@ -69,7 +71,7 @@ public class GeoBroker extends Plugin { Location last = this.locationManager.getLastKnownLocation((enableHighAccuracy ? LocationManager.GPS_PROVIDER : LocationManager.NETWORK_PROVIDER)); // Check if we can use lastKnownLocation to get a quick reading and use less battery if ((System.currentTimeMillis() - last.getTime()) <= maximumAge) { - result = new PluginResult(PluginResult.Status.OK, GeoBroker.returnLocationJSON(last)); + result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(last)); } else { this.getCurrentLocation(callbackId, enableHighAccuracy); } @@ -132,19 +134,27 @@ public class GeoBroker extends Plugin { this.gpsListener = null; } - public static String returnLocationJSON(Location loc) { - return "{" + - "'latitude':" + loc.getLatitude() + "," + - "'longitude':" + loc.getLongitude() + "," + - "'altitude':" + (loc.hasAltitude() ? loc.getAltitude() : "null") + "," + - "'accuracy':" + loc.getAccuracy() + "," + - "'heading':" + (loc.hasBearing() ? (loc.hasSpeed() ? loc.getBearing() : "NaN") : "null") + "," + - "'speed':" + loc.getSpeed() + "," + - "'timestamp':" + loc.getTime() + - "}"; + public JSONObject returnLocationJSON(Location loc) { + JSONObject o = new JSONObject(); + + try { + o.put("latitude", loc.getLatitude()); + o.put("longitude", loc.getLongitude()); + o.put("altitude", (loc.hasAltitude() ? loc.getAltitude() : null)); + o.put("accuracy", loc.getAccuracy()); + o.put("heading", (loc.hasBearing() ? (loc.hasSpeed() ? loc.getBearing() : null) : null)); + o.put("speed", loc.getSpeed()); + o.put("timestamp", loc.getTime()); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + + return o; } public void win(Location loc, String callbackId) { - PluginResult result = new PluginResult(PluginResult.Status.OK, GeoBroker.returnLocationJSON(loc)); + PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(loc)); this.success(result, callbackId); } /** diff --git a/framework/src/org/apache/cordova/GpsListener.java b/framework/src/org/apache/cordova/GpsListener.java index 50107366..2b46c7cf 100755 --- a/framework/src/org/apache/cordova/GpsListener.java +++ b/framework/src/org/apache/cordova/GpsListener.java @@ -28,12 +28,6 @@ import android.location.LocationManager; public class GPSListener extends CordovaLocationListener { public GPSListener(LocationManager locationManager, GeoBroker m) { super(locationManager, m, "[Cordova GPSListener]"); - if (this.locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) { - // If network provider, then create and start network listener - this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 0, this); - } else { - this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "GPS provider is not available."); - } } @@ -42,7 +36,8 @@ public class GPSListener extends CordovaLocationListener { * * @param interval */ - public void start() { + @Override + protected void start() { if (!this.running) { if (this.locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) { this.running = true; diff --git a/framework/src/org/apache/cordova/NetworkListener.java b/framework/src/org/apache/cordova/NetworkListener.java index 050560a6..6eaa8ac1 100755 --- a/framework/src/org/apache/cordova/NetworkListener.java +++ b/framework/src/org/apache/cordova/NetworkListener.java @@ -28,11 +28,5 @@ import android.location.LocationManager; public class NetworkListener extends CordovaLocationListener { public NetworkListener(LocationManager locationManager, GeoBroker m) { super(locationManager, m, "[Cordova NetworkListener]"); - if (this.locationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) { - // If network provider, then create and start network listener - this.locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 60000, 10, this); - } else { - this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "Network provider is not available."); - } } } From 0fd1e3c57ba265c203d78b7d4769e4d2f05b4489 Mon Sep 17 00:00:00 2001 From: Fil Maj Date: Mon, 7 May 2012 16:04:32 -0700 Subject: [PATCH 05/14] axing lowercase java file --- .../src/org/apache/cordova/GpsListener.java | 50 ------------------- 1 file changed, 50 deletions(-) delete mode 100755 framework/src/org/apache/cordova/GpsListener.java diff --git a/framework/src/org/apache/cordova/GpsListener.java b/framework/src/org/apache/cordova/GpsListener.java deleted file mode 100755 index 2b46c7cf..00000000 --- a/framework/src/org/apache/cordova/GpsListener.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ - -package org.apache.cordova; - -import android.location.LocationManager; - -/** - * This class handles requests for GPS location services. - * - */ -public class GPSListener extends CordovaLocationListener { - public GPSListener(LocationManager locationManager, GeoBroker m) { - super(locationManager, m, "[Cordova GPSListener]"); - } - - - /** - * Start requesting location updates. - * - * @param interval - */ - @Override - protected void start() { - if (!this.running) { - if (this.locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) { - this.running = true; - this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 0, this); - } else { - this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "GPS provider is not available."); - } - } - } -} From 18cc90b3d802e6250eb7803d5bd007a0b5eeb220 Mon Sep 17 00:00:00 2001 From: Fil Maj Date: Mon, 7 May 2012 16:04:51 -0700 Subject: [PATCH 06/14] adding uppercase java file! --- .../src/org/apache/cordova/GPSListener.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100755 framework/src/org/apache/cordova/GPSListener.java diff --git a/framework/src/org/apache/cordova/GPSListener.java b/framework/src/org/apache/cordova/GPSListener.java new file mode 100755 index 00000000..2b46c7cf --- /dev/null +++ b/framework/src/org/apache/cordova/GPSListener.java @@ -0,0 +1,50 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ + +package org.apache.cordova; + +import android.location.LocationManager; + +/** + * This class handles requests for GPS location services. + * + */ +public class GPSListener extends CordovaLocationListener { + public GPSListener(LocationManager locationManager, GeoBroker m) { + super(locationManager, m, "[Cordova GPSListener]"); + } + + + /** + * Start requesting location updates. + * + * @param interval + */ + @Override + protected void start() { + if (!this.running) { + if (this.locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) { + this.running = true; + this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 0, this); + } else { + this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "GPS provider is not available."); + } + } + } +} From bafa438ce3f33f0edcaa9e65cc78a7bb434685bd Mon Sep 17 00:00:00 2001 From: Fil Maj Date: Mon, 7 May 2012 16:22:01 -0700 Subject: [PATCH 07/14] updating JS to latest for geolocation updates --- framework/assets/js/cordova.android.js | 421 +++++++++++++++++++------ 1 file changed, 317 insertions(+), 104 deletions(-) diff --git a/framework/assets/js/cordova.android.js b/framework/assets/js/cordova.android.js index abd2a0d9..402de0c0 100644 --- a/framework/assets/js/cordova.android.js +++ b/framework/assets/js/cordova.android.js @@ -1,6 +1,6 @@ -// commit 1c9ac3578a369dcb35b168c3e2d7ce2e89d45d12 +// commit a5f0a62f9a9dc5fd7af95ec3d09b6b17c0b89b44 -// File generated at :: Tue May 01 2012 13:42:28 GMT-0700 (PDT) +// File generated at :: Mon May 07 2012 16:20:11 GMT-0700 (PDT) /* Licensed to the Apache Software Foundation (ASF) under one @@ -349,10 +349,10 @@ function deprecateFunctions(obj, objLabel) { * TODO: remove in 2.0. */ if (!window.PhoneGap) { - window.PhoneGap = cordova; + window.PhoneGap = deprecateFunctions(cordova, 'PhoneGap'); } if (!window.Cordova) { - window.Cordova = cordova; + window.Cordova = deprecateFunctions(cordova, 'Cordova'); } /** @@ -721,6 +721,20 @@ module.exports = { } } }, + Cordova: { + children: { + exec: { + path: 'cordova/exec' + } + } + }, + PhoneGap:{ + children: { + exec: { + path: 'cordova/exec' + } + } + }, navigator: { children: { notification: { @@ -757,6 +771,9 @@ module.exports = { path: 'cordova/plugin/network' } } + }, + splashscreen: { + path: 'cordova/plugin/splashscreen' } } }, @@ -891,6 +908,7 @@ module.exports = { } } }; + }); // file: lib/android/exec.js @@ -1763,15 +1781,20 @@ var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) { /** * The altitude of the position. */ - this.altitude = alt; + this.altitude = (alt !== undefined ? alt : null); /** * The direction the device is moving at the position. */ - this.heading = head; + this.heading = (head !== undefined ? head : null); /** * The velocity with which the device is moving at the position. */ - this.speed = vel; + this.speed = (vel !== undefined ? vel : null); + + if (this.speed === 0 || this.speed === null) { + this.heading = NaN; + } + /** * The altitude accuracy of the position. */ @@ -1779,6 +1802,7 @@ var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) { }; module.exports = Coordinates; + }); // file: lib/common/plugin/DirectoryEntry.js @@ -3246,11 +3270,16 @@ define("cordova/plugin/Position", function(require, exports, module) { var Coordinates = require('cordova/plugin/Coordinates'); var Position = function(coords, timestamp) { - this.coords = new Coordinates(coords.latitude, coords.longitude, coords.altitude, coords.accuracy, coords.heading, coords.velocity, coords.altitudeAccuracy); + if (coords) { + this.coords = new Coordinates(coords.latitude, coords.longitude, coords.altitude, coords.accuracy, coords.heading, coords.velocity, coords.altitudeAccuracy); + } else { + this.coords = new Coordinates(); + } this.timestamp = (timestamp !== undefined) ? timestamp : new Date().getTime(); }; module.exports = Position; + }); // file: lib/common/plugin/PositionError.js @@ -4508,27 +4537,45 @@ var timers = {}; // list of timers in use // Returns default params, overrides if provided with values function parseParameters(options) { var opt = { - maximumAge: 10000, + maximumAge: 0, enableHighAccuracy: false, - timeout: 10000 + timeout: Infinity }; if (options) { - if (options.maximumAge !== undefined) { + if (options.maximumAge !== undefined && !isNaN(options.maximumAge) && options.maximumAge > 0) { opt.maximumAge = options.maximumAge; } if (options.enableHighAccuracy !== undefined) { opt.enableHighAccuracy = options.enableHighAccuracy; } - if (options.timeout !== undefined) { - opt.timeout = options.timeout; + if (options.timeout !== undefined && !isNaN(options.timeout)) { + if (options.timeout < 0) { + opt.timeout = 0; + } else { + opt.timeout = options.timeout; + } } } return opt; } +// Returns a timeout failure, closed over a specified timeout value and error callback. +function createTimeout(errorCallback, timeout) { + var t = setTimeout(function() { + clearTimeout(t); + t = null; + errorCallback({ + code:PositionError.TIMEOUT, + message:"Position retrieval timed out." + }); + }, timeout); + return t; +} + var geolocation = { + lastPosition:null, // reference to last known (cached) position returned /** * Asynchronously aquires the current position. * @@ -4537,10 +4584,24 @@ var geolocation = { * @param {PositionOptions} options The options for getting the position data. (OPTIONAL) */ getCurrentPosition:function(successCallback, errorCallback, options) { + if (arguments.length === 0) { + throw new Error("getCurrentPosition must be called with at least one argument."); + } options = parseParameters(options); + // Timer var that will fire an error callback if no position is retrieved from native + // before the "timeout" param provided expires + var timeoutTimer = null; + var win = function(p) { - successCallback(new Position( + clearTimeout(timeoutTimer); + if (!timeoutTimer) { + // Timeout already happened, or native fired error callback for + // this geo request. + // Don't continue with success callback. + return; + } + var pos = new Position( { latitude:p.latitude, longitude:p.longitude, @@ -4551,13 +4612,45 @@ var geolocation = { altitudeAccuracy:p.altitudeAccuracy }, p.timestamp || new Date() - )); + ); + geolocation.lastPosition = pos; + successCallback(pos); }; var fail = function(e) { - errorCallback(new PositionError(e.code, e.message)); + clearTimeout(timeoutTimer); + timeoutTimer = null; + var err = new PositionError(e.code, e.message); + if (errorCallback) { + errorCallback(err); + } }; - exec(win, fail, "Geolocation", "getLocation", [options.enableHighAccuracy, options.timeout, options.maximumAge]); + // Check our cached position, if its timestamp difference with current time is less than the maximumAge, then just + // fire the success callback with the cached position. + if (geolocation.lastPosition && options.maximumAge && (((new Date()).getTime() - geolocation.lastPosition.timestamp.getTime()) <= options.maximumAge)) { + successCallback(geolocation.lastPosition); + // If the cached position check failed and the timeout was set to 0, error out with a TIMEOUT error object. + } else if (options.timeout === 0) { + fail({ + code:PositionError.TIMEOUT, + message:"timeout value in PositionOptions set to 0 and no cached Position object available, or cached Position object's age exceed's provided PositionOptions' maximumAge parameter." + }); + // Otherwise we have to call into native to retrieve a position. + } else { + if (options.timeout !== Infinity) { + // If the timeout value was not set to Infinity (default), then + // set up a timeout function that will fire the error callback + // if no successful position was retrieved before timeout expired. + timeoutTimer = createTimeout(fail, options.timeout); + } else { + // This is here so the check in the win function doesn't mess stuff up + // may seem weird but this guarantees timeoutTimer is + // always truthy before we call into native + timeoutTimer = true; + } + exec(win, fail, "Geolocation", "getLocation", [options.enableHighAccuracy, options.maximumAge]); + } + return timeoutTimer; }, /** * Asynchronously watches the geolocation for changes to geolocation. When a change occurs, @@ -4569,12 +4662,46 @@ var geolocation = { * @return String The watch id that must be passed to #clearWatch to stop watching. */ watchPosition:function(successCallback, errorCallback, options) { + if (arguments.length === 0) { + throw new Error("watchPosition must be called with at least one argument."); + } options = parseParameters(options); var id = utils.createUUID(); - timers[id] = window.setInterval(function() { - geolocation.getCurrentPosition(successCallback, errorCallback, options); - }, options.timeout); + + // Tell device to get a position ASAP, and also retrieve a reference to the timeout timer generated in getCurrentPosition + timers[id] = geolocation.getCurrentPosition(successCallback, errorCallback, options); + + var fail = function(e) { + clearTimeout(timers[id]); + var err = new PositionError(e.code, e.message); + if (errorCallback) { + errorCallback(err); + } + }; + + var win = function(p) { + clearTimeout(timers[id]); + if (options.timeout !== Infinity) { + timers[id] = createTimeout(fail, options.timeout); + } + var pos = new Position( + { + latitude:p.latitude, + longitude:p.longitude, + altitude:p.altitude, + accuracy:p.accuracy, + heading:p.heading, + velocity:p.velocity, + altitudeAccuracy:p.altitudeAccuracy + }, + p.timestamp || new Date() + ); + geolocation.lastPosition = pos; + successCallback(pos); + }; + + exec(win, fail, "Geolocation", "addWatch", [id, options.enableHighAccuracy]); return id; }, @@ -4585,13 +4712,15 @@ var geolocation = { */ clearWatch:function(id) { if (id && timers[id] !== undefined) { - window.clearInterval(timers[id]); + clearTimeout(timers[id]); delete timers[id]; + exec(null, null, "Geolocation", "clearWatch", [id]); } } }; module.exports = geolocation; + }); // file: lib/common/plugin/network.js @@ -4809,8 +4938,165 @@ module.exports = function(uri, successCallback, errorCallback) { }); +// file: lib/common/plugin/splashscreen.js +define("cordova/plugin/splashscreen", function(require, exports, module) { +var exec = require('cordova/exec'); + +var splashscreen = { + hide:function() { + exec(null, null, "SplashScreen", "hide", []); + } +}; + +module.exports = splashscreen; +}); + // file: lib/common/utils.js define("cordova/utils", function(require, exports, module) { +var utils = exports; + +/** + * Returns an indication of whether the argument is an array or not + */ +utils.isArray = function(a) { + return Object.prototype.toString.call(a) == '[object Array]'; +}; + +/** + * Returns an indication of whether the argument is a Date or not + */ +utils.isDate = function(d) { + return Object.prototype.toString.call(d) == '[object Date]'; +}; + +/** + * Does a deep clone of the object. + */ +utils.clone = function(obj) { + if(!obj || typeof obj == 'function' || utils.isDate(obj) || typeof obj != 'object') { + return obj; + } + + var retVal, i; + + if(utils.isArray(obj)){ + retVal = []; + for(i = 0; i < obj.length; ++i){ + retVal.push(utils.clone(obj[i])); + } + return retVal; + } + + retVal = {}; + for(i in obj){ + if(!(i in retVal) || retVal[i] != obj[i]) { + retVal[i] = utils.clone(obj[i]); + } + } + return retVal; +}; + +/** + * Returns a wrappered version of the function + */ +utils.close = function(context, func, params) { + if (typeof params == 'undefined') { + return function() { + return func.apply(context, arguments); + }; + } else { + return function() { + return func.apply(context, params); + }; + } +}; + +/** + * Create a UUID + */ +utils.createUUID = function() { + return UUIDcreatePart(4) + '-' + + UUIDcreatePart(2) + '-' + + UUIDcreatePart(2) + '-' + + UUIDcreatePart(2) + '-' + + UUIDcreatePart(6); +}; + +/** + * Extends a child object from a parent object using classical inheritance + * pattern. + */ +utils.extend = (function() { + // proxy used to establish prototype chain + var F = function() {}; + // extend Child from Parent + return function(Child, Parent) { + F.prototype = Parent.prototype; + Child.prototype = new F(); + Child.__super__ = Parent.prototype; + Child.prototype.constructor = Child; + }; +}()); + +/** + * Alerts a message in any available way: alert or console.log. + */ +utils.alert = function(msg) { + if (alert) { + alert(msg); + } else if (console && console.log) { + console.log(msg); + } +}; + +/** + * Formats a string and arguments following it ala sprintf() + * + * format chars: + * %j - format arg as JSON + * %o - format arg as JSON + * %c - format arg as '' + * %% - replace with '%' + * any other char following % will format it's + * arg via toString(). + * + * for rationale, see FireBug's Console API: + * http://getfirebug.com/wiki/index.php/Console_API + */ +utils.format = function(formatString /* ,... */) { + if (formatString === null || formatString === undefined) return ""; + if (arguments.length == 1) return formatString.toString(); + + var pattern = /(.*?)%(.)(.*)/; + var rest = formatString.toString(); + var result = []; + var args = [].slice.call(arguments,1); + + while (args.length) { + var arg = args.shift(); + var match = pattern.exec(rest); + + if (!match) break; + + rest = match[3]; + + result.push(match[1]); + + if (match[2] == '%') { + result.push('%'); + args.unshift(arg); + continue; + } + + result.push(formatted(arg, match[2])); + } + + result.push(rest); + + return result.join(''); +}; + +//------------------------------------------------------------------------------ function UUIDcreatePart(length) { var uuidpart = ""; for (var i=0; i Date: Tue, 8 May 2012 15:23:00 -0400 Subject: [PATCH 08/14] Properly querying the Andoid content DB when deleteing an image file --- framework/src/org/apache/cordova/FileUtils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/framework/src/org/apache/cordova/FileUtils.java b/framework/src/org/apache/cordova/FileUtils.java index 863da5bd..c8a45cb4 100755 --- a/framework/src/org/apache/cordova/FileUtils.java +++ b/framework/src/org/apache/cordova/FileUtils.java @@ -220,9 +220,10 @@ public class FileUtils extends Plugin { * @param filePath the path to check */ private void notifyDelete(String filePath) { + String newFilePath = filePath.substring(7); int result = this.ctx.getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, MediaStore.Images.Media.DATA + " = ?", - new String[] {filePath}); + new String[] {newFilePath}); } /** From 2625a57fdd5e6a7f06d95075d29e3b3cae344d40 Mon Sep 17 00:00:00 2001 From: Michael Brooks Date: Wed, 9 May 2012 15:32:53 -0700 Subject: [PATCH 09/14] Fix README.md formatting to install commons-codec-1.6.jar --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 53a3a45c..b2198e93 100755 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Building --- To create your cordova.jar, copy the commons codec: + mv commons-codec-1.6.jar framework/libs then run in the framework directory: From b2f49b15ba26cf59069491bd89fef90c43272cc3 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Thu, 10 May 2012 12:25:47 -0700 Subject: [PATCH 10/14] Don't commit Eclipse preferences --- framework/.settings/org.eclipse.jdt.core.prefs | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 framework/.settings/org.eclipse.jdt.core.prefs diff --git a/framework/.settings/org.eclipse.jdt.core.prefs b/framework/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index f77b31c2..00000000 --- a/framework/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 -org.eclipse.jdt.core.compiler.source=1.5 From 08a32272d37174b15d9e53cb2c2ca1ff2bfdc5d0 Mon Sep 17 00:00:00 2001 From: Fil Maj Date: Thu, 10 May 2012 16:40:41 -0700 Subject: [PATCH 11/14] [CB-683] Pause and resume events should route through fireDocumentEvent so we get the event object passed into the handler --- framework/src/org/apache/cordova/DroidGap.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/src/org/apache/cordova/DroidGap.java b/framework/src/org/apache/cordova/DroidGap.java index 107eb52a..5e2586d0 100755 --- a/framework/src/org/apache/cordova/DroidGap.java +++ b/framework/src/org/apache/cordova/DroidGap.java @@ -813,7 +813,7 @@ public class DroidGap extends Activity implements CordovaInterface { } // Send pause event to JavaScript - this.appView.loadUrl("javascript:try{cordova.require('cordova/channel').onPause.fire();}catch(e){console.log('exception firing pause event from native');};"); + this.appView.loadUrl("javascript:try{cordova.fireDocumentEvent('pause');}catch(e){console.log('exception firing pause event from native');};"); // Forward to plugins if (this.pluginManager != null) { @@ -858,7 +858,7 @@ public class DroidGap extends Activity implements CordovaInterface { } // Send resume event to JavaScript - this.appView.loadUrl("javascript:try{cordova.require('cordova/channel').onResume.fire();}catch(e){console.log('exception firing resume event from native');};"); + this.appView.loadUrl("javascript:try{cordova.fireDocumentEvent('resume');}catch(e){console.log('exception firing resume event from native');};"); // Forward to plugins if (this.pluginManager != null) { From 6a628f7f2d886f8e1bc146c2beab21d02096e068 Mon Sep 17 00:00:00 2001 From: Fil Maj Date: Thu, 10 May 2012 16:43:08 -0700 Subject: [PATCH 12/14] [CB-683] updating JS for fix for 683 --- framework/assets/js/cordova.android.js | 55 +++++++++++++++----------- framework/project.properties | 2 +- 2 files changed, 33 insertions(+), 24 deletions(-) diff --git a/framework/assets/js/cordova.android.js b/framework/assets/js/cordova.android.js index 402de0c0..7bb06c2f 100644 --- a/framework/assets/js/cordova.android.js +++ b/framework/assets/js/cordova.android.js @@ -1,6 +1,6 @@ -// commit a5f0a62f9a9dc5fd7af95ec3d09b6b17c0b89b44 +// commit facaa38a0bd924aa15c14c372537c00382f1e593 -// File generated at :: Mon May 07 2012 16:20:11 GMT-0700 (PDT) +// File generated at :: Thu May 10 2012 16:39:13 GMT-0700 (PDT) /* Licensed to the Apache Software Foundation (ASF) under one @@ -98,17 +98,7 @@ var documentEventHandlers = {}, document.addEventListener = function(evt, handler, capture) { var e = evt.toLowerCase(); - if (e == 'deviceready') { - channel.onDeviceReady.subscribeOnce(handler); - } else if (e == 'resume') { - channel.onResume.subscribe(handler); - // if subscribing listener after event has already fired, invoke the handler - if (channel.onResume.fired && typeof handler == 'function') { - handler(); - } - } else if (e == 'pause') { - channel.onPause.subscribe(handler); - } else if (typeof documentEventHandlers[e] != 'undefined') { + if (typeof documentEventHandlers[e] != 'undefined') { documentEventHandlers[e].subscribe(handler); } else { m_document_addEventListener.call(document, evt, handler, capture); @@ -126,13 +116,8 @@ window.addEventListener = function(evt, handler, capture) { document.removeEventListener = function(evt, handler, capture) { var e = evt.toLowerCase(); - // Check for pause/resume events first. - if (e == 'resume') { - channel.onResume.unsubscribe(handler); - } else if (e == 'pause') { - channel.onPause.unsubscribe(handler); // If unsubcribing from an event that is handled by a plugin - } else if (typeof documentEventHandlers[e] != "undefined") { + if (typeof documentEventHandlers[e] != "undefined") { documentEventHandlers[e].unsubscribe(handler); } else { m_document_removeEventListener.call(document, evt, handler, capture); @@ -318,6 +303,11 @@ var cordova = { } }; +// Register pause, resume and deviceready channels as events on document. +channel.onPause = cordova.addDocumentEventHandler('pause'); +channel.onResume = cordova.addDocumentEventHandler('resume'); +channel.onDeviceReady = cordova.addDocumentEventHandler('deviceready'); + // Adds deprecation warnings to functions of an object (but only logs a message once) function deprecateFunctions(obj, objLabel) { var newObj = {}; @@ -645,10 +635,13 @@ Channel.prototype.unsubscribe = function(g) { if (g === null || g === undefined) { throw "You must pass _something_ into Channel.unsubscribe"; } if (typeof g == 'function') { g = g.observer_guid; } - this.handlers[g] = null; - delete this.handlers[g]; - this.numHandlers--; - if (this.events.onUnsubscribe) this.events.onUnsubscribe.call(this); + var handler = this.handlers[g]; + if (handler) { + this.handlers[g] = null; + delete this.handlers[g]; + this.numHandlers--; + if (this.events.onUnsubscribe) this.events.onUnsubscribe.call(this); + } }; /** @@ -1145,6 +1138,7 @@ module.exports = { } } }; + }); // file: lib/common/plugin/Acceleration.js @@ -1986,6 +1980,21 @@ Entry.prototype.getMetadata = function(successCallback, errorCallback) { exec(success, fail, "File", "getMetadata", [this.fullPath]); }; +/** + * Set the metadata of the entry. + * + * @param successCallback + * {Function} is called with a Metadata object + * @param errorCallback + * {Function} is called with a FileError + * @param metadataObject + * {Object} keys and values to set + */ +Entry.prototype.setMetadata = function(successCallback, errorCallback, metadataObject) { + + exec(successCallback, errorCallback, "File", "setMetadata", [this.fullPath, metadataObject]); +}; + /** * Move a file or directory to a new location. * diff --git a/framework/project.properties b/framework/project.properties index 247ca66e..276f1305 100644 --- a/framework/project.properties +++ b/framework/project.properties @@ -10,5 +10,5 @@ # Indicates whether an apk should be generated for each density. split.density=false # Project target. -target=android-14 +target=Google Inc.:Google APIs:15 apk-configurations= From 5b324c85b088900237c4c51b43bbf0080f8a6a04 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Fri, 11 May 2012 10:38:21 -0700 Subject: [PATCH 13/14] Broke the merge, need to add GPSListener.java --- .../src/org/apache/cordova/GPSListener.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100755 framework/src/org/apache/cordova/GPSListener.java diff --git a/framework/src/org/apache/cordova/GPSListener.java b/framework/src/org/apache/cordova/GPSListener.java new file mode 100755 index 00000000..2b46c7cf --- /dev/null +++ b/framework/src/org/apache/cordova/GPSListener.java @@ -0,0 +1,50 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ + +package org.apache.cordova; + +import android.location.LocationManager; + +/** + * This class handles requests for GPS location services. + * + */ +public class GPSListener extends CordovaLocationListener { + public GPSListener(LocationManager locationManager, GeoBroker m) { + super(locationManager, m, "[Cordova GPSListener]"); + } + + + /** + * Start requesting location updates. + * + * @param interval + */ + @Override + protected void start() { + if (!this.running) { + if (this.locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) { + this.running = true; + this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 0, this); + } else { + this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "GPS provider is not available."); + } + } + } +} From dd0b6b1e30f592a208147fb76a2f7079e421de85 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Fri, 11 May 2012 15:14:35 -0700 Subject: [PATCH 14/14] Adding empty tests. May have to re-think the way we test this method --- .../apache/cordova/test/BackButtonTest.java | 49 +++++++++++++++++++ .../cordova/test/CordovaActivityTest.java | 3 +- .../org/apache/cordova/test/ErrorUrlTest.java | 35 +++++++++++++ .../apache/cordova/test/HtmlNotFoundTest.java | 11 +++++ .../org/apache/cordova/test/IFrameTest.java | 11 +++++ .../org/apache/cordova/test/JQMTabTest.java | 12 +++++ .../apache/cordova/test/LifecycleTest.java | 11 +++++ .../apache/cordova/test/LoadTimeoutTest.java | 10 ++++ .../apache/cordova/test/SplashscreenTest.java | 12 +++++ .../apache/cordova/test/UserWebViewTest.java | 11 +++++ .../apache/cordova/test/WhitelistTest.java | 12 +++++ test/src/org/apache/cordova/test/XhrTest.java | 11 +++++ .../src/org/apache/cordova/test/errorurl.java | 2 + 13 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 test/src/org/apache/cordova/test/BackButtonTest.java create mode 100644 test/src/org/apache/cordova/test/ErrorUrlTest.java create mode 100644 test/src/org/apache/cordova/test/HtmlNotFoundTest.java create mode 100644 test/src/org/apache/cordova/test/IFrameTest.java create mode 100644 test/src/org/apache/cordova/test/JQMTabTest.java create mode 100644 test/src/org/apache/cordova/test/LifecycleTest.java create mode 100644 test/src/org/apache/cordova/test/LoadTimeoutTest.java create mode 100644 test/src/org/apache/cordova/test/SplashscreenTest.java create mode 100644 test/src/org/apache/cordova/test/UserWebViewTest.java create mode 100644 test/src/org/apache/cordova/test/WhitelistTest.java create mode 100644 test/src/org/apache/cordova/test/XhrTest.java diff --git a/test/src/org/apache/cordova/test/BackButtonTest.java b/test/src/org/apache/cordova/test/BackButtonTest.java new file mode 100644 index 00000000..db09792f --- /dev/null +++ b/test/src/org/apache/cordova/test/BackButtonTest.java @@ -0,0 +1,49 @@ +package org.apache.cordova.test; + +import org.apache.cordova.CordovaWebView; + +import android.test.ActivityInstrumentationTestCase2; +import android.test.TouchUtils; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + +public class BackButtonTest extends ActivityInstrumentationTestCase2 { + + private backbuttonmultipage testActivity; + private FrameLayout containerView; + private LinearLayout innerContainer; + private CordovaWebView testView; + private TouchUtils touchTest; + private long TIMEOUT = 5000; + + public BackButtonTest() { + super("org.apache.cordova.test",backbuttonmultipage.class); + } + + protected void setUp() throws Exception { + super.setUp(); + testActivity = this.getActivity(); + containerView = (FrameLayout) testActivity.findViewById(android.R.id.content); + innerContainer = (LinearLayout) containerView.getChildAt(0); + testView = (CordovaWebView) innerContainer.getChildAt(0); + touchTest = new TouchUtils(); + } + + public void testPreconditions(){ + assertNotNull(innerContainer); + assertNotNull(testView); + } + + public void testClick() { + touchTest.tapView(this, testView); + } + + private void sleep() { + try { + Thread.sleep(TIMEOUT ); + } catch (InterruptedException e) { + fail("Unexpected Timeout"); + } + } + +} diff --git a/test/src/org/apache/cordova/test/CordovaActivityTest.java b/test/src/org/apache/cordova/test/CordovaActivityTest.java index 8a38b1ad..3a5b47db 100644 --- a/test/src/org/apache/cordova/test/CordovaActivityTest.java +++ b/test/src/org/apache/cordova/test/CordovaActivityTest.java @@ -33,9 +33,10 @@ public class CordovaActivityTest extends ActivityInstrumentationTestCase2 { + + errorurl testActivity; + private FrameLayout containerView; + private LinearLayout innerContainer; + private CordovaWebView testView; + + public ErrorUrlTest() { + super("org.apache.cordova.test",errorurl.class); + } + + + protected void setUp() throws Exception { + super.setUp(); + testActivity = this.getActivity(); + containerView = (FrameLayout) testActivity.findViewById(android.R.id.content); + innerContainer = (LinearLayout) containerView.getChildAt(0); + testView = (CordovaWebView) innerContainer.getChildAt(0); + + } + + public void testPreconditions(){ + assertNotNull(innerContainer); + assertNotNull(testView); + } + +} diff --git a/test/src/org/apache/cordova/test/HtmlNotFoundTest.java b/test/src/org/apache/cordova/test/HtmlNotFoundTest.java new file mode 100644 index 00000000..4546e5ac --- /dev/null +++ b/test/src/org/apache/cordova/test/HtmlNotFoundTest.java @@ -0,0 +1,11 @@ +package org.apache.cordova.test; + +import android.test.ActivityInstrumentationTestCase2; + +public class HtmlNotFoundTest extends ActivityInstrumentationTestCase2 { + + + public HtmlNotFoundTest() { + super("org.apache.cordova.test",htmlnotfound.class); + } +} diff --git a/test/src/org/apache/cordova/test/IFrameTest.java b/test/src/org/apache/cordova/test/IFrameTest.java new file mode 100644 index 00000000..07fba57a --- /dev/null +++ b/test/src/org/apache/cordova/test/IFrameTest.java @@ -0,0 +1,11 @@ +package org.apache.cordova.test; + +import android.test.ActivityInstrumentationTestCase2; + +public class IFrameTest extends ActivityInstrumentationTestCase2