You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2012/08/22 15:57:11 UTC

[1/6] android commit: Update cordova.android.js to pull in exec changes.

Updated Branches:
  refs/heads/master a9a5284a6 -> 92b1de8cf


Update cordova.android.js to pull in exec changes.


Project: http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/commit/92b1de8c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/tree/92b1de8c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/diff/92b1de8c

Branch: refs/heads/master
Commit: 92b1de8cf879339d48d91138df4af684d7500c38
Parents: bbafe53
Author: Andrew Grieve <ag...@chromium.org>
Authored: Wed Aug 22 09:50:40 2012 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Aug 22 09:50:40 2012 -0400

----------------------------------------------------------------------
 framework/assets/js/cordova.android.js |  522 ++++++++++++++++-----------
 1 files changed, 307 insertions(+), 215 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cordova-android/blob/92b1de8c/framework/assets/js/cordova.android.js
----------------------------------------------------------------------
diff --git a/framework/assets/js/cordova.android.js b/framework/assets/js/cordova.android.js
index ba9e6a9..44166d1 100644
--- a/framework/assets/js/cordova.android.js
+++ b/framework/assets/js/cordova.android.js
@@ -1,6 +1,6 @@
-// commit 114cf5304a74ff8f7c9ff1d21cf5652298af04b0
+// commit f8b6816a5e44b4f8cdcb4b61c49cff9b50b7ce6f
 
