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 2014/06/24 21:29:54 UTC

[1/9] android commit: CB-5971: Fix package / project validation

Repository: cordova-android
Updated Branches:
  refs/heads/4.0.x 96a119247 -> 428e1bc14
  refs/heads/master 58afd0b60 -> 4b4a2e9f9


CB-5971: Fix package / project validation


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

Branch: refs/heads/4.0.x
Commit: 4352456129bfa8a8a6bbf4d38fb40d9876b67ec4
Parents: bb141a7
Author: Ian Clelland <ic...@chromium.org>
Authored: Tue Jun 24 14:05:03 2014 -0400
Committer: Ian Clelland <ic...@chromium.org>
Committed: Tue Jun 24 14:05:56 2014 -0400

----------------------------------------------------------------------
 bin/lib/create.js | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/43524561/bin/lib/create.js
----------------------------------------------------------------------
diff --git a/bin/lib/create.js b/bin/lib/create.js
index a31604a..b2490f2 100755
--- a/bin/lib/create.js
+++ b/bin/lib/create.js
@@ -113,18 +113,13 @@ function copyScripts(projectPath) {
  */
 function validatePackageName(package_name) {
     //Make the package conform to Java package types
-    if (!/[a-zA-Z0-9_]+\.[a-zA-Z0-9_](.[a-zA-Z0-9_])*/.test(package_name)) {
-        return Q.reject('Package name must look like: com.company.Name');
-    }
-
     //Enforce underscore limitation
-    if (/[_]+[a-zA-Z0-9_]*/.test(package_name)) {
-        return Q.reject("Package name can't begin with an underscore");
+    if (!/^[a-zA-Z]+(\.[a-zA-Z0-9][a-zA-Z0-9_]*)+$/.test(package_name)) {
+        return Q.reject('Package name must look like: com.company.Name');
     }
 
     //Class is a reserved word
-    if(/[C|c]+lass+[\s|\.]/.test(package_name) && !/[a-zA-Z0-9_]+[C|c]+lass/.test(package_name))
-    {
+    if(/\b[Cc]lass\b/.test(package_name)) {
         return Q.reject('class is a reserved word');
     }
 
@@ -137,6 +132,11 @@ function validatePackageName(package_name) {
  * otherwise.
  */
 function validateProjectName(project_name) {
+    //Make sure there's something there
+    if (project_name === '') {
+        return Q.reject('Project name cannot be empty');
+    }
+
     //Enforce stupid name error
     if (project_name === 'CordovaActivity') {
         return Q.reject('Project name cannot be CordovaActivity');


[8/9] android commit: Delete onReset and resetJsMessageQueue from CordovaWebView interface

Posted by ag...@apache.org.
Delete onReset and resetJsMessageQueue from CordovaWebView interface

These are implementation details that do not need to be exposed.


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

Branch: refs/heads/4.0.x
Commit: d66bb84924b9171991d7124e7c663b8e7f63f51c
Parents: 4ce5123
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Jun 24 15:26:43 2014 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Jun 24 15:26:43 2014 -0400

----------------------------------------------------------------------
 framework/src/org/apache/cordova/AndroidWebView.java    | 12 ++++--------
 .../src/org/apache/cordova/AndroidWebViewClient.java    |  7 ++-----
 framework/src/org/apache/cordova/CordovaWebView.java    |  4 ----
 3 files changed, 6 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/d66bb849/framework/src/org/apache/cordova/AndroidWebView.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/AndroidWebView.java b/framework/src/org/apache/cordova/AndroidWebView.java
index 49ec782..4074d21 100755
--- a/framework/src/org/apache/cordova/AndroidWebView.java
+++ b/framework/src/org/apache/cordova/AndroidWebView.java
@@ -1024,14 +1024,10 @@ public class AndroidWebView extends WebView implements CordovaWebView {
         return this.pluginManager.onOverrideUrlLoading(url);
     }
 
-    @Override
-    public void resetJsMessageQueue() {
-        this.jsMessageQueue.reset();
-    }
-
-    @Override
-    public void onReset() {
-        this.pluginManager.onReset();
+    void onPageReset() {
+        boundKeyCodes.clear();
+        pluginManager.onReset();
+        jsMessageQueue.reset();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/d66bb849/framework/src/org/apache/cordova/AndroidWebViewClient.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/AndroidWebViewClient.java b/framework/src/org/apache/cordova/AndroidWebViewClient.java
index 044b2c4..b57e0b6 100755
--- a/framework/src/org/apache/cordova/AndroidWebViewClient.java
+++ b/framework/src/org/apache/cordova/AndroidWebViewClient.java
@@ -280,14 +280,11 @@ public class AndroidWebViewClient extends WebViewClient implements CordovaWebVie
         super.onPageStarted(view, url, favicon);
         isCurrentlyLoading = true;
         LOG.d(TAG, "onPageStarted(" + url + ")");
-        // Flush stale messages.
-        this.appView.resetJsMessageQueue();
+        // Flush stale messages & reset plugins.
+        this.appView.onPageReset();
 
         // Broadcast message that page has loaded
         this.appView.postMessage("onPageStarted", url);
-
-        // Notify all plugins of the navigation, so they can clean up if necessary.
-        this.appView.onReset();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/d66bb849/framework/src/org/apache/cordova/CordovaWebView.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaWebView.java b/framework/src/org/apache/cordova/CordovaWebView.java
index 6a9fbaf..5329ce2 100644
--- a/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/framework/src/org/apache/cordova/CordovaWebView.java
@@ -122,10 +122,6 @@ public interface CordovaWebView {
 
     boolean onOverrideUrlLoading(String url);
 
-    void resetJsMessageQueue();
-
-    void onReset();
-
     int getVisibility();
 
     void incUrlTimeout();


[6/9] android commit: CB-7018 Clean up and deprecation of some button-related functions

Posted by ag...@apache.org.
CB-7018 Clean up and deprecation of some button-related functions


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

Branch: refs/heads/4.0.x
Commit: 4b4a2e9f9e6ebcef57cee2e5f4c44108ec72ca25
Parents: 58afd0b
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Jun 24 15:08:47 2014 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Jun 24 15:08:47 2014 -0400

----------------------------------------------------------------------
 framework/src/org/apache/cordova/App.java       | 12 ++-
 .../src/org/apache/cordova/CordovaWebView.java  | 77 ++++++++++----------
 2 files changed, 46 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4b4a2e9f/framework/src/org/apache/cordova/App.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/App.java b/framework/src/org/apache/cordova/App.java
index 4b15906..2112519 100755
--- a/framework/src/org/apache/cordova/App.java
+++ b/framework/src/org/apache/cordova/App.java
@@ -32,6 +32,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.telephony.TelephonyManager;
+import android.view.KeyEvent;
 
 import java.util.HashMap;
 
@@ -217,7 +218,7 @@ public class App extends CordovaPlugin {
      */
     public void overrideBackbutton(boolean override) {
         LOG.i("App", "WARNING: Back Button Default Behavior will be overridden.  The backbutton event will be fired!");
-        webView.bindButton(override);
+        webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_BACK, override);
     }
 
     /**
@@ -229,7 +230,12 @@ public class App extends CordovaPlugin {
      */
     public void overrideButton(String button, boolean override) {
         LOG.i("App", "WARNING: Volume Button Default Behavior will be overridden.  The volume event will be fired!");
-        webView.bindButton(button, override);
+        if (button.equals("volumeup")) {
+            webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_UP, override);
+        }
+        else if (button.equals("volumedown")) {
+            webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_DOWN, override);
+        }
     }
 
     /**
@@ -238,7 +244,7 @@ public class App extends CordovaPlugin {
      * @return boolean
      */
     public boolean isBackbuttonOverridden() {
-        return webView.isBackButtonBound();
+        return webView.isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4b4a2e9f/framework/src/org/apache/cordova/CordovaWebView.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaWebView.java b/framework/src/org/apache/cordova/CordovaWebView.java
index 3b3f80d..b31eec5 100755
--- a/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/framework/src/org/apache/cordova/CordovaWebView.java
@@ -21,8 +21,8 @@ package org.apache.cordova;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Locale;
 
 import org.apache.cordova.Config;
@@ -70,8 +70,7 @@ public class CordovaWebView extends WebView {
     public static final String TAG = "CordovaWebView";
     public static final String CORDOVA_VERSION = "3.6.0-dev";
 
-    private ArrayList<Integer> keyDownCodes = new ArrayList<Integer>();
-    private ArrayList<Integer> keyUpCodes = new ArrayList<Integer>();
+    private HashSet<Integer> boundKeyCodes = new HashSet<Integer>();
 
     public PluginManager pluginManager;
     private boolean paused;
@@ -90,10 +89,6 @@ public class CordovaWebView extends WebView {
     // Flag to track that a loadUrl timeout occurred
     int loadUrlTimeout = 0;
 
-    private boolean bound;
-
-    private boolean handleButton = false;
-    
     private long lastMenuEventTime = 0;
 
     NativeToJsMessageQueue jsMessageQueue;
@@ -705,23 +700,17 @@ public class CordovaWebView extends WebView {
         return p.toString();
     }
 
-    /*
-     * onKeyDown
-     */
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event)
     {
-        if(keyDownCodes.contains(keyCode))
+        if(boundKeyCodes.contains(keyCode))
         {
             if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
-                    // only override default behavior is event bound
-                    LOG.d(TAG, "Down Key Hit");
                     this.loadUrl("javascript:cordova.fireDocumentEvent('volumedownbutton');");
                     return true;
             }
             // If volumeup key
             else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
-                    LOG.d(TAG, "Up Key Hit");
                     this.loadUrl("javascript:cordova.fireDocumentEvent('volumeupbutton');");
                     return true;
             }
@@ -732,7 +721,7 @@ public class CordovaWebView extends WebView {
         }
         else if(keyCode == KeyEvent.KEYCODE_BACK)
         {
-            return !(this.startOfHistory()) || this.bound;
+            return !(this.startOfHistory()) || isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);
         }
         else if(keyCode == KeyEvent.KEYCODE_MENU)
         {
@@ -749,10 +738,8 @@ public class CordovaWebView extends WebView {
                 return super.onKeyDown(keyCode, event);
             }
         }
-        
         return super.onKeyDown(keyCode, event);
     }
-    
 
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event)
@@ -762,10 +749,11 @@ public class CordovaWebView extends WebView {
             // A custom view is currently displayed  (e.g. playing a video)
             if(mCustomView != null) {
                 this.hideCustomView();
+                return true;
             } else {
                 // The webview is currently displayed
                 // If back key is bound, then send event to JavaScript
-                if (this.bound) {
+                if (isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK)) {
                     this.loadUrl("javascript:cordova.fireDocumentEvent('backbutton');");
                     return true;
                 } else {
@@ -791,48 +779,56 @@ public class CordovaWebView extends WebView {
             this.loadUrl("javascript:cordova.fireDocumentEvent('searchbutton');");
             return true;
         }
-        else if(keyUpCodes.contains(keyCode))
-        {
-            //What the hell should this do?
-            return super.onKeyUp(keyCode, event);
-        }
 
         //Does webkit change this behavior?
         return super.onKeyUp(keyCode, event);
     }
 
-    
+    public void setButtonPlumbedToJs(int keyCode, boolean value) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_VOLUME_DOWN:
+            case KeyEvent.KEYCODE_VOLUME_UP:
+            case KeyEvent.KEYCODE_BACK:
+                // TODO: Why are search and menu buttons handled separately?
+                boundKeyCodes.add(keyCode);
+                return;
+            default:
+                throw new IllegalArgumentException("Unsupported keycode: " + keyCode);
+        }
+    }
+
+    @Deprecated // Use setButtonPlumbedToJs() instead.
     public void bindButton(boolean override)
     {
-        this.bound = override;
+        setButtonPlumbedToJs(KeyEvent.KEYCODE_BACK, override);
     }
 
+    @Deprecated // Use setButtonPlumbedToJs() instead.
     public void bindButton(String button, boolean override) {
-        // TODO Auto-generated method stub
         if (button.compareTo("volumeup")==0) {
-          keyDownCodes.add(KeyEvent.KEYCODE_VOLUME_UP);
+            setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_UP, override);
         }
         else if (button.compareTo("volumedown")==0) {
-          keyDownCodes.add(KeyEvent.KEYCODE_VOLUME_DOWN);
+            setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_DOWN, override);
         }
-      }
+    }
 
+    @Deprecated // Use setButtonPlumbedToJs() instead.
     public void bindButton(int keyCode, boolean keyDown, boolean override) {
-       if(keyDown)
-       {
-           keyDownCodes.add(keyCode);
-       }
-       else
-       {
-           keyUpCodes.add(keyCode);
-       }
+        setButtonPlumbedToJs(keyCode, override);
     }
 
+    @Deprecated // Use isButtonPlumbedToJs
     public boolean isBackButtonBound()
     {
-        return this.bound;
+        return isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);
     }
-    
+
+    public boolean isButtonPlumbedToJs(int keyCode)
+    {
+        return boundKeyCodes.contains(keyCode);
+    }
+
     public void handlePause(boolean keepRunning)
     {
         LOG.d(TAG, "Handle the pause");
@@ -904,8 +900,9 @@ public class CordovaWebView extends WebView {
         return paused;
     }
 
+    @Deprecated // This never did anything.
     public boolean hadKeyEvent() {
-        return handleButton;
+        return false;
     }
 
     // Wrapping these functions in their own class prevents warnings in adb like:


[2/9] android commit: CB-5971: Add unit tests to cordova-android

Posted by ag...@apache.org.
CB-5971: Add unit tests to cordova-android


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

Branch: refs/heads/4.0.x
Commit: bb141a70e89cf7826fb1699085df33aac597a688
Parents: ff260c0
Author: Ian Clelland <ic...@chromium.org>
Authored: Tue Jun 24 13:50:00 2014 -0400
Committer: Ian Clelland <ic...@chromium.org>
Committed: Tue Jun 24 14:05:56 2014 -0400

----------------------------------------------------------------------
 bin/lib/create.js   |  4 +++
 package.json        |  7 +++++
 spec/create.spec.js | 82 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 93 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/bb141a70/bin/lib/create.js
----------------------------------------------------------------------
diff --git a/bin/lib/create.js b/bin/lib/create.js
index 8a90827..a31604a 100755
--- a/bin/lib/create.js
+++ b/bin/lib/create.js
@@ -288,3 +288,7 @@ exports.updateProject = function(projectPath) {
     });
 };
 
+
+// For testing
+exports.validatePackageName = validatePackageName;
+exports.validateProjectName = validateProjectName;

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/bb141a70/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index 0d203c9..ed01458 100644
--- a/package.json
+++ b/package.json
@@ -12,10 +12,17 @@
     "cordova",
     "apache"
   ],
+  "scripts": {
+    "test": "jasmine-node --color spec"
+  },
   "author": "Apache Software Foundation",
   "license": "Apache version 2.0",
   "dependencies": {
     "q": "^0.9.0",
     "shelljs": "^0.2.6"
+  },
+  "devDependencies": {
+    "jasmine-node": "~1",
+    "promise-matchers": "~0"
   }
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/bb141a70/spec/create.spec.js
----------------------------------------------------------------------
diff --git a/spec/create.spec.js b/spec/create.spec.js
new file mode 100644
index 0000000..8e08793
--- /dev/null
+++ b/spec/create.spec.js
@@ -0,0 +1,82 @@
+/**
+    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.
+*/
+/* jshint laxcomma:true */
+
+require("promise-matchers");
+
+var create = require("../bin/lib/create");
+
+describe("create", function () {
+  describe("validatePackageName", function() {
+    var valid = [
+        "org.apache.mobilespec"
+      , "com.example"
+      , "com.42floors.package"
+    ];
+    var invalid = [
+        ""
+      , "com.class.is.bad"
+      , "0com.example.mobilespec"
+      , "c-m.e@a!p%e.mobilespec"
+      , "notenoughdots"
+      , ".starts.with.a.dot"
+      , "ends.with.a.dot."
+      , "_underscore.anything"
+      , "underscore._something"
+      , "_underscore._all._the._things"
+    ];
+
+    valid.forEach(function(package_name) {
+      it("should accept " + package_name, function(done) {
+        expect(create.validatePackageName(package_name)).toHaveBeenResolved(done);
+      });
+    });
+
+    invalid.forEach(function(package_name) {
+      it("should reject " + package_name, function(done) {
+        expect(create.validatePackageName(package_name)).toHaveBeenRejected(done);
+      });
+    });
+  });
+  describe("validateProjectName", function() {
+    var valid = [
+        "mobilespec"
+      , "package_name"
+      , "PackageName"
+      , "CordovaLib"
+    ];
+    var invalid = [
+        ""
+      , "0startswithdigit"
+      , "CordovaActivity"
+    ];
+
+    valid.forEach(function(project_name) {
+      it("should accept " + project_name, function(done) {
+        expect(create.validateProjectName(project_name)).toHaveBeenResolved(done);
+      });
+    });
+
+    invalid.forEach(function(project_name) {
+      it("should reject " + project_name, function(done) {
+        expect(create.validateProjectName(project_name)).toHaveBeenRejected(done);
+      });
+    });
+  });
+});


[5/9] android commit: CB-7018 Clean up and deprecation of some button-related functions

Posted by ag...@apache.org.
CB-7018 Clean up and deprecation of some button-related functions


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

Branch: refs/heads/master
Commit: 4b4a2e9f9e6ebcef57cee2e5f4c44108ec72ca25
Parents: 58afd0b
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Jun 24 15:08:47 2014 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Jun 24 15:08:47 2014 -0400

----------------------------------------------------------------------
 framework/src/org/apache/cordova/App.java       | 12 ++-
 .../src/org/apache/cordova/CordovaWebView.java  | 77 ++++++++++----------
 2 files changed, 46 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4b4a2e9f/framework/src/org/apache/cordova/App.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/App.java b/framework/src/org/apache/cordova/App.java
index 4b15906..2112519 100755
--- a/framework/src/org/apache/cordova/App.java
+++ b/framework/src/org/apache/cordova/App.java
@@ -32,6 +32,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.telephony.TelephonyManager;
+import android.view.KeyEvent;
 
 import java.util.HashMap;
 
@@ -217,7 +218,7 @@ public class App extends CordovaPlugin {
      */
     public void overrideBackbutton(boolean override) {
         LOG.i("App", "WARNING: Back Button Default Behavior will be overridden.  The backbutton event will be fired!");
-        webView.bindButton(override);
+        webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_BACK, override);
     }
 
     /**
@@ -229,7 +230,12 @@ public class App extends CordovaPlugin {
      */
     public void overrideButton(String button, boolean override) {
         LOG.i("App", "WARNING: Volume Button Default Behavior will be overridden.  The volume event will be fired!");
-        webView.bindButton(button, override);
+        if (button.equals("volumeup")) {
+            webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_UP, override);
+        }
+        else if (button.equals("volumedown")) {
+            webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_DOWN, override);
+        }
     }
 
     /**
@@ -238,7 +244,7 @@ public class App extends CordovaPlugin {
      * @return boolean
      */
     public boolean isBackbuttonOverridden() {
-        return webView.isBackButtonBound();
+        return webView.isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4b4a2e9f/framework/src/org/apache/cordova/CordovaWebView.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaWebView.java b/framework/src/org/apache/cordova/CordovaWebView.java
index 3b3f80d..b31eec5 100755
--- a/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/framework/src/org/apache/cordova/CordovaWebView.java
@@ -21,8 +21,8 @@ package org.apache.cordova;
 
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Locale;
 
 import org.apache.cordova.Config;
@@ -70,8 +70,7 @@ public class CordovaWebView extends WebView {
     public static final String TAG = "CordovaWebView";
     public static final String CORDOVA_VERSION = "3.6.0-dev";
 
-    private ArrayList<Integer> keyDownCodes = new ArrayList<Integer>();
-    private ArrayList<Integer> keyUpCodes = new ArrayList<Integer>();
+    private HashSet<Integer> boundKeyCodes = new HashSet<Integer>();
 
     public PluginManager pluginManager;
     private boolean paused;
@@ -90,10 +89,6 @@ public class CordovaWebView extends WebView {
     // Flag to track that a loadUrl timeout occurred
     int loadUrlTimeout = 0;
 
-    private boolean bound;
-
-    private boolean handleButton = false;
-    
     private long lastMenuEventTime = 0;
 
     NativeToJsMessageQueue jsMessageQueue;
@@ -705,23 +700,17 @@ public class CordovaWebView extends WebView {
         return p.toString();
     }
 
-    /*
-     * onKeyDown
-     */
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event)
     {
-        if(keyDownCodes.contains(keyCode))
+        if(boundKeyCodes.contains(keyCode))
         {
             if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
-                    // only override default behavior is event bound
-                    LOG.d(TAG, "Down Key Hit");
                     this.loadUrl("javascript:cordova.fireDocumentEvent('volumedownbutton');");
                     return true;
             }
             // If volumeup key
             else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
-                    LOG.d(TAG, "Up Key Hit");
                     this.loadUrl("javascript:cordova.fireDocumentEvent('volumeupbutton');");
                     return true;
             }
@@ -732,7 +721,7 @@ public class CordovaWebView extends WebView {
         }
         else if(keyCode == KeyEvent.KEYCODE_BACK)
         {
-            return !(this.startOfHistory()) || this.bound;
+            return !(this.startOfHistory()) || isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);
         }
         else if(keyCode == KeyEvent.KEYCODE_MENU)
         {
@@ -749,10 +738,8 @@ public class CordovaWebView extends WebView {
                 return super.onKeyDown(keyCode, event);
             }
         }
-        
         return super.onKeyDown(keyCode, event);
     }
