incubator-callback-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Simon MacDonald <simon.macdon...@gmail.com>
Subject Re: [2/2] js commit: Make how exec() sends & receives messages configurable.
Date Fri, 17 Aug 2012 16:03:03 GMT
Hey Andrew,

There is something not quite right with this commit. When I run Mob Spec I
can reproduce this problem:

E/Web Console( 1420): TypeError: Result of expression
'exec.nativeToJsModes' [undefined] is not an object. at
file:///android_asset/www/cordova.android.js:3741

All I needed to do to reproduce was to run mobile spec and navigate to the
Audio Play/Record section.

Can you take a look at it?

Simon Mac Donald
http://hi.im/simonmacdonald


On Fri, Aug 17, 2012 at 11:09 AM, <agrieve@apache.org> wrote:

> 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 <agrieve@chromium.org>
> Authored: Thu Aug 16 17:11:53 2012 -0400
> Committer: Andrew Grieve <agrieve@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
>
>

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message