-// File generated at :: Wed Jul 18 2012 14:44:33 GMT-0700 (PDT)
+// File generated at :: Wed Aug 22 2012 09:42:10 GMT-0400 (EDT)
 
 /*
  Licensed to the Apache Software Foundation (ASF) under one
@@ -29,6 +29,10 @@ var require,
 
 (function () {
     var modules = {};
+    // Stack of moduleIds currently being built.
+    var requireStack = [];
+    // Map of module ID -> index into requireStack of modules currently being built.
+    var inProgressModules = {};
 
     function build(module) {
         var factory = module.factory;
@@ -41,8 +45,21 @@ var require,
     require = function (id) {
         if (!modules[id]) {
             throw "module " + id + " not found";
+        } else if (id in inProgressModules) {
+            var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
+            throw "Cycle in require graph: " + cycle;
         }
-        return modules[id].factory ? build(modules[id]) : modules[id].exports;
+        if (modules[id].factory) {
+            try {
+                inProgressModules[id] = requireStack.length;
+                requireStack.push(id);
+                return build(modules[id]);
+            } finally {
+                delete inProgressModules[id];
+                requireStack.pop();
+            }
+        }
+        return modules[id].exports;
     };
 
     define = function (id, factory) {
@@ -67,6 +84,7 @@ if (typeof module === "object" && typeof require === "function") {
     module.exports.require = require;
     module.exports.define = define;
 }
+
 // file: lib/cordova.js
 define("cordova", function(require, exports, module) {
 var channel = require('cordova/channel');
@@ -207,10 +225,6 @@ var cordova = {
             window.dispatchEvent(evt);
         }
     },
-    // TODO: this is Android only; think about how to do this better
-    shuttingDown:false,
-    UsePolling:false,
-    // END TODO
 
     // TODO: iOS only
     // This queue holds the currently executing command and all pending
@@ -890,75 +904,170 @@ define("cordova/exec", function(require, exports, module) {
  * @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');
+var cordova = require('cordova'),
+    callback = require('cordova/plugin/android/callback'),
+    polling = require('cordova/plugin/android/polling'),
+    jsToNativeBridgeMode,
+    nativeToJsBridgeMode,
+    jsToNativeModes = {
+        PROMPT: 0,
+        JS_OBJECT: 1,
+        LOCATION_CHANGE: 2  // Not yet implemented
+    },
+    nativeToJsModes = {
+        // Polls for messages using the prompt() bridge.
+        POLLING: 0,
+        // Does an XHR to a local server, which will send back messages. This is
+        // broken on ICS when a proxy server is configured.
+        HANGING_GET: 1,
+        // For LOAD_URL to be viable, it would need to have a work-around for
+        // the bug where the soft-keyboard gets dismissed when a message is sent.
+        LOAD_URL: 2,
+        // For the ONLINE_EVENT to be viable, it would need to intercept all event
+        // listeners (both through addEventListener and window.ononline) as well
+        // as set the navigator property itself.
+        ONLINE_EVENT: 3,
+        // Uses reflection to access private APIs of the WebView that can send JS
+        // to be executed.
+        // Requires Android 3.2.4 or above.
+        PRIVATE_API: 4
+    };
 
-module.exports = function(success, fail, service, action, args) {
-  try {
-    var callbackId = service + cordova.callbackId++;
-    if (success || fail) {
-        cordova.callbacks[callbackId] = {success:success, fail:fail};
-    }
+function androidExec(success, fail, service, action, args) {
+    try {
+      var callbackId = service + cordova.callbackId++,
+          argsJson = JSON.stringify(args),
+          result;
+      if (success || fail) {
+          cordova.callbacks[callbackId] = {success:success, fail:fail};
+      }
 
-    var r = prompt(JSON.stringify(args), "gap:"+JSON.stringify([service, action, callbackId, true]));
+      if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT) {
+          // Explicit cast to string is required on Android 2.1 to convert from
+          // a Java string to a JS string.
+          result = '' + _cordovaExec.exec(service, action, callbackId, argsJson);
+      } else {
+          result = prompt(argsJson, "gap:"+JSON.stringify([service, action, callbackId, true]));
+      }
 
-    // If a result was returned
-    if (r.length > 0) {
-        var v = JSON.parse(r);
+      // If a result was returned
+      if (result.length > 0) {
+          var v = JSON.parse(result);
 
-        // If status is OK, then return value back to caller
-        if (v.status === cordova.callbackStatus.OK) {
+          // 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);
-                }
+              // 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;
-        }
+                  // 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 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 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);
-                }
+              // 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;
+                  // Clear callback if not expecting any more results
+                  if (!v.keepCallback) {
+                      delete cordova.callbacks[callbackId];
+                  }
+              }
+              return null;
+          }
+      }
+    } catch (e2) {
+      console.log("Error: "+e2);
+    }
+};
+
+function onOnLineEvent(e) {
+    while (polling.pollOnce());
+}
+
+androidExec.jsToNativeModes = jsToNativeModes;
+androidExec.nativeToJsModes = nativeToJsModes;
+
+androidExec.setJsToNativeBridgeMode = function(mode) {
+    if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaExec) {
+        console.log('Falling back on PROMPT mode since _cordovaExec is missing.');
+        mode = jsToNativeModes.PROMPT;
+    }
+    jsToNativeBridgeMode = mode;
+};
+
+androidExec.setNativeToJsBridgeMode = function(mode) {
+    if (mode == nativeToJsBridgeMode) {
+        return;
+    }
+    if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {
+        polling.stop();
+    } else if (nativeToJsBridgeMode == nativeToJsModes.HANGING_GET) {
+        callback.stop();
+    } else if (nativeToJsBridgeMode == nativeToJsModes.ONLINE_EVENT) {
+        window.removeEventListener('online', onOnLineEvent, false);
+        window.removeEventListener('offline', onOnLineEvent, false);
+    }
+
+    nativeToJsBridgeMode = mode;
+    // Tell the native side to switch modes.
+    prompt(mode, "gap_bridge_mode:");
+
+    if (mode == nativeToJsModes.POLLING) {
+        polling.start();
+    } else if (mode == nativeToJsModes.HANGING_GET) {
+        callback.start();
+    } else if (mode == nativeToJsModes.ONLINE_EVENT) {
+        window.addEventListener('online', onOnLineEvent, false);
+        window.addEventListener('offline', onOnLineEvent, false);
+    }
+};
+
+// Start listening for XHR callbacks
+// Figure out which bridge approach will work on this Android
+// device: polling or XHR-based callbacks
+androidExec.initialize = function() {
+    if (jsToNativeBridgeMode === undefined) {
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
+    }
+    if (nativeToJsBridgeMode === undefined) {
+        if (callback.isAvailable()) {
+            androidExec.setNativeToJsBridgeMode(nativeToJsModes.HANGING_GET);
+        } else {
+            androidExec.setNativeToJsBridgeMode(nativeToJsModes.POLLING);
         }
     }
-  } catch (e2) {
-    console.log("Error: "+e2);
-  }
 };
 
+module.exports = androidExec;
+
 });
 
 // file: lib/android/platform.js
@@ -968,32 +1077,11 @@ module.exports = {
     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
+        // Use a setTimeout here to give apps a chance to set the bridge mode.
         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();
-                }
-            }
+            exec.initialize();
         }, 1);
 
         // Inject a listener for the backbutton on the document.
@@ -2585,10 +2673,12 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
     var mimeType = null;
     var params = null;
     var chunkedMode = true;
+    var headers = null;
     if (options) {
         fileKey = options.fileKey;
         fileName = options.fileName;
         mimeType = options.mimeType;
+        headers = options.headers;
         if (options.chunkedMode !== null || typeof options.chunkedMode != "undefined") {
             chunkedMode = options.chunkedMode;
         }
@@ -2605,7 +2695,7 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro
         errorCallback(error);
     };
 
-    exec(successCallback, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode]);
+    exec(successCallback, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers]);
 };
 
 /**
@@ -2675,15 +2765,19 @@ define("cordova/plugin/FileUploadOptions", function(require, exports, module) {
  * @param fileName {String}  Filename to be used by the server. Defaults to image.jpg.
  * @param mimeType {String}  Mimetype of the uploaded file. Defaults to image/jpeg.
  * @param params {Object}    Object with key: value params to send to the server.
+ * @param headers {Object}   Keys are header names, values are header values. Multiple
+ *                           headers of the same name are not supported.
  */