-    
 
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event)
@@ -762,10 +749,11 @@ public class CordovaWebView extends WebView {
             // A custom view is currently displayed  (e.g. playing a video)
             if(mCustomView != null) {
                 this.hideCustomView();
+                return true;
             } else {
                 // The webview is currently displayed
                 // If back key is bound, then send event to JavaScript
-                if (this.bound) {
+                if (isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK)) {
                     this.loadUrl("javascript:cordova.fireDocumentEvent('backbutton');");
                     return true;
                 } else {
@@ -791,48 +779,56 @@ public class CordovaWebView extends WebView {
             this.loadUrl("javascript:cordova.fireDocumentEvent('searchbutton');");
             return true;
         }
-        else if(keyUpCodes.contains(keyCode))
-        {
-            //What the hell should this do?
-            return super.onKeyUp(keyCode, event);
-        }
 
         //Does webkit change this behavior?
         return super.onKeyUp(keyCode, event);
     }
 
-    
+    public void setButtonPlumbedToJs(int keyCode, boolean value) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_VOLUME_DOWN:
+            case KeyEvent.KEYCODE_VOLUME_UP:
+            case KeyEvent.KEYCODE_BACK:
+                // TODO: Why are search and menu buttons handled separately?
+                boundKeyCodes.add(keyCode);
+                return;
+            default:
+                throw new IllegalArgumentException("Unsupported keycode: " + keyCode);
+        }
+    }
+
+    @Deprecated // Use setButtonPlumbedToJs() instead.
     public void bindButton(boolean override)
     {
-        this.bound = override;
+        setButtonPlumbedToJs(KeyEvent.KEYCODE_BACK, override);
     }
 
+    @Deprecated // Use setButtonPlumbedToJs() instead.
     public void bindButton(String button, boolean override) {
-        // TODO Auto-generated method stub
         if (button.compareTo("volumeup")==0) {
-          keyDownCodes.add(KeyEvent.KEYCODE_VOLUME_UP);
+            setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_UP, override);
         }
         else if (button.compareTo("volumedown")==0) {
-          keyDownCodes.add(KeyEvent.KEYCODE_VOLUME_DOWN);
+            setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_DOWN, override);
         }
-      }
+    }
 
+    @Deprecated // Use setButtonPlumbedToJs() instead.
     public void bindButton(int keyCode, boolean keyDown, boolean override) {
-       if(keyDown)
-       {
-           keyDownCodes.add(keyCode);
-       }
-       else
-       {
-           keyUpCodes.add(keyCode);
-       }
+        setButtonPlumbedToJs(keyCode, override);
     }
 
+    @Deprecated // Use isButtonPlumbedToJs
     public boolean isBackButtonBound()
     {
-        return this.bound;
+        return isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);
     }
