You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by fi...@apache.org on 2013/01/22 02:57:58 UTC

[24/52] [partial] support for 2.4.0rc1. "vendored" the platform libs in. added Gord and Braden as contributors. removed dependency on unzip and axed the old download-cordova code.

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/Geolocation.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/Geolocation.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/Geolocation.java
new file mode 100644
index 0000000..1226f48
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/Geolocation.java
@@ -0,0 +1,372 @@
+/*
+ * 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.geolocation;
+
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import javax.microedition.location.Criteria;
+import javax.microedition.location.Location;
+import javax.microedition.location.LocationException;
+import javax.microedition.location.LocationProvider;
+
+import org.apache.cordova.CordovaExtension;
+import org.apache.cordova.api.Plugin;
+import org.apache.cordova.api.PluginResult;
+import org.apache.cordova.json4j.JSONArray;
+import org.apache.cordova.json4j.JSONException;
+import org.apache.cordova.json4j.JSONObject;
+import org.apache.cordova.util.Logger;
+
+import net.rim.device.api.gps.BlackBerryCriteria;
+import net.rim.device.api.gps.BlackBerryLocationProvider;
+import net.rim.device.api.gps.GPSInfo;
+
+public class Geolocation extends Plugin {
+
+	/**
+	 * Possible actions.
+	 */
+	protected static final int ACTION_WATCH = 0;
+	protected static final int ACTION_CLEAR_WATCH = 1;
+	protected static final int ACTION_GET_POSITION = 2;
+	protected static final int ACTION_SHUTDOWN = 3;
+
+	/**
+	 * Callback ID argument index.
+	 */
+	protected static final int ARG_CALLBACK_ID = 0;
+
+	/**
+	 * Minimum GPS accuracy (meters).
+	 */
+	protected static final float MIN_GPS_ACCURACY = 10F; // meters
+
+	/**
+	 * Hash of all the listeners created, keyed on callback ids.
+	 */
+	protected final Hashtable geoListeners;
+
+	/**
+	 * Constructor.
+	 */
+	public Geolocation() {
+		this.geoListeners = new Hashtable();
+	}
+
+	/**
+	 * Executes the specified geolocation action.
+	 *
+	 * @param action
+	 * 	  "getCurrentPosition" - Retrieves current location.
+	 * 	  "watchPosition"      - Establishes a location provider that is keyed on specified position options
+	 *                           and attaches a listener that notifies registered callbacks of location updates.
+	 *    "stop"               - Clears the watch identified by the watch ID that must be specified in args.
+	 *    "shutdown"           - Stops all listeners and resets all location providers.
+	 * @param callbackId callback managed by the plugin manager (ignored)
+	 * @param args contains the callback id and position options
+	 */
+	public PluginResult execute(String action, JSONArray args,  String callbackId) {
+
+		/*
+		 * The geolocation plugin bypasses the plugin callback framework for
+		 * success callbacks because the current implementation of the framework
+		 * deletes the callbacks after they have been called.  The geolocation
+		 * listener callbacks need to continue listening for location changes,
+		 * and are therefore managed separately from the plugin framework.
+		 *
+		 * This means the invoking script must pass the listener callback ID in
+		 * the args parameter (along with the position options).  The callbackId
+		 * parameter (used by the plugin framework) is ignored.
+		 *
+		 * The invoking script should still provide a failure callback so the
+		 * plugin framework can handle general error reporting.
+		 */
+		String listenerCallbackId;
+		try {
+			listenerCallbackId = args.getString(ARG_CALLBACK_ID);
+		} catch (JSONException e) {
+			return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "Callback ID argument is not valid.");
+		}
+
+		if (!GPSInfo.isGPSModeAvailable(GPSInfo.GPS_DEVICE_INTERNAL)){
+			return new PluginResult(GeolocationStatus.GPS_NOT_AVAILABLE);
+		}
+
+		PositionOptions options;
+		switch (getAction(action)) {
+			case ACTION_CLEAR_WATCH:
+				clearWatch(listenerCallbackId);
+				return null;
+
+			case ACTION_WATCH:
+
+				try {
+					options = PositionOptions.fromJSONArray(args);
+				} catch (NumberFormatException e) {
+					return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "One of the position options is not a valid number.");
+				} catch (JSONException e) {
+					return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "One of the position options is not valid JSON.");
+				}
+
+				this.watchPosition(listenerCallbackId, options);
+				return null;
+
+			case ACTION_GET_POSITION:
+
+				try {
+					options = PositionOptions.fromJSONArray(args);
+				} catch (NumberFormatException e) {
+					return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "One of the position options is not a valid number.");
+				} catch (JSONException e) {
+					return new PluginResult(PluginResult.Status.JSON_EXCEPTION, "One of the position options is not valid JSON.");
+				}
+
+				this.getCurrentPosition(listenerCallbackId, options);
+				return null;
+
+			case ACTION_SHUTDOWN:
+				this.shutdown();
+				return null;
+		}
+
+		return new PluginResult(PluginResult.Status.INVALID_ACTION, "Geolocation: invalid action " + action);
+	}
+
+	/**
+	 * Checks if the provided location is valid.
+	 * @param location
+	 * @return true if the location is valid
+	 */
+	protected boolean isLocationValid(Location location) {
+		return location != null && location.isValid();
+	}
+
+	/**
+	 * Checks if the provided location is fresh or not.
+	 * @param po           position options containing maximum location age allowed
+	 * @param location     location object
+	 * @return true if the location is newer than maximum age allowed
+	 */
+	protected boolean isLocationFresh(PositionOptions po, Location location) {
+		return new Date().getTime() - location.getTimestamp() < po.maxAge;
+	}
+
+	/**
+	 * Checks if the accuracy of the location is high enough.
+	 * @param po           position options containing high accuracy flag
+	 * @param location     location object
+	 * @return true if the location accuracy is lower than MIN_GPS_ACCURACY
+	 */
+	protected boolean isLocationAccurate(PositionOptions po, Location location) {
+		return po.enableHighAccuracy && location.getQualifiedCoordinates().getHorizontalAccuracy() < MIN_GPS_ACCURACY;
+	}
+
+	/**
+	 * Retrieves a location provider with some criteria.
+	 * @param po position options
+	 */
+	protected static LocationProvider getLocationProvider(PositionOptions po) {
+		// configure criteria for location provider
+		// Note: being too restrictive will make it less likely that one will be returned
+		BlackBerryCriteria criteria = new BlackBerryCriteria();
+
+		// can we get GPS info from the wifi network?
+		if (GPSInfo.isGPSModeAvailable(GPSInfo.GPS_MODE_ASSIST))
+			criteria.setMode(GPSInfo.GPS_MODE_ASSIST);
+		// relies on device GPS receiver - not good indoors or if obstructed
+		else if (GPSInfo.isGPSModeAvailable(GPSInfo.GPS_MODE_AUTONOMOUS))
+			criteria.setMode(GPSInfo.GPS_MODE_AUTONOMOUS);
+
+		criteria.setAltitudeRequired(true);
+
+		// enable full power usage to increase location accuracy
+		if (po.enableHighAccuracy) {
+			criteria.setPreferredPowerConsumption(Criteria.POWER_USAGE_HIGH);
+		}
+
+		// Attempt to get a location provider
+		BlackBerryLocationProvider provider;
+		try {
+			// Note: this could return an existing provider that meets above criteria
+			provider  = (BlackBerryLocationProvider) LocationProvider.getInstance(criteria);
+		} catch (LocationException e) {
+			// all LocationProviders are currently permanently unavailable :(
+			provider = null;
+		}
+
+		return provider;
+	}
+
+    /**
+     * Gets the current location, then creates a location listener to receive
+     * updates. Registers the specified callback with the listener.
+     * @param callbackId   callback to receive location updates
+     * @param options      position options
+     */
+    protected void watchPosition(String callbackId, PositionOptions options) {
+
+        // attempt to retrieve a location provider
+        LocationProvider provider = getLocationProvider(options);
+        if (provider == null) {
+            CordovaExtension.invokeErrorCallback(callbackId,
+                    new GeolocationResult(GeolocationStatus.GPS_NOT_AVAILABLE));
+            return;
+        }
+
+        // create a listener for location updates
+        GeolocationListener listener;
+        try {
+            listener = new GeolocationListener(provider, callbackId, options);
+        } catch (IllegalArgumentException e) {
+            // if 	interval < -1, or
+            // if 	(interval != -1) and
+            //		(timeout > interval or maxAge > interval or
+            //			(timeout < 1 and timeout != -1) or
+            //			(maxAge < 1 and maxAge != -1)
+            //		)
+            CordovaExtension.invokeErrorCallback(callbackId,
+                    new GeolocationResult(GeolocationStatus.GPS_JSON_EXCEPTION, e.getMessage()));
+            return;
+        }
+
+        // store the listener
+        addListener(callbackId, listener);
+    }
+
+    /**
+     * Shuts down all location listeners.
+     */
+    protected synchronized void shutdown() {
+        for (Enumeration listeners = this.geoListeners.elements(); listeners.hasMoreElements(); ) {
+            GeolocationListener listener = (GeolocationListener) listeners.nextElement();
+            listener.shutdown();
+        }
+        this.geoListeners.clear();
+    }
+
+	/**
+	 * Clears the watch for the specified callback id.
+	 * If no more watches exist for the location provider, it is shut down.
+	 * @param callbackId   identifer of the listener to shutdown
+	 */
+    protected void clearWatch(String callbackId) {
+        synchronized(this.geoListeners) {
+            GeolocationListener listener = (GeolocationListener) this.geoListeners.get(callbackId);
+            listener.shutdown();
+            this.geoListeners.remove(callbackId);
+        }
+    }
+
+    /**
+     * Returns a PluginResult with status OK and a JSON object representing the coords
+     * @param callbackId   callback to receive the the result
+     * @param po           position options
+     */
+    protected void getCurrentPosition(String callbackId, PositionOptions options) {
+
+        // Check the device for its last known location (may have come from
+        // another app on the device that has already requested a location).
+        // If it is invalid, old, or inaccurate, attempt to get a new one.
+        Location location = LocationProvider.getLastKnownLocation();
+        if (!isLocationValid(location) || !isLocationFresh(options, location) || !isLocationAccurate(options, location)) {
+            // attempt to retrieve a location provider
+            LocationProvider provider = getLocationProvider(options);
+            if (provider == null) {
+                CordovaExtension.invokeErrorCallback(callbackId,
+                        new GeolocationResult(GeolocationStatus.GPS_NOT_AVAILABLE));
+                return;
+            }
+
+            try {
+                // convert timeout from millis
+                int timeout = (options.timeout > 0) ? options.timeout/1000 : -1;
+                Logger.log(this.getClass().getName() + ": retrieving location with timeout=" + timeout);
+                location = provider.getLocation(timeout);
+            } catch(LocationException e) {
+                Logger.log(this.getClass().getName() + ": " + e.getMessage());
+                provider.reset();
+                CordovaExtension.invokeErrorCallback(callbackId,
+                        new GeolocationResult(GeolocationStatus.GPS_TIMEOUT));
+                return;
+            } catch (InterruptedException e) {
+                Logger.log(this.getClass().getName() + ": " + e.getMessage());
+                provider.reset();
+                CordovaExtension.invokeErrorCallback(callbackId,
+                        new GeolocationResult(GeolocationStatus.GPS_INTERUPTED_EXCEPTION));
+                return;
+            }
+        }
+
+        // send the location back
+        sendLocation(callbackId, location);
+    }
+
+    /**
+     * Converts the location to a geo position and sends result to JavaScript.
+     * @param callbackId   callback to receive position
+     * @param location     location to send
+     */
+    protected void sendLocation(String callbackId, Location location) {
+        // convert the location to a JSON object and return it in the PluginResult
+        JSONObject position = null;
+        try {
+            position = Position.fromLocation(location).toJSONObject();
+        } catch (JSONException e) {
+            CordovaExtension.invokeErrorCallback(callbackId,
+                    new GeolocationResult(PluginResult.Status.JSON_EXCEPTION,
+                    "Converting the location to a JSON object failed"));
+            return;
+        }
+
+        // invoke the geolocation callback
+        CordovaExtension.invokeSuccessCallback(callbackId,
+                new GeolocationResult(GeolocationResult.Status.OK, position));
+    }
+
+	/**
+	 * Returns action to perform.
+	 * @param action
+	 * @return action to perform
+	 */
+	protected static int getAction(String action) {
+		if ("watchPosition".equals(action)) return ACTION_WATCH;
+		if ("stop".equals(action)) return ACTION_CLEAR_WATCH;
+		if ("getCurrentPosition".equals(action)) return ACTION_GET_POSITION;
+		if ("shutdown".endsWith(action)) return ACTION_SHUTDOWN;
+		return -1;
+	}
+
+    /**
+     * Adds a location listener.
+     * @param callbackId    callback to receive listener updates
+     * @param listener      location listener
+     */
+    protected synchronized void addListener(String callbackId, GeolocationListener listener) {
+        this.geoListeners.put(callbackId, listener);
+    }
+
+    /**
+     * Called when Plugin is destroyed.
+     */
+    public void onDestroy() {
+        this.shutdown();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/GeolocationListener.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/GeolocationListener.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/GeolocationListener.java
new file mode 100644
index 0000000..58ef4f0
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/GeolocationListener.java
@@ -0,0 +1,133 @@
+/*
+ * 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.geolocation;
+
+import javax.microedition.location.Location;
+import javax.microedition.location.LocationListener;
+import javax.microedition.location.LocationProvider;
+
+import org.apache.cordova.CordovaExtension;
+import org.apache.cordova.api.PluginResult;
+import org.apache.cordova.json4j.JSONException;
+import org.apache.cordova.json4j.JSONObject;
+import org.apache.cordova.util.Logger;
+
+/**
+ * GeolocationListener listens for update notifications from a LocationProvider.
+ * Provides location update notifications to registered callback.
+ */
+public final class GeolocationListener implements LocationListener {
+
+	private LocationProvider locationProvider;  // location provider the listener listens to
+	private String callbackId;                  // callback that is to be notified on location updates
+
+	/**
+	 * Creates a new listener that attaches itself to the specified LocationProvider.
+	 * @param locationProvider location provider that listener will attach to
+	 * @param callbackId       callback to receive location updates
+	 * @param options          position options
+	 */
+	public GeolocationListener(LocationProvider locationProvider, String callbackId, PositionOptions options) {
+	    this.locationProvider = locationProvider;
+	    this.callbackId = callbackId;
+
+	    // Add this as a location listener to the provider.  Updates are received
+	    // at the specified interval.  This is where it gets confusing:
+	    // the setLocationListener method takes three parameters: interval, timeout,
+	    // and maxAge.  The listener only seems to work if all three are the same
+	    // value, which is probably best, since neither timeout nor maxAge can be
+	    // larger than interval.  Also, the actual timeout to wait for a valid
+	    // location is [interval + timeout]. (I told you it was confusing).
+	    // So, we do the only thing we can do, which is to divide the user timeout
+	    // in half, and set it to the interval and timeout values.  This will give
+	    // us the correct timeout value. BTW, this is exactly what RIM does in
+	    // their HTML5 implementation in the 6.0 browser.  Try it :)
+        int seconds = (options.timeout > 0) ? options.timeout/2000 : 1; // half and convert to millis
+	    this.locationProvider.setLocationListener(this,
+	            seconds,     // interval - seconds between location updates
+	            seconds,     // timeout - additional time to wait for update
+	            seconds);    // maxage - maximum age of location
+	}
+
+    /**
+     * Updated when location changes.
+     */
+    public void locationUpdated(LocationProvider provider, Location location) {
+        if (location.isValid()) {
+            Logger.log(this.getClass().getName() + ": updated with valid location");
+            this.updateLocation(location);
+        } else {
+            // This just means we couldn't get a valid location within the listener interval.
+            Logger.log(this.getClass().getName() + ": updated with invalid location");
+            CordovaExtension.invokeErrorCallback(callbackId,
+                    new GeolocationResult(GeolocationStatus.GPS_TIMEOUT));
+        }
+    }
+
+	/**
+	 * Updated when provider state changes.
+	 */
+    public void providerStateChanged(LocationProvider provider, int newState) {
+        switch (newState) {
+        case LocationProvider.AVAILABLE:
+            Logger.log(this.getClass().getName() + ": provider state changed to AVAILABLE");
+            break;
+        case LocationProvider.OUT_OF_SERVICE:
+            Logger.log(this.getClass().getName() + ": provider state changed to OUT_OF_SERVICE");
+            CordovaExtension.invokeErrorCallback(callbackId,
+                    new GeolocationResult(GeolocationStatus.GPS_OUT_OF_SERVICE));
+            this.shutdown();
+            break;
+        case LocationProvider.TEMPORARILY_UNAVAILABLE:
+            Logger.log(this.getClass().getName() + ": provider state changed to TEMPORARILY_UNAVAILABLE");
+            // This is what happens when you are inside
+            // TODO: explore possible ways to recover
+            CordovaExtension.invokeErrorCallback(callbackId,
+                    new GeolocationResult(GeolocationStatus.GPS_TEMPORARILY_UNAVAILABLE));
+            this.shutdown();
+            break;
+        }
+    }
+
+    /**
+     * Shuts down the listener by resetting the location provider.
+     */
+	public void shutdown() {
+		Logger.log(this.getClass().getName() + ": resetting location provider for callback '" + callbackId + "'");
+		this.locationProvider.setLocationListener(null, 0, 0, 0);
+		this.locationProvider.reset();
+	}
+
+	/**
+	 * Notifies callbacks of location updates.
+	 * @param location updated location
+	 */
+	protected void updateLocation(Location location) {
+		JSONObject position = null;
+		try {
+			position = Position.fromLocation(location).toJSONObject();
+		} catch (JSONException e) {
+			CordovaExtension.invokeErrorCallback(callbackId,
+				new GeolocationResult(PluginResult.Status.JSON_EXCEPTION, "Converting the location to a JSON object failed"));
+		}
+
+		CordovaExtension.invokeSuccessCallback(callbackId,
+			new GeolocationResult(GeolocationStatus.OK, position));
+	}
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/GeolocationResult.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/GeolocationResult.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/GeolocationResult.java
new file mode 100644
index 0000000..9969701
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/GeolocationResult.java
@@ -0,0 +1,73 @@
+/*
+ * 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.geolocation;
+
+import org.apache.cordova.api.PluginResult;
+import org.apache.cordova.json4j.JSONObject;
+import org.apache.cordova.util.Logger;
+
+/**
+ * Extends PluginResult for the purposes of overriding the success and error
+ * callback invocations.
+ */
+public class GeolocationResult extends PluginResult {
+
+	/**
+	 * Constructor.
+	 * @param status
+	 */
+	public GeolocationResult(Status status) {
+		super(status);
+	}
+
+	/**
+	 * Constructor.
+	 * @param status
+	 * @param message
+	 */
+	public GeolocationResult(Status status, String message) {
+		super(status, message);
+	}
+
+	/**
+	 * Constructor.
+	 * @param status
+	 * @param message
+	 */
+	public GeolocationResult(Status status, JSONObject message) {
+		super(status, message);
+	}
+
+	/**
+	 * Produces the invocation string for the specified geolocation success callback.
+	 * @param callbackId callback identifier
+	 */
+	public String toSuccessCallbackString(String callbackId) {
+		Logger.log(this.getClass().getName() + ": invoking success callback: " + callbackId + ", with args: " + this.getJSONString());
+		return "try { navigator.geolocation.success('"+callbackId+"', " + this.getJSONString() + "); } catch(e) { alert('error in success callback:' + e.message); }";
+	}
+
+	/**
+	 * Produces the invocation string for the specified geolocation error callback.
+	 * @param callbackId callback identifier
+	 */
+	public String toErrorCallbackString(String callbackId) {
+		return "try { navigator.geolocation.fail('"+callbackId+"', " + this.getJSONString() + "); } catch(e) { alert('error in error callback:' + e.message); }";
+	}
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/GeolocationStatus.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/GeolocationStatus.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/GeolocationStatus.java
new file mode 100644
index 0000000..4c70a10
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/GeolocationStatus.java
@@ -0,0 +1,36 @@
+/*
+ * 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.geolocation;
+
+import org.apache.cordova.api.PluginResult;
+
+public class GeolocationStatus extends PluginResult.Status {
+
+	protected GeolocationStatus(int status, String message) {
+		super(status, message);
+	}
+
+	public static final GeolocationStatus GPS_NOT_AVAILABLE = new GeolocationStatus(101, "GPS not available");
+	public static final GeolocationStatus GPS_OUT_OF_SERVICE = new GeolocationStatus(102, "GPS out of service");
+	public static final GeolocationStatus GPS_TEMPORARILY_UNAVAILABLE = new GeolocationStatus(103, "GPS temporarily unavailable");
+	public static final GeolocationStatus GPS_TIMEOUT = new GeolocationStatus(104, "GPS location acquisition timed out");
+	public static final GeolocationStatus GPS_INTERUPTED_EXCEPTION = new GeolocationStatus(105, "GPS location acquisition interrupted");
+	public static final GeolocationStatus GPS_INVALID_LOCATION = new GeolocationStatus(106, "GPS returned an invalid location");
+	public static final GeolocationStatus GPS_JSON_EXCEPTION = new GeolocationStatus(107, "An illegal argument was passed to the location listener");
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/Position.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/Position.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/Position.java
new file mode 100644
index 0000000..6ce490e
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/Position.java
@@ -0,0 +1,133 @@
+/*
+ * 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.geolocation;
+
+import javax.microedition.location.Location;
+
+import org.apache.cordova.json4j.JSONException;
+import org.apache.cordova.json4j.JSONObject;
+
+/**
+ * Stores geo location variables.
+ */
+public class Position {
+
+	private double _lat = 0;
+    private double _lng = 0;
+	private float altitude = 0;
+	private float accuracy = 0;
+	private float alt_accuracy = 0;
+    private float heading = 0;
+	private float velocity = 0;
+	private long timestamp = 0;
+
+	public Position(double lat, double lng, float altitude, float accuracy, float alt_accuracy,
+			float heading, float speed, long timestamp) {
+		this._lat = lat;
+		this._lng = lng;
+		this.altitude = altitude;
+		this.accuracy = accuracy;
+		this.alt_accuracy = alt_accuracy;
+		this.heading = heading;
+		this.velocity = speed;
+		this.timestamp = timestamp;
+	}
+
+	public static Position fromLocation(Location location) {
+		double latitude = location.getQualifiedCoordinates().getLatitude();
+        double longitude = location.getQualifiedCoordinates().getLongitude();
+        float altitude = location.getQualifiedCoordinates().getAltitude();
+        float accuracy = location.getQualifiedCoordinates().getHorizontalAccuracy();
+        float alt_accuracy = location.getQualifiedCoordinates().getVerticalAccuracy();
+        float heading = location.getCourse();
+        float speed = location.getSpeed();
+        long time = location.getTimestamp();
+
+		return new Position(latitude, longitude, altitude, accuracy, alt_accuracy, heading, speed, time);
+	}
+
+    public double getLatitude() {
+		return _lat;
+	}
+
+	public void setLatitude(double _lat) {
+		this._lat = _lat;
+	}
+
+	public double getLongitude() {
+		return _lng;
+	}
+
+	public void setLongitude(double _lng) {
+		this._lng = _lng;
+	}
+
+	public float getAltitude() {
+		return altitude;
+	}
+
+	public void setAltitude(float altitude) {
+		this.altitude = altitude;
+	}
+
+	public float getAccuracy() {
+		return accuracy;
+	}
+
+	public void setAccuracy(float accuracy) {
+		this.accuracy = accuracy;
+	}
+
+	public float getAltitudeAccuracy() {
+		return alt_accuracy;
+	}
+
+	public void setAltitudeAccuracy(float alt_accuracy) {
+		this.alt_accuracy = alt_accuracy;
+	}
+
+	public float getHeading() {
+		return heading;
+	}
+
+	public void setHeading(float heading) {
+		this.heading = heading;
+	}
+
+	public float getVelocity() {
+		return velocity;
+	}
+
+	public void setVelocity(float velocity) {
+		this.velocity = velocity;
+	}
+
+	public long getTimestamp() {
+		return timestamp;
+	}
+
+	public void setTimestamp(long timestamp) {
+		this.timestamp = timestamp;
+	}
+
+	public JSONObject toJSONObject() throws JSONException {
+		return new JSONObject("{latitude:" + String.valueOf(_lat) + ", longitude:" + String.valueOf(_lng) + ", altitude:" + altitude + ", accuracy:" + accuracy + ", heading:" + heading + ", speed:" + velocity + ", alt_accuracy:" + alt_accuracy + ", timestamp:" + timestamp + "}");
+	}
+
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/PositionOptions.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/PositionOptions.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/PositionOptions.java
new file mode 100644
index 0000000..85d5853
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/geolocation/PositionOptions.java
@@ -0,0 +1,42 @@
+/*
+ * 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.geolocation;
+
+import org.apache.cordova.json4j.JSONArray;
+import org.apache.cordova.json4j.JSONException;
+
+public class PositionOptions {
+	private static final int START_ARG_MAX_AGE = 1;
+	private static final int START_ARG_TIMEOUT = 2;
+	private static final int START_ARG_HIGH_ACCURACY = 3;
+
+	public int maxAge;
+	public int timeout;
+	public boolean enableHighAccuracy;
+
+	public static PositionOptions fromJSONArray(JSONArray args) throws NumberFormatException, JSONException {
+		PositionOptions po = new PositionOptions();
+
+		po.maxAge = Integer.parseInt(args.getString(START_ARG_MAX_AGE));
+		po.timeout = Integer.parseInt(args.getString(START_ARG_TIMEOUT));
+		po.enableHighAccuracy = args.getBoolean(START_ARG_HIGH_ACCURACY);
+
+		return po;
+	}
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/globalization/Globalization.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/globalization/Globalization.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/globalization/Globalization.java
new file mode 100644
index 0000000..e6aaae5
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/globalization/Globalization.java
@@ -0,0 +1,558 @@
+/*
+ * 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.globalization;
+
+import org.apache.cordova.json4j.JSONArray;
+import org.apache.cordova.json4j.JSONObject;
+
+import org.apache.cordova.api.Plugin;
+import org.apache.cordova.api.PluginResult;
+
+import net.rim.device.api.i18n.Locale;
+import net.rim.device.api.i18n.SimpleDateFormat;
+import net.rim.device.api.util.TimeZoneUtilities;
+import javax.microedition.global.Formatter;
+
+import java.util.Date;
+import java.util.Calendar;
+import java.util.TimeZone;
+import java.lang.Long;
+
+public class Globalization extends Plugin {
+
+    /**
+     * Executes the requested action and returns a PluginResult.
+     *
+     * @param action
+     *            The action to execute.
+     * @param data
+     *            JSONArry of arguments for the action.
+     * @param callbackId
+     *            The callback ID to be invoked upon action completion
+     * @return A PluginResult object with a status and message.
+     */
+    public PluginResult execute(String action, JSONArray data, String callbackId) {
+        JSONObject obj = new JSONObject();
+
+        try {
+            if (action.equals(Resources.GETLOCALENAME)) {
+                obj = getLocaleName();
+            } else if (action.equals(Resources.GETPREFERREDLANGUAGE)) {
+                obj = getPreferredLanguage();
+            } else if (action.equalsIgnoreCase(Resources.DATETOSTRING)) {
+                obj = getDateToString(data);
+            } else if (action.equalsIgnoreCase(Resources.STRINGTODATE)) {
+                obj = getStringToDate(data);
+            } else if (action.equalsIgnoreCase(Resources.GETDATEPATTERN)) {
+                obj = getDatePattern(data);
+            } else if (action.equalsIgnoreCase(Resources.GETDATENAMES)) {
+                obj = getDateNames(data);
+            } else if (action.equalsIgnoreCase(Resources.ISDAYLIGHTSAVINGSTIME)) {
+                obj = getIsDayLightSavingsTime(data);
+            } else if (action.equalsIgnoreCase(Resources.GETFIRSTDAYOFWEEK)) {
+                obj = getFirstDayOfWeek(data);
+            } else if (action.equalsIgnoreCase(Resources.NUMBERTOSTRING)) {
+                obj = getNumberToString(data);
+            } else if (action.equalsIgnoreCase(Resources.STRINGTONUMBER)) {
+                obj = getStringToNumber(data);
+            } else if (action.equalsIgnoreCase(Resources.GETNUMBERPATTERN)) {
+                obj = getNumberPattern(data);
+            } else if (action.equalsIgnoreCase(Resources.GETCURRENCYPATTERN)) {
+                obj = getCurrencyPattern(data);
+            } else {
+                return new PluginResult(PluginResult.Status.INVALID_ACTION);
+            }
+        } catch (GlobalizationError ge) {
+            return new PluginResult(PluginResult.Status.ERROR, ge.toJson());
+        } catch (Exception e) {
+            return new PluginResult(PluginResult.Status.JSON_EXCEPTION);
+        }
+
+        return new PluginResult(PluginResult.Status.OK, obj);
+    }
+
+    /**
+     * Returns the string identifier for the client's current locale setting.
+     *
+     * @return JSONObject Object.value {String}: The locale identifier
+     *
+     * @throws GlobalizationError.UNKNOWN_ERROR
+     */
+    private JSONObject getLocaleName() throws GlobalizationError {
+        JSONObject obj = new JSONObject();
+        try {
+            return obj.put("value", Locale.getDefault().toString());
+        } catch (Exception e) {
+            throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
+        }
+    }
+
+    /**
+     * Returns the string identifier for the client's current language
+     *
+     * @return JSONObject Object.value {String}: The language identifier
+     *
+     * @throws GlobalizationError.UNKNOWN_ERROR
+     */
+    private JSONObject getPreferredLanguage() throws GlobalizationError {
+        JSONObject obj = new JSONObject();
+        try {
+            return obj.put("value", Locale.getDefault().getDisplayLanguage()
+                    .toString());
+        } catch (Exception e) {
+            throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
+        }
+    }
+
+    /**
+     * Returns a date formatted as a string according to the client's user
+     * preferences and calendar using the time zone of the client.
+     *
+     * @return JSONObject Object.value {String}: The localized date string
+     *
+     * @throws GlobalizationError.FORMATTING_ERROR
+     */
+    private JSONObject getDateToString(JSONArray options)
+            throws GlobalizationError {
+        JSONObject obj = new JSONObject();
+        try {
+            Date date = new Date(Long.parseLong(options.getJSONObject(0)
+                    .get(Resources.DATE).toString()));
+            // get formatting pattern from BB device
+            SimpleDateFormat fmt = new SimpleDateFormat(
+                    Util.getBlackBerryDatePattern(options));
+
+            // return formatted date
+            return obj.put("value", fmt.format(date));
+        } catch (Exception ge) {
+            throw new GlobalizationError(GlobalizationError.FORMATTING_ERROR);
+        }
+    }
+
+    /**
+     * Parses a date formatted as a string according to the client's user
+     * preferences and calendar using the time zone of the client and returns
+     * the corresponding date object
+     *
+     * @return JSONObject
+     *          Object.year {Number}: The four digit year
+     *          Object.month {Number}: The month from (0 - 11)
+     *          Object.day {Number}: The day from (1 - 31)
+     *          Object.hour {Number}: The hour from (0 - 23)
+     *          Object.minute {Number}: The minute from (0 - 59)
+     *          Object.second {Number}: The second from (0 - 59)
+     *          Object.millisecond {Number}: The milliseconds (from 0 - 999),
+     *                                      not available on all platforms
+     *
+     * @throws GlobalizationError.PARSING_ERROR
+     */
+    private JSONObject getStringToDate(JSONArray options)
+            throws GlobalizationError {
+        JSONObject obj = new JSONObject();
+        try {
+            // get formatting pattern from BB device
+            SimpleDateFormat fmt = new SimpleDateFormat(
+                    Util.getBlackBerryDatePattern(options));
+
+            // Manually parse string based on user preferences or Locale default
+            String userDate = options.getJSONObject(0)
+                    .get(Resources.DATESTRING).toString().trim();
+
+            Calendar date = Util.dateParserBB(userDate, fmt.toPattern());
+            if (date == null) { // date was unparsable
+                throw new Exception();
+            }
+
+            // return properties;
+            obj.put("year", date.get(Calendar.YEAR));
+            obj.put("month", date.get(Calendar.MONTH)); // returns 0-11
+            obj.put("day", date.get(Calendar.DAY_OF_MONTH));
+            obj.put("hour", date.get(Calendar.HOUR));
+            obj.put("minute", date.get(Calendar.MINUTE));
+            obj.put("second", date.get(Calendar.SECOND));
+            obj.put("millisecond", date.get(Calendar.MILLISECOND));
+            return obj;
+        } catch (Exception ge) {
+            throw new GlobalizationError(GlobalizationError.PARSING_ERROR);
+        }
+    }
+
+    /**
+     * Returns a pattern string for formatting and parsing dates according to
+     * the client's user preferences.
+     *
+     * @return JSONObject
+     *          Object.pattern {String}: The date and time pattern for
+     *                  formatting and parsing dates. The patterns follow
+     *                  Unicode Technical Standard #35
+     *                  http://unicode.org/reports/tr35/tr35-4.html
+     *          Object.timezone {String}: The abbreviated name of the time
+     *                  zone on the client
+     *          Object.utc_offset {Number}: The current difference in seconds
+     *                  between the client's time zon and coordinated universal
+     *                  time.
+     *          Object.dst_offset {Number}: The current daylight saving time
+     *                  offset in seconds between the client's non-daylight
+     *                  saving's time zone and the client's daylight saving's
+     *                  time zone.
+     *
+     * @throws GlobalizationError.PATTERN_ERROR
+     */
+    private JSONObject getDatePattern(JSONArray options)
+            throws GlobalizationError {
+        JSONObject obj = new JSONObject();
+        try {
+            // TimeZone from users device
+            TimeZone tz = Calendar.getInstance().getTimeZone();
+
+            // Daylight
+            boolean daylight = tz.useDaylightTime();
+
+            // set dst_offset
+            int dst_offset = 0; // defaulted to zero
+            if (daylight) {
+                Calendar c = Calendar.getInstance();
+                dst_offset = (tz.getOffset(1, c.get(Calendar.YEAR),
+                        c.get(Calendar.MONTH), c.get(Calendar.DAY_OF_MONTH),
+                        c.get(Calendar.DAY_OF_WEEK),
+                        c.get(Calendar.MILLISECOND))) / 1000;
+            }
+
+            obj.put("pattern", Util.getBlackBerryDatePattern(options));
+            obj.put("timezone", TimeZoneUtilities.getDisplayName(tz,
+                    TimeZoneUtilities.SHORT));
+            obj.put("utc_offset", tz.getRawOffset() / 1000);
+            obj.put("dst_offset", dst_offset);
+            return obj;
+        } catch (Exception ge) {
+            throw new GlobalizationError(GlobalizationError.PATTERN_ERROR);
+        }
+    }
+
+    /**
+     * Returns an array of either the names of the months or days of the week
+     * according to the client's user preferences and calendar
+     *
+     * @return JSONObject
+     *          Object.value {Array{String}}: The array of names starting from
+     *                      either the first month in the year or the first day
+     *                      of the week.
+     *
+     * @throws GlobalizationError.UNKNOWN_ERROR
+     */
+    private JSONObject getDateNames(JSONArray options)
+            throws GlobalizationError {
+        JSONObject obj = new JSONObject();
+        JSONArray value = new JSONArray();
+        try {
+            int type = 0; // default wide
+            int item = 0; // default months
+
+            // get options if available
+            if (options.getJSONObject(0).length() > 0) {
+                // get type if available
+                if (!((JSONObject) options.getJSONObject(0).get(
+                        Resources.OPTIONS)).isNull(Resources.TYPE)) {
+                    String t = (String) ((JSONObject) options.getJSONObject(0)
+                            .get(Resources.OPTIONS)).get(Resources.TYPE);
+                    if (t.equalsIgnoreCase(Resources.NARROW)) {
+                        type++;
+                    } // DateUtils.LENGTH_MEDIUM
+                }
+                // get item if available
+                if (!((JSONObject) options.getJSONObject(0).get(
+                        Resources.OPTIONS)).isNull(Resources.ITEM)) {
+                    String t = (String) ((JSONObject) options.getJSONObject(0)
+                            .get(Resources.OPTIONS)).get(Resources.ITEM);
+                    if (t.equalsIgnoreCase(Resources.DAYS)) {
+                        item += 10;
+                    } // Days of week start at 1
+                }
+            }
+            // determine return value
+
+            int method = item + type;
+            if (method == 1) {
+                value = Util.getDateNameString(Resources.MONTHS, "MMM");
+            }// months and narrow
+            else if (method == 10) {
+                value = Util.getDateNameString(Resources.DAYS, "EEEE");
+            }// days and wide
+            else if (method == 11) {
+                value = Util.getDateNameString(Resources.DAYS, "EEE");
+            }// days and narrow
+            else {
+                value = Util.getDateNameString(Resources.MONTHS, "MMMM");
+            }// default: months and wide
+
+            if (value == null) {
+                throw new Exception();
+            }
+
+            // return array of names
+            return obj.put("value", value);
+        } catch (Exception ge) {
+            throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
+        }
+    }
+
+    /**
+     * Returns whether daylight savings time is in effect for a given date using
+     * the client's time zone and calendar.
+     *
+     * @return JSONObject
+     *          Object.dst {Boolean}: The value "true" indicates that daylight
+     *                      savings time is in effect for the given date and
+     *                      "false" indicates that it is not.
+     *
+     * @throws GlobalizationError.UNKNOWN_ERROR
+     *
+     *             Note: Functionality to determine if date is within day light
+     *             savings time is not available in this API version
+     */
+    private JSONObject getIsDayLightSavingsTime(JSONArray options)
+            throws GlobalizationError {
+        throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
+    }
+
+    /**
+     * Returns the first day of the week according to the client's user
+     * preferences and calendar. The days of the week are numbered starting from
+     * 1 where 1 is considered to be Sunday.
+     *
+     * @return JSONObject
+     *          Object.value {Number}: The number of the first day of the week.
+     *
+     * @throws GlobalizationError.UNKNOWN_ERROR
+     */
+    private JSONObject getFirstDayOfWeek(JSONArray options)
+            throws GlobalizationError {
+        JSONObject obj = new JSONObject();
+        try {
+            JSONObject result = Util.getLocaleData(Locale.getDefault()
+                    .toString());
+
+            if (result == null || result.length() <= 0) {
+                throw new Exception();
+            }
+            return obj.put("value", Integer.valueOf(result
+                    .getString(Resources.JSON_FIRISTDAYOFWEEK)));
+        } catch (Exception e) {
+            throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
+        }
+    }
+
+    /**
+     * Returns a number formatted as a string according to the client's user
+     * preferences.
+     *
+     * @return JSONObject
+     *          Object.value {String}: The formatted number string.
+     *
+     * @throws GlobalizationError.FORMATTING_ERROR
+     */
+    private JSONObject getNumberToString(JSONArray options)
+            throws GlobalizationError {
+        JSONObject obj = new JSONObject();
+        String value;
+        try {
+            // Initialize formatter
+            Formatter fmt = new Formatter(Locale.getDefault().toString());
+
+            // obtain user supplied number
+            double num = Double.parseDouble(options.getJSONObject(0)
+                    .get(Resources.NUMBER).toString());
+            // format based on options if available
+            value = fmt.formatNumber(num);
+            if (options.getJSONObject(0).length() > 1) {
+                // options were included
+                if (!((JSONObject) options.getJSONObject(0).get(
+                        Resources.OPTIONS)).isNull(Resources.TYPE)) {
+                    String fmtOpt = (String) ((JSONObject) options
+                            .getJSONObject(0).get(Resources.OPTIONS))
+                            .get(Resources.TYPE);
+                    if (fmtOpt.equalsIgnoreCase(Resources.CURRENCY)) {
+                        value = fmt.formatCurrency(num);
+                    } else if (fmtOpt.equalsIgnoreCase(Resources.PERCENT)) {
+                        // convert double to long
+                        // used 1 decimal places as a default
+                        value = fmt.formatPercentage((float) num, 1);
+                    }
+                }
+            }
+            return obj.put("value", value);
+        } catch (Exception ge) {
+            throw new GlobalizationError(GlobalizationError.FORMATTING_ERROR);
+        }
+
+    }
+
+    /**
+     * Parses a number formatted as a string according to the client's user
+     * preferences and returns the corresponding number.
+     *
+     * @return JSONObject
+     *          Object.value {Number}: The parsed number.
+     *
+     * @throws GlobalizationError.PARSING_ERROR
+     */
+    private JSONObject getStringToNumber(JSONArray options)
+            throws GlobalizationError {
+        JSONObject obj = new JSONObject();
+        double value = 0;
+        try {
+            // format based on options if available
+            String num = options.getJSONObject(0).get(Resources.NUMBERSTRING)
+                    .toString().trim();
+            if (options.getJSONObject(0).length() > 1) {
+                // options were included
+                if (!((JSONObject) options.getJSONObject(0).get(
+                        Resources.OPTIONS)).isNull(Resources.TYPE)) {
+                    String fmtOpt = (String) ((JSONObject) options
+                            .getJSONObject(0).get(Resources.OPTIONS))
+                            .get(Resources.TYPE);
+                    // remove unwanted symbols
+                    if (fmtOpt.equalsIgnoreCase(Resources.CURRENCY)) {
+                        value = (Double.parseDouble(Util.removeSymbols(num)));
+                    } else if (fmtOpt.equalsIgnoreCase(Resources.PERCENT)) {
+                        value = (Double.parseDouble(Util.removeSymbols(num)) / 100);
+                    }
+                }
+            } else {
+                value = Double.parseDouble(num); // decimal default
+            }
+
+            return obj.put("value", value);
+        } catch (Exception ge) {
+            throw new GlobalizationError(GlobalizationError.PARSING_ERROR);
+        }
+    }
+
+    /**
+     * Returns a pattern string for formatting and parsing numbers according to
+     * the client's user preferences.
+     *
+     * @return JSONObject
+     *          Object.pattern {String}: The number pattern for formatting and
+     *                      parsing numbers. The patterns follow Unicode
+     *                      Technical Standard #35.
+     *                      http://unicode.org/reports/tr35/tr35-4.html
+     *          Object.symbol {String}: The symbol to be used when formatting
+     *                      and parsing e.g., percent or currency symbol.
+     *          Object.fraction {Number}: The number of fractional digits to use
+     *                      when parsing and formatting numbers.
+     *          Object.rounding {Number}: The rounding increment to use when
+     *                      parsing and formatting.
+     *          Object.positive {String}: The symbol to use for positive numbers
+     *                      when parsing and formatting.
+     *          Object.negative: {String}: The symbol to use for negative
+     *                      numbers when parsing and formatting.
+     *          Object.decimal: {String}: The decimal symbol to use for parsing
+     *                      and formatting.
+     *          Object.grouping: {String}: The grouping symbol to use for
+     *                      parsing and formatting.
+     *
+     * @throws GlobalizationError.PATTERN_ERROR
+     */
+    private JSONObject getNumberPattern(JSONArray options)
+            throws GlobalizationError {
+        JSONObject obj = new JSONObject();
+        try {
+            JSONObject result = Util.getLocaleData(Locale.getDefault()
+                    .toString());
+
+            String symbol = Resources.JSON_DECIMALSYMBOL;
+            // get Date value + options (if available)
+            if (options.getJSONObject(0).length() > 0) {
+                // options were included
+                if (!((JSONObject) options.getJSONObject(0).get(
+                        Resources.OPTIONS)).isNull(Resources.TYPE)) {
+                    String fmtOpt = (String) ((JSONObject) options
+                            .getJSONObject(0).get(Resources.OPTIONS))
+                            .get(Resources.TYPE);
+                    if (fmtOpt.equalsIgnoreCase(Resources.CURRENCY)) {
+                        symbol = Resources.JSON_CURRENCYSYMBOL;
+                    } else if (fmtOpt.equalsIgnoreCase(Resources.PERCENT)) {
+                        symbol = Resources.JSON_PERCENTSYMBOL;
+                    }
+                }
+            }
+
+            // return properties
+            obj.put("pattern", result.getString(Resources.JSON_PATTERN));
+            obj.put("symbol", result.getString(symbol));
+            obj.put("fraction",
+                    Integer.valueOf(result.getString(Resources.JSON_FRACTION)));
+            obj.put("rounding",
+                    Integer.valueOf(result.getString(Resources.JSON_ROUNDING)));
+            obj.put("positive", result.getString(Resources.JSON_POSITIVE));
+            obj.put("negative", result.getString(Resources.JSON_NEGATIVE));
+            obj.put("decimal", result.getString(Resources.JSON_DECIMALSYMBOL));
+            obj.put("grouping", result.getString(Resources.JSON_GROUPING));
+            return obj;
+        } catch (Exception ge) {
+            throw new GlobalizationError(GlobalizationError.PATTERN_ERROR);
+        }
+    }
+
+    /**
+     * Returns a pattern string for formatting and parsing currency values
+     * according to the client's user preferences and ISO 4217 currency code.
+     *
+     * @return JSONObject =
+     *          Object.pattern {String}: The currency pattern for formatting and
+     *                      parsing currency values. The patterns follow
+     *                      Unicode Technical Standard #35
+     *                      http://unicode.org/reports/tr35/tr35-4.html
+     *          Object.code {String}: The ISO 4217 currency code for the pattern.
+     *          Object.fraction {Number}: The number of fractional digits to use
+     *                      when parsing and formatting currency.
+     *          Object.rounding {Number}: The rounding increment to use when
+     *                      parsing and formatting.
+     *          Object.decimal: {String}: The decimal symbol to use for parsing
+     *                      and formatting.
+     *          Object.grouping: {String}: The grouping symbol to use for
+     *                      parsing and formatting.
+     *
+     * @throws GlobalizationError.FORMATTING_ERROR
+     */
+    private JSONObject getCurrencyPattern(JSONArray options)
+            throws GlobalizationError {
+        JSONObject obj = new JSONObject();
+        try {
+            JSONObject result = Util.getCurrencyData(Locale.getDefault()
+                    .toString(),
+                    options.getJSONObject(0).getString(Resources.CURRENCYCODE));
+
+            // return properties
+            obj.put("pattern", result.getString(Resources.JSON_CURRENCYPATTERN));
+            obj.put("code", result.getString(Resources.JSON_CURRENCYCODE));
+            obj.put("fraction", Integer.valueOf(result
+                    .getString(Resources.JSON_CURRENCYFRACTION)));
+            obj.put("rounding", Integer.valueOf(result
+                    .getString(Resources.JSON_CURRENCYROUNDING)));
+            obj.put("decimal", result.getString(Resources.JSON_CURRENCYDECIMAL));
+            obj.put("grouping",
+                    result.getString(Resources.JSON_CURRENCYGROUPING));
+            return obj;
+        } catch (Exception ge) {
+            throw new GlobalizationError(GlobalizationError.FORMATTING_ERROR);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/globalization/GlobalizationError.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/globalization/GlobalizationError.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/globalization/GlobalizationError.java
new file mode 100644
index 0000000..b2a9388
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/globalization/GlobalizationError.java
@@ -0,0 +1,115 @@
+/*
+ * 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.globalization;
+
+import org.apache.cordova.json4j.JSONException;
+import org.apache.cordova.json4j.JSONObject;
+
+/**
+ * User initiated exception. Exception class representing defined Globalization
+ * error codes.
+ *
+ * Globalization error codes:
+ *          GlobalizationError.UNKNOWN_ERROR = 0;
+ *          GlobalizationError.FORMATTING_ERROR = 1;
+ *          GlobalizationError.PARSING_ERROR = 2;
+ *          GlobalizationError.PATTERN_ERROR = 3;
+ */
+public class GlobalizationError extends Exception {
+
+    private static final long serialVersionUID = 1L;
+    public static final String UNKNOWN_ERROR = "UNKNOWN_ERROR";
+    public static final String FORMATTING_ERROR = "FORMATTING_ERROR";
+    public static final String PARSING_ERROR = "PARSING_ERROR";
+    public static final String PATTERN_ERROR = "PATTERN_ERROR";
+
+    int error = 0; // default unknown error thrown
+
+    /**
+     * Default constructor
+     */
+    public GlobalizationError() {
+    }
+
+    /**
+     * Create an exception returning an error code
+     *
+     * @param s
+     */
+    public GlobalizationError(String s) {
+        if (s.equalsIgnoreCase(FORMATTING_ERROR)) {
+            error = 1;
+        } else if (s.equalsIgnoreCase(PARSING_ERROR)) {
+            error = 2;
+        } else if (s.equalsIgnoreCase(PATTERN_ERROR)) {
+            error = 3;
+        }
+    }
+
+    /**
+     * get error string based on error code
+     *
+     * @param String
+     *            msg
+     */
+    public String getErrorString() {
+        String msg = "";
+        switch (error) {
+        case 0:
+            msg = UNKNOWN_ERROR;
+            break;
+        case 1:
+            msg = FORMATTING_ERROR;
+            break;
+        case 2:
+            msg = PARSING_ERROR;
+            break;
+        case 3:
+            msg = PATTERN_ERROR;
+            break;
+        }
+        return msg;
+    }
+
+    /**
+     * get error code
+     *
+     * @param String
+     *            msg
+     */
+    public int getErrorCode() {
+        return error;
+    }
+
+    /**
+     * get the json version of this object to return to javascript
+     *
+     * @return
+     */
+    public JSONObject toJson() {
+        JSONObject obj = new JSONObject();
+        try {
+            obj.put("code", getErrorCode());
+            obj.put("message", getErrorString());
+        } catch (JSONException e) {
+            // never happens
+        }
+        return obj;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-cli/blob/d61deccd/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/globalization/Resources.java
----------------------------------------------------------------------
diff --git a/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/globalization/Resources.java b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/globalization/Resources.java
new file mode 100644
index 0000000..02cbc8a
--- /dev/null
+++ b/lib/cordova-blackberry/framework/ext/src/org/apache/cordova/globalization/Resources.java
@@ -0,0 +1,99 @@
+/*
+ * 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.globalization;
+
+public class Resources {
+    // Globalization Plugin Actions
+    public static final String GETLOCALENAME = "getLocaleName";
+    public static final String DATETOSTRING = "dateToString";
+    public static final String STRINGTODATE = "stringToDate";
+    public static final String GETDATEPATTERN = "getDatePattern";
+    public static final String GETDATENAMES = "getDateNames";
+    public static final String ISDAYLIGHTSAVINGSTIME = "isDayLightSavingsTime";
+    public static final String GETFIRSTDAYOFWEEK = "getFirstDayOfWeek";
+    public static final String NUMBERTOSTRING = "numberToString";
+    public static final String STRINGTONUMBER = "stringToNumber";
+    public static final String GETNUMBERPATTERN = "getNumberPattern";
+    public static final String GETCURRENCYPATTERN = "getCurrencyPattern";
+    public static final String GETPREFERREDLANGUAGE = "getPreferredLanguage";
+
+    // Globalization Option Parameters
+    public static final String OPTIONS = "options";
+    public static final String FORMATLENGTH = "formatLength";
+    public static final String MEDIUM = "medium";
+    public static final String LONG = "long";
+    public static final String FULL = "full";
+    public static final String SELECTOR = "selector";
+    public static final String DATE = "date";
+    public static final String TIME = "time";
+    public static final String DATESTRING = "dateString";
+    public static final String TYPE = "type";
+    public static final String ITEM = "item";
+    public static final String NARROW = "narrow";
+    public static final String WIDE = "wide";
+    public static final String MONTHS = "months";
+    public static final String DAYS = "days";
+    public static final String SPACE = " ";
+    public static final String DATEDELIMITER = "-";
+    public static final String TIMEDELIMITER = ":";
+    public static final String[] AM_PMFORMATS = { "a", "aa" };
+    public static final String NUMBER = "number";
+    public static final String NUMBERSTRING = "numberString";
+    public static final String PERCENT = "percent";
+    public static final String CURRENCY = "currency";
+    public static final String CURRENCYCODE = "currencyCode";
+
+    // JSON File: JSONObject
+    public static final String JSON_CURRENCY = "currency";
+    public static final String JSON_LOCALE = "locale";
+    public static final String JSON_NAME = "name";
+
+    // JSON File: parameters
+    // locale:
+    public static final String JSON_PATTERN = "pattern";
+    public static final String JSON_DECIMAL = "decimal";
+    public static final String JSON_FRACTION = "fraction";
+    public static final String JSON_ROUNDING = "rounding";
+    public static final String JSON_GROUPING = "grouping";
+    public static final String JSON_NEGATIVE = "negative";
+    public static final String JSON_FIRISTDAYOFWEEK = "firstDayOfWeek";
+    public static final String JSON_POSITIVE = "positive";
+    public static final String JSON_PERCENTSYMBOL = "percentSymbol";
+    public static final String JSON_CURRENCYSYMBOL = "currencySymbol";
+    public static final String JSON_DECIMALSYMBOL = "decimalSymbol";
+    public static final String JSON_DISPLAYNAME = "displayName";
+
+    // currency
+    public static final String JSON_CURRENCYCODE = "currencyCode";
+    public static final String JSON_CURRENCYPATTERN = "currencyPattern";
+    public static final String JSON_CURRENCYDECIMAL = "currencyDecimal";
+    public static final String JSON_CURRENCYFRACTION = "currencyFraction";
+    public static final String JSON_CURRENCYGROUPING = "currencyGrouping";
+    public static final String JSON_CURRENCYROUNDING = "currencyRounding";
+
+    // class paths:
+    public static final String LOCALEINFOPATH = "/res/resourceBundles/";
+    public static final String LOCALEINFOPATHEND = ".js.gz";
+
+    // locale resource key identifiers
+    public static final int LOCALENAME = 0;
+
+    // Persistent Store ID:
+    public static final long PERSISTENTSTORE_ID = 0x10001;
+}