Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/incubator-cordova-mobile-spec
diff --git a/autotest/index.html b/autotest/index.html
index 70a1eeb..48fe722 100755
--- a/autotest/index.html
+++ b/autotest/index.html
@@ -28,6 +28,7 @@
     <a href="pages/notification.html" class="btn large" style="width:100%;">Run Notification Tests</a>
     <a href="pages/platform.html" class="btn large" style="width:100%;">Run Platform Tests</a>
     <a href="pages/storage.html" class="btn large" style="width:100%;">Run Storage Tests</a>
+    <a href="pages/bridge.html" class="btn large" style="width:100%;">Run Bridge Tests</a>
 
     <h2> </h2><div class="backBtn" onclick="backHome();">Back</div>
   </body>
diff --git a/autotest/pages/bridge.html b/autotest/pages/bridge.html
new file mode 100644
index 0000000..56d2d59
--- /dev/null
+++ b/autotest/pages/bridge.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <title>Cordova: Device API Specs</title>
+
+  <meta name="viewport" content="width=device-width, height=device-height, user-scalable=yes, initial-scale=1.0;" />
+  <!-- Load jasmine -->
+  <link href="../jasmine.css" rel="stylesheet"/>
+  <script type="text/javascript" src="../jasmine.js"></script>
+  <script type="text/javascript" src="../html/HtmlReporterHelpers.js"></script>
+  <script type="text/javascript" src="../html/HtmlReporter.js"></script>
+  <script type="text/javascript" src="../html/ReporterView.js"></script>
+  <script type="text/javascript" src="../html/SpecView.js"></script>
+  <script type="text/javascript" src="../html/SuiteView.js"></script>
+  <script type="text/javascript" src="../html/TrivialReporter.js"></script>
+
+  <!-- Source -->
+  <script type="text/javascript" src="../../cordova.js"></script>
+
+  <!-- Load Test Runner -->
+  <script type="text/javascript" src="../test-runner.js"></script>
+
+  <!-- Tests -->
+  <script type="text/javascript" src="../tests/bridge.tests.js"></script>
+
+  <script type="text/javascript">
+    document.addEventListener('deviceready', function () {
+      var jasmineEnv = jasmine.getEnv();
+      jasmineEnv.updateInterval = 1000;
+
+      var htmlReporter = new jasmine.HtmlReporter();
+
+      jasmineEnv.addReporter(htmlReporter);
+
+      jasmineEnv.specFilter = function(spec) {
+        return htmlReporter.specFilter(spec);
+      };
+
+      jasmineEnv.execute();
+    }, false);
+  </script>
+</head>
+
+<body>
+  <a href="javascript:" class="backBtn" onclick="backHome();">Back</a>
+</body>
+</html>
+
diff --git a/autotest/tests/bridge.tests.js b/autotest/tests/bridge.tests.js
new file mode 100644
index 0000000..5a700e0
--- /dev/null
+++ b/autotest/tests/bridge.tests.js
@@ -0,0 +1,176 @@
+/* This test requires some extra code to run, because we want benchmark results */
+
+/*
+ It's never going to be OVER 9000
+ http://youtu.be/SiMHTK15Pik 
+*/
+var FENCEPOST = 9000;
+
+var exec = cordova.require('cordova/exec');
+
+var echo = cordova.require('cordova/plugin/echo'),
+            startTime = +new Date,
+            callCount = 0,
+            durationMs = 1000,
+            asyncEcho = true,
+            useSetTimeout = true,
+            payloadSize = 5,
+            callsPerSecond = 0,
+            completeSpy = null, 
+            payload = new Array(payloadSize * 10 + 1).join('012\n\n 6789');
+
+var vanillaWin = function(result) {
+            callCount++;
+            if (result != payload) {
+                console.log('Wrong echo data!');
+            }
+            var elapsedMs = new Date - startTime;
+            if (elapsedMs < durationMs) {
+                if (useSetTimeout) {
+                    setTimeout(echoMessage, 0);
+                } else {
+                    echoMessage();
+                }
+            } else {
+               callsPerSecond = callCount * 1000 / elapsedMs;
+               console.log('Calls per second: ' + callsPerSecond);
+               if(completeSpy != null)
+                completeSpy();
+            }
+        }
+
+var reset = function()
+{
+            startTime = +new Date,
+            callCount = 0,
+            durationMs = 1000,
+            asyncEcho = true,
+            useSetTimeout = true,
+            payloadSize = 5,
+            callsPerSecond = 0,
+            completeSpy = null,
+            payload = new Array(payloadSize * 10 + 1).join('012\n\n 6789');
+}
+
+var echoMessage = function()
+{
+    echo(vanillaWin, fail, payload, asyncEcho);
+}
+
+var fail = jasmine.createSpy();
+
+describe('The JS to Native Bridge', function() {
+
+    //Run the reset
+    beforeEach(function() {
+        reset();
+    });
+
+    it('should work with prompt', function() {
+        exec.setJsToNativeBridgeMode(0);
+        var win = jasmine.createSpy().andCallFake(function(r) {
+            vanillaWin(r);
+        });
+        completeSpy = jasmine.createSpy();
+        runs(function() { 
+            echo(win, fail, payload, asyncEcho);
+        });
+        waitsFor(function() { return completeSpy.wasCalled; }, "never completed", durationMs * 2);
+        runs(function() { 
+            expect(callsPerSecond).toBeGreaterThan(FENCEPOST);
+        });
+    });
+    it("should work with jsObject", function() {
+        exec.setJsToNativeBridgeMode(1);
+        var win = jasmine.createSpy().andCallFake(function(r) {
+            vanillaWin(r);
+        });
+        completeSpy = jasmine.createSpy();
+        runs(function() { 
+            echo(win, fail, payload, asyncEcho);
+        });
+        waitsFor(function() { return completeSpy.wasCalled; }, "never completed", durationMs * 2);
+        runs(function() { 
+            expect(callsPerSecond).toBeGreaterThan(FENCEPOST);
+        });
+    });
+});
+
+describe("The Native to JS Bridge", function() {
+
+    //Run the reset
+    beforeEach(function() {
+        reset();
+    });
+
+    it("should work with polling", function() {
+       exec.setNativeToJsBridgeMode(0);
+        var win = jasmine.createSpy().andCallFake(function(r) {
+            vanillaWin(r);
+        });
+        completeSpy = jasmine.createSpy();
+        runs(function() { 
+            echo(win, fail, payload, asyncEcho);
+        });
+        waitsFor(function() { return completeSpy.wasCalled; }, "never completed", durationMs * 2);
+        runs(function() { 
+            expect(callsPerSecond).toBeGreaterThan(FENCEPOST);
+        });
+    });
+    it("should work with hanging get", function() {
+        exec.setNativeToJsBridgeMode(1);
+        var win = jasmine.createSpy().andCallFake(function(r) {
+            vanillaWin(r);
+        });
+        completeSpy = jasmine.createSpy();
+        runs(function() { 
+            echo(win, fail, payload, asyncEcho);
+        });
+        waitsFor(function() { return completeSpy.wasCalled; }, "never completed", durationMs * 2);
+        runs(function() { 
+            expect(callsPerSecond).toBeGreaterThan(FENCEPOST);
+        });
+    });
+    it("should work with load_url (not on emulator)", function() {
+       exec.setNativeToJsBridgeMode(2);
+        var win = jasmine.createSpy().andCallFake(function(r) {
+            vanillaWin(r);
+        });
+        completeSpy = jasmine.createSpy();
+        runs(function() { 
+            echo(win, fail, payload, asyncEcho);
+        });
+        waitsFor(function() { return completeSpy.wasCalled; }, "never completed", durationMs * 2);
+        runs(function() { 
+            expect(callsPerSecond).toBeGreaterThan(FENCEPOST);
+        });
+    });
+    it("should work with online event", function() {
+        exec.setNativeToJsBridgeMode(3);
+        var win = jasmine.createSpy().andCallFake(function(r) {
+            vanillaWin(r);
+        });
+        completeSpy = jasmine.createSpy();
+        runs(function() { 
+            echo(win, fail, payload, asyncEcho);
+        });
+        waitsFor(function() { return completeSpy.wasCalled; }, "never completed", durationMs * 2);
+        runs(function() { 
+            expect(callsPerSecond).toBeGreaterThan(FENCEPOST);
+        });
+    });
+    it("should work with the private api", function() {
+        exec.setNativeToJsBridgeMode(4);
+        var win = jasmine.createSpy().andCallFake(function(r) {
+            vanillaWin(r);
+        });
+        completeSpy = jasmine.createSpy();
+        runs(function() { 
+            echo(win, fail, payload, asyncEcho);
+        });
+        waitsFor(function() { return completeSpy.wasCalled; }, "never completed", durationMs * 2);
+        runs(function() { 
+            expect(callsPerSecond).toBeGreaterThan(FENCEPOST);
+        });
+    });
+});