-    
+
+    public boolean isButtonPlumbedToJs(int keyCode)
+    {
+        return boundKeyCodes.contains(keyCode);
+    }
+
     public void handlePause(boolean keepRunning)
     {
         LOG.d(TAG, "Handle the pause");
@@ -904,8 +900,9 @@ public class CordovaWebView extends WebView {
         return paused;
     }
 
+    @Deprecated // This never did anything.
     public boolean hadKeyEvent() {
-        return handleButton;
+        return false;
     }
 
     // Wrapping these functions in their own class prevents warnings in adb like:


[3/9] android commit: CB-5971: Factor out package/project name validation logic

Posted by ag...@apache.org.
CB-5971: Factor out package/project name validation logic


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

Branch: refs/heads/4.0.x
Commit: ff260c03caedeeaaf00563e117faefb8004f269b
Parents: 297f862
Author: Ian Clelland <ic...@chromium.org>
Authored: Tue Jun 24 13:49:12 2014 -0400
Committer: Ian Clelland <ic...@chromium.org>
Committed: Tue Jun 24 14:05:56 2014 -0400

----------------------------------------------------------------------
 bin/lib/create.js | 76 +++++++++++++++++++++++++++++++++-----------------
 1 file changed, 50 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/ff260c03/bin/lib/create.js
----------------------------------------------------------------------
diff --git a/bin/lib/create.js b/bin/lib/create.js
index f99d1da..8a90827 100755
--- a/bin/lib/create.js
+++ b/bin/lib/create.js
@@ -107,6 +107,50 @@ function copyScripts(projectPath) {
 }
 
 /**
+ * Test whether a package name is acceptable for use as an android project.
+ * Returns a promise, fulfilled if the package name is acceptable; rejected
+ * otherwise.
+ */
+function validatePackageName(package_name) {
+    //Make the package conform to Java package types
+    if (!/[a-zA-Z0-9_]+\.[a-zA-Z0-9_](.[a-zA-Z0-9_])*/.test(package_name)) {
+        return Q.reject('Package name must look like: com.company.Name');
+    }
+
+    //Enforce underscore limitation
+    if (/[_]+[a-zA-Z0-9_]*/.test(package_name)) {
+        return Q.reject("Package name can't begin with an underscore");
+    }
+
+    //Class is a reserved word
+    if(/[C|c]+lass+[\s|\.]/.test(package_name) && !/[a-zA-Z0-9_]+[C|c]+lass/.test(package_name))
+    {
+        return Q.reject('class is a reserved word');
+    }
+
+    return Q.resolve();
+}
+
+/**
+ * Test whether a project name is acceptable for use as an android class.
+ * Returns a promise, fulfilled if the project name is acceptable; rejected
+ * otherwise.
+ */
+function validateProjectName(project_name) {
+    //Enforce stupid name error
+    if (project_name === 'CordovaActivity') {
+        return Q.reject('Project name cannot be CordovaActivity');
+    }
+
+    //Classes in Java don't begin with numbers
+    if (/^[0-9]/.test(project_name)) {
+        return Q.reject('Project name must not begin with a number');
+    }
+
+    return Q.resolve();
+}
+
+/**
  * $ create [options]
  *
  * Creates an android application with the given options.
@@ -146,34 +190,14 @@ exports.createProject = function(project_path, package_name, project_name, proje
     }
 
     //Make the package conform to Java package types
-    if (!/[a-zA-Z0-9_]+\.[a-zA-Z0-9_](.[a-zA-Z0-9_])*/.test(package_name)) {
-        return Q.reject('Package name must look like: com.company.Name');
-    }
-
-    //Enforce underscore limitation
-    if (/[_]+[a-zA-Z0-9_]*/.test(package_name)) {
-        return Q.reject("Package name can't begin with an underscore");
-    }
-
-    //Enforce stupid name error
-    if (project_name === 'CordovaActivity') {
-        return Q.reject('Project name cannot be CordovaActivity');
-    }
-
-    //Classes in Java don't begin with numbers
-    if (/[0-9]+[a-zA-Z0-9]/.test(project_name)) {
-        return Q.reject('Project name must not begin with a number');
-    }
-
-    //Class is a reserved word
-    if(/[C|c]+lass+[\s|\.]/.test(package_name) && !/[a-zA-Z0-9_]+[C|c]+lass/.test(package_name))
-    {
-        return Q.reject('class is a reserved word');
-    }
-
+    return validatePackageName(package_name)
+    .then(function() {
+        validateProjectName(project_name);
+    })
     // Check that requirements are met and proper targets are installed
