Make how exec() sends & receives messages configurable. This also deletes the cordova.shuttingDown and cordova.UsePolling flags.
Project: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/commit/5fecf16a Tree: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/tree/5fecf16a Diff: http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/diff/5fecf16a Branch: refs/heads/master Commit: 5fecf16a62155e74dfb8d9f666e24fcf21a22ae9 Parents: 03a0aca Author: Andrew Grieve <agri...@chromium.org> Authored: Thu Aug 16 17:11:53 2012 -0400 Committer: Andrew Grieve <agri...@chromium.org> Committed: Fri Aug 17 11:08:15 2012 -0400 ---------------------------------------------------------------------- lib/android/exec.js | 180 +++++++++++++++++++-------- lib/android/platform.js | 23 +--- lib/android/plugin/android/callback.js | 138 ++++++++++---------- lib/android/plugin/android/polling.js | 55 ++++---- lib/cordova.js | 4 - 5 files changed, 225 insertions(+), 175 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/5fecf16a/lib/android/exec.js ---------------------------------------------------------------------- diff --git a/lib/android/exec.js b/lib/android/exec.js index 60403be..1bd12e8 100644 --- a/lib/android/exec.js +++ b/lib/android/exec.js @@ -12,71 +12,141 @@ * @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 = { + POLLING: 0, + HANGING_GET: 1, + LOAD_URL: 2, // Not yet implemented + ONLINE_EVENT: 3, // Not yet implemented + PRIVATE_API: 4 // Not yet implemented + }; -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); + } +}; + +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 == 0) { + polling.stop(); + } else if (nativeToJsBridgeMode == 1) { + callback.stop(); + } + nativeToJsBridgeMode = mode; + if (mode == 0) { + polling.start(); + } else if (mode == 1) { + callback.start(); + } +}; + +// 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; http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/5fecf16a/lib/android/platform.js ---------------------------------------------------------------------- diff --git a/lib/android/platform.js b/lib/android/platform.js index 4439d30..cbd21bf 100644 --- a/lib/android/platform.js +++ b/lib/android/platform.js @@ -3,32 +3,15 @@ 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; + exec.setNativeToJsBridgeMode(-1); }); - // 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. http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/5fecf16a/lib/android/plugin/android/callback.js ---------------------------------------------------------------------- diff --git a/lib/android/plugin/android/callback.js b/lib/android/plugin/android/callback.js index d41a164..4729678 100644 --- a/lib/android/plugin/android/callback.js +++ b/lib/android/plugin/android/callback.js @@ -1,85 +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; - } + exec = require('cordova/exec'), + xmlhttp; - // If polling flag was changed, start using polling from now on - if (cordova.UsePolling) { - polling(); - return; - } +module.exports = { + start: function callback() { + xmlhttp = new XMLHttpRequest(); - var xmlhttp = new XMLHttpRequest(); + // 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) { - // Callback function when XMLHttpRequest is ready - xmlhttp.onreadystatechange=function(){ - if(xmlhttp.readyState === 4){ + // 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); + } - // Exit if shutting down app - if (cordova.shuttingDown) { - return; - } + // If callback ping (used to keep XHR request from timing out) + else if (xmlhttp.status === 404) { + setTimeout(callback, 10); + } - // If callback has JavaScript statement to execute - if (xmlhttp.status === 200) { + // If security error + else if (xmlhttp.status === 403) { + console.log("JSCallback Error: Invalid token. Stopping callbacks."); + } - // 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 server is stopping + else if (xmlhttp.status === 503) { + console.log("JSCallback Server Closed: Stopping callbacks."); + } - // If callback ping (used to keep XHR request from timing out) - else if (xmlhttp.status === 404) { - setTimeout(callback, 10); - } + // If request wasn't GET + else if (xmlhttp.status === 400) { + console.log("JSCallback Error: Bad request. Stopping callbacks."); + } - // If security error - else if (xmlhttp.status === 403) { - console.log("JSCallback Error: Invalid token. Stopping callbacks."); - } + // If error, revert to polling + else { + console.log("JSCallback Error: Request failed."); + 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."); - } + stop: function() { + if (xmlhttp) { + var tmp = xmlhttp; + xmlhttp = null; + tmp.abort(); + } + }, - // If error, revert to polling - else { - console.log("JSCallback Error: Request failed."); - cordova.UsePolling = true; - polling(); - } - } - }; + isAvailable: function() { + return ("true" != prompt("usePolling", "gap_callbackServer:")); + } - 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; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/5fecf16a/lib/android/plugin/android/polling.js ---------------------------------------------------------------------- diff --git a/lib/android/plugin/android/polling.js b/lib/android/plugin/android/polling.js index 0d6e87e..406dc62 100644 --- a/lib/android/plugin/android/polling.js +++ b/lib/android/plugin/android/polling.js @@ -1,33 +1,34 @@ var cordova = require('cordova'), period = 50, - polling = function() { - // Exit if shutting down app - if (cordova.shuttingDown) { - return; - } + 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; - } - 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 msg = prompt("", "gap_poll:"); + if (msg) { + try { + eval(""+msg); + } + catch (e) { + console.log("JSCallbackPolling: Message from Server: " + msg); + console.log("JSCallbackPolling Error: "+e); + } + setTimeout(doPoll, 1); + } else { + setTimeout(doPoll, period); + } +} + +module.exports = { + start: function() { + enabled = true; + setTimeout(doPoll, 1); + }, + stop: function() { + enabled = false; + } }; -module.exports = polling; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-cordova-js/blob/5fecf16a/lib/cordova.js ---------------------------------------------------------------------- diff --git a/lib/cordova.js b/lib/cordova.js index dbaf478..ea5f7cd 100644 --- a/lib/cordova.js +++ b/lib/cordova.js @@ -136,10 +136,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