-var FileUploadOptions = function(fileKey, fileName, mimeType, params) {
+var FileUploadOptions = function(fileKey, fileName, mimeType, params, headers) {
     this.fileKey = fileKey || null;
     this.fileName = fileName || null;
     this.mimeType = mimeType || null;
     this.params = params || null;
+    this.headers = headers || null;
 };
 
 module.exports = FileUploadOptions;
+
 });
 
 // file: lib/common/plugin/FileUploadResult.js
@@ -3078,7 +3172,6 @@ Media.prototype.stop = function() {
     var me = this;
     exec(function() {
         me._position = 0;
-        me.successCallback();
     }, this.errorCallback, "Media", "stopPlayingAudio", [this.id]);
 };
 
@@ -3124,14 +3217,14 @@ Media.prototype.getCurrentPosition = function(success, fail) {
  * Start recording audio file.
  */
 Media.prototype.startRecord = function() {
-    exec(this.successCallback, this.errorCallback, "Media", "startRecordingAudio", [this.id, this.src]);
+    exec(null, this.errorCallback, "Media", "startRecordingAudio", [this.id, this.src]);
 };
 
 /**
  * Stop recording audio file.
  */
 Media.prototype.stopRecord = function() {
-    exec(this.successCallback, this.errorCallback, "Media", "stopRecordingAudio", [this.id]);
+    exec(null, this.errorCallback, "Media", "stopRecordingAudio", [this.id]);
 };
 
 /**
@@ -3160,14 +3253,14 @@ Media.onStatus = function(id, msg, value) {
     var media = mediaObjects[id];
     // If state update
     if (msg === Media.MEDIA_STATE) {
+        if (media.statusCallback) {
+            media.statusCallback(value);
+        }
         if (value === Media.MEDIA_STOPPED) {
             if (media.successCallback) {
                 media.successCallback();
             }
         }
-        if (media.statusCallback) {
-            media.statusCallback(value);
-        }
     }
     else if (msg === Media.MEDIA_DURATION) {
         media._duration = value;
@@ -3241,28 +3334,6 @@ MediaFile.prototype.getFormatData = function(successCallback, errorCallback) {
     }
 };
 
-// TODO: can we axe this?
-/**
- * Casts a PluginResult message property  (array of objects) to an array of MediaFile objects
- * (used in Objective-C and Android)
- *
- * @param {PluginResult} pluginResult
- */
-MediaFile.cast = function(pluginResult) {
-    var mediaFiles = [];
-    for (var i=0; i<pluginResult.message.length; i++) {
-        var mediaFile = new MediaFile();
-        mediaFile.name = pluginResult.message[i].name;
-        mediaFile.fullPath = pluginResult.message[i].fullPath;
-        mediaFile.type = pluginResult.message[i].type;
-        mediaFile.lastModifiedDate = pluginResult.message[i].lastModifiedDate;
-        mediaFile.size = pluginResult.message[i].size;
-        mediaFiles.push(mediaFile);
-    }
-    pluginResult.message = mediaFiles;
-    return pluginResult;
-};
-
 module.exports = MediaFile;
 
 });