-    return check_reqs.run()
     .then(function() {
+        check_reqs.run();
+    }).then(function() {
         // Log the given values for the project
         console.log('Creating Cordova project for the Android platform:');
         console.log('\tPath: ' + project_path);


[7/9] android commit: Merge branch 'master' into 4.0.x (bindButton changes)

Posted by ag...@apache.org.
Merge branch 'master' into 4.0.x (bindButton changes)

Conflicts:
	framework/src/org/apache/cordova/CordovaWebView.java
	package.json


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

Branch: refs/heads/4.0.x
Commit: 4ce5123a12ec7e9e5248b7a09f70cc62dc4c30de
Parents: 96a1192 4b4a2e9
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Jun 24 15:22:27 2014 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Jun 24 15:22:27 2014 -0400

----------------------------------------------------------------------
 bin/lib/create.js                               | 80 ++++++++++++-------
 .../src/org/apache/cordova/AndroidWebView.java  | 74 ++++++------------
 .../src/org/apache/cordova/CordovaWebView.java  |  7 +-
 .../src/org/apache/cordova/CoreAndroid.java     | 12 ++-
 .../src/org/apache/cordova/PluginManager.java   |  1 +
 package.json                                    |  7 ++
 spec/create.spec.js                             | 82 ++++++++++++++++++++
 7 files changed, 177 insertions(+), 86 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4ce5123a/bin/lib/create.js
----------------------------------------------------------------------
diff --cc bin/lib/create.js
index 5e21b89,b2490f2..485c60e
--- a/bin/lib/create.js
+++ b/bin/lib/create.js
@@@ -109,14 -106,51 +109,58 @@@ function copyScripts(projectPath) 
      shell.cp(path.join(ROOT, 'bin', 'lib', 'android_sdk_version.js'), path.join(projectPath, 'cordova', 'lib', 'android_sdk_version.js'));
  }
  
 +function copyGradleWrapper(sdkPath, projectPath) {
 +    var wrapperDir = path.join(sdkPath, 'tools', 'templates','gradle','wrapper');
 +    shell.cp(path.join(wrapperDir, 'gradlew'), projectPath);
 +    shell.cp(path.join(wrapperDir, 'gradlew.bat'), projectPath);
 +    shell.cp('-r', path.join(wrapperDir, 'gradle'), projectPath);
 +}
 +
  /**
+  * Test whether a package name is acceptable for use as an android project.
+  * Returns a promise, fulfilled if the package name is acceptable; rejected
+  * otherwise.
+  */
+ function validatePackageName(package_name) {
+     //Make the package conform to Java package types
+     //Enforce underscore limitation
+     if (!/^[a-zA-Z]+(\.[a-zA-Z0-9][a-zA-Z0-9_]*)+$/.test(package_name)) {
+         return Q.reject('Package name must look like: com.company.Name');
+     }
+ 
+     //Class is a reserved word
+     if(/\b[Cc]lass\b/.test(package_name)) {
+         return Q.reject('class is a reserved word');
+     }
+ 
+     return Q.resolve();
+ }
+ 
+ /**
+  * Test whether a project name is acceptable for use as an android class.
+  * Returns a promise, fulfilled if the project name is acceptable; rejected
+  * otherwise.
+  */
+ function validateProjectName(project_name) {
+     //Make sure there's something there
+     if (project_name === '') {
+         return Q.reject('Project name cannot be empty');
+     }
+ 
+     //Enforce stupid name error
+     if (project_name === 'CordovaActivity') {
+         return Q.reject('Project name cannot be CordovaActivity');
+     }
+ 
+     //Classes in Java don't begin with numbers
+     if (/^[0-9]/.test(project_name)) {
+         return Q.reject('Project name must not begin with a number');
+     }
+ 
+     return Q.resolve();
+ }
+ 
+ /**
   * $ create [options]
   *
   * Creates an android application with the given options.

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4ce5123a/framework/src/org/apache/cordova/AndroidWebView.java
----------------------------------------------------------------------
diff --cc framework/src/org/apache/cordova/AndroidWebView.java
index 5001b64,0000000..49ec782
mode 100755,000000..100755
--- a/framework/src/org/apache/cordova/AndroidWebView.java
+++ b/framework/src/org/apache/cordova/AndroidWebView.java
@@@ -1,1090 -1,0 +1,1060 @@@
 +/*
 +       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.
 +*/
 +
 +package org.apache.cordova;
 +
 +import java.lang.reflect.InvocationTargetException;
 +import java.lang.reflect.Method;
- import java.util.ArrayList;
 +import java.util.HashMap;
++import java.util.HashSet;
 +import java.util.Locale;
 +
 +import org.apache.cordova.Config;
 +import org.apache.cordova.CordovaInterface;
 +import org.apache.cordova.LOG;
 +import org.apache.cordova.PluginManager;
 +import org.apache.cordova.PluginResult;
 +import org.json.JSONException;
 +
 +import android.annotation.SuppressLint;
 +import android.annotation.TargetApi;
 +import android.content.BroadcastReceiver;
 +import android.content.Context;
 +import android.content.Intent;
 +import android.content.IntentFilter;
 +import android.content.pm.ApplicationInfo;
 +import android.content.pm.PackageManager;
 +import android.content.pm.PackageManager.NameNotFoundException;
 +import android.net.Uri;
 +import android.os.Build;
 +import android.os.Bundle;
 +import android.util.AttributeSet;
 +import android.util.Log;
 +import android.view.Gravity;
 +import android.view.KeyEvent;
 +import android.view.View;
 +import android.view.ViewGroup;
 +import android.view.WindowManager;
 +import android.view.inputmethod.InputMethodManager;
 +import android.webkit.WebBackForwardList;
 +import android.webkit.WebHistoryItem;
 +import android.webkit.WebChromeClient;
 +import android.webkit.WebSettings;
 +import android.webkit.WebView;
 +import android.webkit.WebSettings.LayoutAlgorithm;
 +import android.webkit.WebViewClient;
 +import android.widget.FrameLayout;
 +
 +/*
 + * This class is our web view.
 + *
 + * @see <a href="http://developer.android.com/guide/webapps/webview.html">WebView guide</a>
 + * @see <a href="http://developer.android.com/reference/android/webkit/WebView.html">WebView</a>
 + */
 +public class AndroidWebView extends WebView implements CordovaWebView {
 +
 +    public static final String TAG = "CordovaWebView";
 +    public static final String CORDOVA_VERSION = "4.0.0-dev";
 +
-     private ArrayList<Integer> keyDownCodes = new ArrayList<Integer>();
-     private ArrayList<Integer> keyUpCodes = new ArrayList<Integer>();
++    private HashSet<Integer> boundKeyCodes = new HashSet<Integer>();
 +
 +    PluginManager pluginManager;
 +    private boolean paused;
 +
 +    private BroadcastReceiver receiver;
 +
 +
 +    /** Activities and other important classes **/
 +    private CordovaInterface cordova;
 +    CordovaWebViewClient viewClient;
 +    @SuppressWarnings("unused")
 +    private CordovaChromeClient chromeClient;
 +
 +    private String url;
 +
 +    // Flag to track that a loadUrl timeout occurred
 +    int loadUrlTimeout = 0;
 +
-     private boolean bound;
- 
-     private boolean handleButton = false;
-     
 +    private long lastMenuEventTime = 0;
 +
 +    NativeToJsMessageQueue jsMessageQueue;
 +    ExposedJsApi exposedJsApi;
 +
 +    /** custom view created by the browser (a video player for example) */
 +    private View mCustomView;
 +    private WebChromeClient.CustomViewCallback mCustomViewCallback;
 +
 +    private ActivityResult mResult = null;
 +
 +    private CordovaResourceApi resourceApi;
 +
 +    class ActivityResult {
 +        
 +        int request;
 +        int result;
 +        Intent incoming;
 +        
 +        public ActivityResult(int req, int res, Intent intent) {
 +            request = req;
 +            result = res;
 +            incoming = intent;
 +        }
 +
 +        
 +    }
 +    
 +    static final FrameLayout.LayoutParams COVER_SCREEN_GRAVITY_CENTER =
 +            new FrameLayout.LayoutParams(
 +            ViewGroup.LayoutParams.MATCH_PARENT,
 +            ViewGroup.LayoutParams.MATCH_PARENT,
 +            Gravity.CENTER);
 +    
 +    
 +    /**
 +     * Constructor.
 +     *
 +     * @param context
 +     */
 +    public AndroidWebView(Context context) {
 +        super(context);
 +        if (CordovaInterface.class.isInstance(context))
 +        {
 +            this.cordova = (CordovaInterface) context;
 +        }
 +        else
 +        {
 +            Log.d(TAG, "Your activity must implement CordovaInterface to work");
 +        }
 +        this.loadConfiguration();
 +        this.setup();
 +    }
 +
 +    /**
 +     * Constructor.
 +     *
 +     * @param context
 +     * @param attrs
 +     */
 +    public AndroidWebView(Context context, AttributeSet attrs) {
 +        super(context, attrs);
 +        if (CordovaInterface.class.isInstance(context))
 +        {
 +            this.cordova = (CordovaInterface) context;
 +        }
 +        else
 +        {
 +            Log.d(TAG, "Your activity must implement CordovaInterface to work");
 +        }
 +        this.loadConfiguration();
 +        this.setup();
 +    }
 +
 +    /**
 +     * Constructor.
 +     *
 +     * @param context
 +     * @param attrs
 +     * @param defStyle
 +     *
 +     */
 +    public AndroidWebView(Context context, AttributeSet attrs, int defStyle) {
 +        super(context, attrs, defStyle);
 +        if (CordovaInterface.class.isInstance(context))
 +        {
 +            this.cordova = (CordovaInterface) context;
 +        }
 +        else
 +        {
 +            Log.d(TAG, "Your activity must implement CordovaInterface to work");
 +        }
 +        this.loadConfiguration();
 +        this.setup();
 +    }
 +
 +    /**
 +     * Constructor.
 +     *
 +     * @param context
 +     * @param attrs
 +     * @param defStyle
 +     * @param privateBrowsing
 +     */
 +    @TargetApi(11)
 +    public AndroidWebView(Context context, AttributeSet attrs, int defStyle, boolean privateBrowsing) {
 +        super(context, attrs, defStyle, privateBrowsing);
 +        if (CordovaInterface.class.isInstance(context))
 +        {
 +            this.cordova = (CordovaInterface) context;
 +        }
 +        else
 +        {
 +            Log.d(TAG, "Your activity must implement CordovaInterface to work");
 +        }
 +        this.loadConfiguration();
 +        this.setup();
 +    }
 +
 +    /**
 +     * Create a default WebViewClient object for this webview. This can be overridden by the
 +     * main application's CordovaActivity subclass.
 +     *
 +     * There are two possible client objects that can be returned:
 +     *   AndroidWebViewClient for android < 3.0
 +     *   IceCreamCordovaWebViewClient for Android >= 3.0 (Supports shouldInterceptRequest)
 +     */
 +    @Override
 +    public CordovaWebViewClient makeWebViewClient() {
 +        if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB)
 +        {
 +            return (CordovaWebViewClient) new AndroidWebViewClient(this.cordova, this);
 +        }
 +        else
 +        {
 +            return (CordovaWebViewClient) new IceCreamCordovaWebViewClient(this.cordova, this);
 +        }
 +    }
 +
 +    /**
 +     * Create a default WebViewClient object for this webview. This can be overridden by the
 +     * main application's CordovaActivity subclass.
 +     */
 +    @Override
 +    public CordovaChromeClient makeWebChromeClient() {
 +        return (CordovaChromeClient) new AndroidChromeClient(this.cordova);
 +    }
 +
 +    /**
 +     * Initialize webview.
 +     */
 +    @SuppressWarnings("deprecation")
 +    @SuppressLint("NewApi")
 +    private void setup() {
 +        this.setInitialScale(0);
 +        this.setVerticalScrollBarEnabled(false);
 +        if (shouldRequestFocusOnInit()) {
 +			this.requestFocusFromTouch();
 +		}
 +		// Enable JavaScript
 +        WebSettings settings = this.getSettings();
 +        settings.setJavaScriptEnabled(true);
 +        settings.setJavaScriptCanOpenWindowsAutomatically(true);
 +        settings.setLayoutAlgorithm(LayoutAlgorithm.NORMAL);
 +        
 +        // Set the nav dump for HTC 2.x devices (disabling for ICS, deprecated entirely for Jellybean 4.2)
 +        try {
 +            Method gingerbread_getMethod =  WebSettings.class.getMethod("setNavDump", new Class[] { boolean.class });
 +            
 +            String manufacturer = android.os.Build.MANUFACTURER;
 +            Log.d(TAG, "CordovaWebView is running on device made by: " + manufacturer);
 +            if(android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB &&
 +                    android.os.Build.MANUFACTURER.contains("HTC"))
 +            {
 +                gingerbread_getMethod.invoke(settings, true);
 +            }
 +        } catch (NoSuchMethodException e) {
 +            Log.d(TAG, "We are on a modern version of Android, we will deprecate HTC 2.3 devices in 2.8");
 +        } catch (IllegalArgumentException e) {
 +            Log.d(TAG, "Doing the NavDump failed with bad arguments");
 +        } catch (IllegalAccessException e) {
 +            Log.d(TAG, "This should never happen: IllegalAccessException means this isn't Android anymore");
 +        } catch (InvocationTargetException e) {
 +            Log.d(TAG, "This should never happen: InvocationTargetException means this isn't Android anymore.");
 +        }
 +
 +        //We don't save any form data in the application
 +        settings.setSaveFormData(false);
 +        settings.setSavePassword(false);
 +        
 +        // Jellybean rightfully tried to lock this down. Too bad they didn't give us a whitelist
 +        // while we do this
 +        if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
 +            Level16Apis.enableUniversalAccess(settings);
 +        // Enable database
 +        // We keep this disabled because we use or shim to get around DOM_EXCEPTION_ERROR_16
 +        String databasePath = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
 +        settings.setDatabaseEnabled(true);
 +        settings.setDatabasePath(databasePath);
 +        
 +        
 +        //Determine whether we're in debug or release mode, and turn on Debugging!
 +        try {
 +            final String packageName = this.cordova.getActivity().getPackageName();
 +            final PackageManager pm = this.cordova.getActivity().getPackageManager();
 +            ApplicationInfo appInfo;
 +            
 +            appInfo = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
 +            
 +            if((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0 &&  
 +                android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT)
 +            {
 +                setWebContentsDebuggingEnabled(true);
 +            }
 +        } catch (IllegalArgumentException e) {
 +            Log.d(TAG, "You have one job! To turn on Remote Web Debugging! YOU HAVE FAILED! ");
 +            e.printStackTrace();
 +        } catch (NameNotFoundException e) {
 +            Log.d(TAG, "This should never happen: Your application's package can't be found.");
 +            e.printStackTrace();
 +        }  
 +        
 +        settings.setGeolocationDatabasePath(databasePath);
 +
 +        // Enable DOM storage
 +        settings.setDomStorageEnabled(true);
 +
 +        // Enable built-in geolocation
 +        settings.setGeolocationEnabled(true);
 +        
 +        // Enable AppCache
 +        // Fix for CB-2282
 +        settings.setAppCacheMaxSize(5 * 1048576);
 +        String pathToCache = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
 +        settings.setAppCachePath(pathToCache);
 +        settings.setAppCacheEnabled(true);
 +        
 +        // Fix for CB-1405
 +        // Google issue 4641
 +        this.updateUserAgentString();
 +        
 +        IntentFilter intentFilter = new IntentFilter();
 +        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
 +        if (this.receiver == null) {
 +            this.receiver = new BroadcastReceiver() {
 +                @Override
 +                public void onReceive(Context context, Intent intent) {
 +                    updateUserAgentString();
 +                }
 +            };
 +            this.cordova.getActivity().registerReceiver(this.receiver, intentFilter);
 +        }
 +        // end CB-1405
 +
 +        pluginManager = new PluginManager(this, this.cordova);
 +        jsMessageQueue = new NativeToJsMessageQueue(this, cordova);
 +        exposedJsApi = new AndroidExposedJsApi(pluginManager, jsMessageQueue);
 +        resourceApi = new CordovaResourceApi(this.getContext(), pluginManager);
 +        exposeJsInterface();
 +    }
 +
 +	/**
 +	 * Override this method to decide whether or not you need to request the
 +	 * focus when your application start
 +	 * 
 +	 * @return true unless this method is overriden to return a different value
 +	 */
 +    protected boolean shouldRequestFocusOnInit() {
 +		return true;
 +	}
 +
 +	private void updateUserAgentString() {
 +        this.getSettings().getUserAgentString();
 +    }
 +
 +    private void exposeJsInterface() {
 +        int SDK_INT = Build.VERSION.SDK_INT;
 +        if ((SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)) {
 +            Log.i(TAG, "Disabled addJavascriptInterface() bridge since Android version is old.");
 +            // Bug being that Java Strings do not get converted to JS strings automatically.
 +            // This isn't hard to work-around on the JS side, but it's easier to just
 +            // use the prompt bridge instead.
 +            return;            
 +        } 
 +        this.addJavascriptInterface(exposedJsApi, "_cordovaNative");
 +    }
 +
 +    /**
 +     * Set the WebViewClient.
 +     *
 +     * @param client
 +     */
 +    public void setWebViewClient(CordovaWebViewClient client) {
 +        this.viewClient = client;
 +        super.setWebViewClient((WebViewClient) client);
 +    }
 +
 +    /**
 +     * Set the WebChromeClient.
 +     *
 +     * @param client
 +     */
 +    public void setWebChromeClient(CordovaChromeClient client) {
 +        this.chromeClient = client;
 +        super.setWebChromeClient((WebChromeClient) client);
 +    }
 +    
 +    public CordovaChromeClient getWebChromeClient() {
 +        return this.chromeClient;
 +    }
 +
 +    /**
 +     * Load the url into the webview.
 +     *
 +     * @param url
 +     */
 +    @Override
 +    public void loadUrl(String url) {
 +        if (url.equals("about:blank") || url.startsWith("javascript:")) {
 +            this.loadUrlNow(url);
 +        }
 +        else {
 +
 +            String initUrl = this.getProperty("url", null);
 +
 +            // If first page of app, then set URL to load to be the one passed in
 +            if (initUrl == null) {
 +                this.loadUrlIntoView(url);
 +            }
 +            // Otherwise use the URL specified in the activity's extras bundle
 +            else {
 +                this.loadUrlIntoView(initUrl);
 +            }
 +        }
 +    }
 +
 +    /**
 +     * Load the url into the webview after waiting for period of time.
 +     * This is used to display the splashscreen for certain amount of time.
 +     *
 +     * @param url
 +     * @param time              The number of ms to wait before loading webview
 +     */
 +    public void loadUrl(final String url, int time) {
 +        String initUrl = this.getProperty("url", null);
 +
 +        // If first page of app, then set URL to load to be the one passed in
 +        if (initUrl == null) {
 +            this.loadUrlIntoView(url, time);
 +        }
 +        // Otherwise use the URL specified in the activity's extras bundle
 +        else {
 +            this.loadUrlIntoView(initUrl);
 +        }
 +    }
 +
 +    public void loadUrlIntoView(final String url) {
 +        loadUrlIntoView(url, true);
 +    }
 +
 +    /**
 +     * Load the url into the webview.
 +     *
 +     * @param url
 +     */
 +    public void loadUrlIntoView(final String url, boolean recreatePlugins) {
 +        LOG.d(TAG, ">>> loadUrl(" + url + ")");
 +
 +        if (recreatePlugins) {
 +            this.url = url;
 +            this.pluginManager.init();
 +        }
 +
 +        // Create a timeout timer for loadUrl
 +        final AndroidWebView me = this;
 +        final int currentLoadUrlTimeout = me.loadUrlTimeout;
 +        final int loadUrlTimeoutValue = Integer.parseInt(this.getProperty("LoadUrlTimeoutValue", "20000"));
 +
 +        // Timeout error method
 +        final Runnable loadError = new Runnable() {
 +            public void run() {
 +                me.stopLoading();
 +                LOG.e(TAG, "CordovaWebView: TIMEOUT ERROR!");
 +                if (viewClient != null) {
 +                    viewClient.onReceivedError(-6, "The connection to the server was unsuccessful.", url);
 +                }
 +            }
 +        };
 +
 +        // Timeout timer method
 +        final Runnable timeoutCheck = new Runnable() {
 +            public void run() {
 +                try {
 +                    synchronized (this) {
 +                        wait(loadUrlTimeoutValue);
 +                    }
 +                } catch (InterruptedException e) {
 +                    e.printStackTrace();
 +                }
 +
 +                // If timeout, then stop loading and handle error
 +                if (me.loadUrlTimeout == currentLoadUrlTimeout) {
 +                    me.cordova.getActivity().runOnUiThread(loadError);
 +                }
 +            }
 +        };
 +
 +        // Load url
 +        this.cordova.getActivity().runOnUiThread(new Runnable() {
 +            public void run() {
 +                cordova.getThreadPool().execute(timeoutCheck);
 +                me.loadUrlNow(url);
 +            }
 +        });
 +    }
 +
 +    /**
 +     * Load URL in webview.
 +     *
 +     * @param url
 +     */
 +    public void loadUrlNow(String url) {
 +        if (LOG.isLoggable(LOG.DEBUG) && !url.startsWith("javascript:")) {
 +            LOG.d(TAG, ">>> loadUrlNow()");
 +        }
 +        if (url.startsWith("file://") || url.startsWith("javascript:") || Config.isUrlWhiteListed(url)) {
 +            super.loadUrl(url);
 +        }
 +    }
 +
 +    /**
 +     * Load the url into the webview after waiting for period of time.
 +     * This is used to display the splashscreen for certain amount of time.
 +     *
 +     * @param url
 +     * @param time              The number of ms to wait before loading webview
 +     */
 +    public void loadUrlIntoView(final String url, final int time) {
 +
 +        // If not first page of app, then load immediately
 +        // Add support for browser history if we use it.
 +        if ((url.startsWith("javascript:")) || this.canGoBack()) {
 +        }
 +
 +        // If first page, then show splashscreen
 +        else {
 +
 +            LOG.d(TAG, "loadUrlIntoView(%s, %d)", url, time);
 +
 +            // Send message to show splashscreen now if desired
 +            this.postMessage("splashscreen", "show");
 +        }
 +
 +        // Load url
 +        this.loadUrlIntoView(url);
 +    }
 +    
 +    @Override
 +    public void stopLoading() {
 +        //viewClient.isCurrentlyLoading = false;
 +        super.stopLoading();
 +    }
 +    
 +    public void onScrollChanged(int l, int t, int oldl, int oldt)
 +    {
 +        super.onScrollChanged(l, t, oldl, oldt);
 +        //We should post a message that the scroll changed
 +        ScrollEvent myEvent = new ScrollEvent(l, t, oldl, oldt, this);
 +        this.postMessage("onScrollChanged", myEvent);
 +    }
 +    
 +    /**
 +     * Send JavaScript statement back to JavaScript.
 +     * (This is a convenience method)
 +     *
 +     * @param statement
 +     */
 +    public void sendJavascript(String statement) {
 +        this.jsMessageQueue.addJavaScript(statement);
 +    }
 +
 +    /**
 +     * Send a plugin result back to JavaScript.
 +     * (This is a convenience method)
 +     *
 +     * @param result
 +     * @param callbackId
 +     */
 +    public void sendPluginResult(PluginResult result, String callbackId) {
 +        this.jsMessageQueue.addPluginResult(result, callbackId);
 +    }
 +
 +    /**
 +     * Send a message to all plugins.
 +     *
 +     * @param id            The message id
 +     * @param data          The message data
 +     */
 +    public void postMessage(String id, Object data) {
 +        if (this.pluginManager != null) {
 +            this.pluginManager.postMessage(id, data);
 +        }
 +    }
 +
 +
 +    /**
 +     * Go to previous page in history.  (We manage our own history)
 +     *
 +     * @return true if we went back, false if we are already at top
 +     */
 +    public boolean backHistory() {
 +
 +        // Check webview first to see if there is a history
 +        // This is needed to support curPage#diffLink, since they are added to appView's history, but not our history url array (JQMobile behavior)
 +        if (super.canGoBack()) {
 +            printBackForwardList();
 +            super.goBack();
 +            
 +            return true;
 +        }
 +        return false;
 +    }
 +
 +
 +    /**
 +     * Load the specified URL in the Cordova webview or a new browser instance.
 +     *
 +     * NOTE: If openExternal is false, only URLs listed in whitelist can be loaded.
 +     *
 +     * @param url           The url to load.
 +     * @param openExternal  Load url in browser instead of Cordova webview.
 +     * @param clearHistory  Clear the history stack, so new page becomes top of history
 +     * @param params        Parameters for new app
 +     */
 +    public void showWebPage(String url, boolean openExternal, boolean clearHistory, HashMap<String, Object> params) {
 +        LOG.d(TAG, "showWebPage(%s, %b, %b, HashMap", url, openExternal, clearHistory);
 +
 +        // If clearing history
 +        if (clearHistory) {
 +            this.clearHistory();
 +        }
 +
 +        // If loading into our webview
 +        if (!openExternal) {
 +
 +            // Make sure url is in whitelist
 +            if (url.startsWith("file://") || Config.isUrlWhiteListed(url)) {
 +                // TODO: What about params?
 +                // Load new URL
 +                this.loadUrl(url);
 +                return;
 +            }
 +            // Load in default viewer if not
 +            LOG.w(TAG, "showWebPage: Cannot load URL into webview since it is not in white list.  Loading into browser instead. (URL=" + url + ")");
 +        }
 +        try {
 +            // Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
 +            // Adding the MIME type to http: URLs causes them to not be handled by the downloader.
 +            Intent intent = new Intent(Intent.ACTION_VIEW);
 +            Uri uri = Uri.parse(url);
 +            if ("file".equals(uri.getScheme())) {
 +                intent.setDataAndType(uri, resourceApi.getMimeType(uri));
 +            } else {
 +                intent.setData(uri);
 +            }
 +            cordova.getActivity().startActivity(intent);
 +        } catch (android.content.ActivityNotFoundException e) {
 +            LOG.e(TAG, "Error loading url " + url, e);
 +        }
 +    }
 +
 +    /**
 +     * Check configuration parameters from Config.
 +     * Approved list of URLs that can be loaded into Cordova
 +     *      <access origin="http://server regexp" subdomains="true" />
 +     * Log level: ERROR, WARN, INFO, DEBUG, VERBOSE (default=ERROR)
 +     *      <log level="DEBUG" />
 +     */
 +    private void loadConfiguration() {
 + 
 +        if ("true".equals(this.getProperty("Fullscreen", "false"))) {
 +            this.cordova.getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
 +            this.cordova.getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
 +        }
 +    }
 +
 +    /**
 +     * Get string property for activity.
 +     *
 +     * @param name
 +     * @param defaultValue
 +     * @return the String value for the named property
 +     */
 +    public String getProperty(String name, String defaultValue) {
 +        Bundle bundle = this.cordova.getActivity().getIntent().getExtras();
 +        if (bundle == null) {
 +            return defaultValue;
 +        }
 +        name = name.toLowerCase(Locale.getDefault());
 +        Object p = bundle.get(name);
 +        if (p == null) {
 +            return defaultValue;
 +        }
 +        return p.toString();
 +    }
 +
 +    /*
 +     * onKeyDown
 +     */
 +    @Override
 +    public boolean onKeyDown(int keyCode, KeyEvent event)
 +    {
-         if(keyDownCodes.contains(keyCode))
++        if(boundKeyCodes.contains(keyCode))
 +        {
 +            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
-                     // only override default behavior is event bound
-                     LOG.d(TAG, "Down Key Hit");
 +                    this.loadUrl("javascript:cordova.fireDocumentEvent('volumedownbutton');");
 +                    return true;
 +            }
-             // If volumeup key
 +            else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
-                     LOG.d(TAG, "Up Key Hit");
 +                    this.loadUrl("javascript:cordova.fireDocumentEvent('volumeupbutton');");
 +                    return true;
 +            }
 +            else
 +            {
 +                return super.onKeyDown(keyCode, event);
 +            }
 +        }
 +        else if(keyCode == KeyEvent.KEYCODE_BACK)
 +        {
-             return !(this.startOfHistory()) || this.bound;
++            return !(this.startOfHistory()) || isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);
++
 +        }
 +        else if(keyCode == KeyEvent.KEYCODE_MENU)
 +        {
 +            //How did we get here?  Is there a childView?
 +            View childView = this.getFocusedChild();
 +            if(childView != null)
 +            {
 +                //Make sure we close the keyboard if it's present
 +                InputMethodManager imm = (InputMethodManager) cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
 +                imm.hideSoftInputFromWindow(childView.getWindowToken(), 0);
 +                cordova.getActivity().openOptionsMenu();
 +                return true;
 +            } else {
 +                return super.onKeyDown(keyCode, event);
 +            }
 +        }
