You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by st...@apache.org on 2013/05/17 02:54:53 UTC

[01/22] android commit: CB-3357: Fixing resource grabbing

Updated Branches:
  refs/heads/3.0.0 78a5dcfd4 -> adcbd879c (forced update)


CB-3357: Fixing resource grabbing


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

Branch: refs/heads/3.0.0
Commit: 20caac1b6eafcd2ef3f27d26d42662b8ebd307a7
Parents: 48b8c69
Author: Joe Bowser <bo...@apache.org>
Authored: Tue May 7 13:30:19 2013 -0700
Committer: Joe Bowser <bo...@apache.org>
Committed: Tue May 7 13:30:30 2013 -0700

----------------------------------------------------------------------
 framework/src/org/apache/cordova/Config.java |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/20caac1b/framework/src/org/apache/cordova/Config.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/Config.java b/framework/src/org/apache/cordova/Config.java
index b9f81f0..ccf49c5 100644
--- a/framework/src/org/apache/cordova/Config.java
+++ b/framework/src/org/apache/cordova/Config.java
@@ -119,7 +119,7 @@ public class Config {
                     } else if (name.equals("splashscreen")) {
                         String value = xml.getAttributeValue(null, "value");
                         int resource = 0;
-                        if (value != null)
+                        if (value == null)
                         {
                             value = "splash";
                         }


[09/22] android commit: [CB-3307] Fixing bin/create script due to cordova-$VERSION.js -> cordova.js change.

Posted by st...@apache.org.
[CB-3307] Fixing bin/create script due to cordova-$VERSION.js -> cordova.js change.


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

Branch: refs/heads/3.0.0
Commit: 8bfd45c095c49ff6e5674892b07f3f1e83ff7312
Parents: a001d8c
Author: Michal Mocny <mm...@gmail.com>
Authored: Mon May 13 10:19:29 2013 -0400
Committer: Michal Mocny <mm...@gmail.com>
Committed: Mon May 13 10:30:02 2013 -0400

----------------------------------------------------------------------
 bin/create |   19 ++-----------------
 1 files changed, 2 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8bfd45c0/bin/create
----------------------------------------------------------------------
diff --git a/bin/create b/bin/create
index b7e96b4..39aff6b 100755
--- a/bin/create
+++ b/bin/create
@@ -47,20 +47,6 @@ then
     exit 1
 fi
 
-# cleanup after exit and/or on error
-function on_exit {
-    # [ -f "$BUILD_PATH"/framework/libs/commons-codec-1.6.jar ] && rm "$BUILD_PATH"/framework/libs/commons-codec-1.6.jar
-    # [ -d "$BUILD_PATH"/framework/libs ] && rmdir "$BUILD_PATH"/framework/libs
-    if [ -f "$BUILD_PATH"/framework/assets/www/cordova-$VERSION.js ]
-    then
-        rm "$BUILD_PATH"/framework/assets/www/cordova-$VERSION.js
-    fi
-    if [ -f "$BUILD_PATH"/framework/cordova-$VERSION.jar ]
-    then
-        rm "$BUILD_PATH"/framework/cordova-$VERSION.jar
-    fi
-}
-
 function createAppInfoJar {
     pushd "$BUILD_PATH"/bin/templates/cordova/ApplicationInfo > /dev/null
     javac ApplicationInfo.java
@@ -91,7 +77,6 @@ function replace {
 # we do not want the script to silently fail
 trap 'previous_command=$this_command; this_command=$BASH_COMMAND' DEBUG
 trap on_error ERR
-trap on_exit EXIT
 
 ANDROID_BIN="${ANDROID_BIN:=$( which android )}"
 PACKAGE_AS_PATH=$(echo $PACKAGE | sed 's/\./\//g')
@@ -141,11 +126,11 @@ cp -r "$BUILD_PATH"/bin/templates/project/res "$PROJECT_PATH"
 if [ -d "$BUILD_PATH"/framework ]
 then
     cp -r "$BUILD_PATH"/framework/res/xml "$PROJECT_PATH"/res
-    cp "$BUILD_PATH"/framework/assets/www/cordova-$VERSION.js "$PROJECT_PATH"/assets/www/cordova-$VERSION.js
+    cp "$BUILD_PATH"/framework/assets/www/cordova.js "$PROJECT_PATH"/assets/www/cordova.js
     cp "$BUILD_PATH"/framework/cordova-$VERSION.jar "$PROJECT_PATH"/libs/cordova-$VERSION.jar
 else
     cp -r "$BUILD_PATH"/xml "$PROJECT_PATH"/res/xml
-    cp "$BUILD_PATH"/cordova-$VERSION.js "$PROJECT_PATH"/assets/www/cordova-$VERSION.js
+    cp "$BUILD_PATH"/cordova.js "$PROJECT_PATH"/assets/www/cordova.js
     cp "$BUILD_PATH"/cordova-$VERSION.jar "$PROJECT_PATH"/libs/cordova-$VERSION.jar
 fi
 


[06/22] android commit: DataRequest code cleaned up.

Posted by st...@apache.org.
DataRequest code cleaned up.


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

Branch: refs/heads/3.0.0
Commit: a001d8cfb71930bf21ccc0b85715385ef409d8e0
Parents: 867358e
Author: Shravan Narayan <sh...@google.com>
Authored: Tue May 7 11:02:38 2013 -0400
Committer: Braden Shepherdson <br...@gmail.com>
Committed: Wed May 8 17:38:58 2013 -0400

----------------------------------------------------------------------
 .../src/org/apache/cordova/CameraLauncher.java     |   12 ++--
 framework/src/org/apache/cordova/FileHelper.java   |   20 +++-----
 framework/src/org/apache/cordova/FileUtils.java    |    2 +-
 .../cordova/IceCreamCordovaWebViewClient.java      |    9 +--
 .../src/org/apache/cordova/api/CordovaPlugin.java  |    4 +-
 .../src/org/apache/cordova/api/DataResource.java   |   37 ++++++++-------
 .../apache/cordova/api/DataResourceContext.java    |    9 +---
 .../src/org/apache/cordova/api/PluginManager.java  |    9 ++-
 8 files changed, 46 insertions(+), 56 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/a001d8cf/framework/src/org/apache/cordova/CameraLauncher.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CameraLauncher.java b/framework/src/org/apache/cordova/CameraLauncher.java
index 7597a81..1974dd7 100755
--- a/framework/src/org/apache/cordova/CameraLauncher.java
+++ b/framework/src/org/apache/cordova/CameraLauncher.java
@@ -342,7 +342,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
 
                             // Add compressed version of captured image to returned media store Uri
                             DataResource dataResource = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.CameraExitIntent");
-                            OutputStream os = dataResource.getOs();
+                            OutputStream os = dataResource.getOutputStream();
                             bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
                             os.close();
 
@@ -540,9 +540,9 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
     private void writeUncompressedImage(Uri uri) throws FileNotFoundException,
             IOException {
         DataResource inputDataResource = DataResource.initiateNewDataRequestForUri(imageUri, webView.pluginManager, cordova, "CameraLauncher.writeUncompressedImage");
-        InputStream fis = inputDataResource.getIs();
+        InputStream fis = inputDataResource.getInputStream();
         DataResource outDataResource = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.writeUncompressedImage");
-        OutputStream os = outDataResource.getOs();
+        OutputStream os = outDataResource.getOutputStream();
         if(fis == null) {
             throw new FileNotFoundException("Could not get the input file");
         } else if(os == null) {
@@ -592,13 +592,13 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
         // If no new width or height were specified return the original bitmap
         DataResource dataResource = DataResource.initiateNewDataRequestForUri(imageUrl, webView.pluginManager, cordova, "CameraLauncher.getScaledBitmap");
         if (this.targetWidth <= 0 && this.targetHeight <= 0) {
-            return BitmapFactory.decodeStream(dataResource.getIs());
+            return BitmapFactory.decodeStream(dataResource.getInputStream());
         }
 
         // figure out the original width and height of the image
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inJustDecodeBounds = true;
-        BitmapFactory.decodeStream(dataResource.getIs(), null, options);
+        BitmapFactory.decodeStream(dataResource.getInputStream(), null, options);
         
         //CB-2292: WTF? Why is the width null?
         if(options.outWidth == 0 || options.outHeight == 0)
@@ -612,7 +612,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
         // Load in the smallest bitmap possible that is closest to the size we want
         options.inJustDecodeBounds = false;
         options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, this.targetWidth, this.targetHeight);
-        Bitmap unscaledBitmap = BitmapFactory.decodeStream(dataResource.getIs(), null, options);
+        Bitmap unscaledBitmap = BitmapFactory.decodeStream(dataResource.getInputStream(), null, options);
         if (unscaledBitmap == null) {
             return null;
         }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/a001d8cf/framework/src/org/apache/cordova/FileHelper.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileHelper.java b/framework/src/org/apache/cordova/FileHelper.java
index 81f32f0..400352c 100644
--- a/framework/src/org/apache/cordova/FileHelper.java
+++ b/framework/src/org/apache/cordova/FileHelper.java
@@ -122,33 +122,27 @@ public class FileHelper {
      */
     public static boolean isUriWritable(String uriString) {
         String scheme = uriString.split(":")[0];
-        String writableSchemes[] = new String[]{ "content" };
 
         if(scheme.equals("file")){
             // special case file
-            if(uriString.startsWith("file:///android_asset/")){
-                return false;
-            } else {
-                return true;
-            }
+            return !uriString.startsWith("file:///android_asset/");
         }
-        for(int i = writableSchemes.length - 1; i >= 0 ; i--){
-            if(writableSchemes[i].equals(scheme)){
-                return true;
-            }
-        }
-        return false;
+        return "content".equals(scheme);
     }
 
     /**
      * Ensures the "file://" prefix exists for the given string
-     * If the given URI string has a "file://" prefix, it is returned unchanged
+     * If the given URI string already has a scheme, it is returned unchanged
      *
      * @param path - the path string to operate on
      * @return a String with the "file://" scheme set
      */
     public static String insertFileProtocol(String path) {
         if(!path.matches("^[a-z0-9+.-]+:.*")){
+            //Ensure it is not a relative path
+            if(!path.startsWith("/")){
+                throw new IllegalArgumentException("Relative paths" + path + "are not allowed.");
+            }
             path = "file://" + path;
         }
         return path;

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/a001d8cf/framework/src/org/apache/cordova/FileUtils.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileUtils.java b/framework/src/org/apache/cordova/FileUtils.java
index cf0e5a4..e62fc4a 100755
--- a/framework/src/org/apache/cordova/FileUtils.java
+++ b/framework/src/org/apache/cordova/FileUtils.java
@@ -897,7 +897,7 @@ public class FileUtils extends CordovaPlugin {
             public void run() {
                 try {
                     DataResource dataResource = DataResource.initiateNewDataRequestForUri(filename, webView.pluginManager, cordova, "FileUtils.readFileAs");
-                    byte[] bytes = readAsBinaryHelper(dataResource.getIs(), start, end);
+                    byte[] bytes = readAsBinaryHelper(dataResource.getInputStream(), start, end);
                     
                     PluginResult result;
                     switch (resultType) {

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/a001d8cf/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
index 3a17dc1..d9c1cd2 100644
--- a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
+++ b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
@@ -46,19 +46,16 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
     public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
         // We need to support the new DataResource intercepts without breaking the shouldInterceptRequest mechanism.
         DataResource dataResource = DataResource.initiateNewDataRequestForUri(url, this.appView.pluginManager, cordova,
-                new DataResourceContext("WebViewClient.shouldInterceptRequest", true /* this is from a browser request*/));
+                "WebViewClient.shouldInterceptRequest");
         url = dataResource.getUri().toString();
 
         // This mechanism is no longer needed due to the dataResource mechanism. It would be awesome to just get rid of it.
         //Check if plugins intercept the request
         WebResourceResponse ret = super.shouldInterceptRequest(view, url);
-//      The below bugfix is taken care of by the dataResource mechanism
-//        if(ret == null && (url.contains("?") || url.contains("#") || needsIceCreamSpaceInAssetUrlFix(url))){
-//            ret = generateWebResourceResponse(url);
-//        }
+
         if(ret == null) {
             try {
-                ret = new WebResourceResponse(dataResource.getMimeType(), "UTF-8", dataResource.getIs());
+                ret = new WebResourceResponse(dataResource.getMimeType(), "UTF-8", dataResource.getInputStream());
             } catch(IOException e) {
                 LOG.e("IceCreamCordovaWebViewClient", "Error occurred while loading a file.", e);
             }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/a001d8cf/framework/src/org/apache/cordova/api/CordovaPlugin.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/CordovaPlugin.java b/framework/src/org/apache/cordova/api/CordovaPlugin.java
index 69f8fde..866677c 100644
--- a/framework/src/org/apache/cordova/api/CordovaPlugin.java
+++ b/framework/src/org/apache/cordova/api/CordovaPlugin.java
@@ -182,10 +182,10 @@ public class CordovaPlugin {
      *
      * @param dataResource          The resource to be loaded.
      * @param dataResourceContext   Context associated with the resource load
-     * @return                      Return a new DataResource if the plugin wants o assist in loading the request or null if it doesn't.
+     * @return                      Return a new DataResource if the plugin wants to assist in loading the request or null if it doesn't.
      */
     @TargetApi(Build.VERSION_CODES.HONEYCOMB)
-    public DataResource shouldInterceptDataResourceRequest(DataResource dataResource, DataResourceContext dataResourceContext) {
+    public DataResource handleDataResourceRequest(DataResource dataResource, DataResourceContext dataResourceContext) {
         return null;
     }
 

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/a001d8cf/framework/src/org/apache/cordova/api/DataResource.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/DataResource.java b/framework/src/org/apache/cordova/api/DataResource.java
index 8422b07..3e6ead8 100644
--- a/framework/src/org/apache/cordova/api/DataResource.java
+++ b/framework/src/org/apache/cordova/api/DataResource.java
@@ -24,10 +24,13 @@ public class DataResource {
     private String mimeType;
     private Boolean writable;
     private File realFile;
-    private boolean retryLoad = true;
+    private boolean retryIsLoad = true;
+    private boolean retryOsLoad = true;
+    private boolean retryMimeTypeLoad = true;
+    private boolean retryWritableLoad = true;
+    private boolean retryRealFileLoad = true;
 
     public DataResource(CordovaInterface cordova, Uri uri) {
-        super();
         this.cordova = cordova;
         this.uri = uri;
     }
@@ -43,61 +46,61 @@ public class DataResource {
         // Uri is always provided
         return uri;
     }
-    public InputStream getIs() throws IOException {
-        if(is == null && retryLoad) {
+    public InputStream getInputStream() throws IOException {
+        if(is == null && retryIsLoad) {
             try {
                 is = FileHelper.getInputStreamFromUriString(uri.toString(), cordova);
             } finally {
                 // We failed loading once, don't try loading anymore
                 if(is == null) {
-                    retryLoad = false;
+                    retryIsLoad = false;
                 }
             }
         }
         return is;
     }
-    public OutputStream getOs() throws FileNotFoundException {
-        if(os == null && retryLoad) {
+    public OutputStream getOutputStream() throws FileNotFoundException {
+        if(os == null && retryOsLoad) {
             try {
                 os = FileHelper.getOutputStreamFromUriString(uri.toString(), cordova);
             } finally {
                 // We failed loading once, don't try loading anymore
                 if(os == null) {
-                    retryLoad = false;
+                    retryOsLoad = false;
                 }
             }
         }
         return os;
     }
     public String getMimeType() {
-        if(mimeType == null && retryLoad) {
+        if(mimeType == null && retryMimeTypeLoad) {
             try {
                 mimeType = FileHelper.getMimeType(uri.toString(), cordova);
             } finally {
                 // We failed loading once, don't try loading anymore
                 if(mimeType == null) {
-                    retryLoad = false;
+                    retryMimeTypeLoad = false;
                 }
             }
         }
         return mimeType;
     }
     public boolean isWritable() {
-        if(writable == null && retryLoad) {
+        if(writable == null && retryWritableLoad) {
             try {
                 writable = FileHelper.isUriWritable(uri.toString());
             } finally {
                 // We failed loading once, don't try loading anymore
                 if(writable == null) {
-                    retryLoad = false;
+                    retryWritableLoad = false;
                 }
             }
         }
         // default to false
-        return writable != null? writable.booleanValue() : false;
+        return writable != null && writable.booleanValue();
     }
     public File getRealFile() {
-        if(realFile == null && retryLoad) {
+        if(realFile == null && retryRealFileLoad) {
             try {
                 String realPath = FileHelper.getRealPath(uri, cordova);
                 if(realPath != null) {
@@ -106,7 +109,7 @@ public class DataResource {
             } finally {
                 // We failed loading once, don't try loading anymore
                 if(realFile == null) {
-                    retryLoad = false;
+                    retryRealFileLoad = false;
                 }
             }
         }
@@ -120,7 +123,7 @@ public class DataResource {
         return initiateNewDataRequestForUri(Uri.parse(uriString), pluginManager, cordova, requestSourceTag);
     }
     public static DataResource initiateNewDataRequestForUri(Uri uri, PluginManager pluginManager, CordovaInterface cordova, String requestSourceTag){
-        return initiateNewDataRequestForUri(uri, pluginManager, cordova, new DataResourceContext(requestSourceTag, false /* Assume, not a browser request by default */ ));
+        return initiateNewDataRequestForUri(uri, pluginManager, cordova, new DataResourceContext(requestSourceTag));
     }
     public static DataResource initiateNewDataRequestForUri(String uriString, PluginManager pluginManager, CordovaInterface cordova, DataResourceContext dataResourceContext){
      // if no protocol is specified, assume its file:
@@ -131,7 +134,7 @@ public class DataResource {
         DataResource dataResource = new DataResource(cordova, uri);
         if (pluginManager != null) {
             // get the resource as returned by plugins
-            dataResource = pluginManager.shouldInterceptDataResourceRequest(dataResource, dataResourceContext);
+            dataResource = pluginManager.handleDataResourceRequestWithPlugins(dataResource, dataResourceContext);
         }
         return dataResource;
     }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/a001d8cf/framework/src/org/apache/cordova/api/DataResourceContext.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/DataResourceContext.java b/framework/src/org/apache/cordova/api/DataResourceContext.java
index 3c66817..310586b 100644
--- a/framework/src/org/apache/cordova/api/DataResourceContext.java
+++ b/framework/src/org/apache/cordova/api/DataResourceContext.java
@@ -12,15 +12,11 @@ public class DataResourceContext {
     // A tag associated with the source of this dataResourceContext
     private String source;
     // If needed, any data associated with core plugins can be a part of the context object
-    // This field indicates whether the request came from a browser network request
-    private boolean isFromBrowser;
     // If needed, any data associated with non core plugins  should store data in a Map so as to not clutter the context object
     private Map<String, Object> dataMap;
-    public DataResourceContext(String source, boolean isFromBrowser) {
-        super();
+    public DataResourceContext(String source) {
         this.requestId = new Random().nextInt();
         this.source = source;
-        this.isFromBrowser = isFromBrowser;
         this.dataMap = new HashMap<String, Object>();
     }
     public int getRequestId() {
@@ -29,9 +25,6 @@ public class DataResourceContext {
     public String getSource() {
         return source;
     }
-    public boolean isFromBrowser() {
-        return isFromBrowser;
-    }
     public Map<String, Object> getDataMap() {
         return dataMap;
     }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/a001d8cf/framework/src/org/apache/cordova/api/PluginManager.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/PluginManager.java b/framework/src/org/apache/cordova/api/PluginManager.java
index 6bad5ed..9eb1308 100755
--- a/framework/src/org/apache/cordova/api/PluginManager.java
+++ b/framework/src/org/apache/cordova/api/PluginManager.java
@@ -54,6 +54,7 @@ public class PluginManager {
     // Map URL schemes like foo: to plugins that want to handle those schemes
     // This would allow how all URLs are handled to be offloaded to a plugin
     protected HashMap<String, String> urlMap = new HashMap<String, String>();
+    private int MAX_REPITIONS = 1000;
 
     /**
      * Constructor.
@@ -409,13 +410,15 @@ public class PluginManager {
      * @param dataResourceContext   The context of the dataResource request
      * @return                      Return the resource request that will be loaded. The returned request may be modified or unchanged.
      */
-    public DataResource shouldInterceptDataResourceRequest(DataResource dataResource, DataResourceContext dataResourceContext){
+    public DataResource handleDataResourceRequestWithPlugins(DataResource dataResource, DataResourceContext dataResourceContext){
+        int repetitions = 0;
         boolean requestModified = true;
-        while(requestModified) {
+        while(requestModified && repetitions < MAX_REPITIONS) {
             requestModified = false;
+            repetitions ++;
             for (PluginEntry entry : this.entries.values()) {
                 if (entry.plugin != null) {
-                    DataResource ret = entry.plugin.shouldInterceptDataResourceRequest(dataResource, dataResourceContext);
+                    DataResource ret = entry.plugin.handleDataResourceRequest(dataResource, dataResourceContext);
                     if(ret != null) {
                         dataResource = ret;
                         requestModified = true;


[03/22] [CB-3307] Rename cordova-VERSION.js -> cordova.js

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8a95ed8e/framework/assets/www/cordova.js
----------------------------------------------------------------------
diff --git a/framework/assets/www/cordova.js b/framework/assets/www/cordova.js
new file mode 100644
index 0000000..2941307
--- /dev/null
+++ b/framework/assets/www/cordova.js
@@ -0,0 +1,6836 @@
+// Platform: android
+
+// commit d0ffb852378ff018bac2f3b12c38098a19b8ce00
+
+// File generated at :: Thu Apr 18 2013 15:10:54 GMT-0400 (EDT)
+
+/*
+ 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.
+*/
+
+;(function() {
+
+// file: lib/scripts/require.js
+
+var require,
+    define;
+
+(function () {
+    var modules = {};
+    // Stack of moduleIds currently being built.
+    var requireStack = [];
+    // Map of module ID -> index into requireStack of modules currently being built.
+    var inProgressModules = {};
+
+    function build(module) {
+        var factory = module.factory;
+        module.exports = {};
+        delete module.factory;
+        factory(require, module.exports, module);
+        return module.exports;
+    }
+
+    require = function (id) {
+        if (!modules[id]) {
+            throw "module " + id + " not found";
+        } else if (id in inProgressModules) {
+            var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
+            throw "Cycle in require graph: " + cycle;
+        }
+        if (modules[id].factory) {
+            try {
+                inProgressModules[id] = requireStack.length;
+                requireStack.push(id);
+                return build(modules[id]);
+            } finally {
+                delete inProgressModules[id];
+                requireStack.pop();
+            }
+        }
+        return modules[id].exports;
+    };
+
+    define = function (id, factory) {
+        if (modules[id]) {
+            throw "module " + id + " already defined";
+        }
+
+        modules[id] = {
+            id: id,
+            factory: factory
+        };
+    };
+
+    define.remove = function (id) {
+        delete modules[id];
+    };
+
+    define.moduleMap = modules;
+})();
+
+//Export for use in node
+if (typeof module === "object" && typeof require === "function") {
+    module.exports.require = require;
+    module.exports.define = define;
+}
+
+// file: lib/cordova.js
+define("cordova", function(require, exports, module) {
+
+
+var channel = require('cordova/channel');
+
+/**
+ * Listen for DOMContentLoaded and notify our channel subscribers.
+ */
+document.addEventListener('DOMContentLoaded', function() {
+    channel.onDOMContentLoaded.fire();
+}, false);
+if (document.readyState == 'complete' || document.readyState == 'interactive') {
+    channel.onDOMContentLoaded.fire();
+}
+
+/**
+ * Intercept calls to addEventListener + removeEventListener and handle deviceready,
+ * resume, and pause events.
+ */
+var m_document_addEventListener = document.addEventListener;
+var m_document_removeEventListener = document.removeEventListener;
+var m_window_addEventListener = window.addEventListener;
+var m_window_removeEventListener = window.removeEventListener;
+
+/**
+ * Houses custom event handlers to intercept on document + window event listeners.
+ */
+var documentEventHandlers = {},
+    windowEventHandlers = {};
+
+document.addEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    if (typeof documentEventHandlers[e] != 'undefined') {
+        documentEventHandlers[e].subscribe(handler);
+    } else {
+        m_document_addEventListener.call(document, evt, handler, capture);
+    }
+};
+
+window.addEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    if (typeof windowEventHandlers[e] != 'undefined') {
+        windowEventHandlers[e].subscribe(handler);
+    } else {
+        m_window_addEventListener.call(window, evt, handler, capture);
+    }
+};
+
+document.removeEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    // If unsubscribing from an event that is handled by a plugin
+    if (typeof documentEventHandlers[e] != "undefined") {
+        documentEventHandlers[e].unsubscribe(handler);
+    } else {
+        m_document_removeEventListener.call(document, evt, handler, capture);
+    }
+};
+
+window.removeEventListener = function(evt, handler, capture) {
+    var e = evt.toLowerCase();
+    // If unsubscribing from an event that is handled by a plugin
+    if (typeof windowEventHandlers[e] != "undefined") {
+        windowEventHandlers[e].unsubscribe(handler);
+    } else {
+        m_window_removeEventListener.call(window, evt, handler, capture);
+    }
+};
+
+function createEvent(type, data) {
+    var event = document.createEvent('Events');
+    event.initEvent(type, false, false);
+    if (data) {
+        for (var i in data) {
+            if (data.hasOwnProperty(i)) {
+                event[i] = data[i];
+            }
+        }
+    }
+    return event;
+}
+
+if(typeof window.console === "undefined") {
+    window.console = {
+        log:function(){}
+    };
+}
+
+var cordova = {
+    define:define,
+    require:require,
+    /**
+     * Methods to add/remove your own addEventListener hijacking on document + window.
+     */
+    addWindowEventHandler:function(event) {
+        return (windowEventHandlers[event] = channel.create(event));
+    },
+    addStickyDocumentEventHandler:function(event) {
+        return (documentEventHandlers[event] = channel.createSticky(event));
+    },
+    addDocumentEventHandler:function(event) {
+        return (documentEventHandlers[event] = channel.create(event));
+    },
+    removeWindowEventHandler:function(event) {
+        delete windowEventHandlers[event];
+    },
+    removeDocumentEventHandler:function(event) {
+        delete documentEventHandlers[event];
+    },
+    /**
+     * Retrieve original event handlers that were replaced by Cordova
+     *
+     * @return object
+     */
+    getOriginalHandlers: function() {
+        return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
+        'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
+    },
+    /**
+     * Method to fire event from native code
+     * bNoDetach is required for events which cause an exception which needs to be caught in native code
+     */
+    fireDocumentEvent: function(type, data, bNoDetach) {
+        var evt = createEvent(type, data);
+        if (typeof documentEventHandlers[type] != 'undefined') {
+            if( bNoDetach ) {
+              documentEventHandlers[type].fire(evt);
+            }
+            else {
+              setTimeout(function() {
+                  // Fire deviceready on listeners that were registered before cordova.js was loaded.
+                  if (type == 'deviceready') {
+                      document.dispatchEvent(evt);
+                  }
+                  documentEventHandlers[type].fire(evt);
+              }, 0);
+            }
+        } else {
+            document.dispatchEvent(evt);
+        }
+    },
+    fireWindowEvent: function(type, data) {
+        var evt = createEvent(type,data);
+        if (typeof windowEventHandlers[type] != 'undefined') {
+            setTimeout(function() {
+                windowEventHandlers[type].fire(evt);
+            }, 0);
+        } else {
+            window.dispatchEvent(evt);
+        }
+    },
+
+    /**
+     * Plugin callback mechanism.
+     */
+    // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
+    // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
+    callbackId: Math.floor(Math.random() * 2000000000),
+    callbacks:  {},
+    callbackStatus: {
+        NO_RESULT: 0,
+        OK: 1,
+        CLASS_NOT_FOUND_EXCEPTION: 2,
+        ILLEGAL_ACCESS_EXCEPTION: 3,
+        INSTANTIATION_EXCEPTION: 4,
+        MALFORMED_URL_EXCEPTION: 5,
+        IO_EXCEPTION: 6,
+        INVALID_ACTION: 7,
+        JSON_EXCEPTION: 8,
+        ERROR: 9
+    },
+
+    /**
+     * Called by native code when returning successful result from an action.
+     */
+    callbackSuccess: function(callbackId, args) {
+        try {
+            cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
+        } catch (e) {
+            console.log("Error in error callback: " + callbackId + " = "+e);
+        }
+    },
+
+    /**
+     * Called by native code when returning error result from an action.
+     */
+    callbackError: function(callbackId, args) {
+        // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
+        // Derive success from status.
+        try {
+            cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
+        } catch (e) {
+            console.log("Error in error callback: " + callbackId + " = "+e);
+        }
+    },
+
+    /**
+     * Called by native code when returning the result from an action.
+     */
+    callbackFromNative: function(callbackId, success, status, args, keepCallback) {
+        var callback = cordova.callbacks[callbackId];
+        if (callback) {
+            if (success && status == cordova.callbackStatus.OK) {
+                callback.success && callback.success.apply(null, args);
+            } else if (!success) {
+                callback.fail && callback.fail.apply(null, args);
+            }
+
+            // Clear callback if not expecting any more results
+            if (!keepCallback) {
+                delete cordova.callbacks[callbackId];
+            }
+        }
+    },
+    addConstructor: function(func) {
+        channel.onCordovaReady.subscribe(function() {
+            try {
+                func();
+            } catch(e) {
+                console.log("Failed to run constructor: " + e);
+            }
+        });
+    }
+};
+
+// Register pause, resume and deviceready channels as events on document.
+channel.onPause = cordova.addDocumentEventHandler('pause');
+channel.onResume = cordova.addDocumentEventHandler('resume');
+channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
+
+module.exports = cordova;
+
+});
+
+// file: lib/common/argscheck.js
+define("cordova/argscheck", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+var utils = require('cordova/utils');
+
+var moduleExports = module.exports;
+
+var typeMap = {
+    'A': 'Array',
+    'D': 'Date',
+    'N': 'Number',
+    'S': 'String',
+    'F': 'Function',
+    'O': 'Object'
+};
+
+function extractParamName(callee, argIndex) {
+  return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
+}
+
+function checkArgs(spec, functionName, args, opt_callee) {
+    if (!moduleExports.enableChecks) {
+        return;
+    }
+    var errMsg = null;
+    var typeName;
+    for (var i = 0; i < spec.length; ++i) {
+        var c = spec.charAt(i),
+            cUpper = c.toUpperCase(),
+            arg = args[i];
+        // Asterix means allow anything.
+        if (c == '*') {
+            continue;
+        }
+        typeName = utils.typeName(arg);
+        if ((arg === null || arg === undefined) && c == cUpper) {
+            continue;
+        }
+        if (typeName != typeMap[cUpper]) {
+            errMsg = 'Expected ' + typeMap[cUpper];
+            break;
+        }
+    }
+    if (errMsg) {
+        errMsg += ', but got ' + typeName + '.';
+        errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
+        // Don't log when running jake test.
+        if (typeof jasmine == 'undefined') {
+            console.error(errMsg);
+        }
+        throw TypeError(errMsg);
+    }
+}
+
+function getValue(value, defaultValue) {
+    return value === undefined ? defaultValue : value;
+}
+
+moduleExports.checkArgs = checkArgs;
+moduleExports.getValue = getValue;
+moduleExports.enableChecks = true;
+
+
+});
+
+// file: lib/common/builder.js
+define("cordova/builder", function(require, exports, module) {
+
+var utils = require('cordova/utils');
+
+function each(objects, func, context) {
+    for (var prop in objects) {
+        if (objects.hasOwnProperty(prop)) {
+            func.apply(context, [objects[prop], prop]);
+        }
+    }
+}
+
+function clobber(obj, key, value) {
+    exports.replaceHookForTesting(obj, key);
+    obj[key] = value;
+    // Getters can only be overridden by getters.
+    if (obj[key] !== value) {
+        utils.defineGetter(obj, key, function() {
+            return value;
+        });
+    }
+}
+
+function assignOrWrapInDeprecateGetter(obj, key, value, message) {
+    if (message) {
+        utils.defineGetter(obj, key, function() {
+            console.log(message);
+            delete obj[key];
+            clobber(obj, key, value);
+            return value;
+        });
+    } else {
+        clobber(obj, key, value);
+    }
+}
+
+function include(parent, objects, clobber, merge) {
+    each(objects, function (obj, key) {
+        try {
+          var result = obj.path ? require(obj.path) : {};
+
+          if (clobber) {
+              // Clobber if it doesn't exist.
+              if (typeof parent[key] === 'undefined') {
+                  assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+              } else if (typeof obj.path !== 'undefined') {
+                  // If merging, merge properties onto parent, otherwise, clobber.
+                  if (merge) {
+                      recursiveMerge(parent[key], result);
+                  } else {
+                      assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+                  }
+              }
+              result = parent[key];
+          } else {
+            // Overwrite if not currently defined.
+            if (typeof parent[key] == 'undefined') {
+              assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
+            } else {
+              // Set result to what already exists, so we can build children into it if they exist.
+              result = parent[key];
+            }
+          }
+
+          if (obj.children) {
+            include(result, obj.children, clobber, merge);
+          }
+        } catch(e) {
+          utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"');
+        }
+    });
+}
+
+/**
+ * Merge properties from one object onto another recursively.  Properties from
+ * the src object will overwrite existing target property.
+ *
+ * @param target Object to merge properties into.
+ * @param src Object to merge properties from.
+ */
+function recursiveMerge(target, src) {
+    for (var prop in src) {
+        if (src.hasOwnProperty(prop)) {
+            if (target.prototype && target.prototype.constructor === target) {
+                // If the target object is a constructor override off prototype.
+                clobber(target.prototype, prop, src[prop]);
+            } else {
+                if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
+                    recursiveMerge(target[prop], src[prop]);
+                } else {
+                    clobber(target, prop, src[prop]);
+                }
+            }
+        }
+    }
+}
+
+exports.buildIntoButDoNotClobber = function(objects, target) {
+    include(target, objects, false, false);
+};
+exports.buildIntoAndClobber = function(objects, target) {
+    include(target, objects, true, false);
+};
+exports.buildIntoAndMerge = function(objects, target) {
+    include(target, objects, true, true);
+};
+exports.recursiveMerge = recursiveMerge;
+exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
+exports.replaceHookForTesting = function() {};
+
+});
+
+// file: lib/common/channel.js
+define("cordova/channel", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+    nextGuid = 1;
+
+/**
+ * Custom pub-sub "channel" that can have functions subscribed to it
+ * This object is used to define and control firing of events for
+ * cordova initialization, as well as for custom events thereafter.
+ *
+ * The order of events during page load and Cordova startup is as follows:
+ *
+ * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.
+ * onNativeReady*              Internal event that indicates the Cordova native side is ready.
+ * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.
+ * onCordovaInfoReady*         Internal event fired when device properties are available.
+ * onCordovaConnectionReady*   Internal event fired when the connection property has been set.
+ * onDeviceReady*              User event fired to indicate that Cordova is ready
+ * onResume                    User event fired to indicate a start/resume lifecycle event
+ * onPause                     User event fired to indicate a pause lifecycle event
+ * onDestroy*                  Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
+ *
+ * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
+ * All listeners that subscribe after the event is fired will be executed right away.
+ *
+ * The only Cordova events that user code should register for are:
+ *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript
+ *      pause                 App has moved to background
+ *      resume                App has returned to foreground
+ *
+ * Listeners can be registered as:
+ *      document.addEventListener("deviceready", myDeviceReadyListener, false);
+ *      document.addEventListener("resume", myResumeListener, false);
+ *      document.addEventListener("pause", myPauseListener, false);
+ *
+ * The DOM lifecycle events should be used for saving and restoring state
+ *      window.onload
+ *      window.onunload
+ *
+ */
+
+/**
+ * Channel
+ * @constructor
+ * @param type  String the channel name
+ */
+var Channel = function(type, sticky) {
+    this.type = type;
+    // Map of guid -> function.
+    this.handlers = {};
+    // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
+    this.state = sticky ? 1 : 0;
+    // Used in sticky mode to remember args passed to fire().
+    this.fireArgs = null;
+    // Used by onHasSubscribersChange to know if there are any listeners.
+    this.numHandlers = 0;
+    // Function that is called when the first listener is subscribed, or when
+    // the last listener is unsubscribed.
+    this.onHasSubscribersChange = null;
+},
+    channel = {
+        /**
+         * Calls the provided function only after all of the channels specified
+         * have been fired. All channels must be sticky channels.
+         */
+        join: function(h, c) {
+            var len = c.length,
+                i = len,
+                f = function() {
+                    if (!(--i)) h();
+                };
+            for (var j=0; j<len; j++) {
+                if (c[j].state === 0) {
+                    throw Error('Can only use join with sticky channels.');
+                }
+                c[j].subscribe(f);
+            }
+            if (!len) h();
+        },
+        create: function(type) {
+            return channel[type] = new Channel(type, false);
+        },
+        createSticky: function(type) {
+            return channel[type] = new Channel(type, true);
+        },
+
+        /**
+         * cordova Channels that must fire before "deviceready" is fired.
+         */
+        deviceReadyChannelsArray: [],
+        deviceReadyChannelsMap: {},
+
+        /**
+         * Indicate that a feature needs to be initialized before it is ready to be used.
+         * This holds up Cordova's "deviceready" event until the feature has been initialized
+         * and Cordova.initComplete(feature) is called.
+         *
+         * @param feature {String}     The unique feature name
+         */
+        waitForInitialization: function(feature) {
+            if (feature) {
+                var c = channel[feature] || this.createSticky(feature);
+                this.deviceReadyChannelsMap[feature] = c;
+                this.deviceReadyChannelsArray.push(c);
+            }
+        },
+
+        /**
+         * Indicate that initialization code has completed and the feature is ready to be used.
+         *
+         * @param feature {String}     The unique feature name
+         */
+        initializationComplete: function(feature) {
+            var c = this.deviceReadyChannelsMap[feature];
+            if (c) {
+                c.fire();
+            }
+        }
+    };
+
+function forceFunction(f) {
+    if (typeof f != 'function') throw "Function required as first argument!";
+}
+
+/**
+ * Subscribes the given function to the channel. Any time that
+ * Channel.fire is called so too will the function.
+ * Optionally specify an execution context for the function
+ * and a guid that can be used to stop subscribing to the channel.
+ * Returns the guid.
+ */
+Channel.prototype.subscribe = function(f, c) {
+    // need a function to call
+    forceFunction(f);
+    if (this.state == 2) {
+        f.apply(c || this, this.fireArgs);
+        return;
+    }
+
+    var func = f,
+        guid = f.observer_guid;
+    if (typeof c == "object") { func = utils.close(c, f); }
+
+    if (!guid) {
+        // first time any channel has seen this subscriber
+        guid = '' + nextGuid++;
+    }
+    func.observer_guid = guid;
+    f.observer_guid = guid;
+
+    // Don't add the same handler more than once.
+    if (!this.handlers[guid]) {
+        this.handlers[guid] = func;
+        this.numHandlers++;
+        if (this.numHandlers == 1) {
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+/**
+ * Unsubscribes the function with the given guid from the channel.
+ */
+Channel.prototype.unsubscribe = function(f) {
+    // need a function to unsubscribe
+    forceFunction(f);
+
+    var guid = f.observer_guid,
+        handler = this.handlers[guid];
+    if (handler) {
+        delete this.handlers[guid];
+        this.numHandlers--;
+        if (this.numHandlers === 0) {
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+/**
+ * Calls all functions subscribed to this channel.
+ */
+Channel.prototype.fire = function(e) {
+    var fail = false,
+        fireArgs = Array.prototype.slice.call(arguments);
+    // Apply stickiness.
+    if (this.state == 1) {
+        this.state = 2;
+        this.fireArgs = fireArgs;
+    }
+    if (this.numHandlers) {
+        // Copy the values first so that it is safe to modify it from within
+        // callbacks.
+        var toCall = [];
+        for (var item in this.handlers) {
+            toCall.push(this.handlers[item]);
+        }
+        for (var i = 0; i < toCall.length; ++i) {
+            toCall[i].apply(this, fireArgs);
+        }
+        if (this.state == 2 && this.numHandlers) {
+            this.numHandlers = 0;
+            this.handlers = {};
+            this.onHasSubscribersChange && this.onHasSubscribersChange();
+        }
+    }
+};
+
+
+// defining them here so they are ready super fast!
+// DOM event that is received when the web page is loaded and parsed.
+channel.createSticky('onDOMContentLoaded');
+
+// Event to indicate the Cordova native side is ready.
+channel.createSticky('onNativeReady');
+
+// Event to indicate that all Cordova JavaScript objects have been created
+// and it's time to run plugin constructors.
+channel.createSticky('onCordovaReady');
+
+// Event to indicate that device properties are available
+channel.createSticky('onCordovaInfoReady');
+
+// Event to indicate that the connection property has been set.
+channel.createSticky('onCordovaConnectionReady');
+
+// Event to indicate that all automatically loaded JS plugins are loaded and ready.
+channel.createSticky('onPluginsReady');
+
+// Event to indicate that Cordova is ready
+channel.createSticky('onDeviceReady');
+
+// Event to indicate a resume lifecycle event
+channel.create('onResume');
+
+// Event to indicate a pause lifecycle event
+channel.create('onPause');
+
+// Event to indicate a destroy lifecycle event
+channel.createSticky('onDestroy');
+
+// Channels that must fire before "deviceready" is fired.
+channel.waitForInitialization('onCordovaReady');
+channel.waitForInitialization('onCordovaConnectionReady');
+channel.waitForInitialization('onDOMContentLoaded');
+
+module.exports = channel;
+
+});
+
+// file: lib/common/commandProxy.js
+define("cordova/commandProxy", function(require, exports, module) {
+
+
+// internal map of proxy function
+var CommandProxyMap = {};
+
+module.exports = {
+
+    // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
+    add:function(id,proxyObj) {
+        console.log("adding proxy for " + id);
+        CommandProxyMap[id] = proxyObj;
+        return proxyObj;
+    },
+
+    // cordova.commandProxy.remove("Accelerometer");
+    remove:function(id) {
+        var proxy = CommandProxyMap[id];
+        delete CommandProxyMap[id];
+        CommandProxyMap[id] = null;
+        return proxy;
+    },
+
+    get:function(service,action) {
+        return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null );
+    }
+};
+});
+
+// file: lib/android/exec.js
+define("cordova/exec", function(require, exports, module) {
+
+/**
+ * Execute a cordova command.  It is up to the native side whether this action
+ * is synchronous or asynchronous.  The native side can return:
+ *      Synchronous: PluginResult object as a JSON string
+ *      Asynchronous: Empty string ""
+ * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
+ * depending upon the result of the action.
+ *
+ * @param {Function} success    The success callback
+ * @param {Function} fail       The fail callback
+ * @param {String} service      The name of the service to use
+ * @param {String} action       Action to be run in cordova
+ * @param {String[]} [args]     Zero or more arguments to pass to the method
+ */
+var cordova = require('cordova'),
+    nativeApiProvider = require('cordova/plugin/android/nativeapiprovider'),
+    utils = require('cordova/utils'),
+    jsToNativeModes = {
+        PROMPT: 0,
+        JS_OBJECT: 1,
+        // This mode is currently for benchmarking purposes only. It must be enabled
+        // on the native side through the ENABLE_LOCATION_CHANGE_EXEC_MODE
+        // constant within CordovaWebViewClient.java before it will work.
+        LOCATION_CHANGE: 2
+    },
+    nativeToJsModes = {
+        // Polls for messages using the JS->Native bridge.
+        POLLING: 0,
+        // For LOAD_URL to be viable, it would need to have a work-around for
+        // the bug where the soft-keyboard gets dismissed when a message is sent.
+        LOAD_URL: 1,
+        // For the ONLINE_EVENT to be viable, it would need to intercept all event
+        // listeners (both through addEventListener and window.ononline) as well
+        // as set the navigator property itself.
+        ONLINE_EVENT: 2,
+        // Uses reflection to access private APIs of the WebView that can send JS
+        // to be executed.
+        // Requires Android 3.2.4 or above.
+        PRIVATE_API: 3
+    },
+    jsToNativeBridgeMode,  // Set lazily.
+    nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT,
+    pollEnabled = false,
+    messagesFromNative = [];
+
+function androidExec(success, fail, service, action, args) {
+    // Set default bridge modes if they have not already been set.
+    // By default, we use the failsafe, since addJavascriptInterface breaks too often
+    if (jsToNativeBridgeMode === undefined) {
+        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+    }
+
+    // Process any ArrayBuffers in the args into a string.
+    for (var i = 0; i < args.length; i++) {
+        if (utils.typeName(args[i]) == 'ArrayBuffer') {
+            args[i] = window.btoa(String.fromCharCode.apply(null, new Uint8Array(args[i])));
+        }
+    }
+
+    var callbackId = service + cordova.callbackId++,
+        argsJson = JSON.stringify(args);
+
+    if (success || fail) {
+        cordova.callbacks[callbackId] = {success:success, fail:fail};
+    }
+
+    if (jsToNativeBridgeMode == jsToNativeModes.LOCATION_CHANGE) {
+        window.location = 'http://cdv_exec/' + service + '#' + action + '#' + callbackId + '#' + argsJson;
+    } else {
+        var messages = nativeApiProvider.get().exec(service, action, callbackId, argsJson);
+        // If argsJson was received by Java as null, try again with the PROMPT bridge mode.
+        // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2.  See CB-2666.
+        if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && messages === "@Null arguments.") {
+            androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
+            androidExec(success, fail, service, action, args);
+            androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
+            return;
+        } else {
+            androidExec.processMessages(messages);
+        }
+    }
+}
+
+function pollOnce() {
+    var msg = nativeApiProvider.get().retrieveJsMessages();
+    androidExec.processMessages(msg);
+}
+
+function pollingTimerFunc() {
+    if (pollEnabled) {
+        pollOnce();
+        setTimeout(pollingTimerFunc, 50);
+    }
+}
+
+function hookOnlineApis() {
+    function proxyEvent(e) {
+        cordova.fireWindowEvent(e.type);
+    }
+    // The network module takes care of firing online and offline events.
+    // It currently fires them only on document though, so we bridge them
+    // to window here (while first listening for exec()-releated online/offline
+    // events).
+    window.addEventListener('online', pollOnce, false);
+    window.addEventListener('offline', pollOnce, false);
+    cordova.addWindowEventHandler('online');
+    cordova.addWindowEventHandler('offline');
+    document.addEventListener('online', proxyEvent, false);
+    document.addEventListener('offline', proxyEvent, false);
+}
+
+hookOnlineApis();
+
+androidExec.jsToNativeModes = jsToNativeModes;
+androidExec.nativeToJsModes = nativeToJsModes;
+
+androidExec.setJsToNativeBridgeMode = function(mode) {
+    if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {
+        console.log('Falling back on PROMPT mode since _cordovaNative is missing. Expected for Android 3.2 and lower only.');
+        mode = jsToNativeModes.PROMPT;
+    }
+    nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);
+    jsToNativeBridgeMode = mode;
+};
+
+androidExec.setNativeToJsBridgeMode = function(mode) {
+    if (mode == nativeToJsBridgeMode) {
+        return;
+    }
+    if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {
+        pollEnabled = false;
+    }
+
+    nativeToJsBridgeMode = mode;
+    // Tell the native side to switch modes.
+    nativeApiProvider.get().setNativeToJsBridgeMode(mode);
+
+    if (mode == nativeToJsModes.POLLING) {
+        pollEnabled = true;
+        setTimeout(pollingTimerFunc, 1);
+    }
+};
+
+// Processes a single message, as encoded by NativeToJsMessageQueue.java.
+function processMessage(message) {
+    try {
+        var firstChar = message.charAt(0);
+        if (firstChar == 'J') {
+            eval(message.slice(1));
+        } else if (firstChar == 'S' || firstChar == 'F') {
+            var success = firstChar == 'S';
+            var keepCallback = message.charAt(1) == '1';
+            var spaceIdx = message.indexOf(' ', 2);
+            var status = +message.slice(2, spaceIdx);
+            var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
+            var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
+            var payloadKind = message.charAt(nextSpaceIdx + 1);
+            var payload;
+            if (payloadKind == 's') {
+                payload = message.slice(nextSpaceIdx + 2);
+            } else if (payloadKind == 't') {
+                payload = true;
+            } else if (payloadKind == 'f') {
+                payload = false;
+            } else if (payloadKind == 'N') {
+                payload = null;
+            } else if (payloadKind == 'n') {
+                payload = +message.slice(nextSpaceIdx + 2);
+            } else if (payloadKind == 'A') {
+                var data = message.slice(nextSpaceIdx + 2);
+                var bytes = window.atob(data);
+                var arraybuffer = new Uint8Array(bytes.length);
+                for (var i = 0; i < bytes.length; i++) {
+                    arraybuffer[i] = bytes.charCodeAt(i);
+                }
+                payload = arraybuffer.buffer;
+            } else if (payloadKind == 'S') {
+                payload = window.atob(message.slice(nextSpaceIdx + 2));
+            } else {
+                payload = JSON.parse(message.slice(nextSpaceIdx + 1));
+            }
+            cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback);
+        } else {
+            console.log("processMessage failed: invalid message:" + message);
+        }
+    } catch (e) {
+        console.log("processMessage failed: Message: " + message);
+        console.log("processMessage failed: Error: " + e);
+        console.log("processMessage failed: Stack: " + e.stack);
+    }
+}
+
+// This is called from the NativeToJsMessageQueue.java.
+androidExec.processMessages = function(messages) {
+    if (messages) {
+        messagesFromNative.push(messages);
+        // Check for the reentrant case, and enqueue the message if that's the case.
+        if (messagesFromNative.length > 1) {
+            return;
+        }
+        while (messagesFromNative.length) {
+            // Don't unshift until the end so that reentrancy can be detected.
+            messages = messagesFromNative[0];
+            // The Java side can send a * message to indicate that it
+            // still has messages waiting to be retrieved.
+            if (messages == '*') {
+                messagesFromNative.shift();
+                window.setTimeout(pollOnce, 0);
+                return;
+            }
+
+            var spaceIdx = messages.indexOf(' ');
+            var msgLen = +messages.slice(0, spaceIdx);
+            var message = messages.substr(spaceIdx + 1, msgLen);
+            messages = messages.slice(spaceIdx + msgLen + 1);
+            processMessage(message);
+            if (messages) {
+                messagesFromNative[0] = messages;
+            } else {
+                messagesFromNative.shift();
+            }
+        }
+    }
+};
+
+module.exports = androidExec;
+
+});
+
+// file: lib/common/modulemapper.js
+define("cordova/modulemapper", function(require, exports, module) {
+
+var builder = require('cordova/builder'),
+    moduleMap = define.moduleMap,
+    symbolList,
+    deprecationMap;
+
+exports.reset = function() {
+    symbolList = [];
+    deprecationMap = {};
+};
+
+function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {
+    if (!(moduleName in moduleMap)) {
+        throw new Error('Module ' + moduleName + ' does not exist.');
+    }
+    symbolList.push(strategy, moduleName, symbolPath);
+    if (opt_deprecationMessage) {
+        deprecationMap[symbolPath] = opt_deprecationMessage;
+    }
+}
+
+// Note: Android 2.3 does have Function.bind().
+exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {
+    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
+};
+
+function prepareNamespace(symbolPath, context) {
+    if (!symbolPath) {
+        return context;
+    }
+    var parts = symbolPath.split('.');
+    var cur = context;
+    for (var i = 0, part; part = parts[i]; ++i) {
+        cur = cur[part] = cur[part] || {};
+    }
+    return cur;
+}
+
+exports.mapModules = function(context) {
+    var origSymbols = {};
+    context.CDV_origSymbols = origSymbols;
+    for (var i = 0, len = symbolList.length; i < len; i += 3) {
+        var strategy = symbolList[i];
+        var moduleName = symbolList[i + 1];
+        var symbolPath = symbolList[i + 2];
+        var lastDot = symbolPath.lastIndexOf('.');
+        var namespace = symbolPath.substr(0, lastDot);
+        var lastName = symbolPath.substr(lastDot + 1);
+
+        var module = require(moduleName);
+        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
+        var parentObj = prepareNamespace(namespace, context);
+        var target = parentObj[lastName];
+
+        if (strategy == 'm' && target) {
+            builder.recursiveMerge(target, module);
+        } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
+            if (!(symbolPath in origSymbols)) {
+                origSymbols[symbolPath] = target;
+            }
+            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
+        }
+    }
+};
+
+exports.getOriginalSymbol = function(context, symbolPath) {
+    var origSymbols = context.CDV_origSymbols;
+    if (origSymbols && (symbolPath in origSymbols)) {
+        return origSymbols[symbolPath];
+    }
+    var parts = symbolPath.split('.');
+    var obj = context;
+    for (var i = 0; i < parts.length; ++i) {
+        obj = obj && obj[parts[i]];
+    }
+    return obj;
+};
+
+exports.loadMatchingModules = function(matchingRegExp) {
+    for (var k in moduleMap) {
+        if (matchingRegExp.exec(k)) {
+            require(k);
+        }
+    }
+};
+
+exports.reset();
+
+
+});
+
+// file: lib/android/platform.js
+define("cordova/platform", function(require, exports, module) {
+
+module.exports = {
+    id: "android",
+    initialize:function() {
+        var channel = require("cordova/channel"),
+            cordova = require('cordova'),
+            exec = require('cordova/exec'),
+            modulemapper = require('cordova/modulemapper');
+
+        modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
+        modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');
+
+        modulemapper.mapModules(window);
+
+        // Inject a listener for the backbutton on the document.
+        var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
+        backButtonChannel.onHasSubscribersChange = function() {
+            // If we just attached the first handler or detached the last handler,
+            // let native know we need to override the back button.
+            exec(null, null, "App", "overrideBackbutton", [this.numHandlers == 1]);
+        };
+
+        // Add hardware MENU and SEARCH button handlers
+        cordova.addDocumentEventHandler('menubutton');
+        cordova.addDocumentEventHandler('searchbutton');
+
+        // Let native code know we are all done on the JS side.
+        // Native code will then un-hide the WebView.
+        channel.join(function() {
+            exec(null, null, "App", "show", []);
+        }, [channel.onCordovaReady]);
+    }
+};
+
+});
+
+// file: lib/common/plugin/Acceleration.js
+define("cordova/plugin/Acceleration", function(require, exports, module) {
+
+var Acceleration = function(x, y, z, timestamp) {
+    this.x = x;
+    this.y = y;
+    this.z = z;
+    this.timestamp = timestamp || (new Date()).getTime();
+};
+
+module.exports = Acceleration;
+
+});
+
+// file: lib/common/plugin/Camera.js
+define("cordova/plugin/Camera", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    Camera = require('cordova/plugin/CameraConstants'),
+    CameraPopoverHandle = require('cordova/plugin/CameraPopoverHandle');
+
+var cameraExport = {};
+
+// Tack on the Camera Constants to the base camera plugin.
+for (var key in Camera) {
+    cameraExport[key] = Camera[key];
+}
+
+/**
+ * Gets a picture from source defined by "options.sourceType", and returns the
+ * image as defined by the "options.destinationType" option.
+
+ * The defaults are sourceType=CAMERA and destinationType=FILE_URI.
+ *
+ * @param {Function} successCallback
+ * @param {Function} errorCallback
+ * @param {Object} options
+ */
+cameraExport.getPicture = function(successCallback, errorCallback, options) {
+    argscheck.checkArgs('fFO', 'Camera.getPicture', arguments);
+    options = options || {};
+    var getValue = argscheck.getValue;
+
+    var quality = getValue(options.quality, 50);
+    var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
+    var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
+    var targetWidth = getValue(options.targetWidth, -1);
+    var targetHeight = getValue(options.targetHeight, -1);
+    var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
+    var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
+    var allowEdit = !!options.allowEdit;
+    var correctOrientation = !!options.correctOrientation;
+    var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
+    var popoverOptions = getValue(options.popoverOptions, null);
+    var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
+
+    var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
+                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
+
+    exec(successCallback, errorCallback, "Camera", "takePicture", args);
+    return new CameraPopoverHandle();
+};
+
+cameraExport.cleanup = function(successCallback, errorCallback) {
+    exec(successCallback, errorCallback, "Camera", "cleanup", []);
+};
+
+module.exports = cameraExport;
+
+});
+
+// file: lib/common/plugin/CameraConstants.js
+define("cordova/plugin/CameraConstants", function(require, exports, module) {
+
+module.exports = {
+  DestinationType:{
+    DATA_URL: 0,         // Return base64 encoded string
+    FILE_URI: 1,         // Return file uri (content://media/external/images/media/2 for Android)
+    NATIVE_URI: 2        // Return native uri (eg. asset-library://... for iOS)
+  },
+  EncodingType:{
+    JPEG: 0,             // Return JPEG encoded image
+    PNG: 1               // Return PNG encoded image
+  },
+  MediaType:{
+    PICTURE: 0,          // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
+    VIDEO: 1,            // allow selection of video only, ONLY RETURNS URL
+    ALLMEDIA : 2         // allow selection from all media types
+  },
+  PictureSourceType:{
+    PHOTOLIBRARY : 0,    // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
+    CAMERA : 1,          // Take picture from camera
+    SAVEDPHOTOALBUM : 2  // Choose image from picture library (same as PHOTOLIBRARY for Android)
+  },
+  PopoverArrowDirection:{
+      ARROW_UP : 1,        // matches iOS UIPopoverArrowDirection constants to specify arrow location on popover
+      ARROW_DOWN : 2,
+      ARROW_LEFT : 4,
+      ARROW_RIGHT : 8,
+      ARROW_ANY : 15
+  },
+  Direction:{
+      BACK: 0,
+      FRONT: 1
+  }
+};
+
+});
+
+// file: lib/common/plugin/CameraPopoverHandle.js
+define("cordova/plugin/CameraPopoverHandle", function(require, exports, module) {
+
+var exec = require('cordova/exec');
+
+/**
+ * A handle to an image picker popover.
+ */
+var CameraPopoverHandle = function() {
+    this.setPosition = function(popoverOptions) {
+        console.log('CameraPopoverHandle.setPosition is only supported on iOS.');
+    };
+};
+
+module.exports = CameraPopoverHandle;
+
+});
+
+// file: lib/common/plugin/CameraPopoverOptions.js
+define("cordova/plugin/CameraPopoverOptions", function(require, exports, module) {
+
+var Camera = require('cordova/plugin/CameraConstants');
+
+/**
+ * Encapsulates options for iOS Popover image picker
+ */
+var CameraPopoverOptions = function(x,y,width,height,arrowDir){
+    // information of rectangle that popover should be anchored to
+    this.x = x || 0;
+    this.y = y || 32;
+    this.width = width || 320;
+    this.height = height || 480;
+    // The direction of the popover arrow
+    this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY;
+};
+
+module.exports = CameraPopoverOptions;
+
+});
+
+// file: lib/common/plugin/CaptureAudioOptions.js
+define("cordova/plugin/CaptureAudioOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all audio capture operation configuration options.
+ */
+var CaptureAudioOptions = function(){
+    // Upper limit of sound clips user can record. Value must be equal or greater than 1.
+    this.limit = 1;
+    // Maximum duration of a single sound clip in seconds.
+    this.duration = 0;
+    // The selected audio mode. Must match with one of the elements in supportedAudioModes array.
+    this.mode = null;
+};
+
+module.exports = CaptureAudioOptions;
+
+});
+
+// file: lib/common/plugin/CaptureError.js
+define("cordova/plugin/CaptureError", function(require, exports, module) {
+
+/**
+ * The CaptureError interface encapsulates all errors in the Capture API.
+ */
+var CaptureError = function(c) {
+   this.code = c || null;
+};
+
+// Camera or microphone failed to capture image or sound.
+CaptureError.CAPTURE_INTERNAL_ERR = 0;
+// Camera application or audio capture application is currently serving other capture request.
+CaptureError.CAPTURE_APPLICATION_BUSY = 1;
+// Invalid use of the API (e.g. limit parameter has value less than one).
+CaptureError.CAPTURE_INVALID_ARGUMENT = 2;
+// User exited camera application or audio capture application before capturing anything.
+CaptureError.CAPTURE_NO_MEDIA_FILES = 3;
+// The requested capture operation is not supported.
+CaptureError.CAPTURE_NOT_SUPPORTED = 20;
+
+module.exports = CaptureError;
+
+});
+
+// file: lib/common/plugin/CaptureImageOptions.js
+define("cordova/plugin/CaptureImageOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all image capture operation configuration options.
+ */
+var CaptureImageOptions = function(){
+    // Upper limit of images user can take. Value must be equal or greater than 1.
+    this.limit = 1;
+    // The selected image mode. Must match with one of the elements in supportedImageModes array.
+    this.mode = null;
+};
+
+module.exports = CaptureImageOptions;
+
+});
+
+// file: lib/common/plugin/CaptureVideoOptions.js
+define("cordova/plugin/CaptureVideoOptions", function(require, exports, module) {
+
+/**
+ * Encapsulates all video capture operation configuration options.
+ */
+var CaptureVideoOptions = function(){
+    // Upper limit of videos user can record. Value must be equal or greater than 1.
+    this.limit = 1;
+    // Maximum duration of a single video clip in seconds.
+    this.duration = 0;
+    // The selected video mode. Must match with one of the elements in supportedVideoModes array.
+    this.mode = null;
+};
+
+module.exports = CaptureVideoOptions;
+
+});
+
+// file: lib/common/plugin/CompassError.js
+define("cordova/plugin/CompassError", function(require, exports, module) {
+
+/**
+ *  CompassError.
+ *  An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var CompassError = function(err) {
+    this.code = (err !== undefined ? err : null);
+};
+
+CompassError.COMPASS_INTERNAL_ERR = 0;
+CompassError.COMPASS_NOT_SUPPORTED = 20;
+
+module.exports = CompassError;
+
+});
+
+// file: lib/common/plugin/CompassHeading.js
+define("cordova/plugin/CompassHeading", function(require, exports, module) {
+
+var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) {
+  this.magneticHeading = magneticHeading;
+  this.trueHeading = trueHeading;
+  this.headingAccuracy = headingAccuracy;
+  this.timestamp = timestamp || new Date().getTime();
+};
+
+module.exports = CompassHeading;
+
+});
+
+// file: lib/common/plugin/ConfigurationData.js
+define("cordova/plugin/ConfigurationData", function(require, exports, module) {
+
+/**
+ * Encapsulates a set of parameters that the capture device supports.
+ */
+function ConfigurationData() {
+    // The ASCII-encoded string in lower case representing the media type.
+    this.type = null;
+    // The height attribute represents height of the image or video in pixels.
+    // In the case of a sound clip this attribute has value 0.
+    this.height = 0;
+    // The width attribute represents width of the image or video in pixels.
+    // In the case of a sound clip this attribute has value 0
+    this.width = 0;
+}
+
+module.exports = ConfigurationData;
+
+});
+
+// file: lib/common/plugin/Connection.js
+define("cordova/plugin/Connection", function(require, exports, module) {
+
+/**
+ * Network status
+ */
+module.exports = {
+        UNKNOWN: "unknown",
+        ETHERNET: "ethernet",
+        WIFI: "wifi",
+        CELL_2G: "2g",
+        CELL_3G: "3g",
+        CELL_4G: "4g",
+        CELL:"cellular",
+        NONE: "none"
+};
+
+});
+
+// file: lib/common/plugin/Contact.js
+define("cordova/plugin/Contact", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    ContactError = require('cordova/plugin/ContactError'),
+    utils = require('cordova/utils');
+
+/**
+* Converts primitives into Complex Object
+* Currently only used for Date fields
+*/
+function convertIn(contact) {
+    var value = contact.birthday;
+    try {
+      contact.birthday = new Date(parseFloat(value));
+    } catch (exception){
+      console.log("Cordova Contact convertIn error: exception creating date.");
+    }
+    return contact;
+}
+
+/**
+* Converts Complex objects into primitives
+* Only conversion at present is for Dates.
+**/
+
+function convertOut(contact) {
+    var value = contact.birthday;
+    if (value !== null) {
+        // try to make it a Date object if it is not already
+        if (!utils.isDate(value)){
+            try {
+                value = new Date(value);
+            } catch(exception){
+                value = null;
+            }
+        }
+        if (utils.isDate(value)){
+            value = value.valueOf(); // convert to milliseconds
+        }
+        contact.birthday = value;
+    }
+    return contact;
+}
+
+/**
+* Contains information about a single contact.
+* @constructor
+* @param {DOMString} id unique identifier
+* @param {DOMString} displayName
+* @param {ContactName} name
+* @param {DOMString} nickname
+* @param {Array.<ContactField>} phoneNumbers array of phone numbers
+* @param {Array.<ContactField>} emails array of email addresses
+* @param {Array.<ContactAddress>} addresses array of addresses
+* @param {Array.<ContactField>} ims instant messaging user ids
+* @param {Array.<ContactOrganization>} organizations
+* @param {DOMString} birthday contact's birthday
+* @param {DOMString} note user notes about contact
+* @param {Array.<ContactField>} photos
+* @param {Array.<ContactField>} categories
+* @param {Array.<ContactField>} urls contact's web sites
+*/
+var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
+    ims, organizations, birthday, note, photos, categories, urls) {
+    this.id = id || null;
+    this.rawId = null;
+    this.displayName = displayName || null;
+    this.name = name || null; // ContactName
+    this.nickname = nickname || null;
+    this.phoneNumbers = phoneNumbers || null; // ContactField[]
+    this.emails = emails || null; // ContactField[]
+    this.addresses = addresses || null; // ContactAddress[]
+    this.ims = ims || null; // ContactField[]
+    this.organizations = organizations || null; // ContactOrganization[]
+    this.birthday = birthday || null;
+    this.note = note || null;
+    this.photos = photos || null; // ContactField[]
+    this.categories = categories || null; // ContactField[]
+    this.urls = urls || null; // ContactField[]
+};
+
+/**
+* Removes contact from device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.remove = function(successCB, errorCB) {
+    argscheck.checkArgs('FF', 'Contact.remove', arguments);
+    var fail = errorCB && function(code) {
+        errorCB(new ContactError(code));
+    };
+    if (this.id === null) {
+        fail(ContactError.UNKNOWN_ERROR);
+    }
+    else {
+        exec(successCB, fail, "Contacts", "remove", [this.id]);
+    }
+};
+
+/**
+* Creates a deep copy of this Contact.
+* With the contact ID set to null.
+* @return copy of this Contact
+*/
+Contact.prototype.clone = function() {
+    var clonedContact = utils.clone(this);
+    clonedContact.id = null;
+    clonedContact.rawId = null;
+
+    function nullIds(arr) {
+        if (arr) {
+            for (var i = 0; i < arr.length; ++i) {
+                arr[i].id = null;
+            }
+        }
+    }
+
+    // Loop through and clear out any id's in phones, emails, etc.
+    nullIds(clonedContact.phoneNumbers);
+    nullIds(clonedContact.emails);
+    nullIds(clonedContact.addresses);
+    nullIds(clonedContact.ims);
+    nullIds(clonedContact.organizations);
+    nullIds(clonedContact.categories);
+    nullIds(clonedContact.photos);
+    nullIds(clonedContact.urls);
+    return clonedContact;
+};
+
+/**
+* Persists contact to device storage.
+* @param successCB success callback
+* @param errorCB error callback
+*/
+Contact.prototype.save = function(successCB, errorCB) {
+    argscheck.checkArgs('FFO', 'Contact.save', arguments);
+    var fail = errorCB && function(code) {
+        errorCB(new ContactError(code));
+    };
+    var success = function(result) {
+        if (result) {
+            if (successCB) {
+                var fullContact = require('cordova/plugin/contacts').create(result);
+                successCB(convertIn(fullContact));
+            }
+        }
+        else {
+            // no Entry object returned
+            fail(ContactError.UNKNOWN_ERROR);
+        }
+    };
+    var dupContact = convertOut(utils.clone(this));
+    exec(success, fail, "Contacts", "save", [dupContact]);
+};
+
+
+module.exports = Contact;
+
+});
+
+// file: lib/common/plugin/ContactAddress.js
+define("cordova/plugin/ContactAddress", function(require, exports, module) {
+
+/**
+* Contact address.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code
+* @param formatted // NOTE: not a W3C standard
+* @param streetAddress
+* @param locality
+* @param region
+* @param postalCode
+* @param country
+*/
+
+var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) {
+    this.id = null;
+    this.pref = (typeof pref != 'undefined' ? pref : false);
+    this.type = type || null;
+    this.formatted = formatted || null;
+    this.streetAddress = streetAddress || null;
+    this.locality = locality || null;
+    this.region = region || null;
+    this.postalCode = postalCode || null;
+    this.country = country || null;
+};
+
+module.exports = ContactAddress;
+
+});
+
+// file: lib/common/plugin/ContactError.js
+define("cordova/plugin/ContactError", function(require, exports, module) {
+
+/**
+ *  ContactError.
+ *  An error code assigned by an implementation when an error has occurred
+ * @constructor
+ */
+var ContactError = function(err) {
+    this.code = (typeof err != 'undefined' ? err : null);
+};
+
+/**
+ * Error codes
+ */
+ContactError.UNKNOWN_ERROR = 0;
+ContactError.INVALID_ARGUMENT_ERROR = 1;
+ContactError.TIMEOUT_ERROR = 2;
+ContactError.PENDING_OPERATION_ERROR = 3;
+ContactError.IO_ERROR = 4;
+ContactError.NOT_SUPPORTED_ERROR = 5;
+ContactError.PERMISSION_DENIED_ERROR = 20;
+
+module.exports = ContactError;
+
+});
+
+// file: lib/common/plugin/ContactField.js
+define("cordova/plugin/ContactField", function(require, exports, module) {
+
+/**
+* Generic contact field.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param type
+* @param value
+* @param pref
+*/
+var ContactField = function(type, value, pref) {
+    this.id = null;
+    this.type = (type && type.toString()) || null;
+    this.value = (value && value.toString()) || null;
+    this.pref = (typeof pref != 'undefined' ? pref : false);
+};
+
+module.exports = ContactField;
+
+});
+
+// file: lib/common/plugin/ContactFindOptions.js
+define("cordova/plugin/ContactFindOptions", function(require, exports, module) {
+
+/**
+ * ContactFindOptions.
+ * @constructor
+ * @param filter used to match contacts against
+ * @param multiple boolean used to determine if more than one contact should be returned
+ */
+
+var ContactFindOptions = function(filter, multiple) {
+    this.filter = filter || '';
+    this.multiple = (typeof multiple != 'undefined' ? multiple : false);
+};
+
+module.exports = ContactFindOptions;
+
+});
+
+// file: lib/common/plugin/ContactName.js
+define("cordova/plugin/ContactName", function(require, exports, module) {
+
+/**
+* Contact name.
+* @constructor
+* @param formatted // NOTE: not part of W3C standard
+* @param familyName
+* @param givenName
+* @param middle
+* @param prefix
+* @param suffix
+*/
+var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) {
+    this.formatted = formatted || null;
+    this.familyName = familyName || null;
+    this.givenName = givenName || null;
+    this.middleName = middle || null;
+    this.honorificPrefix = prefix || null;
+    this.honorificSuffix = suffix || null;
+};
+
+module.exports = ContactName;
+
+});
+
+// file: lib/common/plugin/ContactOrganization.js
+define("cordova/plugin/ContactOrganization", function(require, exports, module) {
+
+/**
+* Contact organization.
+* @constructor
+* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
+* @param name
+* @param dept
+* @param title
+* @param startDate
+* @param endDate
+* @param location
+* @param desc
+*/
+
+var ContactOrganization = function(pref, type, name, dept, title) {
+    this.id = null;
+    this.pref = (typeof pref != 'undefined' ? pref : false);
+    this.type = type || null;
+    this.name = name || null;
+    this.department = dept || null;
+    this.title = title || null;
+};
+
+module.exports = ContactOrganization;
+
+});
+
+// file: lib/common/plugin/Coordinates.js
+define("cordova/plugin/Coordinates", function(require, exports, module) {
+
+/**
+ * This class contains position information.
+ * @param {Object} lat
+ * @param {Object} lng
+ * @param {Object} alt
+ * @param {Object} acc
+ * @param {Object} head
+ * @param {Object} vel
+ * @param {Object} altacc
+ * @constructor
+ */
+var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) {
+    /**
+     * The latitude of the position.
+     */
+    this.latitude = lat;
+    /**
+     * The longitude of the position,
+     */
+    this.longitude = lng;
+    /**
+     * The accuracy of the position.
+     */
+    this.accuracy = acc;
+    /**
+     * The altitude of the position.
+     */
+    this.altitude = (alt !== undefined ? alt : null);
+    /**
+     * The direction the device is moving at the position.
+     */
+    this.heading = (head !== undefined ? head : null);
+    /**
+     * The velocity with which the device is moving at the position.
+     */
+    this.speed = (vel !== undefined ? vel : null);
+
+    if (this.speed === 0 || this.speed === null) {
+        this.heading = NaN;
+    }
+
+    /**
+     * The altitude accuracy of the position.
+     */
+    this.altitudeAccuracy = (altacc !== undefined) ? altacc : null;
+};
+
+module.exports = Coordinates;
+
+});
+
+// file: lib/common/plugin/DirectoryEntry.js
+define("cordova/plugin/DirectoryEntry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    utils = require('cordova/utils'),
+    exec = require('cordova/exec'),
+    Entry = require('cordova/plugin/Entry'),
+    FileError = require('cordova/plugin/FileError'),
+    DirectoryReader = require('cordova/plugin/DirectoryReader');
+
+/**
+ * An interface representing a directory on the file system.
+ *
+ * {boolean} isFile always false (readonly)
+ * {boolean} isDirectory always true (readonly)
+ * {DOMString} name of the directory, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the directory (readonly)
+ * TODO: implement this!!! {FileSystem} filesystem on which the directory resides (readonly)
+ */
+var DirectoryEntry = function(name, fullPath) {
+     DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath);
+};
+
+utils.extend(DirectoryEntry, Entry);
+
+/**
+ * Creates a new DirectoryReader to read entries from this directory
+ */
+DirectoryEntry.prototype.createReader = function() {
+    return new DirectoryReader(this.fullPath);
+};
+
+/**
+ * Creates or looks up a directory
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory
+ * @param {Flags} options to create or exclusively create the directory
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) {
+    argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments);
+    var win = successCallback && function(result) {
+        var entry = new DirectoryEntry(result.name, result.fullPath);
+        successCallback(entry);
+    };
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, "File", "getDirectory", [this.fullPath, path, options]);
+};
+
+/**
+ * Deletes a directory and all of it's contents
+ *
+ * @param {Function} successCallback is called with no parameters
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments);
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(successCallback, fail, "File", "removeRecursively", [this.fullPath]);
+};
+
+/**
+ * Creates or looks up a file
+ *
+ * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file
+ * @param {Flags} options to create or exclusively create the file
+ * @param {Function} successCallback is called with the new entry
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) {
+    argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments);
+    var win = successCallback && function(result) {
+        var FileEntry = require('cordova/plugin/FileEntry');
+        var entry = new FileEntry(result.name, result.fullPath);
+        successCallback(entry);
+    };
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, "File", "getFile", [this.fullPath, path, options]);
+};
+
+module.exports = DirectoryEntry;
+
+});
+
+// file: lib/common/plugin/DirectoryReader.js
+define("cordova/plugin/DirectoryReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+    FileError = require('cordova/plugin/FileError') ;
+
+/**
+ * An interface that lists the files and directories in a directory.
+ */
+function DirectoryReader(path) {
+    this.path = path || null;
+}
+
+/**
+ * Returns a list of entries from a directory.
+ *
+ * @param {Function} successCallback is called with a list of entries
+ * @param {Function} errorCallback is called with a FileError
+ */
+DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) {
+    var win = typeof successCallback !== 'function' ? null : function(result) {
+        var retVal = [];
+        for (var i=0; i<result.length; i++) {
+            var entry = null;
+            if (result[i].isDirectory) {
+                entry = new (require('cordova/plugin/DirectoryEntry'))();
+            }
+            else if (result[i].isFile) {
+                entry = new (require('cordova/plugin/FileEntry'))();
+            }
+            entry.isDirectory = result[i].isDirectory;
+            entry.isFile = result[i].isFile;
+            entry.name = result[i].name;
+            entry.fullPath = result[i].fullPath;
+            retVal.push(entry);
+        }
+        successCallback(retVal);
+    };
+    var fail = typeof errorCallback !== 'function' ? null : function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, "File", "readEntries", [this.path]);
+};
+
+module.exports = DirectoryReader;
+
+});
+
+// file: lib/common/plugin/Entry.js
+define("cordova/plugin/Entry", function(require, exports, module) {
+
+var argscheck = require('cordova/argscheck'),
+    exec = require('cordova/exec'),
+    FileError = require('cordova/plugin/FileError'),
+    Metadata = require('cordova/plugin/Metadata');
+
+/**
+ * Represents a file or directory on the local file system.
+ *
+ * @param isFile
+ *            {boolean} true if Entry is a file (readonly)
+ * @param isDirectory
+ *            {boolean} true if Entry is a directory (readonly)
+ * @param name
+ *            {DOMString} name of the file or directory, excluding the path
+ *            leading to it (readonly)
+ * @param fullPath
+ *            {DOMString} the absolute full path to the file or directory
+ *            (readonly)
+ */
+function Entry(isFile, isDirectory, name, fullPath, fileSystem) {
+    this.isFile = !!isFile;
+    this.isDirectory = !!isDirectory;
+    this.name = name || '';
+    this.fullPath = fullPath || '';
+    this.filesystem = fileSystem || null;
+}
+
+/**
+ * Look up the metadata of the entry.
+ *
+ * @param successCallback
+ *            {Function} is called with a Metadata object
+ * @param errorCallback
+ *            {Function} is called with a FileError
+ */
+Entry.prototype.getMetadata = function(successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'Entry.getMetadata', arguments);
+    var success = successCallback && function(lastModified) {
+        var metadata = new Metadata(lastModified);
+        successCallback(metadata);
+    };
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+
+    exec(success, fail, "File", "getMetadata", [this.fullPath]);
+};
+
+/**
+ * Set the metadata of the entry.
+ *
+ * @param successCallback
+ *            {Function} is called with a Metadata object
+ * @param errorCallback
+ *            {Function} is called with a FileError
+ * @param metadataObject
+ *            {Object} keys and values to set
+ */
+Entry.prototype.setMetadata = function(successCallback, errorCallback, metadataObject) {
+    argscheck.checkArgs('FFO', 'Entry.setMetadata', arguments);
+    exec(successCallback, errorCallback, "File", "setMetadata", [this.fullPath, metadataObject]);
+};
+
+/**
+ * Move a file or directory to a new location.
+ *
+ * @param parent
+ *            {DirectoryEntry} the directory to which to move this entry
+ * @param newName
+ *            {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ *            {Function} called with the new DirectoryEntry object
+ * @param errorCallback
+ *            {Function} called with a FileError
+ */
+Entry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) {
+    argscheck.checkArgs('oSFF', 'Entry.moveTo', arguments);
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    // source path
+    var srcPath = this.fullPath,
+        // entry name
+        name = newName || this.name,
+        success = function(entry) {
+            if (entry) {
+                if (successCallback) {
+                    // create appropriate Entry object
+                    var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+                    successCallback(result);
+                }
+            }
+            else {
+                // no Entry object returned
+                fail && fail(FileError.NOT_FOUND_ERR);
+            }
+        };
+
+    // copy
+    exec(success, fail, "File", "moveTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Copy a directory to a different location.
+ *
+ * @param parent
+ *            {DirectoryEntry} the directory to which to copy the entry
+ * @param newName
+ *            {DOMString} new name of the entry, defaults to the current name
+ * @param successCallback
+ *            {Function} called with the new Entry object
+ * @param errorCallback
+ *            {Function} called with a FileError
+ */
+Entry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) {
+    argscheck.checkArgs('oSFF', 'Entry.copyTo', arguments);
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+
+        // source path
+    var srcPath = this.fullPath,
+        // entry name
+        name = newName || this.name,
+        // success callback
+        success = function(entry) {
+            if (entry) {
+                if (successCallback) {
+                    // create appropriate Entry object
+                    var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
+                    successCallback(result);
+                }
+            }
+            else {
+                // no Entry object returned
+                fail && fail(FileError.NOT_FOUND_ERR);
+            }
+        };
+
+    // copy
+    exec(success, fail, "File", "copyTo", [srcPath, parent.fullPath, name]);
+};
+
+/**
+ * Return a URL that can be used to identify this entry.
+ */
+Entry.prototype.toURL = function() {
+    // fullPath attribute contains the full URL
+    return this.fullPath;
+};
+
+/**
+ * Returns a URI that can be used to identify this entry.
+ *
+ * @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
+ * @return uri
+ */
+Entry.prototype.toURI = function(mimeType) {
+    console.log("DEPRECATED: Update your code to use 'toURL'");
+    // fullPath attribute contains the full URI
+    return this.toURL();
+};
+
+/**
+ * Remove a file or directory. It is an error to attempt to delete a
+ * directory that is not empty. It is an error to attempt to delete a
+ * root directory of a file system.
+ *
+ * @param successCallback {Function} called with no parameters
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.remove = function(successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'Entry.remove', arguments);
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(successCallback, fail, "File", "remove", [this.fullPath]);
+};
+
+/**
+ * Look up the parent DirectoryEntry of this entry.
+ *
+ * @param successCallback {Function} called with the parent DirectoryEntry object
+ * @param errorCallback {Function} called with a FileError
+ */
+Entry.prototype.getParent = function(successCallback, errorCallback) {
+    argscheck.checkArgs('FF', 'Entry.getParent', arguments);
+    var win = successCallback && function(result) {
+        var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
+        var entry = new DirectoryEntry(result.name, result.fullPath);
+        successCallback(entry);
+    };
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, "File", "getParent", [this.fullPath]);
+};
+
+module.exports = Entry;
+
+});
+
+// file: lib/common/plugin/File.js
+define("cordova/plugin/File", function(require, exports, module) {
+
+/**
+ * Constructor.
+ * name {DOMString} name of the file, without path information
+ * fullPath {DOMString} the full path of the file, including the name
+ * type {DOMString} mime type
+ * lastModifiedDate {Date} last modified date
+ * size {Number} size of the file in bytes
+ */
+
+var File = function(name, fullPath, type, lastModifiedDate, size){
+    this.name = name || '';
+    this.fullPath = fullPath || null;
+    this.type = type || null;
+    this.lastModifiedDate = lastModifiedDate || null;
+    this.size = size || 0;
+
+    // These store the absolute start and end for slicing the file.
+    this.start = 0;
+    this.end = this.size;
+};
+
+/**
+ * Returns a "slice" of the file. Since Cordova Files don't contain the actual
+ * content, this really returns a File with adjusted start and end.
+ * Slices of slices are supported.
+ * start {Number} The index at which to start the slice (inclusive).
+ * end {Number} The index at which to end the slice (exclusive).
+ */
+File.prototype.slice = function(start, end) {
+    var size = this.end - this.start;
+    var newStart = 0;
+    var newEnd = size;
+    if (arguments.length) {
+        if (start < 0) {
+            newStart = Math.max(size + start, 0);
+        } else {
+            newStart = Math.min(size, start);
+        }
+    }
+
+    if (arguments.length >= 2) {
+        if (end < 0) {
+            newEnd = Math.max(size + end, 0);
+        } else {
+            newEnd = Math.min(end, size);
+        }
+    }
+
+    var newFile = new File(this.name, this.fullPath, this.type, this.lastModifiedData, this.size);
+    newFile.start = this.start + newStart;
+    newFile.end = this.start + newEnd;
+    return newFile;
+};
+
+
+module.exports = File;
+
+});
+
+// file: lib/common/plugin/FileEntry.js
+define("cordova/plugin/FileEntry", function(require, exports, module) {
+
+var utils = require('cordova/utils'),
+    exec = require('cordova/exec'),
+    Entry = require('cordova/plugin/Entry'),
+    FileWriter = require('cordova/plugin/FileWriter'),
+    File = require('cordova/plugin/File'),
+    FileError = require('cordova/plugin/FileError');
+
+/**
+ * An interface representing a file on the file system.
+ *
+ * {boolean} isFile always true (readonly)
+ * {boolean} isDirectory always false (readonly)
+ * {DOMString} name of the file, excluding the path leading to it (readonly)
+ * {DOMString} fullPath the absolute full path to the file (readonly)
+ * {FileSystem} filesystem on which the file resides (readonly)
+ */
+var FileEntry = function(name, fullPath) {
+     FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath]);
+};
+
+utils.extend(FileEntry, Entry);
+
+/**
+ * Creates a new FileWriter associated with the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new FileWriter
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.createWriter = function(successCallback, errorCallback) {
+    this.file(function(filePointer) {
+        var writer = new FileWriter(filePointer);
+
+        if (writer.fileName === null || writer.fileName === "") {
+            errorCallback && errorCallback(new FileError(FileError.INVALID_STATE_ERR));
+        } else {
+            successCallback && successCallback(writer);
+        }
+    }, errorCallback);
+};
+
+/**
+ * Returns a File that represents the current state of the file that this FileEntry represents.
+ *
+ * @param {Function} successCallback is called with the new File object
+ * @param {Function} errorCallback is called with a FileError
+ */
+FileEntry.prototype.file = function(successCallback, errorCallback) {
+    var win = successCallback && function(f) {
+        var file = new File(f.name, f.fullPath, f.type, f.lastModifiedDate, f.size);
+        successCallback(file);
+    };
+    var fail = errorCallback && function(code) {
+        errorCallback(new FileError(code));
+    };
+    exec(win, fail, "File", "getFileMetadata", [this.fullPath]);
+};
+
+
+module.exports = FileEntry;
+
+});
+
+// file: lib/common/plugin/FileError.js
+define("cordova/plugin/FileError", function(require, exports, module) {
+
+/**
+ * FileError
+ */
+function FileError(error) {
+  this.code = error || null;
+}
+
+// File error codes
+// Found in DOMException
+FileError.NOT_FOUND_ERR = 1;
+FileError.SECURITY_ERR = 2;
+FileError.ABORT_ERR = 3;
+
+// Added by File API specification
+FileError.NOT_READABLE_ERR = 4;
+FileError.ENCODING_ERR = 5;
+FileError.NO_MODIFICATION_ALLOWED_ERR = 6;
+FileError.INVALID_STATE_ERR = 7;
+FileError.SYNTAX_ERR = 8;
+FileError.INVALID_MODIFICATION_ERR = 9;
+FileError.QUOTA_EXCEEDED_ERR = 10;
+FileError.TYPE_MISMATCH_ERR = 11;
+FileError.PATH_EXISTS_ERR = 12;
+
+module.exports = FileError;
+
+});
+
+// file: lib/common/plugin/FileReader.js
+define("cordova/plugin/FileReader", function(require, exports, module) {
+
+var exec = require('cordova/exec'),
+    modulemapper = require('cordova/modulemapper'),
+    utils = require('cordova/utils'),
+    File = require('cordova/plugin/File'),
+    FileError = require('cordova/plugin/FileError'),
+    ProgressEvent = require('cordova/plugin/ProgressEvent'),
+    origFileReader = modulemapper.getOriginalSymbol(this, 'FileReader');
+
+/**
+ * This class reads the mobile device file system.
+ *
+ * For Android:
+ *      The root directory is the root of the file system.
+ *      To read from the SD card, the file name is "sdcard/my_file.txt"
+ * @constructor
+ */
+var FileReader = function() {
+    this._readyState = 0;
+    this._error = null;
+    this._result = null;
+    this._fileName = '';
+    this._realReader = origFileReader ? new origFileReader() : {};
+};
+
+// States
+FileReader.EMPTY = 0;
+FileReader.LOADING = 1;
+FileReader.DONE = 2;
+
+utils.defineGetter(FileReader.prototype, 'readyState', function() {
+    return this._fileName ? this._readyState : this._realReader.readyState;
+});
+
+utils.defineGetter(FileReader.prototype, 'error', function() {
+    return this._fileName ? this._error: this._realReader.error;
+});
+
+utils.defineGetter(FileReader.prototype, 'result', function() {
+    return this._fileName ? this._result: this._realReader.result;
+});
+
+function defineEvent(eventName) {
+    utils.defineGetterSetter(FileReader.prototype, eventName, function() {
+        return this._realReader[eventName] || null;
+    }, function(value) {
+        this._realReader[eventName] = value;
+    });
+}
+defineEvent('onloadstart');    // When the read starts.
+defineEvent('onprogress');     // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total)
+defineEvent('onload');         // When the read has successfully completed.
+defineEvent('onerror');        // When the read has failed (see errors).
+defineEvent('onloadend');      // When the request has completed (either in success or failure).
+defineEvent('onabort');        // When the read has been aborted. For instance, by invoking the abort() method.
+
+function initRead(reader, file) {
+    // Already loading something
+    if (reader.readyState == FileReader.LOADING) {
+      throw new FileError(FileError.INVALID_STATE_ERR);
+    }
+
+    reader._result = null;
+    reader._error = null;
+    reader._readyState = FileReader.LOADING;
+
+    if (typeof file == 'string') {
+        // Deprecated in Cordova 2.4.
+        console.warn('Using a string argument with FileReader.readAs functions is deprecated.');
+        reader._fileName = file;
+    } else if (typeof file.fullPath == 'string') {
+        reader._fileName = file.fullPath;
+    } else {
+        reader._fileName = '';
+        return true;
+    }
+
+    reader.onloadstart && reader.onloadstart(new ProgressEvent("loadstart", {target:reader}));
+}
+
+/**
+ * Abort reading file.
+ */
+FileReader.prototype.abort = function() {
+    if (origFileReader && !this._fileName) {
+        return this._realReader.abort();
+    }
+    this._result = null;
+
+    if (this._readyState == FileReader.DONE || this._readyState == FileReader.EMPTY) {
+      return;
+    }
+
+    this._readyState = FileReader.DONE;
+
+    // If abort callback
+    if (typeof this.onabort === 'function') {
+        this.onabort(new ProgressEvent('abort', {target:this}));
+    }
+    // If load end callback
+    if (typeof this.onloadend === 'function') {
+        this.onloadend(new ProgressEvent('loadend', {target:this}));
+    }
+};
+
+/**
+ * Read text file.
+ *
+ * @param file          {File} File object containing file properties
+ * @param encoding      [Optional] (see http://www.iana.org/assignments/character-sets)
+ */
+FileReader.prototype.readAsText = function(file, encoding) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsText(file, encoding);
+    }
+
+    // Default encoding is UTF-8
+    var enc = encoding ? encoding : "UTF-8";
+    var me = this;
+    var execArgs = [this._fileName, enc, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // Save result
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            // null result
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsText", execArgs);
+};
+
+
+/**
+ * Read file and return data as a base64 encoded data url.
+ * A data url is of the form:
+ *      data:[<mediatype>][;base64],<data>
+ *
+ * @param file          {File} File object containing file properties
+ */
+FileReader.prototype.readAsDataURL = function(file) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsDataURL(file);
+    }
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            // Save result
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsDataURL", execArgs);
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file          {File} File object containing file properties
+ */
+FileReader.prototype.readAsBinaryString = function(file) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsBinaryString(file);
+    }
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // Error callback
+        function(e) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = null;
+
+            // Save error
+            me._error = new FileError(e);
+
+            // If onerror callback
+            if (typeof me.onerror === "function") {
+                me.onerror(new ProgressEvent("error", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        }, "File", "readAsBinaryString", execArgs);
+};
+
+/**
+ * Read file and return data as a binary data.
+ *
+ * @param file          {File} File object containing file properties
+ */
+FileReader.prototype.readAsArrayBuffer = function(file) {
+    if (initRead(this, file)) {
+        return this._realReader.readAsArrayBuffer(file);
+    }
+
+    var me = this;
+    var execArgs = [this._fileName, file.start, file.end];
+
+    // Read file
+    exec(
+        // Success callback
+        function(r) {
+            // If DONE (cancelled), then don't do anything
+            if (me._readyState === FileReader.DONE) {
+                return;
+            }
+
+            // DONE state
+            me._readyState = FileReader.DONE;
+
+            me._result = r;
+
+            // If onload callback
+            if (typeof me.onload === "function") {
+                me.onload(new ProgressEvent("load", {target:me}));
+            }
+
+            // If onloadend callback
+            if (typeof me.onloadend === "function") {
+                me.onloadend(new ProgressEvent("loadend", {target:me}));
+            }
+        },
+        // E

<TRUNCATED>

[19/22] ripped out plugins

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/ContactManager.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/ContactManager.java b/framework/src/org/apache/cordova/ContactManager.java
deleted file mode 100755
index 8ea64a6..0000000
--- a/framework/src/org/apache/cordova/ContactManager.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
-       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.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import android.util.Log;
-
-public class ContactManager extends CordovaPlugin {
-
-    private ContactAccessor contactAccessor;
-    private static final String LOG_TAG = "Contact Query";
-
-    public static final int UNKNOWN_ERROR = 0;
-    public static final int INVALID_ARGUMENT_ERROR = 1;
-    public static final int TIMEOUT_ERROR = 2;
-    public static final int PENDING_OPERATION_ERROR = 3;
-    public static final int IO_ERROR = 4;
-    public static final int NOT_SUPPORTED_ERROR = 5;
-    public static final int PERMISSION_DENIED_ERROR = 20;
-
-    /**
-     * Constructor.
-     */
-    public ContactManager() {
-    }
-
-    /**
-     * Executes the request and returns PluginResult.
-     *
-     * @param action            The action to execute.
-     * @param args              JSONArray of arguments for the plugin.
-     * @param callbackContext   The callback context used when calling back into JavaScript.
-     * @return                  True if the action was valid, false otherwise.
-     */
-    public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
-        /**
-         * Check to see if we are on an Android 1.X device.  If we are return an error as we
-         * do not support this as of Cordova 1.0.
-         */
-        if (android.os.Build.VERSION.RELEASE.startsWith("1.")) {
-            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, ContactManager.NOT_SUPPORTED_ERROR));
-            return true;
-        }
-
-        /**
-         * Only create the contactAccessor after we check the Android version or the program will crash
-         * older phones.
-         */
-        if (this.contactAccessor == null) {
-            this.contactAccessor = new ContactAccessorSdk5(this.webView, this.cordova);
-        }
-
-        if (action.equals("search")) {
-            final JSONArray filter = args.getJSONArray(0);
-            final JSONObject options = args.getJSONObject(1);
-            this.cordova.getThreadPool().execute(new Runnable() {
-                public void run() {
-                    JSONArray res = contactAccessor.search(filter, options);
-                    callbackContext.success(res);
-                }
-            });
-        }
-        else if (action.equals("save")) {
-            final JSONObject contact = args.getJSONObject(0);
-            this.cordova.getThreadPool().execute(new Runnable() {
-                public void run() {
-                    JSONObject res = null;
-                    String id = contactAccessor.save(contact);
-                    if (id != null) {
-                        try {
-                            res = contactAccessor.getContactById(id);
-                        } catch (JSONException e) {
-                            Log.e(LOG_TAG, "JSON fail.", e);
-                        }
-                    }
-                    if (res != null) {
-                        callbackContext.success(res);
-                    } else {
-                        callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, UNKNOWN_ERROR));
-                    }
-                }
-            });
-        }
-        else if (action.equals("remove")) {
-            final String contactId = args.getString(0);
-            this.cordova.getThreadPool().execute(new Runnable() {
-                public void run() {
-                    if (contactAccessor.remove(contactId)) {
-                        callbackContext.success();
-                    } else {
-                        callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, UNKNOWN_ERROR));
-                    }
-                }
-            });
-        }
-        else {
-            return false;
-        }
-        return true;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/Echo.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/Echo.java b/framework/src/org/apache/cordova/Echo.java
deleted file mode 100644
index aaebe02..0000000
--- a/framework/src/org/apache/cordova/Echo.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-       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.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.json.JSONException;
-
-public class Echo extends CordovaPlugin {
-
-    @Override
-    public boolean execute(String action, CordovaArgs args, final CallbackContext callbackContext) throws JSONException {
-        if ("echo".equals(action)) {
-            final String result = args.isNull(0) ? null : args.getString(0);
-            callbackContext.success(result);
-            return true;
-        } else if ("echoAsync".equals(action)) {
-            final String result = args.isNull(0) ? null : args.getString(0);
-            cordova.getThreadPool().execute(new Runnable() {
-                public void run() {
-                    callbackContext.success(result);
-                }
-            });
-            return true;
-        } else if ("echoArrayBuffer".equals(action)) {
-            final byte[] result = args.getArrayBuffer(0);
-            callbackContext.success(result);
-            return true;
-        }
-        return false;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/FileProgressResult.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileProgressResult.java b/framework/src/org/apache/cordova/FileProgressResult.java
deleted file mode 100644
index d981175..0000000
--- a/framework/src/org/apache/cordova/FileProgressResult.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
-       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.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * Encapsulates in-progress status of uploading or downloading a file to a remote server.
- */
-public class FileProgressResult {
-
-    private boolean lengthComputable = false; // declares whether total is known
-    private long loaded = 0;                  // bytes sent so far
-    private long total = 0;                   // bytes total, if known
-
-    public boolean getLengthComputable() {
-        return lengthComputable;
-    }
-
-    public void setLengthComputable(boolean computable) {
-        this.lengthComputable = computable;
-    }
-
-    public long getLoaded() {
-        return loaded;
-    }
-
-    public void setLoaded(long bytes) {
-        this.loaded = bytes;
-    }
-
-    public long getTotal() {
-        return total;
-    }
-
-    public void setTotal(long bytes) {
-        this.total = bytes;
-    }
-
-    public JSONObject toJSONObject() throws JSONException {
-        return new JSONObject(
-                "{loaded:" + loaded +
-                ",total:" + total +
-                ",lengthComputable:" + (lengthComputable ? "true" : "false") + "}");
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/FileTransfer.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileTransfer.java b/framework/src/org/apache/cordova/FileTransfer.java
deleted file mode 100644
index c87683f..0000000
--- a/framework/src/org/apache/cordova/FileTransfer.java
+++ /dev/null
@@ -1,964 +0,0 @@
-/*
-       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.io.BufferedReader;
-import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.URLDecoder;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.Inflater;
-
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.SSLSocketFactory;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.net.Uri;
-import android.os.Build;
-import android.util.Log;
-import android.webkit.CookieManager;
-
-import com.squareup.okhttp.OkHttpClient;
-
-public class FileTransfer extends CordovaPlugin {
-
-    private static final String LOG_TAG = "FileTransfer";
-    private static final String LINE_START = "--";
-    private static final String LINE_END = "\r\n";
-    private static final String BOUNDARY =  "+++++";
-
-    public static int FILE_NOT_FOUND_ERR = 1;
-    public static int INVALID_URL_ERR = 2;
-    public static int CONNECTION_ERR = 3;
-    public static int ABORTED_ERR = 4;
-
-    private static HashMap<String, RequestContext> activeRequests = new HashMap<String, RequestContext>();
-    private static final int MAX_BUFFER_SIZE = 16 * 1024;
-
-    private static OkHttpClient httpClient = new OkHttpClient();
-
-    private static final class RequestContext {
-        String source;
-        String target;
-        File targetFile;
-        CallbackContext callbackContext;
-        InputStream currentInputStream;
-        OutputStream currentOutputStream;
-        boolean aborted;
-        RequestContext(String source, String target, CallbackContext callbackContext) {
-            this.source = source;
-            this.target = target;
-            this.callbackContext = callbackContext;
-        }
-        void sendPluginResult(PluginResult pluginResult) {
-            synchronized (this) {
-                if (!aborted) {
-                    callbackContext.sendPluginResult(pluginResult);
-                }
-            }
-        }
-    }
-
-    /**
-     * Adds an interface method to an InputStream to return the number of bytes
-     * read from the raw stream. This is used to track total progress against
-     * the HTTP Content-Length header value from the server.
-     */
-    private static abstract class TrackingInputStream extends FilterInputStream {
-    	public TrackingInputStream(final InputStream in) {
-    		super(in);
-    	}
-        public abstract long getTotalRawBytesRead();
-	}
-
-    private static class ExposedGZIPInputStream extends GZIPInputStream {
-	    public ExposedGZIPInputStream(final InputStream in) throws IOException {
-	    	super(in);
-	    }
-	    public Inflater getInflater() {
-	    	return inf;
-	    }
-	}
-
-    /**
-     * Provides raw bytes-read tracking for a GZIP input stream. Reports the
-     * total number of compressed bytes read from the input, rather than the
-     * number of uncompressed bytes.
-     */
-    private static class TrackingGZIPInputStream extends TrackingInputStream {
-    	private ExposedGZIPInputStream gzin;
-	    public TrackingGZIPInputStream(final ExposedGZIPInputStream gzin) throws IOException {
-	    	super(gzin);
-	    	this.gzin = gzin;
-	    }
-	    public long getTotalRawBytesRead() {
-	    	return gzin.getInflater().getBytesRead();
-	    }
-	}
-
-    /**
-     * Provides simple total-bytes-read tracking for an existing InputStream
-     */
-    private static class TrackingHTTPInputStream extends TrackingInputStream {
-        private long bytesRead = 0;
-        public TrackingHTTPInputStream(InputStream stream) {
-            super(stream);
-        }
-
-        private int updateBytesRead(int newBytesRead) {
-        	if (newBytesRead != -1) {
-        		bytesRead += newBytesRead;
-        	}
-        	return newBytesRead;
-        }
-
-        @Override
-        public int read() throws IOException {
-            return updateBytesRead(super.read());
-        }
-
-        @Override
-        public int read(byte[] buffer) throws IOException {
-            return updateBytesRead(super.read(buffer));
-        }
-
-        @Override
-        public int read(byte[] bytes, int offset, int count) throws IOException {
-            return updateBytesRead(super.read(bytes, offset, count));
-        }
-
-        public long getTotalRawBytesRead() {
-        	return bytesRead;
-        }
-    }
-
-    /**
-     * Works around a bug on Android 2.3.
-     * http://code.google.com/p/android/issues/detail?id=14562
-     */
-    private static final class DoneHandlerInputStream extends TrackingHTTPInputStream {
-        private boolean done;
-        
-        public DoneHandlerInputStream(InputStream stream) {
-            super(stream);
-        }
-        
-        @Override
-        public int read() throws IOException {
-            int result = done ? -1 : super.read();
-            done = (result == -1);
-            return result;
-        }
-
-        @Override
-        public int read(byte[] buffer) throws IOException {
-            int result = done ? -1 : super.read(buffer);
-            done = (result == -1);
-            return result;
-        }
-
-        @Override
-        public int read(byte[] bytes, int offset, int count) throws IOException {
-            int result = done ? -1 : super.read(bytes, offset, count);
-            done = (result == -1);
-            return result;
-        }
-    }
-    
-    @Override
-    public boolean execute(String action, JSONArray args, final CallbackContext callbackContext) throws JSONException {
-        if (action.equals("upload") || action.equals("download")) {
-            String source = args.getString(0);
-            String target = args.getString(1);
-
-            if (action.equals("upload")) {
-                try {
-                    source = URLDecoder.decode(source, "UTF-8");
-                    upload(source, target, args, callbackContext);
-                } catch (UnsupportedEncodingException e) {
-                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.MALFORMED_URL_EXCEPTION, "UTF-8 error."));
-                }
-            } else {
-                download(source, target, args, callbackContext);
-            }
-            return true;
-        } else if (action.equals("abort")) {
-            String objectId = args.getString(0);
-            abort(objectId);
-            callbackContext.success();
-            return true;
-        }
-        return false;
-    }
-
-    private static void addHeadersToRequest(URLConnection connection, JSONObject headers) {
-        try {
-            for (Iterator<?> iter = headers.keys(); iter.hasNext(); ) {
-                String headerKey = iter.next().toString();
-                JSONArray headerValues = headers.optJSONArray(headerKey);
-                if (headerValues == null) {
-                    headerValues = new JSONArray();
-                    headerValues.put(headers.getString(headerKey));
-                }
-                connection.setRequestProperty(headerKey, headerValues.getString(0));
-                for (int i = 1; i < headerValues.length(); ++i) {
-                    connection.addRequestProperty(headerKey, headerValues.getString(i));
-                }
-            }
-        } catch (JSONException e1) {
-          // No headers to be manipulated!
-        }
-    }
-
-    /**
-     * Uploads the specified file to the server URL provided using an HTTP multipart request.
-     * @param source        Full path of the file on the file system
-     * @param target        URL of the server to receive the file
-     * @param args          JSON Array of args
-     * @param callbackContext    callback id for optional progress reports
-     *
-     * args[2] fileKey       Name of file request parameter
-     * args[3] fileName      File name to be used on server
-     * args[4] mimeType      Describes file content type
-     * args[5] params        key:value pairs of user-defined parameters
-     * @return FileUploadResult containing result of upload request
-     */
-    private void upload(final String source, final String target, JSONArray args, CallbackContext callbackContext) throws JSONException {
-        Log.d(LOG_TAG, "upload " + source + " to " +  target);
-
-        // Setup the options
-        final String fileKey = getArgument(args, 2, "file");
-        final String fileName = getArgument(args, 3, "image.jpg");
-        final String mimeType = getArgument(args, 4, "image/jpeg");
-        final JSONObject params = args.optJSONObject(5) == null ? new JSONObject() : args.optJSONObject(5);
-        final boolean trustEveryone = args.optBoolean(6);
-        // Always use chunked mode unless set to false as per API
-        final boolean chunkedMode = args.optBoolean(7) || args.isNull(7);
-        // Look for headers on the params map for backwards compatibility with older Cordova versions.
-        final JSONObject headers = args.optJSONObject(8) == null ? params.optJSONObject("headers") : args.optJSONObject(8);
-        final String objectId = args.getString(9);
-        final String httpMethod = getArgument(args, 10, "POST");
-
-        Log.d(LOG_TAG, "fileKey: " + fileKey);
-        Log.d(LOG_TAG, "fileName: " + fileName);
-        Log.d(LOG_TAG, "mimeType: " + mimeType);
-        Log.d(LOG_TAG, "params: " + params);
-        Log.d(LOG_TAG, "trustEveryone: " + trustEveryone);
-        Log.d(LOG_TAG, "chunkedMode: " + chunkedMode);
-        Log.d(LOG_TAG, "headers: " + headers);
-        Log.d(LOG_TAG, "objectId: " + objectId);
-        Log.d(LOG_TAG, "httpMethod: " + httpMethod);
-        
-        final URL url;
-        try {
-            url = new URL(target);
-        } catch (MalformedURLException e) {
-            JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, null, 0);
-            Log.e(LOG_TAG, error.toString(), e);
-            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
-            return;
-        }
-        final boolean useHttps = url.getProtocol().equals("https");
-
-        final RequestContext context = new RequestContext(source, target, callbackContext);
-        synchronized (activeRequests) {
-            activeRequests.put(objectId, context);
-        }
-        
-        cordova.getThreadPool().execute(new Runnable() {
-            public void run() {
-                if (context.aborted) {
-                    return;
-                }
-                HttpURLConnection conn = null;
-                HostnameVerifier oldHostnameVerifier = null;
-                SSLSocketFactory oldSocketFactory = null;
-                int totalBytes = 0;
-                int fixedLength = -1;
-                try {
-                    // Create return object
-                    FileUploadResult result = new FileUploadResult();
-                    FileProgressResult progress = new FileProgressResult();
-
-                    //------------------ CLIENT REQUEST
-                    // Open a HTTP connection to the URL based on protocol
-                    if (useHttps) {
-                        // Using standard HTTPS connection. Will not allow self signed certificate
-                        if (!trustEveryone) {
-                            conn = (HttpsURLConnection) httpClient.open(url);
-                        }
-                        // Use our HTTPS connection that blindly trusts everyone.
-                        // This should only be used in debug environments
-                        else {
-                            // Setup the HTTPS connection class to trust everyone
-                            HttpsURLConnection https = (HttpsURLConnection) httpClient.open(url);
-                            oldSocketFactory  = trustAllHosts(https);
-                            // Save the current hostnameVerifier
-                            oldHostnameVerifier = https.getHostnameVerifier();
-                            // Setup the connection not to verify hostnames
-                            https.setHostnameVerifier(DO_NOT_VERIFY);
-                            conn = https;
-                        }
-                    }
-                    // Return a standard HTTP connection
-                    else {
-                        conn = httpClient.open(url);
-                    }
-
-                    // Allow Inputs
-                    conn.setDoInput(true);
-
-                    // Allow Outputs
-                    conn.setDoOutput(true);
-
-                    // Don't use a cached copy.
-                    conn.setUseCaches(false);
-
-                    // Use a post method.
-                    conn.setRequestMethod(httpMethod);
-                    conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);
-
-                    // Set the cookies on the response
-                    String cookie = CookieManager.getInstance().getCookie(target);
-                    if (cookie != null) {
-                        conn.setRequestProperty("Cookie", cookie);
-                    }
-
-                    // Handle the other headers
-                    if (headers != null) {
-                        addHeadersToRequest(conn, headers);
-                    }
-
-                    /*
-                        * Store the non-file portions of the multipart data as a string, so that we can add it
-                        * to the contentSize, since it is part of the body of the HTTP request.
-                        */
-                    StringBuilder beforeData = new StringBuilder();
-                    try {
-                        for (Iterator<?> iter = params.keys(); iter.hasNext();) {
-                            Object key = iter.next();
-                            if(!String.valueOf(key).equals("headers"))
-                            {
-                              beforeData.append(LINE_START).append(BOUNDARY).append(LINE_END);
-                              beforeData.append("Content-Disposition: form-data; name=\"").append(key.toString()).append('"');
-                              beforeData.append(LINE_END).append(LINE_END);
-                              beforeData.append(params.getString(key.toString()));
-                              beforeData.append(LINE_END);
-                            }
-                        }
-                    } catch (JSONException e) {
-                        Log.e(LOG_TAG, e.getMessage(), e);
-                    }
-
-                    beforeData.append(LINE_START).append(BOUNDARY).append(LINE_END);
-                    beforeData.append("Content-Disposition: form-data; name=\"").append(fileKey).append("\";");
-                    beforeData.append(" filename=\"").append(fileName).append('"').append(LINE_END);
-                    beforeData.append("Content-Type: ").append(mimeType).append(LINE_END).append(LINE_END);
-                    byte[] beforeDataBytes = beforeData.toString().getBytes("UTF-8");
-                    byte[] tailParamsBytes = (LINE_END + LINE_START + BOUNDARY + LINE_START + LINE_END).getBytes("UTF-8");
-
-                    
-                    // Get a input stream of the file on the phone
-                    InputStream sourceInputStream = getPathFromUri(source);
-                    
-                    int stringLength = beforeDataBytes.length + tailParamsBytes.length;
-                    if (sourceInputStream instanceof FileInputStream) {
-                        fixedLength = (int) ((FileInputStream)sourceInputStream).getChannel().size() + stringLength;
-                        progress.setLengthComputable(true);
-                        progress.setTotal(fixedLength);
-                    }
-                    Log.d(LOG_TAG, "Content Length: " + fixedLength);
-                    // setFixedLengthStreamingMode causes and OutOfMemoryException on pre-Froyo devices.
-                    // http://code.google.com/p/android/issues/detail?id=3164
-                    // It also causes OOM if HTTPS is used, even on newer devices.
-                    boolean useChunkedMode = chunkedMode && (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO || useHttps);
-                    useChunkedMode = useChunkedMode || (fixedLength == -1);
-
-                    if (useChunkedMode) {
-                        conn.setChunkedStreamingMode(MAX_BUFFER_SIZE);
-                        // Although setChunkedStreamingMode sets this header, setting it explicitly here works
-                        // around an OutOfMemoryException when using https.
-                        conn.setRequestProperty("Transfer-Encoding", "chunked");
-                    } else {
-                        conn.setFixedLengthStreamingMode(fixedLength);
-                    }
-
-                    conn.connect();
-                    
-                    OutputStream sendStream = null;
-                    try {
-                        sendStream = conn.getOutputStream();
-                        synchronized (context) {
-                            if (context.aborted) {
-                                return;
-                            }
-                            context.currentOutputStream = sendStream;
-                        }
-                        //We don't want to change encoding, we just want this to write for all Unicode.
-                        sendStream.write(beforeDataBytes);
-                        totalBytes += beforeDataBytes.length;
-    
-                        // create a buffer of maximum size
-                        int bytesAvailable = sourceInputStream.available();
-                        int bufferSize = Math.min(bytesAvailable, MAX_BUFFER_SIZE);
-                        byte[] buffer = new byte[bufferSize];
-    
-                        // read file and write it into form...
-                        int bytesRead = sourceInputStream.read(buffer, 0, bufferSize);
-    
-                        long prevBytesRead = 0;
-                        while (bytesRead > 0) {
-                            result.setBytesSent(totalBytes);
-                            sendStream.write(buffer, 0, bytesRead);
-                            totalBytes += bytesRead;
-                            if (totalBytes > prevBytesRead + 102400) {
-                                prevBytesRead = totalBytes;
-                                Log.d(LOG_TAG, "Uploaded " + totalBytes + " of " + fixedLength + " bytes");
-                            }
-                            bytesAvailable = sourceInputStream.available();
-                            bufferSize = Math.min(bytesAvailable, MAX_BUFFER_SIZE);
-                            bytesRead = sourceInputStream.read(buffer, 0, bufferSize);
-
-                            // Send a progress event.
-                            progress.setLoaded(totalBytes);
-                            PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
-                            progressResult.setKeepCallback(true);
-                            context.sendPluginResult(progressResult);
-                        }
-    
-                        // send multipart form data necessary after file data...
-                        sendStream.write(tailParamsBytes);
-                        totalBytes += tailParamsBytes.length;
-                        sendStream.flush();
-                    } finally {
-                        safeClose(sourceInputStream);
-                        safeClose(sendStream);
-                    }
-                    context.currentOutputStream = null;
-                    Log.d(LOG_TAG, "Sent " + totalBytes + " of " + fixedLength);
-
-                    //------------------ read the SERVER RESPONSE
-                    String responseString;
-                    int responseCode = conn.getResponseCode();
-                    Log.d(LOG_TAG, "response code: " + responseCode);
-                    Log.d(LOG_TAG, "response headers: " + conn.getHeaderFields());
-                    TrackingInputStream inStream = null;
-                    try {
-                        inStream = getInputStream(conn);
-                        synchronized (context) {
-                            if (context.aborted) {
-                                return;
-                            }
-                            context.currentInputStream = inStream;
-                        }
-                        
-                        ByteArrayOutputStream out = new ByteArrayOutputStream(Math.max(1024, conn.getContentLength()));
-                        byte[] buffer = new byte[1024];
-                        int bytesRead = 0;
-                        // write bytes to file
-                        while ((bytesRead = inStream.read(buffer)) > 0) {
-                            out.write(buffer, 0, bytesRead);
-                        }
-                        responseString = out.toString("UTF-8");
-                    } finally {
-                        context.currentInputStream = null;
-                        safeClose(inStream);
-                    }
-                    
-                    Log.d(LOG_TAG, "got response from server");
-                    Log.d(LOG_TAG, responseString.substring(0, Math.min(256, responseString.length())));
-                    
-                    // send request and retrieve response
-                    result.setResponseCode(responseCode);
-                    result.setResponse(responseString);
-
-                    context.sendPluginResult(new PluginResult(PluginResult.Status.OK, result.toJSONObject()));
-                } catch (FileNotFoundException e) {
-                    JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR, source, target, conn);
-                    Log.e(LOG_TAG, error.toString(), e);
-                    context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
-                } catch (IOException e) {
-                    JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, conn);
-                    Log.e(LOG_TAG, error.toString(), e);
-                    Log.e(LOG_TAG, "Failed after uploading " + totalBytes + " of " + fixedLength + " bytes.");
-                    context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
-                } catch (JSONException e) {
-                    Log.e(LOG_TAG, e.getMessage(), e);
-                    context.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
-                } catch (Throwable t) {
-                    // Shouldn't happen, but will
-                    JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, conn);
-                    Log.e(LOG_TAG, error.toString(), t);
-                    context.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
-                } finally {
-                    synchronized (activeRequests) {
-                        activeRequests.remove(objectId);
-                    }
-
-                    if (conn != null) {
-                        // Revert back to the proper verifier and socket factories
-                        // Revert back to the proper verifier and socket factories
-                        if (trustEveryone && useHttps) {
-                            HttpsURLConnection https = (HttpsURLConnection) conn;
-                            https.setHostnameVerifier(oldHostnameVerifier);
-                            https.setSSLSocketFactory(oldSocketFactory);
-                        }
-                    }
-                }                
-            }
-        });
-    }
-
-    private static void safeClose(Closeable stream) {
-        if (stream != null) {
-            try {
-                stream.close();
-            } catch (IOException e) {
-            }
-        }
-    }
-
-    private static TrackingInputStream getInputStream(URLConnection conn) throws IOException {
-        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
-            return new DoneHandlerInputStream(conn.getInputStream());
-        }
-        String encoding = conn.getContentEncoding();
-        if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
-        	return new TrackingGZIPInputStream(new ExposedGZIPInputStream(conn.getInputStream()));
-        }
-        return new TrackingHTTPInputStream(conn.getInputStream());
-    }
-
-    // always verify the host - don't check for certificate
-    private static final HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
-        public boolean verify(String hostname, SSLSession session) {
-            return true;
-        }
-    };
-    // Create a trust manager that does not validate certificate chains
-    private static final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
-        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
-            return new java.security.cert.X509Certificate[] {};
-        }
-        
-        public void checkClientTrusted(X509Certificate[] chain,
-                String authType) throws CertificateException {
-        }
-        
-        public void checkServerTrusted(X509Certificate[] chain,
-                String authType) throws CertificateException {
-        }
-    } };
-
-    /**
-     * This function will install a trust manager that will blindly trust all SSL
-     * certificates.  The reason this code is being added is to enable developers
-     * to do development using self signed SSL certificates on their web server.
-     *
-     * The standard HttpsURLConnection class will throw an exception on self
-     * signed certificates if this code is not run.
-     */
-    private static SSLSocketFactory trustAllHosts(HttpsURLConnection connection) {
-        // Install the all-trusting trust manager
-        SSLSocketFactory oldFactory = connection.getSSLSocketFactory();
-        try {
-            // Install our all trusting manager
-            SSLContext sc = SSLContext.getInstance("TLS");
-            sc.init(null, trustAllCerts, new java.security.SecureRandom());
-            SSLSocketFactory newFactory = sc.getSocketFactory();
-            connection.setSSLSocketFactory(newFactory);
-        } catch (Exception e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-        return oldFactory;
-    }
-
-    private static JSONObject createFileTransferError(int errorCode, String source, String target, URLConnection connection) {
-
-        int httpStatus = 0;
-        StringBuilder bodyBuilder = new StringBuilder();
-        String body = null;
-        if (connection != null) {
-            try {
-                if (connection instanceof HttpURLConnection) {
-                    httpStatus = ((HttpURLConnection)connection).getResponseCode();
-                    InputStream err = ((HttpURLConnection) connection).getErrorStream();
-                    if(err != null)
-                    {
-                        BufferedReader reader = new BufferedReader(new InputStreamReader(err, "UTF-8"));
-                        String line = reader.readLine();
-                        while(line != null)
-                        {
-                            bodyBuilder.append(line);
-                            line = reader.readLine();
-                            if(line != null)
-                                bodyBuilder.append('\n');
-                        }
-                        body = bodyBuilder.toString();
-                    }
-                }
-            } catch (IOException e) {
-                Log.w(LOG_TAG, "Error getting HTTP status code from connection.", e);
-            }
-        }
-
-        return createFileTransferError(errorCode, source, target, body, httpStatus);
-    }
-
-        /**
-        * Create an error object based on the passed in errorCode
-        * @param errorCode 	the error
-        * @return JSONObject containing the error
-        */
-    private static JSONObject createFileTransferError(int errorCode, String source, String target, String body, Integer httpStatus) {
-        JSONObject error = null;
-        try {
-            error = new JSONObject();
-            error.put("code", errorCode);
-            error.put("source", source);
-            error.put("target", target);
-            if(body != null)
-            {
-                error.put("body", body);
-            }   
-            if (httpStatus != null) {
-                error.put("http_status", httpStatus);
-            }
-        } catch (JSONException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-        return error;
-    }
-
-    /**
-     * Convenience method to read a parameter from the list of JSON args.
-     * @param args			the args passed to the Plugin
-     * @param position		the position to retrieve the arg from
-     * @param defaultString the default to be used if the arg does not exist
-     * @return String with the retrieved value
-     */
-    private static String getArgument(JSONArray args, int position, String defaultString) {
-        String arg = defaultString;
-        if (args.length() > position) {
-            arg = args.optString(position);
-            if (arg == null || "null".equals(arg)) {
-                arg = defaultString;
-            }
-        }
-        return arg;
-    }
-
-    /**
-     * Downloads a file form a given URL and saves it to the specified directory.
-     *
-     * @param source        URL of the server to receive the file
-     * @param target      	Full path of the file on the file system
-     */
-    private void download(final String source, final String target, JSONArray args, CallbackContext callbackContext) throws JSONException {
-        Log.d(LOG_TAG, "download " + source + " to " +  target);
-
-        final boolean trustEveryone = args.optBoolean(2);
-        final String objectId = args.getString(3);
-        final JSONObject headers = args.optJSONObject(4);
-
-        final URL url;
-        try {
-            url = new URL(source);
-        } catch (MalformedURLException e) {
-            JSONObject error = createFileTransferError(INVALID_URL_ERR, source, target, null, 0);
-            Log.e(LOG_TAG, error.toString(), e);
-            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
-            return;
-        }
-        final boolean useHttps = url.getProtocol().equals("https");
-
-        if (!Config.isUrlWhiteListed(source)) {
-            Log.w(LOG_TAG, "Source URL is not in white list: '" + source + "'");
-            JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, null, 401);
-            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
-            return;
-        }
-
-        
-        final RequestContext context = new RequestContext(source, target, callbackContext);
-        synchronized (activeRequests) {
-            activeRequests.put(objectId, context);
-        }
-        
-        cordova.getThreadPool().execute(new Runnable() {
-            public void run() {
-                if (context.aborted) {
-                    return;
-                }
-                URLConnection connection = null;
-                HostnameVerifier oldHostnameVerifier = null;
-                SSLSocketFactory oldSocketFactory = null;
-                File file = null;
-                PluginResult result = null;
-
-                try {
-                    file = getFileFromPath(target);
-                    context.targetFile = file;
-                    // create needed directories
-                    file.getParentFile().mkdirs();
-        
-                    // connect to server
-                    // Open a HTTP connection to the URL based on protocol
-                    if (useHttps) {
-                        // Using standard HTTPS connection. Will not allow self signed certificate
-                        if (!trustEveryone) {
-                            connection = (HttpsURLConnection) httpClient.open(url);
-                        }
-                        // Use our HTTPS connection that blindly trusts everyone.
-                        // This should only be used in debug environments
-                        else {
-                            // Setup the HTTPS connection class to trust everyone
-                            HttpsURLConnection https = (HttpsURLConnection) httpClient.open(url);
-                            oldSocketFactory = trustAllHosts(https);
-                            // Save the current hostnameVerifier
-                            oldHostnameVerifier = https.getHostnameVerifier();
-                            // Setup the connection not to verify hostnames
-                            https.setHostnameVerifier(DO_NOT_VERIFY);
-                            connection = https;
-                        }
-                    }
-                    // Return a standard HTTP connection
-                    else {
-                          connection = httpClient.open(url);
-
-                    }
-    
-                    if (connection instanceof HttpURLConnection) {
-                        ((HttpURLConnection)connection).setRequestMethod("GET");
-                    }
-    
-                    //Add cookie support
-                    String cookie = CookieManager.getInstance().getCookie(source);
-                    if(cookie != null)
-                    {
-                        connection.setRequestProperty("cookie", cookie);
-                    }
-                    
-                    // This must be explicitly set for gzip progress tracking to work.
-                    connection.setRequestProperty("Accept-Encoding", "gzip");
-
-                    // Handle the other headers
-                    if (headers != null) {
-                        addHeadersToRequest(connection, headers);
-                    }
-    
-                    connection.connect();
-    
-                    Log.d(LOG_TAG, "Download file:" + url);
-
-                    FileProgressResult progress = new FileProgressResult();
-                    if (connection.getContentEncoding() == null || connection.getContentEncoding().equalsIgnoreCase("gzip")) {
-                        // Only trust content-length header if we understand
-                        // the encoding -- identity or gzip
-                        progress.setLengthComputable(true);
-                        progress.setTotal(connection.getContentLength());
-                    }
-                    
-                    FileOutputStream outputStream = null;
-                    TrackingInputStream inputStream = null;
-                    
-                    try {
-                        inputStream = getInputStream(connection);
-                        outputStream = new FileOutputStream(file);
-                        synchronized (context) {
-                            if (context.aborted) {
-                                return;
-                            }
-                            context.currentInputStream = inputStream;
-                        }
-                        
-                        // write bytes to file
-                        byte[] buffer = new byte[MAX_BUFFER_SIZE];
-                        int bytesRead = 0;
-                        while ((bytesRead = inputStream.read(buffer)) > 0) {
-                            outputStream.write(buffer, 0, bytesRead);
-                            // Send a progress event.
-                            progress.setLoaded(inputStream.getTotalRawBytesRead());
-                            PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
-                            progressResult.setKeepCallback(true);
-                            context.sendPluginResult(progressResult);
-                        }
-                    } finally {
-                        context.currentInputStream = null;
-                        safeClose(inputStream);
-                        safeClose(outputStream);
-                    }
-    
-                    Log.d(LOG_TAG, "Saved file: " + target);
-    
-                    // create FileEntry object
-                    JSONObject fileEntry = FileUtils.getEntry(file);
-                    
-                    result = new PluginResult(PluginResult.Status.OK, fileEntry);
-                } catch (FileNotFoundException e) {
-                    JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR, source, target, connection);
-                    Log.e(LOG_TAG, error.toString(), e);
-                    result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
-                } catch (IOException e) {
-                    JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection);
-                    Log.e(LOG_TAG, error.toString(), e);
-                    result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
-                } catch (JSONException e) {
-                    Log.e(LOG_TAG, e.getMessage(), e);
-                    result = new PluginResult(PluginResult.Status.JSON_EXCEPTION);
-                } catch (Throwable e) {
-                    JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection);
-                    Log.e(LOG_TAG, error.toString(), e);
-                    result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
-                } finally {
-                    synchronized (activeRequests) {
-                        activeRequests.remove(objectId);
-                    }
-
-                    if (connection != null) {
-                        // Revert back to the proper verifier and socket factories
-                        if (trustEveryone && useHttps) {
-                            HttpsURLConnection https = (HttpsURLConnection) connection;
-                            https.setHostnameVerifier(oldHostnameVerifier);
-                            https.setSSLSocketFactory(oldSocketFactory);
-                        }
-                    }
-
-                    if (result == null) {
-                        result = new PluginResult(PluginResult.Status.ERROR, createFileTransferError(CONNECTION_ERR, source, target, connection));
-                    }
-                    // Remove incomplete download.
-                    if (result.getStatus() != PluginResult.Status.OK.ordinal() && file != null) {
-                        file.delete();
-                    }
-                    context.sendPluginResult(result);
-                }
-            }
-        });
-    }
-
-    /**
-     * Get an input stream based on file path or content:// uri
-     *
-     * @param path foo
-     * @return an input stream
-     * @throws FileNotFoundException
-     */
-    private InputStream getPathFromUri(String path) throws FileNotFoundException {
-        if (path.startsWith("content:")) {
-            Uri uri = Uri.parse(path);
-            return cordova.getActivity().getContentResolver().openInputStream(uri);
-        }
-        else if (path.startsWith("file://")) {
-            int question = path.indexOf("?");
-            if (question == -1) {
-                return new FileInputStream(path.substring(7));
-            } else {
-                return new FileInputStream(path.substring(7, question));
-            }
-        }
-        else {
-            return new FileInputStream(path);
-        }
-    }
-
-    /**
-     * Get a File object from the passed in path
-     *
-     * @param path file path
-     * @return file object
-     */
-    private File getFileFromPath(String path) throws FileNotFoundException {
-        File file;
-        String prefix = "file://";
-
-        if (path.startsWith(prefix)) {
-            file = new File(path.substring(prefix.length()));
-        } else {
-            file = new File(path);
-        }
-
-        if (file.getParent() == null) {
-            throw new FileNotFoundException();
-        }
-
-        return file;
-    }
-
-    /**
-     * Abort an ongoing upload or download.
-     */
-    private void abort(String objectId) {
-        final RequestContext context;
-        synchronized (activeRequests) {
-            context = activeRequests.remove(objectId);
-        }
-        if (context != null) {
-            File file = context.targetFile;
-            if (file != null) {
-                file.delete();
-            }
-            // Trigger the abort callback immediately to minimize latency between it and abort() being called.
-            JSONObject error = createFileTransferError(ABORTED_ERR, context.source, context.target, null, -1);
-            synchronized (context) {
-                context.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, error));
-                context.aborted = true;
-            }
-            // Closing the streams can block, so execute on a background thread.
-            cordova.getThreadPool().execute(new Runnable() {
-                public void run() {
-                    synchronized (context) {
-                        safeClose(context.currentInputStream);
-                        safeClose(context.currentOutputStream);
-                    }
-                }
-            });
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/FileUploadResult.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileUploadResult.java b/framework/src/org/apache/cordova/FileUploadResult.java
deleted file mode 100644
index b556869..0000000
--- a/framework/src/org/apache/cordova/FileUploadResult.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
-       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.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * Encapsulates the result and/or status of uploading a file to a remote server.
- */
-public class FileUploadResult {
-
-    private long bytesSent = 0;         // bytes sent
-    private int responseCode = -1;      // HTTP response code
-    private String response = null;     // HTTP response
-    private String objectId = null;     // FileTransfer object id
-
-    public long getBytesSent() {
-        return bytesSent;
-    }
-
-    public void setBytesSent(long bytes) {
-        this.bytesSent = bytes;
-    }
-
-    public int getResponseCode() {
-        return responseCode;
-    }
-
-    public void setResponseCode(int responseCode) {
-        this.responseCode = responseCode;
-    }
-
-    public String getResponse() {
-        return response;
-    }
-
-    public void setResponse(String response) {
-        this.response = response;
-    }
-
-    public String getObjectId() {
-        return objectId;
-    }
-
-    public void setObjectId(String objectId) {
-        this.objectId = objectId;
-    }
-
-    public JSONObject toJSONObject() throws JSONException {
-        return new JSONObject(
-                "{bytesSent:" + bytesSent +
-                ",responseCode:" + responseCode +
-                ",response:" + JSONObject.quote(response) +
-                ",objectId:" + JSONObject.quote(objectId) + "}");
-    }
-}


[11/22] android commit: CB-3068: Android menu not appearing as actionoverflow

Posted by st...@apache.org.
CB-3068: Android menu not appearing as actionoverflow


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

Branch: refs/heads/3.0.0
Commit: cb07fe395cdd48e6994e3c2e72a07496cb376d2d
Parents: a001d8c
Author: Simon MacDonald <si...@gmail.com>
Authored: Mon May 13 22:22:59 2013 -0400
Committer: Simon MacDonald <si...@gmail.com>
Committed: Mon May 13 22:22:59 2013 -0400

----------------------------------------------------------------------
 .../src/org/apache/cordova/CordovaWebView.java     |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/cb07fe39/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 5dd061e..c57cd50 100755
--- a/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/framework/src/org/apache/cordova/CordovaWebView.java
@@ -672,8 +672,10 @@ public class CordovaWebView extends WebView {
                 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 true;
         }
         
         return super.onKeyDown(keyCode, event);


[21/22] ripped out plugins

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/CameraLauncher.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CameraLauncher.java b/framework/src/org/apache/cordova/CameraLauncher.java
deleted file mode 100755
index 1974dd7..0000000
--- a/framework/src/org/apache/cordova/CameraLauncher.java
+++ /dev/null
@@ -1,824 +0,0 @@
-/*
-       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.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.DataResource;
-import org.apache.cordova.api.LOG;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-
-import android.app.Activity;
-import android.content.ContentValues;
-import android.content.Intent;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Matrix;
-import android.graphics.Bitmap.CompressFormat;
-import android.media.MediaScannerConnection;
-import android.media.MediaScannerConnection.MediaScannerConnectionClient;
-import android.net.Uri;
-import android.os.Environment;
-import android.provider.MediaStore;
-import android.util.Log;
-
-/**
- * This class launches the camera view, allows the user to take a picture, closes the camera view,
- * and returns the captured image.  When the camera view is closed, the screen displayed before
- * the camera view was shown is redisplayed.
- */
-public class CameraLauncher extends CordovaPlugin implements MediaScannerConnectionClient {
-
-    private static final int DATA_URL = 0;              // Return base64 encoded string
-    private static final int FILE_URI = 1;              // Return file uri (content://media/external/images/media/2 for Android)
-    private static final int NATIVE_URI = 2;			// On Android, this is the same as FILE_URI
-
-    private static final int PHOTOLIBRARY = 0;          // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
-    private static final int CAMERA = 1;                // Take picture from camera
-    private static final int SAVEDPHOTOALBUM = 2;       // Choose image from picture library (same as PHOTOLIBRARY for Android)
-
-    private static final int PICTURE = 0;               // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
-    private static final int VIDEO = 1;                 // allow selection of video only, ONLY RETURNS URL
-    private static final int ALLMEDIA = 2;              // allow selection from all media types
-
-    private static final int JPEG = 0;                  // Take a picture of type JPEG
-    private static final int PNG = 1;                   // Take a picture of type PNG
-    private static final String GET_PICTURE = "Get Picture";
-    private static final String GET_VIDEO = "Get Video";
-    private static final String GET_All = "Get All";
-
-    private static final String LOG_TAG = "CameraLauncher";
-
-    private int mQuality;                   // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
-    private int targetWidth;                // desired width of the image
-    private int targetHeight;               // desired height of the image
-    private Uri imageUri;                   // Uri of captured image
-    private int encodingType;               // Type of encoding to use
-    private int mediaType;                  // What type of media to retrieve
-    private boolean saveToPhotoAlbum;       // Should the picture be saved to the device's photo album
-    private boolean correctOrientation;     // Should the pictures orientation be corrected
-    //private boolean allowEdit;              // Should we allow the user to crop the image. UNUSED.
-
-    public CallbackContext callbackContext;
-    private int numPics;
-
-    private MediaScannerConnection conn;    // Used to update gallery app with newly-written files
-    private Uri scanMe;                     // Uri of image to be added to content store
-
-    //This should never be null!
-    //private CordovaInterface cordova;
-
-    /**
-     * Constructor.
-     */
-    public CameraLauncher() {
-    }
-
-//    public void setContext(CordovaInterface mCtx) {
-//        super.setContext(mCtx);
-//        if (CordovaInterface.class.isInstance(mCtx))
-//            cordova = (CordovaInterface) mCtx;
-//        else
-//            LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
-//    }
-
-    /**
-     * Executes the request and returns PluginResult.
-     *
-     * @param action        	The action to execute.
-     * @param args          	JSONArry of arguments for the plugin.
-     * @param callbackContext   The callback id used when calling back into JavaScript.
-     * @return              	A PluginResult object with a status and message.
-     */
-    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
-        this.callbackContext = callbackContext;
-
-        if (action.equals("takePicture")) {
-            int srcType = CAMERA;
-            int destType = FILE_URI;
-            this.saveToPhotoAlbum = false;
-            this.targetHeight = 0;
-            this.targetWidth = 0;
-            this.encodingType = JPEG;
-            this.mediaType = PICTURE;
-            this.mQuality = 80;
-
-            this.mQuality = args.getInt(0);
-            destType = args.getInt(1);
-            srcType = args.getInt(2);
-            this.targetWidth = args.getInt(3);
-            this.targetHeight = args.getInt(4);
-            this.encodingType = args.getInt(5);
-            this.mediaType = args.getInt(6);
-            //this.allowEdit = args.getBoolean(7); // This field is unused.
-            this.correctOrientation = args.getBoolean(8);
-            this.saveToPhotoAlbum = args.getBoolean(9);
-
-            // If the user specifies a 0 or smaller width/height
-            // make it -1 so later comparisons succeed
-            if (this.targetWidth < 1) {
-                this.targetWidth = -1;
-            }
-            if (this.targetHeight < 1) {
-                this.targetHeight = -1;
-            }
-
-            if (srcType == CAMERA) {
-                this.takePicture(destType, encodingType);
-            }
-            else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
-                this.getImage(srcType, destType);
-            }
-            PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT);
-            r.setKeepCallback(true);
-            callbackContext.sendPluginResult(r);
-            return true;
-        }
-        return false;
-    }
-
-    //--------------------------------------------------------------------------
-    // LOCAL METHODS
-    //--------------------------------------------------------------------------
-
-    /**
-     * Take a picture with the camera.
-     * When an image is captured or the camera view is cancelled, the result is returned
-     * in CordovaActivity.onActivityResult, which forwards the result to this.onActivityResult.
-     *
-     * The image can either be returned as a base64 string or a URI that points to the file.
-     * To display base64 string in an img tag, set the source to:
-     *      img.src="data:image/jpeg;base64,"+result;
-     * or to display URI in an img tag
-     *      img.src=result;
-     *
-     * @param quality           Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
-     * @param returnType        Set the type of image to return.
-     */
-    public void takePicture(int returnType, int encodingType) {
-        // Save the number of images currently on disk for later
-        this.numPics = queryImgDB(whichContentStore()).getCount();
-
-        // Display camera
-        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
-
-        // Specify file so that large image is captured and returned
-        File photo = createCaptureFile(encodingType);
-        intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
-        this.imageUri = Uri.fromFile(photo);
-
-        if (this.cordova != null) {
-            this.cordova.startActivityForResult((CordovaPlugin) this, intent, (CAMERA + 1) * 16 + returnType + 1);
-        }
-//        else
-//            LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
-    }
-
-    /**
-     * Create a file in the applications temporary directory based upon the supplied encoding.
-     *
-     * @param encodingType of the image to be taken
-     * @return a File object pointing to the temporary picture
-     */
-    private File createCaptureFile(int encodingType) {
-        File photo = null;
-        if (encodingType == JPEG) {
-            photo = new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), ".Pic.jpg");
-        } else if (encodingType == PNG) {
-            photo = new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), ".Pic.png");
-        } else {
-            throw new IllegalArgumentException("Invalid Encoding Type: " + encodingType);
-        }
-        return photo;
-    }
-
-    /**
-     * Get image from photo library.
-     *
-     * @param quality           Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality)
-     * @param srcType           The album to get image from.
-     * @param returnType        Set the type of image to return.
-     */
-    // TODO: Images selected from SDCARD don't display correctly, but from CAMERA ALBUM do!
-    public void getImage(int srcType, int returnType) {
-        Intent intent = new Intent();
-        String title = GET_PICTURE;
-        if (this.mediaType == PICTURE) {
-            intent.setType("image/*");
-        }
-        else if (this.mediaType == VIDEO) {
-            intent.setType("video/*");
-            title = GET_VIDEO;
-        }
-        else if (this.mediaType == ALLMEDIA) {
-            // I wanted to make the type 'image/*, video/*' but this does not work on all versions
-            // of android so I had to go with the wildcard search.
-            intent.setType("*/*");
-            title = GET_All;
-        }
-
-        intent.setAction(Intent.ACTION_GET_CONTENT);
-        intent.addCategory(Intent.CATEGORY_OPENABLE);
-        if (this.cordova != null) {
-            this.cordova.startActivityForResult((CordovaPlugin) this, Intent.createChooser(intent,
-                    new String(title)), (srcType + 1) * 16 + returnType + 1);
-        }
-    }
-
-    /**
-     * Called when the camera view exits.
-     *
-     * @param requestCode       The request code originally supplied to startActivityForResult(),
-     *                          allowing you to identify who this result came from.
-     * @param resultCode        The integer result code returned by the child activity through its setResult().
-     * @param intent            An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
-     */
-    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
-
-        // Get src and dest types from request code
-        int srcType = (requestCode / 16) - 1;
-        int destType = (requestCode % 16) - 1;
-        int rotate = 0;
-
-        // If CAMERA
-        if (srcType == CAMERA) {
-            // If image available
-            if (resultCode == Activity.RESULT_OK) {
-                try {
-                    // Create an ExifHelper to save the exif data that is lost during compression
-                    ExifHelper exif = new ExifHelper();
-                    try {
-                        if (this.encodingType == JPEG) {
-                            exif.createInFile(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/.Pic.jpg");
-                            exif.readExifData();
-                            rotate = exif.getOrientation();
-                        }
-                    } catch (IOException e) {
-                        e.printStackTrace();
-                    }
-
-                    Bitmap bitmap = null;
-                    Uri uri = null;
-
-                    // If sending base64 image back
-                    if (destType == DATA_URL) {
-                        bitmap = getScaledBitmap(imageUri.toString());
-                        if (bitmap == null) {
-                            // Try to get the bitmap from intent.
-                            bitmap = (Bitmap)intent.getExtras().get("data");
-                        }
-                        
-                        // Double-check the bitmap.
-                        if (bitmap == null) {
-                            Log.d(LOG_TAG, "I either have a null image path or bitmap");
-                            this.failPicture("Unable to create bitmap!");
-                            return;
-                        }
-
-                        if (rotate != 0 && this.correctOrientation) {
-                            bitmap = getRotatedBitmap(rotate, bitmap, exif);
-                        }
-
-                        this.processPicture(bitmap);
-                        checkForDuplicateImage(DATA_URL);
-                    }
-
-                    // If sending filename back
-                    else if (destType == FILE_URI || destType == NATIVE_URI) {
-                        if (this.saveToPhotoAlbum) {
-                            Uri inputUri = getUriFromMediaStore();
-                            //Just because we have a media URI doesn't mean we have a real file, we need to make it
-                            DataResource dataResource = DataResource.initiateNewDataRequestForUri(inputUri, webView.pluginManager, cordova, "CameraLauncher.CameraExitIntent");
-                            File file = dataResource.getRealFile();
-                            uri = Uri.fromFile(file);
-                        } else {
-                            uri = Uri.fromFile(new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), System.currentTimeMillis() + ".jpg"));
-                        }
-
-                        if (uri == null) {
-                            this.failPicture("Error capturing image - no media storage found.");
-                        }
-
-                        // If all this is true we shouldn't compress the image.
-                        if (this.targetHeight == -1 && this.targetWidth == -1 && this.mQuality == 100 && 
-                                !this.correctOrientation) {
-                            writeUncompressedImage(uri);
-
-                            this.callbackContext.success(uri.toString());
-                        } else {
-                            bitmap = getScaledBitmap(imageUri.toString());
-
-                            if (rotate != 0 && this.correctOrientation) {
-                                bitmap = getRotatedBitmap(rotate, bitmap, exif);
-                            }
-
-                            // Add compressed version of captured image to returned media store Uri
-                            DataResource dataResource = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.CameraExitIntent");
-                            OutputStream os = dataResource.getOutputStream();
-                            bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
-                            os.close();
-
-                            // Restore exif data to file
-                            if (this.encodingType == JPEG) {
-                                String exifPath;
-                                if (this.saveToPhotoAlbum) {
-                                    exifPath = dataResource.getRealFile().getPath();
-                                } else {
-                                    exifPath = uri.getPath();
-                                }
-                                exif.createOutFile(exifPath);
-                                exif.writeExifData();
-                            }
-
-                        }
-                        // Send Uri back to JavaScript for viewing image
-                        this.callbackContext.success(uri.toString());
-                    }
-
-                    this.cleanup(FILE_URI, this.imageUri, uri, bitmap);
-                    bitmap = null;
-
-                } catch (IOException e) {
-                    e.printStackTrace();
-                    this.failPicture("Error capturing image.");
-                }
-            }
-
-            // If cancelled
-            else if (resultCode == Activity.RESULT_CANCELED) {
-                this.failPicture("Camera cancelled.");
-            }
-
-            // If something else
-            else {
-                this.failPicture("Did not complete!");
-            }
-        }
-
-        // If retrieving photo from library
-        else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) {
-            if (resultCode == Activity.RESULT_OK) {
-                Uri uri = intent.getData();
-
-                // If you ask for video or all media type you will automatically get back a file URI
-                // and there will be no attempt to resize any returned data
-                if (this.mediaType != PICTURE) {
-                    this.callbackContext.success(uri.toString());
-                }
-                else {
-                    // This is a special case to just return the path as no scaling,
-                    // rotating, nor compressing needs to be done
-                    if (this.targetHeight == -1 && this.targetWidth == -1 &&
-                            (destType == FILE_URI || destType == NATIVE_URI) && !this.correctOrientation) {
-                        this.callbackContext.success(uri.toString());
-                    } else {
-                        String uriString = uri.toString();
-                        DataResource dataResource = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.CameraExitIntent");
-                        // Get the path to the image. Makes loading so much easier.
-                        String mimeType = dataResource.getMimeType();
-                        // If we don't have a valid image so quit.
-                        if (!("image/jpeg".equalsIgnoreCase(mimeType) || "image/png".equalsIgnoreCase(mimeType))) {
-                        	Log.d(LOG_TAG, "I either have a null image path or bitmap");
-                            this.failPicture("Unable to retrieve path to picture!");
-                            return;
-                        }
-                        Bitmap bitmap = null;
-                        try {
-                            bitmap = getScaledBitmap(uriString);
-                        } catch (IOException e) {
-                            e.printStackTrace();
-                        }
-                        if (bitmap == null) {
-                        	Log.d(LOG_TAG, "I either have a null image path or bitmap");
-                            this.failPicture("Unable to create bitmap!");
-                            return;
-                        }
-
-                        if (this.correctOrientation) {
-                            rotate = getImageOrientation(uri);
-                            if (rotate != 0) {
-                                Matrix matrix = new Matrix();
-                                matrix.setRotate(rotate);
-                                bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
-                            }
-                        }
-
-                        // If sending base64 image back
-                        if (destType == DATA_URL) {
-                            this.processPicture(bitmap);
-                        }
-
-                        // If sending filename back
-                        else if (destType == FILE_URI || destType == NATIVE_URI) {
-                            // Do we need to scale the returned file
-                            if (this.targetHeight > 0 && this.targetWidth > 0) {
-                                try {
-                                    // Create an ExifHelper to save the exif data that is lost during compression
-                                    String resizePath = DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/resize.jpg";
-                                    // Some content: URIs do not map to file paths (e.g. picasa).
-                                    File realFile = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.CameraExitIntent").getRealFile();
-                                    String realPath = realFile != null? realFile.getPath() : null;
-                                    ExifHelper exif = new ExifHelper();
-                                    if (realPath != null && this.encodingType == JPEG) {
-                                        try {
-                                            exif.createInFile(realPath);
-                                            exif.readExifData();
-                                            rotate = exif.getOrientation();
-                                        } catch (IOException e) {
-                                            e.printStackTrace();
-                                        }
-                                    }
-
-                                    OutputStream os = new FileOutputStream(resizePath);
-                                    bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
-                                    os.close();
-
-                                    // Restore exif data to file
-                                    if (realPath != null && this.encodingType == JPEG) {
-                                        exif.createOutFile(resizePath);
-                                        exif.writeExifData();
-                                    }
-
-                                    // The resized image is cached by the app in order to get around this and not have to delete you
-                                    // application cache I'm adding the current system time to the end of the file url.
-                                    this.callbackContext.success("file://" + resizePath + "?" + System.currentTimeMillis());
-                                } catch (Exception e) {
-                                    e.printStackTrace();
-                                    this.failPicture("Error retrieving image.");
-                                }
-                            }
-                            else {
-                                this.callbackContext.success(uri.toString());
-                            }
-                        }
-                        if (bitmap != null) {
-	                        bitmap.recycle();
-	                        bitmap = null;
-                        }
-                        System.gc();
-                    }
-                }
-            }
-            else if (resultCode == Activity.RESULT_CANCELED) {
-                this.failPicture("Selection cancelled.");
-            }
-            else {
-                this.failPicture("Selection did not complete!");
-            }
-        }
-    }
-
-    private int getImageOrientation(Uri uri) {
-        String[] cols = { MediaStore.Images.Media.ORIENTATION };
-        Cursor cursor = cordova.getActivity().getContentResolver().query(uri,
-                cols, null, null, null);
-        int rotate = 0;
-        if (cursor != null) {
-            cursor.moveToPosition(0);
-            rotate = cursor.getInt(0);
-            cursor.close();
-        }
-        return rotate;
-    }
-
-    /**
-     * Figure out if the bitmap should be rotated. For instance if the picture was taken in
-     * portrait mode
-     *
-     * @param rotate
-     * @param bitmap
-     * @return rotated bitmap
-     */
-    private Bitmap getRotatedBitmap(int rotate, Bitmap bitmap, ExifHelper exif) {
-        Matrix matrix = new Matrix();
-        if (rotate == 180) {
-            matrix.setRotate(rotate);
-        } else {
-            matrix.setRotate(rotate, (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2);
-        }
-        bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
-        exif.resetOrientation();
-        return bitmap;
-    }
-
-    /**
-     * In the special case where the default width, height and quality are unchanged
-     * we just write the file out to disk saving the expensive Bitmap.compress function.
-     *
-     * @param uri
-     * @throws FileNotFoundException
-     * @throws IOException
-     */
-    private void writeUncompressedImage(Uri uri) throws FileNotFoundException,
-            IOException {
-        DataResource inputDataResource = DataResource.initiateNewDataRequestForUri(imageUri, webView.pluginManager, cordova, "CameraLauncher.writeUncompressedImage");
-        InputStream fis = inputDataResource.getInputStream();
-        DataResource outDataResource = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.writeUncompressedImage");
-        OutputStream os = outDataResource.getOutputStream();
-        if(fis == null) {
-            throw new FileNotFoundException("Could not get the input file");
-        } else if(os == null) {
-            throw new FileNotFoundException("Could not get the output file");
-        }
-        byte[] buffer = new byte[4096];
-        int len;
-        while ((len = fis.read(buffer)) != -1) {
-            os.write(buffer, 0, len);
-        }
-        os.flush();
-        os.close();
-        fis.close();
-    }
-
-    /**
-     * Create entry in media store for image
-     *
-     * @return uri
-     */
-    private Uri getUriFromMediaStore() {
-        ContentValues values = new ContentValues();
-        values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
-        Uri uri;
-        try {
-            uri = this.cordova.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
-        } catch (UnsupportedOperationException e) {
-            LOG.d(LOG_TAG, "Can't write to external media storage.");
-            try {
-                uri = this.cordova.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
-            } catch (UnsupportedOperationException ex) {
-                LOG.d(LOG_TAG, "Can't write to internal media storage.");
-                return null;
-            }
-        }
-        return uri;
-    }
-
-    /**
-     * Return a scaled bitmap based on the target width and height
-     *
-     * @param imagePath
-     * @return
-     * @throws IOException 
-     */
-    private Bitmap getScaledBitmap(String imageUrl) throws IOException {
-        // If no new width or height were specified return the original bitmap
-        DataResource dataResource = DataResource.initiateNewDataRequestForUri(imageUrl, webView.pluginManager, cordova, "CameraLauncher.getScaledBitmap");
-        if (this.targetWidth <= 0 && this.targetHeight <= 0) {
-            return BitmapFactory.decodeStream(dataResource.getInputStream());
-        }
-
-        // figure out the original width and height of the image
-        BitmapFactory.Options options = new BitmapFactory.Options();
-        options.inJustDecodeBounds = true;
-        BitmapFactory.decodeStream(dataResource.getInputStream(), null, options);
-        
-        //CB-2292: WTF? Why is the width null?
-        if(options.outWidth == 0 || options.outHeight == 0)
-        {
-            return null;
-        }
-        
-        // determine the correct aspect ratio
-        int[] widthHeight = calculateAspectRatio(options.outWidth, options.outHeight);
-
-        // Load in the smallest bitmap possible that is closest to the size we want
-        options.inJustDecodeBounds = false;
-        options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, this.targetWidth, this.targetHeight);
-        Bitmap unscaledBitmap = BitmapFactory.decodeStream(dataResource.getInputStream(), null, options);
-        if (unscaledBitmap == null) {
-            return null;
-        }
-
-        return Bitmap.createScaledBitmap(unscaledBitmap, widthHeight[0], widthHeight[1], true);
-    }
-
-    /**
-     * Maintain the aspect ratio so the resulting image does not look smooshed
-     *
-     * @param origWidth
-     * @param origHeight
-     * @return
-     */
-    public int[] calculateAspectRatio(int origWidth, int origHeight) {
-        int newWidth = this.targetWidth;
-        int newHeight = this.targetHeight;
-
-        // If no new width or height were specified return the original bitmap
-        if (newWidth <= 0 && newHeight <= 0) {
-            newWidth = origWidth;
-            newHeight = origHeight;
-        }
-        // Only the width was specified
-        else if (newWidth > 0 && newHeight <= 0) {
-            newHeight = (newWidth * origHeight) / origWidth;
-        }
-        // only the height was specified
-        else if (newWidth <= 0 && newHeight > 0) {
-            newWidth = (newHeight * origWidth) / origHeight;
-        }
-        // If the user specified both a positive width and height
-        // (potentially different aspect ratio) then the width or height is
-        // scaled so that the image fits while maintaining aspect ratio.
-        // Alternatively, the specified width and height could have been
-        // kept and Bitmap.SCALE_TO_FIT specified when scaling, but this
-        // would result in whitespace in the new image.
-        else {
-            double newRatio = newWidth / (double) newHeight;
-            double origRatio = origWidth / (double) origHeight;
-
-            if (origRatio > newRatio) {
-                newHeight = (newWidth * origHeight) / origWidth;
-            } else if (origRatio < newRatio) {
-                newWidth = (newHeight * origWidth) / origHeight;
-            }
-        }
-
-        int[] retval = new int[2];
-        retval[0] = newWidth;
-        retval[1] = newHeight;
-        return retval;
-    }
-
-    /**
-     * Figure out what ratio we can load our image into memory at while still being bigger than
-     * our desired width and height
-     *
-     * @param srcWidth
-     * @param srcHeight
-     * @param dstWidth
-     * @param dstHeight
-     * @return
-     */
-    public static int calculateSampleSize(int srcWidth, int srcHeight, int dstWidth, int dstHeight) {
-        final float srcAspect = (float)srcWidth / (float)srcHeight;
-        final float dstAspect = (float)dstWidth / (float)dstHeight;
-
-        if (srcAspect > dstAspect) {
-            return srcWidth / dstWidth;
-        } else {
-            return srcHeight / dstHeight;
-        }
-      }
-
-    /**
-     * Creates a cursor that can be used to determine how many images we have.
-     *
-     * @return a cursor
-     */
-    private Cursor queryImgDB(Uri contentStore) {
-        return this.cordova.getActivity().getContentResolver().query(
-                contentStore,
-                new String[] { MediaStore.Images.Media._ID },
-                null,
-                null,
-                null);
-    }
-
-    /**
-     * Cleans up after picture taking. Checking for duplicates and that kind of stuff.
-     * @param newImage
-     */
-    private void cleanup(int imageType, Uri oldImage, Uri newImage, Bitmap bitmap) {
-        if (bitmap != null) {
-            bitmap.recycle();
-        }
-
-        DataResource dataResource = DataResource.initiateNewDataRequestForUri(oldImage, webView.pluginManager, cordova, "CameraLauncher.cleanup");
-        File file = dataResource.getRealFile();
-        if(file != null) {
-            // Clean up initial camera-written image file.
-            file.delete();
-
-            checkForDuplicateImage(imageType);
-            // Scan for the gallery to update pic refs in gallery
-            if (this.saveToPhotoAlbum && newImage != null) {
-                this.scanForGallery(newImage);
-            }
-
-            System.gc();
-        }
-    }
-
-    /**
-     * Used to find out if we are in a situation where the Camera Intent adds to images
-     * to the content store. If we are using a FILE_URI and the number of images in the DB
-     * increases by 2 we have a duplicate, when using a DATA_URL the number is 1.
-     *
-     * @param type FILE_URI or DATA_URL
-     */
-    private void checkForDuplicateImage(int type) {
-        int diff = 1;
-        Uri contentStore = whichContentStore();
-        Cursor cursor = queryImgDB(contentStore);
-        int currentNumOfImages = cursor.getCount();
-
-        if (type == FILE_URI && this.saveToPhotoAlbum) {
-            diff = 2;
-        }
-
-        // delete the duplicate file if the difference is 2 for file URI or 1 for Data URL
-        if ((currentNumOfImages - numPics) == diff) {
-            cursor.moveToLast();
-            int id = Integer.valueOf(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID)));
-            if (diff == 2) {
-                id--;
-            }
-            Uri uri = Uri.parse(contentStore + "/" + id);
-            this.cordova.getActivity().getContentResolver().delete(uri, null, null);
-        }
-    }
-
-    /**
-     * Determine if we are storing the images in internal or external storage
-     * @return Uri
-     */
-    private Uri whichContentStore() {
-        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
-            return android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
-        } else {
-            return android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI;
-        }
-    }
-
-    /**
-     * Compress bitmap using jpeg, convert to Base64 encoded string, and return to JavaScript.
-     *
-     * @param bitmap
-     */
-    public void processPicture(Bitmap bitmap) {
-        ByteArrayOutputStream jpeg_data = new ByteArrayOutputStream();
-        try {
-            if (bitmap.compress(CompressFormat.JPEG, mQuality, jpeg_data)) {
-                byte[] code = jpeg_data.toByteArray();
-                byte[] output = Base64.encodeBase64(code);
-                String js_out = new String(output);
-                this.callbackContext.success(js_out);
-                js_out = null;
-                output = null;
-                code = null;
-            }
-        } catch (Exception e) {
-            this.failPicture("Error compressing image.");
-        }
-        jpeg_data = null;
-    }
-
-    /**
-     * Send error message to JavaScript.
-     *
-     * @param err
-     */
-    public void failPicture(String err) {
-        this.callbackContext.error(err);
-    }
-
-    private void scanForGallery(Uri newImage) {
-        this.scanMe = newImage;
-        if(this.conn != null) {
-            this.conn.disconnect();
-        }
-        this.conn = new MediaScannerConnection(this.cordova.getActivity().getApplicationContext(), this);
-        conn.connect();
-    }
-
-    public void onMediaScannerConnected() {
-        try{
-            this.conn.scanFile(this.scanMe.toString(), "image/*");
-        } catch (java.lang.IllegalStateException e){
-            LOG.e(LOG_TAG, "Can't scan file in MediaScanner after taking picture");
-        }
-
-    }
-
-    public void onScanCompleted(String path, Uri uri) {
-        this.conn.disconnect();
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/Capture.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/Capture.java b/framework/src/org/apache/cordova/Capture.java
deleted file mode 100644
index d7ad419..0000000
--- a/framework/src/org/apache/cordova/Capture.java
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
-       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.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-
-import android.os.Build;
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.DataResource;
-import org.apache.cordova.api.LOG;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.app.Activity;
-import android.content.ContentValues;
-import android.content.Intent;
-import android.database.Cursor;
-import android.graphics.BitmapFactory;
-import android.media.MediaPlayer;
-import android.net.Uri;
-import android.os.Environment;
-import android.provider.MediaStore;
-import android.util.Log;
-
-public class Capture extends CordovaPlugin {
-
-    private static final String VIDEO_3GPP = "video/3gpp";
-    private static final String VIDEO_MP4 = "video/mp4";
-    private static final String AUDIO_3GPP = "audio/3gpp";
-    private static final String IMAGE_JPEG = "image/jpeg";
-
-    private static final int CAPTURE_AUDIO = 0;     // Constant for capture audio
-    private static final int CAPTURE_IMAGE = 1;     // Constant for capture image
-    private static final int CAPTURE_VIDEO = 2;     // Constant for capture video
-    private static final String LOG_TAG = "Capture";
-
-    private static final int CAPTURE_INTERNAL_ERR = 0;
-//    private static final int CAPTURE_APPLICATION_BUSY = 1;
-//    private static final int CAPTURE_INVALID_ARGUMENT = 2;
-    private static final int CAPTURE_NO_MEDIA_FILES = 3;
-
-    private CallbackContext callbackContext;        // The callback context from which we were invoked.
-    private long limit;                             // the number of pics/vids/clips to take
-    private double duration;                        // optional duration parameter for video recording
-    private JSONArray results;                      // The array of results to be returned to the user
-    private int numPics;                            // Number of pictures before capture activity
-
-    //private CordovaInterface cordova;
-
-//    public void setContext(Context mCtx)
-//    {
-//        if (CordovaInterface.class.isInstance(mCtx))
-//            cordova = (CordovaInterface) mCtx;
-//        else
-//            LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity");
-//    }
-
-    @Override
-    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
-        this.callbackContext = callbackContext;
-        this.limit = 1;
-        this.duration = 0.0f;
-        this.results = new JSONArray();
-
-        JSONObject options = args.optJSONObject(0);
-        if (options != null) {
-            limit = options.optLong("limit", 1);
-            duration = options.optDouble("duration", 0.0f);
-        }
-
-        if (action.equals("getFormatData")) {
-            JSONObject obj = getFormatData(args.getString(0), args.getString(1));
-            callbackContext.success(obj);
-            return true;
-        }
-        else if (action.equals("captureAudio")) {
-            this.captureAudio();
-        }
-        else if (action.equals("captureImage")) {
-            this.captureImage();
-        }
-        else if (action.equals("captureVideo")) {
-            this.captureVideo(duration);
-        }
-        else {
-            return false;
-        }
-
-        return true;
-    }
-
-    /**
-     * Provides the media data file data depending on it's mime type
-     *
-     * @param filePath path to the file
-     * @param mimeType of the file
-     * @return a MediaFileData object
-     */
-    private JSONObject getFormatData(String filePath, String mimeType) throws JSONException {
-        JSONObject obj = new JSONObject();
-        // setup defaults
-        obj.put("height", 0);
-        obj.put("width", 0);
-        obj.put("bitrate", 0);
-        obj.put("duration", 0);
-        obj.put("codecs", "");
-
-        // If the mimeType isn't set the rest will fail
-        // so let's see if we can determine it.
-        if (mimeType == null || mimeType.equals("") || "null".equals(mimeType)) {
-            DataResource dataResource = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "Capture.dataResource");
-            mimeType = dataResource.getMimeType();
-        }
-        Log.d(LOG_TAG, "Mime type = " + mimeType);
-
-        if (mimeType.equals(IMAGE_JPEG) || filePath.endsWith(".jpg")) {
-            obj = getImageData(filePath, obj);
-        }
-        else if (mimeType.endsWith(AUDIO_3GPP)) {
-            obj = getAudioVideoData(filePath, obj, false);
-        }
-        else if (mimeType.equals(VIDEO_3GPP) || mimeType.equals(VIDEO_MP4)) {
-            obj = getAudioVideoData(filePath, obj, true);
-        }
-        return obj;
-    }
-
-    /**
-     * Get the Image specific attributes
-     *
-     * @param filePath path to the file
-     * @param obj represents the Media File Data
-     * @return a JSONObject that represents the Media File Data
-     * @throws JSONException
-     */
-    private JSONObject getImageData(String filePath, JSONObject obj) throws JSONException {
-        BitmapFactory.Options options = new BitmapFactory.Options();
-        options.inJustDecodeBounds = true;
-        DataResource dataResource = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "Capture.getImageData");
-        BitmapFactory.decodeFile(dataResource.getRealFile().getPath(), options);
-        obj.put("height", options.outHeight);
-        obj.put("width", options.outWidth);
-        return obj;
-    }
-
-    /**
-     * Get the Image specific attributes
-     *
-     * @param filePath path to the file
-     * @param obj represents the Media File Data
-     * @param video if true get video attributes as well
-     * @return a JSONObject that represents the Media File Data
-     * @throws JSONException
-     */
-    private JSONObject getAudioVideoData(String filePath, JSONObject obj, boolean video) throws JSONException {
-        MediaPlayer player = new MediaPlayer();
-        try {
-            player.setDataSource(filePath);
-            player.prepare();
-            obj.put("duration", player.getDuration() / 1000);
-            if (video) {
-                obj.put("height", player.getVideoHeight());
-                obj.put("width", player.getVideoWidth());
-            }
-        } catch (IOException e) {
-            Log.d(LOG_TAG, "Error: loading video file");
-        }
-        return obj;
-    }
-
-    /**
-     * Sets up an intent to capture audio.  Result handled by onActivityResult()
-     */
-    private void captureAudio() {
-        Intent intent = new Intent(android.provider.MediaStore.Audio.Media.RECORD_SOUND_ACTION);
-
-        this.cordova.startActivityForResult((CordovaPlugin) this, intent, CAPTURE_AUDIO);
-    }
-
-    /**
-     * Sets up an intent to capture images.  Result handled by onActivityResult()
-     */
-    private void captureImage() {
-        // Save the number of images currently on disk for later
-        this.numPics = queryImgDB(whichContentStore()).getCount();
-
-        Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
-
-        // Specify file so that large image is captured and returned
-        File photo = new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), "Capture.jpg");
-        intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
-
-        this.cordova.startActivityForResult((CordovaPlugin) this, intent, CAPTURE_IMAGE);
-    }
-
-    /**
-     * Sets up an intent to capture video.  Result handled by onActivityResult()
-     */
-    private void captureVideo(double duration) {
-        Intent intent = new Intent(android.provider.MediaStore.ACTION_VIDEO_CAPTURE);
-
-        if(Build.VERSION.SDK_INT > 8){
-            intent.putExtra("android.intent.extra.durationLimit", duration);
-        }
-        this.cordova.startActivityForResult((CordovaPlugin) this, intent, CAPTURE_VIDEO);
-    }
-
-    /**
-     * Called when the video view exits.
-     *
-     * @param requestCode       The request code originally supplied to startActivityForResult(),
-     *                          allowing you to identify who this result came from.
-     * @param resultCode        The integer result code returned by the child activity through its setResult().
-     * @param intent            An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
-     * @throws JSONException
-     */
-    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
-
-        // Result received okay
-        if (resultCode == Activity.RESULT_OK) {
-            // An audio clip was requested
-            if (requestCode == CAPTURE_AUDIO) {
-                // Get the uri of the audio clip
-                Uri data = intent.getData();
-                // create a file object from the uri
-                results.put(createMediaFile(data));
-
-                if (results.length() >= limit) {
-                    // Send Uri back to JavaScript for listening to audio
-                    this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, results));
-                } else {
-                    // still need to capture more audio clips
-                    captureAudio();
-                }
-            } else if (requestCode == CAPTURE_IMAGE) {
-                // For some reason if I try to do:
-                // Uri data = intent.getData();
-                // It crashes in the emulator and on my phone with a null pointer exception
-                // To work around it I had to grab the code from CameraLauncher.java
-                try {
-                    // Create entry in media store for image
-                    // (Don't use insertImage() because it uses default compression setting of 50 - no way to change it)
-                    ContentValues values = new ContentValues();
-                    values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, IMAGE_JPEG);
-                    Uri uri = null;
-                    try {
-                        uri = this.cordova.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
-                    } catch (UnsupportedOperationException e) {
-                        LOG.d(LOG_TAG, "Can't write to external media storage.");
-                        try {
-                            uri = this.cordova.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values);
-                        } catch (UnsupportedOperationException ex) {
-                            LOG.d(LOG_TAG, "Can't write to internal media storage.");
-                            this.fail(createErrorObject(CAPTURE_INTERNAL_ERR, "Error capturing image - no media storage found."));
-                            return;
-                        }
-                    }
-                    FileInputStream fis = new FileInputStream(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/Capture.jpg");
-                    OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
-                    byte[] buffer = new byte[4096];
-                    int len;
-                    while ((len = fis.read(buffer)) != -1) {
-                        os.write(buffer, 0, len);
-                    }
-                    os.flush();
-                    os.close();
-                    fis.close();
-
-                    // Add image to results
-                    results.put(createMediaFile(uri));
-
-                    checkForDuplicateImage();
-
-                    if (results.length() >= limit) {
-                        // Send Uri back to JavaScript for viewing image
-                        this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, results));
-                    } else {
-                        // still need to capture more images
-                        captureImage();
-                    }
-                } catch (IOException e) {
-                    e.printStackTrace();
-                    this.fail(createErrorObject(CAPTURE_INTERNAL_ERR, "Error capturing image."));
-                }
-            } else if (requestCode == CAPTURE_VIDEO) {
-                // Get the uri of the video clip
-                Uri data = intent.getData();
-                // create a file object from the uri
-                results.put(createMediaFile(data));
-
-                if (results.length() >= limit) {
-                    // Send Uri back to JavaScript for viewing video
-                    this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, results));
-                } else {
-                    // still need to capture more video clips
-                    captureVideo(duration);
-                }
-            }
-        }
-        // If canceled
-        else if (resultCode == Activity.RESULT_CANCELED) {
-            // If we have partial results send them back to the user
-            if (results.length() > 0) {
-                this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, results));
-            }
-            // user canceled the action
-            else {
-                this.fail(createErrorObject(CAPTURE_NO_MEDIA_FILES, "Canceled."));
-            }
-        }
-        // If something else
-        else {
-            // If we have partial results send them back to the user
-            if (results.length() > 0) {
-                this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, results));
-            }
-            // something bad happened
-            else {
-                this.fail(createErrorObject(CAPTURE_NO_MEDIA_FILES, "Did not complete!"));
-            }
-        }
-    }
-
-    /**
-     * Creates a JSONObject that represents a File from the Uri
-     *
-     * @param data the Uri of the audio/image/video
-     * @return a JSONObject that represents a File
-     * @throws IOException
-     */
-    private JSONObject createMediaFile(Uri data) {
-        DataResource dataResource = DataResource.initiateNewDataRequestForUri(data, webView.pluginManager, cordova, "Capture.createMediaFile");
-        File fp = dataResource.getRealFile();
-        JSONObject obj = new JSONObject();
-
-        try {
-            // File properties
-            obj.put("name", fp.getName());
-            obj.put("fullPath", "file://" + fp.getAbsolutePath());
-            // Because of an issue with MimeTypeMap.getMimeTypeFromExtension() all .3gpp files
-            // are reported as video/3gpp. I'm doing this hacky check of the URI to see if it
-            // is stored in the audio or video content store.
-
-            if (fp.getAbsoluteFile().toString().endsWith(".3gp") || fp.getAbsoluteFile().toString().endsWith(".3gpp")) {
-                if (data.toString().contains("/audio/")) {
-                    obj.put("type", AUDIO_3GPP);
-                } else {
-                    obj.put("type", VIDEO_3GPP);
-                }
-            } else {
-                obj.put("type", dataResource.getMimeType());
-            }
-
-            obj.put("lastModifiedDate", fp.lastModified());
-            obj.put("size", fp.length());
-        } catch (JSONException e) {
-            // this will never happen
-            e.printStackTrace();
-        }
-
-        return obj;
-    }
-
-    private JSONObject createErrorObject(int code, String message) {
-        JSONObject obj = new JSONObject();
-        try {
-            obj.put("code", code);
-            obj.put("message", message);
-        } catch (JSONException e) {
-            // This will never happen
-        }
-        return obj;
-    }
-
-    /**
-     * Send error message to JavaScript.
-     *
-     * @param err
-     */
-    public void fail(JSONObject err) {
-        this.callbackContext.error(err);
-    }
-
-
-    /**
-     * Creates a cursor that can be used to determine how many images we have.
-     *
-     * @return a cursor
-     */
-    private Cursor queryImgDB(Uri contentStore) {
-        return this.cordova.getActivity().getContentResolver().query(
-            contentStore,
-            new String[] { MediaStore.Images.Media._ID },
-            null,
-            null,
-            null);
-    }
-
-    /**
-     * Used to find out if we are in a situation where the Camera Intent adds to images
-     * to the content store.
-     */
-    private void checkForDuplicateImage() {
-        Uri contentStore = whichContentStore();
-        Cursor cursor = queryImgDB(contentStore);
-        int currentNumOfImages = cursor.getCount();
-
-        // delete the duplicate file if the difference is 2
-        if ((currentNumOfImages - numPics) == 2) {
-            cursor.moveToLast();
-            int id = Integer.valueOf(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID))) - 1;
-            Uri uri = Uri.parse(contentStore + "/" + id);
-            this.cordova.getActivity().getContentResolver().delete(uri, null, null);
-        }
-    }
-
-    /**
-     * Determine if we are storing the images in internal or external storage
-     * @return Uri
-     */
-    private Uri whichContentStore() {
-        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
-            return android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
-        } else {
-            return android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/CompassListener.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CompassListener.java b/framework/src/org/apache/cordova/CompassListener.java
deleted file mode 100755
index 401e053..0000000
--- a/framework/src/org/apache/cordova/CompassListener.java
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
-       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.util.List;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaInterface;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-import android.content.Context;
-
-import android.os.Handler;
-import android.os.Looper;
-
-/**
- * This class listens to the compass sensor and stores the latest heading value.
- */
-public class CompassListener extends CordovaPlugin implements SensorEventListener {
-
-    public static int STOPPED = 0;
-    public static int STARTING = 1;
-    public static int RUNNING = 2;
-    public static int ERROR_FAILED_TO_START = 3;
-
-    public long TIMEOUT = 30000;        // Timeout in msec to shut off listener
-
-    int status;                         // status of listener
-    float heading;                      // most recent heading value
-    long timeStamp;                     // time of most recent value
-    long lastAccessTime;                // time the value was last retrieved
-    int accuracy;                       // accuracy of the sensor
-
-    private SensorManager sensorManager;// Sensor manager
-    Sensor mSensor;                     // Compass sensor returned by sensor manager
-
-    private CallbackContext callbackContext;
-
-    /**
-     * Constructor.
-     */
-    public CompassListener() {
-        this.heading = 0;
-        this.timeStamp = 0;
-        this.setStatus(CompassListener.STOPPED);
-    }
-
-    /**
-     * 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.sensorManager = (SensorManager) cordova.getActivity().getSystemService(Context.SENSOR_SERVICE);
-    }
-
-    /**
-     * Executes the request and returns PluginResult.
-     *
-     * @param action                The action to execute.
-     * @param args          	    JSONArry of arguments for the plugin.
-     * @param callbackS=Context     The callback id used when calling back into JavaScript.
-     * @return              	    True if the action was valid.
-     * @throws JSONException 
-     */
-    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
-        if (action.equals("start")) {
-            this.start();
-        }
-        else if (action.equals("stop")) {
-            this.stop();
-        }
-        else if (action.equals("getStatus")) {
-            int i = this.getStatus();
-            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, i));
-        }
-        else if (action.equals("getHeading")) {
-            // If not running, then this is an async call, so don't worry about waiting
-            if (this.status != CompassListener.RUNNING) {
-                int r = this.start();
-                if (r == CompassListener.ERROR_FAILED_TO_START) {
-                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, CompassListener.ERROR_FAILED_TO_START));
-                    return true;
-                }
-                // Set a timeout callback on the main thread.
-                Handler handler = new Handler(Looper.getMainLooper());
-                handler.postDelayed(new Runnable() {
-                    public void run() {
-                        CompassListener.this.timeout();
-                    }
-                }, 2000);
-            }
-            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, getCompassHeading()));
-        }
-        else if (action.equals("setTimeout")) {
-            this.setTimeout(args.getLong(0));
-        }
-        else if (action.equals("getTimeout")) {
-            long l = this.getTimeout();
-            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, l));
-        } else {
-            // Unsupported action
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * Called when listener is to be shut down and object is being destroyed.
-     */
-    public void onDestroy() {
-        this.stop();
-    }
-
-    /**
-     * Called when app has navigated and JS listeners have been destroyed.
-     */
-    public void onReset() {
-        this.stop();
-    }
-
-    //--------------------------------------------------------------------------
-    // LOCAL METHODS
-    //--------------------------------------------------------------------------
-
-    /**
-     * Start listening for compass sensor.
-     *
-     * @return          status of listener
-     */
-    public int start() {
-
-        // If already starting or running, then just return
-        if ((this.status == CompassListener.RUNNING) || (this.status == CompassListener.STARTING)) {
-            return this.status;
-        }
-
-        // Get compass sensor from sensor manager
-        @SuppressWarnings("deprecation")
-        List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ORIENTATION);
-
-        // If found, then register as listener
-        if (list != null && list.size() > 0) {
-            this.mSensor = list.get(0);
-            this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_NORMAL);
-            this.lastAccessTime = System.currentTimeMillis();
-            this.setStatus(CompassListener.STARTING);
-        }
-
-        // If error, then set status to error
-        else {
-            this.setStatus(CompassListener.ERROR_FAILED_TO_START);
-        }
-
-        return this.status;
-    }
-
-    /**
-     * Stop listening to compass sensor.
-     */
-    public void stop() {
-        if (this.status != CompassListener.STOPPED) {
-            this.sensorManager.unregisterListener(this);
-        }
-        this.setStatus(CompassListener.STOPPED);
-    }
-
-    public void onAccuracyChanged(Sensor sensor, int accuracy) {
-        // TODO Auto-generated method stub
-    }
-
-    /**
-     * Called after a delay to time out if the listener has not attached fast enough.
-     */
-    private void timeout() {
-        if (this.status == CompassListener.STARTING) {
-            this.setStatus(CompassListener.ERROR_FAILED_TO_START);
-            if (this.callbackContext != null) {
-                this.callbackContext.error("Compass listener failed to start.");
-            }
-        }
-    }
-
-    /**
-     * Sensor listener event.
-     *
-     * @param SensorEvent event
-     */
-    public void onSensorChanged(SensorEvent event) {
-
-        // We only care about the orientation as far as it refers to Magnetic North
-        float heading = event.values[0];
-
-        // Save heading
-        this.timeStamp = System.currentTimeMillis();
-        this.heading = heading;
-        this.setStatus(CompassListener.RUNNING);
-
-        // If heading hasn't been read for TIMEOUT time, then turn off compass sensor to save power
-        if ((this.timeStamp - this.lastAccessTime) > this.TIMEOUT) {
-            this.stop();
-        }
-    }
-
-    /**
-     * Get status of compass sensor.
-     *
-     * @return          status
-     */
-    public int getStatus() {
-        return this.status;
-    }
-
-    /**
-     * Get the most recent compass heading.
-     *
-     * @return          heading
-     */
-    public float getHeading() {
-        this.lastAccessTime = System.currentTimeMillis();
-        return this.heading;
-    }
-
-    /**
-     * Set the timeout to turn off compass sensor if getHeading() hasn't been called.
-     *
-     * @param timeout       Timeout in msec.
-     */
-    public void setTimeout(long timeout) {
-        this.TIMEOUT = timeout;
-    }
-
-    /**
-     * Get the timeout to turn off compass sensor if getHeading() hasn't been called.
-     *
-     * @return timeout in msec
-     */
-    public long getTimeout() {
-        return this.TIMEOUT;
-    }
-
-    /**
-     * Set the status and send it to JavaScript.
-     * @param status
-     */
-    private void setStatus(int status) {
-        this.status = status;
-    }
-
-    /**
-     * Create the CompassHeading JSON object to be returned to JavaScript
-     *
-     * @return a compass heading
-     */
-    private JSONObject getCompassHeading() throws JSONException {
-        JSONObject obj = new JSONObject();
-
-        obj.put("magneticHeading", this.getHeading());
-        obj.put("trueHeading", this.getHeading());
-        // Since the magnetic and true heading are always the same our and accuracy
-        // is defined as the difference between true and magnetic always return zero
-        obj.put("headingAccuracy", 0);
-        obj.put("timestamp", this.timeStamp);
-
-        return obj;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/ContactAccessor.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/ContactAccessor.java b/framework/src/org/apache/cordova/ContactAccessor.java
deleted file mode 100644
index 04b4342..0000000
--- a/framework/src/org/apache/cordova/ContactAccessor.java
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed 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.util.HashMap;
-
-import android.util.Log;
-import android.webkit.WebView;
-
-import org.apache.cordova.api.CordovaInterface;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-/**
- * This abstract class defines SDK-independent API for communication with
- * Contacts Provider. The actual implementation used by the application depends
- * on the level of API available on the device. If the API level is Cupcake or
- * Donut, we want to use the {@link ContactAccessorSdk3_4} class. If it is
- * Eclair or higher, we want to use {@link ContactAccessorSdk5}.
- */
-public abstract class ContactAccessor {
-
-    protected final String LOG_TAG = "ContactsAccessor";
-    protected CordovaInterface mApp;
-    protected WebView mView;
-
-    /**
-     * Check to see if the data associated with the key is required to
-     * be populated in the Contact object.
-     * @param key
-     * @param map created by running buildPopulationSet.
-     * @return true if the key data is required
-     */
-    protected boolean isRequired(String key, HashMap<String,Boolean> map) {
-        Boolean retVal = map.get(key);
-        return (retVal == null) ? false : retVal.booleanValue();
-    }
-
-    /**
-     * Create a hash map of what data needs to be populated in the Contact object
-     * @param fields the list of fields to populate
-     * @return the hash map of required data
-     */
-    protected HashMap<String,Boolean> buildPopulationSet(JSONArray fields) {
-        HashMap<String,Boolean> map = new HashMap<String,Boolean>();
-
-        String key;
-        try {
-            if (fields.length() == 1 && fields.getString(0).equals("*")) {
-                map.put("displayName", true);
-                map.put("name", true);
-                map.put("nickname", true);
-                map.put("phoneNumbers", true);
-                map.put("emails", true);
-                map.put("addresses", true);
-                map.put("ims", true);
-                map.put("organizations", true);
-                map.put("birthday", true);
-                map.put("note", true);
-                map.put("urls", true);
-                map.put("photos", true);
-                map.put("categories", true);
-           } 
-            else {
-                for (int i=0; i<fields.length(); i++) {
-                    key = fields.getString(i);
-                    if (key.startsWith("displayName")) {
-                        map.put("displayName", true);
-                    }
-                    else if (key.startsWith("name")) {
-                        map.put("displayName", true);
-                        map.put("name", true);
-                    }
-                    else if (key.startsWith("nickname")) {
-                        map.put("nickname", true);
-                    }
-                    else if (key.startsWith("phoneNumbers")) {
-                        map.put("phoneNumbers", true);
-                    }
-                    else if (key.startsWith("emails")) {
-                        map.put("emails", true);
-                    }
-                    else if (key.startsWith("addresses")) {
-                        map.put("addresses", true);
-                    }
-                    else if (key.startsWith("ims")) {
-                        map.put("ims", true);
-                    }
-                    else if (key.startsWith("organizations")) {
-                        map.put("organizations", true);
-                    }
-                    else if (key.startsWith("birthday")) {
-                        map.put("birthday", true);
-                    }
-                    else if (key.startsWith("note")) {
-                        map.put("note", true);
-                    }
-                    else if (key.startsWith("urls")) {
-                        map.put("urls", true);
-                    }
-                    else if (key.startsWith("photos")) {
-                        map.put("photos", true);
-                    }
-                    else if (key.startsWith("categories")) {
-                        map.put("categories", true);
-                    }
-                }
-            }
-       }
-        catch (JSONException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-        return map;
-    }
-
-    /**
-     * Convenience method to get a string from a JSON object.  Saves a
-     * lot of try/catch writing.
-     * If the property is not found in the object null will be returned.
-     *
-     * @param obj contact object to search
-     * @param property to be looked up
-     * @return The value of the property
-     */
-    protected String getJsonString(JSONObject obj, String property) {
-        String value = null;
-        try {
-            if (obj != null) {
-                value = obj.getString(property);
-                if (value.equals("null")) {
-                    Log.d(LOG_TAG, property + " is string called 'null'");
-                    value = null;
-                }
-            }
-       }
-        catch (JSONException e) {
-            Log.d(LOG_TAG, "Could not get = " + e.getMessage());
-        }
-        return value;
-    }
-
-    /**
-     * Handles adding a JSON Contact object into the database.
-     * @return TODO
-     */
-    public abstract String save(JSONObject contact);
-
-    /**
-     * Handles searching through SDK-specific contacts API.
-     */
-    public abstract JSONArray search(JSONArray filter, JSONObject options);
-
-    /**
-     * Handles searching through SDK-specific contacts API.
-     * @throws JSONException
-     */
-    public abstract JSONObject getContactById(String id) throws JSONException;
-
-    /**
-     * Handles removing a contact from the database.
-     */
-    public abstract boolean remove(String id);
-
-   /**
-     * A class that represents the where clause to be used in the database query 
-     */
-    class WhereOptions {
-        private String where;
-        private String[] whereArgs;
-        public void setWhere(String where) {
-            this.where = where;
-        }
-        public String getWhere() {
-            return where;
-        }
-        public void setWhereArgs(String[] whereArgs) {
-            this.whereArgs = whereArgs;
-        }
-        public String[] getWhereArgs() {
-            return whereArgs;
-        }
-    }
-}


[22/22] android commit: ripped out plugins

Posted by st...@apache.org.
ripped out 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/adcbd879
Tree: http://git-wip-us.apache.org/repos/asf/cordova-android/tree/adcbd879
Diff: http://git-wip-us.apache.org/repos/asf/cordova-android/diff/adcbd879

Branch: refs/heads/3.0.0
Commit: adcbd879c846dd3f7a3db960a3c7af14acbbda41
Parents: 227733d
Author: Steven Gill <st...@gmail.com>
Authored: Thu May 16 17:53:11 2013 -0700
Committer: Steven Gill <st...@gmail.com>
Committed: Thu May 16 17:53:11 2013 -0700

----------------------------------------------------------------------
 framework/res/xml/config.xml                       |   55 -
 .../src/org/apache/cordova/AccelListener.java      |  285 --
 framework/src/org/apache/cordova/App.java          |  221 --
 framework/src/org/apache/cordova/AudioHandler.java |  362 ---
 framework/src/org/apache/cordova/AudioPlayer.java  |  553 ----
 .../src/org/apache/cordova/BatteryListener.java    |  163 --
 .../src/org/apache/cordova/CameraLauncher.java     |  824 ------
 framework/src/org/apache/cordova/Capture.java      |  450 ---
 .../src/org/apache/cordova/CompassListener.java    |  295 --
 .../src/org/apache/cordova/ContactAccessor.java    |  198 --
 .../org/apache/cordova/ContactAccessorSdk5.java    | 2174 ---------------
 .../src/org/apache/cordova/ContactManager.java     |  122 -
 framework/src/org/apache/cordova/Echo.java         |   48 -
 .../src/org/apache/cordova/FileProgressResult.java |   63 -
 framework/src/org/apache/cordova/FileTransfer.java |  964 -------
 .../src/org/apache/cordova/FileUploadResult.java   |   73 -
 framework/src/org/apache/cordova/FileUtils.java    | 1024 -------
 framework/src/org/apache/cordova/GPSListener.java  |   50 -
 framework/src/org/apache/cordova/GeoBroker.java    |  206 --
 .../src/org/apache/cordova/Globalization.java      |  577 ----
 .../src/org/apache/cordova/GlobalizationError.java |  108 -
 framework/src/org/apache/cordova/HttpHandler.java  |   86 -
 framework/src/org/apache/cordova/InAppBrowser.java |  813 ------
 .../src/org/apache/cordova/NetworkListener.java    |   32 -
 .../src/org/apache/cordova/NetworkManager.java     |  248 --
 framework/src/org/apache/cordova/Notification.java |  448 ---
 framework/src/org/apache/cordova/SplashScreen.java |   43 -
 framework/src/org/apache/cordova/Storage.java      |  244 --
 28 files changed, 0 insertions(+), 10729 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/res/xml/config.xml
----------------------------------------------------------------------
diff --git a/framework/res/xml/config.xml b/framework/res/xml/config.xml
index 935eda4..6eea8d4 100644
--- a/framework/res/xml/config.xml
+++ b/framework/res/xml/config.xml
@@ -40,64 +40,9 @@
       <preference name="InAppBrowserStorageEnabled" value="true" />
       <preference name="disallowOverscroll" value="true" />
     -->
-
-    <feature name="App">
-      <param name="android-package" value="org.apache.cordova.App"/>
-    </feature>
-    <feature name="Geolocation">
-      <param name="android-package" value="org.apache.cordova.GeoBroker"/>
-    </feature>
     <feature name="Device">
       <param name="android-package" value="org.apache.cordova.Device"/>
     </feature>
-    <feature name="Accelerometer">
-      <param name="android-package" value="org.apache.cordova.AccelListener"/>
-    </feature>
-    <feature name="Compass">
-      <param name="android-package" value="org.apache.cordova.CompassListener"/>
-    </feature>
-    <feature name="Media">
-      <param name="android-package" value="org.apache.cordova.AudioHandler"/>
-    </feature>
-    <feature name="Camera">
-      <param name="android-package" value="org.apache.cordova.CameraLauncher"/>
-    </feature>
-    <feature name="Contacts">
-      <param name="android-package" value="org.apache.cordova.ContactManager"/>
-    </feature>
-    <feature name="File">
-      <param name="android-package" value="org.apache.cordova.FileUtils"/>
-    </feature>
-    <feature name="NetworkStatus">
-      <param name="android-package" value="org.apache.cordova.NetworkManager"/>
-    </feature>
-    <feature name="Notification">
-      <param name="android-package" value="org.apache.cordova.Notification"/>
-    </feature>
-    <feature name="Storage">
-      <param name="android-package" value="org.apache.cordova.Storage"/>
-    </feature>
-    <feature name="FileTransfer">
-      <param name="android-package" value="org.apache.cordova.FileTransfer"/>
-    </feature>
-    <feature name="Capture">
-      <param name="android-package" value="org.apache.cordova.Capture"/>
-    </feature>
-    <feature name="Battery">
-      <param name="android-package" value="org.apache.cordova.BatteryListener"/>
-    </feature>
-    <feature name="SplashScreen">
-      <param name="android-package" value="org.apache.cordova.SplashScreen"/>
-    </feature>
-    <feature name="Echo">
-      <param name="android-package" value="org.apache.cordova.Echo"/>
-    </feature>
-    <feature name="Globalization">
-      <param name="android-package" value="org.apache.cordova.Globalization"/>
-    </feature>
-    <feature name="InAppBrowser">
-      <param name="android-package" value="org.apache.cordova.InAppBrowser"/>
-    </feature>
     <!-- Deprecated plugins element. Remove in 3.0 -->
     <plugins>
     </plugins>

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/AccelListener.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/AccelListener.java b/framework/src/org/apache/cordova/AccelListener.java
deleted file mode 100755
index 934a8a8..0000000
--- a/framework/src/org/apache/cordova/AccelListener.java
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
-       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.util.List;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaInterface;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.content.Context;
-import android.hardware.Sensor;
-import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener;
-import android.hardware.SensorManager;
-
-import android.os.Handler;
-import android.os.Looper;
-
-/**
- * This class listens to the accelerometer sensor and stores the latest
- * acceleration values x,y,z.
- */
-public class AccelListener extends CordovaPlugin implements SensorEventListener {
-
-    public static int STOPPED = 0;
-    public static int STARTING = 1;
-    public static int RUNNING = 2;
-    public static int ERROR_FAILED_TO_START = 3;
-   
-    private float x,y,z;                                // most recent acceleration values
-    private long timestamp;                         // time of most recent value
-    private int status;                                 // status of listener
-    private int accuracy = SensorManager.SENSOR_STATUS_UNRELIABLE;
-
-    private SensorManager sensorManager;    // Sensor manager
-    private Sensor mSensor;                           // Acceleration sensor returned by sensor manager
-
-    private CallbackContext callbackContext;              // Keeps track of the JS callback context.
-
-    /**
-     * Create an accelerometer listener.
-     */
-    public AccelListener() {
-        this.x = 0;
-        this.y = 0;
-        this.z = 0;
-        this.timestamp = 0;
-        this.setStatus(AccelListener.STOPPED);
-     }
-
-    /**
-     * 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 associated CordovaWebView.
-     */
-    @Override
-    public void initialize(CordovaInterface cordova, CordovaWebView webView) {
-        super.initialize(cordova, webView);
-        this.sensorManager = (SensorManager) cordova.getActivity().getSystemService(Context.SENSOR_SERVICE);
-    }
-
-    /**
-     * Executes the request.
-     *
-     * @param action        The action to execute.
-     * @param args          The exec() arguments.
-     * @param callbackId    The callback id used when calling back into JavaScript.
-     * @return              Whether the action was valid.
-     */
-    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
-        if (action.equals("start")) {
-            this.callbackContext = callbackContext;
-            if (this.status != AccelListener.RUNNING) {
-                // If not running, then this is an async call, so don't worry about waiting
-                // We drop the callback onto our stack, call start, and let start and the sensor callback fire off the callback down the road
-                this.start();
-            }
-        }
-        else if (action.equals("stop")) {
-            if (this.status == AccelListener.RUNNING) {
-                this.stop();
-            }
-        } else {
-          // Unsupported action
-            return false;
-        }
-
-        PluginResult result = new PluginResult(PluginResult.Status.NO_RESULT, "");
-        result.setKeepCallback(true);
-        callbackContext.sendPluginResult(result);
-        return true;
-    }
-
-    /**
-     * Called by AccelBroker when listener is to be shut down.
-     * Stop listener.
-     */
-    public void onDestroy() {
-        this.stop();
-    }
-
-    //--------------------------------------------------------------------------
-    // LOCAL METHODS
-    //--------------------------------------------------------------------------
-    //
-    /**
-     * Start listening for acceleration sensor.
-     * 
-     * @return          status of listener
-    */
-    private int start() {
-        // If already starting or running, then just return
-        if ((this.status == AccelListener.RUNNING) || (this.status == AccelListener.STARTING)) {
-            return this.status;
-        }
-
-        this.setStatus(AccelListener.STARTING);
-
-        // Get accelerometer from sensor manager
-        List<Sensor> list = this.sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
-
-        // If found, then register as listener
-        if ((list != null) && (list.size() > 0)) {
-          this.mSensor = list.get(0);
-          this.sensorManager.registerListener(this, this.mSensor, SensorManager.SENSOR_DELAY_UI);
-          this.setStatus(AccelListener.STARTING);
-        } else {
-          this.setStatus(AccelListener.ERROR_FAILED_TO_START);
-          this.fail(AccelListener.ERROR_FAILED_TO_START, "No sensors found to register accelerometer listening to.");
-          return this.status;
-        }
-
-        // Set a timeout callback on the main thread.
-        Handler handler = new Handler(Looper.getMainLooper());
-        handler.postDelayed(new Runnable() {
-            public void run() {
-                AccelListener.this.timeout();
-            }
-        }, 2000);
-
-        return this.status;
-    }
-
-    /**
-     * Stop listening to acceleration sensor.
-     */
-    private void stop() {
-        if (this.status != AccelListener.STOPPED) {
-            this.sensorManager.unregisterListener(this);
-        }
-        this.setStatus(AccelListener.STOPPED);
-        this.accuracy = SensorManager.SENSOR_STATUS_UNRELIABLE;
-    }
-
-    /**
-     * Returns an error if the sensor hasn't started.
-     *
-     * Called two seconds after starting the listener.
-     */
-    private void timeout() {
-        if (this.status == AccelListener.STARTING) {
-            this.setStatus(AccelListener.ERROR_FAILED_TO_START);
-            this.fail(AccelListener.ERROR_FAILED_TO_START, "Accelerometer could not be started.");
-        }
-    }
-
-    /**
-     * Called when the accuracy of the sensor has changed.
-     *
-     * @param sensor
-     * @param accuracy
-     */
-    public void onAccuracyChanged(Sensor sensor, int accuracy) {
-        // Only look at accelerometer events
-        if (sensor.getType() != Sensor.TYPE_ACCELEROMETER) {
-            return;
-        }
-
-        // If not running, then just return
-        if (this.status == AccelListener.STOPPED) {
-            return;
-        }
-        this.accuracy = accuracy;
-    }
-
-    /**
-     * Sensor listener event.
-     *
-     * @param SensorEvent event
-     */
-    public void onSensorChanged(SensorEvent event) {
-        // Only look at accelerometer events
-        if (event.sensor.getType() != Sensor.TYPE_ACCELEROMETER) {
-            return;
-        }
-
-        // If not running, then just return
-        if (this.status == AccelListener.STOPPED) {
-            return;
-        }
-        this.setStatus(AccelListener.RUNNING);
-
-        if (this.accuracy >= SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM) {
-
-            // Save time that event was received
-            this.timestamp = System.currentTimeMillis();
-            this.x = event.values[0];
-            this.y = event.values[1];
-            this.z = event.values[2];
-
-            this.win();
-        }
-    }
-
-    /**
-     * Called when the view navigates.
-     */
-    @Override
-    public void onReset() {
-        if (this.status == AccelListener.RUNNING) {
-            this.stop();
-        }
-    }
-
-    // Sends an error back to JS
-    private void fail(int code, String message) {
-        // Error object
-        JSONObject errorObj = new JSONObject();
-        try {
-            errorObj.put("code", code);
-            errorObj.put("message", message);
-        } catch (JSONException e) {
-            e.printStackTrace();
-        }
-        PluginResult err = new PluginResult(PluginResult.Status.ERROR, errorObj);
-        err.setKeepCallback(true);
-        callbackContext.sendPluginResult(err);
-    }
-
-    private void win() {
-        // Success return object
-        PluginResult result = new PluginResult(PluginResult.Status.OK, this.getAccelerationJSON());
-        result.setKeepCallback(true);
-        callbackContext.sendPluginResult(result);
-    }
-
-    private void setStatus(int status) {
-        this.status = status;
-    }
-    private JSONObject getAccelerationJSON() {
-        JSONObject r = new JSONObject();
-        try {
-            r.put("x", this.x);
-            r.put("y", this.y);
-            r.put("z", this.z);
-            r.put("timestamp", this.timestamp);
-        } catch (JSONException e) {
-            e.printStackTrace();
-        }
-        return r;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/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
deleted file mode 100755
index afdbf3f..0000000
--- a/framework/src/org/apache/cordova/App.java
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
-       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.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.LOG;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.HashMap;
-
-/**
- * This class exposes methods in DroidGap that can be called from JavaScript.
- */
-public class App extends CordovaPlugin {
-
-    /**
-     * 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() {
-        this.webView.clearCache(true);
-    }
-
-    /**
-     * Load the url into the webview.
-     *
-     * @param url
-     * @param props			Properties that can be passed in to the DroidGap 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() {
-        this.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 Behaviour will be overridden.  The backbutton event will be fired!");
-        webView.bindButton(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("DroidGap", "WARNING: Volume Button Default Behaviour will be overridden.  The volume event will be fired!");
-        webView.bindButton(button, override);
-    }
-
-    /**
-     * Return whether the Android back button is overridden by the user.
-     *
-     * @return boolean
-     */
-    public boolean isBackbuttonOverridden() {
-        return webView.isBackButtonBound();
-    }
-
-    /**
-     * Exit the Android application.
-     */
-    public void exitApp() {
-        this.webView.postMessage("exit", null);
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/AudioHandler.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/AudioHandler.java b/framework/src/org/apache/cordova/AudioHandler.java
deleted file mode 100644
index 20c3c4e..0000000
--- a/framework/src/org/apache/cordova/AudioHandler.java
+++ /dev/null
@@ -1,362 +0,0 @@
-/*
-       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.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.DataResource;
-import android.content.Context;
-import android.media.AudioManager;
-
-import java.util.ArrayList;
-
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import java.util.HashMap;
-
-/**
- * This class called by CordovaActivity to play and record audio.
- * The file can be local or over a network using http.
- *
- * Audio formats supported (tested):
- * 	.mp3, .wav
- *
- * Local audio files must reside in one of two places:
- * 		android_asset: 		file name must start with /android_asset/sound.mp3
- * 		sdcard:				file name is just sound.mp3
- */
-public class AudioHandler extends CordovaPlugin {
-
-    public static String TAG = "AudioHandler";
-    HashMap<String, AudioPlayer> players;	// Audio player object
-    ArrayList<AudioPlayer> pausedForPhone;     // Audio players that were paused when phone call came in
-
-    /**
-     * Constructor.
-     */
-    public AudioHandler() {
-        this.players = new HashMap<String, AudioPlayer>();
-        this.pausedForPhone = new ArrayList<AudioPlayer>();
-    }
-
-    public String getFilePath(String url, String source){
-        DataResource dataResource = DataResource.initiateNewDataRequestForUri(url, this.webView.pluginManager, cordova, source);
-        return dataResource.getRealFile().getPath();
-    }
-
-    /**
-     * 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 used when calling back into JavaScript.
-     * @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 = "";
-
-        if (action.equals("startRecordingAudio")) {
-            this.startRecordingAudio(args.getString(0), getFilePath(args.getString(1), "AudioHandler.startRecordingAudio"));
-        }
-        else if (action.equals("stopRecordingAudio")) {
-            this.stopRecordingAudio(args.getString(0));
-        }
-        else if (action.equals("startPlayingAudio")) {
-            this.startPlayingAudio(args.getString(0), getFilePath(args.getString(1), "AudioHandler.startPlayingAudio"));
-        }
-        else if (action.equals("seekToAudio")) {
-            this.seekToAudio(args.getString(0), args.getInt(1));
-        }
-        else if (action.equals("pausePlayingAudio")) {
-            this.pausePlayingAudio(args.getString(0));
-        }
-        else if (action.equals("stopPlayingAudio")) {
-            this.stopPlayingAudio(args.getString(0));
-        } else if (action.equals("setVolume")) {
-           try {
-               this.setVolume(args.getString(0), Float.parseFloat(args.getString(1)));
-           } catch (NumberFormatException nfe) {
-               //no-op
-           }
-        } else if (action.equals("getCurrentPositionAudio")) {
-            float f = this.getCurrentPositionAudio(args.getString(0));
-            callbackContext.sendPluginResult(new PluginResult(status, f));
-            return true;
-        }
-        else if (action.equals("getDurationAudio")) {
-            float f = this.getDurationAudio(args.getString(0), args.getString(1));
-            callbackContext.sendPluginResult(new PluginResult(status, f));
-            return true;
-        }
-        else if (action.equals("create")) {
-            String id = args.getString(0);
-            String src = getFilePath(args.getString(1), "AudioHandler.create");
-            AudioPlayer audio = new AudioPlayer(this, id, src);
-            this.players.put(id, audio);
-        }
-        else if (action.equals("release")) {
-            boolean b = this.release(args.getString(0));
-            callbackContext.sendPluginResult(new PluginResult(status, b));
-            return true;
-        }
-        else { // Unrecognized action.
-            return false;
-        }
-
-        callbackContext.sendPluginResult(new PluginResult(status, result));
-
-        return true;
-    }
-
-    /**
-     * Stop all audio players and recorders.
-     */
-    public void onDestroy() {
-        for (AudioPlayer audio : this.players.values()) {
-            audio.destroy();
-        }
-        this.players.clear();
-    }
-
-    /**
-     * Stop all audio players and recorders on navigate.
-     */
-    @Override
-    public void onReset() {
-        onDestroy();
-    }
-
-    /**
-     * Called when a message is sent to plugin.
-     *
-     * @param id            The message id
-     * @param data          The message data
-     * @return              Object to stop propagation or null
-     */
-    public Object onMessage(String id, Object data) {
-
-        // If phone message
-        if (id.equals("telephone")) {
-
-            // If phone ringing, then pause playing
-            if ("ringing".equals(data) || "offhook".equals(data)) {
-
-                // Get all audio players and pause them
-                for (AudioPlayer audio : this.players.values()) {
-                    if (audio.getState() == AudioPlayer.STATE.MEDIA_RUNNING.ordinal()) {
-                        this.pausedForPhone.add(audio);
-                        audio.pausePlaying();
-                    }
-                }
-
-            }
-
-            // If phone idle, then resume playing those players we paused
-            else if ("idle".equals(data)) {
-                for (AudioPlayer audio : this.pausedForPhone) {
-                    audio.startPlaying(null);
-                }
-                this.pausedForPhone.clear();
-            }
-        }
-        return null;
-    }
-
-    //--------------------------------------------------------------------------
-    // LOCAL METHODS
-    //--------------------------------------------------------------------------
-
-    /**
-     * Release the audio player instance to save memory.
-     * @param id				The id of the audio player
-     */
-    private boolean release(String id) {
-        if (!this.players.containsKey(id)) {
-            return false;
-        }
-        AudioPlayer audio = this.players.get(id);
-        this.players.remove(id);
-        audio.destroy();
-        return true;
-    }
-
-    /**
-     * Start recording and save the specified file.
-     * @param id				The id of the audio player
-     * @param file				The name of the file
-     */
-    public void startRecordingAudio(String id, String file) {
-        AudioPlayer audio = this.players.get(id);
-        if ( audio == null) {
-            audio = new AudioPlayer(this, id, file);
-            this.players.put(id, audio);
-        }
-        audio.startRecording(file);
-    }
-
-    /**
-     * Stop recording and save to the file specified when recording started.
-     * @param id				The id of the audio player
-     */
-    public void stopRecordingAudio(String id) {
-        AudioPlayer audio = this.players.get(id);
-        if (audio != null) {
-            audio.stopRecording();
-        }
-    }
-
-    /**
-     * Start or resume playing audio file.
-     * @param id				The id of the audio player
-     * @param file				The name of the audio file.
-     */
-    public void startPlayingAudio(String id, String file) {
-        AudioPlayer audio = this.players.get(id);
-        if (audio == null) {
-            audio = new AudioPlayer(this, id, file);
-            this.players.put(id, audio);
-        }
-        audio.startPlaying(file);
-    }
-
-    /**
-     * Seek to a location.
-     * @param id				The id of the audio player
-     * @param milliseconds		int: number of milliseconds to skip 1000 = 1 second
-     */
-    public void seekToAudio(String id, int milliseconds) {
-        AudioPlayer audio = this.players.get(id);
-        if (audio != null) {
-            audio.seekToPlaying(milliseconds);
-        }
-    }
-
-    /**
-     * Pause playing.
-     * @param id				The id of the audio player
-     */
-    public void pausePlayingAudio(String id) {
-        AudioPlayer audio = this.players.get(id);
-        if (audio != null) {
-            audio.pausePlaying();
-        }
-    }
-
-    /**
-     * Stop playing the audio file.
-     * @param id				The id of the audio player
-     */
-    public void stopPlayingAudio(String id) {
-        AudioPlayer audio = this.players.get(id);
-        if (audio != null) {
-            audio.stopPlaying();
-            //audio.destroy();
-            //this.players.remove(id);
-        }
-    }
-
-    /**
-     * Get current position of playback.
-     * @param id				The id of the audio player
-     * @return 					position in msec
-     */
-    public float getCurrentPositionAudio(String id) {
-        AudioPlayer audio = this.players.get(id);
-        if (audio != null) {
-            return (audio.getCurrentPosition() / 1000.0f);
-        }
-        return -1;
-    }
-
-    /**
-     * Get the duration of the audio file.
-     * @param id				The id of the audio player
-     * @param file				The name of the audio file.
-     * @return					The duration in msec.
-     */
-    public float getDurationAudio(String id, String file) {
-
-        // Get audio file
-        AudioPlayer audio = this.players.get(id);
-        if (audio != null) {
-            return (audio.getDuration(file));
-        }
-
-        // If not already open, then open the file
-        else {
-            audio = new AudioPlayer(this, id, file);
-            this.players.put(id, audio);
-            return (audio.getDuration(file));
-        }
-    }
-
-    /**
-     * Set the audio device to be used for playback.
-     *
-     * @param output			1=earpiece, 2=speaker
-     */
-    @SuppressWarnings("deprecation")
-    public void setAudioOutputDevice(int output) {
-        AudioManager audiMgr = (AudioManager) this.cordova.getActivity().getSystemService(Context.AUDIO_SERVICE);
-        if (output == 2) {
-            audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_SPEAKER, AudioManager.ROUTE_ALL);
-        }
-        else if (output == 1) {
-            audiMgr.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_EARPIECE, AudioManager.ROUTE_ALL);
-        }
-        else {
-            System.out.println("AudioHandler.setAudioOutputDevice() Error: Unknown output device.");
-        }
-    }
-
-    /**
-     * Get the audio device to be used for playback.
-     *
-     * @return					1=earpiece, 2=speaker
-     */
-    @SuppressWarnings("deprecation")
-    public int getAudioOutputDevice() {
-        AudioManager audiMgr = (AudioManager) this.cordova.getActivity().getSystemService(Context.AUDIO_SERVICE);
-        if (audiMgr.getRouting(AudioManager.MODE_NORMAL) == AudioManager.ROUTE_EARPIECE) {
-            return 1;
-        }
-        else if (audiMgr.getRouting(AudioManager.MODE_NORMAL) == AudioManager.ROUTE_SPEAKER) {
-            return 2;
-        }
-        else {
-            return -1;
-        }
-    }
-
-    /**
-     * Set the volume for an audio device
-     *
-     * @param id				The id of the audio player
-     * @param volume            Volume to adjust to 0.0f - 1.0f
-     */
-    public void setVolume(String id, float volume) {
-        AudioPlayer audio = this.players.get(id);
-        if (audio != null) {
-            audio.setVolume(volume);
-        } else {
-            System.out.println("AudioHandler.setVolume() Error: Unknown Audio Player " + id);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/AudioPlayer.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/AudioPlayer.java b/framework/src/org/apache/cordova/AudioPlayer.java
deleted file mode 100644
index 0170728..0000000
--- a/framework/src/org/apache/cordova/AudioPlayer.java
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
-       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 android.media.AudioManager;
-import android.media.MediaPlayer;
-import android.media.MediaPlayer.OnCompletionListener;
-import android.media.MediaPlayer.OnErrorListener;
-import android.media.MediaPlayer.OnPreparedListener;
-import android.media.MediaRecorder;
-import android.os.Environment;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-
-/**
- * This class implements the audio playback and recording capabilities used by Cordova.
- * It is called by the AudioHandler Cordova class.
- * Only one file can be played or recorded per class instance.
- *
- * Local audio files must reside in one of two places:
- *      android_asset:      file name must start with /android_asset/sound.mp3
- *      sdcard:             file name is just sound.mp3
- */
-public class AudioPlayer implements OnCompletionListener, OnPreparedListener, OnErrorListener {
-
-    // AudioPlayer modes
-    public enum MODE { NONE, PLAY, RECORD };
-
-    // AudioPlayer states
-    public enum STATE { MEDIA_NONE,
-                        MEDIA_STARTING,
-                        MEDIA_RUNNING,
-                        MEDIA_PAUSED,
-                        MEDIA_STOPPED,
-                        MEDIA_LOADING
-                      };
-
-    private static final String LOG_TAG = "AudioPlayer";
-
-    // AudioPlayer message ids
-    private static int MEDIA_STATE = 1;
-    private static int MEDIA_DURATION = 2;
-    private static int MEDIA_POSITION = 3;
-    private static int MEDIA_ERROR = 9;
-
-    // Media error codes
-    private static int MEDIA_ERR_NONE_ACTIVE    = 0;
-    private static int MEDIA_ERR_ABORTED        = 1;
-    private static int MEDIA_ERR_NETWORK        = 2;
-    private static int MEDIA_ERR_DECODE         = 3;
-    private static int MEDIA_ERR_NONE_SUPPORTED = 4;
-
-    private AudioHandler handler;           // The AudioHandler object
-    private String id;                      // The id of this player (used to identify Media object in JavaScript)
-    private MODE mode = MODE.NONE;          // Playback or Recording mode
-    private STATE state = STATE.MEDIA_NONE; // State of recording or playback
-
-    private String audioFile = null;        // File name to play or record to
-    private float duration = -1;            // Duration of audio
-
-    private MediaRecorder recorder = null;  // Audio recording object
-    private String tempFile = null;         // Temporary recording file name
-
-    private MediaPlayer player = null;      // Audio player object
-    private boolean prepareOnly = true;     // playback after file prepare flag
-    private int seekOnPrepared = 0;     // seek to this location once media is prepared
-
-    /**
-     * Constructor.
-     *
-     * @param handler           The audio handler object
-     * @param id                The id of this audio player
-     */
-    public AudioPlayer(AudioHandler handler, String id, String file) {
-        this.handler = handler;
-        this.id = id;
-        this.audioFile = file;
-        this.recorder = new MediaRecorder();
-
-        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
-            this.tempFile = Environment.getExternalStorageDirectory().getAbsolutePath() + "/tmprecording.3gp";
-        } else {
-            this.tempFile = "/data/data/" + handler.cordova.getActivity().getPackageName() + "/cache/tmprecording.3gp";
-        }
-
-    }
-
-    /**
-     * Destroy player and stop audio playing or recording.
-     */
-    public void destroy() {
-        // Stop any play or record
-        if (this.player != null) {
-            if ((this.state == STATE.MEDIA_RUNNING) || (this.state == STATE.MEDIA_PAUSED)) {
-                this.player.stop();
-                this.setState(STATE.MEDIA_STOPPED);
-            }
-            this.player.release();
-            this.player = null;
-        }
-        if (this.recorder != null) {
-            this.stopRecording();
-            this.recorder.release();
-            this.recorder = null;
-        }
-    }
-
-    /**
-     * Start recording the specified file.
-     *
-     * @param file              The name of the file
-     */
-    public void startRecording(String file) {
-        switch (this.mode) {
-        case PLAY:
-            Log.d(LOG_TAG, "AudioPlayer Error: Can't record in play mode.");
-            this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
-            break;
-        case NONE:
-            this.audioFile = file;
-            this.recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
-            this.recorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); // THREE_GPP);
-            this.recorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); //AMR_NB);
-            this.recorder.setOutputFile(this.tempFile);
-            try {
-                this.recorder.prepare();
-                this.recorder.start();
-                this.setState(STATE.MEDIA_RUNNING);
-                return;
-            } catch (IllegalStateException e) {
-                e.printStackTrace();
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-            this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
-            break;
-        case RECORD:
-            Log.d(LOG_TAG, "AudioPlayer Error: Already recording.");
-            this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
-        }
-    }
-
-    /**
-     * Save temporary recorded file to specified name
-     *
-     * @param file
-     */
-    public void moveFile(String file) {
-        /* this is a hack to save the file as the specified name */
-        File f = new File(this.tempFile);
-
-        if (!file.startsWith("/")) {
-            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
-                file = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + file;
-            } else {
-                file = "/data/data/" + handler.cordova.getActivity().getPackageName() + "/cache/" + file;
-            }
-        }
-
-        String logMsg = "renaming " + this.tempFile + " to " + file;
-        Log.d(LOG_TAG, logMsg);
-        if (!f.renameTo(new File(file))) Log.e(LOG_TAG, "FAILED " + logMsg);
-    }
-
-    /**
-     * Stop recording and save to the file specified when recording started.
-     */
-    public void stopRecording() {
-        if (this.recorder != null) {
-            try{
-                if (this.state == STATE.MEDIA_RUNNING) {
-                    this.recorder.stop();
-                    this.setState(STATE.MEDIA_STOPPED);
-                }
-                this.recorder.reset();
-                this.moveFile(this.audioFile);
-            }
-            catch (Exception e) {
-                e.printStackTrace();
-            }
-        }
-    }
-
-    //==========================================================================
-    // Playback
-    //==========================================================================
-
-    /**
-     * Start or resume playing audio file.
-     *
-     * @param file              The name of the audio file.
-     */
-    public void startPlaying(String file) {
-        if (this.readyPlayer(file) && this.player != null) {
-            this.player.start();
-            this.setState(STATE.MEDIA_RUNNING);
-            this.seekOnPrepared = 0; //insures this is always reset
-        } else {
-            this.prepareOnly = false;
-        }
-    }
-
-    /**
-     * Seek or jump to a new time in the track.
-     */
-    public void seekToPlaying(int milliseconds) {
-        if (this.readyPlayer(this.audioFile)) {
-            this.player.seekTo(milliseconds);
-            Log.d(LOG_TAG, "Send a onStatus update for the new seek");
-            this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_POSITION + ", " + milliseconds / 1000.0f + ");");
-        }
-        else {
-            this.seekOnPrepared = milliseconds;
-        }
-    }
-
-    /**
-     * Pause playing.
-     */
-    public void pausePlaying() {
-
-        // If playing, then pause
-        if (this.state == STATE.MEDIA_RUNNING && this.player != null) {
-            this.player.pause();
-            this.setState(STATE.MEDIA_PAUSED);
-        }
-        else {
-            Log.d(LOG_TAG, "AudioPlayer Error: pausePlaying() called during invalid state: " + this.state.ordinal());
-            this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_NONE_ACTIVE + "});");
-        }
-    }
-
-    /**
-     * Stop playing the audio file.
-     */
-    public void stopPlaying() {
-        if ((this.state == STATE.MEDIA_RUNNING) || (this.state == STATE.MEDIA_PAUSED)) {
-            this.player.pause();
-            this.player.seekTo(0);
-            Log.d(LOG_TAG, "stopPlaying is calling stopped");
-            this.setState(STATE.MEDIA_STOPPED);
-        }
-        else {
-            Log.d(LOG_TAG, "AudioPlayer Error: stopPlaying() called during invalid state: " + this.state.ordinal());
-            this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_NONE_ACTIVE + "});");
-        }
-    }
-
-    /**
-     * Callback to be invoked when playback of a media source has completed.
-     *
-     * @param player           The MediaPlayer that reached the end of the file
-     */
-    public void onCompletion(MediaPlayer player) {
-        Log.d(LOG_TAG, "on completion is calling stopped");
-        this.setState(STATE.MEDIA_STOPPED);
-    }
-
-    /**
-     * Get current position of playback.
-     *
-     * @return                  position in msec or -1 if not playing
-     */
-    public long getCurrentPosition() {
-        if ((this.state == STATE.MEDIA_RUNNING) || (this.state == STATE.MEDIA_PAUSED)) {
-            int curPos = this.player.getCurrentPosition();
-            this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_POSITION + ", " + curPos / 1000.0f + ");");
-            return curPos;
-        }
-        else {
-            return -1;
-        }
-    }
-
-    /**
-     * Determine if playback file is streaming or local.
-     * It is streaming if file name starts with "http://"
-     *
-     * @param file              The file name
-     * @return                  T=streaming, F=local
-     */
-    public boolean isStreaming(String file) {
-        if (file.contains("http://") || file.contains("https://")) {
-            return true;
-        }
-        else {
-            return false;
-        }
-    }
-
-    /**
-      * Get the duration of the audio file.
-      *
-      * @param file             The name of the audio file.
-      * @return                 The duration in msec.
-      *                             -1=can't be determined
-      *                             -2=not allowed
-      */
-    public float getDuration(String file) {
-
-        // Can't get duration of recording
-        if (this.recorder != null) {
-            return (-2); // not allowed
-        }
-
-        // If audio file already loaded and started, then return duration
-        if (this.player != null) {
-            return this.duration;
-        }
-
-        // If no player yet, then create one
-        else {
-            this.prepareOnly = true;
-            this.startPlaying(file);
-
-            // This will only return value for local, since streaming
-            // file hasn't been read yet.
-            return this.duration;
-        }
-    }
-
-    /**
-     * Callback to be invoked when the media source is ready for playback.
-     *
-     * @param player           The MediaPlayer that is ready for playback
-     */
-    public void onPrepared(MediaPlayer player) {
-        // Listen for playback completion
-        this.player.setOnCompletionListener(this);
-        // seek to any location received while not prepared
-        this.seekToPlaying(this.seekOnPrepared);
-        // If start playing after prepared
-        if (!this.prepareOnly) {
-            this.player.start();
-            this.setState(STATE.MEDIA_RUNNING);
-            this.seekOnPrepared = 0; //reset only when played
-        } else {
-            this.setState(STATE.MEDIA_STARTING);
-        }
-        // Save off duration
-        this.duration = getDurationInSeconds();
-        // reset prepare only flag
-        this.prepareOnly = true;
-
-        // Send status notification to JavaScript
-        this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_DURATION + "," + this.duration + ");");
-    }
-
-    /**
-     * By default Android returns the length of audio in mills but we want seconds
-     *
-     * @return length of clip in seconds
-     */
-    private float getDurationInSeconds() {
-        return (this.player.getDuration() / 1000.0f);
-    }
-
-    /**
-     * Callback to be invoked when there has been an error during an asynchronous operation
-     *  (other errors will throw exceptions at method call time).
-     *
-     * @param player           the MediaPlayer the error pertains to
-     * @param arg1              the type of error that has occurred: (MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_SERVER_DIED)
-     * @param arg2              an extra code, specific to the error.
-     */
-    public boolean onError(MediaPlayer player, int arg1, int arg2) {
-        Log.d(LOG_TAG, "AudioPlayer.onError(" + arg1 + ", " + arg2 + ")");
-
-        // TODO: Not sure if this needs to be sent?
-        this.player.stop();
-        this.player.release();
-
-        // Send error notification to JavaScript
-        this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', { \"code\":" + arg1 + "});");
-        return false;
-    }
-
-    /**
-     * Set the state and send it to JavaScript.
-     *
-     * @param state
-     */
-    private void setState(STATE state) {
-        if (this.state != state) {
-            this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_STATE + ", " + state.ordinal() + ");");
-        }
-        this.state = state;
-    }
-
-    /**
-     * Set the mode and send it to JavaScript.
-     *
-     * @param state
-     */
-    private void setMode(MODE mode) {
-        if (this.mode != mode) {
-            //mode is not part of the expected behavior, so no notification
-            //this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_STATE + ", " + mode + ");");
-        }
-        this.mode = mode;
-    }
-
-    /**
-     * Get the audio state.
-     *
-     * @return int
-     */
-    public int getState() {
-        return this.state.ordinal();
-    }
-
-    /**
-     * Set the volume for audio player
-     *
-     * @param volume
-     */
-    public void setVolume(float volume) {
-        this.player.setVolume(volume, volume);
-    }
-
-    /**
-     * attempts to put the player in play mode
-     * @return true if in playmode, false otherwise
-     */
-    private boolean playMode() {
-        switch(this.mode) {
-        case NONE:
-            this.setMode(MODE.PLAY);
-            break;
-        case PLAY:
-            break;
-        case RECORD:
-            Log.d(LOG_TAG, "AudioPlayer Error: Can't play in record mode.");
-            this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
-            return false; //player is not ready
-        }
-        return true;
-    }
-
-    /**
-     * attempts to initialize the media player for playback
-     * @param file the file to play
-     * @return false if player not ready, reports if in wrong mode or state
-     */
-    private boolean readyPlayer(String file) {
-        if (playMode()) {
-            switch (this.state) {
-                case MEDIA_NONE:
-                    if (this.player == null) {
-                        this.player = new MediaPlayer();
-                    }
-                    try {
-                        this.loadAudioFile(file);
-                    } catch (Exception e) {
-                        this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', "+MEDIA_ERROR+", { \"code\":"+MEDIA_ERR_ABORTED+"});");
-                    }
-                    return false;
-                case MEDIA_LOADING:
-                    //cordova js is not aware of MEDIA_LOADING, so we send MEDIA_STARTING instead
-                    Log.d(LOG_TAG, "AudioPlayer Loading: startPlaying() called during media preparation: " + STATE.MEDIA_STARTING.ordinal());
-                    this.prepareOnly = false;
-                    return false;
-                case MEDIA_STARTING:
-                case MEDIA_RUNNING:
-                case MEDIA_PAUSED:
-                    return true;
-                case MEDIA_STOPPED:
-                    //if we are readying the same file
-                    if (this.audioFile.compareTo(file) == 0) {
-                        //reset the audio file
-                        player.seekTo(0);
-                        player.pause();
-                        return true;
-                    } else {
-                        //reset the player
-                        this.player.reset();
-                        try {
-                            this.loadAudioFile(file);
-                        } catch (Exception e) {
-                            this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
-                        }
-                        //if we had to prepare= the file, we won't be in the correct state for playback
-                        return false;
-                    }
-                default:
-                    Log.d(LOG_TAG, "AudioPlayer Error: startPlaying() called during invalid state: " + this.state);
-                    this.handler.webView.sendJavascript("cordova.require('cordova/plugin/Media').onStatus('" + this.id + "', " + MEDIA_ERROR + ", { \"code\":" + MEDIA_ERR_ABORTED + "});");
-            }
-        }
-        return false;
-    }
-
-    /**
-     * load audio file
-     * @throws IOException
-     * @throws IllegalStateException
-     * @throws SecurityException
-     * @throws IllegalArgumentException
-     */
-    private void loadAudioFile(String file) throws IllegalArgumentException, SecurityException, IllegalStateException, IOException {
-        if (this.isStreaming(file)) {
-            this.player.setDataSource(file);
-            this.player.setAudioStreamType(AudioManager.STREAM_MUSIC);
-            //if it's a streaming file, play mode is implied
-            this.setMode(MODE.PLAY);
-            this.setState(STATE.MEDIA_STARTING);
-            this.player.setOnPreparedListener(this);
-            this.player.prepareAsync();
-        }
-        else {
-            if (file.startsWith("/android_asset/")) {
-                String f = file.substring(15);
-                android.content.res.AssetFileDescriptor fd = this.handler.cordova.getActivity().getAssets().openFd(f);
-                this.player.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
-            }
-            else {
-                File fp = new File(file);
-                if (fp.exists()) {
-                    FileInputStream fileInputStream = new FileInputStream(file);
-                    this.player.setDataSource(fileInputStream.getFD());
-                }
-                else {
-                    this.player.setDataSource("/sdcard/" + file);
-                }
-            }
-                this.setState(STATE.MEDIA_STARTING);
-                this.player.setOnPreparedListener(this);
-                this.player.prepare();
-
-                // Get duration
-                this.duration = getDurationInSeconds();
-            }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/BatteryListener.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/BatteryListener.java b/framework/src/org/apache/cordova/BatteryListener.java
deleted file mode 100755
index 85558c2..0000000
--- a/framework/src/org/apache/cordova/BatteryListener.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
-       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.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.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.util.Log;
-
-public class BatteryListener extends CordovaPlugin {
-
-    private static final String LOG_TAG = "BatteryManager";
-
-    BroadcastReceiver receiver;
-
-    private CallbackContext batteryCallbackContext = null;
-
-    /**
-     * Constructor.
-     */
-    public BatteryListener() {
-        this.receiver = null;
-    }
-
-    /**
-     * Executes the request.
-     *
-     * @param action        	The action to execute.
-     * @param args          	JSONArry of arguments for the plugin.
-     * @param callbackContext 	The callback context used when calling back into JavaScript.
-     * @return              	True if the action was valid, false if not.
-     */
-    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
-        if (action.equals("start")) {
-            if (this.batteryCallbackContext != null) {
-                callbackContext.error( "Battery listener already running.");
-                return true;
-            }
-            this.batteryCallbackContext = callbackContext;
-
-            // We need to listen to power events to update battery status
-            IntentFilter intentFilter = new IntentFilter();
-            intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
-            if (this.receiver == null) {
-                this.receiver = new BroadcastReceiver() {
-                    @Override
-                    public void onReceive(Context context, Intent intent) {
-                        updateBatteryInfo(intent);
-                    }
-                };
-                cordova.getActivity().registerReceiver(this.receiver, intentFilter);
-            }
-
-            // Don't return any result now, since status results will be sent when events come in from broadcast receiver
-            PluginResult pluginResult = new PluginResult(PluginResult.Status.NO_RESULT);
-            pluginResult.setKeepCallback(true);
-            callbackContext.sendPluginResult(pluginResult);
-            return true;
-        }
-
-        else if (action.equals("stop")) {
-            removeBatteryListener();
-            this.sendUpdate(new JSONObject(), false); // release status callback in JS side
-            this.batteryCallbackContext = null;
-            callbackContext.success();
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Stop battery receiver.
-     */
-    public void onDestroy() {
-        removeBatteryListener();
-    }
-
-    /**
-     * Stop battery receiver.
-     */
-    public void onReset() {
-        removeBatteryListener();
-    }
-
-    /**
-     * Stop the battery receiver and set it to null.
-     */
-    private void removeBatteryListener() {
-        if (this.receiver != null) {
-            try {
-                this.cordova.getActivity().unregisterReceiver(this.receiver);
-                this.receiver = null;
-            } catch (Exception e) {
-                Log.e(LOG_TAG, "Error unregistering battery receiver: " + e.getMessage(), e);
-            }
-        }
-    }
-
-    /**
-     * Creates a JSONObject with the current battery information
-     *
-     * @param batteryIntent the current battery information
-     * @return a JSONObject containing the battery status information
-     */
-    private JSONObject getBatteryInfo(Intent batteryIntent) {
-        JSONObject obj = new JSONObject();
-        try {
-            obj.put("level", batteryIntent.getIntExtra(android.os.BatteryManager.EXTRA_LEVEL, 0));
-            obj.put("isPlugged", batteryIntent.getIntExtra(android.os.BatteryManager.EXTRA_PLUGGED, -1) > 0 ? true : false);
-        } catch (JSONException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-        return obj;
-    }
-
-    /**
-     * Updates the JavaScript side whenever the battery changes
-     *
-     * @param batteryIntent the current battery information
-     * @return
-     */
-    private void updateBatteryInfo(Intent batteryIntent) {
-        sendUpdate(this.getBatteryInfo(batteryIntent), true);
-    }
-
-    /**
-     * Create a new plugin result and send it back to JavaScript
-     *
-     * @param connection the network info to set as navigator.connection
-     */
-    private void sendUpdate(JSONObject info, boolean keepCallback) {
-        if (this.batteryCallbackContext != null) {
-            PluginResult result = new PluginResult(PluginResult.Status.OK, info);
-            result.setKeepCallback(keepCallback);
-            this.batteryCallbackContext.sendPluginResult(result);
-        }
-    }
-}


[16/22] android commit: [CB-3416] adding empty element during deprecation window.

Posted by st...@apache.org.
[CB-3416] adding empty <plugins> element during deprecation window.


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

Branch: refs/heads/3.0.0
Commit: 227733d195dc0413303667fa4e0fc45ea88f39d0
Parents: 1314872
Author: Fil Maj <ma...@gmail.com>
Authored: Thu May 16 14:35:58 2013 -0700
Committer: Fil Maj <ma...@gmail.com>
Committed: Thu May 16 14:35:58 2013 -0700

----------------------------------------------------------------------
 framework/res/xml/config.xml |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/227733d1/framework/res/xml/config.xml
----------------------------------------------------------------------
diff --git a/framework/res/xml/config.xml b/framework/res/xml/config.xml
index 2fb16c4..935eda4 100644
--- a/framework/res/xml/config.xml
+++ b/framework/res/xml/config.xml
@@ -98,4 +98,7 @@
     <feature name="InAppBrowser">
       <param name="android-package" value="org.apache.cordova.InAppBrowser"/>
     </feature>
+    <!-- Deprecated plugins element. Remove in 3.0 -->
+    <plugins>
+    </plugins>
 </widget>


[02/22] [CB-3307] Rename cordova-VERSION.js -> cordova.js

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8a95ed8e/framework/assets/www/index.html
----------------------------------------------------------------------
diff --git a/framework/assets/www/index.html b/framework/assets/www/index.html
index 1caeb8a..57ad752 100644
--- a/framework/assets/www/index.html
+++ b/framework/assets/www/index.html
@@ -19,7 +19,7 @@
 <html>
   <head>
     <title></title>
-    <script src="cordova-2.6.0.js"></script>
+    <script src="cordova.js"></script>
   </head>
   <body>
 

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8a95ed8e/framework/build.xml
----------------------------------------------------------------------
diff --git a/framework/build.xml b/framework/build.xml
index 9e7b127..989dbb2 100644
--- a/framework/build.xml
+++ b/framework/build.xml
@@ -26,8 +26,7 @@
         </filterchain>
     </loadfile>
 
-    <!-- check that the version of ant is at least 1.8.0, as is needed
-         for the dblQuote property -->
+    <!-- check that the version of ant is at least 1.8.0 -->
     <antversion property="thisantversion" atleast="1.8.0" />
     <fail message="The required minimum version of ant is 1.8.0, you have ${ant.version}"
           unless="thisantversion" />
@@ -80,9 +79,6 @@
          -->
     <property file="ant.properties" />
 
-    <!-- We need to setup the double quote. -->
-    <property name="dblQuote">"</property>
-
     <!-- The project.properties file is created and updated by the 'android'
          tool, as well as ADT.
 
@@ -136,33 +132,10 @@
     -->
     <import file="${sdk.dir}/tools/ant/build.xml" />
 
-    <!-- Combine JavaScript files into one cordova-uncompressed.js file. -->
-    <target name="build-javascript" depends="clean">
-
-      <!-- Clean up existing files -->
-      <!--<delete file="assets/www/cordova_${version}.js"/>-->
-
-      <!-- Create uncompressed JS file -->
-      <concat destfile="assets/www/cordova-${version}.js">
-        <filelist dir="assets/js" files="cordova.android.js"/>
-      </concat>
-
-      <!-- update project files to reference cordova-x.x.x.min.js -->
-      <replaceregexp match="cordova(.*)\.js" replace="cordova-${version}.js" byline="true">
-         <fileset file="assets/www/index.html" />
-         <fileset file="../bin/templates/project/assets/www/index.html" />
-      </replaceregexp>
-
-      <!-- This is sketchy, but it works, ${dblQuote} does not -->
-      <replaceregexp match="cordovaVersion = [\u0022].*[\u0022];" replace='cordovaVersion = ${dblQuote}${version}${dblQuote};' byline="true">
-        <fileset file="src/org/apache/cordova/Device.java" />
-      </replaceregexp>
-    </target>
-
     <!-- Build Cordova jar file that includes all native code, and Cordova JS file
          that includes all JavaScript code.
     -->
-    <target name="jar" depends="build-javascript, -compile">
+    <target name="jar" depends="-compile">
       <jar jarfile="cordova-${version}.jar" basedir="bin/classes" excludes="org/apache/cordova/R.class,org/apache/cordova/R$*.class"/>
     </target>
 
@@ -195,10 +168,10 @@
         </junit>
     </target>
 
-    <target name="cordova_debug" depends="build-javascript, debug">
+    <target name="cordova_debug" depends="debug">
     </target>
 
-    <target name="cordova_release" depends="build-javascript, release">
+    <target name="cordova_release" depends="release">
     </target>
 
 </project>

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8a95ed8e/framework/src/org/apache/cordova/Device.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/Device.java b/framework/src/org/apache/cordova/Device.java
index aa316c5..d9d9928 100644
--- a/framework/src/org/apache/cordova/Device.java
+++ b/framework/src/org/apache/cordova/Device.java
@@ -38,7 +38,7 @@ import android.telephony.TelephonyManager;
 public class Device extends CordovaPlugin {
     public static final String TAG = "Device";
 
-    public static String cordovaVersion = "2.6.0";              // Cordova version
+    public static String cordovaVersion = "dev";              // Cordova version
     public static String platform = "Android";                  // Device OS
     public static String uuid;                                  // Device UUID
 


[15/22] android commit: Bugfix: Config parser for plugins with onload param. The functionality was broken in the move from plugins to feature tags.

Posted by st...@apache.org.
Bugfix: Config parser for plugins with onload param.
The functionality was broken in the move from plugins to feature tags.

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

Branch: refs/heads/3.0.0
Commit: 13148728b3fbbf2c528d008660f378af35532048
Parents: 8f91ebf
Author: Shravan Narayan <sh...@google.com>
Authored: Thu May 16 15:41:59 2013 -0400
Committer: Shravan Narayan <sh...@google.com>
Committed: Thu May 16 15:41:59 2013 -0400

----------------------------------------------------------------------
 .../src/org/apache/cordova/api/PluginManager.java  |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/13148728/framework/src/org/apache/cordova/api/PluginManager.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/PluginManager.java b/framework/src/org/apache/cordova/api/PluginManager.java
index 9eb1308..e0ceabf 100755
--- a/framework/src/org/apache/cordova/api/PluginManager.java
+++ b/framework/src/org/apache/cordova/api/PluginManager.java
@@ -138,7 +138,7 @@ public class PluginManager {
                     else if (paramType.equals("package") || paramType.equals("android-package"))
                         pluginClass = xml.getAttributeValue(null,"value");
                     else if (paramType.equals("onload"))
-                        onload = "true".equals(xml.getAttributeValue(null, "onload"));
+                        onload = "true".equals(xml.getAttributeValue(null, "value"));
                 }
             }
             else if (eventType == XmlResourceParser.END_TAG)


[08/22] android commit: Changed all usages of FileHelper to use the new DataResource mechanism.

Posted by st...@apache.org.
Changed all usages of FileHelper to use the new DataResource mechanism.


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

Branch: refs/heads/3.0.0
Commit: 867358ea81619ce2b0e674758f1d66f1bc22172c
Parents: 62c3e46
Author: Shravan Narayan <sh...@google.com>
Authored: Sun May 5 05:32:20 2013 -0400
Committer: Braden Shepherdson <br...@gmail.com>
Committed: Wed May 8 17:38:58 2013 -0400

----------------------------------------------------------------------
 framework/src/org/apache/cordova/AudioHandler.java |   13 +-
 .../src/org/apache/cordova/CameraLauncher.java     |   61 +++++---
 framework/src/org/apache/cordova/Capture.java      |   13 +-
 framework/src/org/apache/cordova/FileUtils.java    |  121 +++++---------
 .../cordova/IceCreamCordovaWebViewClient.java      |    1 +
 5 files changed, 101 insertions(+), 108 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/867358ea/framework/src/org/apache/cordova/AudioHandler.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/AudioHandler.java b/framework/src/org/apache/cordova/AudioHandler.java
index fd8c9df..20c3c4e 100644
--- a/framework/src/org/apache/cordova/AudioHandler.java
+++ b/framework/src/org/apache/cordova/AudioHandler.java
@@ -20,7 +20,7 @@ package org.apache.cordova;
 
 import org.apache.cordova.api.CallbackContext;
 import org.apache.cordova.api.CordovaPlugin;
-
+import org.apache.cordova.api.DataResource;
 import android.content.Context;
 import android.media.AudioManager;
 
@@ -56,6 +56,11 @@ public class AudioHandler extends CordovaPlugin {
         this.pausedForPhone = new ArrayList<AudioPlayer>();
     }
 
+    public String getFilePath(String url, String source){
+        DataResource dataResource = DataResource.initiateNewDataRequestForUri(url, this.webView.pluginManager, cordova, source);
+        return dataResource.getRealFile().getPath();
+    }
+
     /**
      * Executes the request and returns PluginResult.
      * @param action 		The action to execute.
@@ -68,13 +73,13 @@ public class AudioHandler extends CordovaPlugin {
         String result = "";
 
         if (action.equals("startRecordingAudio")) {
-            this.startRecordingAudio(args.getString(0), FileHelper.stripFileProtocol(args.getString(1)));
+            this.startRecordingAudio(args.getString(0), getFilePath(args.getString(1), "AudioHandler.startRecordingAudio"));
         }
         else if (action.equals("stopRecordingAudio")) {
             this.stopRecordingAudio(args.getString(0));
         }
         else if (action.equals("startPlayingAudio")) {
-            this.startPlayingAudio(args.getString(0), FileHelper.stripFileProtocol(args.getString(1)));
+            this.startPlayingAudio(args.getString(0), getFilePath(args.getString(1), "AudioHandler.startPlayingAudio"));
         }
         else if (action.equals("seekToAudio")) {
             this.seekToAudio(args.getString(0), args.getInt(1));
@@ -102,7 +107,7 @@ public class AudioHandler extends CordovaPlugin {
         }
         else if (action.equals("create")) {
             String id = args.getString(0);
-            String src = FileHelper.stripFileProtocol(args.getString(1));
+            String src = getFilePath(args.getString(1), "AudioHandler.create");
             AudioPlayer audio = new AudioPlayer(this, id, src);
             this.players.put(id, audio);
         }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/867358ea/framework/src/org/apache/cordova/CameraLauncher.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CameraLauncher.java b/framework/src/org/apache/cordova/CameraLauncher.java
index 426d250..7597a81 100755
--- a/framework/src/org/apache/cordova/CameraLauncher.java
+++ b/framework/src/org/apache/cordova/CameraLauncher.java
@@ -20,15 +20,16 @@ package org.apache.cordova;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.cordova.api.CallbackContext;
 import org.apache.cordova.api.CordovaPlugin;
+import org.apache.cordova.api.DataResource;
 import org.apache.cordova.api.LOG;
 import org.apache.cordova.api.PluginResult;
 import org.json.JSONArray;
@@ -42,7 +43,6 @@ import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Matrix;
 import android.graphics.Bitmap.CompressFormat;
-import android.graphics.Rect;
 import android.media.MediaScannerConnection;
 import android.media.MediaScannerConnection.MediaScannerConnectionClient;
 import android.net.Uri;
@@ -290,7 +290,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
 
                     // If sending base64 image back
                     if (destType == DATA_URL) {
-                        bitmap = getScaledBitmap(FileHelper.stripFileProtocol(imageUri.toString()));
+                        bitmap = getScaledBitmap(imageUri.toString());
                         if (bitmap == null) {
                             // Try to get the bitmap from intent.
                             bitmap = (Bitmap)intent.getExtras().get("data");
@@ -316,7 +316,9 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                         if (this.saveToPhotoAlbum) {
                             Uri inputUri = getUriFromMediaStore();
                             //Just because we have a media URI doesn't mean we have a real file, we need to make it
-                            uri = Uri.fromFile(new File(FileHelper.getRealPath(inputUri, this.cordova)));
+                            DataResource dataResource = DataResource.initiateNewDataRequestForUri(inputUri, webView.pluginManager, cordova, "CameraLauncher.CameraExitIntent");
+                            File file = dataResource.getRealFile();
+                            uri = Uri.fromFile(file);
                         } else {
                             uri = Uri.fromFile(new File(DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()), System.currentTimeMillis() + ".jpg"));
                         }
@@ -332,14 +334,15 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
 
                             this.callbackContext.success(uri.toString());
                         } else {
-                            bitmap = getScaledBitmap(FileHelper.stripFileProtocol(imageUri.toString()));
+                            bitmap = getScaledBitmap(imageUri.toString());
 
                             if (rotate != 0 && this.correctOrientation) {
                                 bitmap = getRotatedBitmap(rotate, bitmap, exif);
                             }
 
                             // Add compressed version of captured image to returned media store Uri
-                            OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
+                            DataResource dataResource = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.CameraExitIntent");
+                            OutputStream os = dataResource.getOs();
                             bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os);
                             os.close();
 
@@ -347,7 +350,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                             if (this.encodingType == JPEG) {
                                 String exifPath;
                                 if (this.saveToPhotoAlbum) {
-                                    exifPath = FileHelper.getRealPath(uri, this.cordova);
+                                    exifPath = dataResource.getRealFile().getPath();
                                 } else {
                                     exifPath = uri.getPath();
                                 }
@@ -398,8 +401,9 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                         this.callbackContext.success(uri.toString());
                     } else {
                         String uriString = uri.toString();
+                        DataResource dataResource = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.CameraExitIntent");
                         // Get the path to the image. Makes loading so much easier.
-                        String mimeType = FileHelper.getMimeType(uriString, this.cordova);
+                        String mimeType = dataResource.getMimeType();
                         // If we don't have a valid image so quit.
                         if (!("image/jpeg".equalsIgnoreCase(mimeType) || "image/png".equalsIgnoreCase(mimeType))) {
                         	Log.d(LOG_TAG, "I either have a null image path or bitmap");
@@ -440,7 +444,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
                                     // Create an ExifHelper to save the exif data that is lost during compression
                                     String resizePath = DirectoryManager.getTempDirectoryPath(this.cordova.getActivity()) + "/resize.jpg";
                                     // Some content: URIs do not map to file paths (e.g. picasa).
-                                    String realPath = FileHelper.getRealPath(uri, this.cordova);
+                                    File realFile = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.CameraExitIntent").getRealFile();
+                                    String realPath = realFile != null? realFile.getPath() : null;
                                     ExifHelper exif = new ExifHelper();
                                     if (realPath != null && this.encodingType == JPEG) {
                                         try {
@@ -534,8 +539,15 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
      */
     private void writeUncompressedImage(Uri uri) throws FileNotFoundException,
             IOException {
-        FileInputStream fis = new FileInputStream(FileHelper.stripFileProtocol(imageUri.toString()));
-        OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri);
+        DataResource inputDataResource = DataResource.initiateNewDataRequestForUri(imageUri, webView.pluginManager, cordova, "CameraLauncher.writeUncompressedImage");
+        InputStream fis = inputDataResource.getIs();
+        DataResource outDataResource = DataResource.initiateNewDataRequestForUri(uri, webView.pluginManager, cordova, "CameraLauncher.writeUncompressedImage");
+        OutputStream os = outDataResource.getOs();
+        if(fis == null) {
+            throw new FileNotFoundException("Could not get the input file");
+        } else if(os == null) {
+            throw new FileNotFoundException("Could not get the output file");
+        }
         byte[] buffer = new byte[4096];
         int len;
         while ((len = fis.read(buffer)) != -1) {
@@ -578,14 +590,15 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
      */
     private Bitmap getScaledBitmap(String imageUrl) throws IOException {
         // If no new width or height were specified return the original bitmap
+        DataResource dataResource = DataResource.initiateNewDataRequestForUri(imageUrl, webView.pluginManager, cordova, "CameraLauncher.getScaledBitmap");
         if (this.targetWidth <= 0 && this.targetHeight <= 0) {
-            return BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova));
+            return BitmapFactory.decodeStream(dataResource.getIs());
         }
 
         // figure out the original width and height of the image
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inJustDecodeBounds = true;
-        BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova), null, options);
+        BitmapFactory.decodeStream(dataResource.getIs(), null, options);
         
         //CB-2292: WTF? Why is the width null?
         if(options.outWidth == 0 || options.outHeight == 0)
@@ -599,7 +612,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
         // Load in the smallest bitmap possible that is closest to the size we want
         options.inJustDecodeBounds = false;
         options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, this.targetWidth, this.targetHeight);
-        Bitmap unscaledBitmap = BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova), null, options);
+        Bitmap unscaledBitmap = BitmapFactory.decodeStream(dataResource.getIs(), null, options);
         if (unscaledBitmap == null) {
             return null;
         }
@@ -698,16 +711,20 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
             bitmap.recycle();
         }
 
-        // Clean up initial camera-written image file.
-        (new File(FileHelper.stripFileProtocol(oldImage.toString()))).delete();
+        DataResource dataResource = DataResource.initiateNewDataRequestForUri(oldImage, webView.pluginManager, cordova, "CameraLauncher.cleanup");
+        File file = dataResource.getRealFile();
+        if(file != null) {
+            // Clean up initial camera-written image file.
+            file.delete();
 
-        checkForDuplicateImage(imageType);
-        // Scan for the gallery to update pic refs in gallery
-        if (this.saveToPhotoAlbum && newImage != null) {
-            this.scanForGallery(newImage);
-        }
+            checkForDuplicateImage(imageType);
+            // Scan for the gallery to update pic refs in gallery
+            if (this.saveToPhotoAlbum && newImage != null) {
+                this.scanForGallery(newImage);
+            }
 
-        System.gc();
+            System.gc();
+        }
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/867358ea/framework/src/org/apache/cordova/Capture.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/Capture.java b/framework/src/org/apache/cordova/Capture.java
index 5f737ca..d7ad419 100644
--- a/framework/src/org/apache/cordova/Capture.java
+++ b/framework/src/org/apache/cordova/Capture.java
@@ -26,6 +26,7 @@ import java.io.OutputStream;
 import android.os.Build;
 import org.apache.cordova.api.CallbackContext;
 import org.apache.cordova.api.CordovaPlugin;
+import org.apache.cordova.api.DataResource;
 import org.apache.cordova.api.LOG;
 import org.apache.cordova.api.PluginResult;
 import org.json.JSONArray;
@@ -129,7 +130,8 @@ public class Capture extends CordovaPlugin {
         // If the mimeType isn't set the rest will fail
         // so let's see if we can determine it.
         if (mimeType == null || mimeType.equals("") || "null".equals(mimeType)) {
-            mimeType = FileHelper.getMimeType(filePath, cordova);
+            DataResource dataResource = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "Capture.dataResource");
+            mimeType = dataResource.getMimeType();
         }
         Log.d(LOG_TAG, "Mime type = " + mimeType);
 
@@ -156,7 +158,8 @@ public class Capture extends CordovaPlugin {
     private JSONObject getImageData(String filePath, JSONObject obj) throws JSONException {
         BitmapFactory.Options options = new BitmapFactory.Options();
         options.inJustDecodeBounds = true;
-        BitmapFactory.decodeFile(FileHelper.stripFileProtocol(filePath), options);
+        DataResource dataResource = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "Capture.getImageData");
+        BitmapFactory.decodeFile(dataResource.getRealFile().getPath(), options);
         obj.put("height", options.outHeight);
         obj.put("width", options.outWidth);
         return obj;
@@ -348,7 +351,8 @@ public class Capture extends CordovaPlugin {
      * @throws IOException
      */
     private JSONObject createMediaFile(Uri data) {
-        File fp = new File(FileHelper.getRealPath(data, this.cordova));
+        DataResource dataResource = DataResource.initiateNewDataRequestForUri(data, webView.pluginManager, cordova, "Capture.createMediaFile");
+        File fp = dataResource.getRealFile();
         JSONObject obj = new JSONObject();
 
         try {
@@ -358,6 +362,7 @@ public class Capture extends CordovaPlugin {
             // Because of an issue with MimeTypeMap.getMimeTypeFromExtension() all .3gpp files
             // are reported as video/3gpp. I'm doing this hacky check of the URI to see if it
             // is stored in the audio or video content store.
+
             if (fp.getAbsoluteFile().toString().endsWith(".3gp") || fp.getAbsoluteFile().toString().endsWith(".3gpp")) {
                 if (data.toString().contains("/audio/")) {
                     obj.put("type", AUDIO_3GPP);
@@ -365,7 +370,7 @@ public class Capture extends CordovaPlugin {
                     obj.put("type", VIDEO_3GPP);
                 }
             } else {
-                obj.put("type", FileHelper.getMimeType(fp.getAbsolutePath(), cordova));
+                obj.put("type", dataResource.getMimeType());
             }
 
             obj.put("lastModifiedDate", fp.lastModified());

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/867358ea/framework/src/org/apache/cordova/FileUtils.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileUtils.java b/framework/src/org/apache/cordova/FileUtils.java
index 2135be9..cf0e5a4 100755
--- a/framework/src/org/apache/cordova/FileUtils.java
+++ b/framework/src/org/apache/cordova/FileUtils.java
@@ -18,8 +18,6 @@
  */
 package org.apache.cordova;
 
-import android.database.Cursor;
-import android.net.Uri;
 import android.os.Environment;
 import android.provider.MediaStore;
 import android.util.Log;
@@ -27,6 +25,7 @@ import android.util.Log;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.cordova.api.CallbackContext;
 import org.apache.cordova.api.CordovaPlugin;
+import org.apache.cordova.api.DataResource;
 import org.apache.cordova.api.PluginResult;
 import org.apache.cordova.file.EncodingException;
 import org.apache.cordova.file.FileExistsException;
@@ -46,8 +45,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.RandomAccessFile;
 import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLDecoder;
 import java.nio.channels.FileChannel;
 
 /**
@@ -234,7 +231,7 @@ public class FileUtils extends CordovaPlugin {
      * @param filePath the path to check
      */
     private void notifyDelete(String filePath) {
-        String newFilePath = FileHelper.getRealPath(filePath, cordova);
+        String newFilePath = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.notifyDelete").getRealFile().getPath();
         try {
             this.cordova.getActivity().getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                     MediaStore.Images.Media.DATA + " = ?",
@@ -256,37 +253,10 @@ public class FileUtils extends CordovaPlugin {
      * @throws IOException if the user can't read the file
      * @throws JSONException
      */
-    @SuppressWarnings("deprecation")
     private JSONObject resolveLocalFileSystemURI(String url) throws IOException, JSONException {
-        String decoded = URLDecoder.decode(url, "UTF-8");
+        File fp = DataResource.initiateNewDataRequestForUri(url, webView.pluginManager, cordova, "FileUtils.resolveLocalFileSystemURI").getRealFile();
 
-        File fp = null;
-
-        // Handle the special case where you get an Android content:// uri.
-        if (decoded.startsWith("content:")) {
-            Cursor cursor = this.cordova.getActivity().managedQuery(Uri.parse(decoded), new String[] { MediaStore.Images.Media.DATA }, null, null, null);
-            // Note: MediaStore.Images/Audio/Video.Media.DATA is always "_data"
-            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
-            cursor.moveToFirst();
-            fp = new File(cursor.getString(column_index));
-        } else {
-            // Test to see if this is a valid URL first
-            @SuppressWarnings("unused")
-            URL testUrl = new URL(decoded);
-
-            if (decoded.startsWith("file://")) {
-                int questionMark = decoded.indexOf("?");
-                if (questionMark < 0) {
-                    fp = new File(decoded.substring(7, decoded.length()));
-                } else {
-                    fp = new File(decoded.substring(7, questionMark));
-                }
-            } else {
-                fp = new File(decoded);
-            }
-        }
-
-        if (!fp.exists()) {
+        if (fp == null || !fp.exists()) {
             throw new FileNotFoundException();
         }
         if (!fp.canRead()) {
@@ -304,9 +274,9 @@ public class FileUtils extends CordovaPlugin {
      * @throws JSONException
      */
     private JSONArray readEntries(String fileName) throws FileNotFoundException, JSONException {
-        File fp = createFileObject(fileName);
+        File fp = DataResource.initiateNewDataRequestForUri(fileName, webView.pluginManager, cordova, "FileUtils.readEntries").getRealFile();
 
-        if (!fp.exists()) {
+        if (fp == null || !fp.exists()) {
             // The directory we are listing doesn't exist so we should fail.
             throw new FileNotFoundException();
         }
@@ -341,8 +311,10 @@ public class FileUtils extends CordovaPlugin {
      * @throws FileExistsException
      */
     private JSONObject transferTo(String fileName, String newParent, String newName, boolean move) throws JSONException, NoModificationAllowedException, IOException, InvalidModificationException, EncodingException, FileExistsException {
-        String newFileName = FileHelper.getRealPath(fileName, cordova);
-        newParent = FileHelper.getRealPath(newParent, cordova);
+        DataResource dataResourceFrom = DataResource.initiateNewDataRequestForUri(fileName, webView.pluginManager, cordova, "FileUtils.transferTo");
+        String newFileName = dataResourceFrom.getRealFile().getPath();
+        DataResource dataResourceTo = DataResource.initiateNewDataRequestForUri(newParent, webView.pluginManager, cordova, "FileUtils.transferTo");
+        newParent = dataResourceTo.getRealFile().getPath();
 
         // Check for invalid file name
         if (newName != null && newName.contains(":")) {
@@ -613,7 +585,7 @@ public class FileUtils extends CordovaPlugin {
      * @throws FileExistsException
      */
     private boolean removeRecursively(String filePath) throws FileExistsException {
-        File fp = createFileObject(filePath);
+        File fp = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.readEntries").getRealFile();
 
         // You can't delete the root directory.
         if (atRootDirectory(filePath)) {
@@ -654,7 +626,7 @@ public class FileUtils extends CordovaPlugin {
      * @throws InvalidModificationException
      */
     private boolean remove(String filePath) throws NoModificationAllowedException, InvalidModificationException {
-        File fp = createFileObject(filePath);
+        File fp = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.readEntries").getRealFile();
 
         // You can't delete the root directory.
         if (atRootDirectory(filePath)) {
@@ -698,7 +670,8 @@ public class FileUtils extends CordovaPlugin {
             throw new EncodingException("This file has a : in it's name");
         }
 
-        File fp = createFileObject(dirPath, fileName);
+        String filePath = getFullFilePath(dirPath, fileName);
+        File fp = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.getFile").getRealFile();
 
         if (create) {
             if (exclusive && fp.exists()) {
@@ -740,15 +713,14 @@ public class FileUtils extends CordovaPlugin {
      * @param fileName new file name
      * @return
      */
-    private File createFileObject(String dirPath, String fileName) {
-        File fp = null;
+    private String getFullFilePath(String dirPath, String fileName) {
         if (fileName.startsWith("/")) {
-            fp = new File(fileName);
+            return fileName;
         } else {
-            dirPath = FileHelper.getRealPath(dirPath, cordova);
-            fp = new File(dirPath + File.separator + fileName);
+            DataResource dataResource = DataResource.initiateNewDataRequestForUri(dirPath, webView.pluginManager, cordova, "FileUtils.getFullFilePath");
+            dirPath = dataResource.getRealFile().getPath();
+            return dirPath + File.separator + fileName;
         }
-        return fp;
     }
 
     /**
@@ -760,12 +732,13 @@ public class FileUtils extends CordovaPlugin {
      * @throws JSONException
      */
     private JSONObject getParent(String filePath) throws JSONException {
-        filePath = FileHelper.getRealPath(filePath, cordova);
+        DataResource dataResource = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.getParent");
+        filePath = dataResource.getRealFile().getPath();
 
         if (atRootDirectory(filePath)) {
             return getEntry(filePath);
         }
-        return getEntry(new File(filePath).getParent());
+        return getEntry(dataResource.getRealFile().getParent());
     }
 
     /**
@@ -776,7 +749,7 @@ public class FileUtils extends CordovaPlugin {
      * @return true if we are at the root, false otherwise.
      */
     private boolean atRootDirectory(String filePath) {
-        filePath = FileHelper.getRealPath(filePath, cordova);
+        filePath = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.atRootDirectory").getRealFile().getPath();
 
         if (filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + cordova.getActivity().getPackageName() + "/cache") ||
                 filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath()) ||
@@ -787,19 +760,6 @@ public class FileUtils extends CordovaPlugin {
     }
 
     /**
-     * Create a File object from the passed in path
-     *
-     * @param filePath
-     * @return
-     */
-    private File createFileObject(String filePath) {
-        filePath = FileHelper.getRealPath(filePath, cordova);
-
-        File file = new File(filePath);
-        return file;
-    }
-
-    /**
      * Look up metadata about this entry.
      *
      * @param filePath to entry
@@ -807,9 +767,9 @@ public class FileUtils extends CordovaPlugin {
      * @throws FileNotFoundException
      */
     private long getMetadata(String filePath) throws FileNotFoundException {
-        File file = createFileObject(filePath);
+        File file = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.getMetadata").getRealFile();
 
-        if (!file.exists()) {
+        if (file == null || !file.exists()) {
             throw new FileNotFoundException("Failed to find file in getMetadata");
         }
 
@@ -825,15 +785,16 @@ public class FileUtils extends CordovaPlugin {
      * @throws JSONException
      */
     private JSONObject getFileMetadata(String filePath) throws FileNotFoundException, JSONException {
-        File file = createFileObject(filePath);
+        DataResource dataResource = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.getMetadata");
+        File file = dataResource.getRealFile();
 
-        if (!file.exists()) {
+        if (file == null || !file.exists()) {
             throw new FileNotFoundException("File: " + filePath + " does not exist.");
         }
 
         JSONObject metadata = new JSONObject();
         metadata.put("size", file.length());
-        metadata.put("type", FileHelper.getMimeType(filePath, cordova));
+        metadata.put("type", dataResource.getMimeType());
         metadata.put("name", file.getName());
         metadata.put("fullPath", filePath);
         metadata.put("lastModifiedDate", file.lastModified());
@@ -935,7 +896,8 @@ public class FileUtils extends CordovaPlugin {
         this.cordova.getThreadPool().execute(new Runnable() {
             public void run() {
                 try {
-                    byte[] bytes = readAsBinaryHelper(filename, start, end);
+                    DataResource dataResource = DataResource.initiateNewDataRequestForUri(filename, webView.pluginManager, cordova, "FileUtils.readFileAs");
+                    byte[] bytes = readAsBinaryHelper(dataResource.getIs(), start, end);
                     
                     PluginResult result;
                     switch (resultType) {
@@ -949,7 +911,7 @@ public class FileUtils extends CordovaPlugin {
                             result = new PluginResult(PluginResult.Status.OK, bytes, true);
                             break;
                         default: // Base64.
-                            String contentType = FileHelper.getMimeType(filename, cordova);
+                            String contentType = dataResource.getMimeType();
                             byte[] base64 = Base64.encodeBase64(bytes);
                             String s = "data:" + contentType + ";base64," + new String(base64, "US-ASCII");
                             result = new PluginResult(PluginResult.Status.OK, s);
@@ -976,10 +938,9 @@ public class FileUtils extends CordovaPlugin {
      * @return                  Contents of the file as a byte[].
      * @throws IOException
      */
-    private byte[] readAsBinaryHelper(String filename, int start, int end) throws IOException {
+    private byte[] readAsBinaryHelper(InputStream inputStream, int start, int end) throws IOException {
         int numBytesToRead = end - start;
         byte[] bytes = new byte[numBytesToRead];
-        InputStream inputStream = FileHelper.getInputStreamFromUriString(filename, cordova);
         int numBytesRead = 0;
 
         if (start > 0) {
@@ -1008,7 +969,8 @@ public class FileUtils extends CordovaPlugin {
             throw new NoModificationAllowedException("Couldn't write to file given its content URI");
         }
 
-        filename = FileHelper.getRealPath(filename, cordova);
+        DataResource dataResource = DataResource.initiateNewDataRequestForUri(filename, webView.pluginManager, cordova, "FileUtils.write");
+        filename = dataResource.getRealFile().getPath();
 
         boolean append = false;
         if (offset > 0) {
@@ -1037,13 +999,16 @@ public class FileUtils extends CordovaPlugin {
      * @throws NoModificationAllowedException
      */
     private long truncateFile(String filename, long size) throws FileNotFoundException, IOException, NoModificationAllowedException {
-        if (filename.startsWith("content://")) {
-            throw new NoModificationAllowedException("Couldn't truncate file given its content URI");
+        DataResource dataResource = DataResource.initiateNewDataRequestForUri(filename, webView.pluginManager, cordova, "FileUtils.truncateFile");
+        if(!dataResource.isWritable()) {
+            throw new NoModificationAllowedException("Couldn't truncate file as it is not writable");
+        }
+        File file = dataResource.getRealFile();
+        if(file == null) {
+            throw new FileNotFoundException("Couldn't get the file");
         }
 
-        filename = FileHelper.getRealPath(filename, cordova);
-
-        RandomAccessFile raf = new RandomAccessFile(filename, "rw");
+        RandomAccessFile raf = new RandomAccessFile(file, "rw");
         try {
             if (raf.length() >= size) {
                 FileChannel channel = raf.getChannel();

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/867358ea/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
index c4c4d3e..3a17dc1 100644
--- a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
+++ b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
@@ -49,6 +49,7 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
                 new DataResourceContext("WebViewClient.shouldInterceptRequest", true /* this is from a browser request*/));
         url = dataResource.getUri().toString();
 
+        // This mechanism is no longer needed due to the dataResource mechanism. It would be awesome to just get rid of it.
         //Check if plugins intercept the request
         WebResourceResponse ret = super.shouldInterceptRequest(view, url);
 //      The below bugfix is taken care of by the dataResource mechanism


[20/22] ripped out plugins

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/ContactAccessorSdk5.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/ContactAccessorSdk5.java b/framework/src/org/apache/cordova/ContactAccessorSdk5.java
deleted file mode 100644
index 47336c0..0000000
--- a/framework/src/org/apache/cordova/ContactAccessorSdk5.java
+++ /dev/null
@@ -1,2174 +0,0 @@
-/*
-       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 android.accounts.Account;
-import android.accounts.AccountManager;
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.OperationApplicationException;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.RemoteException;
-import android.provider.ContactsContract;
-import android.util.Log;
-import android.webkit.WebView;
-
-import org.apache.cordova.api.CordovaInterface;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-//import android.app.Activity;
-//import android.content.Context;
-
-/**
- * An implementation of {@link ContactAccessor} that uses current Contacts API.
- * This class should be used on Eclair or beyond, but would not work on any earlier
- * release of Android.  As a matter of fact, it could not even be loaded.
- * <p>
- * This implementation has several advantages:
- * <ul>
- * <li>It sees contacts from multiple accounts.
- * <li>It works with aggregated contacts. So for example, if the contact is the result
- * of aggregation of two raw contacts from different accounts, it may return the name from
- * one and the phone number from the other.
- * <li>It is efficient because it uses the more efficient current API.
- * <li>Not obvious in this particular example, but it has access to new kinds
- * of data available exclusively through the new APIs. Exercise for the reader: add support
- * for nickname (see {@link android.provider.ContactsContract.CommonDataKinds.Nickname}) or
- * social status updates (see {@link android.provider.ContactsContract.StatusUpdates}).
- * </ul>
- */
-
-public class ContactAccessorSdk5 extends ContactAccessor {
-
-    /**
-     * Keep the photo size under the 1 MB blog limit.
-     */
-    private static final long MAX_PHOTO_SIZE = 1048576;
-
-    private static final String EMAIL_REGEXP = ".+@.+\\.+.+"; /* <anything>@<anything>.<anything>*/
-
-    /**
-     * A static map that converts the JavaScript property name to Android database column name.
-     */
-    private static final Map<String, String> dbMap = new HashMap<String, String>();
-    static {
-        dbMap.put("id", ContactsContract.Data.CONTACT_ID);
-        dbMap.put("displayName", ContactsContract.Contacts.DISPLAY_NAME);
-        dbMap.put("name", ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
-        dbMap.put("name.formatted", ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
-        dbMap.put("name.familyName", ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME);
-        dbMap.put("name.givenName", ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME);
-        dbMap.put("name.middleName", ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME);
-        dbMap.put("name.honorificPrefix", ContactsContract.CommonDataKinds.StructuredName.PREFIX);
-        dbMap.put("name.honorificSuffix", ContactsContract.CommonDataKinds.StructuredName.SUFFIX);
-        dbMap.put("nickname", ContactsContract.CommonDataKinds.Nickname.NAME);
-        dbMap.put("phoneNumbers", ContactsContract.CommonDataKinds.Phone.NUMBER);
-        dbMap.put("phoneNumbers.value", ContactsContract.CommonDataKinds.Phone.NUMBER);
-        dbMap.put("emails", ContactsContract.CommonDataKinds.Email.DATA);
-        dbMap.put("emails.value", ContactsContract.CommonDataKinds.Email.DATA);
-        dbMap.put("addresses", ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS);
-        dbMap.put("addresses.formatted", ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS);
-        dbMap.put("addresses.streetAddress", ContactsContract.CommonDataKinds.StructuredPostal.STREET);
-        dbMap.put("addresses.locality", ContactsContract.CommonDataKinds.StructuredPostal.CITY);
-        dbMap.put("addresses.region", ContactsContract.CommonDataKinds.StructuredPostal.REGION);
-        dbMap.put("addresses.postalCode", ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE);
-        dbMap.put("addresses.country", ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY);
-        dbMap.put("ims", ContactsContract.CommonDataKinds.Im.DATA);
-        dbMap.put("ims.value", ContactsContract.CommonDataKinds.Im.DATA);
-        dbMap.put("organizations", ContactsContract.CommonDataKinds.Organization.COMPANY);
-        dbMap.put("organizations.name", ContactsContract.CommonDataKinds.Organization.COMPANY);
-        dbMap.put("organizations.department", ContactsContract.CommonDataKinds.Organization.DEPARTMENT);
-        dbMap.put("organizations.title", ContactsContract.CommonDataKinds.Organization.TITLE);
-        dbMap.put("birthday", ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE);
-        dbMap.put("note", ContactsContract.CommonDataKinds.Note.NOTE);
-        dbMap.put("photos.value", ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
-        //dbMap.put("categories.value", null);
-        dbMap.put("urls", ContactsContract.CommonDataKinds.Website.URL);
-        dbMap.put("urls.value", ContactsContract.CommonDataKinds.Website.URL);
-    }
-
-    /**
-     * Create an contact accessor.
-     */
-    public ContactAccessorSdk5(WebView view, CordovaInterface context) {
-        mApp = context;
-        mView = view;
-    }
-
-    /**
-     * This method takes the fields required and search options in order to produce an
-     * array of contacts that matches the criteria provided.
-     * @param fields an array of items to be used as search criteria
-     * @param options that can be applied to contact searching
-     * @return an array of contacts
-     */
-    @Override
-    public JSONArray search(JSONArray fields, JSONObject options) {
-        // Get the find options
-        String searchTerm = "";
-        int limit = Integer.MAX_VALUE;
-        boolean multiple = true;
-
-        if (options != null) {
-            searchTerm = options.optString("filter");
-            if (searchTerm.length() == 0) {
-                searchTerm = "%";
-            }
-            else {
-                searchTerm = "%" + searchTerm + "%";
-            }
-            
-            try {
-                multiple = options.getBoolean("multiple");
-                if (!multiple) {
-                    limit = 1;
-                }
-            } catch (JSONException e) {
-                // Multiple was not specified so we assume the default is true.
-            }
-        }
-        else {
-            searchTerm = "%";
-        }
-        
-
-        //Log.d(LOG_TAG, "Search Term = " + searchTerm);
-        //Log.d(LOG_TAG, "Field Length = " + fields.length());
-        //Log.d(LOG_TAG, "Fields = " + fields.toString());
-
-        // Loop through the fields the user provided to see what data should be returned.
-        HashMap<String, Boolean> populate = buildPopulationSet(fields);
-
-        // Build the ugly where clause and where arguments for one big query.
-        WhereOptions whereOptions = buildWhereClause(fields, searchTerm);
-
-        // Get all the id's where the search term matches the fields passed in.
-        Cursor idCursor = mApp.getActivity().getContentResolver().query(ContactsContract.Data.CONTENT_URI,
-                new String[] { ContactsContract.Data.CONTACT_ID },
-                whereOptions.getWhere(),
-                whereOptions.getWhereArgs(),
-                ContactsContract.Data.CONTACT_ID + " ASC");
-
-        // Create a set of unique ids
-        Set<String> contactIds = new HashSet<String>();
-        int idColumn = -1;
-        while (idCursor.moveToNext()) {
-            if (idColumn < 0) {
-                idColumn = idCursor.getColumnIndex(ContactsContract.Data.CONTACT_ID);
-            }
-            contactIds.add(idCursor.getString(idColumn));
-        }
-        idCursor.close();
-
-        // Build a query that only looks at ids
-        WhereOptions idOptions = buildIdClause(contactIds, searchTerm);
-
-        // Determine which columns we should be fetching.
-        HashSet<String> columnsToFetch = new HashSet<String>();
-        columnsToFetch.add(ContactsContract.Data.CONTACT_ID);
-        columnsToFetch.add(ContactsContract.Data.RAW_CONTACT_ID);
-        columnsToFetch.add(ContactsContract.Data.MIMETYPE);
-        
-        if (isRequired("displayName", populate)) {
-            columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);            
-        }
-        if (isRequired("name", populate)) {
-            columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.PREFIX);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredName.SUFFIX);
-        }
-        if (isRequired("phoneNumbers", populate)) {
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Phone._ID);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Phone.NUMBER);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Phone.TYPE);
-        }
-        if (isRequired("emails", populate)) {
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Email._ID);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Email.DATA);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Email.TYPE);
-        }
-        if (isRequired("addresses", populate)) {
-            columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal._ID);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Organization.TYPE);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.STREET);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.CITY);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.REGION);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY);
-        }
-        if (isRequired("organizations", populate)) {
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Organization._ID);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Organization.TYPE);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Organization.DEPARTMENT);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Organization.COMPANY);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Organization.TITLE);
-        }
-        if (isRequired("ims", populate)) {
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Im._ID);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Im.DATA);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Im.TYPE);
-        }
-        if (isRequired("note", populate)) {
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Note.NOTE);
-        }
-        if (isRequired("nickname", populate)) {
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Nickname.NAME);
-        }
-        if (isRequired("urls", populate)) {
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Website._ID);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Website.URL);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Website.TYPE);
-        }
-        if (isRequired("birthday", populate)) {
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Event.START_DATE);
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Event.TYPE);
-        }
-        if (isRequired("photos", populate)) {
-            columnsToFetch.add(ContactsContract.CommonDataKinds.Photo._ID);
-        }
-        
-        // Do the id query
-        Cursor c = mApp.getActivity().getContentResolver().query(ContactsContract.Data.CONTENT_URI,
-                columnsToFetch.toArray(new String[] {}),
-                idOptions.getWhere(),
-                idOptions.getWhereArgs(),
-                ContactsContract.Data.CONTACT_ID + " ASC");
-
-        JSONArray contacts = populateContactArray(limit, populate, c);
-        return contacts;
-    }
-
-    /**
-     * A special search that finds one contact by id
-     *
-     * @param id   contact to find by id
-     * @return     a JSONObject representing the contact
-     * @throws JSONException
-     */
-    public JSONObject getContactById(String id) throws JSONException {
-        // Do the id query
-        Cursor c = mApp.getActivity().getContentResolver().query(ContactsContract.Data.CONTENT_URI,
-                null,
-                ContactsContract.Data.CONTACT_ID + " = ? ",
-                new String[] { id },
-                ContactsContract.Data.CONTACT_ID + " ASC");
-
-        JSONArray fields = new JSONArray();
-        fields.put("*");
-
-        HashMap<String, Boolean> populate = buildPopulationSet(fields);
-
-        JSONArray contacts = populateContactArray(1, populate, c);
-
-        if (contacts.length() == 1) {
-            return contacts.getJSONObject(0);
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Creates an array of contacts from the cursor you pass in
-     *
-     * @param limit        max number of contacts for the array
-     * @param populate     whether or not you should populate a certain value
-     * @param c            the cursor
-     * @return             a JSONArray of contacts
-     */
-    private JSONArray populateContactArray(int limit,
-            HashMap<String, Boolean> populate, Cursor c) {
-
-        String contactId = "";
-        String rawId = "";
-        String oldContactId = "";
-        boolean newContact = true;
-        String mimetype = "";
-
-        JSONArray contacts = new JSONArray();
-        JSONObject contact = new JSONObject();
-        JSONArray organizations = new JSONArray();
-        JSONArray addresses = new JSONArray();
-        JSONArray phones = new JSONArray();
-        JSONArray emails = new JSONArray();
-        JSONArray ims = new JSONArray();
-        JSONArray websites = new JSONArray();
-        JSONArray photos = new JSONArray();
-
-        // Column indices
-        int colContactId = c.getColumnIndex(ContactsContract.Data.CONTACT_ID);
-        int colRawContactId = c.getColumnIndex(ContactsContract.Data.RAW_CONTACT_ID);
-        int colMimetype = c.getColumnIndex(ContactsContract.Data.MIMETYPE);
-        int colDisplayName = c.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
-        int colNote = c.getColumnIndex(ContactsContract.CommonDataKinds.Note.NOTE);
-        int colNickname = c.getColumnIndex(ContactsContract.CommonDataKinds.Nickname.NAME);
-        int colBirthday = c.getColumnIndex(ContactsContract.CommonDataKinds.Event.START_DATE);
-        int colEventType = c.getColumnIndex(ContactsContract.CommonDataKinds.Event.TYPE);
-
-        if (c.getCount() > 0) {
-            while (c.moveToNext() && (contacts.length() <= (limit - 1))) {
-                try {
-                    contactId = c.getString(colContactId);
-                    rawId = c.getString(colRawContactId);
-
-                    // If we are in the first row set the oldContactId
-                    if (c.getPosition() == 0) {
-                        oldContactId = contactId;
-                    }
-
-                    // When the contact ID changes we need to push the Contact object
-                    // to the array of contacts and create new objects.
-                    if (!oldContactId.equals(contactId)) {
-                        // Populate the Contact object with it's arrays
-                        // and push the contact into the contacts array
-                        contacts.put(populateContact(contact, organizations, addresses, phones,
-                                emails, ims, websites, photos));
-
-                        // Clean up the objects
-                        contact = new JSONObject();
-                        organizations = new JSONArray();
-                        addresses = new JSONArray();
-                        phones = new JSONArray();
-                        emails = new JSONArray();
-                        ims = new JSONArray();
-                        websites = new JSONArray();
-                        photos = new JSONArray();
-
-                        // Set newContact to true as we are starting to populate a new contact
-                        newContact = true;
-                    }
-
-                    // When we detect a new contact set the ID and display name.
-                    // These fields are available in every row in the result set returned.
-                    if (newContact) {
-                        newContact = false;
-                        contact.put("id", contactId);
-                        contact.put("rawId", rawId);
-                    }
-
-                    // Grab the mimetype of the current row as it will be used in a lot of comparisons
-                    mimetype = c.getString(colMimetype);
-                    
-                    if (mimetype.equals(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)) {
-                        contact.put("displayName", c.getString(colDisplayName));
-                    }
-
-                    if (mimetype.equals(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
-                            && isRequired("name", populate)) {
-                        contact.put("name", nameQuery(c));
-                    }
-                    else if (mimetype.equals(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
-                            && isRequired("phoneNumbers", populate)) {
-                        phones.put(phoneQuery(c));
-                    }
-                    else if (mimetype.equals(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
-                            && isRequired("emails", populate)) {
-                        emails.put(emailQuery(c));
-                    }
-                    else if (mimetype.equals(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
-                            && isRequired("addresses", populate)) {
-                        addresses.put(addressQuery(c));
-                    }
-                    else if (mimetype.equals(ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
-                            && isRequired("organizations", populate)) {
-                        organizations.put(organizationQuery(c));
-                    }
-                    else if (mimetype.equals(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
-                            && isRequired("ims", populate)) {
-                        ims.put(imQuery(c));
-                    }
-                    else if (mimetype.equals(ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE)
-                            && isRequired("note", populate)) {
-                        contact.put("note", c.getString(colNote));
-                    }
-                    else if (mimetype.equals(ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE)
-                            && isRequired("nickname", populate)) {
-                        contact.put("nickname", c.getString(colNickname));
-                    }
-                    else if (mimetype.equals(ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE)
-                            && isRequired("urls", populate)) {
-                        websites.put(websiteQuery(c));
-                    }
-                    else if (mimetype.equals(ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE)) {
-                        if (isRequired("birthday", populate) &&
-                                ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY == c.getInt(colEventType)) {
-                            contact.put("birthday", c.getString(colBirthday));
-                        }
-                    }
-                    else if (mimetype.equals(ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
-                            && isRequired("photos", populate)) {
-                        photos.put(photoQuery(c, contactId));
-                    }
-                } catch (JSONException e) {
-                    Log.e(LOG_TAG, e.getMessage(), e);
-                }
-
-                // Set the old contact ID
-                oldContactId = contactId;
-
-            }
-            
-            // Push the last contact into the contacts array
-            if (contacts.length() < limit) {
-                contacts.put(populateContact(contact, organizations, addresses, phones,
-                        emails, ims, websites, photos));
-            }
-        }
-        c.close();
-        return contacts;
-    }
-
-    /**
-     * Builds a where clause all all the ids passed into the method
-     * @param contactIds a set of unique contact ids
-     * @param searchTerm what to search for
-     * @return an object containing the selection and selection args
-     */
-    private WhereOptions buildIdClause(Set<String> contactIds, String searchTerm) {
-        WhereOptions options = new WhereOptions();
-
-        // If the user is searching for every contact then short circuit the method
-        // and return a shorter where clause to be searched.
-        if (searchTerm.equals("%")) {
-            options.setWhere("(" + ContactsContract.Data.CONTACT_ID + " LIKE ? )");
-            options.setWhereArgs(new String[] { searchTerm });
-            return options;
-        }
-
-        // This clause means that there are specific ID's to be populated
-        Iterator<String> it = contactIds.iterator();
-        StringBuffer buffer = new StringBuffer("(");
-
-        while (it.hasNext()) {
-            buffer.append("'" + it.next() + "'");
-            if (it.hasNext()) {
-                buffer.append(",");
-            }
-        }
-        buffer.append(")");
-
-        options.setWhere(ContactsContract.Data.CONTACT_ID + " IN " + buffer.toString());
-        options.setWhereArgs(null);
-
-        return options;
-    }
-
-    /**
-     * Create a new contact using a JSONObject to hold all the data.
-     * @param contact
-     * @param organizations array of organizations
-     * @param addresses array of addresses
-     * @param phones array of phones
-     * @param emails array of emails
-     * @param ims array of instant messenger addresses
-     * @param websites array of websites
-     * @param photos
-     * @return
-     */
-    private JSONObject populateContact(JSONObject contact, JSONArray organizations,
-            JSONArray addresses, JSONArray phones, JSONArray emails,
-            JSONArray ims, JSONArray websites, JSONArray photos) {
-        try {
-            // Only return the array if it has at least one entry
-            if (organizations.length() > 0) {
-                contact.put("organizations", organizations);
-            }
-            if (addresses.length() > 0) {
-                contact.put("addresses", addresses);
-            }
-            if (phones.length() > 0) {
-                contact.put("phoneNumbers", phones);
-            }
-            if (emails.length() > 0) {
-                contact.put("emails", emails);
-            }
-            if (ims.length() > 0) {
-                contact.put("ims", ims);
-            }
-            if (websites.length() > 0) {
-                contact.put("urls", websites);
-            }
-            if (photos.length() > 0) {
-                contact.put("photos", photos);
-            }
-        } catch (JSONException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-        return contact;
-    }
-
-  /**
-   * Take the search criteria passed into the method and create a SQL WHERE clause.
-   * @param fields the properties to search against
-   * @param searchTerm the string to search for
-   * @return an object containing the selection and selection args
-   */
-  private WhereOptions buildWhereClause(JSONArray fields, String searchTerm) {
-
-    ArrayList<String> where = new ArrayList<String>();
-    ArrayList<String> whereArgs = new ArrayList<String>();
-
-    WhereOptions options = new WhereOptions();
-
-        /*
-         * Special case where the user wants all fields returned
-         */
-        if (isWildCardSearch(fields)) {
-            // Get all contacts with all properties
-            if ("%".equals(searchTerm)) {
-                options.setWhere("(" + ContactsContract.Contacts.DISPLAY_NAME + " LIKE ? )");
-                options.setWhereArgs(new String[] { searchTerm });
-                return options;
-            } else {
-                // Get all contacts that match the filter but return all properties
-                where.add("(" + dbMap.get("displayName") + " LIKE ? )");
-                whereArgs.add(searchTerm);
-                where.add("(" + dbMap.get("name") + " LIKE ? AND "
-                        + ContactsContract.Data.MIMETYPE + " = ? )");
-                whereArgs.add(searchTerm);
-                whereArgs.add(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
-                where.add("(" + dbMap.get("nickname") + " LIKE ? AND "
-                        + ContactsContract.Data.MIMETYPE + " = ? )");
-                whereArgs.add(searchTerm);
-                whereArgs.add(ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE);
-                where.add("(" + dbMap.get("phoneNumbers") + " LIKE ? AND "
-                        + ContactsContract.Data.MIMETYPE + " = ? )");
-                whereArgs.add(searchTerm);
-                whereArgs.add(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
-                where.add("(" + dbMap.get("emails") + " LIKE ? AND "
-                        + ContactsContract.Data.MIMETYPE + " = ? )");
-                whereArgs.add(searchTerm);
-                whereArgs.add(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
-                where.add("(" + dbMap.get("addresses") + " LIKE ? AND "
-                        + ContactsContract.Data.MIMETYPE + " = ? )");
-                whereArgs.add(searchTerm);
-                whereArgs.add(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
-                where.add("(" + dbMap.get("ims") + " LIKE ? AND "
-                        + ContactsContract.Data.MIMETYPE + " = ? )");
-                whereArgs.add(searchTerm);
-                whereArgs.add(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE);
-                where.add("(" + dbMap.get("organizations") + " LIKE ? AND "
-                        + ContactsContract.Data.MIMETYPE + " = ? )");
-                whereArgs.add(searchTerm);
-                whereArgs.add(ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE);
-                where.add("(" + dbMap.get("note") + " LIKE ? AND "
-                        + ContactsContract.Data.MIMETYPE + " = ? )");
-                whereArgs.add(searchTerm);
-                whereArgs.add(ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE);
-                where.add("(" + dbMap.get("urls") + " LIKE ? AND "
-                        + ContactsContract.Data.MIMETYPE + " = ? )");
-                whereArgs.add(searchTerm);
-                whereArgs.add(ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE);
-            }
-        }
-
-        /*
-         * Special case for when the user wants all the contacts but
-         */
-        if ("%".equals(searchTerm)) {
-            options.setWhere("(" + ContactsContract.Contacts.DISPLAY_NAME + " LIKE ? )");
-            options.setWhereArgs(new String[] { searchTerm });
-            return options;
-        }
-
-        String key;
-        try {
-            //Log.d(LOG_TAG, "How many fields do we have = " + fields.length());
-            for (int i = 0; i < fields.length(); i++) {
-                key = fields.getString(i);
-
-                if (key.equals("id")) {
-                    where.add("(" + dbMap.get(key) + " = ? )");
-                    whereArgs.add(searchTerm.substring(1, searchTerm.length() - 1));
-                }
-                else if (key.startsWith("displayName")) {
-                    where.add("(" + dbMap.get(key) + " LIKE ? )");
-                    whereArgs.add(searchTerm);
-                }
-                else if (key.startsWith("name")) {
-                    where.add("(" + dbMap.get(key) + " LIKE ? AND "
-                            + ContactsContract.Data.MIMETYPE + " = ? )");
-                    whereArgs.add(searchTerm);
-                    whereArgs.add(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
-                }
-                else if (key.startsWith("nickname")) {
-                    where.add("(" + dbMap.get(key) + " LIKE ? AND "
-                            + ContactsContract.Data.MIMETYPE + " = ? )");
-                    whereArgs.add(searchTerm);
-                    whereArgs.add(ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE);
-                }
-                else if (key.startsWith("phoneNumbers")) {
-                    where.add("(" + dbMap.get(key) + " LIKE ? AND "
-                            + ContactsContract.Data.MIMETYPE + " = ? )");
-                    whereArgs.add(searchTerm);
-                    whereArgs.add(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
-                }
-                else if (key.startsWith("emails")) {
-                    where.add("(" + dbMap.get(key) + " LIKE ? AND "
-                            + ContactsContract.Data.MIMETYPE + " = ? )");
-                    whereArgs.add(searchTerm);
-                    whereArgs.add(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
-                }
-                else if (key.startsWith("addresses")) {
-                    where.add("(" + dbMap.get(key) + " LIKE ? AND "
-                            + ContactsContract.Data.MIMETYPE + " = ? )");
-                    whereArgs.add(searchTerm);
-                    whereArgs.add(ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
-                }
-                else if (key.startsWith("ims")) {
-                    where.add("(" + dbMap.get(key) + " LIKE ? AND "
-                            + ContactsContract.Data.MIMETYPE + " = ? )");
-                    whereArgs.add(searchTerm);
-                    whereArgs.add(ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE);
-                }
-                else if (key.startsWith("organizations")) {
-                    where.add("(" + dbMap.get(key) + " LIKE ? AND "
-                            + ContactsContract.Data.MIMETYPE + " = ? )");
-                    whereArgs.add(searchTerm);
-                    whereArgs.add(ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE);
-                }
-                //        else if (key.startsWith("birthday")) {
-//          where.add("(" + dbMap.get(key) + " LIKE ? AND "
-//              + ContactsContract.Data.MIMETYPE + " = ? )");
-//        }
-                else if (key.startsWith("note")) {
-                    where.add("(" + dbMap.get(key) + " LIKE ? AND "
-                            + ContactsContract.Data.MIMETYPE + " = ? )");
-                    whereArgs.add(searchTerm);
-                    whereArgs.add(ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE);
-                }
-                else if (key.startsWith("urls")) {
-                    where.add("(" + dbMap.get(key) + " LIKE ? AND "
-                            + ContactsContract.Data.MIMETYPE + " = ? )");
-                    whereArgs.add(searchTerm);
-                    whereArgs.add(ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE);
-                }
-            }
-        } catch (JSONException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-
-        // Creating the where string
-        StringBuffer selection = new StringBuffer();
-        for (int i = 0; i < where.size(); i++) {
-            selection.append(where.get(i));
-            if (i != (where.size() - 1)) {
-                selection.append(" OR ");
-            }
-        }
-        options.setWhere(selection.toString());
-
-        // Creating the where args array
-        String[] selectionArgs = new String[whereArgs.size()];
-        for (int i = 0; i < whereArgs.size(); i++) {
-            selectionArgs[i] = whereArgs.get(i);
-        }
-        options.setWhereArgs(selectionArgs);
-
-        return options;
-    }
-
-    /**
-     * If the user passes in the '*' wildcard character for search then they want all fields for each contact
-     *
-     * @param fields
-     * @return true if wildcard search requested, false otherwise
-     */
-    private boolean isWildCardSearch(JSONArray fields) {
-        // Only do a wildcard search if we are passed ["*"]
-        if (fields.length() == 1) {
-            try {
-                if ("*".equals(fields.getString(0))) {
-                    return true;
-                }
-            } catch (JSONException e) {
-                return false;
-            }
-        }
-        return false;
-    }
-
-    /**
-    * Create a ContactOrganization JSONObject
-    * @param cursor the current database row
-    * @return a JSONObject representing a ContactOrganization
-    */
-    private JSONObject organizationQuery(Cursor cursor) {
-        JSONObject organization = new JSONObject();
-        try {
-            organization.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization._ID)));
-            organization.put("pref", false); // Android does not store pref attribute
-            organization.put("type", getOrgType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TYPE))));
-            organization.put("department", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.DEPARTMENT)));
-            organization.put("name", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.COMPANY)));
-            organization.put("title", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TITLE)));
-        } catch (JSONException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-        return organization;
-    }
-
-    /**
-     * Create a ContactAddress JSONObject
-     * @param cursor the current database row
-     * @return a JSONObject representing a ContactAddress
-     */
-    private JSONObject addressQuery(Cursor cursor) {
-        JSONObject address = new JSONObject();
-        try {
-            address.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal._ID)));
-            address.put("pref", false); // Android does not store pref attribute
-            address.put("type", getAddressType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Organization.TYPE))));
-            address.put("formatted", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS)));
-            address.put("streetAddress", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.STREET)));
-            address.put("locality", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.CITY)));
-            address.put("region", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.REGION)));
-            address.put("postalCode", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE)));
-            address.put("country", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY)));
-        } catch (JSONException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-        return address;
-    }
-
-    /**
-     * Create a ContactName JSONObject
-     * @param cursor the current database row
-     * @return a JSONObject representing a ContactName
-     */
-    private JSONObject nameQuery(Cursor cursor) {
-        JSONObject contactName = new JSONObject();
-        try {
-            String familyName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
-            String givenName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
-            String middleName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME));
-            String honorificPrefix = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.PREFIX));
-            String honorificSuffix = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.SUFFIX));
-
-            // Create the formatted name
-            StringBuffer formatted = new StringBuffer("");
-            if (honorificPrefix != null) {
-                formatted.append(honorificPrefix + " ");
-            }
-            if (givenName != null) {
-                formatted.append(givenName + " ");
-            }
-            if (middleName != null) {
-                formatted.append(middleName + " ");
-            }
-            if (familyName != null) {
-                formatted.append(familyName);
-            }
-            if (honorificSuffix != null) {
-                formatted.append(" " + honorificSuffix);
-            }
-
-            contactName.put("familyName", familyName);
-            contactName.put("givenName", givenName);
-            contactName.put("middleName", middleName);
-            contactName.put("honorificPrefix", honorificPrefix);
-            contactName.put("honorificSuffix", honorificSuffix);
-            contactName.put("formatted", formatted);
-        } catch (JSONException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-        return contactName;
-    }
-
-    /**
-     * Create a ContactField JSONObject
-     * @param cursor the current database row
-     * @return a JSONObject representing a ContactField
-     */
-    private JSONObject phoneQuery(Cursor cursor) {
-        JSONObject phoneNumber = new JSONObject();
-        try {
-            phoneNumber.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID)));
-            phoneNumber.put("pref", false); // Android does not store pref attribute
-            phoneNumber.put("value", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
-            phoneNumber.put("type", getPhoneType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE))));
-        } catch (JSONException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        } catch (Exception excp) {
-            Log.e(LOG_TAG, excp.getMessage(), excp);
-        }
-        return phoneNumber;
-    }
-
-    /**
-     * Create a ContactField JSONObject
-     * @param cursor the current database row
-     * @return a JSONObject representing a ContactField
-     */
-    private JSONObject emailQuery(Cursor cursor) {
-        JSONObject email = new JSONObject();
-        try {
-            email.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email._ID)));
-            email.put("pref", false); // Android does not store pref attribute
-            email.put("value", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA)));
-            email.put("type", getContactType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE))));
-        } catch (JSONException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-        return email;
-    }
-
-    /**
-     * Create a ContactField JSONObject
-     * @param cursor the current database row
-     * @return a JSONObject representing a ContactField
-     */
-    private JSONObject imQuery(Cursor cursor) {
-        JSONObject im = new JSONObject();
-        try {
-            im.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Im._ID)));
-            im.put("pref", false); // Android does not store pref attribute
-            im.put("value", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Im.DATA)));
-            im.put("type", getImType(cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Im.PROTOCOL))));
-        } catch (JSONException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-        return im;
-    }
-
-    /**
-     * Create a ContactField JSONObject
-     * @param cursor the current database row
-     * @return a JSONObject representing a ContactField
-     */
-    private JSONObject websiteQuery(Cursor cursor) {
-        JSONObject website = new JSONObject();
-        try {
-            website.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Website._ID)));
-            website.put("pref", false); // Android does not store pref attribute
-            website.put("value", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Website.URL)));
-            website.put("type", getContactType(cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Website.TYPE))));
-        } catch (JSONException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-        return website;
-    }
-
-    /**
-     * Create a ContactField JSONObject
-     * @param contactId
-     * @return a JSONObject representing a ContactField
-     */
-    private JSONObject photoQuery(Cursor cursor, String contactId) {
-        JSONObject photo = new JSONObject();
-        try {
-            photo.put("id", cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Photo._ID)));
-            photo.put("pref", false);
-            photo.put("type", "url");
-            Uri person = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, (new Long(contactId)));
-            Uri photoUri = Uri.withAppendedPath(person, ContactsContract.Contacts.Photo.CONTENT_DIRECTORY);
-            photo.put("value", photoUri.toString());
-        } catch (JSONException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-        return photo;
-    }
-
-    @Override
-    /**
-     * This method will save a contact object into the devices contacts database.
-     *
-     * @param contact the contact to be saved.
-     * @returns the id if the contact is successfully saved, null otherwise.
-     */
-    public String save(JSONObject contact) {
-        AccountManager mgr = AccountManager.get(mApp.getActivity());
-        Account[] accounts = mgr.getAccounts();
-        String accountName = null;
-        String accountType = null;
-
-        if (accounts.length == 1) {
-            accountName = accounts[0].name;
-            accountType = accounts[0].type;
-        }
-        else if (accounts.length > 1) {
-            for (Account a : accounts) {
-                if (a.type.contains("eas") && a.name.matches(EMAIL_REGEXP)) /*Exchange ActiveSync*/{
-                    accountName = a.name;
-                    accountType = a.type;
-                    break;
-                }
-            }
-            if (accountName == null) {
-                for (Account a : accounts) {
-                    if (a.type.contains("com.google") && a.name.matches(EMAIL_REGEXP)) /*Google sync provider*/{
-                        accountName = a.name;
-                        accountType = a.type;
-                        break;
-                    }
-                }
-            }
-            if (accountName == null) {
-                for (Account a : accounts) {
-                    if (a.name.matches(EMAIL_REGEXP)) /*Last resort, just look for an email address...*/{
-                        accountName = a.name;
-                        accountType = a.type;
-                        break;
-                    }
-                }
-            }
-        }
-
-        String id = getJsonString(contact, "id");
-        // Create new contact
-        if (id == null) {
-            return createNewContact(contact, accountType, accountName);
-        }
-        // Modify existing contact
-        else {
-            return modifyContact(id, contact, accountType, accountName);
-        }
-    }
-
-    /**
-     * Creates a new contact and stores it in the database
-     *
-     * @param id the raw contact id which is required for linking items to the contact
-     * @param contact the contact to be saved
-     * @param account the account to be saved under
-     */
-    private String modifyContact(String id, JSONObject contact, String accountType, String accountName) {
-        // Get the RAW_CONTACT_ID which is needed to insert new values in an already existing contact.
-        // But not needed to update existing values.
-        int rawId = (new Integer(getJsonString(contact, "rawId"))).intValue();
-
-        // Create a list of attributes to add to the contact database
-        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
-
-        //Add contact type
-        ops.add(ContentProviderOperation.newUpdate(ContactsContract.RawContacts.CONTENT_URI)
-                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
-                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
-                .build());
-
-        // Modify name
-        JSONObject name;
-        try {
-            String displayName = getJsonString(contact, "displayName");
-            name = contact.getJSONObject("name");
-            if (displayName != null || name != null) {
-                ContentProviderOperation.Builder builder = ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
-                        .withSelection(ContactsContract.Data.CONTACT_ID + "=? AND " +
-                                ContactsContract.Data.MIMETYPE + "=?",
-                                new String[] { id, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE });
-
-                if (displayName != null) {
-                    builder.withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName);
-                }
-
-                String familyName = getJsonString(name, "familyName");
-                if (familyName != null) {
-                    builder.withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, familyName);
-                }
-                String middleName = getJsonString(name, "middleName");
-                if (middleName != null) {
-                    builder.withValue(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME, middleName);
-                }
-                String givenName = getJsonString(name, "givenName");
-                if (givenName != null) {
-                    builder.withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, givenName);
-                }
-                String honorificPrefix = getJsonString(name, "honorificPrefix");
-                if (honorificPrefix != null) {
-                    builder.withValue(ContactsContract.CommonDataKinds.StructuredName.PREFIX, honorificPrefix);
-                }
-                String honorificSuffix = getJsonString(name, "honorificSuffix");
-                if (honorificSuffix != null) {
-                    builder.withValue(ContactsContract.CommonDataKinds.StructuredName.SUFFIX, honorificSuffix);
-                }
-
-                ops.add(builder.build());
-            }
-        } catch (JSONException e1) {
-            Log.d(LOG_TAG, "Could not get name");
-        }
-
-        // Modify phone numbers
-        JSONArray phones = null;
-        try {
-            phones = contact.getJSONArray("phoneNumbers");
-            if (phones != null) {
-                // Delete all the phones
-                if (phones.length() == 0) {
-                    ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
-                            .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
-                                    ContactsContract.Data.MIMETYPE + "=?",
-                                    new String[] { "" + rawId, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE })
-                            .build());
-                }
-                // Modify or add a phone
-                else {
-                    for (int i = 0; i < phones.length(); i++) {
-                        JSONObject phone = (JSONObject) phones.get(i);
-                        String phoneId = getJsonString(phone, "id");
-                        // This is a new phone so do a DB insert
-                        if (phoneId == null) {
-                            ContentValues contentValues = new ContentValues();
-                            contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
-                            contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
-                            contentValues.put(ContactsContract.CommonDataKinds.Phone.NUMBER, getJsonString(phone, "value"));
-                            contentValues.put(ContactsContract.CommonDataKinds.Phone.TYPE, getPhoneType(getJsonString(phone, "type")));
-
-                            ops.add(ContentProviderOperation.newInsert(
-                                    ContactsContract.Data.CONTENT_URI).withValues(contentValues).build());
-                        }
-                        // This is an existing phone so do a DB update
-                        else {
-                            ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
-                                    .withSelection(ContactsContract.CommonDataKinds.Phone._ID + "=? AND " +
-                                            ContactsContract.Data.MIMETYPE + "=?",
-                                            new String[] { phoneId, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE })
-                                    .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, getJsonString(phone, "value"))
-                                    .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, getPhoneType(getJsonString(phone, "type")))
-                                    .build());
-                        }
-                    }
-                }
-            }
-        } catch (JSONException e) {
-            Log.d(LOG_TAG, "Could not get phone numbers");
-        }
-
-        // Modify emails
-        JSONArray emails = null;
-        try {
-            emails = contact.getJSONArray("emails");
-            if (emails != null) {
-                // Delete all the emails
-                if (emails.length() == 0) {
-                    ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
-                            .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
-                                    ContactsContract.Data.MIMETYPE + "=?",
-                                    new String[] { "" + rawId, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE })
-                            .build());
-                }
-                // Modify or add a email
-                else {
-                    for (int i = 0; i < emails.length(); i++) {
-                        JSONObject email = (JSONObject) emails.get(i);
-                        String emailId = getJsonString(email, "id");
-                        // This is a new email so do a DB insert
-                        if (emailId == null) {
-                            ContentValues contentValues = new ContentValues();
-                            contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
-                            contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE);
-                            contentValues.put(ContactsContract.CommonDataKinds.Email.DATA, getJsonString(email, "value"));
-                            contentValues.put(ContactsContract.CommonDataKinds.Email.TYPE, getContactType(getJsonString(email, "type")));
-
-                            ops.add(ContentProviderOperation.newInsert(
-                                    ContactsContract.Data.CONTENT_URI).withValues(contentValues).build());
-                        }
-                        // This is an existing email so do a DB update
-                        else {
-                            ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
-                                    .withSelection(ContactsContract.CommonDataKinds.Email._ID + "=? AND " +
-                                            ContactsContract.Data.MIMETYPE + "=?",
-                                            new String[] { emailId, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE })
-                                    .withValue(ContactsContract.CommonDataKinds.Email.DATA, getJsonString(email, "value"))
-                                    .withValue(ContactsContract.CommonDataKinds.Email.TYPE, getContactType(getJsonString(email, "type")))
-                                    .build());
-                        }
-                    }
-                }
-            }
-        } catch (JSONException e) {
-            Log.d(LOG_TAG, "Could not get emails");
-        }
-
-        // Modify addresses
-        JSONArray addresses = null;
-        try {
-            addresses = contact.getJSONArray("addresses");
-            if (addresses != null) {
-                // Delete all the addresses
-                if (addresses.length() == 0) {
-                    ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
-                            .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
-                                    ContactsContract.Data.MIMETYPE + "=?",
-                                    new String[] { "" + rawId, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE })
-                            .build());
-                }
-                // Modify or add a address
-                else {
-                    for (int i = 0; i < addresses.length(); i++) {
-                        JSONObject address = (JSONObject) addresses.get(i);
-                        String addressId = getJsonString(address, "id");
-                        // This is a new address so do a DB insert
-                        if (addressId == null) {
-                            ContentValues contentValues = new ContentValues();
-                            contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
-                            contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE);
-                            contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, getAddressType(getJsonString(address, "type")));
-                            contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted"));
-                            contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress"));
-                            contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality"));
-                            contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.REGION, getJsonString(address, "region"));
-                            contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE, getJsonString(address, "postalCode"));
-                            contentValues.put(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, getJsonString(address, "country"));
-
-                            ops.add(ContentProviderOperation.newInsert(
-                                    ContactsContract.Data.CONTENT_URI).withValues(contentValues).build());
-                        }
-                        // This is an existing address so do a DB update
-                        else {
-                            ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
-                                    .withSelection(ContactsContract.CommonDataKinds.StructuredPostal._ID + "=? AND " +
-                                            ContactsContract.Data.MIMETYPE + "=?",
-                                            new String[] { addressId, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE })
-                                    .withValue(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, getAddressType(getJsonString(address, "type")))
-                                    .withValue(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted"))
-                                    .withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress"))
-                                    .withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality"))
-                                    .withValue(ContactsContract.CommonDataKinds.StructuredPostal.REGION, getJsonString(address, "region"))
-                                    .withValue(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE, getJsonString(address, "postalCode"))
-                                    .withValue(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, getJsonString(address, "country"))
-                                    .build());
-                        }
-                    }
-                }
-            }
-        } catch (JSONException e) {
-            Log.d(LOG_TAG, "Could not get addresses");
-        }
-
-        // Modify organizations
-        JSONArray organizations = null;
-        try {
-            organizations = contact.getJSONArray("organizations");
-            if (organizations != null) {
-                // Delete all the organizations
-                if (organizations.length() == 0) {
-                    ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
-                            .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
-                                    ContactsContract.Data.MIMETYPE + "=?",
-                                    new String[] { "" + rawId, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE })
-                            .build());
-                }
-                // Modify or add a organization
-                else {
-                    for (int i = 0; i < organizations.length(); i++) {
-                        JSONObject org = (JSONObject) organizations.get(i);
-                        String orgId = getJsonString(org, "id");
-                        // This is a new organization so do a DB insert
-                        if (orgId == null) {
-                            ContentValues contentValues = new ContentValues();
-                            contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
-                            contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE);
-                            contentValues.put(ContactsContract.CommonDataKinds.Organization.TYPE, getOrgType(getJsonString(org, "type")));
-                            contentValues.put(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department"));
-                            contentValues.put(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name"));
-                            contentValues.put(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title"));
-
-                            ops.add(ContentProviderOperation.newInsert(
-                                    ContactsContract.Data.CONTENT_URI).withValues(contentValues).build());
-                        }
-                        // This is an existing organization so do a DB update
-                        else {
-                            ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
-                                    .withSelection(ContactsContract.CommonDataKinds.Organization._ID + "=? AND " +
-                                            ContactsContract.Data.MIMETYPE + "=?",
-                                            new String[] { orgId, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE })
-                                    .withValue(ContactsContract.CommonDataKinds.Organization.TYPE, getOrgType(getJsonString(org, "type")))
-                                    .withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department"))
-                                    .withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name"))
-                                    .withValue(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title"))
-                                    .build());
-                        }
-                    }
-                }
-            }
-        } catch (JSONException e) {
-            Log.d(LOG_TAG, "Could not get organizations");
-        }
-
-        // Modify IMs
-        JSONArray ims = null;
-        try {
-            ims = contact.getJSONArray("ims");
-            if (ims != null) {
-                // Delete all the ims
-                if (ims.length() == 0) {
-                    ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
-                            .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
-                                    ContactsContract.Data.MIMETYPE + "=?",
-                                    new String[] { "" + rawId, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE })
-                            .build());
-                }
-                // Modify or add a im
-                else {
-                    for (int i = 0; i < ims.length(); i++) {
-                        JSONObject im = (JSONObject) ims.get(i);
-                        String imId = getJsonString(im, "id");
-                        // This is a new IM so do a DB insert
-                        if (imId == null) {
-                            ContentValues contentValues = new ContentValues();
-                            contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
-                            contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE);
-                            contentValues.put(ContactsContract.CommonDataKinds.Im.DATA, getJsonString(im, "value"));
-                            contentValues.put(ContactsContract.CommonDataKinds.Im.TYPE, getImType(getJsonString(im, "type")));
-
-                            ops.add(ContentProviderOperation.newInsert(
-                                    ContactsContract.Data.CONTENT_URI).withValues(contentValues).build());
-                        }
-                        // This is an existing IM so do a DB update
-                        else {
-                            ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
-                                    .withSelection(ContactsContract.CommonDataKinds.Im._ID + "=? AND " +
-                                            ContactsContract.Data.MIMETYPE + "=?",
-                                            new String[] { imId, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE })
-                                    .withValue(ContactsContract.CommonDataKinds.Im.DATA, getJsonString(im, "value"))
-                                    .withValue(ContactsContract.CommonDataKinds.Im.TYPE, getContactType(getJsonString(im, "type")))
-                                    .build());
-                        }
-                    }
-                }
-            }
-        } catch (JSONException e) {
-            Log.d(LOG_TAG, "Could not get emails");
-        }
-
-        // Modify note
-        String note = getJsonString(contact, "note");
-        ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
-                .withSelection(ContactsContract.Data.CONTACT_ID + "=? AND " +
-                        ContactsContract.Data.MIMETYPE + "=?",
-                        new String[] { id, ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE })
-                .withValue(ContactsContract.CommonDataKinds.Note.NOTE, note)
-                .build());
-
-        // Modify nickname
-        String nickname = getJsonString(contact, "nickname");
-        if (nickname != null) {
-            ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
-                    .withSelection(ContactsContract.Data.CONTACT_ID + "=? AND " +
-                            ContactsContract.Data.MIMETYPE + "=?",
-                            new String[] { id, ContactsContract.CommonDataKinds.Nickname.CONTENT_ITEM_TYPE })
-                    .withValue(ContactsContract.CommonDataKinds.Nickname.NAME, nickname)
-                    .build());
-        }
-
-        // Modify urls
-        JSONArray websites = null;
-        try {
-            websites = contact.getJSONArray("urls");
-            if (websites != null) {
-                // Delete all the websites
-                if (websites.length() == 0) {
-                    Log.d(LOG_TAG, "This means we should be deleting all the phone numbers.");
-                    ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
-                            .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
-                                    ContactsContract.Data.MIMETYPE + "=?",
-                                    new String[] { "" + rawId, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE })
-                            .build());
-                }
-                // Modify or add a website
-                else {
-                    for (int i = 0; i < websites.length(); i++) {
-                        JSONObject website = (JSONObject) websites.get(i);
-                        String websiteId = getJsonString(website, "id");
-                        // This is a new website so do a DB insert
-                        if (websiteId == null) {
-                            ContentValues contentValues = new ContentValues();
-                            contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
-                            contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE);
-                            contentValues.put(ContactsContract.CommonDataKinds.Website.DATA, getJsonString(website, "value"));
-                            contentValues.put(ContactsContract.CommonDataKinds.Website.TYPE, getContactType(getJsonString(website, "type")));
-
-                            ops.add(ContentProviderOperation.newInsert(
-                                    ContactsContract.Data.CONTENT_URI).withValues(contentValues).build());
-                        }
-                        // This is an existing website so do a DB update
-                        else {
-                            ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
-                                    .withSelection(ContactsContract.CommonDataKinds.Website._ID + "=? AND " +
-                                            ContactsContract.Data.MIMETYPE + "=?",
-                                            new String[] { websiteId, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE })
-                                    .withValue(ContactsContract.CommonDataKinds.Website.DATA, getJsonString(website, "value"))
-                                    .withValue(ContactsContract.CommonDataKinds.Website.TYPE, getContactType(getJsonString(website, "type")))
-                                    .build());
-                        }
-                    }
-                }
-            }
-        } catch (JSONException e) {
-            Log.d(LOG_TAG, "Could not get websites");
-        }
-
-        // Modify birthday
-        String birthday = getJsonString(contact, "birthday");
-        if (birthday != null) {
-            ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
-                    .withSelection(ContactsContract.Data.CONTACT_ID + "=? AND " +
-                            ContactsContract.Data.MIMETYPE + "=? AND " +
-                            ContactsContract.CommonDataKinds.Event.TYPE + "=?",
-                            new String[] { id, ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE, new String("" + ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY) })
-                    .withValue(ContactsContract.CommonDataKinds.Event.TYPE, ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY)
-                    .withValue(ContactsContract.CommonDataKinds.Event.START_DATE, birthday)
-                    .build());
-        }
-
-        // Modify photos
-        JSONArray photos = null;
-        try {
-            photos = contact.getJSONArray("photos");
-            if (photos != null) {
-                // Delete all the photos
-                if (photos.length() == 0) {
-                    ops.add(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI)
-                            .withSelection(ContactsContract.Data.RAW_CONTACT_ID + "=? AND " +
-                                    ContactsContract.Data.MIMETYPE + "=?",
-                                    new String[] { "" + rawId, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE })
-                            .build());
-                }
-                // Modify or add a photo
-                else {
-                    for (int i = 0; i < photos.length(); i++) {
-                        JSONObject photo = (JSONObject) photos.get(i);
-                        String photoId = getJsonString(photo, "id");
-                        byte[] bytes = getPhotoBytes(getJsonString(photo, "value"));
-                        // This is a new photo so do a DB insert
-                        if (photoId == null) {
-                            ContentValues contentValues = new ContentValues();
-                            contentValues.put(ContactsContract.Data.RAW_CONTACT_ID, rawId);
-                            contentValues.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
-                            contentValues.put(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
-                            contentValues.put(ContactsContract.CommonDataKinds.Photo.PHOTO, bytes);
-
-                            ops.add(ContentProviderOperation.newInsert(
-                                    ContactsContract.Data.CONTENT_URI).withValues(contentValues).build());
-                        }
-                        // This is an existing photo so do a DB update
-                        else {
-                            ops.add(ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI)
-                                    .withSelection(ContactsContract.CommonDataKinds.Photo._ID + "=? AND " +
-                                            ContactsContract.Data.MIMETYPE + "=?",
-                                            new String[] { photoId, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE })
-                                    .withValue(ContactsContract.Data.IS_SUPER_PRIMARY, 1)
-                                    .withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, bytes)
-                                    .build());
-                        }
-                    }
-                }
-            }
-        } catch (JSONException e) {
-            Log.d(LOG_TAG, "Could not get photos");
-        }
-
-        boolean retVal = true;
-
-        //Modify contact
-        try {
-            mApp.getActivity().getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
-        } catch (RemoteException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-            Log.e(LOG_TAG, Log.getStackTraceString(e), e);
-            retVal = false;
-        } catch (OperationApplicationException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-            Log.e(LOG_TAG, Log.getStackTraceString(e), e);
-            retVal = false;
-        }
-
-        // if the save was a success return the contact ID
-        if (retVal) {
-            return id;
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Add a website to a list of database actions to be performed
-     *
-     * @param ops the list of database actions
-     * @param website the item to be inserted
-     */
-    private void insertWebsite(ArrayList<ContentProviderOperation> ops,
-            JSONObject website) {
-        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
-                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
-                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE)
-                .withValue(ContactsContract.CommonDataKinds.Website.DATA, getJsonString(website, "value"))
-                .withValue(ContactsContract.CommonDataKinds.Website.TYPE, getContactType(getJsonString(website, "type")))
-                .build());
-    }
-
-    /**
-     * Add an im to a list of database actions to be performed
-     *
-     * @param ops the list of database actions
-     * @param im the item to be inserted
-     */
-    private void insertIm(ArrayList<ContentProviderOperation> ops, JSONObject im) {
-        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
-                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
-                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Im.CONTENT_ITEM_TYPE)
-                .withValue(ContactsContract.CommonDataKinds.Im.DATA, getJsonString(im, "value"))
-                .withValue(ContactsContract.CommonDataKinds.Im.TYPE, getImType(getJsonString(im, "type")))
-                .build());
-    }
-
-    /**
-     * Add an organization to a list of database actions to be performed
-     *
-     * @param ops the list of database actions
-     * @param org the item to be inserted
-     */
-    private void insertOrganization(ArrayList<ContentProviderOperation> ops,
-            JSONObject org) {
-        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
-                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
-                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE)
-                .withValue(ContactsContract.CommonDataKinds.Organization.TYPE, getOrgType(getJsonString(org, "type")))
-                .withValue(ContactsContract.CommonDataKinds.Organization.DEPARTMENT, getJsonString(org, "department"))
-                .withValue(ContactsContract.CommonDataKinds.Organization.COMPANY, getJsonString(org, "name"))
-                .withValue(ContactsContract.CommonDataKinds.Organization.TITLE, getJsonString(org, "title"))
-                .build());
-    }
-
-    /**
-     * Add an address to a list of database actions to be performed
-     *
-     * @param ops the list of database actions
-     * @param address the item to be inserted
-     */
-    private void insertAddress(ArrayList<ContentProviderOperation> ops,
-            JSONObject address) {
-        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
-                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
-                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE)
-                .withValue(ContactsContract.CommonDataKinds.StructuredPostal.TYPE, getAddressType(getJsonString(address, "type")))
-                .withValue(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS, getJsonString(address, "formatted"))
-                .withValue(ContactsContract.CommonDataKinds.StructuredPostal.STREET, getJsonString(address, "streetAddress"))
-                .withValue(ContactsContract.CommonDataKinds.StructuredPostal.CITY, getJsonString(address, "locality"))
-                .withValue(ContactsContract.CommonDataKinds.StructuredPostal.REGION, getJsonString(address, "region"))
-                .withValue(ContactsContract.CommonDataKinds.StructuredPostal.POSTCODE, getJsonString(address, "postalCode"))
-                .withValue(ContactsContract.CommonDataKinds.StructuredPostal.COUNTRY, getJsonString(address, "country"))
-                .build());
-    }
-
-    /**
-     * Add an email to a list of database actions to be performed
-     *
-     * @param ops the list of database actions
-     * @param email the item to be inserted
-     */
-    private void insertEmail(ArrayList<ContentProviderOperation> ops,
-            JSONObject email) {
-        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
-                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
-                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
-                .withValue(ContactsContract.CommonDataKinds.Email.DATA, getJsonString(email, "value"))
-                .withValue(ContactsContract.CommonDataKinds.Email.TYPE, getContactType(getJsonString(email, "type")))
-                .build());
-    }
-
-    /**
-     * Add a phone to a list of database actions to be performed
-     *
-     * @param ops the list of database actions
-     * @param phone the item to be inserted
-     */
-    private void insertPhone(ArrayList<ContentProviderOperation> ops,
-            JSONObject phone) {
-        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
-                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
-                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
-                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, getJsonString(phone, "value"))
-                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, getPhoneType(getJsonString(phone, "type")))
-                .build());
-    }
-
-    /**
-     * Add a phone to a list of database actions to be performed
-     *
-     * @param ops the list of database actions
-     * @param phone the item to be inserted
-     */
-    private void insertPhoto(ArrayList<ContentProviderOperation> ops,
-            JSONObject photo) {
-        byte[] bytes = getPhotoBytes(getJsonString(photo, "value"));
-        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
-                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
-                .withValue(ContactsContract.Data.IS_SUPER_PRIMARY, 1)
-                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
-                .withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, bytes)
-                .build());
-    }
-
-    /**
-     * Gets the raw bytes from the supplied filename
-     *
-     * @param filename the file to read the bytes from
-     * @return a byte array
-     * @throws IOException
-     */
-    private byte[] getPhotoBytes(String filename) {
-        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-        try {
-            int bytesRead = 0;
-            long totalBytesRead = 0;
-            byte[] data = new byte[8192];
-            InputStream in = getPathFromUri(filename);
-
-            while ((bytesRead = in.read(data, 0, data.length)) != -1 && totalBytesRead <= MAX_PHOTO_SIZE) {
-                buffer.write(data, 0, bytesRead);
-                totalBytesRead += bytesRead;
-            }
-
-            in.close();
-            buffer.flush();
-        } catch (FileNotFoundException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        } catch (IOException e) {
-            Log.e(LOG_TAG, e.getMessage(), e);
-        }
-        return buffer.toByteArray();
-    }
-
-    /**
-       * Get an input stream based on file path or uri content://, http://, file://
-       *
-       * @param path
-       * @return an input stream
-     * @throws IOException
-       */
-    private InputStream getPathFromUri(String path) throws IOException {
-        if (path.startsWith("content:")) {
-            Uri uri = Uri.parse(path);
-            return mApp.getActivity().getContentResolver().openInputStream(uri);
-        }
-        if (path.startsWith("http:") || path.startsWith("https:") || path.startsWith("file:")) {
-            URL url = new URL(path);
-            return url.openStream();
-        }
-        else {
-            return new FileInputStream(path);
-        }
-    }
-
-    /**
-     * Creates a new contact and stores it in the database
-     *
-     * @param contact the contact to be saved
-     * @param account the account to be saved under
-     */
-    private String createNewContact(JSONObject contact, String accountType, String accountName) {
-        // Create a list of attributes to add to the contact database
-        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
-
-        //Add contact type
-        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
-                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, accountType)
-                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, accountName)
-                .build());
-
-        // Add name
-        try {
-            JSONObject name = contact.optJSONObject("name");
-            String displayName = contact.getString("displayName");
-            if (displayName != null || name != null) {
-                ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
-                        .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
-                        .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
-                        .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, displayName)
-                        .withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, getJsonString(name, "familyName"))
-                        .withValue(ContactsContract.CommonDataKinds.StructuredName.MIDDLE_NAME, getJsonString(name, "middleName"))
-                        .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, getJsonString(name, "givenName"))
-                        .withValue(ContactsContract.CommonDataKinds.StructuredName.PREFIX, getJsonString(name, "honorificPrefix"))
-                        .withValue(ContactsContract.CommonDataKinds.StructuredName.SUFFIX, getJsonString(name, "honorificSuffix"))
-                        .build());
-            }
-        } catch (JSONException e) {
-            Log.d(LOG_TAG, "Could not get name object");
-        }
-
-        //Add phone numbers
-        JSONArray phones = null;
-        try {
-            phones = contact.getJSONArray("phoneNumbers");
-            if (phones != null) {
-                for (int i = 0; i < phones.length(); i++) {
-                    JSONObject phone = (JSONObject) phones.get(i);
-                    insertPhone(ops, phone);
-                }
-            }
-        } catch (JSONException e) {
-            Log.d(LOG_TAG, "Could not get phone numbers");
-        }
-
-        // Add emails
-        JSONArray emails = null;
-        try {
-            emails = contact.getJSONArray("emails");
-            if (emails != null) {
-                for (int i = 0; i < emails.length(); i++) {
-                    JSONObject email = (JSONObject) emails.get(i);
-                    insertEmail(ops, email);
-                }
-            }
-        } catch (JSONException e) {
-            Log.d(LOG_TAG, "Could not get emails");
-        }
-
-        // Add addresses
-        JSONArray addresses = null;
-        try {
-            addresses = contact.getJSONArray("addresses");
-            if (addresses != null) {
-                for (int i = 0; i < addresses.length(); i++) {
-                    JSONObject address = (JSONObject) addresses.get(i);
-                    insertAddress(ops, address);
-                }
-            }
-        } catch (JSONException e) {
-            Log.d(LOG_TAG, "Could not get addresses");
-        }
-
-        // Add organizations
-        JSONArray organizations = null;
-        try {
-            organizations = contact.getJSONArray("organizations");
-            if (organizations != null) {
-                for (int i = 0; i < organizations.length(); i++) {
-                    JSONObject org = (JSONObject) organizations.get(i);
-                    insertOrganization(ops, org);
-                }
-            }
-        } catch (JSONException e) {
-            Log.d(LOG_TAG, "Could not get organizations");
-        }
-
-        // Add IMs
-        JSONArray ims = null;
-        try {
-            ims = contact.getJSONArray("ims");
-            if (ims != null) {
-                for (int i = 0; i < ims.length(); i++) {
-                    JSONObject im = (JSONObject) ims.get(i);
-                    insertIm(ops, im);
-                }
-            }
-        } catch (JSONException e) {
-            Log.d(LOG_TAG, "Could not get emails");
-        }
-
-        // Add note
-        String note = getJsonString(contact, "note");
-        if (note != null) {
-            ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
-                    .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
-                    .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Note.CONTENT_ITEM_TYPE)
-                    .withValue(ContactsContract.CommonDataKinds.Note.NOTE, note)
-                    .build());
-        }
-
-        // Add nickname
-        String nickname = getJsonString(contact, "nickname");
-        if (nickname != null) {
-            ops.add(ContentProviderOperati

<TRUNCATED>

[10/22] android commit: [CB-3340] - version script

Posted by st...@apache.org.
[CB-3340] - version script


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

Branch: refs/heads/3.0.0
Commit: 3917284f713c5073262e4020cf372858291d428d
Parents: 8bfd45c
Author: Tim Kim <ti...@adobe.com>
Authored: Mon May 13 15:30:16 2013 -0700
Committer: Tim Kim <ti...@adobe.com>
Committed: Mon May 13 15:30:16 2013 -0700

----------------------------------------------------------------------
 bin/templates/cordova/version |   32 ++++++++++++++++++++++++++++++++
 1 files changed, 32 insertions(+), 0 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/3917284f/bin/templates/cordova/version
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/version b/bin/templates/cordova/version
new file mode 100755
index 0000000..21147ab
--- /dev/null
+++ b/bin/templates/cordova/version
@@ -0,0 +1,32 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+CORDOVA_PATH=$( cd "$( dirname "$0" )" && pwd -P)
+PROJECT_PATH="$(dirname "$CORDOVA_PATH")"
+
+VERSION_FILE_PATH="$PROJECT_PATH/assets/www/cordova.js"
+
+if [ -f "$VERSION_FILE_PATH" ]; then
+    JSVersion=$(sed -n '2,2p' assets/www/cordova.js)
+    echo $JSVersion | sed -e 's/\/\/ //'| cut -f 1 -d '-'
+else
+    echo "The file \"$VERSION_FILE_PATH\" does not exist."
+    exit 1
+fi


[07/22] android commit: Added "DataResource" - allows many plugins to intercept a single request

Posted by st...@apache.org.
Added "DataResource" - allows many plugins to intercept a single request


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

Branch: refs/heads/3.0.0
Commit: 62c3e4652975f3e23a2f5a203dc13f7d4c98a30e
Parents: 8a95ed8
Author: Shravan Narayan <sh...@google.com>
Authored: Sat May 4 17:59:24 2013 -0400
Committer: Braden Shepherdson <br...@gmail.com>
Committed: Wed May 8 17:38:58 2013 -0400

----------------------------------------------------------------------
 framework/src/org/apache/cordova/FileHelper.java   |   58 ++++++-
 .../cordova/IceCreamCordovaWebViewClient.java      |   48 ++----
 .../src/org/apache/cordova/api/CordovaPlugin.java  |   14 ++
 .../src/org/apache/cordova/api/DataResource.java   |  138 +++++++++++++++
 .../apache/cordova/api/DataResourceContext.java    |   38 ++++
 .../src/org/apache/cordova/api/PluginManager.java  |   26 +++
 6 files changed, 287 insertions(+), 35 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/62c3e465/framework/src/org/apache/cordova/FileHelper.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileHelper.java b/framework/src/org/apache/cordova/FileHelper.java
index 8b446b0..81f32f0 100644
--- a/framework/src/org/apache/cordova/FileHelper.java
+++ b/framework/src/org/apache/cordova/FileHelper.java
@@ -26,10 +26,11 @@ import org.apache.cordova.api.CordovaInterface;
 import org.apache.cordova.api.LOG;
 
 import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.URLConnection;
-import java.util.Locale;
+import java.io.OutputStream;
 
 public class FileHelper {
     private static final String LOG_TAG = "FileUtils";
@@ -90,7 +91,7 @@ public class FileHelper {
      * @throws IOException
      */
     public static InputStream getInputStreamFromUriString(String uriString, CordovaInterface cordova) throws IOException {
-        if (uriString.startsWith("content")) {
+        if (uriString.startsWith("content:")) {
             Uri uri = Uri.parse(uriString);
             return cordova.getActivity().getContentResolver().openInputStream(uri);
         } else if (uriString.startsWith("file:///android_asset/")) {
@@ -102,6 +103,57 @@ public class FileHelper {
         }
     }
 
+    public static OutputStream getOutputStreamFromUriString(String uriString, CordovaInterface cordova) throws FileNotFoundException{
+        if (uriString.startsWith("content:")) {
+            Uri uri = Uri.parse(uriString);
+            return cordova.getActivity().getContentResolver().openOutputStream(uri);
+        } else if (uriString.startsWith("file:") && !uriString.startsWith("file:///android_asset/")) {
+            String realPath = uriString.substring(7);
+            return new FileOutputStream(realPath);
+        } else {
+            return null;
+        }
+    }
+    /**
+     * Returns whether the uri can be written to by openeing a File to that uri
+     *
+     * @param the URI to test
+     * @return boolean indicating whether the uri is writable
+     */
+    public static boolean isUriWritable(String uriString) {
+        String scheme = uriString.split(":")[0];
+        String writableSchemes[] = new String[]{ "content" };
+
+        if(scheme.equals("file")){
+            // special case file
+            if(uriString.startsWith("file:///android_asset/")){
+                return false;
+            } else {
+                return true;
+            }
+        }
+        for(int i = writableSchemes.length - 1; i >= 0 ; i--){
+            if(writableSchemes[i].equals(scheme)){
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Ensures the "file://" prefix exists for the given string
+     * If the given URI string has a "file://" prefix, it is returned unchanged
+     *
+     * @param path - the path string to operate on
+     * @return a String with the "file://" scheme set
+     */
+    public static String insertFileProtocol(String path) {
+        if(!path.matches("^[a-z0-9+.-]+:.*")){
+            path = "file://" + path;
+        }
+        return path;
+    }
+
     /**
      * Removes the "file://" prefix from the given URI string, if applicable.
      * If the given URI string doesn't have a "file://" prefix, it is returned unchanged.

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/62c3e465/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
index 847972e..c4c4d3e 100644
--- a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
+++ b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
@@ -19,9 +19,10 @@
 package org.apache.cordova;
 
 import java.io.IOException;
-import java.io.InputStream;
 
 import org.apache.cordova.api.CordovaInterface;
+import org.apache.cordova.api.DataResource;
+import org.apache.cordova.api.DataResourceContext;
 import org.apache.cordova.api.LOG;
 
 import android.annotation.TargetApi;
@@ -43,41 +44,24 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
 
     @Override
     public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
+        // We need to support the new DataResource intercepts without breaking the shouldInterceptRequest mechanism.
+        DataResource dataResource = DataResource.initiateNewDataRequestForUri(url, this.appView.pluginManager, cordova,
+                new DataResourceContext("WebViewClient.shouldInterceptRequest", true /* this is from a browser request*/));
+        url = dataResource.getUri().toString();
+
         //Check if plugins intercept the request
         WebResourceResponse ret = super.shouldInterceptRequest(view, url);
-        if(ret == null && (url.contains("?") || url.contains("#") || needsIceCreamSpaceInAssetUrlFix(url))){
-            ret = generateWebResourceResponse(url);
-        }
-        return ret;
-    }
-
-    private WebResourceResponse generateWebResourceResponse(String url) {
-        if (url.startsWith("file:///android_asset/")) {
-            String mimetype = FileHelper.getMimeType(url, cordova);
-
+//      The below bugfix is taken care of by the dataResource mechanism
+//        if(ret == null && (url.contains("?") || url.contains("#") || needsIceCreamSpaceInAssetUrlFix(url))){
+//            ret = generateWebResourceResponse(url);
+//        }
+        if(ret == null) {
             try {
-                InputStream stream = FileHelper.getInputStreamFromUriString(url, cordova);
-                WebResourceResponse response = new WebResourceResponse(mimetype, "UTF-8", stream);
-                return response;
-            } catch (IOException e) {
-                LOG.e("generateWebResourceResponse", e.getMessage(), e);
+                ret = new WebResourceResponse(dataResource.getMimeType(), "UTF-8", dataResource.getIs());
+            } catch(IOException e) {
+                LOG.e("IceCreamCordovaWebViewClient", "Error occurred while loading a file.", e);
             }
         }
-        return null;
-    }
-    
-    private static boolean needsIceCreamSpaceInAssetUrlFix(String url) {
-        if (!url.contains("%20")){
-            return false;
-        }
-
-        switch(android.os.Build.VERSION.SDK_INT){
-            case android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH:
-            case android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1:
-                return true;
-            default:
-                return false;
-        }
+        return ret;
     }
-    
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/62c3e465/framework/src/org/apache/cordova/api/CordovaPlugin.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/CordovaPlugin.java b/framework/src/org/apache/cordova/api/CordovaPlugin.java
index 2b225e6..69f8fde 100644
--- a/framework/src/org/apache/cordova/api/CordovaPlugin.java
+++ b/framework/src/org/apache/cordova/api/CordovaPlugin.java
@@ -176,6 +176,20 @@ public class CordovaPlugin {
     }
 
     /**
+     * All plugins can now choose if they want to modify any uri requests. This includes all webview requests, opening of files, content uri's etc.
+     * This mechanism allows several plugins to modify the same request
+     * @param requestSource The source of the incoming request
+     *
+     * @param dataResource          The resource to be loaded.
+     * @param dataResourceContext   Context associated with the resource load
+     * @return                      Return a new DataResource if the plugin wants o assist in loading the request or null if it doesn't.
+     */
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+    public DataResource shouldInterceptDataResourceRequest(DataResource dataResource, DataResourceContext dataResourceContext) {
+        return null;
+    }
+
+    /**
      * Called when the WebView does a top-level navigation or refreshes.
      *
      * Plugins should stop any long-running processes and clean up internal state.

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/62c3e465/framework/src/org/apache/cordova/api/DataResource.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/DataResource.java b/framework/src/org/apache/cordova/api/DataResource.java
new file mode 100644
index 0000000..8422b07
--- /dev/null
+++ b/framework/src/org/apache/cordova/api/DataResource.java
@@ -0,0 +1,138 @@
+package org.apache.cordova.api;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.cordova.FileHelper;
+
+import android.net.Uri;
+
+/*
+ * All requests to access files, browser network requests etc have to go through this class.
+ */
+public class DataResource {
+    private CordovaInterface cordova;
+
+    // Uri of the request. Always required.
+    private Uri uri;
+    // Remaining fields may or may not be null
+    private InputStream is;
+    private OutputStream os;
+    private String mimeType;
+    private Boolean writable;
+    private File realFile;
+    private boolean retryLoad = true;
+
+    public DataResource(CordovaInterface cordova, Uri uri) {
+        super();
+        this.cordova = cordova;
+        this.uri = uri;
+    }
+    public DataResource(CordovaInterface cordova, Uri uri, InputStream is,
+            OutputStream os, String mimeType, boolean writable, File realFile) {
+        this(cordova, uri);
+        this.is = is;
+        this.mimeType = mimeType;
+        this.writable = Boolean.valueOf(writable);
+        this.realFile = realFile;
+    }
+    public Uri getUri() {
+        // Uri is always provided
+        return uri;
+    }
+    public InputStream getIs() throws IOException {
+        if(is == null && retryLoad) {
+            try {
+                is = FileHelper.getInputStreamFromUriString(uri.toString(), cordova);
+            } finally {
+                // We failed loading once, don't try loading anymore
+                if(is == null) {
+                    retryLoad = false;
+                }
+            }
+        }
+        return is;
+    }
+    public OutputStream getOs() throws FileNotFoundException {
+        if(os == null && retryLoad) {
+            try {
+                os = FileHelper.getOutputStreamFromUriString(uri.toString(), cordova);
+            } finally {
+                // We failed loading once, don't try loading anymore
+                if(os == null) {
+                    retryLoad = false;
+                }
+            }
+        }
+        return os;
+    }
+    public String getMimeType() {
+        if(mimeType == null && retryLoad) {
+            try {
+                mimeType = FileHelper.getMimeType(uri.toString(), cordova);
+            } finally {
+                // We failed loading once, don't try loading anymore
+                if(mimeType == null) {
+                    retryLoad = false;
+                }
+            }
+        }
+        return mimeType;
+    }
+    public boolean isWritable() {
+        if(writable == null && retryLoad) {
+            try {
+                writable = FileHelper.isUriWritable(uri.toString());
+            } finally {
+                // We failed loading once, don't try loading anymore
+                if(writable == null) {
+                    retryLoad = false;
+                }
+            }
+        }
+        // default to false
+        return writable != null? writable.booleanValue() : false;
+    }
+    public File getRealFile() {
+        if(realFile == null && retryLoad) {
+            try {
+                String realPath = FileHelper.getRealPath(uri, cordova);
+                if(realPath != null) {
+                    realFile = new File(realPath);
+                }
+            } finally {
+                // We failed loading once, don't try loading anymore
+                if(realFile == null) {
+                    retryLoad = false;
+                }
+            }
+        }
+        return realFile;
+    }
+
+    // static instantiation methods
+    public static DataResource initiateNewDataRequestForUri(String uriString, PluginManager pluginManager, CordovaInterface cordova, String requestSourceTag){
+        // if no protocol is specified, assume its file:
+        uriString = FileHelper.insertFileProtocol(uriString);
+        return initiateNewDataRequestForUri(Uri.parse(uriString), pluginManager, cordova, requestSourceTag);
+    }
+    public static DataResource initiateNewDataRequestForUri(Uri uri, PluginManager pluginManager, CordovaInterface cordova, String requestSourceTag){
+        return initiateNewDataRequestForUri(uri, pluginManager, cordova, new DataResourceContext(requestSourceTag, false /* Assume, not a browser request by default */ ));
+    }
+    public static DataResource initiateNewDataRequestForUri(String uriString, PluginManager pluginManager, CordovaInterface cordova, DataResourceContext dataResourceContext){
+     // if no protocol is specified, assume its file:
+        uriString = FileHelper.insertFileProtocol(uriString);
+        return initiateNewDataRequestForUri(Uri.parse(uriString), pluginManager, cordova, dataResourceContext);
+    }
+    public static DataResource initiateNewDataRequestForUri(Uri uri, PluginManager pluginManager, CordovaInterface cordova, DataResourceContext dataResourceContext){
+        DataResource dataResource = new DataResource(cordova, uri);
+        if (pluginManager != null) {
+            // get the resource as returned by plugins
+            dataResource = pluginManager.shouldInterceptDataResourceRequest(dataResource, dataResourceContext);
+        }
+        return dataResource;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/62c3e465/framework/src/org/apache/cordova/api/DataResourceContext.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/DataResourceContext.java b/framework/src/org/apache/cordova/api/DataResourceContext.java
new file mode 100644
index 0000000..3c66817
--- /dev/null
+++ b/framework/src/org/apache/cordova/api/DataResourceContext.java
@@ -0,0 +1,38 @@
+package org.apache.cordova.api;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+/*
+ * Some context information associated with a DataRequest.
+ */
+public class DataResourceContext {
+    // A random id that is unique for a particular request.
+    private int requestId;
+    // A tag associated with the source of this dataResourceContext
+    private String source;
+    // If needed, any data associated with core plugins can be a part of the context object
+    // This field indicates whether the request came from a browser network request
+    private boolean isFromBrowser;
+    // If needed, any data associated with non core plugins  should store data in a Map so as to not clutter the context object
+    private Map<String, Object> dataMap;
+    public DataResourceContext(String source, boolean isFromBrowser) {
+        super();
+        this.requestId = new Random().nextInt();
+        this.source = source;
+        this.isFromBrowser = isFromBrowser;
+        this.dataMap = new HashMap<String, Object>();
+    }
+    public int getRequestId() {
+        return requestId;
+    }
+    public String getSource() {
+        return source;
+    }
+    public boolean isFromBrowser() {
+        return isFromBrowser;
+    }
+    public Map<String, Object> getDataMap() {
+        return dataMap;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/62c3e465/framework/src/org/apache/cordova/api/PluginManager.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/api/PluginManager.java b/framework/src/org/apache/cordova/api/PluginManager.java
index 36e286e..6bad5ed 100755
--- a/framework/src/org/apache/cordova/api/PluginManager.java
+++ b/framework/src/org/apache/cordova/api/PluginManager.java
@@ -400,4 +400,30 @@ public class PluginManager {
         LOG.e(TAG, "https://git-wip-us.apache.org/repos/asf?p=incubator-cordova-android.git;a=blob;f=framework/res/xml/plugins.xml");
         LOG.e(TAG, "=====================================================================================");
     }
+
+    /**
+     * Called when the any resource is going to be loaded - either from the webview, files or any other resource
+     *
+     *
+     * @param dataResource          The resource request to be loaded.
+     * @param dataResourceContext   The context of the dataResource request
+     * @return                      Return the resource request that will be loaded. The returned request may be modified or unchanged.
+     */
+    public DataResource shouldInterceptDataResourceRequest(DataResource dataResource, DataResourceContext dataResourceContext){
+        boolean requestModified = true;
+        while(requestModified) {
+            requestModified = false;
+            for (PluginEntry entry : this.entries.values()) {
+                if (entry.plugin != null) {
+                    DataResource ret = entry.plugin.shouldInterceptDataResourceRequest(dataResource, dataResourceContext);
+                    if(ret != null) {
+                        dataResource = ret;
+                        requestModified = true;
+                        break;
+                    }
+                }
+            }
+        }
+        return dataResource;
+    }
 }


[17/22] ripped out plugins

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/HttpHandler.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/HttpHandler.java b/framework/src/org/apache/cordova/HttpHandler.java
deleted file mode 100755
index 1de8302..0000000
--- a/framework/src/org/apache/cordova/HttpHandler.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
-       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.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.DefaultHttpClient;
-
-public class HttpHandler {
-
-    protected Boolean get(String url, String file)
-    {
-        HttpEntity entity = getHttpEntity(url);
-        try {
-            writeToDisk(entity, file);
-        } catch (Exception e) {
-            e.printStackTrace();
-            return false;
-        }
-        try {
-            entity.consumeContent();
-        } catch (Exception e) {
-            e.printStackTrace();
-            return false;
-        }
-        return true;
-    }
-
-    private HttpEntity getHttpEntity(String url)
-    /**
-     * get the http entity at a given url
-     */
-    {
-        HttpEntity entity = null;
-        try {
-            DefaultHttpClient httpclient = new DefaultHttpClient();
-            HttpGet httpget = new HttpGet(url);
-            HttpResponse response = httpclient.execute(httpget);
-            entity = response.getEntity();
-        } catch (Exception e) { e.printStackTrace(); return null; }
-        return entity;
-    }
-
-    private void writeToDisk(HttpEntity entity, String file) throws IllegalStateException, IOException
-    /**
-     * writes a HTTP entity to the specified filename and location on disk
-     */
-    {
-        //int i = 0;
-        String FilePath = "/sdcard/" + file;
-        InputStream in = entity.getContent();
-        byte buff[] = new byte[1024];
-        FileOutputStream out =
-                new FileOutputStream(FilePath);
-       do {
-            int numread = in.read(buff);
-            if (numread <= 0)
-                break;
-            out.write(buff, 0, numread);
-            //i++;
-        } while (true);
-        out.flush();
-        out.close();
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/InAppBrowser.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/InAppBrowser.java b/framework/src/org/apache/cordova/InAppBrowser.java
deleted file mode 100644
index 8e78baa..0000000
--- a/framework/src/org/apache/cordova/InAppBrowser.java
+++ /dev/null
@@ -1,813 +0,0 @@
-/*
-       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.util.HashMap;
-import java.util.StringTokenizer;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.LOG;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.annotation.SuppressLint;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.net.Uri;
-import android.os.Bundle;
-import android.text.InputType;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.WindowManager.LayoutParams;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.webkit.WebChromeClient;
-import android.webkit.GeolocationPermissions.Callback;
-import android.webkit.JsPromptResult;
-import android.webkit.WebSettings;
-import android.webkit.WebStorage;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-
-@SuppressLint("SetJavaScriptEnabled")
-public class InAppBrowser extends CordovaPlugin {
-
-    private static final String NULL = "null";
-    protected static final String LOG_TAG = "InAppBrowser";
-    private static final String SELF = "_self";
-    private static final String SYSTEM = "_system";
-    // private static final String BLANK = "_blank";
-    private static final String LOCATION = "location";
-    private static final String EXIT_EVENT = "exit";
-    private static final String LOAD_START_EVENT = "loadstart";
-    private static final String LOAD_STOP_EVENT = "loadstop";
-    private static final String LOAD_ERROR_EVENT = "loaderror";
-    private static final String CLOSE_BUTTON_CAPTION = "closebuttoncaption";
-    private long MAX_QUOTA = 100 * 1024 * 1024;
-
-    private Dialog dialog;
-    private WebView inAppWebView;
-    private EditText edittext;
-    private boolean showLocationBar = true;
-    private CallbackContext callbackContext;
-    private String buttonLabel = "Done";
-    
-    /**
-     * Executes the request and returns PluginResult.
-     *
-     * @param action        The action to execute.
-     * @param args          JSONArry of arguments for the plugin.
-     * @param callbackId    The callback id used when calling back into JavaScript.
-     * @return              A PluginResult object with a status and message.
-     */
-    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
-        try {
-            if (action.equals("open")) {
-                this.callbackContext = callbackContext;
-                String url = args.getString(0);
-                String target = args.optString(1);
-                if (target == null || target.equals("") || target.equals(NULL)) {
-                    target = SELF;
-                }
-                HashMap<String, Boolean> features = parseFeature(args.optString(2));
-                
-                Log.d(LOG_TAG, "target = " + target);
-
-                url = updateUrl(url);
-                String result = "";
-
-                // SELF
-                if (SELF.equals(target)) {
-                    Log.d(LOG_TAG, "in self");
-                    // load in webview
-                    if (url.startsWith("file://") || url.startsWith("javascript:") 
-                            || Config.isUrlWhiteListed(url)) {
-                        this.webView.loadUrl(url);
-                    }
-                    //Load the dialer
-                    else if (url.startsWith(WebView.SCHEME_TEL))
-                    {
-                        try {
-                            Intent intent = new Intent(Intent.ACTION_DIAL);
-                            intent.setData(Uri.parse(url));
-                            this.cordova.getActivity().startActivity(intent);
-                        } catch (android.content.ActivityNotFoundException e) {
-                            LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
-                        }
-                    }
-                    // load in InAppBrowser
-                    else {
-                        result = this.showWebPage(url, features);
-                    }
-                }
-                // SYSTEM
-                else if (SYSTEM.equals(target)) {
-                    Log.d(LOG_TAG, "in system");
-                    result = this.openExternal(url);
-                }
-                // BLANK - or anything else
-                else {
-                    Log.d(LOG_TAG, "in blank");
-                    result = this.showWebPage(url, features);
-                }
-
-                PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, result);
-                pluginResult.setKeepCallback(true);
-                this.callbackContext.sendPluginResult(pluginResult);
-            }
-            else if (action.equals("close")) {
-                closeDialog();
-                this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK));
-            }
-            else if (action.equals("injectScriptCode")) {
-                String jsWrapper = null;
-                if (args.getBoolean(1)) {
-                    jsWrapper = String.format("prompt(JSON.stringify([eval(%%s)]), 'gap-iab://%s')", callbackContext.getCallbackId());
-                }
-                injectDeferredObject(args.getString(0), jsWrapper);
-            }
-            else if (action.equals("injectScriptFile")) {
-                String jsWrapper;
-                if (args.getBoolean(1)) {
-                    jsWrapper = String.format("(function(d) { var c = d.createElement('script'); c.src = %%s; c.onload = function() { prompt('', 'gap-iab://%s'); }; d.body.appendChild(c); })(document)", callbackContext.getCallbackId());
-                } else {
-                    jsWrapper = "(function(d) { var c = d.createElement('script'); c.src = %s; d.body.appendChild(c); })(document)";
-                }
-                injectDeferredObject(args.getString(0), jsWrapper);
-            }
-            else if (action.equals("injectStyleCode")) {
-                String jsWrapper;
-                if (args.getBoolean(1)) {
-                    jsWrapper = String.format("(function(d) { var c = d.createElement('style'); c.innerHTML = %%s; d.body.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
-                } else {
-                    jsWrapper = "(function(d) { var c = d.createElement('style'); c.innerHTML = %s; d.body.appendChild(c); })(document)";
-                }
-                injectDeferredObject(args.getString(0), jsWrapper);
-            }
-            else if (action.equals("injectStyleFile")) {
-                String jsWrapper;
-                if (args.getBoolean(1)) {
-                    jsWrapper = String.format("(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %%s; d.head.appendChild(c); prompt('', 'gap-iab://%s');})(document)", callbackContext.getCallbackId());
-                } else {
-                    jsWrapper = "(function(d) { var c = d.createElement('link'); c.rel='stylesheet'; c.type='text/css'; c.href = %s; d.head.appendChild(c); })(document)";
-                }
-                injectDeferredObject(args.getString(0), jsWrapper);
-            }
-            else {
-                return false;
-            }
-        } catch (JSONException e) {
-            this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
-        }
-        return true;
-    }
-
-    /**
-     * Inject an object (script or style) into the InAppBrowser WebView.
-     *
-     * This is a helper method for the inject{Script|Style}{Code|File} API calls, which
-     * provides a consistent method for injecting JavaScript code into the document.
-     *
-     * If a wrapper string is supplied, then the source string will be JSON-encoded (adding
-     * quotes) and wrapped using string formatting. (The wrapper string should have a single
-     * '%s' marker)
-     *
-     * @param source      The source object (filename or script/style text) to inject into
-     *                    the document.
-     * @param jsWrapper   A JavaScript string to wrap the source string in, so that the object
-     *                    is properly injected, or null if the source string is JavaScript text
-     *                    which should be executed directly.
-     */
-    private void injectDeferredObject(String source, String jsWrapper) {
-        String scriptToInject;
-        if (jsWrapper != null) {
-            org.json.JSONArray jsonEsc = new org.json.JSONArray();
-            jsonEsc.put(source);
-            String jsonRepr = jsonEsc.toString();
-            String jsonSourceString = jsonRepr.substring(1, jsonRepr.length()-1);
-            scriptToInject = String.format(jsWrapper, jsonSourceString);
-        } else {
-            scriptToInject = source;
-        }
-        // This action will have the side-effect of blurring the currently focused element
-        this.inAppWebView.loadUrl("javascript:" + scriptToInject);
-    }
-
-    /**
-     * Put the list of features into a hash map
-     * 
-     * @param optString
-     * @return
-     */
-    private HashMap<String, Boolean> parseFeature(String optString) {
-        if (optString.equals(NULL)) {
-            return null;
-        } else {
-            HashMap<String, Boolean> map = new HashMap<String, Boolean>();
-            StringTokenizer features = new StringTokenizer(optString, ",");
-            StringTokenizer option;
-            while(features.hasMoreElements()) {
-                option = new StringTokenizer(features.nextToken(), "=");
-                if (option.hasMoreElements()) {
-                    String key = option.nextToken();
-                    if (key.equalsIgnoreCase(CLOSE_BUTTON_CAPTION)) {
-                        this.buttonLabel = option.nextToken();
-                    } else {
-                        Boolean value = option.nextToken().equals("no") ? Boolean.FALSE : Boolean.TRUE;
-                        map.put(key, value);
-                    }
-                }
-            }
-            return map;
-        }
-    }
-
-    /**
-     * Convert relative URL to full path
-     * 
-     * @param url
-     * @return 
-     */
-    private String updateUrl(String url) {
-        Uri newUrl = Uri.parse(url);
-        if (newUrl.isRelative()) {
-            url = this.webView.getUrl().substring(0, this.webView.getUrl().lastIndexOf("/")+1) + url;
-        }
-        return url;
-    }
-
-    /**
-     * Display a new browser with the specified URL.
-     *
-     * @param url           The url to load.
-     * @param usePhoneGap   Load url in PhoneGap webview
-     * @return              "" if ok, or error message.
-     */
-    public String openExternal(String url) {
-        try {
-            Intent intent = null;
-            intent = new Intent(Intent.ACTION_VIEW);
-            intent.setData(Uri.parse(url));
-            this.cordova.getActivity().startActivity(intent);
-            return "";
-        } catch (android.content.ActivityNotFoundException e) {
-            Log.d(LOG_TAG, "InAppBrowser: Error loading url "+url+":"+ e.toString());
-            return e.toString();
-        }
-    }
-
-    /**
-     * Closes the dialog
-     */
-    private void closeDialog() {
-        try {
-            this.inAppWebView.loadUrl("about:blank");
-            JSONObject obj = new JSONObject();
-            obj.put("type", EXIT_EVENT);
-
-            sendUpdate(obj, false);
-        } catch (JSONException ex) {
-            Log.d(LOG_TAG, "Should never happen");
-        }
-        
-        if (dialog != null) {
-            dialog.dismiss();
-        }
-    }
-
-    /**
-     * Checks to see if it is possible to go back one page in history, then does so.
-     */
-    private void goBack() {
-        if (this.inAppWebView.canGoBack()) {
-            this.inAppWebView.goBack();
-        }
-    }
-
-    /**
-     * Checks to see if it is possible to go forward one page in history, then does so.
-     */
-    private void goForward() {
-        if (this.inAppWebView.canGoForward()) {
-            this.inAppWebView.goForward();
-        }
-    }
-
-    /**
-     * Navigate to the new page
-     *
-     * @param url to load
-     */
-    private void navigate(String url) {
-        InputMethodManager imm = (InputMethodManager)this.cordova.getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
-        imm.hideSoftInputFromWindow(edittext.getWindowToken(), 0);
-
-        if (!url.startsWith("http") && !url.startsWith("file:")) {
-            this.inAppWebView.loadUrl("http://" + url);
-        } else {
-            this.inAppWebView.loadUrl(url);
-        }
-        this.inAppWebView.requestFocus();
-    }
-
-
-    /**
-     * Should we show the location bar?
-     *
-     * @return boolean
-     */
-    private boolean getShowLocationBar() {
-        return this.showLocationBar;
-    }
-
-    /**
-     * Display a new browser with the specified URL.
-     *
-     * @param url           The url to load.
-     * @param jsonObject
-     */
-    public String showWebPage(final String url, HashMap<String, Boolean> features) {
-        // Determine if we should hide the location bar.
-        showLocationBar = true;
-        if (features != null) {
-            Boolean show = features.get(LOCATION);
-            if (show != null) {
-                showLocationBar = show.booleanValue();
-            }
-        }
-        
-        final CordovaWebView thatWebView = this.webView;
-
-        // Create dialog in new thread
-        Runnable runnable = new Runnable() {
-            /**
-             * Convert our DIP units to Pixels
-             *
-             * @return int
-             */
-            private int dpToPixels(int dipValue) {
-                int value = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP,
-                                                            (float) dipValue,
-                                                            cordova.getActivity().getResources().getDisplayMetrics()
-                );
-
-                return value;
-            }
-
-            public void run() {
-                // Let's create the main dialog
-                dialog = new Dialog(cordova.getActivity(), android.R.style.Theme_NoTitleBar);
-                dialog.getWindow().getAttributes().windowAnimations = android.R.style.Animation_Dialog;
-                dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
-                dialog.setCancelable(true);
-                dialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
-                        public void onDismiss(DialogInterface dialog) {
-                            try {
-                                JSONObject obj = new JSONObject();
-                                obj.put("type", EXIT_EVENT);
-
-                                sendUpdate(obj, false);
-                            } catch (JSONException e) {
-                                Log.d(LOG_TAG, "Should never happen");
-                            }
-                        }
-                });
-
-                // Main container layout
-                LinearLayout main = new LinearLayout(cordova.getActivity());
-                main.setOrientation(LinearLayout.VERTICAL);
-
-                // Toolbar layout
-                RelativeLayout toolbar = new RelativeLayout(cordova.getActivity());
-                toolbar.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, this.dpToPixels(44)));
-                toolbar.setPadding(this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2), this.dpToPixels(2));
-                toolbar.setHorizontalGravity(Gravity.LEFT);
-                toolbar.setVerticalGravity(Gravity.TOP);
-
-                // Action Button Container layout
-                RelativeLayout actionButtonContainer = new RelativeLayout(cordova.getActivity());
-                actionButtonContainer.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
-                actionButtonContainer.setHorizontalGravity(Gravity.LEFT);
-                actionButtonContainer.setVerticalGravity(Gravity.CENTER_VERTICAL);
-                actionButtonContainer.setId(1);
-
-                // Back button
-                Button back = new Button(cordova.getActivity());
-                RelativeLayout.LayoutParams backLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
-                backLayoutParams.addRule(RelativeLayout.ALIGN_LEFT);
-                back.setLayoutParams(backLayoutParams);
-                back.setContentDescription("Back Button");
-                back.setId(2);
-                back.setText("<");
-                back.setOnClickListener(new View.OnClickListener() {
-                    public void onClick(View v) {
-                        goBack();
-                    }
-                });
-
-                // Forward button
-                Button forward = new Button(cordova.getActivity());
-                RelativeLayout.LayoutParams forwardLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
-                forwardLayoutParams.addRule(RelativeLayout.RIGHT_OF, 2);
-                forward.setLayoutParams(forwardLayoutParams);
-                forward.setContentDescription("Forward Button");
-                forward.setId(3);
-                forward.setText(">");
-                forward.setOnClickListener(new View.OnClickListener() {
-                    public void onClick(View v) {
-                        goForward();
-                    }
-                });
-
-                // Edit Text Box
-                edittext = new EditText(cordova.getActivity());
-                RelativeLayout.LayoutParams textLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
-                textLayoutParams.addRule(RelativeLayout.RIGHT_OF, 1);
-                textLayoutParams.addRule(RelativeLayout.LEFT_OF, 5);
-                edittext.setLayoutParams(textLayoutParams);
-                edittext.setId(4);
-                edittext.setSingleLine(true);
-                edittext.setText(url);
-                edittext.setInputType(InputType.TYPE_TEXT_VARIATION_URI);
-                edittext.setImeOptions(EditorInfo.IME_ACTION_GO);
-                edittext.setInputType(InputType.TYPE_NULL); // Will not except input... Makes the text NON-EDITABLE
-                edittext.setOnKeyListener(new View.OnKeyListener() {
-                    public boolean onKey(View v, int keyCode, KeyEvent event) {
-                        // If the event is a key-down event on the "enter" button
-                        if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
-                          navigate(edittext.getText().toString());
-                          return true;
-                        }
-                        return false;
-                    }
-                });
-
-                // Close button
-                Button close = new Button(cordova.getActivity());
-                RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
-                closeLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
-                close.setLayoutParams(closeLayoutParams);
-                forward.setContentDescription("Close Button");
-                close.setId(5);
-                close.setText(buttonLabel);
-                close.setOnClickListener(new View.OnClickListener() {
-                    public void onClick(View v) {
-                        closeDialog();
-                    }
-                });
-
-                // WebView
-                inAppWebView = new WebView(cordova.getActivity());
-                inAppWebView.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
-                inAppWebView.setWebChromeClient(new InAppChromeClient(thatWebView));
-                WebViewClient client = new InAppBrowserClient(thatWebView, edittext);
-                inAppWebView.setWebViewClient(client);
-                WebSettings settings = inAppWebView.getSettings();
-                settings.setJavaScriptEnabled(true);
-                settings.setJavaScriptCanOpenWindowsAutomatically(true);
-                settings.setBuiltInZoomControls(true);
-                /** 
-                 * We need to be careful of this line as a future Android release may deprecate it out of existence.
-                 * Can't replace it with the API 8 level call right now as our minimum SDK is 7 until May 2013
-                 */
-                // @TODO: replace with settings.setPluginState(android.webkit.WebSettings.PluginState.ON)
-                settings.setPluginsEnabled(true);
-                
-                //Toggle whether this is enabled or not!
-                Bundle appSettings = cordova.getActivity().getIntent().getExtras();
-                boolean enableDatabase = appSettings == null ? true : appSettings.getBoolean("InAppBrowserStorageEnabled", true);
-                if(enableDatabase)
-                {
-                    String databasePath = cordova.getActivity().getApplicationContext().getDir("inAppBrowserDB", Context.MODE_PRIVATE).getPath();
-                    settings.setDatabasePath(databasePath);
-                    settings.setDatabaseEnabled(true);
-                }
-                settings.setDomStorageEnabled(true);
-               
-                inAppWebView.loadUrl(url);
-                inAppWebView.setId(6);
-                inAppWebView.getSettings().setLoadWithOverviewMode(true);
-                inAppWebView.getSettings().setUseWideViewPort(true);
-                inAppWebView.requestFocus();
-                inAppWebView.requestFocusFromTouch();
-
-                // Add the back and forward buttons to our action button container layout
-                actionButtonContainer.addView(back);
-                actionButtonContainer.addView(forward);
-
-                // Add the views to our toolbar
-                toolbar.addView(actionButtonContainer);
-                toolbar.addView(edittext);
-                toolbar.addView(close);
-
-                // Don't add the toolbar if its been disabled
-                if (getShowLocationBar()) {
-                    // Add our toolbar to our main view/layout
-                    main.addView(toolbar);
-                }
-
-                // Add our webview to our main view/layout
-                main.addView(inAppWebView);
-
-                WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
-                lp.copyFrom(dialog.getWindow().getAttributes());
-                lp.width = WindowManager.LayoutParams.MATCH_PARENT;
-                lp.height = WindowManager.LayoutParams.MATCH_PARENT;
-
-                dialog.setContentView(main);
-                dialog.show();
-                dialog.getWindow().setAttributes(lp);
-            }
-        };
-        this.cordova.getActivity().runOnUiThread(runnable);
-        return "";
-    }
-
-    /**
-     * Create a new plugin success result and send it back to JavaScript
-     *
-     * @param obj a JSONObject contain event payload information
-     */
-    private void sendUpdate(JSONObject obj, boolean keepCallback) {
-        sendUpdate(obj, keepCallback, PluginResult.Status.OK);
-    }
-
-    /**
-     * Create a new plugin result and send it back to JavaScript
-     *
-     * @param obj a JSONObject contain event payload information
-     * @param status the status code to return to the JavaScript environment
-     */    private void sendUpdate(JSONObject obj, boolean keepCallback, PluginResult.Status status) {
-        PluginResult result = new PluginResult(status, obj);
-        result.setKeepCallback(keepCallback);
-        this.callbackContext.sendPluginResult(result);
-    }
-
-    public class InAppChromeClient extends WebChromeClient {
-
-        private CordovaWebView webView;
-
-        public InAppChromeClient(CordovaWebView webView) {
-            super();
-            this.webView = webView;
-        }
-        /**
-         * Handle database quota exceeded notification.
-         *
-         * @param url
-         * @param databaseIdentifier
-         * @param currentQuota
-         * @param estimatedSize
-         * @param totalUsedQuota
-         * @param quotaUpdater
-         */
-        @Override
-        public void onExceededDatabaseQuota(String url, String databaseIdentifier, long currentQuota, long estimatedSize,
-                long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater)
-        {
-            LOG.d(LOG_TAG, "onExceededDatabaseQuota estimatedSize: %d  currentQuota: %d  totalUsedQuota: %d", estimatedSize, currentQuota, totalUsedQuota);
-
-            if (estimatedSize < MAX_QUOTA)
-            {
-                //increase for 1Mb
-                long newQuota = estimatedSize;
-                LOG.d(LOG_TAG, "calling quotaUpdater.updateQuota newQuota: %d", newQuota);
-                quotaUpdater.updateQuota(newQuota);
-            }
-            else
-            {
-                // Set the quota to whatever it is and force an error
-                // TODO: get docs on how to handle this properly
-                quotaUpdater.updateQuota(currentQuota);
-            }
-        }
-
-        /**
-         * Instructs the client to show a prompt to ask the user to set the Geolocation permission state for the specified origin.
-         *
-         * @param origin
-         * @param callback
-         */
-        @Override
-        public void onGeolocationPermissionsShowPrompt(String origin, Callback callback) {
-            super.onGeolocationPermissionsShowPrompt(origin, callback);
-            callback.invoke(origin, true, false);
-        }
-
-        /**
-         * Tell the client to display a prompt dialog to the user.
-         * If the client returns true, WebView will assume that the client will
-         * handle the prompt dialog and call the appropriate JsPromptResult method.
-         *
-         * The prompt bridge provided for the InAppBrowser is capable of executing any
-         * oustanding callback belonging to the InAppBrowser plugin. Care has been
-         * taken that other callbacks cannot be triggered, and that no other code
-         * execution is possible.
-         *
-         * To trigger the bridge, the prompt default value should be of the form:
-         *
-         * gap-iab://<callbackId>
-         *
-         * where <callbackId> is the string id of the callback to trigger (something
-         * like "InAppBrowser0123456789")
-         *
-         * If present, the prompt message is expected to be a JSON-encoded value to
-         * pass to the callback. A JSON_EXCEPTION is returned if the JSON is invalid.
-         *
-         * @param view
-         * @param url
-         * @param message
-         * @param defaultValue
-         * @param result
-         */
-        @Override
-        public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
-            // See if the prompt string uses the 'gap-iab' protocol. If so, the remainder should be the id of a callback to execute.
-            if (defaultValue != null && defaultValue.startsWith("gap-iab://")) {
-                PluginResult scriptResult;
-                String scriptCallbackId = defaultValue.substring(10);
-                if (scriptCallbackId.startsWith("InAppBrowser")) {
-                    if(message == null || message.length() == 0) {
-                        scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray());
-                    } else {
-                        try {
-                            scriptResult = new PluginResult(PluginResult.Status.OK, new JSONArray(message));
-                        } catch(JSONException e) {
-                            scriptResult = new PluginResult(PluginResult.Status.JSON_EXCEPTION, e.getMessage());
-                        }
-                    }
-                    this.webView.sendPluginResult(scriptResult, scriptCallbackId);
-                    result.confirm("");
-                    return true;
-                }
-            }
-            return false;
-        }
-
-    }
-    
-    /**
-     * The webview client receives notifications about appView
-     */
-    public class InAppBrowserClient extends WebViewClient {
-        EditText edittext;
-        CordovaWebView webView;
-
-        /**
-         * Constructor.
-         *
-         * @param mContext
-         * @param edittext
-         */
-        public InAppBrowserClient(CordovaWebView webView, EditText mEditText) {
-            this.webView = webView;
-            this.edittext = mEditText;
-        }
-
-        /**
-         * Notify the host application that a page has started loading.
-         *
-         * @param view          The webview initiating the callback.
-         * @param url           The url of the page.
-         */
-        @Override
-        public void onPageStarted(WebView view, String url,  Bitmap favicon) {
-            super.onPageStarted(view, url, favicon);
-            String newloc = "";
-            if (url.startsWith("http:") || url.startsWith("https:") || url.startsWith("file:")) {
-                newloc = url;
-            } 
-            // If dialing phone (tel:5551212)
-            else if (url.startsWith(WebView.SCHEME_TEL)) {
-                try {
-                    Intent intent = new Intent(Intent.ACTION_DIAL);
-                    intent.setData(Uri.parse(url));
-                    cordova.getActivity().startActivity(intent);
-                } catch (android.content.ActivityNotFoundException e) {
-                    LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
-                }
-            }
-
-            else if (url.startsWith("geo:") || url.startsWith(WebView.SCHEME_MAILTO) || url.startsWith("market:")) {
-                try {
-                    Intent intent = new Intent(Intent.ACTION_VIEW);
-                    intent.setData(Uri.parse(url));
-                    cordova.getActivity().startActivity(intent);
-                } catch (android.content.ActivityNotFoundException e) {
-                    LOG.e(LOG_TAG, "Error with " + url + ": " + e.toString());
-                }
-            }
-            // If sms:5551212?body=This is the message
-            else if (url.startsWith("sms:")) {
-                try {
-                    Intent intent = new Intent(Intent.ACTION_VIEW);
-
-                    // Get address
-                    String address = null;
-                    int parmIndex = url.indexOf('?');
-                    if (parmIndex == -1) {
-                        address = url.substring(4);
-                    }
-                    else {
-                        address = url.substring(4, parmIndex);
-
-                        // If body, then set sms body
-                        Uri uri = Uri.parse(url);
-                        String query = uri.getQuery();
-                        if (query != null) {
-                            if (query.startsWith("body=")) {
-                                intent.putExtra("sms_body", query.substring(5));
-                            }
-                        }
-                    }
-                    intent.setData(Uri.parse("sms:" + address));
-                    intent.putExtra("address", address);
-                    intent.setType("vnd.android-dir/mms-sms");
-                    cordova.getActivity().startActivity(intent);
-                } catch (android.content.ActivityNotFoundException e) {
-                    LOG.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
-                }
-            }
-            else {
-                newloc = "http://" + url;
-            }
-
-            if (!newloc.equals(edittext.getText().toString())) {
-                edittext.setText(newloc);
-            }
-
-            try {
-                JSONObject obj = new JSONObject();
-                obj.put("type", LOAD_START_EVENT);
-                obj.put("url", newloc);
-    
-                sendUpdate(obj, true);
-            } catch (JSONException ex) {
-                Log.d(LOG_TAG, "Should never happen");
-            }
-        }
-        
-        public void onPageFinished(WebView view, String url) {
-            super.onPageFinished(view, url);
-            
-            try {
-                JSONObject obj = new JSONObject();
-                obj.put("type", LOAD_STOP_EVENT);
-                obj.put("url", url);
-    
-                sendUpdate(obj, true);
-            } catch (JSONException ex) {
-                Log.d(LOG_TAG, "Should never happen");
-            }
-        }
-        
-        public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
-            super.onReceivedError(view, errorCode, description, failingUrl);
-            
-            try {
-                JSONObject obj = new JSONObject();
-                obj.put("type", LOAD_ERROR_EVENT);
-                obj.put("url", failingUrl);
-                obj.put("code", errorCode);
-                obj.put("message", description);
-    
-                sendUpdate(obj, true, PluginResult.Status.ERROR);
-            } catch (JSONException ex) {
-                Log.d(LOG_TAG, "Should never happen");
-            }
-        	
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/NetworkListener.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/NetworkListener.java b/framework/src/org/apache/cordova/NetworkListener.java
deleted file mode 100755
index 7d19259..0000000
--- a/framework/src/org/apache/cordova/NetworkListener.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
-       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 android.location.LocationManager;
-
-/**
- * This class handles requests for GPS location services.
- *
- */
-public class NetworkListener extends CordovaLocationListener {
-    public NetworkListener(LocationManager locationManager, GeoBroker m) {
-        super(locationManager, m, "[Cordova NetworkListener]");
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/NetworkManager.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/NetworkManager.java b/framework/src/org/apache/cordova/NetworkManager.java
deleted file mode 100755
index bb4743f..0000000
--- a/framework/src/org/apache/cordova/NetworkManager.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
-       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.api.CallbackContext;
-import org.apache.cordova.api.CordovaInterface;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.util.Log;
-
-public class NetworkManager extends CordovaPlugin {
-
-    public static int NOT_REACHABLE = 0;
-    public static int REACHABLE_VIA_CARRIER_DATA_NETWORK = 1;
-    public static int REACHABLE_VIA_WIFI_NETWORK = 2;
-
-    public static final String WIFI = "wifi";
-    public static final String WIMAX = "wimax";
-    // mobile
-    public static final String MOBILE = "mobile";
-    // 2G network types
-    public static final String GSM = "gsm";
-    public static final String GPRS = "gprs";
-    public static final String EDGE = "edge";
-    // 3G network types
-    public static final String CDMA = "cdma";
-    public static final String UMTS = "umts";
-    public static final String HSPA = "hspa";
-    public static final String HSUPA = "hsupa";
-    public static final String HSDPA = "hsdpa";
-    public static final String ONEXRTT = "1xrtt";
-    public static final String EHRPD = "ehrpd";
-    // 4G network types
-    public static final String LTE = "lte";
-    public static final String UMB = "umb";
-    public static final String HSPA_PLUS = "hspa+";
-    // return type
-    public static final String TYPE_UNKNOWN = "unknown";
-    public static final String TYPE_ETHERNET = "ethernet";
-    public static final String TYPE_WIFI = "wifi";
-    public static final String TYPE_2G = "2g";
-    public static final String TYPE_3G = "3g";
-    public static final String TYPE_4G = "4g";
-    public static final String TYPE_NONE = "none";
-
-    private static final String LOG_TAG = "NetworkManager";
-
-    private CallbackContext connectionCallbackContext;
-    private boolean registered = false;
-
-    ConnectivityManager sockMan;
-    BroadcastReceiver receiver;
-    private String lastStatus = "";
-
-    /**
-     * Constructor.
-     */
-    public NetworkManager() {
-        this.receiver = null;
-    }
-
-    /**
-     * 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.sockMan = (ConnectivityManager) cordova.getActivity().getSystemService(Context.CONNECTIVITY_SERVICE);
-        this.connectionCallbackContext = null;
-
-        // We need to listen to connectivity events to update navigator.connection
-        IntentFilter intentFilter = new IntentFilter();
-        intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
-        if (this.receiver == null) {
-            this.receiver = new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    // (The null check is for the ARM Emulator, please use Intel Emulator for better results)
-                    if(NetworkManager.this.webView != null)                        
-                        updateConnectionInfo(sockMan.getActiveNetworkInfo());
-                }
-            };
-            cordova.getActivity().registerReceiver(this.receiver, intentFilter);
-            this.registered = true;
-        }
-
-    }
-
-    /**
-     * Executes the request and returns PluginResult.
-     *
-     * @param action            The action to execute.
-     * @param args              JSONArry of arguments for the plugin.
-     * @param callbackContext   The callback id used when calling back into JavaScript.
-     * @return                  True if the action was valid, false otherwise.
-     */
-    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
-        if (action.equals("getConnectionInfo")) {
-            this.connectionCallbackContext = callbackContext;
-            NetworkInfo info = sockMan.getActiveNetworkInfo();
-            PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, this.getConnectionInfo(info));
-            pluginResult.setKeepCallback(true);
-            callbackContext.sendPluginResult(pluginResult);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Stop network receiver.
-     */
-    public void onDestroy() {
-        if (this.receiver != null && this.registered) {
-            try {
-                this.cordova.getActivity().unregisterReceiver(this.receiver);
-                this.registered = false;
-            } catch (Exception e) {
-                Log.e(LOG_TAG, "Error unregistering network receiver: " + e.getMessage(), e);
-            }
-        }
-    }
-
-    //--------------------------------------------------------------------------
-    // LOCAL METHODS
-    //--------------------------------------------------------------------------
-
-    /**
-     * Updates the JavaScript side whenever the connection changes
-     *
-     * @param info the current active network info
-     * @return
-     */
-    private void updateConnectionInfo(NetworkInfo info) {
-        // send update to javascript "navigator.network.connection"
-        // Jellybean sends its own info
-        String thisStatus = this.getConnectionInfo(info);
-        if(!thisStatus.equals(lastStatus))
-        {
-            sendUpdate(thisStatus);
-            lastStatus = thisStatus;
-        }
-            
-    }
-
-    /**
-     * Get the latest network connection information
-     *
-     * @param info the current active network info
-     * @return a JSONObject that represents the network info
-     */
-    private String getConnectionInfo(NetworkInfo info) {
-        String type = TYPE_NONE;
-        if (info != null) {
-            // If we are not connected to any network set type to none
-            if (!info.isConnected()) {
-                type = TYPE_NONE;
-            }
-            else {
-                type = getType(info);
-            }
-        }
-        Log.d("CordovaNetworkManager", "Connection Type: " + type);
-        return type;
-    }
-
-    /**
-     * Create a new plugin result and send it back to JavaScript
-     *
-     * @param connection the network info to set as navigator.connection
-     */
-    private void sendUpdate(String type) {
-        if (connectionCallbackContext != null) {
-            PluginResult result = new PluginResult(PluginResult.Status.OK, type);
-            result.setKeepCallback(true);
-            connectionCallbackContext.sendPluginResult(result);
-        }
-        webView.postMessage("networkconnection", type);
-    }
-
-    /**
-     * Determine the type of connection
-     *
-     * @param info the network info so we can determine connection type.
-     * @return the type of mobile network we are on
-     */
-    private String getType(NetworkInfo info) {
-        if (info != null) {
-            String type = info.getTypeName();
-
-            if (type.toLowerCase().equals(WIFI)) {
-                return TYPE_WIFI;
-            }
-            else if (type.toLowerCase().equals(MOBILE)) {
-                type = info.getSubtypeName();
-                if (type.toLowerCase().equals(GSM) ||
-                        type.toLowerCase().equals(GPRS) ||
-                        type.toLowerCase().equals(EDGE)) {
-                    return TYPE_2G;
-                }
-                else if (type.toLowerCase().startsWith(CDMA) ||
-                        type.toLowerCase().equals(UMTS) ||
-                        type.toLowerCase().equals(ONEXRTT) ||
-                        type.toLowerCase().equals(EHRPD) ||
-                        type.toLowerCase().equals(HSUPA) ||
-                        type.toLowerCase().equals(HSDPA) ||
-                        type.toLowerCase().equals(HSPA)) {
-                    return TYPE_3G;
-                }
-                else if (type.toLowerCase().equals(LTE) ||
-                        type.toLowerCase().equals(UMB) ||
-                        type.toLowerCase().equals(HSPA_PLUS)) {
-                    return TYPE_4G;
-                }
-            }
-        }
-        else {
-            return TYPE_NONE;
-        }
-        return TYPE_UNKNOWN;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/Notification.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/Notification.java b/framework/src/org/apache/cordova/Notification.java
deleted file mode 100755
index cf2e95f..0000000
--- a/framework/src/org/apache/cordova/Notification.java
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
-       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.api.CallbackContext;
-import org.apache.cordova.api.CordovaInterface;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import android.app.AlertDialog;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.net.Uri;
-import android.os.Vibrator;
-import android.widget.EditText;
-
-/**
- * This class provides access to notifications on the device.
- */
-public class Notification extends CordovaPlugin {
-
-    public int confirmResult = -1;
-    public ProgressDialog spinnerDialog = null;
-    public ProgressDialog progressDialog = null;
-
-    /**
-     * Constructor.
-     */
-    public Notification() {
-    }
-
-    /**
-     * Executes the request and returns PluginResult.
-     *
-     * @param action            The action to execute.
-     * @param args              JSONArray of arguments for the plugin.
-     * @param callbackContext   The callback context used when calling back into JavaScript.
-     * @return                  True when the action was valid, false otherwise.
-     */
-    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
-        if (action.equals("beep")) {
-            this.beep(args.getLong(0));
-        }
-        else if (action.equals("vibrate")) {
-            this.vibrate(args.getLong(0));
-        }
-        else if (action.equals("alert")) {
-            this.alert(args.getString(0), args.getString(1), args.getString(2), callbackContext);
-            return true;
-        }
-        else if (action.equals("confirm")) {
-            this.confirm(args.getString(0), args.getString(1), args.getJSONArray(2), callbackContext);
-            return true;
-        }
-        else if (action.equals("prompt")) {
-            this.prompt(args.getString(0), args.getString(1), args.getJSONArray(2), args.getString(3), callbackContext);
-            return true;
-        }
-        else if (action.equals("activityStart")) {
-            this.activityStart(args.getString(0), args.getString(1));
-        }
-        else if (action.equals("activityStop")) {
-            this.activityStop();
-        }
-        else if (action.equals("progressStart")) {
-            this.progressStart(args.getString(0), args.getString(1));
-        }
-        else if (action.equals("progressValue")) {
-            this.progressValue(args.getInt(0));
-        }
-        else if (action.equals("progressStop")) {
-            this.progressStop();
-        }
-        else {
-            return false;
-        }
-
-        // Only alert and confirm are async.
-        callbackContext.success();
-        return true;
-    }
-
-    //--------------------------------------------------------------------------
-    // LOCAL METHODS
-    //--------------------------------------------------------------------------
-
-    /**
-     * Beep plays the default notification ringtone.
-     *
-     * @param count     Number of times to play notification
-     */
-    public void beep(long count) {
-        Uri ringtone = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
-        Ringtone notification = RingtoneManager.getRingtone(this.cordova.getActivity().getBaseContext(), ringtone);
-
-        // If phone is not set to silent mode
-        if (notification != null) {
-            for (long i = 0; i < count; ++i) {
-                notification.play();
-                long timeout = 5000;
-                while (notification.isPlaying() && (timeout > 0)) {
-                    timeout = timeout - 100;
-                    try {
-                        Thread.sleep(100);
-                    } catch (InterruptedException e) {
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * Vibrates the device for the specified amount of time.
-     *
-     * @param time      Time to vibrate in ms.
-     */
-    public void vibrate(long time) {
-        // Start the vibration, 0 defaults to half a second.
-        if (time == 0) {
-            time = 500;
-        }
-        Vibrator vibrator = (Vibrator) this.cordova.getActivity().getSystemService(Context.VIBRATOR_SERVICE);
-        vibrator.vibrate(time);
-    }
-
-    /**
-     * Builds and shows a native Android alert with given Strings
-     * @param message           The message the alert should display
-     * @param title             The title of the alert
-     * @param buttonLabel       The label of the button
-     * @param callbackContext   The callback context
-     */
-    public synchronized void alert(final String message, final String title, final String buttonLabel, final CallbackContext callbackContext) {
-
-        final CordovaInterface cordova = this.cordova;
-
-        Runnable runnable = new Runnable() {
-            public void run() {
-
-                AlertDialog.Builder dlg = new AlertDialog.Builder(cordova.getActivity());
-                dlg.setMessage(message);
-                dlg.setTitle(title);
-                dlg.setCancelable(true);
-                dlg.setPositiveButton(buttonLabel,
-                        new AlertDialog.OnClickListener() {
-                            public void onClick(DialogInterface dialog, int which) {
-                                dialog.dismiss();
-                                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0));
-                            }
-                        });
-                dlg.setOnCancelListener(new AlertDialog.OnCancelListener() {
-                    public void onCancel(DialogInterface dialog)
-                    {
-                        dialog.dismiss();
-                        callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0));
-                    }
-                });
-
-                dlg.create();
-                dlg.show();
-            };
-        };
-        this.cordova.getActivity().runOnUiThread(runnable);
-    }
-
-    /**
-     * Builds and shows a native Android confirm dialog with given title, message, buttons.
-     * This dialog only shows up to 3 buttons.  Any labels after that will be ignored.
-     * The index of the button pressed will be returned to the JavaScript callback identified by callbackId.
-     *
-     * @param message           The message the dialog should display
-     * @param title             The title of the dialog
-     * @param buttonLabels      A comma separated list of button labels (Up to 3 buttons)
-     * @param callbackContext   The callback context.
-     */
-    public synchronized void confirm(final String message, final String title, final JSONArray buttonLabels, final CallbackContext callbackContext) {
-
-        final CordovaInterface cordova = this.cordova;
-
-        Runnable runnable = new Runnable() {
-            public void run() {
-                AlertDialog.Builder dlg = new AlertDialog.Builder(cordova.getActivity());
-                dlg.setMessage(message);
-                dlg.setTitle(title);
-                dlg.setCancelable(true);
-
-                // First button
-                if (buttonLabels.length() > 0) {
-                    try {
-                        dlg.setNegativeButton(buttonLabels.getString(0),
-                            new AlertDialog.OnClickListener() {
-                                public void onClick(DialogInterface dialog, int which) {
-                                    dialog.dismiss();
-                                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 1));
-                                }
-                            });
-                    } catch (JSONException e) { }
-                }
-
-                // Second button
-                if (buttonLabels.length() > 1) {
-                    try {
-                        dlg.setNeutralButton(buttonLabels.getString(1),
-                            new AlertDialog.OnClickListener() {
-                                public void onClick(DialogInterface dialog, int which) {
-                                    dialog.dismiss();
-                                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 2));
-                                }
-                            });
-                    } catch (JSONException e) { }
-                }
-
-                // Third button
-                if (buttonLabels.length() > 2) {
-                    try {
-                        dlg.setPositiveButton(buttonLabels.getString(2),
-                            new AlertDialog.OnClickListener() {
-                                public void onClick(DialogInterface dialog, int which) {
-                                  dialog.dismiss();
-                                  callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 3));
-                                }
-                            });
-                    } catch (JSONException e) { }
-                }
-                dlg.setOnCancelListener(new AlertDialog.OnCancelListener() {
-                    public void onCancel(DialogInterface dialog)
-                    {
-                        dialog.dismiss();
-                        callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, 0));
-                    }
-                });
-
-                dlg.create();
-                dlg.show();
-            };
-        };
-        this.cordova.getActivity().runOnUiThread(runnable);
-    }
-
-    /**
-     * Builds and shows a native Android prompt dialog with given title, message, buttons.
-     * This dialog only shows up to 3 buttons.  Any labels after that will be ignored.
-     * The following results are returned to the JavaScript callback identified by callbackId:
-     *     buttonIndex			Index number of the button selected
-     *     input1				The text entered in the prompt dialog box
-     *
-     * @param message           The message the dialog should display
-     * @param title             The title of the dialog
-     * @param buttonLabels      A comma separated list of button labels (Up to 3 buttons)
-     * @param callbackContext   The callback context.
-     */
-    public synchronized void prompt(final String message, final String title, final JSONArray buttonLabels, final String defaultText, final CallbackContext callbackContext) {
-    	
-        final CordovaInterface cordova = this.cordova;
-        final EditText promptInput =  new EditText(cordova.getActivity());
-        promptInput.setHint(defaultText);
-       
-        Runnable runnable = new Runnable() {
-            public void run() {
-                AlertDialog.Builder dlg = new AlertDialog.Builder(cordova.getActivity());
-                dlg.setMessage(message);
-                dlg.setTitle(title);
-                dlg.setCancelable(true);
-                
-                dlg.setView(promptInput);
-                
-                final JSONObject result = new JSONObject();
-                
-                // First button
-                if (buttonLabels.length() > 0) {
-                    try {
-                        dlg.setNegativeButton(buttonLabels.getString(0),
-                            new AlertDialog.OnClickListener() {
-                                public void onClick(DialogInterface dialog, int which) {
-                                    dialog.dismiss();
-                                    try {
-                                        result.put("buttonIndex",1);
-                                        result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText());											
-                                    } catch (JSONException e) { e.printStackTrace(); }
-                                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
-                                }
-                            });
-                    } catch (JSONException e) { }
-                }
-
-                // Second button
-                if (buttonLabels.length() > 1) {
-                    try {
-                        dlg.setNeutralButton(buttonLabels.getString(1),
-                            new AlertDialog.OnClickListener() {
-                                public void onClick(DialogInterface dialog, int which) {
-                                    dialog.dismiss();
-                                    try {
-                                        result.put("buttonIndex",2);
-                                        result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText());
-                                    } catch (JSONException e) { e.printStackTrace(); }
-                                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
-                                }
-                            });
-                    } catch (JSONException e) { }
-                }
-
-                // Third button
-                if (buttonLabels.length() > 2) {
-                    try {
-                        dlg.setPositiveButton(buttonLabels.getString(2),
-                            new AlertDialog.OnClickListener() {
-                                public void onClick(DialogInterface dialog, int which) {
-                                    dialog.dismiss();
-                                    try {
-                                        result.put("buttonIndex",3);
-                                        result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText());
-                                    } catch (JSONException e) { e.printStackTrace(); }
-                                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
-                                }
-                            });
-                    } catch (JSONException e) { }
-                }
-                dlg.setOnCancelListener(new AlertDialog.OnCancelListener() {
-                    public void onCancel(DialogInterface dialog){
-                        dialog.dismiss();
-                        try {
-                            result.put("buttonIndex",0);
-                            result.put("input1", promptInput.getText().toString().trim().length()==0 ? defaultText : promptInput.getText());
-                        } catch (JSONException e) { e.printStackTrace(); }
-                        callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, result));
-                    }
-                });
-
-                dlg.create();
-                dlg.show();
-
-            };
-        };
-        this.cordova.getActivity().runOnUiThread(runnable);
-    }
-
-    /**
-     * Show the spinner.
-     *
-     * @param title     Title of the dialog
-     * @param message   The message of the dialog
-     */
-    public synchronized void activityStart(final String title, final String message) {
-        if (this.spinnerDialog != null) {
-            this.spinnerDialog.dismiss();
-            this.spinnerDialog = null;
-        }
-        final CordovaInterface cordova = this.cordova;
-        Runnable runnable = new Runnable() {
-            public void run() {
-                Notification.this.spinnerDialog = ProgressDialog.show(cordova.getActivity(), title, message, true, true,
-                        new DialogInterface.OnCancelListener() {
-                            public void onCancel(DialogInterface dialog) {
-                                Notification.this.spinnerDialog = null;
-                            }
-                        });
-            }
-        };
-        this.cordova.getActivity().runOnUiThread(runnable);
-    }
-
-    /**
-     * Stop spinner.
-     */
-    public synchronized void activityStop() {
-        if (this.spinnerDialog != null) {
-            this.spinnerDialog.dismiss();
-            this.spinnerDialog = null;
-        }
-    }
-
-    /**
-     * Show the progress dialog.
-     *
-     * @param title     Title of the dialog
-     * @param message   The message of the dialog
-     */
-    public synchronized void progressStart(final String title, final String message) {
-        if (this.progressDialog != null) {
-            this.progressDialog.dismiss();
-            this.progressDialog = null;
-        }
-        final Notification notification = this;
-        final CordovaInterface cordova = this.cordova;
-        Runnable runnable = new Runnable() {
-            public void run() {
-                notification.progressDialog = new ProgressDialog(cordova.getActivity());
-                notification.progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
-                notification.progressDialog.setTitle(title);
-                notification.progressDialog.setMessage(message);
-                notification.progressDialog.setCancelable(true);
-                notification.progressDialog.setMax(100);
-                notification.progressDialog.setProgress(0);
-                notification.progressDialog.setOnCancelListener(
-                        new DialogInterface.OnCancelListener() {
-                            public void onCancel(DialogInterface dialog) {
-                                notification.progressDialog = null;
-                            }
-                        });
-                notification.progressDialog.show();
-            }
-        };
-        this.cordova.getActivity().runOnUiThread(runnable);
-    }
-
-    /**
-     * Set value of progress bar.
-     *
-     * @param value     0-100
-     */
-    public synchronized void progressValue(int value) {
-        if (this.progressDialog != null) {
-            this.progressDialog.setProgress(value);
-        }
-    }
-
-    /**
-     * Stop progress dialog.
-     */
-    public synchronized void progressStop() {
-        if (this.progressDialog != null) {
-            this.progressDialog.dismiss();
-            this.progressDialog = null;
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/SplashScreen.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/SplashScreen.java b/framework/src/org/apache/cordova/SplashScreen.java
deleted file mode 100644
index 66b5bae..0000000
--- a/framework/src/org/apache/cordova/SplashScreen.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-       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.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.json.JSONArray;
-
-public class SplashScreen extends CordovaPlugin {
-
-    @Override
-    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
-        if (action.equals("hide")) {
-            this.webView.postMessage("splashscreen", "hide");
-        } else if (action.equals("show")){
-            this.webView.postMessage("splashscreen", "show");
-        }
-        else {
-            return false;
-        }
-
-        callbackContext.success();
-        return true;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/Storage.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/Storage.java b/framework/src/org/apache/cordova/Storage.java
deleted file mode 100755
index 34ebf38..0000000
--- a/framework/src/org/apache/cordova/Storage.java
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
-       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.io.File;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.*;
-
-/**
- * This class implements the HTML5 database support to work around a bug for
- * Android 3.0 devices. It is not used for other versions of Android, since
- * HTML5 database is built in to the browser.
- */
-public class Storage extends CordovaPlugin {
-
-    // Data Definition Language
-    private static final String ALTER = "alter";
-    private static final String CREATE = "create";
-    private static final String DROP = "drop";
-    private static final String TRUNCATE = "truncate";
-
-    SQLiteDatabase myDb = null; // Database object
-    String path = null; // Database path
-    String dbName = null; // Database name
-
-    /**
-     * Constructor.
-     */
-    public Storage() {
-    }
-
-    /**
-     * 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 used when calling back into JavaScript.
-     * @return True if the action was valid, false otherwise.
-     */
-    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
-        if (action.equals("openDatabase")) {
-            this.openDatabase(args.getString(0), args.getString(1),
-                    args.getString(2), args.getLong(3));
-        } else if (action.equals("executeSql")) {
-            String[] s = null;
-            if (args.isNull(1)) {
-                s = new String[0];
-            } else {
-                JSONArray a = args.getJSONArray(1);
-                int len = a.length();
-                s = new String[len];
-                for (int i = 0; i < len; i++) {
-                    s[i] = a.getString(i);
-                }
-            }
-            this.executeSql(args.getString(0), s, args.getString(2));
-        }
-        else {
-            return false;
-        }
-        callbackContext.success();
-        return true;
-    }
-
-    /**
-     * Clean up and close database.
-     */
-    @Override
-    public void onDestroy() {
-        if (this.myDb != null) {
-            this.myDb.close();
-            this.myDb = null;
-        }
-    }
-
-    /**
-     * Clean up on navigation/refresh.
-     */
-    public void onReset() {
-        this.onDestroy();
-    }
-
-    // --------------------------------------------------------------------------
-    // LOCAL METHODS
-    // --------------------------------------------------------------------------
-
-    /**
-     * Open database.
-     *
-     * @param db
-     *            The name of the database
-     * @param version
-     *            The version
-     * @param display_name
-     *            The display name
-     * @param size
-     *            The size in bytes
-     */
-    public void openDatabase(String db, String version, String display_name,
-            long size) {
-
-        // If database is open, then close it
-        if (this.myDb != null) {
-            this.myDb.close();
-        }
-
-        // If no database path, generate from application package
-        if (this.path == null) {
-            this.path = this.cordova.getActivity().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
-        }
-
-        this.dbName = this.path + File.separator + db + ".db";
-
-        /*
-         * What is all this nonsense? Well the separator was incorrect so the db was showing up in the wrong 
-         * directory. This bit of code fixes that issue and moves the db to the correct directory.
-         */
-        File oldDbFile = new File(this.path + File.pathSeparator + db + ".db");
-        if (oldDbFile.exists()) {
-            File dbPath = new File(this.path);
-            File dbFile = new File(dbName);
-            dbPath.mkdirs();
-            oldDbFile.renameTo(dbFile);
-        }
-        
-        this.myDb = SQLiteDatabase.openOrCreateDatabase(this.dbName, null);
-    }
-
-    /**
-     * Execute SQL statement.
-     *
-     * @param query
-     *            The SQL query
-     * @param params
-     *            Parameters for the query
-     * @param tx_id
-     *            Transaction id
-     */
-    public void executeSql(String query, String[] params, String tx_id) {
-        try {
-            if (isDDL(query)) {
-                this.myDb.execSQL(query);
-                this.webView.sendJavascript("cordova.require('cordova/plugin/android/storage').completeQuery('" + tx_id + "', '');");
-            }
-            else {
-                Cursor myCursor = this.myDb.rawQuery(query, params);
-                this.processResults(myCursor, tx_id);
-                myCursor.close();
-            }
-        }
-        catch (SQLiteException ex) {
-            ex.printStackTrace();
-            System.out.println("Storage.executeSql(): Error=" +  ex.getMessage());
-
-            // Send error message back to JavaScript
-            this.webView.sendJavascript("cordova.require('cordova/plugin/android/storage').failQuery('" + ex.getMessage() + "','" + tx_id + "');");
-        }
-    }
-
-    /**
-     * Checks to see the the query is a Data Definition command
-     *
-     * @param query to be executed
-     * @return true if it is a DDL command, false otherwise
-     */
-    private boolean isDDL(String query) {
-        String cmd = query.toLowerCase();
-        if (cmd.startsWith(DROP) || cmd.startsWith(CREATE) || cmd.startsWith(ALTER) || cmd.startsWith(TRUNCATE)) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Process query results.
-     *
-     * @param cur
-     *            Cursor into query results
-     * @param tx_id
-     *            Transaction id
-     */
-    public void processResults(Cursor cur, String tx_id) {
-
-        String result = "[]";
-        // If query result has rows
-
-        if (cur.moveToFirst()) {
-            JSONArray fullresult = new JSONArray();
-            String key = "";
-            String value = "";
-            int colCount = cur.getColumnCount();
-
-            // Build up JSON result object for each row
-            do {
-                JSONObject row = new JSONObject();
-                try {
-                    for (int i = 0; i < colCount; ++i) {
-                        key = cur.getColumnName(i);
-                        value = cur.getString(i);
-                        row.put(key, value);
-                    }
-                    fullresult.put(row);
-
-                } catch (JSONException e) {
-                    e.printStackTrace();
-                }
-
-            } while (cur.moveToNext());
-
-            result = fullresult.toString();
-        }
-
-        // Let JavaScript know that there are no more rows
-        this.webView.sendJavascript("cordova.require('cordova/plugin/android/storage').completeQuery('" + tx_id + "', " + result + ");");
-    }
-
-}


[12/22] android commit: Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-android

Posted by st...@apache.org.
Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/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/e1f93028
Tree: http://git-wip-us.apache.org/repos/asf/cordova-android/tree/e1f93028
Diff: http://git-wip-us.apache.org/repos/asf/cordova-android/diff/e1f93028

Branch: refs/heads/3.0.0
Commit: e1f930282c2dd87d422a5c776fc6f171128f237a
Parents: cb07fe3 3917284
Author: Simon MacDonald <si...@gmail.com>
Authored: Mon May 13 22:23:25 2013 -0400
Committer: Simon MacDonald <si...@gmail.com>
Committed: Mon May 13 22:23:25 2013 -0400

----------------------------------------------------------------------
 bin/create                    |   19 ++-----------------
 bin/templates/cordova/version |   32 ++++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 17 deletions(-)
----------------------------------------------------------------------



[13/22] android commit: [CB-3392] Fix a problem with the Windows jscript runtime

Posted by st...@apache.org.
[CB-3392] Fix a problem with the Windows jscript runtime

The problem is with this line in "create.js":

var ACTIVITY_PATH=PROJECT_PATH+'\\src\\'+PACKAGE_AS_PATH+'\\'+ACTIVITY+'.java';
[...]
exec('%comspec% /c copy "'+ROOT+'"\\bin\\templates\\project\\Activity.java '+ ACTIVITY_PATH +' /Y');

The Windows "copy" command will not create directories that don't exist, so the command above fails because "src\PACKAGE_AS_PATH" doesn't exist.  This can be fixed with:

Also update cordova.js reference


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

Branch: refs/heads/3.0.0
Commit: 230c635a54ced58f1519c7204f9b3b541e77b87c
Parents: e1f9302
Author: macdonst <si...@gmail.com>
Authored: Mon May 13 22:18:45 2013 -0300
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue May 14 19:19:10 2013 -0400

----------------------------------------------------------------------
 bin/create.js |   14 ++++++++------
 1 files changed, 8 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/230c635a/bin/create.js
----------------------------------------------------------------------
diff --git a/bin/create.js b/bin/create.js
index 3979594..b1de5fe 100644
--- a/bin/create.js
+++ b/bin/create.js
@@ -190,7 +190,8 @@ if(fso.FolderExists(PROJECT_PATH)) {
 }
 
 var PACKAGE_AS_PATH=PACKAGE.replace(/\./g, '\\');
-var ACTIVITY_PATH=PROJECT_PATH+'\\src\\'+PACKAGE_AS_PATH+'\\'+ACTIVITY+'.java';
+var ACTIVITY_DIR=PROJECT_PATH + '\\src\\' + PACKAGE_AS_PATH;
+var ACTIVITY_PATH=ACTIVITY_DIR+'\\'+ACTIVITY+'.java';
 var MANIFEST_PATH=PROJECT_PATH+'\\AndroidManifest.xml';
 var TARGET=setTarget();
 var API_LEVEL=setApiLevel();
@@ -201,7 +202,7 @@ exec('android.bat create project --target "'+TARGET+'" --path "'+PROJECT_PATH+'"
 
 // build from source. distro should have these files
 if (!fso.FileExists(ROOT+'\\cordova-'+VERSION+'.jar') &&
-    !fso.FileExists(ROOT+'\\cordova-'+VERSION+'.js')) {
+    !fso.FileExists(ROOT+'\\cordova.js')) {
     Log("Building jar and js files...");
     // update the cordova framework project to a target that exists on this machine
     exec('android.bat update project --target "'+TARGET+'" --path "'+ROOT+'\\framework"');
@@ -215,18 +216,19 @@ Log("Copying template files...");
 exec('%comspec% /c xcopy "'+ ROOT + '\\bin\\templates\\project\\res" "'+PROJECT_PATH+'\\res\\" /E /Y');
 exec('%comspec% /c xcopy "'+ ROOT + '\\bin\\templates\\project\\assets" "'+PROJECT_PATH+'\\assets\\" /E /Y');
 exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\project\\AndroidManifest.xml" "' + PROJECT_PATH + '\\AndroidManifest.xml" /Y');
-exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\project\\Activity.java" "'+ ACTIVITY_PATH +'" /Y');
+exec('%comspec% /c mkdir "' + ACTIVITY_DIR + '"');
+exec('%comspec% /c copy "' + ROOT + '"\\bin\\templates\\project\\Activity.java "' + ACTIVITY_PATH + '" /Y');
 
 // check if we have the source or the distro files
 Log("Copying js, jar & config.xml files...");
 if(fso.FolderExists(ROOT + '\\framework')) {
-    exec('%comspec% /c copy "'+ROOT+'\\framework\\assets\\www\\cordova-'+VERSION+'.js" "'+PROJECT_PATH+'\\assets\\www\\cordova-'+VERSION+'.js" /Y');
+    exec('%comspec% /c copy "'+ROOT+'\\framework\\assets\\www\\cordova.js" "'+PROJECT_PATH+'\\assets\\www\\cordova.js" /Y');
     exec('%comspec% /c copy "'+ROOT+'\\framework\\cordova-'+VERSION+'.jar" "'+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar" /Y');
     fso.CreateFolder(PROJECT_PATH + '\\res\\xml');
     exec('%comspec% /c copy "'+ROOT+'\\framework\\res\\xml\\config.xml" "' + PROJECT_PATH + '\\res\\xml\\config.xml" /Y');
 } else {
     // copy in cordova.js
-    exec('%comspec% /c copy "'+ROOT+'\\cordova-'+VERSION+'.js" "'+PROJECT_PATH+'\\assets\\www\\cordova-'+VERSION+'.js" /Y');
+    exec('%comspec% /c copy "'+ROOT+'\\cordova.js" "'+PROJECT_PATH+'\\assets\\www\\cordova.js" /Y');
     // copy in cordova.jar
     exec('%comspec% /c copy "'+ROOT+'\\cordova-'+VERSION+'.jar" "'+PROJECT_PATH+'\\libs\\cordova-'+VERSION+'.jar" /Y');
     // copy in xml
@@ -240,7 +242,7 @@ fso.CreateFolder(PROJECT_PATH + '\\cordova\\lib');
 createAppInfoJar();
 Log("Copying cordova command tools...");
 exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\appinfo.jar" "' + PROJECT_PATH + '\\cordova\\appinfo.jar" /Y');
-exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\cordova.js" "' + PROJECT_PATH + '\\cordova\\cordova.js" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\cordova.js" "' + PROJECT_PATH + '\\cordova\\lib\\cordova.js" /Y');
 exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\install-device.bat" "' + PROJECT_PATH + '\\cordova\\lib\\install-device.bat" /Y');
 exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\install-emulator.bat" "' + PROJECT_PATH + '\\cordova\\lib\\install-emulator.bat" /Y');
 exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\list-emulator-images.bat" "' + PROJECT_PATH + '\\cordova\\lib\\list-emulator-images.bat" /Y');


[14/22] android commit: DataResource bugfix WebviewClient logs error for http urls.

Posted by st...@apache.org.
DataResource bugfix WebviewClient logs error for http urls.


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

Branch: refs/heads/3.0.0
Commit: 8f91ebf194baa8028367e9e41f2e5ee2ff099b88
Parents: 230c635
Author: Shravan Narayan <sh...@google.com>
Authored: Fri May 10 17:08:50 2013 -0400
Committer: Braden Shepherdson <br...@google.com>
Committed: Thu May 16 14:29:04 2013 -0400

----------------------------------------------------------------------
 framework/src/org/apache/cordova/FileHelper.java   |    4 +++-
 .../cordova/IceCreamCordovaWebViewClient.java      |    8 +++++++-
 2 files changed, 10 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8f91ebf1/framework/src/org/apache/cordova/FileHelper.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileHelper.java b/framework/src/org/apache/cordova/FileHelper.java
index 400352c..8bc24aa 100644
--- a/framework/src/org/apache/cordova/FileHelper.java
+++ b/framework/src/org/apache/cordova/FileHelper.java
@@ -98,8 +98,10 @@ public class FileHelper {
             Uri uri = Uri.parse(uriString);
             String relativePath = uri.getPath().substring(15);
             return cordova.getActivity().getAssets().open(relativePath);
-        } else {
+        } else if (uriString.startsWith("file://")) {
             return new FileInputStream(getRealPath(uriString, cordova));
+        } else {
+            return null;
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8f91ebf1/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
index d9c1cd2..14c7603 100644
--- a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
+++ b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
@@ -19,6 +19,7 @@
 package org.apache.cordova;
 
 import java.io.IOException;
+import java.io.InputStream;
 
 import org.apache.cordova.api.CordovaInterface;
 import org.apache.cordova.api.DataResource;
@@ -55,7 +56,12 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
 
         if(ret == null) {
             try {
-                ret = new WebResourceResponse(dataResource.getMimeType(), "UTF-8", dataResource.getInputStream());
+                InputStream is;
+                String mimeType;
+                if((is = dataResource.getInputStream()) != null && (mimeType = dataResource.getMimeType()) != null) {
+                    // If we don't know how to open this file, let the browser continue loading
+                    ret = new WebResourceResponse(mimeType, "UTF-8", is);
+                }
             } catch(IOException e) {
                 LOG.e("IceCreamCordovaWebViewClient", "Error occurred while loading a file.", e);
             }


[18/22] ripped out plugins

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/FileUtils.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileUtils.java b/framework/src/org/apache/cordova/FileUtils.java
deleted file mode 100755
index e62fc4a..0000000
--- a/framework/src/org/apache/cordova/FileUtils.java
+++ /dev/null
@@ -1,1024 +0,0 @@
-/*
-       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 android.os.Environment;
-import android.provider.MediaStore;
-import android.util.Log;
-
-import org.apache.commons.codec.binary.Base64;
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.DataResource;
-import org.apache.cordova.api.PluginResult;
-import org.apache.cordova.file.EncodingException;
-import org.apache.cordova.file.FileExistsException;
-import org.apache.cordova.file.InvalidModificationException;
-import org.apache.cordova.file.NoModificationAllowedException;
-import org.apache.cordova.file.TypeMismatchException;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.RandomAccessFile;
-import java.net.MalformedURLException;
-import java.nio.channels.FileChannel;
-
-/**
- * This class provides SD card file and directory services to JavaScript.
- * Only files on the SD card can be accessed.
- */
-public class FileUtils extends CordovaPlugin {
-    private static final String LOG_TAG = "FileUtils";
-
-    public static int NOT_FOUND_ERR = 1;
-    public static int SECURITY_ERR = 2;
-    public static int ABORT_ERR = 3;
-
-    public static int NOT_READABLE_ERR = 4;
-    public static int ENCODING_ERR = 5;
-    public static int NO_MODIFICATION_ALLOWED_ERR = 6;
-    public static int INVALID_STATE_ERR = 7;
-    public static int SYNTAX_ERR = 8;
-    public static int INVALID_MODIFICATION_ERR = 9;
-    public static int QUOTA_EXCEEDED_ERR = 10;
-    public static int TYPE_MISMATCH_ERR = 11;
-    public static int PATH_EXISTS_ERR = 12;
-
-    public static int TEMPORARY = 0;
-    public static int PERSISTENT = 1;
-    public static int RESOURCE = 2;
-    public static int APPLICATION = 3;
-
-    /**
-     * Constructor.
-     */
-    public FileUtils() {
-    }
-
-    /**
-     * Executes the request and returns whether the action was valid.
-     *
-     * @param action 		The action to execute.
-     * @param args 		JSONArray of arguments for the plugin.
-     * @param callbackContext	The callback context used when calling back into JavaScript.
-     * @return 			True if the action was valid, false otherwise.
-     */
-    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
-        try {
-            if (action.equals("testSaveLocationExists")) {
-                boolean b = DirectoryManager.testSaveLocationExists();
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b));
-            }
-            else if (action.equals("getFreeDiskSpace")) {
-                long l = DirectoryManager.getFreeDiskSpace(false);
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, l));
-            }
-            else if (action.equals("testFileExists")) {
-                boolean b = DirectoryManager.testFileExists(args.getString(0));
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b));
-            }
-            else if (action.equals("testDirectoryExists")) {
-                boolean b = DirectoryManager.testFileExists(args.getString(0));
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, b));
-            }
-            else if (action.equals("readAsText")) {
-                String encoding = args.getString(1);
-                int start = args.getInt(2);
-                int end = args.getInt(3);
-
-                this.readFileAs(args.getString(0), start, end, callbackContext, encoding, PluginResult.MESSAGE_TYPE_STRING);
-            }
-            else if (action.equals("readAsDataURL")) {
-                int start = args.getInt(1);
-                int end = args.getInt(2);
-
-                this.readFileAs(args.getString(0), start, end, callbackContext, null, -1);
-            }
-            else if (action.equals("readAsArrayBuffer")) {
-                int start = args.getInt(1);
-                int end = args.getInt(2);
-
-                this.readFileAs(args.getString(0), start, end, callbackContext, null, PluginResult.MESSAGE_TYPE_ARRAYBUFFER);
-            }
-            else if (action.equals("readAsBinaryString")) {
-                int start = args.getInt(1);
-                int end = args.getInt(2);
-
-                this.readFileAs(args.getString(0), start, end, callbackContext, null, PluginResult.MESSAGE_TYPE_BINARYSTRING);
-            }
-            else if (action.equals("write")) {
-                long fileSize = this.write(args.getString(0), args.getString(1), args.getInt(2));
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, fileSize));
-            }
-            else if (action.equals("truncate")) {
-                long fileSize = this.truncateFile(args.getString(0), args.getLong(1));
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, fileSize));
-            }
-            else if (action.equals("requestFileSystem")) {
-                long size = args.optLong(1);
-                if (size != 0 && size > (DirectoryManager.getFreeDiskSpace(true) * 1024)) {
-                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, FileUtils.QUOTA_EXCEEDED_ERR));
-                } else {
-                    JSONObject obj = requestFileSystem(args.getInt(0));
-                    callbackContext.success(obj);
-                }
-            }
-            else if (action.equals("resolveLocalFileSystemURI")) {
-                JSONObject obj = resolveLocalFileSystemURI(args.getString(0));
-                callbackContext.success(obj);
-            }
-            else if (action.equals("getMetadata")) {
-                callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, getMetadata(args.getString(0))));
-            }
-            else if (action.equals("getFileMetadata")) {
-                JSONObject obj = getFileMetadata(args.getString(0));
-                callbackContext.success(obj);
-            }
-            else if (action.equals("getParent")) {
-                JSONObject obj = getParent(args.getString(0));
-                callbackContext.success(obj);
-            }
-            else if (action.equals("getDirectory")) {
-                JSONObject obj = getFile(args.getString(0), args.getString(1), args.optJSONObject(2), true);
-                callbackContext.success(obj);
-            }
-            else if (action.equals("getFile")) {
-                JSONObject obj = getFile(args.getString(0), args.getString(1), args.optJSONObject(2), false);
-                callbackContext.success(obj);
-            }
-            else if (action.equals("remove")) {
-                boolean success;
-
-                success = remove(args.getString(0));
-
-                if (success) {
-                    notifyDelete(args.getString(0));
-                    callbackContext.success();
-                } else {
-                    callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR);
-                }
-            }
-            else if (action.equals("removeRecursively")) {
-                boolean success = removeRecursively(args.getString(0));
-                if (success) {
-                    callbackContext.success();
-                } else {
-                    callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR);
-                }
-            }
-            else if (action.equals("moveTo")) {
-                JSONObject entry = transferTo(args.getString(0), args.getString(1), args.getString(2), true);
-                callbackContext.success(entry);
-            }
-            else if (action.equals("copyTo")) {
-                JSONObject entry = transferTo(args.getString(0), args.getString(1), args.getString(2), false);
-                callbackContext.success(entry);
-            }
-            else if (action.equals("readEntries")) {
-                JSONArray entries = readEntries(args.getString(0));
-                callbackContext.success(entries);
-            }
-            else {
-                return false;
-            }
-        } catch (FileNotFoundException e) {
-            callbackContext.error(FileUtils.NOT_FOUND_ERR);
-        } catch (FileExistsException e) {
-            callbackContext.error(FileUtils.PATH_EXISTS_ERR);
-        } catch (NoModificationAllowedException e) {
-            callbackContext.error(FileUtils.NO_MODIFICATION_ALLOWED_ERR);
-        } catch (InvalidModificationException e) {
-            callbackContext.error(FileUtils.INVALID_MODIFICATION_ERR);
-        } catch (MalformedURLException e) {
-            callbackContext.error(FileUtils.ENCODING_ERR);
-        } catch (IOException e) {
-            callbackContext.error(FileUtils.INVALID_MODIFICATION_ERR);
-        } catch (EncodingException e) {
-            callbackContext.error(FileUtils.ENCODING_ERR);
-        } catch (TypeMismatchException e) {
-            callbackContext.error(FileUtils.TYPE_MISMATCH_ERR);
-        }
-        return true;
-    }
-
-    /**
-     * Need to check to see if we need to clean up the content store
-     *
-     * @param filePath the path to check
-     */
-    private void notifyDelete(String filePath) {
-        String newFilePath = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.notifyDelete").getRealFile().getPath();
-        try {
-            this.cordova.getActivity().getContentResolver().delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
-                    MediaStore.Images.Media.DATA + " = ?",
-                    new String[] { newFilePath });
-        } catch (UnsupportedOperationException t) {
-            // Was seeing this on the File mobile-spec tests on 4.0.3 x86 emulator.
-            // The ContentResolver applies only when the file was registered in the
-            // first case, which is generally only the case with images.
-        }
-    }
-
-    /**
-     * Allows the user to look up the Entry for a file or directory referred to by a local URI.
-     *
-     * @param url of the file/directory to look up
-     * @return a JSONObject representing a Entry from the filesystem
-     * @throws MalformedURLException if the url is not valid
-     * @throws FileNotFoundException if the file does not exist
-     * @throws IOException if the user can't read the file
-     * @throws JSONException
-     */
-    private JSONObject resolveLocalFileSystemURI(String url) throws IOException, JSONException {
-        File fp = DataResource.initiateNewDataRequestForUri(url, webView.pluginManager, cordova, "FileUtils.resolveLocalFileSystemURI").getRealFile();
-
-        if (fp == null || !fp.exists()) {
-            throw new FileNotFoundException();
-        }
-        if (!fp.canRead()) {
-            throw new IOException();
-        }
-        return getEntry(fp);
-    }
-
-    /**
-     * Read the list of files from this directory.
-     *
-     * @param fileName the directory to read from
-     * @return a JSONArray containing JSONObjects that represent Entry objects.
-     * @throws FileNotFoundException if the directory is not found.
-     * @throws JSONException
-     */
-    private JSONArray readEntries(String fileName) throws FileNotFoundException, JSONException {
-        File fp = DataResource.initiateNewDataRequestForUri(fileName, webView.pluginManager, cordova, "FileUtils.readEntries").getRealFile();
-
-        if (fp == null || !fp.exists()) {
-            // The directory we are listing doesn't exist so we should fail.
-            throw new FileNotFoundException();
-        }
-
-        JSONArray entries = new JSONArray();
-
-        if (fp.isDirectory()) {
-            File[] files = fp.listFiles();
-            for (int i = 0; i < files.length; i++) {
-                if (files[i].canRead()) {
-                    entries.put(getEntry(files[i]));
-                }
-            }
-        }
-
-        return entries;
-    }
-
-    /**
-     * A setup method that handles the move/copy of files/directories
-     *
-     * @param fileName to be copied/moved
-     * @param newParent is the location where the file will be copied/moved to
-     * @param newName for the file directory to be called, if null use existing file name
-     * @param move if false do a copy, if true do a move
-     * @return a Entry object
-     * @throws NoModificationAllowedException
-     * @throws IOException
-     * @throws InvalidModificationException
-     * @throws EncodingException
-     * @throws JSONException
-     * @throws FileExistsException
-     */
-    private JSONObject transferTo(String fileName, String newParent, String newName, boolean move) throws JSONException, NoModificationAllowedException, IOException, InvalidModificationException, EncodingException, FileExistsException {
-        DataResource dataResourceFrom = DataResource.initiateNewDataRequestForUri(fileName, webView.pluginManager, cordova, "FileUtils.transferTo");
-        String newFileName = dataResourceFrom.getRealFile().getPath();
-        DataResource dataResourceTo = DataResource.initiateNewDataRequestForUri(newParent, webView.pluginManager, cordova, "FileUtils.transferTo");
-        newParent = dataResourceTo.getRealFile().getPath();
-
-        // Check for invalid file name
-        if (newName != null && newName.contains(":")) {
-            throw new EncodingException("Bad file name");
-        }
-
-        File source = new File(newFileName);
-
-        if (!source.exists()) {
-            // The file/directory we are copying doesn't exist so we should fail.
-            throw new FileNotFoundException("The source does not exist");
-        }
-
-        File destinationDir = new File(newParent);
-        if (!destinationDir.exists()) {
-            // The destination does not exist so we should fail.
-            throw new FileNotFoundException("The source does not exist");
-        }
-
-        // Figure out where we should be copying to
-        File destination = createDestination(newName, source, destinationDir);
-
-        //Log.d(LOG_TAG, "Source: " + source.getAbsolutePath());
-        //Log.d(LOG_TAG, "Destin: " + destination.getAbsolutePath());
-
-        // Check to see if source and destination are the same file
-        if (source.getAbsolutePath().equals(destination.getAbsolutePath())) {
-            throw new InvalidModificationException("Can't copy a file onto itself");
-        }
-
-        if (source.isDirectory()) {
-            if (move) {
-                return moveDirectory(source, destination);
-            } else {
-                return copyDirectory(source, destination);
-            }
-        } else {
-            if (move) {
-                JSONObject newFileEntry = moveFile(source, destination);
-
-                // If we've moved a file given its content URI, we need to clean up.
-                if (fileName.startsWith("content://")) {
-                    notifyDelete(fileName);
-                }
-
-                return newFileEntry;
-            } else {
-                return copyFile(source, destination);
-            }
-        }
-    }
-
-    /**
-     * Creates the destination File object based on name passed in
-     *
-     * @param newName for the file directory to be called, if null use existing file name
-     * @param fp represents the source file
-     * @param destination represents the destination file
-     * @return a File object that represents the destination
-     */
-    private File createDestination(String newName, File fp, File destination) {
-        File destFile = null;
-
-        // I know this looks weird but it is to work around a JSON bug.
-        if ("null".equals(newName) || "".equals(newName)) {
-            newName = null;
-        }
-
-        if (newName != null) {
-            destFile = new File(destination.getAbsolutePath() + File.separator + newName);
-        } else {
-            destFile = new File(destination.getAbsolutePath() + File.separator + fp.getName());
-        }
-        return destFile;
-    }
-
-    /**
-     * Copy a file
-     *
-     * @param srcFile file to be copied
-     * @param destFile destination to be copied to
-     * @return a FileEntry object
-     * @throws IOException
-     * @throws InvalidModificationException
-     * @throws JSONException
-     */
-    private JSONObject copyFile(File srcFile, File destFile) throws IOException, InvalidModificationException, JSONException {
-        // Renaming a file to an existing directory should fail
-        if (destFile.exists() && destFile.isDirectory()) {
-            throw new InvalidModificationException("Can't rename a file to a directory");
-        }
-
-        copyAction(srcFile, destFile);
-
-        return getEntry(destFile);
-    }
-
-    /**
-     * Moved this code into it's own method so moveTo could use it when the move is across file systems
-     */
-    private void copyAction(File srcFile, File destFile)
-            throws FileNotFoundException, IOException {
-        FileInputStream istream = new FileInputStream(srcFile);
-        FileOutputStream ostream = new FileOutputStream(destFile);
-        FileChannel input = istream.getChannel();
-        FileChannel output = ostream.getChannel();
-
-        try {
-            input.transferTo(0, input.size(), output);
-        } finally {
-            istream.close();
-            ostream.close();
-            input.close();
-            output.close();
-        }
-    }
-
-    /**
-     * Copy a directory
-     *
-     * @param srcDir directory to be copied
-     * @param destinationDir destination to be copied to
-     * @return a DirectoryEntry object
-     * @throws JSONException
-     * @throws IOException
-     * @throws NoModificationAllowedException
-     * @throws InvalidModificationException
-     */
-    private JSONObject copyDirectory(File srcDir, File destinationDir) throws JSONException, IOException, NoModificationAllowedException, InvalidModificationException {
-        // Renaming a file to an existing directory should fail
-        if (destinationDir.exists() && destinationDir.isFile()) {
-            throw new InvalidModificationException("Can't rename a file to a directory");
-        }
-
-        // Check to make sure we are not copying the directory into itself
-        if (isCopyOnItself(srcDir.getAbsolutePath(), destinationDir.getAbsolutePath())) {
-            throw new InvalidModificationException("Can't copy itself into itself");
-        }
-
-        // See if the destination directory exists. If not create it.
-        if (!destinationDir.exists()) {
-            if (!destinationDir.mkdir()) {
-                // If we can't create the directory then fail
-                throw new NoModificationAllowedException("Couldn't create the destination directory");
-            }
-        }
-
-        for (File file : srcDir.listFiles()) {
-            if (file.isDirectory()) {
-                copyDirectory(file, destinationDir);
-            } else {
-                File destination = new File(destinationDir.getAbsoluteFile() + File.separator + file.getName());
-                copyFile(file, destination);
-            }
-        }
-
-        return getEntry(destinationDir);
-    }
-
-    /**
-     * Check to see if the user attempted to copy an entry into its parent without changing its name,
-     * or attempted to copy a directory into a directory that it contains directly or indirectly.
-     *
-     * @param srcDir
-     * @param destinationDir
-     * @return
-     */
-    private boolean isCopyOnItself(String src, String dest) {
-
-        // This weird test is to determine if we are copying or moving a directory into itself.
-        // Copy /sdcard/myDir to /sdcard/myDir-backup is okay but
-        // Copy /sdcard/myDir to /sdcard/myDir/backup should throw an INVALID_MODIFICATION_ERR
-        if (dest.startsWith(src) && dest.indexOf(File.separator, src.length() - 1) != -1) {
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * Move a file
-     *
-     * @param srcFile file to be copied
-     * @param destFile destination to be copied to
-     * @return a FileEntry object
-     * @throws IOException
-     * @throws InvalidModificationException
-     * @throws JSONException
-     */
-    private JSONObject moveFile(File srcFile, File destFile) throws IOException, JSONException, InvalidModificationException {
-        // Renaming a file to an existing directory should fail
-        if (destFile.exists() && destFile.isDirectory()) {
-            throw new InvalidModificationException("Can't rename a file to a directory");
-        }
-
-        // Try to rename the file
-        if (!srcFile.renameTo(destFile)) {
-            // Trying to rename the file failed.  Possibly because we moved across file system on the device.
-            // Now we have to do things the hard way
-            // 1) Copy all the old file
-            // 2) delete the src file
-            copyAction(srcFile, destFile);
-            if (destFile.exists()) {
-                srcFile.delete();
-            } else {
-                throw new IOException("moved failed");
-            }
-        }
-
-        return getEntry(destFile);
-    }
-
-    /**
-     * Move a directory
-     *
-     * @param srcDir directory to be copied
-     * @param destinationDir destination to be copied to
-     * @return a DirectoryEntry object
-     * @throws JSONException
-     * @throws IOException
-     * @throws InvalidModificationException
-     * @throws NoModificationAllowedException
-     * @throws FileExistsException
-     */
-    private JSONObject moveDirectory(File srcDir, File destinationDir) throws IOException, JSONException, InvalidModificationException, NoModificationAllowedException, FileExistsException {
-        // Renaming a file to an existing directory should fail
-        if (destinationDir.exists() && destinationDir.isFile()) {
-            throw new InvalidModificationException("Can't rename a file to a directory");
-        }
-
-        // Check to make sure we are not copying the directory into itself
-        if (isCopyOnItself(srcDir.getAbsolutePath(), destinationDir.getAbsolutePath())) {
-            throw new InvalidModificationException("Can't move itself into itself");
-        }
-
-        // If the destination directory already exists and is empty then delete it.  This is according to spec.
-        if (destinationDir.exists()) {
-            if (destinationDir.list().length > 0) {
-                throw new InvalidModificationException("directory is not empty");
-            }
-        }
-
-        // Try to rename the directory
-        if (!srcDir.renameTo(destinationDir)) {
-            // Trying to rename the directory failed.  Possibly because we moved across file system on the device.
-            // Now we have to do things the hard way
-            // 1) Copy all the old files
-            // 2) delete the src directory
-            copyDirectory(srcDir, destinationDir);
-            if (destinationDir.exists()) {
-                removeDirRecursively(srcDir);
-            } else {
-                throw new IOException("moved failed");
-            }
-        }
-
-        return getEntry(destinationDir);
-    }
-
-    /**
-     * Deletes a directory and all of its contents, if any. In the event of an error
-     * [e.g. trying to delete a directory that contains a file that cannot be removed],
-     * some of the contents of the directory may be deleted.
-     * It is an error to attempt to delete the root directory of a filesystem.
-     *
-     * @param filePath the directory to be removed
-     * @return a boolean representing success of failure
-     * @throws FileExistsException
-     */
-    private boolean removeRecursively(String filePath) throws FileExistsException {
-        File fp = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.readEntries").getRealFile();
-
-        // You can't delete the root directory.
-        if (atRootDirectory(filePath)) {
-            return false;
-        }
-
-        return removeDirRecursively(fp);
-    }
-
-    /**
-     * Loops through a directory deleting all the files.
-     *
-     * @param directory to be removed
-     * @return a boolean representing success of failure
-     * @throws FileExistsException
-     */
-    private boolean removeDirRecursively(File directory) throws FileExistsException {
-        if (directory.isDirectory()) {
-            for (File file : directory.listFiles()) {
-                removeDirRecursively(file);
-            }
-        }
-
-        if (!directory.delete()) {
-            throw new FileExistsException("could not delete: " + directory.getName());
-        } else {
-            return true;
-        }
-    }
-
-    /**
-     * Deletes a file or directory. It is an error to attempt to delete a directory that is not empty.
-     * It is an error to attempt to delete the root directory of a filesystem.
-     *
-     * @param filePath file or directory to be removed
-     * @return a boolean representing success of failure
-     * @throws NoModificationAllowedException
-     * @throws InvalidModificationException
-     */
-    private boolean remove(String filePath) throws NoModificationAllowedException, InvalidModificationException {
-        File fp = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.readEntries").getRealFile();
-
-        // You can't delete the root directory.
-        if (atRootDirectory(filePath)) {
-            throw new NoModificationAllowedException("You can't delete the root directory");
-        }
-
-        // You can't delete a directory that is not empty
-        if (fp.isDirectory() && fp.list().length > 0) {
-            throw new InvalidModificationException("You can't delete a directory that is not empty.");
-        }
-
-        return fp.delete();
-    }
-
-    /**
-     * Creates or looks up a file.
-     *
-     * @param dirPath base directory
-     * @param fileName file/directory to lookup or create
-     * @param options specify whether to create or not
-     * @param directory if true look up directory, if false look up file
-     * @return a Entry object
-     * @throws FileExistsException
-     * @throws IOException
-     * @throws TypeMismatchException
-     * @throws EncodingException
-     * @throws JSONException
-     */
-    private JSONObject getFile(String dirPath, String fileName, JSONObject options, boolean directory) throws FileExistsException, IOException, TypeMismatchException, EncodingException, JSONException {
-        boolean create = false;
-        boolean exclusive = false;
-        if (options != null) {
-            create = options.optBoolean("create");
-            if (create) {
-                exclusive = options.optBoolean("exclusive");
-            }
-        }
-
-        // Check for a ":" character in the file to line up with BB and iOS
-        if (fileName.contains(":")) {
-            throw new EncodingException("This file has a : in it's name");
-        }
-
-        String filePath = getFullFilePath(dirPath, fileName);
-        File fp = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.getFile").getRealFile();
-
-        if (create) {
-            if (exclusive && fp.exists()) {
-                throw new FileExistsException("create/exclusive fails");
-            }
-            if (directory) {
-                fp.mkdir();
-            } else {
-                fp.createNewFile();
-            }
-            if (!fp.exists()) {
-                throw new FileExistsException("create fails");
-            }
-        }
-        else {
-            if (!fp.exists()) {
-                throw new FileNotFoundException("path does not exist");
-            }
-            if (directory) {
-                if (fp.isFile()) {
-                    throw new TypeMismatchException("path doesn't exist or is file");
-                }
-            } else {
-                if (fp.isDirectory()) {
-                    throw new TypeMismatchException("path doesn't exist or is directory");
-                }
-            }
-        }
-
-        // Return the directory
-        return getEntry(fp);
-    }
-
-    /**
-     * If the path starts with a '/' just return that file object. If not construct the file
-     * object from the path passed in and the file name.
-     *
-     * @param dirPath root directory
-     * @param fileName new file name
-     * @return
-     */
-    private String getFullFilePath(String dirPath, String fileName) {
-        if (fileName.startsWith("/")) {
-            return fileName;
-        } else {
-            DataResource dataResource = DataResource.initiateNewDataRequestForUri(dirPath, webView.pluginManager, cordova, "FileUtils.getFullFilePath");
-            dirPath = dataResource.getRealFile().getPath();
-            return dirPath + File.separator + fileName;
-        }
-    }
-
-    /**
-     * Look up the parent DirectoryEntry containing this Entry.
-     * If this Entry is the root of its filesystem, its parent is itself.
-     *
-     * @param filePath
-     * @return
-     * @throws JSONException
-     */
-    private JSONObject getParent(String filePath) throws JSONException {
-        DataResource dataResource = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.getParent");
-        filePath = dataResource.getRealFile().getPath();
-
-        if (atRootDirectory(filePath)) {
-            return getEntry(filePath);
-        }
-        return getEntry(dataResource.getRealFile().getParent());
-    }
-
-    /**
-     * Checks to see if we are at the root directory.  Useful since we are
-     * not allow to delete this directory.
-     *
-     * @param filePath to directory
-     * @return true if we are at the root, false otherwise.
-     */
-    private boolean atRootDirectory(String filePath) {
-        filePath = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.atRootDirectory").getRealFile().getPath();
-
-        if (filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + cordova.getActivity().getPackageName() + "/cache") ||
-                filePath.equals(Environment.getExternalStorageDirectory().getAbsolutePath()) ||
-                filePath.equals("/data/data/" + cordova.getActivity().getPackageName())) {
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Look up metadata about this entry.
-     *
-     * @param filePath to entry
-     * @return a long
-     * @throws FileNotFoundException
-     */
-    private long getMetadata(String filePath) throws FileNotFoundException {
-        File file = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.getMetadata").getRealFile();
-
-        if (file == null || !file.exists()) {
-            throw new FileNotFoundException("Failed to find file in getMetadata");
-        }
-
-        return file.lastModified();
-    }
-
-    /**
-     * Returns a File that represents the current state of the file that this FileEntry represents.
-     *
-     * @param filePath to entry
-     * @return returns a JSONObject represent a W3C File object
-     * @throws FileNotFoundException
-     * @throws JSONException
-     */
-    private JSONObject getFileMetadata(String filePath) throws FileNotFoundException, JSONException {
-        DataResource dataResource = DataResource.initiateNewDataRequestForUri(filePath, webView.pluginManager, cordova, "FileUtils.getMetadata");
-        File file = dataResource.getRealFile();
-
-        if (file == null || !file.exists()) {
-            throw new FileNotFoundException("File: " + filePath + " does not exist.");
-        }
-
-        JSONObject metadata = new JSONObject();
-        metadata.put("size", file.length());
-        metadata.put("type", dataResource.getMimeType());
-        metadata.put("name", file.getName());
-        metadata.put("fullPath", filePath);
-        metadata.put("lastModifiedDate", file.lastModified());
-
-        return metadata;
-    }
-
-    /**
-     * Requests a filesystem in which to store application data.
-     *
-     * @param type of file system requested
-     * @return a JSONObject representing the file system
-     * @throws IOException
-     * @throws JSONException
-     */
-    private JSONObject requestFileSystem(int type) throws IOException, JSONException {
-        JSONObject fs = new JSONObject();
-        if (type == TEMPORARY) {
-            File fp;
-            fs.put("name", "temporary");
-            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
-                fp = new File(Environment.getExternalStorageDirectory().getAbsolutePath() +
-                        "/Android/data/" + cordova.getActivity().getPackageName() + "/cache/");
-                // Create the cache dir if it doesn't exist.
-                fp.mkdirs();
-                fs.put("root", getEntry(Environment.getExternalStorageDirectory().getAbsolutePath() +
-                        "/Android/data/" + cordova.getActivity().getPackageName() + "/cache/"));
-            } else {
-                fp = new File("/data/data/" + cordova.getActivity().getPackageName() + "/cache/");
-                // Create the cache dir if it doesn't exist.
-                fp.mkdirs();
-                fs.put("root", getEntry("/data/data/" + cordova.getActivity().getPackageName() + "/cache/"));
-            }
-        }
-        else if (type == PERSISTENT) {
-            fs.put("name", "persistent");
-            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
-                fs.put("root", getEntry(Environment.getExternalStorageDirectory()));
-            } else {
-                fs.put("root", getEntry("/data/data/" + cordova.getActivity().getPackageName()));
-            }
-        }
-        else {
-            throw new IOException("No filesystem of type requested");
-        }
-
-        return fs;
-    }
-
-    /**
-     * Returns a JSON object representing the given File.
-     *
-     * @param file the File to convert
-     * @return a JSON representation of the given File
-     * @throws JSONException
-     */
-    public static JSONObject getEntry(File file) throws JSONException {
-        JSONObject entry = new JSONObject();
-
-        entry.put("isFile", file.isFile());
-        entry.put("isDirectory", file.isDirectory());
-        entry.put("name", file.getName());
-        entry.put("fullPath", "file://" + file.getAbsolutePath());
-        // The file system can't be specified, as it would lead to an infinite loop.
-        // entry.put("filesystem", null);
-
-        return entry;
-    }
-
-    /**
-     * Returns a JSON Object representing a directory on the device's file system
-     *
-     * @param path to the directory
-     * @return
-     * @throws JSONException
-     */
-    private JSONObject getEntry(String path) throws JSONException {
-        return getEntry(new File(path));
-    }
-
-
-    //--------------------------------------------------------------------------
-    // LOCAL METHODS
-    //--------------------------------------------------------------------------
-
-    /**
-     * Read the contents of a file.
-     * This is done in a background thread; the result is sent to the callback.
-     *
-     * @param filename          The name of the file.
-     * @param start             Start position in the file.
-     * @param end               End position to stop at (exclusive).
-     * @param callbackContext   The context through which to send the result.
-     * @param encoding          The encoding to return contents as.  Typical value is UTF-8. (see http://www.iana.org/assignments/character-sets)
-     * @param resultType        The desired type of data to send to the callback.
-     * @return                  Contents of file.
-     */
-    public void readFileAs(final String filename, final int start, final int end, final CallbackContext callbackContext, final String encoding, final int resultType) {
-        this.cordova.getThreadPool().execute(new Runnable() {
-            public void run() {
-                try {
-                    DataResource dataResource = DataResource.initiateNewDataRequestForUri(filename, webView.pluginManager, cordova, "FileUtils.readFileAs");
-                    byte[] bytes = readAsBinaryHelper(dataResource.getInputStream(), start, end);
-                    
-                    PluginResult result;
-                    switch (resultType) {
-                        case PluginResult.MESSAGE_TYPE_STRING:
-                            result = new PluginResult(PluginResult.Status.OK, new String(bytes, encoding));
-                            break;
-                        case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
-                            result = new PluginResult(PluginResult.Status.OK, bytes);
-                            break;
-                        case PluginResult.MESSAGE_TYPE_BINARYSTRING:
-                            result = new PluginResult(PluginResult.Status.OK, bytes, true);
-                            break;
-                        default: // Base64.
-                            String contentType = dataResource.getMimeType();
-                            byte[] base64 = Base64.encodeBase64(bytes);
-                            String s = "data:" + contentType + ";base64," + new String(base64, "US-ASCII");
-                            result = new PluginResult(PluginResult.Status.OK, s);
-                    }
-
-                    callbackContext.sendPluginResult(result);
-                } catch (FileNotFoundException e) {
-                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_FOUND_ERR));
-                } catch (IOException e) {
-                    Log.d(LOG_TAG, e.getLocalizedMessage());
-                    callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, NOT_READABLE_ERR));
-                }
-            }
-        });
-    }
-
-    /**
-     * Read the contents of a file as binary.
-     * This is done synchronously; the result is returned.
-     *
-     * @param filename          The name of the file.
-     * @param start             Start position in the file.
-     * @param end               End position to stop at (exclusive).
-     * @return                  Contents of the file as a byte[].
-     * @throws IOException
-     */
-    private byte[] readAsBinaryHelper(InputStream inputStream, int start, int end) throws IOException {
-        int numBytesToRead = end - start;
-        byte[] bytes = new byte[numBytesToRead];
-        int numBytesRead = 0;
-
-        if (start > 0) {
-            inputStream.skip(start);
-        }
-
-        while (numBytesToRead > 0 && (numBytesRead = inputStream.read(bytes, numBytesRead, numBytesToRead)) >= 0) {
-            numBytesToRead -= numBytesRead;
-        }
-
-        return bytes;
-    }
-
-    /**
-     * Write contents of file.
-     *
-     * @param filename			The name of the file.
-     * @param data				The contents of the file.
-     * @param offset			The position to begin writing the file.
-     * @throws FileNotFoundException, IOException
-     * @throws NoModificationAllowedException
-     */
-    /**/
-    public long write(String filename, String data, int offset) throws FileNotFoundException, IOException, NoModificationAllowedException {
-        if (filename.startsWith("content://")) {
-            throw new NoModificationAllowedException("Couldn't write to file given its content URI");
-        }
-
-        DataResource dataResource = DataResource.initiateNewDataRequestForUri(filename, webView.pluginManager, cordova, "FileUtils.write");
-        filename = dataResource.getRealFile().getPath();
-
-        boolean append = false;
-        if (offset > 0) {
-            this.truncateFile(filename, offset);
-            append = true;
-        }
-
-        byte[] rawData = data.getBytes();
-        ByteArrayInputStream in = new ByteArrayInputStream(rawData);
-        FileOutputStream out = new FileOutputStream(filename, append);
-        byte buff[] = new byte[rawData.length];
-        in.read(buff, 0, buff.length);
-        out.write(buff, 0, rawData.length);
-        out.flush();
-        out.close();
-
-        return rawData.length;
-    }
-
-    /**
-     * Truncate the file to size
-     *
-     * @param filename
-     * @param size
-     * @throws FileNotFoundException, IOException
-     * @throws NoModificationAllowedException
-     */
-    private long truncateFile(String filename, long size) throws FileNotFoundException, IOException, NoModificationAllowedException {
-        DataResource dataResource = DataResource.initiateNewDataRequestForUri(filename, webView.pluginManager, cordova, "FileUtils.truncateFile");
-        if(!dataResource.isWritable()) {
-            throw new NoModificationAllowedException("Couldn't truncate file as it is not writable");
-        }
-        File file = dataResource.getRealFile();
-        if(file == null) {
-            throw new FileNotFoundException("Couldn't get the file");
-        }
-
-        RandomAccessFile raf = new RandomAccessFile(file, "rw");
-        try {
-            if (raf.length() >= size) {
-                FileChannel channel = raf.getChannel();
-                channel.truncate(size);
-                return size;
-            }
-
-            return raf.length();
-        } finally {
-            raf.close();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/GPSListener.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/GPSListener.java b/framework/src/org/apache/cordova/GPSListener.java
deleted file mode 100755
index daaf7ee..0000000
--- a/framework/src/org/apache/cordova/GPSListener.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-       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 android.location.LocationManager;
-
-/**
- * This class handles requests for GPS location services.
- *
- */
-public class GPSListener extends CordovaLocationListener {
-    public GPSListener(LocationManager locationManager, GeoBroker m) {
-        super(locationManager, m, "[Cordova GPSListener]");
-    }
-
-
-    /**
-     * Start requesting location updates.
-     *
-     * @param interval
-     */
-    @Override
-    protected void start() {
-        if (!this.running) {
-            if (this.locationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
-                this.running = true;
-                this.locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 60000, 0, this);
-            } else {
-                this.fail(CordovaLocationListener.POSITION_UNAVAILABLE, "GPS provider is not available.");
-            }
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/GeoBroker.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/GeoBroker.java b/framework/src/org/apache/cordova/GeoBroker.java
deleted file mode 100644
index 4a07b73..0000000
--- a/framework/src/org/apache/cordova/GeoBroker.java
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
-       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.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.content.Context;
-import android.location.Location;
-import android.location.LocationManager;
-
-/*
- * This class is the interface to the Geolocation.  It's bound to the geo object.
- *
- * This class only starts and stops various GeoListeners, which consist of a GPS and a Network Listener
- */
-
-public class GeoBroker extends CordovaPlugin {
-    private GPSListener gpsListener;
-    private NetworkListener networkListener;
-    private LocationManager locationManager;    
-
-    /**
-     * Constructor.
-     */
-    public GeoBroker() {
-    }
-
-    /**
-     * Executes the request and returns PluginResult.
-     *
-     * @param action 		The action to execute.
-     * @param args 		JSONArry of arguments for the plugin.
-     * @param callbackContext	The callback id used when calling back into JavaScript.
-     * @return 			True if the action was valid, or false if not.
-     */
-    public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
-        if (this.locationManager == null) {
-            this.locationManager = (LocationManager) this.cordova.getActivity().getSystemService(Context.LOCATION_SERVICE);
-            this.networkListener = new NetworkListener(this.locationManager, this);
-            this.gpsListener = new GPSListener(this.locationManager, this);
-        }
-
-        if ( locationManager.isProviderEnabled( LocationManager.GPS_PROVIDER ) ||
-                locationManager.isProviderEnabled( LocationManager.NETWORK_PROVIDER )) {
-
-            if (action.equals("getLocation")) {
-                boolean enableHighAccuracy = args.getBoolean(0);
-                int maximumAge = args.getInt(1);
-                Location last = this.locationManager.getLastKnownLocation((enableHighAccuracy ? LocationManager.GPS_PROVIDER : LocationManager.NETWORK_PROVIDER));
-                // Check if we can use lastKnownLocation to get a quick reading and use less battery
-                if (last != null && (System.currentTimeMillis() - last.getTime()) <= maximumAge) {
-                    PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(last));
-                    callbackContext.sendPluginResult(result);
-                } else {
-                    this.getCurrentLocation(callbackContext, enableHighAccuracy, args.optInt(2, 60000));
-                }
-            }
-            else if (action.equals("addWatch")) {
-                String id = args.getString(0);
-                boolean enableHighAccuracy = args.getBoolean(1);
-                this.addWatch(id, callbackContext, enableHighAccuracy);
-            }
-            else if (action.equals("clearWatch")) {
-                String id = args.getString(0);
-                this.clearWatch(id);
-            }
-            else {
-                return false;
-            }
-        } else {
-            PluginResult.Status status = PluginResult.Status.NO_RESULT;
-            String message = "Location API is not available for this device.";
-            PluginResult result = new PluginResult(status, message);
-            callbackContext.sendPluginResult(result);
-        }
-        return true;
-    }
-
-    private void clearWatch(String id) {
-        this.gpsListener.clearWatch(id);
-        this.networkListener.clearWatch(id);
-    }
-
-    private void getCurrentLocation(CallbackContext callbackContext, boolean enableHighAccuracy, int timeout) {
-        if (enableHighAccuracy) {
-            this.gpsListener.addCallback(callbackContext, timeout);
-        } else {
-            this.networkListener.addCallback(callbackContext, timeout);
-        }
-    }
-
-    private void addWatch(String timerId, CallbackContext callbackContext, boolean enableHighAccuracy) {
-        if (enableHighAccuracy) {
-            this.gpsListener.addWatch(timerId, callbackContext);
-        } else {
-            this.networkListener.addWatch(timerId, callbackContext);
-        }
-    }
-
-    /**
-     * Called when the activity is to be shut down.
-     * Stop listener.
-     */
-    public void onDestroy() {
-        if (this.networkListener != null) {
-            this.networkListener.destroy();
-            this.networkListener = null;
-        }
-        if (this.gpsListener != null) {
-            this.gpsListener.destroy();
-            this.gpsListener = null;
-        }
-    }
-
-    /**
-     * Called when the view navigates.
-     * Stop the listeners.
-     */
-    public void onReset() {
-        this.onDestroy();
-    }
-
-    public JSONObject returnLocationJSON(Location loc) {
-        JSONObject o = new JSONObject();
-
-        try {
-            o.put("latitude", loc.getLatitude());
-            o.put("longitude", loc.getLongitude());
-            o.put("altitude", (loc.hasAltitude() ? loc.getAltitude() : null));
-            o.put("accuracy", loc.getAccuracy());
-            o.put("heading", (loc.hasBearing() ? (loc.hasSpeed() ? loc.getBearing() : null) : null));
-            o.put("velocity", loc.getSpeed());
-            o.put("timestamp", loc.getTime());
-        } catch (JSONException e) {
-            // TODO Auto-generated catch block
-            e.printStackTrace();
-        }
-
-        return o;
-    }
-
-    public void win(Location loc, CallbackContext callbackContext, boolean keepCallback) {
-    	PluginResult result = new PluginResult(PluginResult.Status.OK, this.returnLocationJSON(loc));
-    	result.setKeepCallback(keepCallback);
-        callbackContext.sendPluginResult(result);
-    }
-
-    /**
-     * Location failed.  Send error back to JavaScript.
-     * 
-     * @param code			The error code
-     * @param msg			The error message
-     * @throws JSONException 
-     */
-    public void fail(int code, String msg, CallbackContext callbackContext, boolean keepCallback) {
-        JSONObject obj = new JSONObject();
-        String backup = null;
-        try {
-            obj.put("code", code);
-            obj.put("message", msg);
-        } catch (JSONException e) {
-            obj = null;
-            backup = "{'code':" + code + ",'message':'" + msg.replaceAll("'", "\'") + "'}";
-        }
-        PluginResult result;
-        if (obj != null) {
-            result = new PluginResult(PluginResult.Status.ERROR, obj);
-        } else {
-            result = new PluginResult(PluginResult.Status.ERROR, backup);
-        }
-
-        result.setKeepCallback(keepCallback);
-        callbackContext.sendPluginResult(result);
-    }
-
-    public boolean isGlobalListener(CordovaLocationListener listener)
-    {
-    	if (gpsListener != null && networkListener != null)
-    	{
-    		return gpsListener.equals(listener) || networkListener.equals(listener);
-    	}
-    	else
-    		return false;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/Globalization.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/Globalization.java b/framework/src/org/apache/cordova/Globalization.java
deleted file mode 100644
index 5c75e10..0000000
--- a/framework/src/org/apache/cordova/Globalization.java
+++ /dev/null
@@ -1,577 +0,0 @@
-/*
-       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.text.DateFormat;
-import java.text.DecimalFormat;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Currency;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TimeZone;
-
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginResult;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import android.annotation.TargetApi;
-import android.text.format.Time;
-
-/**
- *
- */
-public class Globalization extends CordovaPlugin  {
-    //GlobalizationCommand Plugin Actions
-    public static final String GETLOCALENAME = "getLocaleName";
-    public static final String DATETOSTRING = "dateToString";
-    public static final String STRINGTODATE = "stringToDate";
-    public static final String GETDATEPATTERN = "getDatePattern";
-    public static final String GETDATENAMES = "getDateNames";
-    public static final String ISDAYLIGHTSAVINGSTIME = "isDayLightSavingsTime";
-    public static final String GETFIRSTDAYOFWEEK = "getFirstDayOfWeek";
-    public static final String NUMBERTOSTRING = "numberToString";
-    public static final String STRINGTONUMBER = "stringToNumber";
-    public static final String GETNUMBERPATTERN = "getNumberPattern";
-    public static final String GETCURRENCYPATTERN = "getCurrencyPattern";
-    public static final String GETPREFERREDLANGUAGE = "getPreferredLanguage";
-
-    //GlobalizationCommand Option Parameters
-    public static final String OPTIONS = "options";
-    public static final String FORMATLENGTH = "formatLength";
-    //public static final String SHORT = "short"; //default for dateToString format
-    public static final String MEDIUM = "medium";
-    public static final String LONG = "long";
-    public static final String FULL = "full";
-    public static final String SELECTOR = "selector";
-    //public static final String DATEANDTIME = "date and time"; //default for dateToString
-    public static final String DATE = "date";
-    public static final String TIME = "time";
-    public static final String DATESTRING = "dateString";
-    public static final String TYPE = "type";
-    public static final String ITEM = "item";
-    public static final String NARROW = "narrow";
-    public static final String WIDE = "wide";
-    public static final String MONTHS = "months";
-    public static final String DAYS = "days";
-    //public static final String DECMIAL = "wide"; //default for numberToString
-    public static final String NUMBER = "number";
-    public static final String NUMBERSTRING = "numberString";
-    public static final String PERCENT = "percent";
-    public static final String CURRENCY = "currency";
-    public static final String CURRENCYCODE = "currencyCode";
-
-    @Override
-    public boolean execute(String action, JSONArray data, CallbackContext callbackContext) {
-        JSONObject obj = new JSONObject();
-
-        try{
-            if (action.equals(GETLOCALENAME)){
-                obj = getLocaleName();
-            }else if (action.equals(GETPREFERREDLANGUAGE)){
-                obj = getPreferredLanguage();
-            } else if (action.equalsIgnoreCase(DATETOSTRING)) {
-                obj = getDateToString(data);
-            }else if(action.equalsIgnoreCase(STRINGTODATE)){
-                obj = getStringtoDate(data);
-            }else if(action.equalsIgnoreCase(GETDATEPATTERN)){
-                obj = getDatePattern(data);
-            }else if(action.equalsIgnoreCase(GETDATENAMES)){
-                if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.GINGERBREAD) {
-                    throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
-                } else {
-                    obj = getDateNames(data);
-                }
-            }else if(action.equalsIgnoreCase(ISDAYLIGHTSAVINGSTIME)){
-                obj = getIsDayLightSavingsTime(data);
-            }else if(action.equalsIgnoreCase(GETFIRSTDAYOFWEEK)){
-                obj = getFirstDayOfWeek(data);
-            }else if(action.equalsIgnoreCase(NUMBERTOSTRING)){
-                obj = getNumberToString(data);
-            }else if(action.equalsIgnoreCase(STRINGTONUMBER)){
-                obj = getStringToNumber(data);
-            }else if(action.equalsIgnoreCase(GETNUMBERPATTERN)){
-                obj = getNumberPattern(data);
-            }else if(action.equalsIgnoreCase(GETCURRENCYPATTERN)){
-                obj = getCurrencyPattern(data);
-            }else {
-                return false;
-            }
-
-            callbackContext.success(obj);
-        }catch (GlobalizationError ge){
-            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, ge.toJson()));
-        }catch (Exception e){
-            callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
-        }
-        return true;
-    }
-    /*
-     * @Description: Returns the string identifier for the client's current locale setting
-     *
-     * @Return: JSONObject
-     *          Object.value {String}: The locale identifier
-     *
-     * @throws: GlobalizationError.UNKNOWN_ERROR
-     */
-    private JSONObject getLocaleName() throws GlobalizationError{
-        JSONObject obj = new JSONObject();
-        try{
-            obj.put("value",Locale.getDefault().toString());//get the locale from the Android Device
-            return obj;
-        }catch(Exception e){
-            throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
-        }
-    }
-    /*
-     * @Description: Returns the string identifier for the client's current language
-     *
-     * @Return: JSONObject
-     *          Object.value {String}: The language identifier
-     *
-     * @throws: GlobalizationError.UNKNOWN_ERROR
-     */
-    private JSONObject getPreferredLanguage() throws GlobalizationError {
-        JSONObject obj = new JSONObject();
-        try {
-            obj.put("value", Locale.getDefault().getDisplayLanguage().toString());
-            return obj;
-        } catch (Exception e) {
-            throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
-        }
-    }
-    /*
-     * @Description: Returns a date formatted as a string according to the client's user preferences and
-     * calendar using the time zone of the client.
-     *
-     * @Return: JSONObject
-     *          Object.value {String}: The localized date string
-     *
-     * @throws: GlobalizationError.FORMATTING_ERROR
-     */
-    private JSONObject getDateToString(JSONArray options) throws GlobalizationError{
-        JSONObject obj = new JSONObject();
-        try{
-            Date date = new Date((Long)options.getJSONObject(0).get(DATE));
-
-            //get formatting pattern from android device (Will only have device specific formatting for short form of date) or options supplied
-            JSONObject datePattern = getDatePattern(options);
-            SimpleDateFormat fmt = new SimpleDateFormat(datePattern.getString("pattern"));
-
-            //return formatted date
-            return obj.put("value",fmt.format(date));
-        }catch(Exception ge){
-            throw new GlobalizationError(GlobalizationError.FORMATTING_ERROR);
-        }
-    }
-
-    /*
-     * @Description: Parses a date formatted as a string according to the client's user
-     * preferences and calendar using the time zone of the client and returns
-     * the corresponding date object
-     * @Return: JSONObject
-     *          Object.year {Number}: The four digit year
-     *          Object.month {Number}: The month from (0 - 11)
-     *          Object.day {Number}: The day from (1 - 31)
-     *          Object.hour {Number}: The hour from (0 - 23)
-     *          Object.minute {Number}: The minute from (0 - 59)
-     *          Object.second {Number}: The second from (0 - 59)
-     *          Object.millisecond {Number}: The milliseconds (from 0 - 999), not available on all platforms
-     *
-     * @throws: GlobalizationError.PARSING_ERROR
-    */
-    private JSONObject getStringtoDate(JSONArray options)throws GlobalizationError{
-        JSONObject obj = new JSONObject();
-        Date date;
-        try{
-            //get format pattern from android device (Will only have device specific formatting for short form of date) or options supplied
-            DateFormat fmt = new SimpleDateFormat(getDatePattern(options).getString("pattern"));
-
-            //attempt parsing string based on user preferences
-            date = fmt.parse(options.getJSONObject(0).get(DATESTRING).toString());
-
-            //set Android Time object
-            Time time = new Time();
-            time.set(date.getTime());
-
-            //return properties;
-            obj.put("year", time.year);
-            obj.put("month", time.month);
-            obj.put("day", time.monthDay);
-            obj.put("hour", time.hour);
-            obj.put("minute", time.minute);
-            obj.put("second", time.second);
-            obj.put("millisecond", new Long(0));
-            return obj;
-        }catch(Exception ge){
-            throw new GlobalizationError(GlobalizationError.PARSING_ERROR);
-        }
-    }
-
-    /*
-     * @Description: Returns a pattern string for formatting and parsing dates according to the client's
-     * user preferences.
-     * @Return: JSONObject
-     *
-     *          Object.pattern {String}: The date and time pattern for formatting and parsing dates.
-     *                                  The patterns follow Unicode Technical Standard #35
-     *                                  http://unicode.org/reports/tr35/tr35-4.html
-     *          Object.timezone {String}: The abbreviated name of the time zone on the client
-     *          Object.utc_offset {Number}: The current difference in seconds between the client's
-     *                                      time zone and coordinated universal time.
-     *          Object.dst_offset {Number}: The current daylight saving time offset in seconds
-     *                                      between the client's non-daylight saving's time zone
-     *                                      and the client's daylight saving's time zone.
-     *
-     * @throws: GlobalizationError.PATTERN_ERROR
-    */
-    private JSONObject getDatePattern(JSONArray options) throws GlobalizationError{
-        JSONObject obj = new JSONObject();
-
-        try{
-            SimpleDateFormat fmtDate = (SimpleDateFormat)android.text.format.DateFormat.getDateFormat(this.cordova.getActivity()); //default user preference for date
-            SimpleDateFormat fmtTime = (SimpleDateFormat)android.text.format.DateFormat.getTimeFormat(this.cordova.getActivity());  //default user preference for time
-
-            String fmt = fmtDate.toLocalizedPattern() + " " + fmtTime.toLocalizedPattern(); //default SHORT date/time format. ex. dd/MM/yyyy h:mm a
-
-            //get Date value + options (if available)
-            if (options.getJSONObject(0).length() > 1){
-                //options were included
-
-                //get formatLength option
-                if (!((JSONObject)options.getJSONObject(0).get(OPTIONS)).isNull(FORMATLENGTH)){
-                    String fmtOpt = (String)((JSONObject)options.getJSONObject(0).get(OPTIONS)).get(FORMATLENGTH);
-                    if (fmtOpt.equalsIgnoreCase(MEDIUM)){//medium
-                        fmtDate = (SimpleDateFormat)android.text.format.DateFormat.getMediumDateFormat(this.cordova.getActivity());
-                    }else if (fmtOpt.equalsIgnoreCase(LONG) || fmtOpt.equalsIgnoreCase(FULL)){ //long/full
-                        fmtDate = (SimpleDateFormat)android.text.format.DateFormat.getLongDateFormat(this.cordova.getActivity());
-                    }
-                }
-
-                //return pattern type
-                fmt = fmtDate.toLocalizedPattern() + " " + fmtTime.toLocalizedPattern();
-                if (!((JSONObject)options.getJSONObject(0).get(OPTIONS)).isNull(SELECTOR)){
-                    String selOpt = (String)((JSONObject)options.getJSONObject(0).get(OPTIONS)).get(SELECTOR);
-                    if (selOpt.equalsIgnoreCase(DATE)){
-                        fmt =  fmtDate.toLocalizedPattern();
-                    }else if (selOpt.equalsIgnoreCase(TIME)){
-                        fmt = fmtTime.toLocalizedPattern();
-                    }
-                }
-            }
-
-            //TimeZone from users device
-            //TimeZone tz = Calendar.getInstance(Locale.getDefault()).getTimeZone(); //substitute method
-            TimeZone tz = TimeZone.getTimeZone(Time.getCurrentTimezone());
-
-            obj.put("pattern", fmt);
-            obj.put("timezone", tz.getDisplayName(tz.inDaylightTime(Calendar.getInstance().getTime()),TimeZone.SHORT));
-            obj.put("utc_offset", tz.getRawOffset()/1000);
-            obj.put("dst_offset", tz.getDSTSavings()/1000);
-            return obj;
-
-        }catch(Exception ge){
-            throw new GlobalizationError(GlobalizationError.PATTERN_ERROR);
-        }
-    }
-
-    /*
-     * @Description: Returns an array of either the names of the months or days of the week
-     * according to the client's user preferences and calendar
-     * @Return: JSONObject
-     *          Object.value {Array{String}}: The array of names starting from either
-     *                                      the first month in the year or the
-     *                                      first day of the week.
-     *
-     * @throws: GlobalizationError.UNKNOWN_ERROR
-    */
-    @TargetApi(9)
-    private JSONObject getDateNames(JSONArray options) throws GlobalizationError{
-        JSONObject obj = new JSONObject();
-        //String[] value;
-        JSONArray value = new JSONArray();
-        List<String> namesList = new ArrayList<String>();
-        final Map<String,Integer> namesMap; // final needed for sorting with anonymous comparator
-        try{
-            int type = 0; //default wide
-            int item = 0; //default months
-
-            //get options if available
-            if (options.getJSONObject(0).length() > 0){
-                //get type if available
-                if (!((JSONObject)options.getJSONObject(0).get(OPTIONS)).isNull(TYPE)){
-                    String t = (String)((JSONObject)options.getJSONObject(0).get(OPTIONS)).get(TYPE);
-                    if (t.equalsIgnoreCase(NARROW)){type++;} //DateUtils.LENGTH_MEDIUM
-                }
-                //get item if available
-                if (!((JSONObject)options.getJSONObject(0).get(OPTIONS)).isNull(ITEM)){
-                    String t = (String)((JSONObject)options.getJSONObject(0).get(OPTIONS)).get(ITEM);
-                    if (t.equalsIgnoreCase(DAYS)){item += 10;} //Days of week start at 1
-                }
-            }
-            //determine return value
-            int method = item + type;
-            if  (method == 1) { //months and narrow
-                namesMap = Calendar.getInstance().getDisplayNames(Calendar.MONTH, Calendar.SHORT, Locale.getDefault());
-            } else if (method == 10) { //days and wide
-                namesMap = Calendar.getInstance().getDisplayNames(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.getDefault());
-            } else if (method == 11) { //days and narrow
-                namesMap = Calendar.getInstance().getDisplayNames(Calendar.DAY_OF_WEEK, Calendar.SHORT, Locale.getDefault());
-            } else { //default: months and wide
-                namesMap = Calendar.getInstance().getDisplayNames(Calendar.MONTH, Calendar.LONG, Locale.getDefault());
-            }
-
-            // save names as a list
-            for(String name : namesMap.keySet()) {
-                namesList.add(name);
-            }
-
-            // sort the list according to values in namesMap
-            Collections.sort(namesList, new Comparator<String>() {
-                public int compare(String arg0, String arg1) {
-                    return namesMap.get(arg0).compareTo(namesMap.get(arg1));
-                }
-            });
-
-            // convert nameList into JSONArray of String objects
-            for (int i = 0; i < namesList.size(); i ++){
-                value.put(namesList.get(i));
-            }
-
-            //return array of names
-            return obj.put("value", value);
-        }catch(Exception ge){
-            throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
-        }
-    }
-
-    /*
-     * @Description: Returns whether daylight savings time is in effect for a given date using the client's
-     * time zone and calendar.
-     * @Return: JSONObject
-     *          Object.dst {Boolean}: The value "true" indicates that daylight savings time is
-     *                              in effect for the given date and "false" indicate that it is not.    *
-     *
-     * @throws: GlobalizationError.UNKNOWN_ERROR
-    */
-    private JSONObject getIsDayLightSavingsTime(JSONArray options) throws GlobalizationError{
-        JSONObject obj = new JSONObject();
-        boolean dst = false;
-        try{
-            Date date = new Date((Long)options.getJSONObject(0).get(DATE));
-            //TimeZone tz = Calendar.getInstance(Locale.getDefault()).getTimeZone();
-            TimeZone tz = TimeZone.getTimeZone(Time.getCurrentTimezone());
-            dst = tz.inDaylightTime(date); //get daylight savings data from date object and user timezone settings
-
-            return obj.put("dst",dst);
-        }catch(Exception ge){
-            throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
-        }
-    }
-
-    /*
-     * @Description: Returns the first day of the week according to the client's user preferences and calendar.
-     * The days of the week are numbered starting from 1 where 1 is considered to be Sunday.
-     * @Return: JSONObject
-     *          Object.value {Number}: The number of the first day of the week.
-     *
-     * @throws: GlobalizationError.UNKNOWN_ERROR
-    */
-    private JSONObject getFirstDayOfWeek(JSONArray options) throws GlobalizationError{
-        JSONObject obj = new JSONObject();
-        try{
-            int value = Calendar.getInstance(Locale.getDefault()).getFirstDayOfWeek(); //get first day of week based on user locale settings
-            return obj.put("value", value);
-        }catch(Exception ge){
-            throw new GlobalizationError(GlobalizationError.UNKNOWN_ERROR);
-        }
-    }
-
-    /*
-     * @Description: Returns a number formatted as a string according to the client's user preferences.
-     * @Return: JSONObject
-     *          Object.value {String}: The formatted number string.
-     *
-     * @throws: GlobalizationError.FORMATTING_ERROR
-    */
-    private JSONObject getNumberToString(JSONArray options) throws GlobalizationError{
-        JSONObject obj = new JSONObject();
-        String value = "";
-        try{
-            DecimalFormat fmt = getNumberFormatInstance(options);//returns Decimal/Currency/Percent instance
-            value = fmt.format(options.getJSONObject(0).get(NUMBER));
-            return obj.put("value", value);
-        }catch(Exception ge){
-            throw new GlobalizationError(GlobalizationError.FORMATTING_ERROR);
-        }
-    }
-
-    /*
-     * @Description: Parses a number formatted as a string according to the client's user preferences and
-     * returns the corresponding number.
-     * @Return: JSONObject
-     *          Object.value {Number}: The parsed number.
-     *
-     * @throws: GlobalizationError.PARSING_ERROR
-    */
-    private JSONObject getStringToNumber(JSONArray options) throws GlobalizationError{
-        JSONObject obj = new JSONObject();
-        Number value;
-        try{
-            DecimalFormat fmt = getNumberFormatInstance(options); //returns Decimal/Currency/Percent instance
-            value = fmt.parse((String)options.getJSONObject(0).get(NUMBERSTRING));
-            return obj.put("value", value);
-        }catch(Exception ge){
-            throw new GlobalizationError(GlobalizationError.PARSING_ERROR);
-        }
-    }
-
-    /*
-     * @Description: Returns a pattern string for formatting and parsing numbers according to the client's user
-     * preferences.
-     * @Return: JSONObject
-     *          Object.pattern {String}: The number pattern for formatting and parsing numbers.
-     *                                  The patterns follow Unicode Technical Standard #35.
-     *                                  http://unicode.org/reports/tr35/tr35-4.html
-     *          Object.symbol {String}: The symbol to be used when formatting and parsing
-     *                                  e.g., percent or currency symbol.
-     *          Object.fraction {Number}: The number of fractional digits to use when parsing and
-     *                                  formatting numbers.
-     *          Object.rounding {Number}: The rounding increment to use when parsing and formatting.
-     *          Object.positive {String}: The symbol to use for positive numbers when parsing and formatting.
-     *          Object.negative: {String}: The symbol to use for negative numbers when parsing and formatting.
-     *          Object.decimal: {String}: The decimal symbol to use for parsing and formatting.
-     *          Object.grouping: {String}: The grouping symbol to use for parsing and formatting.
-     *
-     * @throws: GlobalizationError.PATTERN_ERROR
-    */
-    private JSONObject getNumberPattern(JSONArray options) throws GlobalizationError{
-        JSONObject obj = new JSONObject();
-        try{
-            //uses java.text.DecimalFormat to format value
-            DecimalFormat fmt = (DecimalFormat) DecimalFormat.getInstance(Locale.getDefault()); //default format
-            String symbol = String.valueOf(fmt.getDecimalFormatSymbols().getDecimalSeparator());
-            //get Date value + options (if available)
-            if (options.getJSONObject(0).length() > 0){
-                //options were included
-                if (!((JSONObject)options.getJSONObject(0).get(OPTIONS)).isNull(TYPE)){
-                    String fmtOpt = (String)((JSONObject)options.getJSONObject(0).get(OPTIONS)).get(TYPE);
-                    if (fmtOpt.equalsIgnoreCase(CURRENCY)){
-                        fmt = (DecimalFormat) DecimalFormat.getCurrencyInstance(Locale.getDefault());
-                        symbol = fmt.getDecimalFormatSymbols().getCurrencySymbol();
-                    }else if(fmtOpt.equalsIgnoreCase(PERCENT)){
-                        fmt = (DecimalFormat) DecimalFormat.getPercentInstance(Locale.getDefault());
-                        symbol = String.valueOf(fmt.getDecimalFormatSymbols().getPercent());
-                    }
-                }
-            }
-
-            //return properties
-            obj.put("pattern", fmt.toPattern());
-            obj.put("symbol", symbol);
-            obj.put("fraction", fmt.getMinimumFractionDigits());
-            obj.put("rounding", new Integer(0));
-            obj.put("positive", fmt.getPositivePrefix());
-            obj.put("negative", fmt.getNegativePrefix());
-            obj.put("decimal", String.valueOf(fmt.getDecimalFormatSymbols().getDecimalSeparator()));
-            obj.put("grouping", String.valueOf(fmt.getDecimalFormatSymbols().getGroupingSeparator()));
-
-            return obj;
-        }catch(Exception ge){
-            throw new GlobalizationError(GlobalizationError.PATTERN_ERROR);
-        }
-    }
-
-    /*
-     * @Description: Returns a pattern string for formatting and parsing currency values according to the client's
-     * user preferences and ISO 4217 currency code.
-     * @Return: JSONObject
-     *          Object.pattern {String}: The currency pattern for formatting and parsing currency values.
-     *                                  The patterns follow Unicode Technical Standard #35
-     *                                  http://unicode.org/reports/tr35/tr35-4.html
-     *          Object.code {String}: The ISO 4217 currency code for the pattern.
-     *          Object.fraction {Number}: The number of fractional digits to use when parsing and
-     *                                  formatting currency.
-     *          Object.rounding {Number}: The rounding increment to use when parsing and formatting.
-     *          Object.decimal: {String}: The decimal symbol to use for parsing and formatting.
-     *          Object.grouping: {String}: The grouping symbol to use for parsing and formatting.
-     *
-     * @throws: GlobalizationError.FORMATTING_ERROR
-    */
-    private JSONObject getCurrencyPattern(JSONArray options) throws GlobalizationError{
-        JSONObject obj = new JSONObject();
-        try{
-            //get ISO 4217 currency code
-            String code = options.getJSONObject(0).getString(CURRENCYCODE);
-
-            //uses java.text.DecimalFormat to format value
-            DecimalFormat fmt = (DecimalFormat) DecimalFormat.getCurrencyInstance(Locale.getDefault());
-
-            //set currency format
-            Currency currency = Currency.getInstance(code);
-            fmt.setCurrency(currency);
-
-            //return properties
-            obj.put("pattern", fmt.toPattern());
-            obj.put("code", currency.getCurrencyCode());
-            obj.put("fraction", fmt.getMinimumFractionDigits());
-            obj.put("rounding", new Integer(0));
-            obj.put("decimal", String.valueOf(fmt.getDecimalFormatSymbols().getDecimalSeparator()));
-            obj.put("grouping", String.valueOf(fmt.getDecimalFormatSymbols().getGroupingSeparator()));
-
-            return obj;
-        }catch(Exception ge){
-            throw new GlobalizationError(GlobalizationError.FORMATTING_ERROR);
-        }
-    }
-
-    /*
-     * @Description: Parses a JSONArray from user options and returns the correct Instance of Decimal/Percent/Currency.
-     * @Return: DecimalFormat : The Instance to use.
-     *
-     * @throws: JSONException
-    */
-    private DecimalFormat getNumberFormatInstance(JSONArray options) throws JSONException{
-        DecimalFormat fmt =  (DecimalFormat)DecimalFormat.getInstance(Locale.getDefault()); //default format
-        try{
-            if (options.getJSONObject(0).length() > 1){
-                //options were included
-                if (!((JSONObject)options.getJSONObject(0).get(OPTIONS)).isNull(TYPE)){
-                    String fmtOpt = (String)((JSONObject)options.getJSONObject(0).get(OPTIONS)).get(TYPE);
-                    if (fmtOpt.equalsIgnoreCase(CURRENCY)){
-                        fmt = (DecimalFormat)DecimalFormat.getCurrencyInstance(Locale.getDefault());
-                    }else if(fmtOpt.equalsIgnoreCase(PERCENT)){
-                        fmt = (DecimalFormat)DecimalFormat.getPercentInstance(Locale.getDefault());
-                    }
-                }
-            }
-
-        }catch (JSONException je){}
-        return fmt;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/adcbd879/framework/src/org/apache/cordova/GlobalizationError.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/GlobalizationError.java b/framework/src/org/apache/cordova/GlobalizationError.java
deleted file mode 100644
index 8a171d4..0000000
--- a/framework/src/org/apache/cordova/GlobalizationError.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
-       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.json.JSONException;
-import org.json.JSONObject;
-
-/** 
- * @description Exception class representing defined Globalization error codes
- * @Globalization error codes:
- *      GlobalizationError.UNKNOWN_ERROR = 0;
- *      GlobalizationError.FORMATTING_ERROR = 1;   
- *      GlobalizationError.PARSING_ERROR = 2;   
- *      GlobalizationError.PATTERN_ERROR = 3;
- */
-public class GlobalizationError extends Exception{
-    /**
-     * 
-     */
-    private static final long serialVersionUID = 1L;
-    public static final String UNKNOWN_ERROR = "UNKNOWN_ERROR";
-    public static final String FORMATTING_ERROR = "FORMATTING_ERROR";
-    public static final String PARSING_ERROR = "PARSING_ERROR";
-    public static final String PATTERN_ERROR = "PATTERN_ERROR";
-    
-    int error = 0;  //default unknown error thrown
-    /**
-     * Default constructor        
-     */
-    public GlobalizationError() {}
-    /**
-     * Create an exception returning an error code 
-     *    
-     * @param   s           
-     */
-    public GlobalizationError(String s) {       
-        if (s.equalsIgnoreCase(FORMATTING_ERROR)){
-            error = 1;
-        }else if (s.equalsIgnoreCase(PARSING_ERROR)){
-            error = 2;
-        }else if (s.equalsIgnoreCase(PATTERN_ERROR)){
-            error = 3;
-        }       
-    }
-    /**
-     * get error string based on error code 
-     *    
-     * @param   String msg           
-     */
-    public String getErrorString(){
-        String msg = "";
-        switch (error){
-        case 0:
-            msg = UNKNOWN_ERROR;
-            break;
-        case 1:
-            msg =  FORMATTING_ERROR;
-            break;
-        case 2:
-            msg =  PARSING_ERROR;
-            break;
-        case 3:
-            msg =  PATTERN_ERROR;
-            break;
-        }
-        return msg;
-    }
-    /**
-     * get error code 
-     *    
-     * @param   String msg           
-     */
-    public int getErrorCode(){      
-        return error;
-    }
-    
-    /**
-     * get the json version of this object to return to javascript
-     * @return
-     */
-    public JSONObject toJson() {
-        JSONObject obj = new JSONObject();
-        try {
-            obj.put("code", getErrorCode());
-            obj.put("message", getErrorString());
-        } catch (JSONException e) {
-            // never happens
-        }
-        return obj;
-    }
-}


[04/22] [CB-3307] Rename cordova-VERSION.js -> cordova.js

Posted by st...@apache.org.
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8a95ed8e/framework/assets/js/cordova.android.js
----------------------------------------------------------------------
diff --git a/framework/assets/js/cordova.android.js b/framework/assets/js/cordova.android.js
deleted file mode 100644
index 2941307..0000000
--- a/framework/assets/js/cordova.android.js
+++ /dev/null
@@ -1,6836 +0,0 @@
-// Platform: android
-
-// commit d0ffb852378ff018bac2f3b12c38098a19b8ce00
-
-// File generated at :: Thu Apr 18 2013 15:10:54 GMT-0400 (EDT)
-
-/*
- 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.
-*/
-
-;(function() {
-
-// file: lib/scripts/require.js
-
-var require,
-    define;
-
-(function () {
-    var modules = {};
-    // Stack of moduleIds currently being built.
-    var requireStack = [];
-    // Map of module ID -> index into requireStack of modules currently being built.
-    var inProgressModules = {};
-
-    function build(module) {
-        var factory = module.factory;
-        module.exports = {};
-        delete module.factory;
-        factory(require, module.exports, module);
-        return module.exports;
-    }
-
-    require = function (id) {
-        if (!modules[id]) {
-            throw "module " + id + " not found";
-        } else if (id in inProgressModules) {
-            var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
-            throw "Cycle in require graph: " + cycle;
-        }
-        if (modules[id].factory) {
-            try {
-                inProgressModules[id] = requireStack.length;
-                requireStack.push(id);
-                return build(modules[id]);
-            } finally {
-                delete inProgressModules[id];
-                requireStack.pop();
-            }
-        }
-        return modules[id].exports;
-    };
-
-    define = function (id, factory) {
-        if (modules[id]) {
-            throw "module " + id + " already defined";
-        }
-
-        modules[id] = {
-            id: id,
-            factory: factory
-        };
-    };
-
-    define.remove = function (id) {
-        delete modules[id];
-    };
-
-    define.moduleMap = modules;
-})();
-
-//Export for use in node
-if (typeof module === "object" && typeof require === "function") {
-    module.exports.require = require;
-    module.exports.define = define;
-}
-
-// file: lib/cordova.js
-define("cordova", function(require, exports, module) {
-
-
-var channel = require('cordova/channel');
-
-/**
- * Listen for DOMContentLoaded and notify our channel subscribers.
- */
-document.addEventListener('DOMContentLoaded', function() {
-    channel.onDOMContentLoaded.fire();
-}, false);
-if (document.readyState == 'complete' || document.readyState == 'interactive') {
-    channel.onDOMContentLoaded.fire();
-}
-
-/**
- * Intercept calls to addEventListener + removeEventListener and handle deviceready,
- * resume, and pause events.
- */
-var m_document_addEventListener = document.addEventListener;
-var m_document_removeEventListener = document.removeEventListener;
-var m_window_addEventListener = window.addEventListener;
-var m_window_removeEventListener = window.removeEventListener;
-
-/**
- * Houses custom event handlers to intercept on document + window event listeners.
- */
-var documentEventHandlers = {},
-    windowEventHandlers = {};
-
-document.addEventListener = function(evt, handler, capture) {
-    var e = evt.toLowerCase();
-    if (typeof documentEventHandlers[e] != 'undefined') {
-        documentEventHandlers[e].subscribe(handler);
-    } else {
-        m_document_addEventListener.call(document, evt, handler, capture);
-    }
-};
-
-window.addEventListener = function(evt, handler, capture) {
-    var e = evt.toLowerCase();
-    if (typeof windowEventHandlers[e] != 'undefined') {
-        windowEventHandlers[e].subscribe(handler);
-    } else {
-        m_window_addEventListener.call(window, evt, handler, capture);
-    }
-};
-
-document.removeEventListener = function(evt, handler, capture) {
-    var e = evt.toLowerCase();
-    // If unsubscribing from an event that is handled by a plugin
-    if (typeof documentEventHandlers[e] != "undefined") {
-        documentEventHandlers[e].unsubscribe(handler);
-    } else {
-        m_document_removeEventListener.call(document, evt, handler, capture);
-    }
-};
-
-window.removeEventListener = function(evt, handler, capture) {
-    var e = evt.toLowerCase();
-    // If unsubscribing from an event that is handled by a plugin
-    if (typeof windowEventHandlers[e] != "undefined") {
-        windowEventHandlers[e].unsubscribe(handler);
-    } else {
-        m_window_removeEventListener.call(window, evt, handler, capture);
-    }
-};
-
-function createEvent(type, data) {
-    var event = document.createEvent('Events');
-    event.initEvent(type, false, false);
-    if (data) {
-        for (var i in data) {
-            if (data.hasOwnProperty(i)) {
-                event[i] = data[i];
-            }
-        }
-    }
-    return event;
-}
-
-if(typeof window.console === "undefined") {
-    window.console = {
-        log:function(){}
-    };
-}
-
-var cordova = {
-    define:define,
-    require:require,
-    /**
-     * Methods to add/remove your own addEventListener hijacking on document + window.
-     */
-    addWindowEventHandler:function(event) {
-        return (windowEventHandlers[event] = channel.create(event));
-    },
-    addStickyDocumentEventHandler:function(event) {
-        return (documentEventHandlers[event] = channel.createSticky(event));
-    },
-    addDocumentEventHandler:function(event) {
-        return (documentEventHandlers[event] = channel.create(event));
-    },
-    removeWindowEventHandler:function(event) {
-        delete windowEventHandlers[event];
-    },
-    removeDocumentEventHandler:function(event) {
-        delete documentEventHandlers[event];
-    },
-    /**
-     * Retrieve original event handlers that were replaced by Cordova
-     *
-     * @return object
-     */
-    getOriginalHandlers: function() {
-        return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
-        'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
-    },
-    /**
-     * Method to fire event from native code
-     * bNoDetach is required for events which cause an exception which needs to be caught in native code
-     */
-    fireDocumentEvent: function(type, data, bNoDetach) {
-        var evt = createEvent(type, data);
-        if (typeof documentEventHandlers[type] != 'undefined') {
-            if( bNoDetach ) {
-              documentEventHandlers[type].fire(evt);
-            }
-            else {
-              setTimeout(function() {
-                  // Fire deviceready on listeners that were registered before cordova.js was loaded.
-                  if (type == 'deviceready') {
-                      document.dispatchEvent(evt);
-                  }
-                  documentEventHandlers[type].fire(evt);
-              }, 0);
-            }
-        } else {
-            document.dispatchEvent(evt);
-        }
-    },
-    fireWindowEvent: function(type, data) {
-        var evt = createEvent(type,data);
-        if (typeof windowEventHandlers[type] != 'undefined') {
-            setTimeout(function() {
-                windowEventHandlers[type].fire(evt);
-            }, 0);
-        } else {
-            window.dispatchEvent(evt);
-        }
-    },
-
-    /**
-     * Plugin callback mechanism.
-     */
-    // Randomize the starting callbackId to avoid collisions after refreshing or navigating.
-    // This way, it's very unlikely that any new callback would get the same callbackId as an old callback.
-    callbackId: Math.floor(Math.random() * 2000000000),
-    callbacks:  {},
-    callbackStatus: {
-        NO_RESULT: 0,
-        OK: 1,
-        CLASS_NOT_FOUND_EXCEPTION: 2,
-        ILLEGAL_ACCESS_EXCEPTION: 3,
-        INSTANTIATION_EXCEPTION: 4,
-        MALFORMED_URL_EXCEPTION: 5,
-        IO_EXCEPTION: 6,
-        INVALID_ACTION: 7,
-        JSON_EXCEPTION: 8,
-        ERROR: 9
-    },
-
-    /**
-     * Called by native code when returning successful result from an action.
-     */
-    callbackSuccess: function(callbackId, args) {
-        try {
-            cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback);
-        } catch (e) {
-            console.log("Error in error callback: " + callbackId + " = "+e);
-        }
-    },
-
-    /**
-     * Called by native code when returning error result from an action.
-     */
-    callbackError: function(callbackId, args) {
-        // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative.
-        // Derive success from status.
-        try {
-            cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback);
-        } catch (e) {
-            console.log("Error in error callback: " + callbackId + " = "+e);
-        }
-    },
-
-    /**
-     * Called by native code when returning the result from an action.
-     */
-    callbackFromNative: function(callbackId, success, status, args, keepCallback) {
-        var callback = cordova.callbacks[callbackId];
-        if (callback) {
-            if (success && status == cordova.callbackStatus.OK) {
-                callback.success && callback.success.apply(null, args);
-            } else if (!success) {
-                callback.fail && callback.fail.apply(null, args);
-            }
-
-            // Clear callback if not expecting any more results
-            if (!keepCallback) {
-                delete cordova.callbacks[callbackId];
-            }
-        }
-    },
-    addConstructor: function(func) {
-        channel.onCordovaReady.subscribe(function() {
-            try {
-                func();
-            } catch(e) {
-                console.log("Failed to run constructor: " + e);
-            }
-        });
-    }
-};
-
-// Register pause, resume and deviceready channels as events on document.
-channel.onPause = cordova.addDocumentEventHandler('pause');
-channel.onResume = cordova.addDocumentEventHandler('resume');
-channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
-
-module.exports = cordova;
-
-});
-
-// file: lib/common/argscheck.js
-define("cordova/argscheck", function(require, exports, module) {
-
-var exec = require('cordova/exec');
-var utils = require('cordova/utils');
-
-var moduleExports = module.exports;
-
-var typeMap = {
-    'A': 'Array',
-    'D': 'Date',
-    'N': 'Number',
-    'S': 'String',
-    'F': 'Function',
-    'O': 'Object'
-};
-
-function extractParamName(callee, argIndex) {
-  return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
-}
-
-function checkArgs(spec, functionName, args, opt_callee) {
-    if (!moduleExports.enableChecks) {
-        return;
-    }
-    var errMsg = null;
-    var typeName;
-    for (var i = 0; i < spec.length; ++i) {
-        var c = spec.charAt(i),
-            cUpper = c.toUpperCase(),
-            arg = args[i];
-        // Asterix means allow anything.
-        if (c == '*') {
-            continue;
-        }
-        typeName = utils.typeName(arg);
-        if ((arg === null || arg === undefined) && c == cUpper) {
-            continue;
-        }
-        if (typeName != typeMap[cUpper]) {
-            errMsg = 'Expected ' + typeMap[cUpper];
-            break;
-        }
-    }
-    if (errMsg) {
-        errMsg += ', but got ' + typeName + '.';
-        errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
-        // Don't log when running jake test.
-        if (typeof jasmine == 'undefined') {
-            console.error(errMsg);
-        }
-        throw TypeError(errMsg);
-    }
-}
-
-function getValue(value, defaultValue) {
-    return value === undefined ? defaultValue : value;
-}
-
-moduleExports.checkArgs = checkArgs;
-moduleExports.getValue = getValue;
-moduleExports.enableChecks = true;
-
-
-});
-
-// file: lib/common/builder.js
-define("cordova/builder", function(require, exports, module) {
-
-var utils = require('cordova/utils');
-
-function each(objects, func, context) {
-    for (var prop in objects) {
-        if (objects.hasOwnProperty(prop)) {
-            func.apply(context, [objects[prop], prop]);
-        }
-    }
-}
-
-function clobber(obj, key, value) {
-    exports.replaceHookForTesting(obj, key);
-    obj[key] = value;
-    // Getters can only be overridden by getters.
-    if (obj[key] !== value) {
-        utils.defineGetter(obj, key, function() {
-            return value;
-        });
-    }
-}
-
-function assignOrWrapInDeprecateGetter(obj, key, value, message) {
-    if (message) {
-        utils.defineGetter(obj, key, function() {
-            console.log(message);
-            delete obj[key];
-            clobber(obj, key, value);
-            return value;
-        });
-    } else {
-        clobber(obj, key, value);
-    }
-}
-
-function include(parent, objects, clobber, merge) {
-    each(objects, function (obj, key) {
-        try {
-          var result = obj.path ? require(obj.path) : {};
-
-          if (clobber) {
-              // Clobber if it doesn't exist.
-              if (typeof parent[key] === 'undefined') {
-                  assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
-              } else if (typeof obj.path !== 'undefined') {
-                  // If merging, merge properties onto parent, otherwise, clobber.
-                  if (merge) {
-                      recursiveMerge(parent[key], result);
-                  } else {
-                      assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
-                  }
-              }
-              result = parent[key];
-          } else {
-            // Overwrite if not currently defined.
-            if (typeof parent[key] == 'undefined') {
-              assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
-            } else {
-              // Set result to what already exists, so we can build children into it if they exist.
-              result = parent[key];
-            }
-          }
-
-          if (obj.children) {
-            include(result, obj.children, clobber, merge);
-          }
-        } catch(e) {
-          utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"');
-        }
-    });
-}
-
-/**
- * Merge properties from one object onto another recursively.  Properties from
- * the src object will overwrite existing target property.
- *
- * @param target Object to merge properties into.
- * @param src Object to merge properties from.
- */
-function recursiveMerge(target, src) {
-    for (var prop in src) {
-        if (src.hasOwnProperty(prop)) {
-            if (target.prototype && target.prototype.constructor === target) {
-                // If the target object is a constructor override off prototype.
-                clobber(target.prototype, prop, src[prop]);
-            } else {
-                if (typeof src[prop] === 'object' && typeof target[prop] === 'object') {
-                    recursiveMerge(target[prop], src[prop]);
-                } else {
-                    clobber(target, prop, src[prop]);
-                }
-            }
-        }
-    }
-}
-
-exports.buildIntoButDoNotClobber = function(objects, target) {
-    include(target, objects, false, false);
-};
-exports.buildIntoAndClobber = function(objects, target) {
-    include(target, objects, true, false);
-};
-exports.buildIntoAndMerge = function(objects, target) {
-    include(target, objects, true, true);
-};
-exports.recursiveMerge = recursiveMerge;
-exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter;
-exports.replaceHookForTesting = function() {};
-
-});
-
-// file: lib/common/channel.js
-define("cordova/channel", function(require, exports, module) {
-
-var utils = require('cordova/utils'),
-    nextGuid = 1;
-
-/**
- * Custom pub-sub "channel" that can have functions subscribed to it
- * This object is used to define and control firing of events for
- * cordova initialization, as well as for custom events thereafter.
- *
- * The order of events during page load and Cordova startup is as follows:
- *
- * onDOMContentLoaded*         Internal event that is received when the web page is loaded and parsed.
- * onNativeReady*              Internal event that indicates the Cordova native side is ready.
- * onCordovaReady*             Internal event fired when all Cordova JavaScript objects have been created.
- * onCordovaInfoReady*         Internal event fired when device properties are available.
- * onCordovaConnectionReady*   Internal event fired when the connection property has been set.
- * onDeviceReady*              User event fired to indicate that Cordova is ready
- * onResume                    User event fired to indicate a start/resume lifecycle event
- * onPause                     User event fired to indicate a pause lifecycle event
- * onDestroy*                  Internal event fired when app is being destroyed (User should use window.onunload event, not this one).
- *
- * The events marked with an * are sticky. Once they have fired, they will stay in the fired state.
- * All listeners that subscribe after the event is fired will be executed right away.
- *
- * The only Cordova events that user code should register for are:
- *      deviceready           Cordova native code is initialized and Cordova APIs can be called from JavaScript
- *      pause                 App has moved to background
- *      resume                App has returned to foreground
- *
- * Listeners can be registered as:
- *      document.addEventListener("deviceready", myDeviceReadyListener, false);
- *      document.addEventListener("resume", myResumeListener, false);
- *      document.addEventListener("pause", myPauseListener, false);
- *
- * The DOM lifecycle events should be used for saving and restoring state
- *      window.onload
- *      window.onunload
- *
- */
-
-/**
- * Channel
- * @constructor
- * @param type  String the channel name
- */
-var Channel = function(type, sticky) {
-    this.type = type;
-    // Map of guid -> function.
-    this.handlers = {};
-    // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired.
-    this.state = sticky ? 1 : 0;
-    // Used in sticky mode to remember args passed to fire().
-    this.fireArgs = null;
-    // Used by onHasSubscribersChange to know if there are any listeners.
-    this.numHandlers = 0;
-    // Function that is called when the first listener is subscribed, or when
-    // the last listener is unsubscribed.
-    this.onHasSubscribersChange = null;
-},
-    channel = {
-        /**
-         * Calls the provided function only after all of the channels specified
-         * have been fired. All channels must be sticky channels.
-         */
-        join: function(h, c) {
-            var len = c.length,
-                i = len,
-                f = function() {
-                    if (!(--i)) h();
-                };
-            for (var j=0; j<len; j++) {
-                if (c[j].state === 0) {
-                    throw Error('Can only use join with sticky channels.');
-                }
-                c[j].subscribe(f);
-            }
-            if (!len) h();
-        },
-        create: function(type) {
-            return channel[type] = new Channel(type, false);
-        },
-        createSticky: function(type) {
-            return channel[type] = new Channel(type, true);
-        },
-
-        /**
-         * cordova Channels that must fire before "deviceready" is fired.
-         */
-        deviceReadyChannelsArray: [],
-        deviceReadyChannelsMap: {},
-
-        /**
-         * Indicate that a feature needs to be initialized before it is ready to be used.
-         * This holds up Cordova's "deviceready" event until the feature has been initialized
-         * and Cordova.initComplete(feature) is called.
-         *
-         * @param feature {String}     The unique feature name
-         */
-        waitForInitialization: function(feature) {
-            if (feature) {
-                var c = channel[feature] || this.createSticky(feature);
-                this.deviceReadyChannelsMap[feature] = c;
-                this.deviceReadyChannelsArray.push(c);
-            }
-        },
-
-        /**
-         * Indicate that initialization code has completed and the feature is ready to be used.
-         *
-         * @param feature {String}     The unique feature name
-         */
-        initializationComplete: function(feature) {
-            var c = this.deviceReadyChannelsMap[feature];
-            if (c) {
-                c.fire();
-            }
-        }
-    };
-
-function forceFunction(f) {
-    if (typeof f != 'function') throw "Function required as first argument!";
-}
-
-/**
- * Subscribes the given function to the channel. Any time that
- * Channel.fire is called so too will the function.
- * Optionally specify an execution context for the function
- * and a guid that can be used to stop subscribing to the channel.
- * Returns the guid.
- */
-Channel.prototype.subscribe = function(f, c) {
-    // need a function to call
-    forceFunction(f);
-    if (this.state == 2) {
-        f.apply(c || this, this.fireArgs);
-        return;
-    }
-
-    var func = f,
-        guid = f.observer_guid;
-    if (typeof c == "object") { func = utils.close(c, f); }
-
-    if (!guid) {
-        // first time any channel has seen this subscriber
-        guid = '' + nextGuid++;
-    }
-    func.observer_guid = guid;
-    f.observer_guid = guid;
-
-    // Don't add the same handler more than once.
-    if (!this.handlers[guid]) {
-        this.handlers[guid] = func;
-        this.numHandlers++;
-        if (this.numHandlers == 1) {
-            this.onHasSubscribersChange && this.onHasSubscribersChange();
-        }
-    }
-};
-
-/**
- * Unsubscribes the function with the given guid from the channel.
- */
-Channel.prototype.unsubscribe = function(f) {
-    // need a function to unsubscribe
-    forceFunction(f);
-
-    var guid = f.observer_guid,
-        handler = this.handlers[guid];
-    if (handler) {
-        delete this.handlers[guid];
-        this.numHandlers--;
-        if (this.numHandlers === 0) {
-            this.onHasSubscribersChange && this.onHasSubscribersChange();
-        }
-    }
-};
-
-/**
- * Calls all functions subscribed to this channel.
- */
-Channel.prototype.fire = function(e) {
-    var fail = false,
-        fireArgs = Array.prototype.slice.call(arguments);
-    // Apply stickiness.
-    if (this.state == 1) {
-        this.state = 2;
-        this.fireArgs = fireArgs;
-    }
-    if (this.numHandlers) {
-        // Copy the values first so that it is safe to modify it from within
-        // callbacks.
-        var toCall = [];
-        for (var item in this.handlers) {
-            toCall.push(this.handlers[item]);
-        }
-        for (var i = 0; i < toCall.length; ++i) {
-            toCall[i].apply(this, fireArgs);
-        }
-        if (this.state == 2 && this.numHandlers) {
-            this.numHandlers = 0;
-            this.handlers = {};
-            this.onHasSubscribersChange && this.onHasSubscribersChange();
-        }
-    }
-};
-
-
-// defining them here so they are ready super fast!
-// DOM event that is received when the web page is loaded and parsed.
-channel.createSticky('onDOMContentLoaded');
-
-// Event to indicate the Cordova native side is ready.
-channel.createSticky('onNativeReady');
-
-// Event to indicate that all Cordova JavaScript objects have been created
-// and it's time to run plugin constructors.
-channel.createSticky('onCordovaReady');
-
-// Event to indicate that device properties are available
-channel.createSticky('onCordovaInfoReady');
-
-// Event to indicate that the connection property has been set.
-channel.createSticky('onCordovaConnectionReady');
-
-// Event to indicate that all automatically loaded JS plugins are loaded and ready.
-channel.createSticky('onPluginsReady');
-
-// Event to indicate that Cordova is ready
-channel.createSticky('onDeviceReady');
-
-// Event to indicate a resume lifecycle event
-channel.create('onResume');
-
-// Event to indicate a pause lifecycle event
-channel.create('onPause');
-
-// Event to indicate a destroy lifecycle event
-channel.createSticky('onDestroy');
-
-// Channels that must fire before "deviceready" is fired.
-channel.waitForInitialization('onCordovaReady');
-channel.waitForInitialization('onCordovaConnectionReady');
-channel.waitForInitialization('onDOMContentLoaded');
-
-module.exports = channel;
-
-});
-
-// file: lib/common/commandProxy.js
-define("cordova/commandProxy", function(require, exports, module) {
-
-
-// internal map of proxy function
-var CommandProxyMap = {};
-
-module.exports = {
-
-    // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
-    add:function(id,proxyObj) {
-        console.log("adding proxy for " + id);
-        CommandProxyMap[id] = proxyObj;
-        return proxyObj;
-    },
-
-    // cordova.commandProxy.remove("Accelerometer");
-    remove:function(id) {
-        var proxy = CommandProxyMap[id];
-        delete CommandProxyMap[id];
-        CommandProxyMap[id] = null;
-        return proxy;
-    },
-
-    get:function(service,action) {
-        return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null );
-    }
-};
-});
-
-// file: lib/android/exec.js
-define("cordova/exec", function(require, exports, module) {
-
-/**
- * Execute a cordova command.  It is up to the native side whether this action
- * is synchronous or asynchronous.  The native side can return:
- *      Synchronous: PluginResult object as a JSON string
- *      Asynchronous: Empty string ""
- * If async, the native side will cordova.callbackSuccess or cordova.callbackError,
- * depending upon the result of the action.
- *
- * @param {Function} success    The success callback
- * @param {Function} fail       The fail callback
- * @param {String} service      The name of the service to use
- * @param {String} action       Action to be run in cordova
- * @param {String[]} [args]     Zero or more arguments to pass to the method
- */
-var cordova = require('cordova'),
-    nativeApiProvider = require('cordova/plugin/android/nativeapiprovider'),
-    utils = require('cordova/utils'),
-    jsToNativeModes = {
-        PROMPT: 0,
-        JS_OBJECT: 1,
-        // This mode is currently for benchmarking purposes only. It must be enabled
-        // on the native side through the ENABLE_LOCATION_CHANGE_EXEC_MODE
-        // constant within CordovaWebViewClient.java before it will work.
-        LOCATION_CHANGE: 2
-    },
-    nativeToJsModes = {
-        // Polls for messages using the JS->Native bridge.
-        POLLING: 0,
-        // For LOAD_URL to be viable, it would need to have a work-around for
-        // the bug where the soft-keyboard gets dismissed when a message is sent.
-        LOAD_URL: 1,
-        // For the ONLINE_EVENT to be viable, it would need to intercept all event
-        // listeners (both through addEventListener and window.ononline) as well
-        // as set the navigator property itself.
-        ONLINE_EVENT: 2,
-        // Uses reflection to access private APIs of the WebView that can send JS
-        // to be executed.
-        // Requires Android 3.2.4 or above.
-        PRIVATE_API: 3
-    },
-    jsToNativeBridgeMode,  // Set lazily.
-    nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT,
-    pollEnabled = false,
-    messagesFromNative = [];
-
-function androidExec(success, fail, service, action, args) {
-    // Set default bridge modes if they have not already been set.
-    // By default, we use the failsafe, since addJavascriptInterface breaks too often
-    if (jsToNativeBridgeMode === undefined) {
-        androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
-    }
-
-    // Process any ArrayBuffers in the args into a string.
-    for (var i = 0; i < args.length; i++) {
-        if (utils.typeName(args[i]) == 'ArrayBuffer') {
-            args[i] = window.btoa(String.fromCharCode.apply(null, new Uint8Array(args[i])));
-        }
-    }
-
-    var callbackId = service + cordova.callbackId++,
-        argsJson = JSON.stringify(args);
-
-    if (success || fail) {
-        cordova.callbacks[callbackId] = {success:success, fail:fail};
-    }
-
-    if (jsToNativeBridgeMode == jsToNativeModes.LOCATION_CHANGE) {
-        window.location = 'http://cdv_exec/' + service + '#' + action + '#' + callbackId + '#' + argsJson;
-    } else {
-        var messages = nativeApiProvider.get().exec(service, action, callbackId, argsJson);
-        // If argsJson was received by Java as null, try again with the PROMPT bridge mode.
-        // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2.  See CB-2666.
-        if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && messages === "@Null arguments.") {
-            androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT);
-            androidExec(success, fail, service, action, args);
-            androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT);
-            return;
-        } else {
-            androidExec.processMessages(messages);
-        }
-    }
-}
-
-function pollOnce() {
-    var msg = nativeApiProvider.get().retrieveJsMessages();
-    androidExec.processMessages(msg);
-}
-
-function pollingTimerFunc() {
-    if (pollEnabled) {
-        pollOnce();
-        setTimeout(pollingTimerFunc, 50);
-    }
-}
-
-function hookOnlineApis() {
-    function proxyEvent(e) {
-        cordova.fireWindowEvent(e.type);
-    }
-    // The network module takes care of firing online and offline events.
-    // It currently fires them only on document though, so we bridge them
-    // to window here (while first listening for exec()-releated online/offline
-    // events).
-    window.addEventListener('online', pollOnce, false);
-    window.addEventListener('offline', pollOnce, false);
-    cordova.addWindowEventHandler('online');
-    cordova.addWindowEventHandler('offline');
-    document.addEventListener('online', proxyEvent, false);
-    document.addEventListener('offline', proxyEvent, false);
-}
-
-hookOnlineApis();
-
-androidExec.jsToNativeModes = jsToNativeModes;
-androidExec.nativeToJsModes = nativeToJsModes;
-
-androidExec.setJsToNativeBridgeMode = function(mode) {
-    if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) {
-        console.log('Falling back on PROMPT mode since _cordovaNative is missing. Expected for Android 3.2 and lower only.');
-        mode = jsToNativeModes.PROMPT;
-    }
-    nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT);
-    jsToNativeBridgeMode = mode;
-};
-
-androidExec.setNativeToJsBridgeMode = function(mode) {
-    if (mode == nativeToJsBridgeMode) {
-        return;
-    }
-    if (nativeToJsBridgeMode == nativeToJsModes.POLLING) {
-        pollEnabled = false;
-    }
-
-    nativeToJsBridgeMode = mode;
-    // Tell the native side to switch modes.
-    nativeApiProvider.get().setNativeToJsBridgeMode(mode);
-
-    if (mode == nativeToJsModes.POLLING) {
-        pollEnabled = true;
-        setTimeout(pollingTimerFunc, 1);
-    }
-};
-
-// Processes a single message, as encoded by NativeToJsMessageQueue.java.
-function processMessage(message) {
-    try {
-        var firstChar = message.charAt(0);
-        if (firstChar == 'J') {
-            eval(message.slice(1));
-        } else if (firstChar == 'S' || firstChar == 'F') {
-            var success = firstChar == 'S';
-            var keepCallback = message.charAt(1) == '1';
-            var spaceIdx = message.indexOf(' ', 2);
-            var status = +message.slice(2, spaceIdx);
-            var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1);
-            var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx);
-            var payloadKind = message.charAt(nextSpaceIdx + 1);
-            var payload;
-            if (payloadKind == 's') {
-                payload = message.slice(nextSpaceIdx + 2);
-            } else if (payloadKind == 't') {
-                payload = true;
-            } else if (payloadKind == 'f') {
-                payload = false;
-            } else if (payloadKind == 'N') {
-                payload = null;
-            } else if (payloadKind == 'n') {
-                payload = +message.slice(nextSpaceIdx + 2);
-            } else if (payloadKind == 'A') {
-                var data = message.slice(nextSpaceIdx + 2);
-                var bytes = window.atob(data);
-                var arraybuffer = new Uint8Array(bytes.length);
-                for (var i = 0; i < bytes.length; i++) {
-                    arraybuffer[i] = bytes.charCodeAt(i);
-                }
-                payload = arraybuffer.buffer;
-            } else if (payloadKind == 'S') {
-                payload = window.atob(message.slice(nextSpaceIdx + 2));
-            } else {
-                payload = JSON.parse(message.slice(nextSpaceIdx + 1));
-            }
-            cordova.callbackFromNative(callbackId, success, status, [payload], keepCallback);
-        } else {
-            console.log("processMessage failed: invalid message:" + message);
-        }
-    } catch (e) {
-        console.log("processMessage failed: Message: " + message);
-        console.log("processMessage failed: Error: " + e);
-        console.log("processMessage failed: Stack: " + e.stack);
-    }
-}
-
-// This is called from the NativeToJsMessageQueue.java.
-androidExec.processMessages = function(messages) {
-    if (messages) {
-        messagesFromNative.push(messages);
-        // Check for the reentrant case, and enqueue the message if that's the case.
-        if (messagesFromNative.length > 1) {
-            return;
-        }
-        while (messagesFromNative.length) {
-            // Don't unshift until the end so that reentrancy can be detected.
-            messages = messagesFromNative[0];
-            // The Java side can send a * message to indicate that it
-            // still has messages waiting to be retrieved.
-            if (messages == '*') {
-                messagesFromNative.shift();
-                window.setTimeout(pollOnce, 0);
-                return;
-            }
-
-            var spaceIdx = messages.indexOf(' ');
-            var msgLen = +messages.slice(0, spaceIdx);
-            var message = messages.substr(spaceIdx + 1, msgLen);
-            messages = messages.slice(spaceIdx + msgLen + 1);
-            processMessage(message);
-            if (messages) {
-                messagesFromNative[0] = messages;
-            } else {
-                messagesFromNative.shift();
-            }
-        }
-    }
-};
-
-module.exports = androidExec;
-
-});
-
-// file: lib/common/modulemapper.js
-define("cordova/modulemapper", function(require, exports, module) {
-
-var builder = require('cordova/builder'),
-    moduleMap = define.moduleMap,
-    symbolList,
-    deprecationMap;
-
-exports.reset = function() {
-    symbolList = [];
-    deprecationMap = {};
-};
-
-function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) {
-    if (!(moduleName in moduleMap)) {
-        throw new Error('Module ' + moduleName + ' does not exist.');
-    }
-    symbolList.push(strategy, moduleName, symbolPath);
-    if (opt_deprecationMessage) {
-        deprecationMap[symbolPath] = opt_deprecationMessage;
-    }
-}
-
-// Note: Android 2.3 does have Function.bind().
-exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) {
-    addEntry('c', moduleName, symbolPath, opt_deprecationMessage);
-};
-
-exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) {
-    addEntry('m', moduleName, symbolPath, opt_deprecationMessage);
-};
-
-exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) {
-    addEntry('d', moduleName, symbolPath, opt_deprecationMessage);
-};
-
-function prepareNamespace(symbolPath, context) {
-    if (!symbolPath) {
-        return context;
-    }
-    var parts = symbolPath.split('.');
-    var cur = context;
-    for (var i = 0, part; part = parts[i]; ++i) {
-        cur = cur[part] = cur[part] || {};
-    }
-    return cur;
-}
-
-exports.mapModules = function(context) {
-    var origSymbols = {};
-    context.CDV_origSymbols = origSymbols;
-    for (var i = 0, len = symbolList.length; i < len; i += 3) {
-        var strategy = symbolList[i];
-        var moduleName = symbolList[i + 1];
-        var symbolPath = symbolList[i + 2];
-        var lastDot = symbolPath.lastIndexOf('.');
-        var namespace = symbolPath.substr(0, lastDot);
-        var lastName = symbolPath.substr(lastDot + 1);
-
-        var module = require(moduleName);
-        var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null;
-        var parentObj = prepareNamespace(namespace, context);
-        var target = parentObj[lastName];
-
-        if (strategy == 'm' && target) {
-            builder.recursiveMerge(target, module);
-        } else if ((strategy == 'd' && !target) || (strategy != 'd')) {
-            if (!(symbolPath in origSymbols)) {
-                origSymbols[symbolPath] = target;
-            }
-            builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg);
-        }
-    }
-};
-
-exports.getOriginalSymbol = function(context, symbolPath) {
-    var origSymbols = context.CDV_origSymbols;
-    if (origSymbols && (symbolPath in origSymbols)) {
-        return origSymbols[symbolPath];
-    }
-    var parts = symbolPath.split('.');
-    var obj = context;
-    for (var i = 0; i < parts.length; ++i) {
-        obj = obj && obj[parts[i]];
-    }
-    return obj;
-};
-
-exports.loadMatchingModules = function(matchingRegExp) {
-    for (var k in moduleMap) {
-        if (matchingRegExp.exec(k)) {
-            require(k);
-        }
-    }
-};
-
-exports.reset();
-
-
-});
-
-// file: lib/android/platform.js
-define("cordova/platform", function(require, exports, module) {
-
-module.exports = {
-    id: "android",
-    initialize:function() {
-        var channel = require("cordova/channel"),
-            cordova = require('cordova'),
-            exec = require('cordova/exec'),
-            modulemapper = require('cordova/modulemapper');
-
-        modulemapper.loadMatchingModules(/cordova.*\/symbols$/);
-        modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');
-
-        modulemapper.mapModules(window);
-
-        // Inject a listener for the backbutton on the document.
-        var backButtonChannel = cordova.addDocumentEventHandler('backbutton');
-        backButtonChannel.onHasSubscribersChange = function() {
-            // If we just attached the first handler or detached the last handler,
-            // let native know we need to override the back button.
-            exec(null, null, "App", "overrideBackbutton", [this.numHandlers == 1]);
-        };
-
-        // Add hardware MENU and SEARCH button handlers
-        cordova.addDocumentEventHandler('menubutton');
-        cordova.addDocumentEventHandler('searchbutton');
-
-        // Let native code know we are all done on the JS side.
-        // Native code will then un-hide the WebView.
-        channel.join(function() {
-            exec(null, null, "App", "show", []);
-        }, [channel.onCordovaReady]);
-    }
-};
-
-});
-
-// file: lib/common/plugin/Acceleration.js
-define("cordova/plugin/Acceleration", function(require, exports, module) {
-
-var Acceleration = function(x, y, z, timestamp) {
-    this.x = x;
-    this.y = y;
-    this.z = z;
-    this.timestamp = timestamp || (new Date()).getTime();
-};
-
-module.exports = Acceleration;
-
-});
-
-// file: lib/common/plugin/Camera.js
-define("cordova/plugin/Camera", function(require, exports, module) {
-
-var argscheck = require('cordova/argscheck'),
-    exec = require('cordova/exec'),
-    Camera = require('cordova/plugin/CameraConstants'),
-    CameraPopoverHandle = require('cordova/plugin/CameraPopoverHandle');
-
-var cameraExport = {};
-
-// Tack on the Camera Constants to the base camera plugin.
-for (var key in Camera) {
-    cameraExport[key] = Camera[key];
-}
-
-/**
- * Gets a picture from source defined by "options.sourceType", and returns the
- * image as defined by the "options.destinationType" option.
-
- * The defaults are sourceType=CAMERA and destinationType=FILE_URI.
- *
- * @param {Function} successCallback
- * @param {Function} errorCallback
- * @param {Object} options
- */
-cameraExport.getPicture = function(successCallback, errorCallback, options) {
-    argscheck.checkArgs('fFO', 'Camera.getPicture', arguments);
-    options = options || {};
-    var getValue = argscheck.getValue;
-
-    var quality = getValue(options.quality, 50);
-    var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
-    var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
-    var targetWidth = getValue(options.targetWidth, -1);
-    var targetHeight = getValue(options.targetHeight, -1);
-    var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
-    var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
-    var allowEdit = !!options.allowEdit;
-    var correctOrientation = !!options.correctOrientation;
-    var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
-    var popoverOptions = getValue(options.popoverOptions, null);
-    var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
-
-    var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
-                mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
-
-    exec(successCallback, errorCallback, "Camera", "takePicture", args);
-    return new CameraPopoverHandle();
-};
-
-cameraExport.cleanup = function(successCallback, errorCallback) {
-    exec(successCallback, errorCallback, "Camera", "cleanup", []);
-};
-
-module.exports = cameraExport;
-
-});
-
-// file: lib/common/plugin/CameraConstants.js
-define("cordova/plugin/CameraConstants", function(require, exports, module) {
-
-module.exports = {
-  DestinationType:{
-    DATA_URL: 0,         // Return base64 encoded string
-    FILE_URI: 1,         // Return file uri (content://media/external/images/media/2 for Android)
-    NATIVE_URI: 2        // Return native uri (eg. asset-library://... for iOS)
-  },
-  EncodingType:{
-    JPEG: 0,             // Return JPEG encoded image
-    PNG: 1               // Return PNG encoded image
-  },
-  MediaType:{
-    PICTURE: 0,          // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
-    VIDEO: 1,            // allow selection of video only, ONLY RETURNS URL
-    ALLMEDIA : 2         // allow selection from all media types
-  },
-  PictureSourceType:{
-    PHOTOLIBRARY : 0,    // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
-    CAMERA : 1,          // Take picture from camera
-    SAVEDPHOTOALBUM : 2  // Choose image from picture library (same as PHOTOLIBRARY for Android)
-  },
-  PopoverArrowDirection:{
-      ARROW_UP : 1,        // matches iOS UIPopoverArrowDirection constants to specify arrow location on popover
-      ARROW_DOWN : 2,
-      ARROW_LEFT : 4,
-      ARROW_RIGHT : 8,
-      ARROW_ANY : 15
-  },
-  Direction:{
-      BACK: 0,
-      FRONT: 1
-  }
-};
-
-});
-
-// file: lib/common/plugin/CameraPopoverHandle.js
-define("cordova/plugin/CameraPopoverHandle", function(require, exports, module) {
-
-var exec = require('cordova/exec');
-
-/**
- * A handle to an image picker popover.
- */
-var CameraPopoverHandle = function() {
-    this.setPosition = function(popoverOptions) {
-        console.log('CameraPopoverHandle.setPosition is only supported on iOS.');
-    };
-};
-
-module.exports = CameraPopoverHandle;
-
-});
-
-// file: lib/common/plugin/CameraPopoverOptions.js
-define("cordova/plugin/CameraPopoverOptions", function(require, exports, module) {
-
-var Camera = require('cordova/plugin/CameraConstants');
-
-/**
- * Encapsulates options for iOS Popover image picker
- */
-var CameraPopoverOptions = function(x,y,width,height,arrowDir){
-    // information of rectangle that popover should be anchored to
-    this.x = x || 0;
-    this.y = y || 32;
-    this.width = width || 320;
-    this.height = height || 480;
-    // The direction of the popover arrow
-    this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY;
-};
-
-module.exports = CameraPopoverOptions;
-
-});
-
-// file: lib/common/plugin/CaptureAudioOptions.js
-define("cordova/plugin/CaptureAudioOptions", function(require, exports, module) {
-
-/**
- * Encapsulates all audio capture operation configuration options.
- */
-var CaptureAudioOptions = function(){
-    // Upper limit of sound clips user can record. Value must be equal or greater than 1.
-    this.limit = 1;
-    // Maximum duration of a single sound clip in seconds.
-    this.duration = 0;
-    // The selected audio mode. Must match with one of the elements in supportedAudioModes array.
-    this.mode = null;
-};
-
-module.exports = CaptureAudioOptions;
-
-});
-
-// file: lib/common/plugin/CaptureError.js
-define("cordova/plugin/CaptureError", function(require, exports, module) {
-
-/**
- * The CaptureError interface encapsulates all errors in the Capture API.
- */
-var CaptureError = function(c) {
-   this.code = c || null;
-};
-
-// Camera or microphone failed to capture image or sound.
-CaptureError.CAPTURE_INTERNAL_ERR = 0;
-// Camera application or audio capture application is currently serving other capture request.
-CaptureError.CAPTURE_APPLICATION_BUSY = 1;
-// Invalid use of the API (e.g. limit parameter has value less than one).
-CaptureError.CAPTURE_INVALID_ARGUMENT = 2;
-// User exited camera application or audio capture application before capturing anything.
-CaptureError.CAPTURE_NO_MEDIA_FILES = 3;
-// The requested capture operation is not supported.
-CaptureError.CAPTURE_NOT_SUPPORTED = 20;
-
-module.exports = CaptureError;
-
-});
-
-// file: lib/common/plugin/CaptureImageOptions.js
-define("cordova/plugin/CaptureImageOptions", function(require, exports, module) {
-
-/**
- * Encapsulates all image capture operation configuration options.
- */
-var CaptureImageOptions = function(){
-    // Upper limit of images user can take. Value must be equal or greater than 1.
-    this.limit = 1;
-    // The selected image mode. Must match with one of the elements in supportedImageModes array.
-    this.mode = null;
-};
-
-module.exports = CaptureImageOptions;
-
-});
-
-// file: lib/common/plugin/CaptureVideoOptions.js
-define("cordova/plugin/CaptureVideoOptions", function(require, exports, module) {
-
-/**
- * Encapsulates all video capture operation configuration options.
- */
-var CaptureVideoOptions = function(){
-    // Upper limit of videos user can record. Value must be equal or greater than 1.
-    this.limit = 1;
-    // Maximum duration of a single video clip in seconds.
-    this.duration = 0;
-    // The selected video mode. Must match with one of the elements in supportedVideoModes array.
-    this.mode = null;
-};
-
-module.exports = CaptureVideoOptions;
-
-});
-
-// file: lib/common/plugin/CompassError.js
-define("cordova/plugin/CompassError", function(require, exports, module) {
-
-/**
- *  CompassError.
- *  An error code assigned by an implementation when an error has occurred
- * @constructor
- */
-var CompassError = function(err) {
-    this.code = (err !== undefined ? err : null);
-};
-
-CompassError.COMPASS_INTERNAL_ERR = 0;
-CompassError.COMPASS_NOT_SUPPORTED = 20;
-
-module.exports = CompassError;
-
-});
-
-// file: lib/common/plugin/CompassHeading.js
-define("cordova/plugin/CompassHeading", function(require, exports, module) {
-
-var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) {
-  this.magneticHeading = magneticHeading;
-  this.trueHeading = trueHeading;
-  this.headingAccuracy = headingAccuracy;
-  this.timestamp = timestamp || new Date().getTime();
-};
-
-module.exports = CompassHeading;
-
-});
-
-// file: lib/common/plugin/ConfigurationData.js
-define("cordova/plugin/ConfigurationData", function(require, exports, module) {
-
-/**
- * Encapsulates a set of parameters that the capture device supports.
- */
-function ConfigurationData() {
-    // The ASCII-encoded string in lower case representing the media type.
-    this.type = null;
-    // The height attribute represents height of the image or video in pixels.
-    // In the case of a sound clip this attribute has value 0.
-    this.height = 0;
-    // The width attribute represents width of the image or video in pixels.
-    // In the case of a sound clip this attribute has value 0
-    this.width = 0;
-}
-
-module.exports = ConfigurationData;
-
-});
-
-// file: lib/common/plugin/Connection.js
-define("cordova/plugin/Connection", function(require, exports, module) {
-
-/**
- * Network status
- */
-module.exports = {
-        UNKNOWN: "unknown",
-        ETHERNET: "ethernet",
-        WIFI: "wifi",
-        CELL_2G: "2g",
-        CELL_3G: "3g",
-        CELL_4G: "4g",
-        CELL:"cellular",
-        NONE: "none"
-};
-
-});
-
-// file: lib/common/plugin/Contact.js
-define("cordova/plugin/Contact", function(require, exports, module) {
-
-var argscheck = require('cordova/argscheck'),
-    exec = require('cordova/exec'),
-    ContactError = require('cordova/plugin/ContactError'),
-    utils = require('cordova/utils');
-
-/**
-* Converts primitives into Complex Object
-* Currently only used for Date fields
-*/
-function convertIn(contact) {
-    var value = contact.birthday;
-    try {
-      contact.birthday = new Date(parseFloat(value));
-    } catch (exception){
-      console.log("Cordova Contact convertIn error: exception creating date.");
-    }
-    return contact;
-}
-
-/**
-* Converts Complex objects into primitives
-* Only conversion at present is for Dates.
-**/
-
-function convertOut(contact) {
-    var value = contact.birthday;
-    if (value !== null) {
-        // try to make it a Date object if it is not already
-        if (!utils.isDate(value)){
-            try {
-                value = new Date(value);
-            } catch(exception){
-                value = null;
-            }
-        }
-        if (utils.isDate(value)){
-            value = value.valueOf(); // convert to milliseconds
-        }
-        contact.birthday = value;
-    }
-    return contact;
-}
-
-/**
-* Contains information about a single contact.
-* @constructor
-* @param {DOMString} id unique identifier
-* @param {DOMString} displayName
-* @param {ContactName} name
-* @param {DOMString} nickname
-* @param {Array.<ContactField>} phoneNumbers array of phone numbers
-* @param {Array.<ContactField>} emails array of email addresses
-* @param {Array.<ContactAddress>} addresses array of addresses
-* @param {Array.<ContactField>} ims instant messaging user ids
-* @param {Array.<ContactOrganization>} organizations
-* @param {DOMString} birthday contact's birthday
-* @param {DOMString} note user notes about contact
-* @param {Array.<ContactField>} photos
-* @param {Array.<ContactField>} categories
-* @param {Array.<ContactField>} urls contact's web sites
-*/
-var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, addresses,
-    ims, organizations, birthday, note, photos, categories, urls) {
-    this.id = id || null;
-    this.rawId = null;
-    this.displayName = displayName || null;
-    this.name = name || null; // ContactName
-    this.nickname = nickname || null;
-    this.phoneNumbers = phoneNumbers || null; // ContactField[]
-    this.emails = emails || null; // ContactField[]
-    this.addresses = addresses || null; // ContactAddress[]
-    this.ims = ims || null; // ContactField[]
-    this.organizations = organizations || null; // ContactOrganization[]
-    this.birthday = birthday || null;
-    this.note = note || null;
-    this.photos = photos || null; // ContactField[]
-    this.categories = categories || null; // ContactField[]
-    this.urls = urls || null; // ContactField[]
-};
-
-/**
-* Removes contact from device storage.
-* @param successCB success callback
-* @param errorCB error callback
-*/
-Contact.prototype.remove = function(successCB, errorCB) {
-    argscheck.checkArgs('FF', 'Contact.remove', arguments);
-    var fail = errorCB && function(code) {
-        errorCB(new ContactError(code));
-    };
-    if (this.id === null) {
-        fail(ContactError.UNKNOWN_ERROR);
-    }
-    else {
-        exec(successCB, fail, "Contacts", "remove", [this.id]);
-    }
-};
-
-/**
-* Creates a deep copy of this Contact.
-* With the contact ID set to null.
-* @return copy of this Contact
-*/
-Contact.prototype.clone = function() {
-    var clonedContact = utils.clone(this);
-    clonedContact.id = null;
-    clonedContact.rawId = null;
-
-    function nullIds(arr) {
-        if (arr) {
-            for (var i = 0; i < arr.length; ++i) {
-                arr[i].id = null;
-            }
-        }
-    }
-
-    // Loop through and clear out any id's in phones, emails, etc.
-    nullIds(clonedContact.phoneNumbers);
-    nullIds(clonedContact.emails);
-    nullIds(clonedContact.addresses);
-    nullIds(clonedContact.ims);
-    nullIds(clonedContact.organizations);
-    nullIds(clonedContact.categories);
-    nullIds(clonedContact.photos);
-    nullIds(clonedContact.urls);
-    return clonedContact;
-};
-
-/**
-* Persists contact to device storage.
-* @param successCB success callback
-* @param errorCB error callback
-*/
-Contact.prototype.save = function(successCB, errorCB) {
-    argscheck.checkArgs('FFO', 'Contact.save', arguments);
-    var fail = errorCB && function(code) {
-        errorCB(new ContactError(code));
-    };
-    var success = function(result) {
-        if (result) {
-            if (successCB) {
-                var fullContact = require('cordova/plugin/contacts').create(result);
-                successCB(convertIn(fullContact));
-            }
-        }
-        else {
-            // no Entry object returned
-            fail(ContactError.UNKNOWN_ERROR);
-        }
-    };
-    var dupContact = convertOut(utils.clone(this));
-    exec(success, fail, "Contacts", "save", [dupContact]);
-};
-
-
-module.exports = Contact;
-
-});
-
-// file: lib/common/plugin/ContactAddress.js
-define("cordova/plugin/ContactAddress", function(require, exports, module) {
-
-/**
-* Contact address.
-* @constructor
-* @param {DOMString} id unique identifier, should only be set by native code
-* @param formatted // NOTE: not a W3C standard
-* @param streetAddress
-* @param locality
-* @param region
-* @param postalCode
-* @param country
-*/
-
-var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country) {
-    this.id = null;
-    this.pref = (typeof pref != 'undefined' ? pref : false);
-    this.type = type || null;
-    this.formatted = formatted || null;
-    this.streetAddress = streetAddress || null;
-    this.locality = locality || null;
-    this.region = region || null;
-    this.postalCode = postalCode || null;
-    this.country = country || null;
-};
-
-module.exports = ContactAddress;
-
-});
-
-// file: lib/common/plugin/ContactError.js
-define("cordova/plugin/ContactError", function(require, exports, module) {
-
-/**
- *  ContactError.
- *  An error code assigned by an implementation when an error has occurred
- * @constructor
- */
-var ContactError = function(err) {
-    this.code = (typeof err != 'undefined' ? err : null);
-};
-
-/**
- * Error codes
- */
-ContactError.UNKNOWN_ERROR = 0;
-ContactError.INVALID_ARGUMENT_ERROR = 1;
-ContactError.TIMEOUT_ERROR = 2;
-ContactError.PENDING_OPERATION_ERROR = 3;
-ContactError.IO_ERROR = 4;
-ContactError.NOT_SUPPORTED_ERROR = 5;
-ContactError.PERMISSION_DENIED_ERROR = 20;
-
-module.exports = ContactError;
-
-});
-
-// file: lib/common/plugin/ContactField.js
-define("cordova/plugin/ContactField", function(require, exports, module) {
-
-/**
-* Generic contact field.
-* @constructor
-* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
-* @param type
-* @param value
-* @param pref
-*/
-var ContactField = function(type, value, pref) {
-    this.id = null;
-    this.type = (type && type.toString()) || null;
-    this.value = (value && value.toString()) || null;
-    this.pref = (typeof pref != 'undefined' ? pref : false);
-};
-
-module.exports = ContactField;
-
-});
-
-// file: lib/common/plugin/ContactFindOptions.js
-define("cordova/plugin/ContactFindOptions", function(require, exports, module) {
-
-/**
- * ContactFindOptions.
- * @constructor
- * @param filter used to match contacts against
- * @param multiple boolean used to determine if more than one contact should be returned
- */
-
-var ContactFindOptions = function(filter, multiple) {
-    this.filter = filter || '';
-    this.multiple = (typeof multiple != 'undefined' ? multiple : false);
-};
-
-module.exports = ContactFindOptions;
-
-});
-
-// file: lib/common/plugin/ContactName.js
-define("cordova/plugin/ContactName", function(require, exports, module) {
-
-/**
-* Contact name.
-* @constructor
-* @param formatted // NOTE: not part of W3C standard
-* @param familyName
-* @param givenName
-* @param middle
-* @param prefix
-* @param suffix
-*/
-var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) {
-    this.formatted = formatted || null;
-    this.familyName = familyName || null;
-    this.givenName = givenName || null;
-    this.middleName = middle || null;
-    this.honorificPrefix = prefix || null;
-    this.honorificSuffix = suffix || null;
-};
-
-module.exports = ContactName;
-
-});
-
-// file: lib/common/plugin/ContactOrganization.js
-define("cordova/plugin/ContactOrganization", function(require, exports, module) {
-
-/**
-* Contact organization.
-* @constructor
-* @param {DOMString} id unique identifier, should only be set by native code // NOTE: not a W3C standard
-* @param name
-* @param dept
-* @param title
-* @param startDate
-* @param endDate
-* @param location
-* @param desc
-*/
-
-var ContactOrganization = function(pref, type, name, dept, title) {
-    this.id = null;
-    this.pref = (typeof pref != 'undefined' ? pref : false);
-    this.type = type || null;
-    this.name = name || null;
-    this.department = dept || null;
-    this.title = title || null;
-};
-
-module.exports = ContactOrganization;
-
-});
-
-// file: lib/common/plugin/Coordinates.js
-define("cordova/plugin/Coordinates", function(require, exports, module) {
-
-/**
- * This class contains position information.
- * @param {Object} lat
- * @param {Object} lng
- * @param {Object} alt
- * @param {Object} acc
- * @param {Object} head
- * @param {Object} vel
- * @param {Object} altacc
- * @constructor
- */
-var Coordinates = function(lat, lng, alt, acc, head, vel, altacc) {
-    /**
-     * The latitude of the position.
-     */
-    this.latitude = lat;
-    /**
-     * The longitude of the position,
-     */
-    this.longitude = lng;
-    /**
-     * The accuracy of the position.
-     */
-    this.accuracy = acc;
-    /**
-     * The altitude of the position.
-     */
-    this.altitude = (alt !== undefined ? alt : null);
-    /**
-     * The direction the device is moving at the position.
-     */
-    this.heading = (head !== undefined ? head : null);
-    /**
-     * The velocity with which the device is moving at the position.
-     */
-    this.speed = (vel !== undefined ? vel : null);
-
-    if (this.speed === 0 || this.speed === null) {
-        this.heading = NaN;
-    }
-
-    /**
-     * The altitude accuracy of the position.
-     */
-    this.altitudeAccuracy = (altacc !== undefined) ? altacc : null;
-};
-
-module.exports = Coordinates;
-
-});
-
-// file: lib/common/plugin/DirectoryEntry.js
-define("cordova/plugin/DirectoryEntry", function(require, exports, module) {
-
-var argscheck = require('cordova/argscheck'),
-    utils = require('cordova/utils'),
-    exec = require('cordova/exec'),
-    Entry = require('cordova/plugin/Entry'),
-    FileError = require('cordova/plugin/FileError'),
-    DirectoryReader = require('cordova/plugin/DirectoryReader');
-
-/**
- * An interface representing a directory on the file system.
- *
- * {boolean} isFile always false (readonly)
- * {boolean} isDirectory always true (readonly)
- * {DOMString} name of the directory, excluding the path leading to it (readonly)
- * {DOMString} fullPath the absolute full path to the directory (readonly)
- * TODO: implement this!!! {FileSystem} filesystem on which the directory resides (readonly)
- */
-var DirectoryEntry = function(name, fullPath) {
-     DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath);
-};
-
-utils.extend(DirectoryEntry, Entry);
-
-/**
- * Creates a new DirectoryReader to read entries from this directory
- */
-DirectoryEntry.prototype.createReader = function() {
-    return new DirectoryReader(this.fullPath);
-};
-
-/**
- * Creates or looks up a directory
- *
- * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory
- * @param {Flags} options to create or exclusively create the directory
- * @param {Function} successCallback is called with the new entry
- * @param {Function} errorCallback is called with a FileError
- */
-DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) {
-    argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments);
-    var win = successCallback && function(result) {
-        var entry = new DirectoryEntry(result.name, result.fullPath);
-        successCallback(entry);
-    };
-    var fail = errorCallback && function(code) {
-        errorCallback(new FileError(code));
-    };
-    exec(win, fail, "File", "getDirectory", [this.fullPath, path, options]);
-};
-
-/**
- * Deletes a directory and all of it's contents
- *
- * @param {Function} successCallback is called with no parameters
- * @param {Function} errorCallback is called with a FileError
- */
-DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) {
-    argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments);
-    var fail = errorCallback && function(code) {
-        errorCallback(new FileError(code));
-    };
-    exec(successCallback, fail, "File", "removeRecursively", [this.fullPath]);
-};
-
-/**
- * Creates or looks up a file
- *
- * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file
- * @param {Flags} options to create or exclusively create the file
- * @param {Function} successCallback is called with the new entry
- * @param {Function} errorCallback is called with a FileError
- */
-DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) {
-    argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments);
-    var win = successCallback && function(result) {
-        var FileEntry = require('cordova/plugin/FileEntry');
-        var entry = new FileEntry(result.name, result.fullPath);
-        successCallback(entry);
-    };
-    var fail = errorCallback && function(code) {
-        errorCallback(new FileError(code));
-    };
-    exec(win, fail, "File", "getFile", [this.fullPath, path, options]);
-};
-
-module.exports = DirectoryEntry;
-
-});
-
-// file: lib/common/plugin/DirectoryReader.js
-define("cordova/plugin/DirectoryReader", function(require, exports, module) {
-
-var exec = require('cordova/exec'),
-    FileError = require('cordova/plugin/FileError') ;
-
-/**
- * An interface that lists the files and directories in a directory.
- */
-function DirectoryReader(path) {
-    this.path = path || null;
-}
-
-/**
- * Returns a list of entries from a directory.
- *
- * @param {Function} successCallback is called with a list of entries
- * @param {Function} errorCallback is called with a FileError
- */
-DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) {
-    var win = typeof successCallback !== 'function' ? null : function(result) {
-        var retVal = [];
-        for (var i=0; i<result.length; i++) {
-            var entry = null;
-            if (result[i].isDirectory) {
-                entry = new (require('cordova/plugin/DirectoryEntry'))();
-            }
-            else if (result[i].isFile) {
-                entry = new (require('cordova/plugin/FileEntry'))();
-            }
-            entry.isDirectory = result[i].isDirectory;
-            entry.isFile = result[i].isFile;
-            entry.name = result[i].name;
-            entry.fullPath = result[i].fullPath;
-            retVal.push(entry);
-        }
-        successCallback(retVal);
-    };
-    var fail = typeof errorCallback !== 'function' ? null : function(code) {
-        errorCallback(new FileError(code));
-    };
-    exec(win, fail, "File", "readEntries", [this.path]);
-};
-
-module.exports = DirectoryReader;
-
-});
-
-// file: lib/common/plugin/Entry.js
-define("cordova/plugin/Entry", function(require, exports, module) {
-
-var argscheck = require('cordova/argscheck'),
-    exec = require('cordova/exec'),
-    FileError = require('cordova/plugin/FileError'),
-    Metadata = require('cordova/plugin/Metadata');
-
-/**
- * Represents a file or directory on the local file system.
- *
- * @param isFile
- *            {boolean} true if Entry is a file (readonly)
- * @param isDirectory
- *            {boolean} true if Entry is a directory (readonly)
- * @param name
- *            {DOMString} name of the file or directory, excluding the path
- *            leading to it (readonly)
- * @param fullPath
- *            {DOMString} the absolute full path to the file or directory
- *            (readonly)
- */
-function Entry(isFile, isDirectory, name, fullPath, fileSystem) {
-    this.isFile = !!isFile;
-    this.isDirectory = !!isDirectory;
-    this.name = name || '';
-    this.fullPath = fullPath || '';
-    this.filesystem = fileSystem || null;
-}
-
-/**
- * Look up the metadata of the entry.
- *
- * @param successCallback
- *            {Function} is called with a Metadata object
- * @param errorCallback
- *            {Function} is called with a FileError
- */
-Entry.prototype.getMetadata = function(successCallback, errorCallback) {
-    argscheck.checkArgs('FF', 'Entry.getMetadata', arguments);
-    var success = successCallback && function(lastModified) {
-        var metadata = new Metadata(lastModified);
-        successCallback(metadata);
-    };
-    var fail = errorCallback && function(code) {
-        errorCallback(new FileError(code));
-    };
-
-    exec(success, fail, "File", "getMetadata", [this.fullPath]);
-};
-
-/**
- * Set the metadata of the entry.
- *
- * @param successCallback
- *            {Function} is called with a Metadata object
- * @param errorCallback
- *            {Function} is called with a FileError
- * @param metadataObject
- *            {Object} keys and values to set
- */
-Entry.prototype.setMetadata = function(successCallback, errorCallback, metadataObject) {
-    argscheck.checkArgs('FFO', 'Entry.setMetadata', arguments);
-    exec(successCallback, errorCallback, "File", "setMetadata", [this.fullPath, metadataObject]);
-};
-
-/**
- * Move a file or directory to a new location.
- *
- * @param parent
- *            {DirectoryEntry} the directory to which to move this entry
- * @param newName
- *            {DOMString} new name of the entry, defaults to the current name
- * @param successCallback
- *            {Function} called with the new DirectoryEntry object
- * @param errorCallback
- *            {Function} called with a FileError
- */
-Entry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) {
-    argscheck.checkArgs('oSFF', 'Entry.moveTo', arguments);
-    var fail = errorCallback && function(code) {
-        errorCallback(new FileError(code));
-    };
-    // source path
-    var srcPath = this.fullPath,
-        // entry name
-        name = newName || this.name,
-        success = function(entry) {
-            if (entry) {
-                if (successCallback) {
-                    // create appropriate Entry object
-                    var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
-                    successCallback(result);
-                }
-            }
-            else {
-                // no Entry object returned
-                fail && fail(FileError.NOT_FOUND_ERR);
-            }
-        };
-
-    // copy
-    exec(success, fail, "File", "moveTo", [srcPath, parent.fullPath, name]);
-};
-
-/**
- * Copy a directory to a different location.
- *
- * @param parent
- *            {DirectoryEntry} the directory to which to copy the entry
- * @param newName
- *            {DOMString} new name of the entry, defaults to the current name
- * @param successCallback
- *            {Function} called with the new Entry object
- * @param errorCallback
- *            {Function} called with a FileError
- */
-Entry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) {
-    argscheck.checkArgs('oSFF', 'Entry.copyTo', arguments);
-    var fail = errorCallback && function(code) {
-        errorCallback(new FileError(code));
-    };
-
-        // source path
-    var srcPath = this.fullPath,
-        // entry name
-        name = newName || this.name,
-        // success callback
-        success = function(entry) {
-            if (entry) {
-                if (successCallback) {
-                    // create appropriate Entry object
-                    var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath);
-                    successCallback(result);
-                }
-            }
-            else {
-                // no Entry object returned
-                fail && fail(FileError.NOT_FOUND_ERR);
-            }
-        };
-
-    // copy
-    exec(success, fail, "File", "copyTo", [srcPath, parent.fullPath, name]);
-};
-
-/**
- * Return a URL that can be used to identify this entry.
- */
-Entry.prototype.toURL = function() {
-    // fullPath attribute contains the full URL
-    return this.fullPath;
-};
-
-/**
- * Returns a URI that can be used to identify this entry.
- *
- * @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
- * @return uri
- */
-Entry.prototype.toURI = function(mimeType) {
-    console.log("DEPRECATED: Update your code to use 'toURL'");
-    // fullPath attribute contains the full URI
-    return this.toURL();
-};
-
-/**
- * Remove a file or directory. It is an error to attempt to delete a
- * directory that is not empty. It is an error to attempt to delete a
- * root directory of a file system.
- *
- * @param successCallback {Function} called with no parameters
- * @param errorCallback {Function} called with a FileError
- */
-Entry.prototype.remove = function(successCallback, errorCallback) {
-    argscheck.checkArgs('FF', 'Entry.remove', arguments);
-    var fail = errorCallback && function(code) {
-        errorCallback(new FileError(code));
-    };
-    exec(successCallback, fail, "File", "remove", [this.fullPath]);
-};
-
-/**
- * Look up the parent DirectoryEntry of this entry.
- *
- * @param successCallback {Function} called with the parent DirectoryEntry object
- * @param errorCallback {Function} called with a FileError
- */
-Entry.prototype.getParent = function(successCallback, errorCallback) {
-    argscheck.checkArgs('FF', 'Entry.getParent', arguments);
-    var win = successCallback && function(result) {
-        var DirectoryEntry = require('cordova/plugin/DirectoryEntry');
-        var entry = new DirectoryEntry(result.name, result.fullPath);
-        successCallback(entry);
-    };
-    var fail = errorCallback && function(code) {
-        errorCallback(new FileError(code));
-    };
-    exec(win, fail, "File", "getParent", [this.fullPath]);
-};
-
-module.exports = Entry;
-
-});
-
-// file: lib/common/plugin/File.js
-define("cordova/plugin/File", function(require, exports, module) {
-
-/**
- * Constructor.
- * name {DOMString} name of the file, without path information
- * fullPath {DOMString} the full path of the file, including the name
- * type {DOMString} mime type
- * lastModifiedDate {Date} last modified date
- * size {Number} size of the file in bytes
- */
-
-var File = function(name, fullPath, type, lastModifiedDate, size){
-    this.name = name || '';
-    this.fullPath = fullPath || null;
-    this.type = type || null;
-    this.lastModifiedDate = lastModifiedDate || null;
-    this.size = size || 0;
-
-    // These store the absolute start and end for slicing the file.
-    this.start = 0;
-    this.end = this.size;
-};
-
-/**
- * Returns a "slice" of the file. Since Cordova Files don't contain the actual
- * content, this really returns a File with adjusted start and end.
- * Slices of slices are supported.
- * start {Number} The index at which to start the slice (inclusive).
- * end {Number} The index at which to end the slice (exclusive).
- */
-File.prototype.slice = function(start, end) {
-    var size = this.end - this.start;
-    var newStart = 0;
-    var newEnd = size;
-    if (arguments.length) {
-        if (start < 0) {
-            newStart = Math.max(size + start, 0);
-        } else {
-            newStart = Math.min(size, start);
-        }
-    }
-
-    if (arguments.length >= 2) {
-        if (end < 0) {
-            newEnd = Math.max(size + end, 0);
-        } else {
-            newEnd = Math.min(end, size);
-        }
-    }
-
-    var newFile = new File(this.name, this.fullPath, this.type, this.lastModifiedData, this.size);
-    newFile.start = this.start + newStart;
-    newFile.end = this.start + newEnd;
-    return newFile;
-};
-
-
-module.exports = File;
-
-});
-
-// file: lib/common/plugin/FileEntry.js
-define("cordova/plugin/FileEntry", function(require, exports, module) {
-
-var utils = require('cordova/utils'),
-    exec = require('cordova/exec'),
-    Entry = require('cordova/plugin/Entry'),
-    FileWriter = require('cordova/plugin/FileWriter'),
-    File = require('cordova/plugin/File'),
-    FileError = require('cordova/plugin/FileError');
-
-/**
- * An interface representing a file on the file system.
- *
- * {boolean} isFile always true (readonly)
- * {boolean} isDirectory always false (readonly)
- * {DOMString} name of the file, excluding the path leading to it (readonly)
- * {DOMString} fullPath the absolute full path to the file (readonly)
- * {FileSystem} filesystem on which the file resides (readonly)
- */
-var FileEntry = function(name, fullPath) {
-     FileEntry.__super__.constructor.apply(this, [true, false, name, fullPath]);
-};
-
-utils.extend(FileEntry, Entry);
-
-/**
- * Creates a new FileWriter associated with the file that this FileEntry represents.
- *
- * @param {Function} successCallback is called with the new FileWriter
- * @param {Function} errorCallback is called with a FileError
- */
-FileEntry.prototype.createWriter = function(successCallback, errorCallback) {
-    this.file(function(filePointer) {
-        var writer = new FileWriter(filePointer);
-
-        if (writer.fileName === null || writer.fileName === "") {
-            errorCallback && errorCallback(new FileError(FileError.INVALID_STATE_ERR));
-        } else {
-            successCallback && successCallback(writer);
-        }
-    }, errorCallback);
-};
-
-/**
- * Returns a File that represents the current state of the file that this FileEntry represents.
- *
- * @param {Function} successCallback is called with the new File object
- * @param {Function} errorCallback is called with a FileError
- */
-FileEntry.prototype.file = function(successCallback, errorCallback) {
-    var win = successCallback && function(f) {
-        var file = new File(f.name, f.fullPath, f.type, f.lastModifiedDate, f.size);
-        successCallback(file);
-    };
-    var fail = errorCallback && function(code) {
-        errorCallback(new FileError(code));
-    };
-    exec(win, fail, "File", "getFileMetadata", [this.fullPath]);
-};
-
-
-module.exports = FileEntry;
-
-});
-
-// file: lib/common/plugin/FileError.js
-define("cordova/plugin/FileError", function(require, exports, module) {
-
-/**
- * FileError
- */
-function FileError(error) {
-  this.code = error || null;
-}
-
-// File error codes
-// Found in DOMException
-FileError.NOT_FOUND_ERR = 1;
-FileError.SECURITY_ERR = 2;
-FileError.ABORT_ERR = 3;
-
-// Added by File API specification
-FileError.NOT_READABLE_ERR = 4;
-FileError.ENCODING_ERR = 5;
-FileError.NO_MODIFICATION_ALLOWED_ERR = 6;
-FileError.INVALID_STATE_ERR = 7;
-FileError.SYNTAX_ERR = 8;
-FileError.INVALID_MODIFICATION_ERR = 9;
-FileError.QUOTA_EXCEEDED_ERR = 10;
-FileError.TYPE_MISMATCH_ERR = 11;
-FileError.PATH_EXISTS_ERR = 12;
-
-module.exports = FileError;
-
-});
-
-// file: lib/common/plugin/FileReader.js
-define("cordova/plugin/FileReader", function(require, exports, module) {
-
-var exec = require('cordova/exec'),
-    modulemapper = require('cordova/modulemapper'),
-    utils = require('cordova/utils'),
-    File = require('cordova/plugin/File'),
-    FileError = require('cordova/plugin/FileError'),
-    ProgressEvent = require('cordova/plugin/ProgressEvent'),
-    origFileReader = modulemapper.getOriginalSymbol(this, 'FileReader');
-
-/**
- * This class reads the mobile device file system.
- *
- * For Android:
- *      The root directory is the root of the file system.
- *      To read from the SD card, the file name is "sdcard/my_file.txt"
- * @constructor
- */
-var FileReader = function() {
-    this._readyState = 0;
-    this._error = null;
-    this._result = null;
-    this._fileName = '';
-    this._realReader = origFileReader ? new origFileReader() : {};
-};
-
-// States
-FileReader.EMPTY = 0;
-FileReader.LOADING = 1;
-FileReader.DONE = 2;
-
-utils.defineGetter(FileReader.prototype, 'readyState', function() {
-    return this._fileName ? this._readyState : this._realReader.readyState;
-});
-
-utils.defineGetter(FileReader.prototype, 'error', function() {
-    return this._fileName ? this._error: this._realReader.error;
-});
-
-utils.defineGetter(FileReader.prototype, 'result', function() {
-    return this._fileName ? this._result: this._realReader.result;
-});
-
-function defineEvent(eventName) {
-    utils.defineGetterSetter(FileReader.prototype, eventName, function() {
-        return this._realReader[eventName] || null;
-    }, function(value) {
-        this._realReader[eventName] = value;
-    });
-}
-defineEvent('onloadstart');    // When the read starts.
-defineEvent('onprogress');     // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total)
-defineEvent('onload');         // When the read has successfully completed.
-defineEvent('onerror');        // When the read has failed (see errors).
-defineEvent('onloadend');      // When the request has completed (either in success or failure).
-defineEvent('onabort');        // When the read has been aborted. For instance, by invoking the abort() method.
-
-function initRead(reader, file) {
-    // Already loading something
-    if (reader.readyState == FileReader.LOADING) {
-      throw new FileError(FileError.INVALID_STATE_ERR);
-    }
-
-    reader._result = null;
-    reader._error = null;
-    reader._readyState = FileReader.LOADING;
-
-    if (typeof file == 'string') {
-        // Deprecated in Cordova 2.4.
-        console.warn('Using a string argument with FileReader.readAs functions is deprecated.');
-        reader._fileName = file;
-    } else if (typeof file.fullPath == 'string') {
-        reader._fileName = file.fullPath;
-    } else {
-        reader._fileName = '';
-        return true;
-    }
-
-    reader.onloadstart && reader.onloadstart(new ProgressEvent("loadstart", {target:reader}));
-}
-
-/**
- * Abort reading file.
- */
-FileReader.prototype.abort = function() {
-    if (origFileReader && !this._fileName) {
-        return this._realReader.abort();
-    }
-    this._result = null;
-
-    if (this._readyState == FileReader.DONE || this._readyState == FileReader.EMPTY) {
-      return;
-    }
-
-    this._readyState = FileReader.DONE;
-
-    // If abort callback
-    if (typeof this.onabort === 'function') {
-        this.onabort(new ProgressEvent('abort', {target:this}));
-    }
-    // If load end callback
-    if (typeof this.onloadend === 'function') {
-        this.onloadend(new ProgressEvent('loadend', {target:this}));
-    }
-};
-
-/**
- * Read text file.
- *
- * @param file          {File} File object containing file properties
- * @param encoding      [Optional] (see http://www.iana.org/assignments/character-sets)
- */
-FileReader.prototype.readAsText = function(file, encoding) {
-    if (initRead(this, file)) {
-        return this._realReader.readAsText(file, encoding);
-    }
-
-    // Default encoding is UTF-8
-    var enc = encoding ? encoding : "UTF-8";
-    var me = this;
-    var execArgs = [this._fileName, enc, file.start, file.end];
-
-    // Read file
-    exec(
-        // Success callback
-        function(r) {
-            // If DONE (cancelled), then don't do anything
-            if (me._readyState === FileReader.DONE) {
-                return;
-            }
-
-            // Save result
-            me._result = r;
-
-            // If onload callback
-            if (typeof me.onload === "function") {
-                me.onload(new ProgressEvent("load", {target:me}));
-            }
-
-            // DONE state
-            me._readyState = FileReader.DONE;
-
-            // If onloadend callback
-            if (typeof me.onloadend === "function") {
-                me.onloadend(new ProgressEvent("loadend", {target:me}));
-            }
-        },
-        // Error callback
-        function(e) {
-            // If DONE (cancelled), then don't do anything
-            if (me._readyState === FileReader.DONE) {
-                return;
-            }
-
-            // DONE state
-            me._readyState = FileReader.DONE;
-
-            // null result
-            me._result = null;
-
-            // Save error
-            me._error = new FileError(e);
-
-            // If onerror callback
-            if (typeof me.onerror === "function") {
-                me.onerror(new ProgressEvent("error", {target:me}));
-            }
-
-            // If onloadend callback
-            if (typeof me.onloadend === "function") {
-                me.onloadend(new ProgressEvent("loadend", {target:me}));
-            }
-        }, "File", "readAsText", execArgs);
-};
-
-
-/**
- * Read file and return data as a base64 encoded data url.
- * A data url is of the form:
- *      data:[<mediatype>][;base64],<data>
- *
- * @param file          {File} File object containing file properties
- */
-FileReader.prototype.readAsDataURL = function(file) {
-    if (initRead(this, file)) {
-        return this._realReader.readAsDataURL(file);
-    }
-
-    var me = this;
-    var execArgs = [this._fileName, file.start, file.end];
-
-    // Read file
-    exec(
-        // Success callback
-        function(r) {
-            // If DONE (cancelled), then don't do anything
-            if (me._readyState === FileReader.DONE) {
-                return;
-            }
-
-            // DONE state
-            me._readyState = FileReader.DONE;
-
-            // Save result
-            me._result = r;
-
-            // If onload callback
-            if (typeof me.onload === "function") {
-                me.onload(new ProgressEvent("load", {target:me}));
-            }
-
-            // If onloadend callback
-            if (typeof me.onloadend === "function") {
-                me.onloadend(new ProgressEvent("loadend", {target:me}));
-            }
-        },
-        // Error callback
-        function(e) {
-            // If DONE (cancelled), then don't do anything
-            if (me._readyState === FileReader.DONE) {
-                return;
-            }
-
-            // DONE state
-            me._readyState = FileReader.DONE;
-
-            me._result = null;
-
-            // Save error
-            me._error = new FileError(e);
-
-            // If onerror callback
-            if (typeof me.onerror === "function") {
-                me.onerror(new ProgressEvent("error", {target:me}));
-            }
-
-            // If onloadend callback
-            if (typeof me.onloadend === "function") {
-                me.onloadend(new ProgressEvent("loadend", {target:me}));
-            }
-        }, "File", "readAsDataURL", execArgs);
-};
-
-/**
- * Read file and return data as a binary data.
- *
- * @param file          {File} File object containing file properties
- */
-FileReader.prototype.readAsBinaryString = function(file) {
-    if (initRead(this, file)) {
-        return this._realReader.readAsBinaryString(file);
-    }
-
-    var me = this;
-    var execArgs = [this._fileName, file.start, file.end];
-
-    // Read file
-    exec(
-        // Success callback
-        function(r) {
-            // If DONE (cancelled), then don't do anything
-            if (me._readyState === FileReader.DONE) {
-                return;
-            }
-
-            // DONE state
-            me._readyState = FileReader.DONE;
-
-            me._result = r;
-
-            // If onload callback
-            if (typeof me.onload === "function") {
-                me.onload(new ProgressEvent("load", {target:me}));
-            }
-
-            // If onloadend callback
-            if (typeof me.onloadend === "function") {
-                me.onloadend(new ProgressEvent("loadend", {target:me}));
-            }
-        },
-        // Error callback
-        function(e) {
-            // If DONE (cancelled), then don't do anything
-            if (me._readyState === FileReader.DONE) {
-                return;
-            }
-
-            // DONE state
-            me._readyState = FileReader.DONE;
-
-            me._result = null;
-
-            // Save error
-            me._error = new FileError(e);
-
-            // If onerror callback
-            if (typeof me.onerror === "function") {
-                me.onerror(new ProgressEvent("error", {target:me}));
-            }
-
-            // If onloadend callback
-            if (typeof me.onloadend === "function") {
-                me.onloadend(new ProgressEvent("loadend", {target:me}));
-            }
-        }, "File", "readAsBinaryString", execArgs);
-};
-
-/**
- * Read file and return data as a binary data.
- *
- * @param file          {File} File object containing file properties
- */
-FileReader.prototype.readAsArrayBuffer = function(file) {
-    if (initRead(this, file)) {
-        return this._realReader.readAsArrayBuffer(file);
-    }
-
-    var me = this;
-    var execArgs = [this._fileName, file.start, file.end];
-
-    // Read file
-    exec(
-        // Success callback
-        function(r) {
-            // If DONE (cancelled), then don't do anything
-            if (me._readyState === FileReader.DONE) {
-                return;
-            }
-
-            // DONE state
-            me._readyState = FileReader.DONE;
-
-            me._result = r;
-
-            // If onload callback
-            if (typeof me.onload === "function") {
-                me.onload(new ProgressEvent("load", {target:me}));
-            }
-
-            // If onloadend callback
-            if (typeof me.onloadend === "function") {
-                me.onloadend(new ProgressEvent("loadend", {target:me}));
-       

<TRUNCATED>

[05/22] android commit: [CB-3307] Rename cordova-VERSION.js -> cordova.js

Posted by st...@apache.org.
[CB-3307] Rename cordova-VERSION.js -> cordova.js


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

Branch: refs/heads/3.0.0
Commit: 8a95ed8ee669d191157636e6259d0d6272c5d5ed
Parents: 20caac1
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue May 7 10:27:01 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed May 8 09:52:56 2013 -0400

----------------------------------------------------------------------
 bin/templates/project/assets/www/index.html  |    2 +-
 framework/assets/js/cordova.android.js       | 6836 ---------------------
 framework/assets/www/cordova.js              | 6836 +++++++++++++++++++++
 framework/assets/www/index.html              |    2 +-
 framework/build.xml                          |   35 +-
 framework/src/org/apache/cordova/Device.java |    2 +-
 6 files changed, 6843 insertions(+), 6870 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8a95ed8e/bin/templates/project/assets/www/index.html
----------------------------------------------------------------------
diff --git a/bin/templates/project/assets/www/index.html b/bin/templates/project/assets/www/index.html
index 4d39cf3..e84fbd7 100644
--- a/bin/templates/project/assets/www/index.html
+++ b/bin/templates/project/assets/www/index.html
@@ -33,7 +33,7 @@
                 <p class="event received">Device is Ready</p>
             </div>
         </div>
-        <script type="text/javascript" src="cordova-2.6.0.js"></script>
+        <script type="text/javascript" src="cordova.js"></script>
         <script type="text/javascript" src="js/index.js"></script>
         <script type="text/javascript">
             app.initialize();