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/22 13:50:23 UTC

[4/12] 2nd try at file refactoring

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/76f64673/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
deleted file mode 100644
index 312a1d2..0000000
--- a/lib-platforms/playbook/cordova/plugin/playbook/manager.js
+++ /dev/null
@@ -1,285 +0,0 @@
-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/76f64673/lib-platforms/test/cordova/exec.js
----------------------------------------------------------------------
diff --git a/lib-platforms/test/cordova/exec.js b/lib-platforms/test/cordova/exec.js
deleted file mode 100644
index a5d1a69..0000000
--- a/lib-platforms/test/cordova/exec.js
+++ /dev/null
@@ -1 +0,0 @@
-module.exports = jasmine.createSpy();

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/76f64673/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
deleted file mode 100644
index 7ea6592..0000000
--- a/lib-platforms/webworks/cordova/plugin/webworks/manager.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// 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/76f64673/lib-platforms/wp7/cordova/exec.js
----------------------------------------------------------------------
diff --git a/lib-platforms/wp7/cordova/exec.js b/lib-platforms/wp7/cordova/exec.js
deleted file mode 100644
index 78eef40..0000000
--- a/lib-platforms/wp7/cordova/exec.js
+++ /dev/null
@@ -1,57 +0,0 @@
-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);
-    }
-};

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

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/76f64673/lib-platforms/wp7/cordova/plugin/wp7/device.js
----------------------------------------------------------------------
diff --git a/lib-platforms/wp7/cordova/plugin/wp7/device.js b/lib-platforms/wp7/cordova/plugin/wp7/device.js
deleted file mode 100644
index b51fe93..0000000
--- a/lib-platforms/wp7/cordova/plugin/wp7/device.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * this represents the mobile device, and provides properties for inspecting the model, version, UUID of the
- * phone, etc.
- * @constructor
- */
-var Device = function() 
-{
-    this.platform = null;
-    this.version  = null;
-    this.name     = null;
-    this.phonegap = null;
-    this.uuid     = null;
-    try {      
-	this.platform = DeviceInfo.platform;
-	this.version  = DeviceInfo.version;
-	this.name     = DeviceInfo.name;
-	this.phonegap = DeviceInfo.gap;
-	this.uuid     = DeviceInfo.uuid;
-    } 
-    catch(e) {
-        // TODO: 
-    }
-    this.available = PhoneGap.available = !!this.uuid;
-};
-
-module.exports = new Device();

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/76f64673/lib-scripts/bootstrap-errgen.js
----------------------------------------------------------------------
diff --git a/lib-scripts/bootstrap-errgen.js b/lib-scripts/bootstrap-errgen.js
deleted file mode 100644
index cc479e8..0000000
--- a/lib-scripts/bootstrap-errgen.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-require('cordova/channel').onNativeReady.fire()
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/76f64673/lib-scripts/bootstrap-playbook.js
----------------------------------------------------------------------
diff --git a/lib-scripts/bootstrap-playbook.js b/lib-scripts/bootstrap-playbook.js
deleted file mode 100644
index 19cf867..0000000
--- a/lib-scripts/bootstrap-playbook.js
+++ /dev/null
@@ -1 +0,0 @@
-require('cordova/channel').onNativeReady.fire();

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/76f64673/lib-scripts/bootstrap.js
----------------------------------------------------------------------
diff --git a/lib-scripts/bootstrap.js b/lib-scripts/bootstrap.js
deleted file mode 100755
index 73875ee..0000000
--- a/lib-scripts/bootstrap.js
+++ /dev/null
@@ -1,69 +0,0 @@
-(function (context) {
-    var channel = require("cordova/channel"),
-        _self = {
-            boot: function () {
-                //---------------
-                // Event handling
-                //---------------
-
-                /**
-                 * Listen for DOMContentLoaded and notify our channel subscribers.
-                 */
-                document.addEventListener('DOMContentLoaded', function() {
-                    channel.onDOMContentLoaded.fire();
-                }, false);
-                if (document.readyState == 'complete') {
-                  channel.onDOMContentLoaded.fire();
-                }
-
-                /**
-                 * Create all cordova objects once page has fully loaded and native side is ready.
-                 */
-                channel.join(function() {
-                    var builder = require('cordova/builder'),
-                        base = require('cordova/common'),
-                        platform = require('cordova/platform');
-
-                    // Drop the common globals into the window object, but be nice and don't overwrite anything.
-                    builder.build(base.objects).intoButDontClobber(window);
-
-                    // Drop the platform-specific globals into the window object
-                    // and clobber any existing object.
-                    builder.build(platform.objects).intoAndClobber(window);
-
-                    // Merge the platform-specific overrides/enhancements into
-                    // the window object.
-                    if (typeof platform.merges !== 'undefined') {
-                        builder.build(platform.merges).intoAndMerge(window);
-                    }
-
-                    // Call the platform-specific initialization
-                    platform.initialize();
-
-                    // Fire event to notify that all objects are created
-                    channel.onCordovaReady.fire();
-
-                    // Fire onDeviceReady event once all constructors have run and
-                    // cordova info has been received from native side.
-                    channel.join(function() {
-                        channel.onDeviceReady.fire();
-
-                        // Fire the onresume event, since first one happens before JavaScript is loaded
-                        channel.onResume.fire();
-                    }, channel.deviceReadyChannelsArray);
-                    
-                }, [ channel.onDOMContentLoaded, channel.onNativeReady ]);
-            }
-        };
-        
-    // boot up once native side is ready
-    channel.onNativeReady.subscribeOnce(_self.boot);
-
-    // _nativeReady is global variable that the native side can set
-    // to signify that the native code is ready. It is a global since
-    // it may be called before any cordova JS is ready.
-    if (window._nativeReady) {
-        channel.onNativeReady.fire();
-    }
-
-}(window));

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/76f64673/lib-scripts/require.js
----------------------------------------------------------------------
diff --git a/lib-scripts/require.js b/lib-scripts/require.js
deleted file mode 100644
index a92249d..0000000
--- a/lib-scripts/require.js
+++ /dev/null
@@ -1,43 +0,0 @@
-var require,
-    define;
-
-(function () {
-    var modules = {};
-
-    function build(module) {
-        var factory = module.factory;
-        module.exports = {};
-        delete module.factory;
-        factory(require, module.exports, module);
-        return module.exports;
-    }
-
-    require = function (id) {
-        if (!modules[id]) {
-            throw "module " + id + " not found";
-        }
-        return modules[id].factory ? build(modules[id]) : modules[id].exports;
-    };
-
-    define = function (id, factory) {
-        if (modules[id]) {
-            throw "module " + id + " already defined";
-        }
-
-        modules[id] = {
-            id: id,
-            factory: factory
-        };
-    };
-
-    define.remove = function (id) {
-        delete modules[id];
-    };
-
-})();
-
-//Export for use in node
-if (typeof module === "object" && typeof require === "function") {
-    module.exports.require = require;
-    module.exports.define = define;
-}

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/76f64673/lib/android/exec.js
----------------------------------------------------------------------
diff --git a/lib/android/exec.js b/lib/android/exec.js
new file mode 100644
index 0000000..b3410bb
--- /dev/null
+++ b/lib/android/exec.js
@@ -0,0 +1,82 @@
+/**
+ * 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 cordova = require('cordova');
+
+module.exports = function(success, fail, service, action, args) {
+  try {
+    var callbackId = service + cordova.callbackId++;
+    if (success || fail) {
+        cordova.callbacks[callbackId] = {success:success, fail:fail};
+    }
+
+    var r = prompt(JSON.stringify(args), "gap:"+JSON.stringify([service, action, callbackId, true]));
+
+    // If a result was returned
+    if (r.length > 0) {
+        eval("var v="+r+";");
+
+        // 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: " + callbackId  + " = " + e);
+                }
+
+                // Clear callback if not expecting any more results
+                if (!v.keepCallback) {
+                    delete cordova.callbacks[callbackId];
+                }
+            }
+            return v.message;
+        }
+
+        // If no result
+        else if (v.status === cordova.callbackStatus.NO_RESULT) {
+            // Clear callback if not expecting any more results
+            if (!v.keepCallback) {
+                delete cordova.callbacks[callbackId];
+            }
+        }
+
+        // If error, then display error
+        else {
+            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 (e1) {
+                    console.log("Error in error callback: "+callbackId+" = "+e1);
+                }
+
+                // Clear callback if not expecting any more results
+                if (!v.keepCallback) {
+                    delete cordova.callbacks[callbackId];
+                }
+            }
+            return null;
+        }
+    }
+  } catch (e2) {
+    console.log("Error: "+e2);
+  }
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/76f64673/lib/android/platform.js
----------------------------------------------------------------------
diff --git a/lib/android/platform.js b/lib/android/platform.js
new file mode 100644
index 0000000..6c71820
--- /dev/null
+++ b/lib/android/platform.js
@@ -0,0 +1,131 @@
+module.exports = {
+    id: "android",
+    initialize:function() {
+        var channel = require("cordova/channel"),
+            cordova = require('cordova'),
+            callback = require('cordova/plugin/android/callback'),
+            polling = require('cordova/plugin/android/polling'),
+            exec = require('cordova/exec');
+
+        channel.onDestroy.subscribe(function() {
+            cordova.shuttingDown = true;
+        });
+
+        // Start listening for XHR callbacks
+        // Figure out which bridge approach will work on this Android
+        // device: polling or XHR-based callbacks
+        setTimeout(function() {
+            if (cordova.UsePolling) {
+                polling();
+            }
+            else {
+                var isPolling = prompt("usePolling", "gap_callbackServer:");
+                cordova.UsePolling = isPolling;
+                if (isPolling == "true") {
+                    cordova.UsePolling = true;
+                    polling();
+                } else {
+                    cordova.UsePolling = false;
+                    callback();
+                }
+            }
+        }, 1);
+
+        // Inject a listener for the backbutton on the document.
+        var backButtonChannel = cordova.addDocumentEventHandler('backbutton', {
+            onSubscribe:function() {
+                // If we just attached the first handler, let native know we need to override the back button.
+                if (this.numHandlers === 1) {
+                    exec(null, null, "App", "overrideBackbutton", [true]);
+                }
+            },
+            onUnsubscribe:function() {
+                // If we just detached the last handler, let native know we no longer override the back button.
+                if (this.numHandlers === 0) {
+                    exec(null, null, "App", "overrideBackbutton", [false]);
+                }
+            }
+        });
+
+        // Add hardware MENU and SEARCH button handlers
+        cordova.addDocumentEventHandler('menubutton');
+        cordova.addDocumentEventHandler('searchbutton');
+
+        // Figure out if we need to shim-in localStorage and WebSQL
+        // support from the native side.
+        var storage = require('cordova/plugin/android/storage');
+
+        // First patch WebSQL if necessary
+        if (typeof window.openDatabase == 'undefined') {
+            // Not defined, create an openDatabase function for all to use!
+            window.openDatabase = storage.openDatabase;
+        } else {
+            // Defined, but some Android devices will throw a SECURITY_ERR -
+            // so we wrap the whole thing in a try-catch and shim in our own
+            // if the device has Android bug 16175.
+            var originalOpenDatabase = window.openDatabase;
+            window.openDatabase = function(name, version, desc, size) {
+                var db = null;
+                try {
+                    db = originalOpenDatabase(name, version, desc, size);
+                } 
+                catch (ex) {
+                    db = null;
+                }
+
+                if (db === null) {
+                    return storage.openDatabase(name, version, desc, size);
+                }
+                else {
+                    return db;
+                }
+              
+            };
+        }
+
+        // Patch localStorage if necessary
+        if (typeof window.localStorage == 'undefined' || window.localStorage === null) {
+            window.localStorage = new storage.CupCakeLocalStorage();
+        }
+
+        // Let native code know we are all done on the JS side.
+        // Native code will then un-hide the WebView.
+        channel.join(function() {
+            prompt("", "gap_init:");
+        }, [channel.onCordovaReady]);
+    },
+    objects: {
+        cordova: {
+            children: {
+                JSCallback:{
+                    path:"cordova/plugin/android/callback"
+                },
+                JSCallbackPolling:{
+                    path:"cordova/plugin/android/polling"
+                }
+            }
+        },
+        navigator: {
+            children: {
+                app:{
+                    path: "cordova/plugin/android/app"
+                }
+            }
+        },
+        device:{
+            path: "cordova/plugin/android/device"
+        },
+        File: { // exists natively on Android WebView, override
+            path: "cordova/plugin/File"
+        },
+        FileReader: { // exists natively on Android WebView, override
+            path: "cordova/plugin/FileReader"
+        },
+        FileError: { //exists natively on Android WebView on Android 4.x
+            path: "cordova/plugin/FileError"
+        },
+        MediaError: { // exists natively on Android WebView on Android 4.x
+            path: "cordova/plugin/MediaError"
+        }
+    }
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/76f64673/lib/android/plugin/android/app.js
----------------------------------------------------------------------
diff --git a/lib/android/plugin/android/app.js b/lib/android/plugin/android/app.js
new file mode 100644
index 0000000..f858829
--- /dev/null
+++ b/lib/android/plugin/android/app.js
@@ -0,0 +1,71 @@
+var exec = require('cordova/exec');
+
+module.exports = {
+  /**
+   * Clear the resource cache.
+   */
+  clearCache:function() {
+    exec(null, null, "App", "clearCache", []);
+  },
+
+  /**
+   * Load the url into the webview or into new browser instance.
+   *
+   * @param url           The URL to load
+   * @param props         Properties that can be passed in to the activity:
+   *      wait: int                           => wait msec before loading URL
+   *      loadingDialog: "Title,Message"      => display a native loading dialog
+   *      loadUrlTimeoutValue: int            => time in msec to wait before triggering a timeout error
+   *      clearHistory: boolean              => clear webview history (default=false)
+   *      openExternal: boolean              => open in a new browser (default=false)
+   *
+   * Example:
+   *      navigator.app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000});
+   */
+  loadUrl:function(url, props) {
+    exec(null, null, "App", "loadUrl", [url, props]);
+  },
+
+  /**
+   * Cancel loadUrl that is waiting to be loaded.
+   */
+  cancelLoadUrl:function() {
+    exec(null, null, "App", "cancelLoadUrl", []);
+  },
+
+  /**
+   * 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() {
+    exec(null, null, "App", "backHistory", []);
+  },
+
+  /**
+   * Override the default behavior of the Android back button.
+   * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired.
+   *
+   * Note: The user should not have to call this method.  Instead, when the user
+   *       registers for the "backbutton" event, this is automatically done.
+   *
+   * @param override		T=override, F=cancel override
+   */
+  overrideBackbutton:function(override) {
+    exec(null, null, "App", "overrideBackbutton", [override]);
+  },
+
+  /**
+   * Exit and terminate the application.
+   */
+  exitApp:function() {
+    return exec(null, null, "App", "exitApp", []);
+  } 
+};

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/76f64673/lib/android/plugin/android/callback.js
----------------------------------------------------------------------
diff --git a/lib/android/plugin/android/callback.js b/lib/android/plugin/android/callback.js
new file mode 100644
index 0000000..d5768a7
--- /dev/null
+++ b/lib/android/plugin/android/callback.js
@@ -0,0 +1,85 @@
+var port = null,
+    token = null,
+    cordova = require('cordova'),
+    polling = require('cordova/plugin/android/polling'),
+    callback = function() {
+      // Exit if shutting down app
+      if (cordova.shuttingDown) {
+          return;
+      }
+
+      // If polling flag was changed, start using polling from now on
+      if (cordova.UsePolling) {
+          polling();
+          return;
+      }
+
+      var xmlhttp = new XMLHttpRequest();
+
+      // Callback function when XMLHttpRequest is ready
+      xmlhttp.onreadystatechange=function(){
+          if(xmlhttp.readyState === 4){
+
+              // Exit if shutting down app
+              if (cordova.shuttingDown) {
+                  return;
+              }
+
+              // If callback has JavaScript statement to execute
+              if (xmlhttp.status === 200) {
+
+                  // Need to url decode the response
+                  var msg = decodeURIComponent(xmlhttp.responseText);
+                  setTimeout(function() {
+                      try {
+                          var t = eval(msg);
+                      }
+                      catch (e) {
+                          // If we're getting an error here, seeing the message will help in debugging
+                          console.log("JSCallback: Message from Server: " + msg);
+                          console.log("JSCallback Error: "+e);
+                      }
+                  }, 1);
+                  setTimeout(callback, 1);
+              }
+
+              // If callback ping (used to keep XHR request from timing out)
+              else if (xmlhttp.status === 404) {
+                  setTimeout(callback, 10);
+              }
+
+              // If security error
+              else if (xmlhttp.status === 403) {
+                  console.log("JSCallback Error: Invalid token.  Stopping callbacks.");
+              }
+
+              // If server is stopping
+              else if (xmlhttp.status === 503) {
+                  console.log("JSCallback Server Closed: Stopping callbacks.");
+              }
+
+              // If request wasn't GET
+              else if (xmlhttp.status === 400) {
+                  console.log("JSCallback Error: Bad request.  Stopping callbacks.");
+              }
+
+              // If error, revert to polling
+              else {
+                  console.log("JSCallback Error: Request failed.");
+                  cordova.UsePolling = true;
+                  polling();
+              }
+          }
+      };
+
+      if (port === null) {
+          port = prompt("getPort", "gap_callbackServer:");
+      }
+      if (token === null) {
+          token = prompt("getToken", "gap_callbackServer:");
+      }
+      xmlhttp.open("GET", "http://127.0.0.1:"+port+"/"+token , true);
+      xmlhttp.send();
+};
+
+module.exports = callback;

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/76f64673/lib/android/plugin/android/device.js
----------------------------------------------------------------------
diff --git a/lib/android/plugin/android/device.js b/lib/android/plugin/android/device.js
new file mode 100644
index 0000000..1defbbe
--- /dev/null
+++ b/lib/android/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/76f64673/lib/android/plugin/android/polling.js
----------------------------------------------------------------------
diff --git a/lib/android/plugin/android/polling.js b/lib/android/plugin/android/polling.js
new file mode 100644
index 0000000..36b8e86
--- /dev/null
+++ b/lib/android/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/76f64673/lib/android/plugin/android/storage.js
----------------------------------------------------------------------
diff --git a/lib/android/plugin/android/storage.js b/lib/android/plugin/android/storage.js
new file mode 100644
index 0000000..000612b
--- /dev/null
+++ b/lib/android/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/76f64673/lib/blackberry/exec.js
----------------------------------------------------------------------
diff --git a/lib/blackberry/exec.js b/lib/blackberry/exec.js
new file mode 100644
index 0000000..a5fb81f
--- /dev/null
+++ b/lib/blackberry/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/76f64673/lib/blackberry/platform.js
----------------------------------------------------------------------
diff --git a/lib/blackberry/platform.js b/lib/blackberry/platform.js
new file mode 100644
index 0000000..e7fa2e3
--- /dev/null
+++ b/lib/blackberry/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/76f64673/lib/blackberry/plugin/blackberry/DirectoryEntry.js
----------------------------------------------------------------------
diff --git a/lib/blackberry/plugin/blackberry/DirectoryEntry.js b/lib/blackberry/plugin/blackberry/DirectoryEntry.js
new file mode 100644
index 0000000..76acaf7
--- /dev/null
+++ b/lib/blackberry/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/76f64673/lib/blackberry/plugin/blackberry/Entry.js
----------------------------------------------------------------------
diff --git a/lib/blackberry/plugin/blackberry/Entry.js b/lib/blackberry/plugin/blackberry/Entry.js
new file mode 100644
index 0000000..cc9626d
--- /dev/null
+++ b/lib/blackberry/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/76f64673/lib/blackberry/plugin/blackberry/app.js
----------------------------------------------------------------------
diff --git a/lib/blackberry/plugin/blackberry/app.js b/lib/blackberry/plugin/blackberry/app.js
new file mode 100644
index 0000000..6c58e30
--- /dev/null
+++ b/lib/blackberry/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/76f64673/lib/blackberry/plugin/blackberry/device.js
----------------------------------------------------------------------
diff --git a/lib/blackberry/plugin/blackberry/device.js b/lib/blackberry/plugin/blackberry/device.js
new file mode 100644
index 0000000..42a0647
--- /dev/null
+++ b/lib/blackberry/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/76f64673/lib/blackberry/plugin/blackberry/manager.js
----------------------------------------------------------------------
diff --git a/lib/blackberry/plugin/blackberry/manager.js b/lib/blackberry/plugin/blackberry/manager.js
new file mode 100644
index 0000000..ef353bb
--- /dev/null
+++ b/lib/blackberry/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/76f64673/lib/blackberry/plugin/blackberry/notification.js
----------------------------------------------------------------------
diff --git a/lib/blackberry/plugin/blackberry/notification.js b/lib/blackberry/plugin/blackberry/notification.js
new file mode 100644
index 0000000..83bc77c
--- /dev/null
+++ b/lib/blackberry/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/76f64673/lib/bootstrap.js
----------------------------------------------------------------------
diff --git a/lib/bootstrap.js b/lib/bootstrap.js
deleted file mode 100755
index 73875ee..0000000
--- a/lib/bootstrap.js
+++ /dev/null
@@ -1,69 +0,0 @@
-(function (context) {
-    var channel = require("cordova/channel"),
-        _self = {
-            boot: function () {
-                //---------------
-                // Event handling
-                //---------------
-
-                /**
-                 * Listen for DOMContentLoaded and notify our channel subscribers.
-                 */
-                document.addEventListener('DOMContentLoaded', function() {
-                    channel.onDOMContentLoaded.fire();
-                }, false);
-                if (document.readyState == 'complete') {
-                  channel.onDOMContentLoaded.fire();
-                }
-
-                /**
-                 * Create all cordova objects once page has fully loaded and native side is ready.
-                 */
-                channel.join(function() {
-                    var builder = require('cordova/builder'),
-                        base = require('cordova/common'),
-                        platform = require('cordova/platform');
-
-                    // Drop the common globals into the window object, but be nice and don't overwrite anything.
-                    builder.build(base.objects).intoButDontClobber(window);
-
-                    // Drop the platform-specific globals into the window object
-                    // and clobber any existing object.
-                    builder.build(platform.objects).intoAndClobber(window);
-
-                    // Merge the platform-specific overrides/enhancements into
-                    // the window object.
-                    if (typeof platform.merges !== 'undefined') {
-                        builder.build(platform.merges).intoAndMerge(window);
-                    }
-
-                    // Call the platform-specific initialization
-                    platform.initialize();
-
-                    // Fire event to notify that all objects are created
-                    channel.onCordovaReady.fire();
-
-                    // Fire onDeviceReady event once all constructors have run and
-                    // cordova info has been received from native side.
-                    channel.join(function() {
-                        channel.onDeviceReady.fire();
-
-                        // Fire the onresume event, since first one happens before JavaScript is loaded
-                        channel.onResume.fire();
-                    }, channel.deviceReadyChannelsArray);
-                    
-                }, [ channel.onDOMContentLoaded, channel.onNativeReady ]);
-            }
-        };
-        
-    // boot up once native side is ready
-    channel.onNativeReady.subscribeOnce(_self.boot);
-
-    // _nativeReady is global variable that the native side can set
-    // to signify that the native code is ready. It is a global since
-    // it may be called before any cordova JS is ready.
-    if (window._nativeReady) {
-        channel.onNativeReady.fire();
-    }
-
-}(window));

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/76f64673/lib/bootstrap/errgen.js
----------------------------------------------------------------------
diff --git a/lib/bootstrap/errgen.js b/lib/bootstrap/errgen.js
deleted file mode 100644
index cc479e8..0000000
--- a/lib/bootstrap/errgen.js
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-require('cordova/channel').onNativeReady.fire()
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/76f64673/lib/bootstrap/playbook.js
----------------------------------------------------------------------
diff --git a/lib/bootstrap/playbook.js b/lib/bootstrap/playbook.js
deleted file mode 100644
index 19cf867..0000000
--- a/lib/bootstrap/playbook.js
+++ /dev/null
@@ -1 +0,0 @@
-require('cordova/channel').onNativeReady.fire();