-         
 +        return super.onKeyDown(keyCode, event);
 +    }
-     
 +
 +    @Override
 +    public boolean onKeyUp(int keyCode, KeyEvent event)
 +    {
 +        // If back key
 +        if (keyCode == KeyEvent.KEYCODE_BACK) {
 +            // A custom view is currently displayed  (e.g. playing a video)
 +            if(mCustomView != null) {
 +                this.hideCustomView();
++                return true;
 +            } else {
 +                // The webview is currently displayed
 +                // If back key is bound, then send event to JavaScript
-                 if (this.bound) {
++                if (isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK)) {
 +                    this.loadUrl("javascript:cordova.fireDocumentEvent('backbutton');");
 +                    return true;
 +                } else {
 +                    // If not bound
 +                    // Go to previous page in webview if it is possible to go back
 +                    if (this.backHistory()) {
 +                        return true;
 +                    }
 +                    // If not, then invoke default behavior
 +                }
 +            }
 +        }
 +        // Legacy
 +        else if (keyCode == KeyEvent.KEYCODE_MENU) {
 +            if (this.lastMenuEventTime < event.getEventTime()) {
 +                this.loadUrl("javascript:cordova.fireDocumentEvent('menubutton');");
 +            }
 +            this.lastMenuEventTime = event.getEventTime();
 +            return super.onKeyUp(keyCode, event);
 +        }
 +        // If search key
 +        else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
 +            this.loadUrl("javascript:cordova.fireDocumentEvent('searchbutton');");
 +            return true;
 +        }
-         else if(keyUpCodes.contains(keyCode))
-         {
-             //What the hell should this do?
-             return super.onKeyUp(keyCode, event);
-         }
 +
 +        //Does webkit change this behavior?
 +        return super.onKeyUp(keyCode, event);
 +    }
 +
