You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by pm...@apache.org on 2012/03/21 20:00:23 UTC

[3/4] initial pass at reorganizing the lib directory

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/android/cordova/plugin/android/device.js
----------------------------------------------------------------------
diff --git a/lib-platforms/android/cordova/plugin/android/device.js b/lib-platforms/android/cordova/plugin/android/device.js
new file mode 100644
index 0000000..1defbbe
--- /dev/null
+++ b/lib-platforms/android/cordova/plugin/android/device.js
@@ -0,0 +1,92 @@
+var channel = require('cordova/channel'),
+    exec = require('cordova/exec');
+
+/**
+ * This represents the mobile device, and provides properties for inspecting the model, version, UUID of the
+ * phone, etc.
+ * @constructor
+ */
+function Device() {
+    this.available = false;
+    this.platform = null;
+    this.version = null;
+    this.name = null;
+    this.uuid = null;
+    this.cordova = null;
+
+    var me = this;
+    this.getInfo(
+        function(info) {
+            me.available = true;
+            me.platform = info.platform;
+            me.version = info.version;
+            me.name = info.name;
+            me.uuid = info.uuid;
+            me.cordova = info.cordova;
+            channel.onCordovaInfoReady.fire();
+        },
+        function(e) {
+            me.available = false;
+            console.log("Error initializing Cordova: " + e);
+            alert("Error initializing Cordova: "+e);
+        });
+}
+
+/**
+ * Get device info
+ *
+ * @param {Function} successCallback The function to call when the heading data is available
+ * @param {Function} errorCallback The function to call when there is an error getting the heading data. (OPTIONAL)
+ */
+Device.prototype.getInfo = function(successCallback, errorCallback) {
+
+    // successCallback required
+    if (typeof successCallback !== "function") {
+        console.log("Device Error: successCallback is not a function");
+        return;
+    }
+
+    // errorCallback optional
+    if (errorCallback && (typeof errorCallback !== "function")) {
+        console.log("Device Error: errorCallback is not a function");
+        return;
+    }
+
+    // Get info
+    exec(successCallback, errorCallback, "Device", "getDeviceInfo", []);
+};
+
+/*
+ * DEPRECATED
+ * This is only for Android.
+ *
+ * You must explicitly override the back button.
+ */
+Device.prototype.overrideBackButton = function() {
+	console.log("Device.overrideBackButton() is deprecated.  Use App.overrideBackbutton(true).");
+	navigator.app.overrideBackbutton(true);
+};
+
+/*
+ * DEPRECATED
+ * This is only for Android.
+ *
+ * This resets the back button to the default behaviour
+ */
+Device.prototype.resetBackButton = function() {
+	console.log("Device.resetBackButton() is deprecated.  Use App.overrideBackbutton(false).");
+	navigator.app.overrideBackbutton(false);
+};
+
+/*
+ * DEPRECATED
+ * This is only for Android.
+ *
+ * This terminates the activity!
+ */
+Device.prototype.exitApp = function() {
+	console.log("Device.exitApp() is deprecated.  Use App.exitApp().");
+	navigator.app.exitApp();
+};
+
+module.exports = new Device();

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/android/cordova/plugin/android/polling.js
----------------------------------------------------------------------
diff --git a/lib-platforms/android/cordova/plugin/android/polling.js b/lib-platforms/android/cordova/plugin/android/polling.js
new file mode 100644
index 0000000..36b8e86
--- /dev/null
+++ b/lib-platforms/android/cordova/plugin/android/polling.js
@@ -0,0 +1,33 @@
+var cordova = require('cordova'),
+    period = 50,
+    polling = function() {
+      // Exit if shutting down app
+      if (cordova.shuttingDown) {
+          return;
+      }
+
+      // If polling flag was changed, stop using polling from now on and switch to XHR server / callback
+      if (!cordova.UsePolling) {
+          require('cordova/plugin/android/callback')();
+          return;
+      }
+
+      var msg = prompt("", "gap_poll:");
+      if (msg) {
+          setTimeout(function() {
+              try {
+                  var t = eval(""+msg);
+              }
+              catch (e) {
+                  console.log("JSCallbackPolling: Message from Server: " + msg);
+                  console.log("JSCallbackPolling Error: "+e);
+              }
+          }, 1);
+          setTimeout(polling, 1);
+      }
+      else {
+          setTimeout(polling, period);
+      }
+};
+
+module.exports = polling;

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/android/cordova/plugin/android/storage.js
----------------------------------------------------------------------
diff --git a/lib-platforms/android/cordova/plugin/android/storage.js b/lib-platforms/android/cordova/plugin/android/storage.js
new file mode 100644
index 0000000..000612b
--- /dev/null
+++ b/lib-platforms/android/cordova/plugin/android/storage.js
@@ -0,0 +1,377 @@
+var utils = require('cordova/utils'),
+    exec = require('cordova/exec');
+    channel = require('cordova/channel');
+
+var queryQueue = {};
+
+/**
+ * SQL result set object
+ * PRIVATE METHOD
+ * @constructor
+ */
+var DroidDB_Rows = function() {
+    this.resultSet = [];    // results array
+    this.length = 0;        // number of rows
+};
+
+/**
+ * Get item from SQL result set
+ *
+ * @param row           The row number to return
+ * @return              The row object
+ */
+DroidDB_Rows.prototype.item = function(row) {
+    return this.resultSet[row];
+};
+
+/**
+ * SQL result set that is returned to user.
+ * PRIVATE METHOD
+ * @constructor
+ */
+var DroidDB_Result = function() {
+    this.rows = new DroidDB_Rows();
+};
+
+/**
+ * Callback from native code when query is complete.
+ * PRIVATE METHOD
+ *
+ * @param id   Query id
+ */
+function completeQuery(id, data) {
+    var query = queryQueue[id];
+    if (query) {
+        try {
+            delete queryQueue[id];
+
+            // Get transaction
+            var tx = query.tx;
+
+            // If transaction hasn't failed
+            // Note: We ignore all query results if previous query
+            //       in the same transaction failed.
+            if (tx && tx.queryList[id]) {
+
+                // Save query results
+                var r = new DroidDB_Result();
+                r.rows.resultSet = data;
+                r.rows.length = data.length;
+                try {
+                    if (typeof query.successCallback === 'function') {
+                        query.successCallback(query.tx, r);
+                    }
+                } catch (ex) {
+                    console.log("executeSql error calling user success callback: "+ex);
+                }
+
+                tx.queryComplete(id);
+            }
+        } catch (e) {
+            console.log("executeSql error: "+e);
+        }
+    }
+}
+
+/**
+ * Callback from native code when query fails
+ * PRIVATE METHOD
+ *
+ * @param reason            Error message
+ * @param id                Query id
+ */
+function failQuery(reason, id) {
+    var query = queryQueue[id];
+    if (query) {
+        try {
+            delete queryQueue[id];
+
+            // Get transaction
+            var tx = query.tx;
+
+            // If transaction hasn't failed
+            // Note: We ignore all query results if previous query
+            //       in the same transaction failed.
+            if (tx && tx.queryList[id]) {
+                tx.queryList = {};
+
+                try {
+                    if (typeof query.errorCallback === 'function') {
+                        query.errorCallback(query.tx, reason);
+                    }
+                } catch (ex) {
+                    console.log("executeSql error calling user error callback: "+ex);
+                }
+
+                tx.queryFailed(id, reason);
+            }
+
+        } catch (e) {
+            console.log("executeSql error: "+e);
+        }
+    }
+}
+
+/**
+ * SQL query object
+ * PRIVATE METHOD
+ *
+ * @constructor
+ * @param tx                The transaction object that this query belongs to
+ */
+var DroidDB_Query = function(tx) {
+
+    // Set the id of the query
+    this.id = utils.createUUID();
+
+    // Add this query to the queue
+    queryQueue[this.id] = this;
+
+    // Init result
+    this.resultSet = [];
+
+    // Set transaction that this query belongs to
+    this.tx = tx;
+
+    // Add this query to transaction list
+    this.tx.queryList[this.id] = this;
+
+    // Callbacks
+    this.successCallback = null;
+    this.errorCallback = null;
+
+};
+
+/**
+ * Transaction object
+ * PRIVATE METHOD
+ * @constructor
+ */
+var DroidDB_Tx = function() {
+
+    // Set the id of the transaction
+    this.id = utils.createUUID();
+
+    // Callbacks
+    this.successCallback = null;
+    this.errorCallback = null;
+
+    // Query list
+    this.queryList = {};
+};
+
+/**
+ * Mark query in transaction as complete.
+ * If all queries are complete, call the user's transaction success callback.
+ *
+ * @param id                Query id
+ */
+DroidDB_Tx.prototype.queryComplete = function(id) {
+    delete this.queryList[id];
+
+    // If no more outstanding queries, then fire transaction success
+    if (this.successCallback) {
+        var count = 0;
+        var i;
+        for (i in this.queryList) {
+            if (this.queryList.hasOwnProperty(i)) {
+                count++;
+            }
+        }
+        if (count === 0) {
+            try {
+                this.successCallback();
+            } catch(e) {
+                console.log("Transaction error calling user success callback: " + e);
+            }
+        }
+    }
+};
+
+/**
+ * Mark query in transaction as failed.
+ *
+ * @param id                Query id
+ * @param reason            Error message
+ */
+DroidDB_Tx.prototype.queryFailed = function(id, reason) {
+
+    // The sql queries in this transaction have already been run, since
+    // we really don't have a real transaction implemented in native code.
+    // However, the user callbacks for the remaining sql queries in transaction
+    // will not be called.
+    this.queryList = {};
+
+    if (this.errorCallback) {
+        try {
+            this.errorCallback(reason);
+        } catch(e) {
+            console.log("Transaction error calling user error callback: " + e);
+        }
+    }
+};
+
+/**
+ * Execute SQL statement
+ *
+ * @param sql                   SQL statement to execute
+ * @param params                Statement parameters
+ * @param successCallback       Success callback
+ * @param errorCallback         Error callback
+ */
+DroidDB_Tx.prototype.executeSql = function(sql, params, successCallback, errorCallback) {
+
+    // Init params array
+    if (typeof params === 'undefined') {
+        params = [];
+    }
+
+    // Create query and add to queue
+    var query = new DroidDB_Query(this);
+    queryQueue[query.id] = query;
+
+    // Save callbacks
+    query.successCallback = successCallback;
+    query.errorCallback = errorCallback;
+
+    // Call native code
+    exec(null, null, "Storage", "executeSql", [sql, params, query.id]);
+};
+
+var DatabaseShell = function() {
+};
+
+/**
+ * Start a transaction.
+ * Does not support rollback in event of failure.
+ *
+ * @param process {Function}            The transaction function
+ * @param successCallback {Function}
+ * @param errorCallback {Function}
+ */
+DatabaseShell.prototype.transaction = function(process, errorCallback, successCallback) {
+    var tx = new DroidDB_Tx();
+    tx.successCallback = successCallback;
+    tx.errorCallback = errorCallback;
+    try {
+        process(tx);
+    } catch (e) {
+        console.log("Transaction error: "+e);
+        if (tx.errorCallback) {
+            try {
+                tx.errorCallback(e);
+            } catch (ex) {
+                console.log("Transaction error calling user error callback: "+e);
+            }
+        }
+    }
+};
+
+/**
+ * Open database
+ *
+ * @param name              Database name
+ * @param version           Database version
+ * @param display_name      Database display name
+ * @param size              Database size in bytes
+ * @return                  Database object
+ */
+var DroidDB_openDatabase = function(name, version, display_name, size) {
+    exec(null, null, "Storage", "openDatabase", [name, version, display_name, size]);
+    var db = new DatabaseShell();
+    return db;
+};
+
+/**
+ * For browsers with no localStorage we emulate it with SQLite. Follows the w3c api.
+ * TODO: Do similar for sessionStorage.
+ * @constructor
+ */
+var CupcakeLocalStorage = function() {
+    channel.waitForInitialization("cupcakeStorage");
+
+    try {
+
+      this.db = openDatabase('localStorage', '1.0', 'localStorage', 2621440);
+      var storage = {};
+      this.length = 0;
+      function setLength (length) {
+        this.length = length;
+        localStorage.length = length;
+      }
+      this.db.transaction(
+        function (transaction) {
+            var i;
+          transaction.executeSql('CREATE TABLE IF NOT EXISTS storage (id NVARCHAR(40) PRIMARY KEY, body NVARCHAR(255))');
+          transaction.executeSql('SELECT * FROM storage', [], function(tx, result) {
+            for(var i = 0; i < result.rows.length; i++) {
+              storage[result.rows.item(i)['id']] =  result.rows.item(i)['body'];
+            }
+            setLength(result.rows.length);
+            channel.initializationComplete("cupcakeStorage");
+          });
+
+        },
+        function (err) {
+          alert(err.message);
+        }
+      );
+      this.setItem = function(key, val) {
+        if (typeof(storage[key])=='undefined') {
+          this.length++;
+        }
+        storage[key] = val;
+        this.db.transaction(
+          function (transaction) {
+            transaction.executeSql('CREATE TABLE IF NOT EXISTS storage (id NVARCHAR(40) PRIMARY KEY, body NVARCHAR(255))');
+            transaction.executeSql('REPLACE INTO storage (id, body) values(?,?)', [key,val]);
+          }
+        );
+      };
+      this.getItem = function(key) {
+        return storage[key];
+      };
+      this.removeItem = function(key) {
+        delete storage[key];
+        this.length--;
+        this.db.transaction(
+          function (transaction) {
+            transaction.executeSql('CREATE TABLE IF NOT EXISTS storage (id NVARCHAR(40) PRIMARY KEY, body NVARCHAR(255))');
+            transaction.executeSql('DELETE FROM storage where id=?', [key]);
+          }
+        );
+      };
+      this.clear = function() {
+        storage = {};
+        this.length = 0;
+        this.db.transaction(
+          function (transaction) {
+            transaction.executeSql('CREATE TABLE IF NOT EXISTS storage (id NVARCHAR(40) PRIMARY KEY, body NVARCHAR(255))');
+            transaction.executeSql('DELETE FROM storage', []);
+          }
+        );
+      };
+      this.key = function(index) {
+        var i = 0;
+        for (var j in storage) {
+          if (i==index) {
+            return j;
+          } else {
+            i++;
+          }
+        }
+        return null;
+      };
+
+    } catch(e) {
+      alert("Database error "+e+".");
+        return;
+    }
+};
+
+module.exports = {
+  openDatabase:DroidDB_openDatabase,
+  CupcakeLocalStorage:CupcakeLocalStorage,
+  failQuery:failQuery,
+  completeQuery:completeQuery
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/blackberry/cordova/exec.js
----------------------------------------------------------------------
diff --git a/lib-platforms/blackberry/cordova/exec.js b/lib-platforms/blackberry/cordova/exec.js
new file mode 100644
index 0000000..a5fb81f
--- /dev/null
+++ b/lib-platforms/blackberry/cordova/exec.js
@@ -0,0 +1,56 @@
+/**
+ * Execute a cordova command.  It is up to the native side whether this action
+ * is synchronous or asynchronous.  The native side can return:
+ *      Synchronous: PluginResult object as a JSON string
+ *      Asynchrounous: Empty string ""
+ * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
+ * depending upon the result of the action.
+ *
+ * @param {Function} success    The success callback
+ * @param {Function} fail       The fail callback
+ * @param {String} service      The name of the service to use
+ * @param {String} action       Action to be run in cordova
+ * @param {String[]} [args]     Zero or more arguments to pass to the method
+ */
+var blackberry = require('cordova/plugin/blackberry/manager'),
+    cordova = require('cordova');
+
+module.exports = function(success, fail, service, action, args) {
+    try {
+        var v = blackberry.exec(success, fail, service, action, args);
+
+        // If status is OK, then return value back to caller
+        if (v.status == cordova.callbackStatus.OK) {
+
+            // If there is a success callback, then call it now with returned value
+            if (success) {
+                try {
+                    success(v.message);
+                }
+                catch (e) {
+                    console.log("Error in success callback: "+ service + "." + action + " = "+e);
+                }
+
+            }
+            return v.message;
+        } else if (v.status == cordova.callbackStatus.NO_RESULT) {
+
+        } else {
+            // If error, then display error
+            console.log("Error: " + service + "." + action + " Status="+v.status+" Message="+v.message);
+
+            // If there is a fail callback, then call it now with returned value
+            if (fail) {
+                try {
+                    fail(v.message);
+                }
+                catch (e) {
+                    console.log("Error in error callback: " + service + "." + action + " = "+e);
+                }
+            }
+            return null;
+        }
+    } catch (e) {
+        alert("Error: "+e);
+    }
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/blackberry/cordova/platform.js
----------------------------------------------------------------------
diff --git a/lib-platforms/blackberry/cordova/platform.js b/lib-platforms/blackberry/cordova/platform.js
new file mode 100644
index 0000000..e7fa2e3
--- /dev/null
+++ b/lib-platforms/blackberry/cordova/platform.js
@@ -0,0 +1,173 @@
+module.exports = {
+    id: "blackberry",
+    initialize:function() {
+        var cordova = require('cordova'),
+            exec = require('cordova/exec'),
+            channel = require('cordova/channel'),
+            blackberryManager = require('cordova/plugin/blackberry/manager'),
+            app = require('cordova/plugin/blackberry/app');
+
+        // BB OS 5 does not define window.console.
+        if (typeof window.console === 'undefined') {
+            window.console = {};
+        }
+
+        // Override console.log with native logging ability.
+        // BB OS 7 devices define console.log for use with web inspector
+        // debugging. If console.log is already defined, invoke it in addition
+        // to native logging.
+        var origLog = window.console.log;
+        window.console.log = function(msg) {
+            if (typeof origLog === 'function') {
+                origLog.call(window.console, msg);
+            }
+            org.apache.cordova.Logger.log(''+msg);
+        };
+
+        // Mapping of button events to BlackBerry key identifier.
+        var buttonMapping = {
+            'backbutton'         : blackberry.system.event.KEY_BACK,
+            'conveniencebutton1' : blackberry.system.event.KEY_CONVENIENCE_1,
+            'conveniencebutton2' : blackberry.system.event.KEY_CONVENIENCE_2,
+            'endcallbutton'      : blackberry.system.event.KEY_ENDCALL,
+            'menubutton'         : blackberry.system.event.KEY_MENU,
+            'startcallbutton'    : blackberry.system.event.KEY_STARTCALL,
+            'volumedownbutton'   : blackberry.system.event.KEY_VOLUMEDOWN,
+            'volumeupbutton'     : blackberry.system.event.KEY_VOLUMEUP
+        };
+
+        // Generates a function which fires the specified event.
+        var fireEvent = function(event) {
+            return function() {
+                cordova.fireDocumentEvent(event, null);
+            };
+        };
+
+        var eventHandler = function(event) {
+            return { onSubscribe : function() {
+                // If we just attached the first handler, let native know we
+                // need to override the back button.
+                if (this.numHandlers === 1) {
+                    blackberry.system.event.onHardwareKey(
+                            buttonMapping[event], fireEvent(event));
+                }
+            },
+            onUnsubscribe : function() {
+                // If we just detached the last handler, let native know we
+                // no longer override the back button.
+                if (this.numHandlers === 0) {
+                    blackberry.system.event.onHardwareKey(
+                            buttonMapping[event], null);
+                }
+            }};
+        };
+
+        // Inject listeners for buttons on the document.
+        for (var button in buttonMapping) {
+            if (buttonMapping.hasOwnProperty(button)) {
+                cordova.addDocumentEventHandler(button, eventHandler(button));
+            }
+        }
+
+        // Fires off necessary code to pause/resume app
+        var resume = function() {
+            cordova.fireDocumentEvent('resume');
+            blackberryManager.resume();
+        };
+        var pause = function() {
+            cordova.fireDocumentEvent('pause');
+            blackberryManager.pause();
+        };
+
+        /************************************************
+         * Patch up the generic pause/resume listeners. *
+         ************************************************/
+
+        // Unsubscribe handler - turns off native backlight change
+        // listener
+        var onUnsubscribe = function() {
+            if (channel.onResume.numHandlers === 0 && channel.onPause.numHandlers === 0) {
+                exec(null, null, 'App', 'ignoreBacklight', []);
+            }
+        };
+
+        // Native backlight detection win/fail callbacks
+        var backlightWin = function(isOn) {
+            if (isOn === true) {
+                resume();
+            } else {
+                pause();
+            }
+        };
+        var backlightFail = function(e) {
+            console.log("Error detecting backlight on/off.");
+        };
+
+        // Override stock resume and pause listeners so we can trigger
+        // some native methods during attach/remove
+        channel.onResume = cordova.addDocumentEventHandler('resume', {
+            onSubscribe:function() {
+                // If we just attached the first handler and there are
+                // no pause handlers, start the backlight system
+                // listener on the native side.
+                if (channel.onResume.numHandlers === 1 && channel.onPause.numHandlers === 0) {
+                    exec(backlightWin, backlightFail, "App", "detectBacklight", []);
+                }
+            },
+            onUnsubscribe:onUnsubscribe
+        });
+        channel.onPause = cordova.addDocumentEventHandler('pause', {
+            onSubscribe:function() {
+                // If we just attached the first handler and there are
+                // no resume handlers, start the backlight system
+                // listener on the native side.
+                if (channel.onResume.numHandlers === 0 && channel.onPause.numHandlers === 1) {
+                    exec(backlightWin, backlightFail, "App", "detectBacklight", []);
+                }
+            },
+            onUnsubscribe:onUnsubscribe
+        });
+
+        // Fire resume event when application brought to foreground.
+        blackberry.app.event.onForeground(resume);
+
+        // Fire pause event when application sent to background.
+        blackberry.app.event.onBackground(pause);
+
+        // Trap BlackBerry WebWorks exit. Allow plugins to clean up before exiting.
+        blackberry.app.event.onExit(app.exitApp);
+    },
+    objects: {
+        navigator: {
+            children: {
+                app: {
+                    path: "cordova/plugin/blackberry/app"
+                }
+            }
+        },
+        device: {
+            path: "cordova/plugin/blackberry/device"
+        },
+        File: { // exists natively on BlackBerry OS 7, override
+            path: "cordova/plugin/File"
+        }
+    },
+    merges: {
+        navigator: {
+            children: {
+                device: {
+                    path: 'cordova/plugin/blackberry/device'
+                },
+                notification: {
+                    path: 'cordova/plugin/blackberry/notification'
+                }
+            }
+        },
+        DirectoryEntry: {
+            path: 'cordova/plugin/blackberry/DirectoryEntry'
+        },
+        Entry: {
+            path: 'cordova/plugin/blackberry/Entry'
+        }
+    }
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/blackberry/cordova/plugin/blackberry/DirectoryEntry.js
----------------------------------------------------------------------
diff --git a/lib-platforms/blackberry/cordova/plugin/blackberry/DirectoryEntry.js b/lib-platforms/blackberry/cordova/plugin/blackberry/DirectoryEntry.js
new file mode 100644
index 0000000..76acaf7
--- /dev/null
+++ b/lib-platforms/blackberry/cordova/plugin/blackberry/DirectoryEntry.js
@@ -0,0 +1,239 @@
+var DirectoryEntry = require('cordova/plugin/DirectoryEntry'),
+    FileEntry = require('cordova/plugin/FileEntry'),
+    FileError = require('cordova/plugin/FileError'),
+    exec = require('cordova/exec');
+
+module.exports = {
+    /**
+     * Creates or looks up a directory; override for BlackBerry.
+     *
+     * @param path
+     *            {DOMString} either a relative or absolute path from this
+     *            directory in which to look up or create a directory
+     * @param options
+     *            {Flags} options to create or exclusively create the directory
+     * @param successCallback
+     *            {Function} called with the new DirectoryEntry
+     * @param errorCallback
+     *            {Function} called with a FileError
+     */
+    getDirectory : function(path, options, successCallback, errorCallback) {
+        // create directory if it doesn't exist
+        var create = (options && options.create === true) ? true : false,
+        // if true, causes failure if create is true and path already exists
+        exclusive = (options && options.exclusive === true) ? true : false,
+        // directory exists
+        exists,
+        // create a new DirectoryEntry object and invoke success callback
+        createEntry = function() {
+            var path_parts = path.split('/'),
+                name = path_parts[path_parts.length - 1],
+                dirEntry = new DirectoryEntry(name, path);
+
+            // invoke success callback
+            if (typeof successCallback === 'function') {
+                successCallback(dirEntry);
+            }
+        };
+
+        var fail = function(error) {
+            if (typeof errorCallback === 'function') {
+                errorCallback(new FileError(error));
+            }
+        };
+
+        // determine if path is relative or absolute
+        if (!path) {
+            fail(FileError.ENCODING_ERR);
+            return;
+        } else if (path.indexOf(this.fullPath) !== 0) {
+            // path does not begin with the fullPath of this directory
+            // therefore, it is relative
+            path = this.fullPath + '/' + path;
+        }
+
+        // determine if directory exists
+        try {
+            // will return true if path exists AND is a directory
+            exists = blackberry.io.dir.exists(path);
+        } catch (e) {
+            // invalid path
+            fail(FileError.ENCODING_ERR);
+            return;
+        }
+
+        // path is a directory
+        if (exists) {
+            if (create && exclusive) {
+                // can't guarantee exclusivity
+                fail(FileError.PATH_EXISTS_ERR);
+            } else {
+                // create entry for existing directory
+                createEntry();
+            }
+        }
+        // will return true if path exists AND is a file
+        else if (blackberry.io.file.exists(path)) {
+            // the path is a file
+            fail(FileError.TYPE_MISMATCH_ERR);
+        }
+        // path does not exist, create it
+        else if (create) {
+            try {
+                // directory path must have trailing slash
+                var dirPath = path;
+                if (dirPath.substr(-1) !== '/') {
+                    dirPath += '/';
+                }
+                blackberry.io.dir.createNewDir(dirPath);
+                createEntry();
+            } catch (eone) {
+                // unable to create directory
+                fail(FileError.NOT_FOUND_ERR);
+            }
+        }
+        // path does not exist, don't create
+        else {
+            // directory doesn't exist
+            fail(FileError.NOT_FOUND_ERR);
+        }
+    },
+    /**
+     * Create or look up a file.
+     *
+     * @param path {DOMString}
+     *            either a relative or absolute path from this directory in
+     *            which to look up or create a file
+     * @param options {Flags}
+     *            options to create or exclusively create the file
+     * @param successCallback {Function}
+     *            called with the new FileEntry object
+     * @param errorCallback {Function}
+     *            called with a FileError object if error occurs
+     */
+    getFile:function(path, options, successCallback, errorCallback) {
+        // create file if it doesn't exist
+        var create = (options && options.create === true) ? true : false,
+            // if true, causes failure if create is true and path already exists
+            exclusive = (options && options.exclusive === true) ? true : false,
+            // file exists
+            exists,
+            // create a new FileEntry object and invoke success callback
+            createEntry = function() {
+                var path_parts = path.split('/'),
+                    name = path_parts[path_parts.length - 1],
+                    fileEntry = new FileEntry(name, path);
+
+                // invoke success callback
+                if (typeof successCallback === 'function') {
+                    successCallback(fileEntry);
+                }
+            };
+
+        var fail = function(error) {
+            if (typeof errorCallback === 'function') {
+                errorCallback(new FileError(error));
+            }
+        };
+
+        // determine if path is relative or absolute
+        if (!path) {
+            fail(FileError.ENCODING_ERR);
+            return;
+        }
+        else if (path.indexOf(this.fullPath) !== 0) {
+            // path does not begin with the fullPath of this directory
+            // therefore, it is relative
+            path = this.fullPath + '/' + path;
+        }
+
+        // determine if file exists
+        try {
+            // will return true if path exists AND is a file
+            exists = blackberry.io.file.exists(path);
+        }
+        catch (e) {
+            // invalid path
+            fail(FileError.ENCODING_ERR);
+            return;
+        }
+
+        // path is a file
+        if (exists) {
+            if (create && exclusive) {
+                // can't guarantee exclusivity
+                fail(FileError.PATH_EXISTS_ERR);
+            }
+            else {
+                // create entry for existing file
+                createEntry();
+            }
+        }
+        // will return true if path exists AND is a directory
+        else if (blackberry.io.dir.exists(path)) {
+            // the path is a directory
+            fail(FileError.TYPE_MISMATCH_ERR);
+        }
+        // path does not exist, create it
+        else if (create) {
+            // create empty file
+            exec(
+                function(result) {
+                    // file created
+                    createEntry();
+                },
+                fail, "File", "write", [ path, "", 0 ]);
+        }
+        // path does not exist, don't create
+        else {
+            // file doesn't exist
+            fail(FileError.NOT_FOUND_ERR);
+        }
+    },
+
+    /**
+     * Delete a directory and all of it's contents.
+     *
+     * @param successCallback {Function} called with no parameters
+     * @param errorCallback {Function} called with a FileError
+     */
+    removeRecursively : function(successCallback, errorCallback) {
+        // we're removing THIS directory
+        var path = this.fullPath;
+
+        var fail = function(error) {
+            if (typeof errorCallback === 'function') {
+                errorCallback(new FileError(error));
+            }
+        };
+
+        // attempt to delete directory
+        if (blackberry.io.dir.exists(path)) {
+            // it is an error to attempt to remove the file system root
+            if (exec(null, null, "File", "isFileSystemRoot", [ path ]) === true) {
+                fail(FileError.NO_MODIFICATION_ALLOWED_ERR);
+            }
+            else {
+                try {
+                    // delete the directory, setting recursive flag to true
+                    blackberry.io.dir.deleteDirectory(path, true);
+                    if (typeof successCallback === "function") {
+                        successCallback();
+                    }
+                } catch (e) {
+                    // permissions don't allow deletion
+                    console.log(e);
+                    fail(FileError.NO_MODIFICATION_ALLOWED_ERR);
+                }
+            }
+        }
+        // it's a file, not a directory
+        else if (blackberry.io.file.exists(path)) {
+            fail(FileError.TYPE_MISMATCH_ERR);
+        }
+        // not found
+        else {
+            fail(FileError.NOT_FOUND_ERR);
+        }
+    }
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/blackberry/cordova/plugin/blackberry/Entry.js
----------------------------------------------------------------------
diff --git a/lib-platforms/blackberry/cordova/plugin/blackberry/Entry.js b/lib-platforms/blackberry/cordova/plugin/blackberry/Entry.js
new file mode 100644
index 0000000..cc9626d
--- /dev/null
+++ b/lib-platforms/blackberry/cordova/plugin/blackberry/Entry.js
@@ -0,0 +1,87 @@
+var FileError = require('cordova/plugin/FileError'),
+    LocalFileSystem = require('cordova/plugin/LocalFileSystem'),
+    resolveLocalFileSystemURI = require('cordova/plugin/resolveLocalFileSystemURI'),
+    exec = require('cordova/exec');
+
+module.exports = {
+    remove : function(successCallback, errorCallback) {
+        var path = this.fullPath,
+            // directory contents
+            contents = [];
+
+        var fail = function(error) {
+            if (typeof errorCallback === 'function') {
+                errorCallback(new FileError(error));
+            }
+        };
+
+        // file
+        if (blackberry.io.file.exists(path)) {
+            try {
+                blackberry.io.file.deleteFile(path);
+                if (typeof successCallback === "function") {
+                    successCallback();
+                }
+            } catch (e) {
+                // permissions don't allow
+                fail(FileError.INVALID_MODIFICATION_ERR);
+            }
+        }
+        // directory
+        else if (blackberry.io.dir.exists(path)) {
+            // it is an error to attempt to remove the file system root
+            if (exec(null, null, "File", "isFileSystemRoot", [ path ]) === true) {
+                fail(FileError.NO_MODIFICATION_ALLOWED_ERR);
+            } else {
+                // check to see if directory is empty
+                contents = blackberry.io.dir.listFiles(path);
+                if (contents.length !== 0) {
+                    fail(FileError.INVALID_MODIFICATION_ERR);
+                } else {
+                    try {
+                        // delete
+                        blackberry.io.dir.deleteDirectory(path, false);
+                        if (typeof successCallback === "function") {
+                            successCallback();
+                        }
+                    } catch (eone) {
+                        // permissions don't allow
+                        fail(FileError.NO_MODIFICATION_ALLOWED_ERR);
+                    }
+                }
+            }
+        }
+        // not found
+        else {
+            fail(FileError.NOT_FOUND_ERR);
+        }
+    },
+    getParent : function(successCallback, errorCallback) {
+        var that = this;
+
+        try {
+            // On BlackBerry, the TEMPORARY file system is actually a temporary
+            // directory that is created on a per-application basis. This is
+            // to help ensure that applications do not share the same temporary
+            // space. So we check to see if this is the TEMPORARY file system
+            // (directory). If it is, we must return this Entry, rather than
+            // the Entry for its parent.
+            requestFileSystem(LocalFileSystem.TEMPORARY, 0,
+                    function(fileSystem) {
+                        if (fileSystem.root.fullPath === that.fullPath) {
+                            if (typeof successCallback === 'function') {
+                                successCallback(fileSystem.root);
+                            }
+                        } else {
+                            resolveLocalFileSystemURI(blackberry.io.dir
+                                    .getParentDirectory(that.fullPath),
+                                    successCallback, errorCallback);
+                        }
+                    }, errorCallback);
+        } catch (e) {
+            if (typeof errorCallback === 'function') {
+                errorCallback(new FileError(FileError.NOT_FOUND_ERR));
+            }
+        }
+    }
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/blackberry/cordova/plugin/blackberry/app.js
----------------------------------------------------------------------
diff --git a/lib-platforms/blackberry/cordova/plugin/blackberry/app.js b/lib-platforms/blackberry/cordova/plugin/blackberry/app.js
new file mode 100644
index 0000000..6c58e30
--- /dev/null
+++ b/lib-platforms/blackberry/cordova/plugin/blackberry/app.js
@@ -0,0 +1,51 @@
+var exec = require('cordova/exec');
+var manager = require('cordova/plugin/blackberry/manager');
+
+module.exports = {
+  /**
+   * Clear the resource cache.
+   */
+  clearCache:function() {
+      if (typeof blackberry.widgetcache === "undefined"
+          || blackberry.widgetcache === null) {
+          console.log("blackberry.widgetcache permission not found. Cache clear denied.");
+          return;
+      }
+      blackberry.widgetcache.clearAll();
+  },
+
+  /**
+   * Clear web history in this web view.
+   * Instead of BACK button loading the previous web page, it will exit the app.
+   */
+  clearHistory:function() {
+    exec(null, null, "App", "clearHistory", []);
+  },
+
+  /**
+   * Go to previous page displayed.
+   * This is the same as pressing the backbutton on Android device.
+   */
+  backHistory:function() {
+    // window.history.back() behaves oddly on BlackBerry, so use
+    // native implementation.
+    exec(null, null, "App", "backHistory", []);
+  },
+
+  /**
+   * Exit and terminate the application.
+   */
+  exitApp:function() {
+      // Call onunload if it is defined since BlackBerry does not invoke
+      // on application exit.
+      if (typeof window.onunload === "function") {
+          window.onunload();
+      }
+
+      // allow Cordova JavaScript Extension opportunity to cleanup
+      manager.destroy();
+
+      // exit the app
+      blackberry.app.exit();
+  }
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/blackberry/cordova/plugin/blackberry/device.js
----------------------------------------------------------------------
diff --git a/lib-platforms/blackberry/cordova/plugin/blackberry/device.js b/lib-platforms/blackberry/cordova/plugin/blackberry/device.js
new file mode 100644
index 0000000..42a0647
--- /dev/null
+++ b/lib-platforms/blackberry/cordova/plugin/blackberry/device.js
@@ -0,0 +1,23 @@
+var me = {},
+    channel = require('cordova/channel'),
+    exec = require('cordova/exec');
+
+exec(
+    function (device) {
+        me.platform = device.platform;
+        me.version  = device.version;
+        me.name     = device.name;
+        me.uuid     = device.uuid;
+        me.cordova  = device.cordova;
+
+        channel.onCordovaInfoReady.fire();
+    },
+    function (e) {
+        console.log("error initializing cordova: " + e);
+    },
+    "Device",
+    "getDeviceInfo",
+    []
+);
+
+module.exports = me;

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/blackberry/cordova/plugin/blackberry/manager.js
----------------------------------------------------------------------
diff --git a/lib-platforms/blackberry/cordova/plugin/blackberry/manager.js b/lib-platforms/blackberry/cordova/plugin/blackberry/manager.js
new file mode 100644
index 0000000..ef353bb
--- /dev/null
+++ b/lib-platforms/blackberry/cordova/plugin/blackberry/manager.js
@@ -0,0 +1,87 @@
+var webworks = require('cordova/plugin/webworks/manager'),
+    Cordova = require('cordova'),
+    plugins = {};
+
+function _exec(win, fail, clazz, action, args) {
+    var callbackId = clazz + Cordova.callbackId++,
+        origResult,
+        evalResult,
+        execResult;
+
+    try {
+
+        if (win || fail) {
+            Cordova.callbacks[callbackId] = {success: win, fail: fail};
+        }
+
+        // Note: Device returns string, but for some reason emulator returns object - so convert to string.
+        origResult = "" + org.apache.cordova.JavaPluginManager.exec(clazz, action, callbackId, JSON.stringify(args), true);
+
+        // If a result was returned
+        if (origResult.length > 0) {
+            eval("evalResult = " + origResult + ";");
+
+            // If status is OK, then return evalResultalue back to caller
+            if (evalResult.status === Cordova.callbackStatus.OK) {
+
+                // If there is a success callback, then call it now with returned evalResultalue
+                if (win) {
+                    // Clear callback if not expecting any more results
+                    if (!evalResult.keepCallback) {
+                        delete Cordova.callbacks[callbackId];
+                    }
+                }
+            } else if (evalResult.status === Cordova.callbackStatus.NO_RESULT) {
+
+                // Clear callback if not expecting any more results
+                if (!evalResult.keepCallback) {
+                    delete Cordova.callbacks[callbackId];
+                }
+            } else {
+                // If there is a fail callback, then call it now with returned evalResultalue
+                if (fail) {
+
+                    // Clear callback if not expecting any more results
+                    if (!evalResult.keepCallback) {
+                        delete Cordova.callbacks[callbackId];
+                    }
+                }
+            }
+            execResult = evalResult;
+        } else {
+            // Asynchronous calls return an empty string. Return a NO_RESULT
+            // status for those executions.
+            execResult = {"status" : Cordova.callbackStatus.NO_RESULT,
+                    "message" : ""};
+        }
+    } catch (e) {
+        console.log("BlackBerryPluginManager Error: " + e);
+        execResult = {"status" : Cordova.callbackStatus.ERROR,
+                      "message" : e.message};
+    }
+
+    return execResult;
+}
+
+module.exports = {
+    exec: function (win, fail, clazz, action, args) {
+        var result = webworks.exec(win, fail, clazz, action, args);
+
+        //We got a sync result or a not found from WW that we can pass on to get a native mixin
+        //For async calls there's nothing to do
+        if (result.status === Cordova.callbackStatus.CLASS_NOT_FOUND_EXCEPTION  ||
+                result.status === Cordova.callbackStatus.INVALID_ACTION ||
+                result.status === Cordova.callbackStatus.OK) {
+            if (plugins[clazz]) {
+                return plugins[clazz].execute(result.message, action, args, win, fail);
+            } else {
+                result = _exec(win, fail, clazz, action, args);
+            }
+        }
+
+        return result;
+    },
+    resume: org.apache.cordova.JavaPluginManager.resume,
+    pause: org.apache.cordova.JavaPluginManager.pause,
+    destroy: org.apache.cordova.JavaPluginManager.destroy
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/blackberry/cordova/plugin/blackberry/notification.js
----------------------------------------------------------------------
diff --git a/lib-platforms/blackberry/cordova/plugin/blackberry/notification.js b/lib-platforms/blackberry/cordova/plugin/blackberry/notification.js
new file mode 100644
index 0000000..83bc77c
--- /dev/null
+++ b/lib-platforms/blackberry/cordova/plugin/blackberry/notification.js
@@ -0,0 +1,53 @@
+var exec = require('cordova/exec');
+
+/**
+ * Provides BlackBerry enhanced notification API.
+ */
+module.exports = {
+    activityStart : function(title, message) {
+        // If title and message not specified then mimic Android behavior of
+        // using default strings.
+        if (typeof title === "undefined" && typeof message == "undefined") {
+            title = "Busy";
+            message = 'Please wait...';
+        }
+
+        exec(null, null, 'Notification', 'activityStart', [ title, message ]);
+    },
+
+    /**
+     * Close an activity dialog
+     */
+    activityStop : function() {
+        exec(null, null, 'Notification', 'activityStop', []);
+    },
+
+    /**
+     * Display a progress dialog with progress bar that goes from 0 to 100.
+     *
+     * @param {String}
+     *            title Title of the progress dialog.
+     * @param {String}
+     *            message Message to display in the dialog.
+     */
+    progressStart : function(title, message) {
+        exec(null, null, 'Notification', 'progressStart', [ title, message ]);
+    },
+
+    /**
+     * Close the progress dialog.
+     */
+    progressStop : function() {
+        exec(null, null, 'Notification', 'progressStop', []);
+    },
+
+    /**
+     * Set the progress dialog value.
+     *
+     * @param {Number}
+     *            value 0-100
+     */
+    progressValue : function(value) {
+        exec(null, null, 'Notification', 'progressValue', [ value ]);
+    },
+};
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/errgen/cordova/exec.js
----------------------------------------------------------------------
diff --git a/lib-platforms/errgen/cordova/exec.js b/lib-platforms/errgen/cordova/exec.js
new file mode 100644
index 0000000..dc47fcb
--- /dev/null
+++ b/lib-platforms/errgen/cordova/exec.js
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+/**
+ * Execute a cordova command.  It is up to the native side whether this action
+ * is synchronous or asynchronous.  The native side can return:
+ *      Synchronous: PluginResult object as a JSON string
+ *      Asynchrounous: Empty string ""
+ * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
+ * depending upon the result of the action.
+ *
+ * @param {Function} success    The success callback
+ * @param {Function} fail       The fail callback
+ * @param {String} service      The name of the service to use
+ * @param {String} action       Action to be run in cordova
+ * @param {String[]} [args]     Zero or more arguments to pass to the method
+ */
+
+//------------------------------------------------------------------------------
+module.exports = function exec(success, fail, service, action, args) {
+    var signature = service + "::" + action
+
+    //--------------------------------------------------------------------------
+    function callFail() {
+        var args = "<unable to JSONify>"
+        
+        try {
+            args = JSON.stringify(args)
+        }
+        catch (e) {}
+
+        var call = signature + "(" + args + ")"
+
+        if (!fail) {
+            console.log("failure callback not set for " + call)
+            return
+        }
+        
+        if (typeof(fail) != 'function') {
+            console.log("failure callback not a function for " + call)
+            return
+        }
+        
+        try {
+            fail("expected errgen failure for " + call)
+        }
+        catch (e) {
+            console.log("exception running failure callback for " + call)
+            console.log("   exception: " + e)
+            return
+        }
+    }
+
+    //--------------------------------------------------------------------------
+    if (Overrides[signature]) {
+        Overrides[signature].call(null, success, fail, args)
+        return
+    }
+    
+    setTimeout(callFail, 10)
+}
+
+//------------------------------------------------------------------------------
+var Overrides = {}
+
+//------------------------------------------------------------------------------
+function addOverride(func) {
+    var name = func.name.replace('__', '::')
+    Overrides[name] = func
+}
+
+//------------------------------------------------------------------------------
+addOverride(function Accelerometer__setTimeout(success, fail, args) {
+    setTimeout(function() { 
+        fail("Accelerometer::setTimeout") 
+    }, 10)
+})
+
+//------------------------------------------------------------------------------
+addOverride(function Accelerometer__getTimeout(success, fail, args) {
+    setTimeout(function() { 
+        fail("Accelerometer::getTimeout") 
+    }, 10)
+})
+
+//------------------------------------------------------------------------------
+addOverride(function Network_Status__getConnectionInfo(success, fail) {
+    setTimeout(function() { 
+        success("none")
+    }, 10)
+})

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/errgen/cordova/platform.js
----------------------------------------------------------------------
diff --git a/lib-platforms/errgen/cordova/platform.js b/lib-platforms/errgen/cordova/platform.js
new file mode 100644
index 0000000..8677cab
--- /dev/null
+++ b/lib-platforms/errgen/cordova/platform.js
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+// required call to kick off the device ready callback
+require('cordova/plugin/errgen/device')
+
+//------------------------------------------------------------------------------
+module.exports = {
+    id:         "errgen",
+    initialize: function() {},
+    objects:    {}
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/errgen/cordova/plugin/errgen/device.js
----------------------------------------------------------------------
diff --git a/lib-platforms/errgen/cordova/plugin/errgen/device.js b/lib-platforms/errgen/cordova/plugin/errgen/device.js
new file mode 100644
index 0000000..4e05777
--- /dev/null
+++ b/lib-platforms/errgen/cordova/plugin/errgen/device.js
@@ -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.
+ */
+
+/**
+ * this represents the mobile device, and provides properties for inspecting the model, version, UUID of the
+ * phone, etc.
+ * @constructor
+ */
+
+//------------------------------------------------------------------------------
+function Device() {
+    window.DeviceInfo = {}
+    
+    this.platform  = "errgen"
+    this.version   = "any"
+    this.name      = "errgen"
+    this.phonegap  = {}
+    this.gap       = this.phonegap
+    this.uuid      = "1234-5678-9012-3456"
+    this.available = true
+    
+    require('cordova/channel').onCordovaInfoReady.fire()
+}
+
+//------------------------------------------------------------------------------
+module.exports = window.DeviceInfo = new Device()

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/ios/cordova/exec.js
----------------------------------------------------------------------
diff --git a/lib-platforms/ios/cordova/exec.js b/lib-platforms/ios/cordova/exec.js
new file mode 100644
index 0000000..32d8b6a
--- /dev/null
+++ b/lib-platforms/ios/cordova/exec.js
@@ -0,0 +1,93 @@
+    /**
+     * Creates a gap bridge iframe used to notify the native code about queued
+     * commands.
+     *
+     * @private
+     */
+var cordova = require('cordova'),
+    gapBridge,
+    createGapBridge = function() {
+        gapBridge = document.createElement("iframe");
+        gapBridge.setAttribute("style", "display:none;");
+        gapBridge.setAttribute("height","0px");
+        gapBridge.setAttribute("width","0px");
+        gapBridge.setAttribute("frameborder","0");
+        document.documentElement.appendChild(gapBridge);
+    },
+    channel = require('cordova/channel');
+
+module.exports = function() { 
+    if (!channel.onCordovaInfoReady.fired) {
+        alert("ERROR: Attempting to call cordova.exec()" +
+              " before 'deviceready'. Ignoring.");
+        return;
+    }
+
+    var successCallback, failCallback, service, action, actionArgs;
+    var callbackId = null;
+    if (typeof arguments[0] !== "string") {
+        // FORMAT ONE
+        successCallback = arguments[0];
+        failCallback = arguments[1];
+        service = arguments[2];
+        action = arguments[3];
+        actionArgs = arguments[4];
+
+        // Since we need to maintain backwards compatibility, we have to pass
+        // an invalid callbackId even if no callback was provided since plugins
+        // will be expecting it. The Cordova.exec() implementation allocates
+        // an invalid callbackId and passes it even if no callbacks were given.
+        callbackId = 'INVALID';
+    } else {
+        // FORMAT TWO
+        splitCommand = arguments[0].split(".");
+        action = splitCommand.pop();
+        service = splitCommand.join(".");
+        actionArgs = Array.prototype.splice.call(arguments, 1);
+    }
+    
+    // Start building the command object.
+    var command = {
+        className: service,
+        methodName: action,
+        arguments: []
+    };
+
+    // Register the callbacks and add the callbackId to the positional
+    // arguments if given.
+    if (successCallback || failCallback) {
+        callbackId = service + cordova.callbackId++;
+        cordova.callbacks[callbackId] = 
+            {success:successCallback, fail:failCallback};
+    }
+    if (callbackId != null) {
+        command.arguments.push(callbackId);
+    }
+
+    for (var i = 0; i < actionArgs.length; ++i) {
+        var arg = actionArgs[i];
+        if (arg == undefined || arg == null) { // nulls are pushed to the args now (becomes NSNull)
+            continue;  //command.arguments.push(arg);
+        } else if (typeof(arg) == 'object' && !(arg instanceof Array)) {
+            command.options = arg;
+        } else {
+            command.arguments.push(arg);
+        }
+    }
+
+    // Stringify and queue the command. We stringify to command now to
+    // effectively clone the command arguments in case they are mutated before
+    // the command is executed.
+    cordova.commandQueue.push(JSON.stringify(command));
+
+    // If the queue length is 1, then that means it was empty before we queued
+    // the given command, so let the native side know that we have some
+    // commands to execute, unless the queue is currently being flushed, in
+    // which case the command will be picked up without notification.
+    if (cordova.commandQueue.length == 1 && !cordova.commandQueueFlushing) {
+        if (!gapBridge) {
+            createGapBridge();
+        }
+        gapBridge.src = "gap://ready";
+    }
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/ios/cordova/platform.js
----------------------------------------------------------------------
diff --git a/lib-platforms/ios/cordova/platform.js b/lib-platforms/ios/cordova/platform.js
new file mode 100644
index 0000000..e68b52e
--- /dev/null
+++ b/lib-platforms/ios/cordova/platform.js
@@ -0,0 +1,41 @@
+module.exports = {
+    id: "ios",
+    initialize:function() {
+        // iOS doesn't allow reassigning / overriding navigator.geolocation object.
+        // So clobber its methods here instead :)
+        var geo = require('cordova/plugin/geolocation');
+        
+        navigator.geolocation.getCurrentPosition = geo.getCurrentPosition;
+        navigator.geolocation.watchPosition = geo.watchPosition;
+        navigator.geolocation.clearWatch = geo.clearWatch;
+    },
+    objects: {
+        File: { // exists natively, override
+            path: "cordova/plugin/File"
+        },
+        MediaError: { // exists natively, override
+            path: "cordova/plugin/MediaError"
+        },
+        device: {
+            path: 'cordova/plugin/ios/device'
+        },
+        console: {
+            path: 'cordova/plugin/ios/console'
+        }
+    },
+    merges:{
+        Entry:{
+            path: "cordova/plugin/ios/Entry"
+        },
+        FileReader:{
+            path: "cordova/plugin/ios/FileReader"
+        },
+        navigator:{
+            children:{
+                notification:{
+                    path:"cordova/plugin/ios/notification"
+                }
+            }
+        }
+    }
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/ios/cordova/plugin/ios/Entry.js
----------------------------------------------------------------------
diff --git a/lib-platforms/ios/cordova/plugin/ios/Entry.js b/lib-platforms/ios/cordova/plugin/ios/Entry.js
new file mode 100644
index 0000000..230da8a
--- /dev/null
+++ b/lib-platforms/ios/cordova/plugin/ios/Entry.js
@@ -0,0 +1,7 @@
+module.exports = {
+    toURL:function() {
+        // TODO: refactor path in a cross-platform way so we can eliminate 
+        // these kinds of platform-specific hacks.
+        return "file://localhost" + this.fullPath;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/ios/cordova/plugin/ios/FileReader.js
----------------------------------------------------------------------
diff --git a/lib-platforms/ios/cordova/plugin/ios/FileReader.js b/lib-platforms/ios/cordova/plugin/ios/FileReader.js
new file mode 100644
index 0000000..5711393
--- /dev/null
+++ b/lib-platforms/ios/cordova/plugin/ios/FileReader.js
@@ -0,0 +1,87 @@
+var exec = require('cordova/exec'),
+    FileError = require('cordova/plugin/FileError'),
+    FileReader = require('cordova/plugin/FileReader'),
+    ProgressEvent = require('cordova/plugin/ProgressEvent');
+
+module.exports = {
+    readAsText:function(file, encoding) {
+        // Figure out pathing
+        this.fileName = '';
+        if (typeof file.fullPath === 'undefined') {
+            this.fileName = file;
+        } else {
+            this.fileName = file.fullPath;
+        }
+
+        // Already loading something
+        if (this.readyState == FileReader.LOADING) {
+            throw new FileError(FileError.INVALID_STATE_ERR);
+        }
+
+        // LOADING state
+        this.readyState = FileReader.LOADING;
+
+        // If loadstart callback
+        if (typeof this.onloadstart === "function") {
+            this.onloadstart(new ProgressEvent("loadstart", {target:this}));
+        }
+
+        // Default encoding is UTF-8
+        var enc = encoding ? encoding : "UTF-8";
+
+        var me = this;
+
+        // Read file
+        exec(
+            // Success callback
+            function(r) {
+                // If DONE (cancelled), then don't do anything
+                if (me.readyState === FileReader.DONE) {
+                    return;
+                }
+
+                // Save result
+                me.result = decodeURIComponent(r);
+
+                // If onload callback
+                if (typeof me.onload === "function") {
+                    me.onload(new ProgressEvent("load", {target:me}));
+                }
+
+                // DONE state
+                me.readyState = FileReader.DONE;
+
+                // If onloadend callback
+                if (typeof me.onloadend === "function") {
+                    me.onloadend(new ProgressEvent("loadend", {target:me}));
+                }
+            },
+            // Error callback
+            function(e) {
+                // If DONE (cancelled), then don't do anything
+                if (me.readyState === FileReader.DONE) {
+                    return;
+                }
+
+                // DONE state
+                me.readyState = FileReader.DONE;
+
+                // null result
+                me.result = null;
+
+                // Save error
+                me.error = new FileError(e);
+
+                // If onerror callback
+                if (typeof me.onerror === "function") {
+                    me.onerror(new ProgressEvent("error", {target:me}));
+                }
+
+                // If onloadend callback
+                if (typeof me.onloadend === "function") {
+                    me.onloadend(new ProgressEvent("loadend", {target:me}));
+                }
+            }, 
+        "File", "readAsText", [this.fileName, enc]);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/ios/cordova/plugin/ios/console.js
----------------------------------------------------------------------
diff --git a/lib-platforms/ios/cordova/plugin/ios/console.js b/lib-platforms/ios/cordova/plugin/ios/console.js
new file mode 100644
index 0000000..8651591
--- /dev/null
+++ b/lib-platforms/ios/cordova/plugin/ios/console.js
@@ -0,0 +1,102 @@
+var exec = require('cordova/exec');
+
+/**
+ * String indentation/formatting
+ */
+function indent(str) {
+    return str.replace(/^/mg, "    ");
+}
+/**
+ * Format a string for pretty logging
+ */
+function makeStructured(obj, depth) {
+    var str = "";
+    for (var i in obj) {
+        try {
+            if (typeof(obj[i]) == 'object' && depth < maxDepth) {
+                str += i + ":\n" + indent(makeStructured(obj[i])) + "\n";
+            } else {
+                str += i + " = " + indent(String(obj[i])).replace(/^ {4}/, "") + "\n";
+            }
+        } catch(e) {
+            str += i + " = EXCEPTION: " + e.message + "\n";
+        }
+    }
+    return str;
+}
+
+/**
+ * This class provides access to the debugging console.
+ * @constructor
+ */
+var DebugConsole = function() {
+    this.winConsole = window.console;
+    this.logLevel = DebugConsole.INFO_LEVEL;
+};
+
+// from most verbose, to least verbose
+DebugConsole.ALL_LEVEL    = 1; // same as first level
+DebugConsole.INFO_LEVEL   = 1;
+DebugConsole.WARN_LEVEL   = 2;
+DebugConsole.ERROR_LEVEL  = 4;
+DebugConsole.NONE_LEVEL   = 8;
+													
+DebugConsole.prototype.setLevel = function(level) {
+    this.logLevel = level;
+};
+
+/**
+ * Utility function for rendering and indenting strings, or serializing
+ * objects to a string capable of being printed to the console.
+ * @param {Object|String} message The string or object to convert to an indented string
+ * @private
+ */
+DebugConsole.prototype.processMessage = function(message, maxDepth) {
+	if (maxDepth === undefined) maxDepth = 0;
+    if (typeof(message) != 'object') {
+        return (this.isDeprecated ? "WARNING: debug object is deprecated, please use console object \n" + message : message);
+    } else {
+        return ("Object:\n" + makeStructured(message, maxDepth));
+    }
+};
+
+/**
+ * Print a normal log message to the console
+ * @param {Object|String} message Message or object to print to the console
+ */
+DebugConsole.prototype.log = function(message, maxDepth) {
+    if (this.logLevel <= DebugConsole.INFO_LEVEL)
+        exec(null, null, 'Debug Console', 'log',
+            [ this.processMessage(message, maxDepth), { logLevel: 'INFO' } ]
+        );
+    else
+        this.winConsole.log(message);
+};
+
+/**
+ * Print a warning message to the console
+ * @param {Object|String} message Message or object to print to the console
+ */
+DebugConsole.prototype.warn = function(message, maxDepth) {
+    if (this.logLevel <= DebugConsole.WARN_LEVEL)
+        exec(null, null, 'Debug Console', 'log',
+            [ this.processMessage(message, maxDepth), { logLevel: 'WARN' } ]
+        );
+    else
+        this.winConsole.error(message);
+};
+
+/**
+ * Print an error message to the console
+ * @param {Object|String} message Message or object to print to the console
+ */
+DebugConsole.prototype.error = function(message, maxDepth) {
+    if (this.logLevel <= DebugConsole.ERROR_LEVEL)
+        exec(null, null, 'Debug Console', 'log',
+            [ this.processMessage(message, maxDepth), { logLevel: 'ERROR' } ]
+        );
+    else
+        this.winConsole.error(message);
+};
+
+module.exports = new DebugConsole();

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/ios/cordova/plugin/ios/device.js
----------------------------------------------------------------------
diff --git a/lib-platforms/ios/cordova/plugin/ios/device.js b/lib-platforms/ios/cordova/plugin/ios/device.js
new file mode 100644
index 0000000..c6d117b
--- /dev/null
+++ b/lib-platforms/ios/cordova/plugin/ios/device.js
@@ -0,0 +1,30 @@
+/**
+ * this represents the mobile device, and provides properties for inspecting the model, version, UUID of the
+ * phone, etc.
+ * @constructor
+ */
+var exec = require('cordova/exec'),
+    channel = require('cordova/channel');
+
+var Device = function() {
+    this.platform = null;
+    this.version  = null;
+    this.name     = null;
+    this.cordova  = null;
+    this.uuid     = null;
+};
+
+Device.prototype.setInfo = function(info) {
+    try {
+        this.platform = info.platform;
+        this.version = info.version;
+        this.name = info.name;
+        this.cordova = info.gap;
+        this.uuid = info.uuid;
+        channel.onCordovaInfoReady.fire();
+    } catch(e) {
+        alert('Error during device info setting in cordova/plugin/ios/device!');
+    }
+};
+
+module.exports = new Device();

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/ios/cordova/plugin/ios/nativecomm.js
----------------------------------------------------------------------
diff --git a/lib-platforms/ios/cordova/plugin/ios/nativecomm.js b/lib-platforms/ios/cordova/plugin/ios/nativecomm.js
new file mode 100644
index 0000000..938a68c
--- /dev/null
+++ b/lib-platforms/ios/cordova/plugin/ios/nativecomm.js
@@ -0,0 +1,10 @@
+var cordova = require('cordova');
+
+/**
+ * Called by native code to retrieve all queued commands and clear the queue.
+ */
+module.exports = function() {
+  var json = JSON.stringify(cordova.commandQueue);
+  cordova.commandQueue = [];
+  return json;
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/ios/cordova/plugin/ios/notification.js
----------------------------------------------------------------------
diff --git a/lib-platforms/ios/cordova/plugin/ios/notification.js b/lib-platforms/ios/cordova/plugin/ios/notification.js
new file mode 100644
index 0000000..a49567d
--- /dev/null
+++ b/lib-platforms/ios/cordova/plugin/ios/notification.js
@@ -0,0 +1,7 @@
+var Media = require('cordova/plugin/Media');
+
+module.exports = {
+    beep:function(count) {
+        (new Media('beep.wav')).play();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/playbook/cordova/exec.js
----------------------------------------------------------------------
diff --git a/lib-platforms/playbook/cordova/exec.js b/lib-platforms/playbook/cordova/exec.js
new file mode 100644
index 0000000..ff2cbd9
--- /dev/null
+++ b/lib-platforms/playbook/cordova/exec.js
@@ -0,0 +1,56 @@
+/**
+ * Execute a cordova command.  It is up to the native side whether this action
+ * is synchronous or asynchronous.  The native side can return:
+ *      Synchronous: PluginResult object as a JSON string
+ *      Asynchrounous: Empty string ""
+ * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
+ * depending upon the result of the action.
+ *
+ * @param {Function} success    The success callback
+ * @param {Function} fail       The fail callback
+ * @param {String} service      The name of the service to use
+ * @param {String} action       Action to be run in cordova
+ * @param {String[]} [args]     Zero or more arguments to pass to the method
+ */
+
+module.exports = function(success, fail, service, action, args) {
+    try {
+        var playbook = require('cordova/plugin/playbook/manager'),
+            cordova = require('cordova'),
+            v = playbook.exec(success, fail, service, action, args);
+
+        // If status is OK, then return value back to caller
+        if (v.status == cordova.callbackStatus.OK) {
+
+            // If there is a success callback, then call it now with returned value
+            if (success) {
+                try {
+                    success(v.message);
+                }
+                catch (e) {
+                    console.log("Error in success callback: "+cordova.callbackId+" = "+e);
+                }
+
+            }
+            return v.message;
+        } else if (v.status == cordova.callbackStatus.NO_RESULT) {
+
+        } else {
+            // If error, then display error
+            console.log("Error: Status="+v.status+" Message="+v.message);
+
+            // If there is a fail callback, then call it now with returned value
+            if (fail) {
+                try {
+                    fail(v.message);
+                }
+                catch (e) {
+                    console.log("Error in error callback: "+cordova.callbackId+" = "+e);
+                }
+            }
+            return null;
+        }
+    } catch (e) {
+        alert("Error: "+e);
+    }
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/playbook/cordova/platform.js
----------------------------------------------------------------------
diff --git a/lib-platforms/playbook/cordova/platform.js b/lib-platforms/playbook/cordova/platform.js
new file mode 100644
index 0000000..4854f9b
--- /dev/null
+++ b/lib-platforms/playbook/cordova/platform.js
@@ -0,0 +1,16 @@
+module.exports = {
+    id: "playbook",
+    initialize:function() {},
+    objects: {
+        navigator: {
+            children: {
+                device: {
+                    path: "cordova/plugin/playbook/device"
+                }
+            }
+        },
+        device: {
+            path: "cordova/plugin/playbook/device"
+        }
+    }
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/playbook/cordova/plugin/playbook/device.js
----------------------------------------------------------------------
diff --git a/lib-platforms/playbook/cordova/plugin/playbook/device.js b/lib-platforms/playbook/cordova/plugin/playbook/device.js
new file mode 100644
index 0000000..90ec376
--- /dev/null
+++ b/lib-platforms/playbook/cordova/plugin/playbook/device.js
@@ -0,0 +1,23 @@
+var me = {},
+    exec = require('cordova/exec'),
+    channel = require('cordova/channel');
+
+exec(
+    function (device) {
+        me.platform = device.platform;
+        me.version  = device.version;
+        me.name     = device.name;
+        me.uuid     = device.uuid;
+        me.cordova  = device.cordova;
+
+        channel.onCordovaInfoReady.fire();
+    },
+    function (e) {
+        console.log("error initializing cordova: " + e);
+    },
+    "Device",
+    "getDeviceInfo",
+    []
+);
+
+module.exports = me;

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/playbook/cordova/plugin/playbook/manager.js
----------------------------------------------------------------------
diff --git a/lib-platforms/playbook/cordova/plugin/playbook/manager.js b/lib-platforms/playbook/cordova/plugin/playbook/manager.js
new file mode 100644
index 0000000..312a1d2
--- /dev/null
+++ b/lib-platforms/playbook/cordova/plugin/playbook/manager.js
@@ -0,0 +1,285 @@
+var webworks = require('cordova/plugin/webworks/manager'),
+    cordova = require('cordova'),
+    /**
+     * Private list of HTML 5 audio objects, indexed by the Cordova media object ids
+     */
+    audioObjects = {},
+    retInvalidAction = function () {
+        return { "status" : cordova.callbackStatus.INVALID_ACTION, "message" : "Action not found" };
+    },
+    retAsyncCall = function () {
+        return { "status" : cordova.callbackStatus.NO_RESULT, "message" : "WebWorks Is On It" };
+    },
+    cameraAPI = {
+        execute: function (webWorksResult, action, args, win, fail) {
+            if (action === 'takePicture') {
+                blackberry.media.camera.takePicture(win, fail, fail);
+                return retAsyncCall();
+            }
+            else {
+                return retInvalidAction();
+            }
+        }
+    },
+    deviceAPI = {
+        execute: function (webWorksResult, action, args, win, fail) {
+            if (action === 'getDeviceInfo') {
+                return {"status" : cordova.callbackStatus.OK,
+                        "message" : {
+                            "version" : blackberry.system.softwareVersion,
+                            "name" : blackberry.system.model,
+                            "uuid" : blackberry.identity.PIN,
+                            "platform" : "PlayBook",
+                            "cordova" : "1.4.1"
+                        }
+                };
+            }
+            return retInvalidAction();
+        }
+    },
+    loggerAPI = {
+        execute: function (webWorksResult, action, args, win, fail) {
+            if (action === 'log') {
+                console.log(args);
+                return {"status" : cordova.callbackStatus.OK,
+                        "message" : 'Message logged to console: ' + args};
+            }
+            else {
+                return retInvalidAction();
+            }
+        }
+    },
+    mediaAPI = {
+        execute: function (webWorksResult, action, args, win, fail) {
+            if (!args.length) {
+                return {"status" : 9, "message" : "Media Object id was not sent in arguments"};
+            }
+
+            var id = args[0],
+                audio = audioObjects[id],
+                result;
+
+            switch (action) {
+            case 'startPlayingAudio':
+                if (args.length === 1) {
+                    result = {"status" : 9, "message" : "Media source argument not found"};
+
+                }
+
+                if (audio) {
+                    audio.pause();
+                    audioObjects[id] = undefined;
+                }
+
+                audio = audioObjects[id] = new Audio(args[1]);
+                audio.play();
+
+                result = {"status" : 1, "message" : "Audio play started" };
+                break;
+            case 'stopPlayingAudio':
+                if (!audio) {
+                    return {"status" : 2, "message" : "Audio Object has not been initialized"};
+                }
+
+                audio.pause();
+                audioObjects[id] = undefined;
+
+                result = {"status" : 1, "message" : "Audio play stopped" };
+                break;
+            case 'seekToAudio':
+                if (!audio) {
+                    result = {"status" : 2, "message" : "Audio Object has not been initialized"};
+                } else if (args.length === 1) {
+                    result = {"status" : 9, "message" : "Media seek time argument not found"};
+                } else {
+                    try {
+                        audio.currentTime = args[1];
+                    } catch (e) {
+                        console.log('Error seeking audio: ' + e);
+                        return {"status" : 3, "message" : "Error seeking audio: " + e};
+                    }
+
+                    result = {"status" : 1, "message" : "Seek to audio succeeded" };
+                }
+                break;
+            case 'pausePlayingAudio':
+                if (!audio) {
+                    return {"status" : 2, "message" : "Audio Object has not been initialized"};
+                }
+
+                audio.pause();
+
+                result = {"status" : 1, "message" : "Audio paused" };
+                break;
+            case 'getCurrentPositionAudio':
+                if (!audio) {
+                    return {"status" : 2, "message" : "Audio Object has not been initialized"};
+                }
+
+                result = {"status" : 1, "message" : audio.currentTime };
+                break;
+            case 'getDuration':
+                if (!audio) {
+                    return {"status" : 2, "message" : "Audio Object has not been initialized"};
+                }
+
+                result = {"status" : 1, "message" : audio.duration };
+                break;
+            case 'startRecordingAudio':
+                if (args.length <= 1) {
+                    result = {"status" : 9, "message" : "Media start recording, insufficient arguments"};
+                }
+
+                blackberry.media.microphone.record(args[1], win, fail);
+                result = retAsyncCall();
+                break;
+            case 'stopRecordingAudio':
+                break;
+            case 'release':
+                if (audio) {
+                    audioObjects[id] = undefined;
+                    audio.src = undefined;
+                    //delete audio;
+                }
+
+                result = {"status" : 1, "message" : "Media resources released"};
+                break;
+            default:
+                result = retInvalidAction();
+            }
+
+            return result;
+        }
+    },
+    mediaCaptureAPI = {
+        execute: function (webWorksResult, action, args, win, fail) {
+            var limit = args[0],
+                pictureFiles = [],
+                captureMethod;
+
+            function captureCB(filePath) {
+                var mediaFile;
+
+                if (filePath) {
+                    mediaFile = new MediaFile();
+                    mediaFile.fullPath = filePath;
+                    pictureFiles.push(mediaFile);
+                }
+
+                if (limit > 0) {
+                    limit--;
+                    blackberry.media.camera[captureMethod](win, fail, fail);
+                    return;
+                }
+
+                win(pictureFiles);
+
+                return retAsyncCall();
+            }
+
+            switch (action) {
+                case 'getSupportedAudioModes':
+                case 'getSupportedImageModes':
+                case 'getSupportedVideoModes':
+                    return {"status": cordova.callbackStatus.OK, "message": []};
+                case 'captureImage':
+                    captureMethod = "takePicture";
+                    captureCB();
+                    break;
+                case 'captureVideo':
+                    captureMethod = "takeVideo";
+                    captureCB();
+                    break;
+                case 'captureAudio':
+                    return {"status": cordova.callbackStatus.INVALID_ACTION, "message": "captureAudio is not currently supported"};
+            }
+
+            return retAsyncCall();
+        }
+    },
+    networkAPI = {
+        execute: function (webWorksResult, action, args, win, fail) {
+            if (action !== 'getConnectionInfo') {
+                return retInvalidAction();
+            }
+
+            var connectionType = require("cordova/plugin/Connection").NONE,
+                eventType = "offline",
+                callbackID,
+                request;
+
+            /**
+             * For PlayBooks, we currently only have WiFi connections, so return WiFi if there is
+             * any access at all.
+             * TODO: update if/when PlayBook gets other connection types...
+             */
+            if (blackberry.system.hasDataCoverage()) {
+                connectionType = require("cordova/plugin/Connection").WIFI;
+                eventType = "online";
+            }
+
+            //Register an event handler for the networkChange event
+            callbackID = blackberry.events.registerEventHandler("networkChange", win);
+
+            //pass our callback id down to our network extension
+            request = new blackberry.transport.RemoteFunctionCall("org/apache/cordova/getConnectionInfo");
+            request.addParam("networkStatusChangedID", callbackID);
+            request.makeSyncCall();
+
+            return { "status": cordova.callbackStatus.OK, "message": {"type": connectionType, "event": eventType } };
+        }
+    },
+    notificationAPI = {
+        execute: function (webWorksResult, action, args, win, fail) {
+            if (args.length !== 3) {
+              return {"status" : 9, "message" : "Notification action - " + action + " arguments not found"};
+
+            }
+
+            //Unpack and map the args
+            var msg = args[0],
+                title = args[1],
+                btnLabel = args[2],
+                btnLabels;
+
+            switch (action) {
+            case 'alert':
+                blackberry.ui.dialog.customAskAsync.apply(this, [ msg, [ btnLabel ], win, { "title" : title } ]);
+                return retAsyncCall();
+            case 'confirm':
+                btnLabels = btnLabel.split(",");
+                blackberry.ui.dialog.customAskAsync.apply(this, [msg, btnLabels, win, {"title" : title} ]);
+                return retAsyncCall();
+            }
+            return retInvalidAction();
+
+        }
+    },
+    plugins = {
+        'Camera' : cameraAPI,
+        'Device' : deviceAPI,
+        'Logger' : loggerAPI,
+        'Media' : mediaAPI,
+        'MediaCapture' : mediaCaptureAPI,
+        'Network Status' : networkAPI,
+        'Notification' : notificationAPI
+    };
+
+module.exports = {
+    exec: function (win, fail, clazz, action, args) {
+        var wwResult = webworks.exec(win, fail, clazz, action, args);
+
+        //We got a sync result or a not found from WW that we can pass on to get a native mixin
+        //For async calls there's nothing to do
+        if ((wwResult.status === cordova.callbackStatus.OK ||
+          wwResult.status === cordova.callbackStatus.CLASS_NOT_FOUND_EXCEPTION) &&
+          plugins[clazz]) {
+            return plugins[clazz].execute(wwResult.message, action, args, win, fail);
+        }
+
+        return wwResult;
+    },
+    resume: function () {},
+    pause: function () {},
+    destroy: function () {}
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/test/cordova/exec.js
----------------------------------------------------------------------
diff --git a/lib-platforms/test/cordova/exec.js b/lib-platforms/test/cordova/exec.js
new file mode 100644
index 0000000..a5d1a69
--- /dev/null
+++ b/lib-platforms/test/cordova/exec.js
@@ -0,0 +1 @@
+module.exports = jasmine.createSpy();

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/webworks/cordova/plugin/webworks/manager.js
----------------------------------------------------------------------
diff --git a/lib-platforms/webworks/cordova/plugin/webworks/manager.js b/lib-platforms/webworks/cordova/plugin/webworks/manager.js
new file mode 100644
index 0000000..7ea6592
--- /dev/null
+++ b/lib-platforms/webworks/cordova/plugin/webworks/manager.js
@@ -0,0 +1,14 @@
+// Define JavaScript plugin implementations that are common across
+// WebWorks platforms (phone/tablet).
+var plugins = {},
+    cordova = require('cordova');
+
+module.exports = {
+    exec: function (win, fail, clazz, action, args) {
+        if (plugins[clazz]) {
+            return plugins[clazz].execute(action, args, win, fail);
+        }
+
+        return {"status" : cordova.callbackStatus.CLASS_NOT_FOUND_EXCEPTION, "message" : "Class " + clazz + " cannot be found"};
+    }
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/f3acff6d/lib-platforms/wp7/cordova/exec.js
----------------------------------------------------------------------
diff --git a/lib-platforms/wp7/cordova/exec.js b/lib-platforms/wp7/cordova/exec.js
new file mode 100644
index 0000000..78eef40
--- /dev/null
+++ b/lib-platforms/wp7/cordova/exec.js
@@ -0,0 +1,57 @@
+var cordova = require('cordova');
+
+/**
+ * Execute a cordova command.  It is up to the native side whether this action
+ * is synchronous or asynchronous.  The native side can return:
+ *      Synchronous: PluginResult object as a JSON string
+ *      Asynchrounous: Empty string ""
+ * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
+ * depending upon the result of the action.
+ *
+ * @param {Function} success    The success callback
+ * @param {Function} fail       The fail callback
+ * @param {String} service      The name of the service to use
+ * @param {String} action       Action to be run in cordova
+ * @param {String[]} [args]     Zero or more arguments to pass to the method
+ */
+
+module.exports = function(success, fail, service, action, args) {
+    var callbackId = service + cordova.callbackId++;
+    if (typeof success == "function" || typeof fail == "function") {
+        cordova.callbacks[callbackId] = {success:success, fail:fail};
+    }
+    // generate a new command string, ex. DebugConsole/log/DebugConsole23/{"message":"wtf dude?"}
+     var command = service + "/" + action + "/" + callbackId + "/" + JSON.stringify(args);
+     // pass it on to Notify
+     window.external.Notify(command);
+};
+
+// TODO: is this what native side invokes?
+// if so pluginize under plugin/wp7
+cordovaCommandResult = function(status,callbackId,args,cast) {
+    if(status === "backbutton") {
+
+        cordova.fireEvent(document,"backbutton");
+        return "true";
+
+    } else if(status === "resume") {
+
+        cordova.onResume.fire();
+        return "true";
+
+    } else if(status === "pause") {
+
+        cordova.onPause.fire();
+        return "true";  
+    }
+    
+    var safeStatus = parseInt(status, 10);
+    if(safeStatus === cordova.callbackStatus.NO_RESULT ||
+       safeStatus === cordova.callbackStatus.OK) {
+        cordova.CallbackSuccess(callbackId,args,cast);
+    }
+    else
+    {
+        cordova.CallbackError(callbackId,args,cast);
+    }
+};