@@ -3630,89 +3701,82 @@ module.exports = {
 define("cordova/plugin/android/callback", function(require, exports, module) {
 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;
-      }
+    xmlhttp;
 
-      var xmlhttp = new XMLHttpRequest();
+function startXhr() {
+    // cordova/exec depends on this module, so we can't require cordova/exec on the module level.
+    var exec = require('cordova/exec'),
+    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;
-              }
+    // Callback function when XMLHttpRequest is ready
+    xmlhttp.onreadystatechange=function(){
+        if (!xmlhttp) {
+            return;
+        }
+        if (xmlhttp.readyState === 4){
+            // If callback has JavaScript statement to execute
+            if (xmlhttp.status === 200) {
 
-              // 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);
-              }
+                // 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(startXhr, 1);
+            }
 
-              // If callback ping (used to keep XHR request from timing out)
-              else if (xmlhttp.status === 404) {
-                  setTimeout(callback, 10);
-              }
+            // If callback ping (used to keep XHR request from timing out)
+            else if (xmlhttp.status === 404) {
+                setTimeout(startXhr, 10);
+            }
 
-              // If security error
-              else if (xmlhttp.status === 403) {
-                  console.log("JSCallback Error: Invalid token.  Stopping callbacks.");
-              }
+            // 0 == Page is unloading.
+            // 400 == Bad request.
+            // 403 == invalid token.
+            // 503 == server stopped.
+            else {
+                console.log("JSCallback Error: Request failed with status " + xmlhttp.status);
+                exec.setNativeToJsBridgeMode(exec.nativeToJsModes.POLLING);
+            }
+        }
+    };
 
-              // If server is stopping
-              else if (xmlhttp.status === 503) {
-                  console.log("JSCallback Server Closed: Stopping callbacks.");
-              }
+    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();
+}
 
-              // If request wasn't GET
-              else if (xmlhttp.status === 400) {
-                  console.log("JSCallback Error: Bad request.  Stopping callbacks.");
-              }
+module.exports = {
+    start: function() {
+        startXhr();
+    },
 
-              // If error, revert to polling
-              else {
-                  console.log("JSCallback Error: Request failed.");
-                  cordova.UsePolling = true;
-                  polling();
-              }
-          }
-      };
+    stop: function() {
+        if (xmlhttp) {
+            var tmp = xmlhttp;
+            xmlhttp = null;
+            tmp.abort();
+        }
+    },
 
-      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();
+    isAvailable: function() {
+        return ("true" != prompt("usePolling", "gap_callbackServer:"));
+    }
 };
 
-module.exports = callback;
+
 });
 
 // file: lib/android/plugin/android/device.js
@@ -3819,38 +3883,47 @@ module.exports = {
 // file: lib/android/plugin/android/polling.js
 define("cordova/plugin/android/polling", function(require, exports, module) {
 var cordova = require('cordova'),
-    period = 50,
-    polling = function() {
-      // Exit if shutting down app
-      if (cordova.shuttingDown) {
-          return;
-      }
+    POLL_INTERVAL = 50,
+    enabled = false;
 
-      // 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;
-      }
+function pollOnce() {
+    var msg = prompt("", "gap_poll:");
+    if (msg) {
+        try {
+            eval(""+msg);
+        }
+        catch (e) {
+            console.log("JSCallbackPolling: Message from Server: " + msg);
+            console.log("JSCallbackPolling Error: "+e);
+        }
+        return true;
+    }
+    return false;
+}
 
-      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);
-      }
+function doPoll() {
+    if (!enabled) {
+        return;
+    }
+    var nextDelay = POLL_INTERVAL;
+    if (pollOnce()) {
+        nextDelay = 0;
+    }
+    setTimeout(doPoll, nextDelay);
+}
+
+module.exports = {
+    start: function() {
+        enabled = true;
+        setTimeout(doPoll, 1);
+    },
+    stop: function() {
+        enabled = false;
+    },
+    pollOnce: pollOnce
 };
 
-module.exports = polling;
+
 });
 
 // file: lib/android/plugin/android/storage.js
@@ -4810,6 +4883,25 @@ module.exports = new Device();
 
 });
 
+// file: lib/common/plugin/echo.js
+define("cordova/plugin/echo", function(require, exports, module) {
+var exec = require('cordova/exec');
+
+/**
+ * Sends the given message through exec() to the Echo plugink, which sends it back to the successCallback.
+ * @param successCallback  invoked with a FileSystem object
+ * @param errorCallback  invoked if error occurs retrieving file system
+ * @param message  The string to be echoed.
+ * @param forceAsync  Whether to force an async return value (for testing native->js bridge).
+ */
+module.exports = function(successCallback, errorCallback, message, forceAsync) {
+    var action = forceAsync ? 'echoAsync' : 'echo';
+    exec(successCallback, errorCallback, "Echo", action, [message]);
+};
+
+
+});
+
 // file: lib/common/plugin/geolocation.js
 define("cordova/plugin/geolocation", function(require, exports, module) {
 var utils = require('cordova/utils'),