-     
-     public void bindButton(boolean override)
-     {
-         this.bound = override;
-     }
- 
-     public void bindButton(String button, boolean override) {
-         // TODO Auto-generated method stub
-         if (button.compareTo("volumeup")==0) {
-           keyDownCodes.add(KeyEvent.KEYCODE_VOLUME_UP);
-         }
-         else if (button.compareTo("volumedown")==0) {
-           keyDownCodes.add(KeyEvent.KEYCODE_VOLUME_DOWN);
++    @Override
++    public void setButtonPlumbedToJs(int keyCode, boolean value) {
++        switch (keyCode) {
++            case KeyEvent.KEYCODE_VOLUME_DOWN:
++            case KeyEvent.KEYCODE_VOLUME_UP:
++            case KeyEvent.KEYCODE_BACK:
++                // TODO: Why are search and menu buttons handled separately?
++                boundKeyCodes.add(keyCode);
++                return;
++            default:
++                throw new IllegalArgumentException("Unsupported keycode: " + keyCode);
 +        }
-       }
- 
-     public void bindButton(int keyCode, boolean keyDown, boolean override) {
-        if(keyDown)
-        {
-            keyDownCodes.add(keyCode);
-        }
-        else
-        {
-            keyUpCodes.add(keyCode);
-        }
 +    }
 +
-     public boolean isBackButtonBound()
++    @Override
++    public boolean isButtonPlumbedToJs(int keyCode)
 +    {
-         return this.bound;
++        return boundKeyCodes.contains(keyCode);
 +    }
-     
++
 +    public void handlePause(boolean keepRunning)
 +    {
 +        LOG.d(TAG, "Handle the pause");
 +        // Send pause event to JavaScript
 +        this.loadUrl("javascript:try{cordova.fireDocumentEvent('pause');}catch(e){console.log('exception firing pause event from native');};");
 +
 +        // Forward to plugins
 +        if (this.pluginManager != null) {
 +            this.pluginManager.onPause(keepRunning);
 +        }
 +
 +        // If app doesn't want to run in background
 +        if (!keepRunning) {
 +            // Pause JavaScript timers (including setInterval)
 +            this.pauseTimers();
 +        }
 +        paused = true;
 +   
 +    }
 +    
 +    public void handleResume(boolean keepRunning, boolean activityResultKeepRunning)
 +    {
 +
 +        this.loadUrl("javascript:try{cordova.fireDocumentEvent('resume');}catch(e){console.log('exception firing resume event from native');};");
 +        
 +        // Forward to plugins
 +        if (this.pluginManager != null) {
 +            this.pluginManager.onResume(keepRunning);
 +        }
 +
 +        // Resume JavaScript timers (including setInterval)
 +        this.resumeTimers();
 +        paused = false;
 +    }
 +    
 +    public void handleDestroy()
 +    {
 +        // Send destroy event to JavaScript
 +        this.loadUrl("javascript:try{cordova.require('cordova/channel').onDestroy.fire();}catch(e){console.log('exception firing destroy event from native');};");
 +
 +        // Load blank page so that JavaScript onunload is called
 +        this.loadUrl("about:blank");
 +
 +        // Forward to plugins
 +        if (this.pluginManager != null) {
 +            this.pluginManager.onDestroy();
 +        }
 +        
 +        // unregister the receiver
 +        if (this.receiver != null) {
 +            try {
 +                this.cordova.getActivity().unregisterReceiver(this.receiver);
 +            } catch (Exception e) {
 +                Log.e(TAG, "Error unregistering configuration receiver: " + e.getMessage(), e);
 +            }
 +        }
 +    }
 +    
 +    public void onNewIntent(Intent intent)
 +    {
 +        //Forward to plugins
 +        if (this.pluginManager != null) {
 +            this.pluginManager.onNewIntent(intent);
 +        }
 +    }
 +    
 +    public boolean isPaused()
 +    {
 +        return paused;
 +    }
 +
-     public boolean hadKeyEvent() {
-         return handleButton;
-     }
- 
 +    // Wrapping these functions in their own class prevents warnings in adb like:
 +    // VFY: unable to resolve virtual method 285: Landroid/webkit/WebSettings;.setAllowUniversalAccessFromFileURLs
 +    @TargetApi(16)
 +    private static class Level16Apis {
 +        static void enableUniversalAccess(WebSettings settings) {
 +            settings.setAllowUniversalAccessFromFileURLs(true);
 +        }
 +    }
 +    
 +    public void printBackForwardList() {
 +        WebBackForwardList currentList = this.copyBackForwardList();
 +        int currentSize = currentList.getSize();
 +        for(int i = 0; i < currentSize; ++i)
 +        {
 +            WebHistoryItem item = currentList.getItemAtIndex(i);
 +            String url = item.getUrl();
 +            LOG.d(TAG, "The URL at index: " + Integer.toString(i) + " is " + url );
 +        }
 +    }
 +    
 +    
 +    //Can Go Back is BROKEN!
 +    public boolean startOfHistory()
 +    {
 +        WebBackForwardList currentList = this.copyBackForwardList();
 +        WebHistoryItem item = currentList.getItemAtIndex(0);
 +        if( item!=null){	// Null-fence in case they haven't called loadUrl yet (CB-2458)
 +	        String url = item.getUrl();
 +	        String currentUrl = this.getUrl();
 +	        LOG.d(TAG, "The current URL is: " + currentUrl);
 +	        LOG.d(TAG, "The URL at item 0 is: " + url);
 +	        return currentUrl.equals(url);
 +        }
 +        return false;
 +    }
 +
 +    public void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {
 +        // This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0
 +        Log.d(TAG, "showing Custom View");
 +        // if a view already exists then immediately terminate the new one
 +        if (mCustomView != null) {
 +            callback.onCustomViewHidden();
 +            return;
 +        }
 +        
 +        // Store the view and its callback for later (to kill it properly)
 +        mCustomView = view;
 +        mCustomViewCallback = callback;
 +        
 +        // Add the custom view to its container.
 +        ViewGroup parent = (ViewGroup) this.getParent();
 +        parent.addView(view, COVER_SCREEN_GRAVITY_CENTER);
 +        
 +        // Hide the content view.
 +        this.setVisibility(View.GONE);
 +        
 +        // Finally show the custom view container.
 +        parent.setVisibility(View.VISIBLE);
 +        parent.bringToFront();
 +    }
 +
 +    public void hideCustomView() {
 +        // This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0
 +        Log.d(TAG, "Hiding Custom View");
 +        if (mCustomView == null) return;
 +
 +        // Hide the custom view.
 +        mCustomView.setVisibility(View.GONE);
 +        
 +        // Remove the custom view from its container.
 +        ViewGroup parent = (ViewGroup) this.getParent();
 +        parent.removeView(mCustomView);
 +        mCustomView = null;
 +        mCustomViewCallback.onCustomViewHidden();
 +        
 +        // Show the content view.
 +        this.setVisibility(View.VISIBLE);
 +    }
 +    
 +    /**
 +     * if the video overlay is showing then we need to know 
 +     * as it effects back button handling
 +     * 
 +     * @return true if custom view is showing
 +     */
 +    public boolean isCustomViewShowing() {
 +        return mCustomView != null;
 +    }
 +    
 +    public WebBackForwardList restoreState(Bundle savedInstanceState)
 +    {
 +        WebBackForwardList myList = super.restoreState(savedInstanceState);
 +        Log.d(TAG, "WebView restoration crew now restoring!");
 +        //Initialize the plugin manager once more
 +        this.pluginManager.init();
 +        return myList;
 +    }
 +
 +    public void storeResult(int requestCode, int resultCode, Intent intent) {
 +        mResult = new ActivityResult(requestCode, resultCode, intent);
 +    }
 +    
 +    public CordovaResourceApi getResourceApi() {
 +        return resourceApi;
 +    }
 +
 +    @Override
 +    public void setLayoutParams(
 +            android.widget.LinearLayout.LayoutParams layoutParams) {
 +        super.setLayoutParams(layoutParams);
 +    }
 +
 +    @Override
 +    public void setOverScrollMode(int mode) {
 +        super.setOverScrollMode(mode);
 +    }
 +
 +    @Override
 +    public void addJavascript(String statement) {
 +        this.jsMessageQueue.addJavaScript(statement);
 +    }
 +
 +    @Override
 +    public CordovaPlugin getPlugin(String initCallbackClass) {
 +        // TODO Auto-generated method stub
 +        return this.pluginManager.getPlugin(initCallbackClass);
 +    }
 +
 +    @Override
 +    public String exec(String service, String action, String callbackId,
 +            String message) throws JSONException {
 +        return this.exposedJsApi.exec(service, action, callbackId, message);
 +    }
 +
 +    @Override
 +    public void setNativeToJsBridgeMode(int parseInt) {
 +        this.exposedJsApi.setNativeToJsBridgeMode(parseInt);
 +    }
 +
 +    @Override
 +    public String retrieveJsMessages(boolean equals) {
 +        return this.exposedJsApi.retrieveJsMessages(equals);
 +    }
 +
 +    @Override
 +    public boolean onOverrideUrlLoading(String url) {
 +        return this.pluginManager.onOverrideUrlLoading(url);
 +    }
 +
 +    @Override
 +    public void resetJsMessageQueue() {
 +        this.jsMessageQueue.reset();
 +    }
 +
 +    @Override
 +    public void onReset() {
 +        this.pluginManager.onReset();
 +    }
 +
 +    @Override
 +    public void incUrlTimeout() {
 +        this.loadUrlTimeout++;
 +    }
 +
 +    @Override
 +    public PluginManager getPluginManager() {
 +        // TODO Auto-generated method stub
 +        return this.pluginManager;
 +    }
 +
 +    @Override
 +    public void setLayoutParams(
 +            android.widget.FrameLayout.LayoutParams layoutParams) {
 +        super.setLayoutParams(layoutParams);
 +    }
 +
 +    @Override
 +    public View getView() {
 +        return this;
 +    }
 +
 +
 +}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4ce5123a/framework/src/org/apache/cordova/CordovaWebView.java
----------------------------------------------------------------------
diff --cc framework/src/org/apache/cordova/CordovaWebView.java
index 70c6051,b31eec5..6a9fbaf
mode 100644,100755..100644
--- a/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/framework/src/org/apache/cordova/CordovaWebView.java
@@@ -96,59 -571,443 +96,56 @@@ public interface CordovaWebView 
       *    savedCallbackContext.sendPluginResult(dataResult);
       */
      @Deprecated
 -    public void sendJavascript(String statement) {
 -        this.jsMessageQueue.addJavaScript(statement);
 -    }
 +    void sendJavascript(String statememt);
  
 -    /**
 -     * Send a plugin result back to JavaScript.
 -     * (This is a convenience method)
 -     *
 -     * @param result
 -     * @param callbackId
 -     */
 -    public void sendPluginResult(PluginResult result, String callbackId) {
 -        this.jsMessageQueue.addPluginResult(result, callbackId);
 -    }
 +    CordovaChromeClient getWebChromeClient();
  
 -    /**
 -     * Send a message to all plugins.
 -     *
 -     * @param id            The message id
 -     * @param data          The message data
 -     */
 -    public void postMessage(String id, Object data) {
 -        if (this.pluginManager != null) {
 -            this.pluginManager.postMessage(id, data);
 -        }
 -    }
 +    CordovaPlugin getPlugin(String initCallbackClass);
  
 +    void showWebPage(String errorUrl, boolean b, boolean c, HashMap<String, Object> params);
  
 -    /**
 -     * Go to previous page in history.  (We manage our own history)
 -     *
 -     * @return true if we went back, false if we are already at top
 -     */
 -    public boolean backHistory() {
 +    Object getFocusedChild();
  
 -        // Check webview first to see if there is a history
 -        // This is needed to support curPage#diffLink, since they are added to appView's history, but not our history url array (JQMobile behavior)
 -        if (super.canGoBack()) {
 -            printBackForwardList();
 -            super.goBack();
 -            
 -            return true;
 -        }
 -        return false;
 -    }
 +    boolean isCustomViewShowing();
  
 +    String exec(String service, String action, String callbackId, String message) throws JSONException;
  
 -    /**
 -     * Load the specified URL in the Cordova webview or a new browser instance.
 -     *
 -     * NOTE: If openExternal is false, only URLs listed in whitelist can be loaded.
 -     *
 -     * @param url           The url to load.
 -     * @param openExternal  Load url in browser instead of Cordova webview.
 -     * @param clearHistory  Clear the history stack, so new page becomes top of history
 -     * @param params        Parameters for new app
 -     */
 -    public void showWebPage(String url, boolean openExternal, boolean clearHistory, HashMap<String, Object> params) {
 -        LOG.d(TAG, "showWebPage(%s, %b, %b, HashMap", url, openExternal, clearHistory);
 -
 -        // If clearing history
 -        if (clearHistory) {
 -            this.clearHistory();
 -        }
 -
 -        // If loading into our webview
 -        if (!openExternal) {
 -
 -            // Make sure url is in whitelist
 -            if (url.startsWith("file://") || Config.isUrlWhiteListed(url)) {
 -                // TODO: What about params?
 -                // Load new URL
 -                this.loadUrl(url);
 -                return;
 -            }
 -            // Load in default viewer if not
 -            LOG.w(TAG, "showWebPage: Cannot load URL into webview since it is not in white list.  Loading into browser instead. (URL=" + url + ")");
 -        }
 -        try {
 -            // Omitting the MIME type for file: URLs causes "No Activity found to handle Intent".
 -            // Adding the MIME type to http: URLs causes them to not be handled by the downloader.
 -            Intent intent = new Intent(Intent.ACTION_VIEW);
 -            Uri uri = Uri.parse(url);
 -            if ("file".equals(uri.getScheme())) {
 -                intent.setDataAndType(uri, resourceApi.getMimeType(uri));
 -            } else {
 -                intent.setData(uri);
 -            }
 -            cordova.getActivity().startActivity(intent);
 -        } catch (android.content.ActivityNotFoundException e) {
 -            LOG.e(TAG, "Error loading url " + url, e);
 -        }
 -    }
 +    void setNativeToJsBridgeMode(int parseInt);
  
 -    /**
 -     * Check configuration parameters from Config.
 -     * Approved list of URLs that can be loaded into Cordova
 -     *      <access origin="http://server regexp" subdomains="true" />
 -     * Log level: ERROR, WARN, INFO, DEBUG, VERBOSE (default=ERROR)
 -     *      <log level="DEBUG" />
 -     */
 -    private void loadConfiguration() {
 - 
 -        if ("true".equals(this.getProperty("Fullscreen", "false"))) {
 -            this.cordova.getActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
 -            this.cordova.getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
 -        }
 -    }
 +    String retrieveJsMessages(boolean equals);
  
 -    /**
 -     * Get string property for activity.
 -     *
 -     * @param name
 -     * @param defaultValue
 -     * @return the String value for the named property
 -     */
 -    public String getProperty(String name, String defaultValue) {
 -        Bundle bundle = this.cordova.getActivity().getIntent().getExtras();
 -        if (bundle == null) {
 -            return defaultValue;
 -        }
 -        name = name.toLowerCase(Locale.getDefault());
 -        Object p = bundle.get(name);
 -        if (p == null) {
 -            return defaultValue;
 -        }
 -        return p.toString();
 -    }
 -
 -    @Override
 -    public boolean onKeyDown(int keyCode, KeyEvent event)
 -    {
 -        if(boundKeyCodes.contains(keyCode))
 -        {
 -            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
 -                    this.loadUrl("javascript:cordova.fireDocumentEvent('volumedownbutton');");
 -                    return true;
 -            }
 -            // If volumeup key
 -            else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
 -                    this.loadUrl("javascript:cordova.fireDocumentEvent('volumeupbutton');");
 -                    return true;
 -            }
 -            else
 -            {
 -                return super.onKeyDown(keyCode, event);
 -            }
 -        }
 -        else if(keyCode == KeyEvent.KEYCODE_BACK)
 -        {
 -            return !(this.startOfHistory()) || isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);
 -        }
 -        else if(keyCode == KeyEvent.KEYCODE_MENU)
 -        {
 -            //How did we get here?  Is there a childView?
 -            View childView = this.getFocusedChild();
 -            if(childView != null)
 -            {
 -                //Make sure we close the keyboard if it's present
 -                InputMethodManager imm = (InputMethodManager) cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
 -                imm.hideSoftInputFromWindow(childView.getWindowToken(), 0);
 -                cordova.getActivity().openOptionsMenu();
 -                return true;
 -            } else {
 -                return super.onKeyDown(keyCode, event);
 -            }
 -        }
 -        return super.onKeyDown(keyCode, event);
 -    }
 -
 -    @Override
 -    public boolean onKeyUp(int keyCode, KeyEvent event)
 -    {
 -        // If back key
 -        if (keyCode == KeyEvent.KEYCODE_BACK) {
 -            // A custom view is currently displayed  (e.g. playing a video)
 -            if(mCustomView != null) {
 -                this.hideCustomView();
 -                return true;
 -            } else {
 -                // The webview is currently displayed
 -                // If back key is bound, then send event to JavaScript
 -                if (isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK)) {
 -                    this.loadUrl("javascript:cordova.fireDocumentEvent('backbutton');");
 -                    return true;
 -                } else {
 -                    // If not bound
 -                    // Go to previous page in webview if it is possible to go back
 -                    if (this.backHistory()) {
 -                        return true;
 -                    }
 -                    // If not, then invoke default behavior
 -                }
 -            }
 -        }
 -        // Legacy
 -        else if (keyCode == KeyEvent.KEYCODE_MENU) {
 -            if (this.lastMenuEventTime < event.getEventTime()) {
 -                this.loadUrl("javascript:cordova.fireDocumentEvent('menubutton');");
 -            }
 -            this.lastMenuEventTime = event.getEventTime();
 -            return super.onKeyUp(keyCode, event);
 -        }
 -        // If search key
 -        else if (keyCode == KeyEvent.KEYCODE_SEARCH) {
 -            this.loadUrl("javascript:cordova.fireDocumentEvent('searchbutton');");
 -            return true;
 -        }
 -
 -        //Does webkit change this behavior?
 -        return super.onKeyUp(keyCode, event);
 -    }
 -
 -    public void setButtonPlumbedToJs(int keyCode, boolean value) {
 -        switch (keyCode) {
 -            case KeyEvent.KEYCODE_VOLUME_DOWN:
 -            case KeyEvent.KEYCODE_VOLUME_UP:
 -            case KeyEvent.KEYCODE_BACK:
 -                // TODO: Why are search and menu buttons handled separately?
 -                boundKeyCodes.add(keyCode);
 -                return;
 -            default:
 -                throw new IllegalArgumentException("Unsupported keycode: " + keyCode);
 -        }
 -    }
 -
 -    @Deprecated // Use setButtonPlumbedToJs() instead.
 -    public void bindButton(boolean override)
 -    {
 -        setButtonPlumbedToJs(KeyEvent.KEYCODE_BACK, override);
 -    }
 -
 -    @Deprecated // Use setButtonPlumbedToJs() instead.
 -    public void bindButton(String button, boolean override) {
 -        if (button.compareTo("volumeup")==0) {
 -            setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_UP, override);
 -        }
 -        else if (button.compareTo("volumedown")==0) {
 -            setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_DOWN, override);
 -        }
 -    }
 -
 -    @Deprecated // Use setButtonPlumbedToJs() instead.
 -    public void bindButton(int keyCode, boolean keyDown, boolean override) {
 -        setButtonPlumbedToJs(keyCode, override);
 -    }
 -
 -    @Deprecated // Use isButtonPlumbedToJs
 -    public boolean isBackButtonBound()
 -    {
 -        return isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);
 -    }
 -
 -    public boolean isButtonPlumbedToJs(int keyCode)
 -    {
 -        return boundKeyCodes.contains(keyCode);
 -    }
 -
 -    public void handlePause(boolean keepRunning)
 -    {
 -        LOG.d(TAG, "Handle the pause");
 -        // Send pause event to JavaScript
 -        this.loadUrl("javascript:try{cordova.fireDocumentEvent('pause');}catch(e){console.log('exception firing pause event from native');};");
 -
 -        // Forward to plugins
 -        if (this.pluginManager != null) {
 -            this.pluginManager.onPause(keepRunning);
 -        }
 -
 -        // If app doesn't want to run in background
 -        if (!keepRunning) {
 -            // Pause JavaScript timers (including setInterval)
 -            this.pauseTimers();
 -        }
 -        paused = true;
 -   
 -    }
 -    
 -    public void handleResume(boolean keepRunning, boolean activityResultKeepRunning)
 -    {
 -
 -        this.loadUrl("javascript:try{cordova.fireDocumentEvent('resume');}catch(e){console.log('exception firing resume event from native');};");
 -        
 -        // Forward to plugins
 -        if (this.pluginManager != null) {
 -            this.pluginManager.onResume(keepRunning);
 -        }
 -
 -        // Resume JavaScript timers (including setInterval)
 -        this.resumeTimers();
 -        paused = false;
 -    }
 -    
 -    public void handleDestroy()
 -    {
 -        // Send destroy event to JavaScript
 -        this.loadUrl("javascript:try{cordova.require('cordova/channel').onDestroy.fire();}catch(e){console.log('exception firing destroy event from native');};");
 -
 -        // Load blank page so that JavaScript onunload is called
 -        this.loadUrl("about:blank");
 -
 -        // Forward to plugins
 -        if (this.pluginManager != null) {
 -            this.pluginManager.onDestroy();
 -        }
 -        
 -        // unregister the receiver
 -        if (this.receiver != null) {
 -            try {
 -                this.cordova.getActivity().unregisterReceiver(this.receiver);
 -            } catch (Exception e) {
 -                Log.e(TAG, "Error unregistering configuration receiver: " + e.getMessage(), e);
 -            }
 -        }
 -    }
 -    
 -    public void onNewIntent(Intent intent)
 -    {
 -        //Forward to plugins
 -        if (this.pluginManager != null) {
 -            this.pluginManager.onNewIntent(intent);
 -        }
 -    }
 -    
 -    public boolean isPaused()
 -    {
 -        return paused;
 -    }
 -
 -    @Deprecated // This never did anything.
 -    public boolean hadKeyEvent() {
 -        return false;
 -    }
 -
 -    // Wrapping these functions in their own class prevents warnings in adb like:
 -    // VFY: unable to resolve virtual method 285: Landroid/webkit/WebSettings;.setAllowUniversalAccessFromFileURLs
 -    @TargetApi(16)
 -    private static class Level16Apis {
 -        static void enableUniversalAccess(WebSettings settings) {
 -            settings.setAllowUniversalAccessFromFileURLs(true);
 -        }
 -    }
 -    
 -    public void printBackForwardList() {
 -        WebBackForwardList currentList = this.copyBackForwardList();
 -        int currentSize = currentList.getSize();
 -        for(int i = 0; i < currentSize; ++i)
 -        {
 -            WebHistoryItem item = currentList.getItemAtIndex(i);
 -            String url = item.getUrl();
 -            LOG.d(TAG, "The URL at index: " + Integer.toString(i) + " is " + url );
 -        }
 -    }
 -    
 -    
 -    //Can Go Back is BROKEN!
 -    public boolean startOfHistory()
 -    {
 -        WebBackForwardList currentList = this.copyBackForwardList();
 -        WebHistoryItem item = currentList.getItemAtIndex(0);
 -        if( item!=null){	// Null-fence in case they haven't called loadUrl yet (CB-2458)
 -	        String url = item.getUrl();
 -	        String currentUrl = this.getUrl();
 -	        LOG.d(TAG, "The current URL is: " + currentUrl);
 -	        LOG.d(TAG, "The URL at item 0 is: " + url);
 -	        return currentUrl.equals(url);
 -        }
 -        return false;
 -    }
 -
 -    public void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {
 -        // This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0
 -        Log.d(TAG, "showing Custom View");
 -        // if a view already exists then immediately terminate the new one
 -        if (mCustomView != null) {
 -            callback.onCustomViewHidden();
 -            return;
 -        }
 -        
 -        // Store the view and its callback for later (to kill it properly)
 -        mCustomView = view;
 -        mCustomViewCallback = callback;
 -        
 -        // Add the custom view to its container.
 -        ViewGroup parent = (ViewGroup) this.getParent();
 -        parent.addView(view, COVER_SCREEN_GRAVITY_CENTER);
 -        
 -        // Hide the content view.
 -        this.setVisibility(View.GONE);
 -        
 -        // Finally show the custom view container.
 -        parent.setVisibility(View.VISIBLE);
 -        parent.bringToFront();
 -    }
 -
 -    public void hideCustomView() {
 -        // This code is adapted from the original Android Browser code, licensed under the Apache License, Version 2.0
 -        Log.d(TAG, "Hiding Custom View");
 -        if (mCustomView == null) return;
 -
 -        // Hide the custom view.
 -        mCustomView.setVisibility(View.GONE);
 -        
 -        // Remove the custom view from its container.
 -        ViewGroup parent = (ViewGroup) this.getParent();
 -        parent.removeView(mCustomView);
 -        mCustomView = null;
 -        mCustomViewCallback.onCustomViewHidden();
 -        
 -        // Show the content view.
 -        this.setVisibility(View.VISIBLE);
 -    }
 -    
 -    /**
 -     * if the video overlay is showing then we need to know 
 -     * as it effects back button handling
 -     * 
 -     * @return true if custom view is showing
 -     */
 -    public boolean isCustomViewShowing() {
 -        return mCustomView != null;
 -    }
 -    
 -    public WebBackForwardList restoreState(Bundle savedInstanceState)
 -    {
 -        WebBackForwardList myList = super.restoreState(savedInstanceState);
 -        Log.d(TAG, "WebView restoration crew now restoring!");
 -        //Initialize the plugin manager once more
 -        this.pluginManager.init();
 -        return myList;
 -    }
 -
 -    public void storeResult(int requestCode, int resultCode, Intent intent) {
 -        mResult = new ActivityResult(requestCode, resultCode, intent);
 -    }
 +    void showCustomView(View view, CustomViewCallback callback);
 +
 +    void hideCustomView();
 +
 +    Context getContext();
 +
 +    boolean onOverrideUrlLoading(String url);
 +
 +    void resetJsMessageQueue();
 +
 +    void onReset();
 +
 +    int getVisibility();
 +
 +    void incUrlTimeout();
 +
 +    void setOverScrollMode(int overScrollNever);
 +
 +    void setNetworkAvailable(boolean online);
 +
 +    CordovaResourceApi getResourceApi();
 +
-     void bindButton(boolean override);
-     void bindButton(String button, boolean override);
- 
-     boolean isBackButtonBound();
++    void setButtonPlumbedToJs(int keyCode, boolean override);
++    boolean isButtonPlumbedToJs(int keyCode);
 +
 +    void sendPluginResult(PluginResult cr, String callbackId);
 +
 +    PluginManager getPluginManager();
 +
 +    void setLayoutParams(android.widget.FrameLayout.LayoutParams layoutParams);
      
 -    public CordovaResourceApi getResourceApi() {
 -        return resourceApi;
 -    }
 +    // Required for test
-     
 +    String getUrl();
 +    boolean isPaused();
  }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4ce5123a/framework/src/org/apache/cordova/CoreAndroid.java
----------------------------------------------------------------------
diff --cc framework/src/org/apache/cordova/CoreAndroid.java
index b47efa8,0000000..56c7e64
mode 100755,000000..100755
--- a/framework/src/org/apache/cordova/CoreAndroid.java
+++ b/framework/src/org/apache/cordova/CoreAndroid.java
@@@ -1,299 -1,0 +1,305 @@@
 +/*
 +       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.
 +*/
 +
 +package org.apache.cordova;
 +
 +import org.apache.cordova.CallbackContext;
 +import org.apache.cordova.CordovaPlugin;
 +import org.apache.cordova.LOG;
 +import org.apache.cordova.PluginResult;
 +import org.json.JSONArray;
 +import org.json.JSONException;
 +import org.json.JSONObject;
 +
 +import android.content.BroadcastReceiver;
 +import android.content.Context;
 +import android.content.Intent;
 +import android.content.IntentFilter;
 +import android.telephony.TelephonyManager;
++import android.view.KeyEvent;
 +
 +import java.util.HashMap;
 +
 +/**
 + * This class exposes methods in Cordova that can be called from JavaScript.
 + */
 +public class CoreAndroid extends CordovaPlugin {
 +
 +    protected static final String TAG = "CordovaApp";
 +    private BroadcastReceiver telephonyReceiver;
 +
 +    /**
 +     * Sets the context of the Command. This can then be used to do things like
 +     * get file paths associated with the Activity.
 +     *
 +     * @param cordova The context of the main Activity.
 +     * @param webView The CordovaWebView Cordova is running in.
 +     */
 +    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
 +        super.initialize(cordova, webView);
 +        this.initTelephonyReceiver();
 +    }
 +
 +
 +    /**
 +     * Executes the request and returns PluginResult.
 +     *
 +     * @param action            The action to execute.
 +     * @param args              JSONArry of arguments for the plugin.
 +     * @param callbackContext   The callback context from which we were invoked.
 +     * @return                  A PluginResult object with a status and message.
 +     */
 +    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
 +        PluginResult.Status status = PluginResult.Status.OK;
 +        String result = "";
 +
 +        try {
 +            if (action.equals("clearCache")) {
 +                this.clearCache();
 +            }
 +            else if (action.equals("show")) {
 +                // This gets called from JavaScript onCordovaReady to show the webview.
 +                // I recommend we change the name of the Message as spinner/stop is not
 +                // indicative of what this actually does (shows the webview).
 +                cordova.getActivity().runOnUiThread(new Runnable() {
 +                    public void run() {
 +                        webView.postMessage("spinner", "stop");
 +                    }
 +                });
 +            }
 +            else if (action.equals("loadUrl")) {
 +                this.loadUrl(args.getString(0), args.optJSONObject(1));
 +            }
 +            else if (action.equals("cancelLoadUrl")) {
 +                //this.cancelLoadUrl();
 +            }
 +            else if (action.equals("clearHistory")) {
 +                this.clearHistory();
 +            }
 +            else if (action.equals("backHistory")) {
 +                this.backHistory();
 +            }
 +            else if (action.equals("overrideButton")) {
 +                this.overrideButton(args.getString(0), args.getBoolean(1));
 +            }
 +            else if (action.equals("overrideBackbutton")) {
 +                this.overrideBackbutton(args.getBoolean(0));
 +            }
 +            else if (action.equals("exitApp")) {
 +                this.exitApp();
 +            }
 +            callbackContext.sendPluginResult(new PluginResult(status, result));
 +            return true;
 +        } catch (JSONException e) {
 +            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
 +            return false;
 +        }
 +    }
 +
 +    //--------------------------------------------------------------------------
 +    // LOCAL METHODS
 +    //--------------------------------------------------------------------------
 +
 +    /**
 +     * Clear the resource cache.
 +     */
 +    public void clearCache() {
 +        cordova.getActivity().runOnUiThread(new Runnable() {
 +            public void run() {
 +                webView.clearCache(true);
 +            }
 +        });
 +    }
 +
 +    /**
 +     * Load the url into the webview.
 +     *
 +     * @param url
 +     * @param props			Properties that can be passed in to the Cordova activity (i.e. loadingDialog, wait, ...)
 +     * @throws JSONException
 +     */
 +    public void loadUrl(String url, JSONObject props) throws JSONException {
 +        LOG.d("App", "App.loadUrl("+url+","+props+")");
 +        int wait = 0;
 +        boolean openExternal = false;
 +        boolean clearHistory = false;
 +
 +        // If there are properties, then set them on the Activity
 +        HashMap<String, Object> params = new HashMap<String, Object>();
 +        if (props != null) {
 +            JSONArray keys = props.names();
 +            for (int i = 0; i < keys.length(); i++) {
 +                String key = keys.getString(i);
 +                if (key.equals("wait")) {
 +                    wait = props.getInt(key);
 +                }
 +                else if (key.equalsIgnoreCase("openexternal")) {
 +                    openExternal = props.getBoolean(key);
 +                }
 +                else if (key.equalsIgnoreCase("clearhistory")) {
 +                    clearHistory = props.getBoolean(key);
 +                }
 +                else {
 +                    Object value = props.get(key);
 +                    if (value == null) {
 +
 +                    }
 +                    else if (value.getClass().equals(String.class)) {
 +                        params.put(key, (String)value);
 +                    }
 +                    else if (value.getClass().equals(Boolean.class)) {
 +                        params.put(key, (Boolean)value);
 +                    }
 +                    else if (value.getClass().equals(Integer.class)) {
 +                        params.put(key, (Integer)value);
 +                    }
 +                }
 +            }
 +        }
 +
 +        // If wait property, then delay loading
 +
 +        if (wait > 0) {
 +            try {
 +                synchronized(this) {
 +                    this.wait(wait);
 +                }
 +            } catch (InterruptedException e) {
 +                e.printStackTrace();
 +            }
 +        }
 +        this.webView.showWebPage(url, openExternal, clearHistory, params);
 +    }
 +
 +    /**
 +     * Clear page history for the app.
 +     */
 +    public void clearHistory() {
 +        cordova.getActivity().runOnUiThread(new Runnable() {
 +            public void run() {
 +                webView.clearHistory();
 +            }
 +        });
 +    }
 +
 +    /**
 +     * Go to previous page displayed.
 +     * This is the same as pressing the backbutton on Android device.
 +     */
 +    public void backHistory() {
 +        cordova.getActivity().runOnUiThread(new Runnable() {
 +            public void run() {
 +                webView.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.
 +     *
 +     * @param override		T=override, F=cancel override
 +     */
 +    public void overrideBackbutton(boolean override) {
 +        LOG.i("App", "WARNING: Back Button Default Behavior will be overridden.  The backbutton event will be fired!");
-         webView.bindButton(override);
++        webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_BACK, override);
 +    }
 +
 +    /**
 +     * Override the default behavior of the Android volume buttons.
 +     * If overridden, when the volume button is pressed, the "volume[up|down]button" JavaScript event will be fired.
 +     *
 +     * @param button        volumeup, volumedown
 +     * @param override      T=override, F=cancel override
 +     */
 +    public void overrideButton(String button, boolean override) {
 +        LOG.i("App", "WARNING: Volume Button Default Behavior will be overridden.  The volume event will be fired!");
-         webView.bindButton(button, override);
++        if (button.equals("volumeup")) {
++            webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_UP, override);
++        }
++        else if (button.equals("volumedown")) {
++            webView.setButtonPlumbedToJs(KeyEvent.KEYCODE_VOLUME_DOWN, override);
++        }
 +    }
 +
 +    /**
 +     * Return whether the Android back button is overridden by the user.
 +     *
 +     * @return boolean
 +     */
 +    public boolean isBackbuttonOverridden() {
-         return webView.isBackButtonBound();
++        return webView.isButtonPlumbedToJs(KeyEvent.KEYCODE_BACK);
 +    }
 +
 +    /**
 +     * Exit the Android application.
 +     */
 +    public void exitApp() {
 +        this.webView.postMessage("exit", null);
 +    }
 +    
 +
 +    /**
 +     * Listen for telephony events: RINGING, OFFHOOK and IDLE
 +     * Send these events to all plugins using
 +     *      CordovaActivity.onMessage("telephone", "ringing" | "offhook" | "idle")
 +     */
 +    private void initTelephonyReceiver() {
 +        IntentFilter intentFilter = new IntentFilter();
 +        intentFilter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
 +        //final CordovaInterface mycordova = this.cordova;
 +        this.telephonyReceiver = new BroadcastReceiver() {
 +
 +            @Override
 +            public void onReceive(Context context, Intent intent) {
 +
 +                // If state has changed
 +                if ((intent != null) && intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
 +                    if (intent.hasExtra(TelephonyManager.EXTRA_STATE)) {
 +                        String extraData = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
 +                        if (extraData.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
 +                            LOG.i(TAG, "Telephone RINGING");
 +                            webView.postMessage("telephone", "ringing");
 +                        }
 +                        else if (extraData.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
 +                            LOG.i(TAG, "Telephone OFFHOOK");
 +                            webView.postMessage("telephone", "offhook");
 +                        }
 +                        else if (extraData.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
 +                            LOG.i(TAG, "Telephone IDLE");
 +                            webView.postMessage("telephone", "idle");
 +                        }
 +                    }
 +                }
 +            }
 +        };
 +
 +        // Register the receiver
 +        this.cordova.getActivity().registerReceiver(this.telephonyReceiver, intentFilter);
 +    }
 +
 +    /*
 +     * Unregister the receiver
 +     *
 +     */
 +    public void onDestroy()
 +    {
 +        this.cordova.getActivity().unregisterReceiver(this.telephonyReceiver);
 +    }
 +}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4ce5123a/framework/src/org/apache/cordova/PluginManager.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4ce5123a/package.json
----------------------------------------------------------------------
diff --cc package.json
index f38c187,ed01458..4dbd5ce
--- a/package.json
+++ b/package.json
@@@ -16,7 -19,10 +19,11 @@@
    "license": "Apache version 2.0",
    "dependencies": {
      "q": "^0.9.0",
 -    "shelljs": "^0.2.6"
 +    "shelljs": "^0.2.6",
 +    "which": "^1.0.5"
+   },
+   "devDependencies": {
+     "jasmine-node": "~1",
+     "promise-matchers": "~0"
    }
  }


[9/9] android commit: Remove fields from CordovaWebView interface

Posted by ag...@apache.org.
Remove fields from CordovaWebView interface

Fields don't make sense in an interface.


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

Branch: refs/heads/4.0.x
Commit: 428e1bc14d87b4b9f8bd5c9bfb358a2a15310167
Parents: d66bb84
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Jun 24 15:28:53 2014 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Jun 24 15:28:53 2014 -0400

----------------------------------------------------------------------
 framework/src/org/apache/cordova/AndroidWebView.java | 3 +--
 framework/src/org/apache/cordova/CordovaWebView.java | 6 ------
 2 files changed, 1 insertion(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/428e1bc1/framework/src/org/apache/cordova/AndroidWebView.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/AndroidWebView.java b/framework/src/org/apache/cordova/AndroidWebView.java
index 4074d21..5fd6495 100755
--- a/framework/src/org/apache/cordova/AndroidWebView.java
+++ b/framework/src/org/apache/cordova/AndroidWebView.java
@@ -69,8 +69,7 @@ import android.widget.FrameLayout;
  */
 public class AndroidWebView extends WebView implements CordovaWebView {
 
-    public static final String TAG = "CordovaWebView";
-    public static final String CORDOVA_VERSION = "4.0.0-dev";
+    public static final String TAG = "AndroidWebView";
 
     private HashSet<Integer> boundKeyCodes = new HashSet<Integer>();
 

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/428e1bc1/framework/src/org/apache/cordova/CordovaWebView.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaWebView.java b/framework/src/org/apache/cordova/CordovaWebView.java
index 5329ce2..6534a5d 100644
--- a/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/framework/src/org/apache/cordova/CordovaWebView.java
@@ -12,12 +12,6 @@ import android.webkit.WebChromeClient.CustomViewCallback;
 import android.widget.LinearLayout.LayoutParams;
 
 public interface CordovaWebView {
-
-    String OVER_SCROLL_NEVER = null;
-    Object pluginManager = null;
-    Object jsMessageQueue = null;
-
-    public static final String TAG = "CordovaWebView";
     public static final String CORDOVA_VERSION = "4.0.0-dev";
 
     View getView();


[4/9] android commit: CB-7017 Fix onload=true being set on all subsequent plugins

Posted by ag...@apache.org.
CB-7017 Fix onload=true being set on all subsequent plugins


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

Branch: refs/heads/4.0.x
Commit: 58afd0b6040b086cfe32e96e1438b4c2f9d23743
Parents: 4352456
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Jun 24 14:55:34 2014 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Jun 24 14:55:34 2014 -0400

----------------------------------------------------------------------
 framework/src/org/apache/cordova/PluginManager.java | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/58afd0b6/framework/src/org/apache/cordova/PluginManager.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/PluginManager.java b/framework/src/org/apache/cordova/PluginManager.java
index f095722..1ed0523 100755
--- a/framework/src/org/apache/cordova/PluginManager.java
+++ b/framework/src/org/apache/cordova/PluginManager.java
@@ -165,6 +165,7 @@ public class PluginManager {
                     service = "";
                     pluginClass = "";
                     insideFeature = false;
+                    onload = false;
                 }
             }
             try {