You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2013/10/22 21:19:59 UTC

[01/16] android commit: [CB-3384] Make UriResolver assert that IO is not on the UI nor WebCore threads. (cherry picked from commit 99341bce295d7ab373de9f91c43a4d2a59be22c2)

Updated Branches:
  refs/heads/2.9.x 6a57a3c45 -> 93b9b53ac


[CB-3384] Make UriResolver assert that IO is not on the UI nor WebCore threads.
(cherry picked from commit 99341bce295d7ab373de9f91c43a4d2a59be22c2)


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

Branch: refs/heads/2.9.x
Commit: e9b46e5cf6d8a91918001795f2bd395e7573c186
Parents: 6a57a3c
Author: Andrew Grieve <ag...@chromium.org>
Authored: Fri Jul 5 11:44:38 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:04:08 2013 -0400

----------------------------------------------------------------------
 .../src/org/apache/cordova/CordovaWebView.java  |  22 ++--
 .../cordova/IceCreamCordovaWebViewClient.java   |  43 ++++---
 .../src/org/apache/cordova/UriResolver.java     |   3 -
 .../src/org/apache/cordova/UriResolvers.java    | 124 +++++++++++--------
 4 files changed, 106 insertions(+), 86 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e9b46e5c/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 472f5af..278bfa4 100755
--- a/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/framework/src/org/apache/cordova/CordovaWebView.java
@@ -961,22 +961,22 @@ public class CordovaWebView extends WebView {
         if (!uri.isAbsolute()) {
             throw new IllegalArgumentException("Relative URIs are not yet supported by resolveUri.");
         }
+        UriResolver ret = null;
         // Check the against the white-list before delegating to plugins.
         if (("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) && !Config.isUrlWhiteListed(uri.toString()))
         {
             LOG.w(TAG, "resolveUri - URL is not in whitelist: " + uri);
-            return new UriResolvers.ErrorUriResolver(uri, "Whitelist rejection");
-        }
-
-        // Give plugins a chance to handle the request.
-        UriResolver resolver = ((org.apache.cordova.PluginManager)pluginManager).resolveUri(uri);
-        if (resolver == null && !fromWebView) {
-            resolver = UriResolvers.forUri(uri, cordova.getActivity());
-            if (resolver == null) {
-                resolver = new UriResolvers.ErrorUriResolver(uri, "Unresolvable URI");
+            ret = UriResolvers.createError("Whitelist rejection for: " + uri);
+        } else {
+            // Give plugins a chance to handle the request.
+            ret = ((org.apache.cordova.PluginManager)pluginManager).resolveUri(uri);
+        }
+        if (ret == null && !fromWebView) {
+            ret = UriResolvers.forUri(uri, cordova.getActivity());
+            if (ret == null) {
+                ret = UriResolvers.createError("Unresolvable URI: " + uri);
             }
         }
-
-        return resolver;
+        return ret == null ? null : UriResolvers.makeThreadChecking(ret);
     }
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e9b46e5c/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 8527d35..c23d580 100644
--- a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
+++ b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
@@ -44,27 +44,34 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
 
     @Override
     public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
-        UriResolver uriResolver = appView.resolveUri(Uri.parse(url), true);
-        
-        if (uriResolver == null && url.startsWith("file:///android_asset/")) {
-            if (url.contains("?") || url.contains("#") || needsIceCreamSpecialsInAssetUrlFix(url)) {
-                uriResolver = appView.resolveUri(Uri.parse(url), false);
+        // Disable checks during shouldInterceptRequest since there is no way to avoid IO here :(.
+        UriResolvers.webCoreThread = null;
+        try {
+            UriResolver uriResolver = appView.resolveUri(Uri.parse(url), true);
+            
+            if (uriResolver == null && url.startsWith("file:///android_asset/")) {
+                if (url.contains("?") || url.contains("#") || needsIceCreamSpecialsInAssetUrlFix(url)) {
+                    uriResolver = appView.resolveUri(Uri.parse(url), false);
+                }
             }
-        }
-        
-        if (uriResolver != null) {
-            try {
-                InputStream stream = uriResolver.getInputStream();
-                String mimeType = uriResolver.getMimeType();
-                // If we don't know how to open this file, let the browser continue loading
-                return new WebResourceResponse(mimeType, "UTF-8", stream);
-            } catch (IOException e) {
-                LOG.e("IceCreamCordovaWebViewClient", "Error occurred while loading a file.", e);
-                // Results in a 404.
-                return new WebResourceResponse("text/plain", "UTF-8", null);
+            
+            if (uriResolver != null) {
+                try {
+                    InputStream stream = uriResolver.getInputStream();
+                    String mimeType = uriResolver.getMimeType();
+                    // If we don't know how to open this file, let the browser continue loading
+                    return new WebResourceResponse(mimeType, "UTF-8", stream);
+                } catch (IOException e) {
+                    LOG.e("IceCreamCordovaWebViewClient", "Error occurred while loading a file.", e);
+                    // Results in a 404.
+                    return new WebResourceResponse("text/plain", "UTF-8", null);
+                }
             }
+            return null;
+        } finally {
+            // Tell the Thread-Checking resolve what thread the WebCore thread is.
+            UriResolvers.webCoreThread = Thread.currentThread();
         }
-        return null;
     }
         
     private static boolean needsIceCreamSpecialsInAssetUrlFix(String url) {

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e9b46e5c/framework/src/org/apache/cordova/UriResolver.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/UriResolver.java b/framework/src/org/apache/cordova/UriResolver.java
index 42e9a3a..8341b18 100644
--- a/framework/src/org/apache/cordova/UriResolver.java
+++ b/framework/src/org/apache/cordova/UriResolver.java
@@ -31,9 +31,6 @@ import android.net.Uri;
  */
 public interface UriResolver {
 
-    /** Returns the URI that this instance will resolve. */
-    Uri getUri();
-    
     /** 
      * Returns the InputStream for the resource. 
      * Throws an exception if it cannot be read. 

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e9b46e5c/framework/src/org/apache/cordova/UriResolvers.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/UriResolvers.java b/framework/src/org/apache/cordova/UriResolvers.java
index e8be407..dcb5001 100644
--- a/framework/src/org/apache/cordova/UriResolvers.java
+++ b/framework/src/org/apache/cordova/UriResolvers.java
@@ -34,76 +34,64 @@ import android.content.ContentResolver;
 import android.content.Context;
 import android.content.res.AssetManager;
 import android.net.Uri;
+import android.os.Looper;
 
 /*
  * UriResolver implementations.
  */
 public final class UriResolvers {
+    static Thread webCoreThread;
+
     private UriResolvers() {}
 
     private static final class FileUriResolver implements UriResolver {
-        private final Uri uri;
+        private final File localFile;
         private String mimeType;
-        private File localFile;
     
         FileUriResolver(Uri uri) {
-            this.uri = uri;
-        }
-        
-        public Uri getUri() {
-            return uri;
+            localFile = new File(uri.getPath());
         }
         
         public InputStream getInputStream() throws IOException {
-            return new FileInputStream(getLocalFile());
+            return new FileInputStream(localFile);
         }
         
         public OutputStream getOutputStream() throws FileNotFoundException {
-            return new FileOutputStream(getLocalFile());
+            return new FileOutputStream(localFile);
         }
         
         public String getMimeType() {
             if (mimeType == null) {
-                mimeType = FileHelper.getMimeTypeForExtension(getLocalFile().getName());
+                mimeType = FileHelper.getMimeTypeForExtension(localFile.getName());
             }
             return mimeType;
         }
         
         public boolean isWritable() {
-            File f = getLocalFile();
-            if (f.isDirectory()) {
+            if (localFile.isDirectory()) {
                 return false;
             }
-            if (f.exists()) {
-                return f.canWrite();
+            if (localFile.exists()) {
+                return localFile.canWrite();
             }
-            return f.getParentFile().canWrite();
+            return localFile.getParentFile().canWrite();
         }
         
         public File getLocalFile() {
-            if (localFile == null) {
-                localFile = new File(uri.getPath());
-            }
             return localFile;
         }
     }
     
     private static final class AssetUriResolver implements UriResolver {
-        private final Uri uri;
         private final AssetManager assetManager;
         private final String assetPath;
         private String mimeType;
     
         AssetUriResolver(Uri uri, AssetManager assetManager) {
-            this.uri = uri;
             this.assetManager = assetManager;
             this.assetPath = uri.getPath().substring(15);
         }
         
-        public Uri getUri() {
-            return uri;
-        }
-        
         public InputStream getInputStream() throws IOException {
             return assetManager.open(assetPath);
         }
@@ -138,10 +126,6 @@ public final class UriResolvers {
             this.contentResolver = contentResolver;
         }
         
-        public Uri getUri() {
-            return uri;
-        }
-        
         public InputStream getInputStream() throws IOException {
             return contentResolver.openInputStream(uri);
         }
@@ -166,88 +150,108 @@ public final class UriResolvers {
         }
     }
     
-    static final class ErrorUriResolver implements UriResolver {
-        final Uri uri;
+    private static final class ErrorUriResolver implements UriResolver {
         final String errorMsg;
         
-        ErrorUriResolver(Uri uri, String errorMsg) {
-            this.uri = uri;
+        ErrorUriResolver(String errorMsg) {
             this.errorMsg = errorMsg;
         }
         
-        @Override
         public boolean isWritable() {
             return false;
         }
         
-        @Override
-        public Uri getUri() {
-            return uri;
-        }
-        
-        @Override
         public File getLocalFile() {
             return null;
         }
         
-        @Override
         public OutputStream getOutputStream() throws IOException {
             throw new FileNotFoundException(errorMsg);
         }
         
-        @Override
         public String getMimeType() {
             return null;
         }
         
-        @Override
         public InputStream getInputStream() throws IOException {
             throw new FileNotFoundException(errorMsg);
         }
     }
     
     private static final class ReadOnlyResolver implements UriResolver {
-        private Uri uri;
         private InputStream inputStream;
         private String mimeType;
         
         public ReadOnlyResolver(Uri uri, InputStream inputStream, String mimeType) {
-            this.uri = uri;
             this.inputStream = inputStream;
             this.mimeType = mimeType;
         }
         
-        @Override
         public boolean isWritable() {
             return false;
         }
         
-        @Override
-        public Uri getUri() {
-            return uri;
-        }
-        
-        @Override
         public File getLocalFile() {
             return null;
         }
         
-        @Override
         public OutputStream getOutputStream() throws IOException {
             throw new FileNotFoundException("URI is not writable");
         }
         
-        @Override
         public String getMimeType() {
             return mimeType;
         }
         
-        @Override
         public InputStream getInputStream() throws IOException {
             return inputStream;
         }
     }
     
+    private static final class ThreadCheckingResolver implements UriResolver {
+        final UriResolver delegate;
+        
+        ThreadCheckingResolver(UriResolver delegate) {
+            this.delegate = delegate;
+        }
+
+        private static void checkThread() {
+            Thread curThread = Thread.currentThread();
+            if (curThread == Looper.getMainLooper().getThread()) {
+                throw new IllegalStateException("Do not perform IO operations on the UI thread. Use CordovaInterface.getThreadPool() instead.");
+            }
+            if (curThread == webCoreThread) {
+                throw new IllegalStateException("Tried to perform an IO operation on the WebCore thread. Use CordovaInterface.getThreadPool() instead.");
+            }
+        }
+        
+        public boolean isWritable() {
+            checkThread();
+            return delegate.isWritable();
+        }
+        
+
+        public File getLocalFile() {
+            checkThread();
+            return delegate.getLocalFile();
+        }
+        
+        public OutputStream getOutputStream() throws IOException {
+            checkThread();
+            return delegate.getOutputStream();
+        }
+        
+        public String getMimeType() {
+            checkThread();
+            return delegate.getMimeType();
+        }
+        
+        public InputStream getInputStream() throws IOException {
+            checkThread();
+            return delegate.getInputStream();
+        }
+    }
+    
     public static UriResolver createInline(Uri uri, String response, String mimeType) {
         return createInline(uri, EncodingUtils.getBytes(response, "UTF-8"), mimeType);
     }
@@ -260,6 +264,10 @@ public final class UriResolvers {
         return new ReadOnlyResolver(uri, inputStream, mimeType);
     }
     
+    public static UriResolver createError(String errorMsg) {
+        return new ErrorUriResolver(errorMsg);
+    }
+    
     /* Package-private to force clients to go through CordovaWebView.resolveUri(). */
     static UriResolver forUri(Uri uri, Context context) {
         String scheme = uri.getScheme();
@@ -274,4 +282,12 @@ public final class UriResolvers {
         }
         return null;
     }
+    
+    /* Used only by CordovaWebView.resolveUri(). */
+    static UriResolver makeThreadChecking(UriResolver resolver) {
+        if (resolver instanceof ThreadCheckingResolver) {
+            return resolver;
+        }
+        return new ThreadCheckingResolver(resolver);
+    }
 }
\ No newline at end of file


[13/16] android commit: Log WebView IOExceptions only when they are not 404s (cherry picked from commit 5451320350f8a814e3d09ab465710ddca462d243)

Posted by ag...@apache.org.
Log WebView IOExceptions only when they are not 404s
(cherry picked from commit 5451320350f8a814e3d09ab465710ddca462d243)


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

Branch: refs/heads/2.9.x
Commit: 64c617d8abb7ce2677a1145c9c4d2751139e7c88
Parents: bcccb0c
Author: Andrew Grieve <ag...@chromium.org>
Authored: Thu Aug 15 11:33:38 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:15:45 2013 -0400

----------------------------------------------------------------------
 .../src/org/apache/cordova/IceCreamCordovaWebViewClient.java    | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/64c617d8/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 3f98f56..13f9431 100644
--- a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
+++ b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
@@ -18,6 +18,7 @@
 */
 package org.apache.cordova;
 
+import java.io.FileNotFoundException;
 import java.io.IOException;
 
 import org.apache.cordova.CordovaResourceApi.OpenForReadResult;
@@ -65,7 +66,9 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
             // If we don't need to special-case the request, let the browser load it.
             return null;
         } catch (IOException e) {
-            LOG.e("IceCreamCordovaWebViewClient", "Error occurred while loading a file.", e);
+            if (!(e instanceof FileNotFoundException)) {
+                LOG.e("IceCreamCordovaWebViewClient", "Error occurred while loading a file (returning a 404).", e);
+            }
             // Results in a 404.
             return new WebResourceResponse("text/plain", "UTF-8", null);
         }


[08/16] android commit: [CB-4198] bin/create should handle spaces in activity better.

Posted by ag...@apache.org.
[CB-4198] bin/create should handle spaces in activity better.


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

Branch: refs/heads/2.9.x
Commit: 624a8d370cef21d9d6c1f991aba6f7ca3c97dd3e
Parents: 5814d66
Author: Fil Maj <ma...@gmail.com>
Authored: Wed Jul 24 21:21:41 2013 -0700
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:12:03 2013 -0400

----------------------------------------------------------------------
 bin/create | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/624a8d37/bin/create
----------------------------------------------------------------------
diff --git a/bin/create b/bin/create
index 4dfd20f..3883227 100755
--- a/bin/create
+++ b/bin/create
@@ -38,7 +38,8 @@ VERSION=$(cat "$BUILD_PATH"/VERSION)
 
 PROJECT_PATH="${1:-'./example'}"
 PACKAGE=${2:-"org.apache.cordova.example"}
-ACTIVITY=${3:-"cordovaExample"}
+ACTIVITY=$(echo ${3:-"cordovaExample"} | tr -d ' ')
+APP_LABEL=${3:-"Cordova Example"};
 
 # clobber any existing example
 if [ -d "$PROJECT_PATH" ]
@@ -67,7 +68,7 @@ function replace {
     # Mac OS X requires -i argument
     if [[ "$OSTYPE" =~ "darwin" ]]
     then
-        /usr/bin/sed -i '' -e $pattern "$filename"
+        /usr/bin/sed -i '' -e "$pattern" "$filename"
     elif [[ "$OSTYPE" =~ "linux" ]]
     then
         /bin/sed -i -e $pattern "$filename"
@@ -82,6 +83,7 @@ ANDROID_BIN="${ANDROID_BIN:=$( which android )}"
 PACKAGE_AS_PATH=$(echo $PACKAGE | sed 's/\./\//g')
 ACTIVITY_PATH="$PROJECT_PATH"/src/$PACKAGE_AS_PATH/$ACTIVITY.java
 MANIFEST_PATH="$PROJECT_PATH"/AndroidManifest.xml
+STRINGS_PATH="$PROJECT_PATH"/res/values/strings.xml
 
 TARGET=$("$ANDROID_BIN" list targets | grep id: | tail -1 | cut -f 2 -d ' ' )
 API_LEVEL=$("$ANDROID_BIN" list target | grep "API level:" | tail -n 1 | cut -f 2 -d ':' | tr -d ' ')
@@ -129,6 +131,9 @@ cp "$BUILD_PATH"/bin/templates/project/Activity.java "$ACTIVITY_PATH"
 replace "s/__ACTIVITY__/${ACTIVITY}/g" "$ACTIVITY_PATH"
 replace "s/__ID__/${PACKAGE}/g" "$ACTIVITY_PATH"
 
+# interpolate the app name into strings.xml
+replace "s/>${ACTIVITY}</>${APP_LABEL}</g" "$STRINGS_PATH"
+
 cp "$BUILD_PATH"/bin/templates/project/AndroidManifest.xml "$MANIFEST_PATH"
 replace "s/__ACTIVITY__/${ACTIVITY}/g" "$MANIFEST_PATH"
 replace "s/__PACKAGE__/${PACKAGE}/g" "$MANIFEST_PATH"


[09/16] android commit: [CB-4198] bin/create script should be better at handling non-word characters in activity name. Patched windows script as well. (cherry picked from commit b4236b978355a599cad77a4d2a776354dbfdbe09)

Posted by ag...@apache.org.
[CB-4198] bin/create script should be better at handling non-word characters in activity name. Patched windows script as well.
(cherry picked from commit b4236b978355a599cad77a4d2a776354dbfdbe09)


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

Branch: refs/heads/2.9.x
Commit: dc494c85f2620a28eccd49bf99fcc8f7d1e90eb3
Parents: 624a8d3
Author: Fil Maj <ma...@gmail.com>
Authored: Thu Jul 25 10:33:05 2013 -0700
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:12:11 2013 -0400

----------------------------------------------------------------------
 bin/create    |   2 +-
 bin/create.js | 424 +++++++++++++++++++++++++++--------------------------
 2 files changed, 215 insertions(+), 211 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/dc494c85/bin/create
----------------------------------------------------------------------
diff --git a/bin/create b/bin/create
index 3883227..7c4ddbc 100755
--- a/bin/create
+++ b/bin/create
@@ -38,7 +38,7 @@ VERSION=$(cat "$BUILD_PATH"/VERSION)
 
 PROJECT_PATH="${1:-'./example'}"
 PACKAGE=${2:-"org.apache.cordova.example"}
-ACTIVITY=$(echo ${3:-"cordovaExample"} | tr -d ' ')
+ACTIVITY=$(echo ${3:-"cordovaExample"} | tr -d '[:blank:][:punct:]')
 APP_LABEL=${3:-"Cordova Example"};
 
 # clobber any existing example

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/dc494c85/bin/create.js
----------------------------------------------------------------------
diff --git a/bin/create.js b/bin/create.js
index 1cb794f..c723b12 100644
--- a/bin/create.js
+++ b/bin/create.js
@@ -1,210 +1,214 @@
-/*
-       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.
-*/
-
-/*
- * create a cordova/android project
- *
- * USAGE
- *  ./create [path package activity]
- */
-
-var args = WScript.Arguments, PROJECT_PATH="example", 
-    PACKAGE="org.apache.cordova.example", ACTIVITY="cordovaExample",
-    shell=WScript.CreateObject("WScript.Shell"),
-    fso = WScript.CreateObject('Scripting.FileSystemObject');
-
-function Usage() {
-    Log("Usage: create PathTONewProject [ PackageName AppName ]");
-    Log("    PathTONewProject : The path to where you wish to create the project");
-    Log("    PackageName      : The package for the project (default is org.apache.cordova.example)")
-    Log("    AppName          : The name of the application/activity (default is cordovaExample)");
-    Log("examples:");
-    Log("    create C:\\Users\\anonymous\\Desktop\\MyProject");
-    Log("    create C:\\Users\\anonymous\\Desktop\\MyProject io.Cordova.Example AnApp");
-}
-
-// logs messaged to stdout and stderr
-function Log(msg, error) {
-    if (error) {
-        WScript.StdErr.WriteLine(msg);
-    }
-    else {
-        WScript.StdOut.WriteLine(msg);
-    }
-}
-
-function read(filename) {
-    var fso=WScript.CreateObject("Scripting.FileSystemObject");
-    var f=fso.OpenTextFile(filename, 1);
-    var s=f.ReadAll();
-    f.Close();
-    return s;
-}
-
-function checkTargets(targets) {
-    if(!targets) {
-        Log("You do not have any android targets setup. Please create at least one target with the `android` command", true);
-        WScript.Quit(69);
-    }
-}
-
-function setTarget() {
-    var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/id:\s\d+/g);
-    checkTargets(targets);
-    return targets[targets.length - 1].replace(/id: /, ""); // TODO: give users the option to set their target 
-}
-function setApiLevel() {
-    var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/API level:\s\d+/g);
-    checkTargets(targets);
-    return targets[targets.length - 1].replace(/API level: /, "");
-}
-function write(filename, contents) {
-    var fso=WScript.CreateObject("Scripting.FileSystemObject");
-    var f=fso.OpenTextFile(filename, 2, true);
-    f.Write(contents);
-    f.Close();
-}
-function replaceInFile(filename, regexp, replacement) {
-    write(filename, read(filename).replace(regexp, replacement));
-}
-function exec(command) {
-    var oShell=shell.Exec(command);
-    while (oShell.Status == 0) {
-        if(!oShell.StdOut.AtEndOfStream) {
-            var line = oShell.StdOut.ReadLine();
-            // XXX: Change to verbose mode 
-            // WScript.StdOut.WriteLine(line);
-        }
-        WScript.sleep(100);
-    }
-}
-
-function createAppInfoJar() {
-    if(!fso.FileExists(ROOT+"\\bin\\templates\\cordova\\appinfo.jar")) {
-        Log("Creating appinfo.jar...");
-        var cur = shell.CurrentDirectory;
-        shell.CurrentDirectory = ROOT+"\\bin\\templates\\cordova\\ApplicationInfo";
-        exec("javac ApplicationInfo.java");
-        exec("jar -cfe ..\\appinfo.jar ApplicationInfo ApplicationInfo.class");
-        shell.CurrentDirectory = cur;
-    }
-}
-
-// working dir
-var ROOT = WScript.ScriptFullName.split('\\bin\\create.js').join('');
-if (args.Count() > 0) {
-    // support help flags
-    if (args(0) == "--help" || args(0) == "/?" ||
-            args(0) == "help" || args(0) == "-help" || args(0) == "/help" || args(0) == "-h") {
-        Usage();
-        WScript.Quit(2);
-    }
-
-    PROJECT_PATH=args(0);
-    if (args.Count() > 1) {
-        PACKAGE = args(1);
-    }
-    if (args.Count() > 2) {
-        ACTIVITY = args(2);
-    }
-}
-else {
-    Log("Error : No project path provided.");
-    Usage();
-    WScript.Quit(2);
-}
-
-if(fso.FolderExists(PROJECT_PATH)) {
-    Log("Project path already exists!", true);
-    WScript.Quit(2);
-}
-
-var PACKAGE_AS_PATH=PACKAGE.replace(/\./g, '\\');
-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();
-var VERSION=read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,'');
-// create the project
-Log("Creating new android project...");
-exec('android.bat create project --target "'+TARGET+'" --path "'+PROJECT_PATH+'" --package "'+PACKAGE+'" --activity "'+ACTIVITY+'"');
-
-// build from source. distro should have these files
-if (!fso.FileExists(ROOT+'\\cordova-'+VERSION+'.jar') &&
-    !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"');
-    exec('ant.bat -f "'+ ROOT +'\\framework\\build.xml" jar');
-}
-
-// copy in the project template
-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 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.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.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
-    fso.CreateFolder(PROJECT_PATH + '\\res\\xml');
-    exec('%comspec% /c copy "'+ROOT+'\\xml\\config.xml" "' + PROJECT_PATH + '\\res\\xml\\config.xml" /Y');
-}
-
-// copy cordova scripts
-fso.CreateFolder(PROJECT_PATH + '\\cordova');
-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\\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');
-exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\list-devices.bat" "' + PROJECT_PATH + '\\cordova\\lib\\list-devices.bat" /Y');
-exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\list-started-emulators.bat" "' + PROJECT_PATH + '\\cordova\\lib\\list-started-emulators.bat" /Y');
-exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\start-emulator.bat" "' + PROJECT_PATH + '\\cordova\\lib\\start-emulator.bat" /Y');
-exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\cordova.bat" "' + PROJECT_PATH + '\\cordova\\cordova.bat" /Y');
-exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\clean.bat" "' + PROJECT_PATH + '\\cordova\\clean.bat" /Y');
-exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\build.bat" "' + PROJECT_PATH + '\\cordova\\build.bat" /Y');
-exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\log.bat" "' + PROJECT_PATH + '\\cordova\\log.bat" /Y');
-exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\run.bat" "' + PROJECT_PATH + '\\cordova\\run.bat" /Y');
-exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\version.bat" "' + PROJECT_PATH + '\\cordova\\version.bat" /Y');
-
-// interpolate the activity name and package
-Log("Updating AndroidManifest.xml and Main Activity...");
-replaceInFile(ACTIVITY_PATH, /__ACTIVITY__/, ACTIVITY);
-replaceInFile(ACTIVITY_PATH, /__ID__/, PACKAGE);
-
-replaceInFile(MANIFEST_PATH, /__ACTIVITY__/, ACTIVITY);
-replaceInFile(MANIFEST_PATH, /__PACKAGE__/, PACKAGE);
-replaceInFile(MANIFEST_PATH, /__APILEVEL__/, API_LEVEL);
\ No newline at end of file
+/*
+       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.
+*/
+
+/*
+ * create a cordova/android project
+ *
+ * USAGE
+ *  ./create [path package activity]
+ */
+
+var args = WScript.Arguments, PROJECT_PATH="example", 
+    PACKAGE="org.apache.cordova.example", ACTIVITY="cordovaExample",
+    shell=WScript.CreateObject("WScript.Shell"),
+    fso = WScript.CreateObject('Scripting.FileSystemObject');
+
+function Usage() {
+    Log("Usage: create PathTONewProject [ PackageName AppName ]");
+    Log("    PathTONewProject : The path to where you wish to create the project");
+    Log("    PackageName      : The package for the project (default is org.apache.cordova.example)")
+    Log("    AppName          : The name of the application/activity (default is cordovaExample)");
+    Log("examples:");
+    Log("    create C:\\Users\\anonymous\\Desktop\\MyProject");
+    Log("    create C:\\Users\\anonymous\\Desktop\\MyProject io.Cordova.Example AnApp");
+}
+
+// logs messaged to stdout and stderr
+function Log(msg, error) {
+    if (error) {
+        WScript.StdErr.WriteLine(msg);
+    }
+    else {
+        WScript.StdOut.WriteLine(msg);
+    }
+}
+
+function read(filename) {
+    var fso=WScript.CreateObject("Scripting.FileSystemObject");
+    var f=fso.OpenTextFile(filename, 1);
+    var s=f.ReadAll();
+    f.Close();
+    return s;
+}
+
+function checkTargets(targets) {
+    if(!targets) {
+        Log("You do not have any android targets setup. Please create at least one target with the `android` command", true);
+        WScript.Quit(69);
+    }
+}
+
+function setTarget() {
+    var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/id:\s\d+/g);
+    checkTargets(targets);
+    return targets[targets.length - 1].replace(/id: /, ""); // TODO: give users the option to set their target 
+}
+function setApiLevel() {
+    var targets = shell.Exec('android.bat list targets').StdOut.ReadAll().match(/API level:\s\d+/g);
+    checkTargets(targets);
+    return targets[targets.length - 1].replace(/API level: /, "");
+}
+function write(filename, contents) {
+    var fso=WScript.CreateObject("Scripting.FileSystemObject");
+    var f=fso.OpenTextFile(filename, 2, true);
+    f.Write(contents);
+    f.Close();
+}
+function replaceInFile(filename, regexp, replacement) {
+    write(filename, read(filename).replace(regexp, replacement));
+}
+function exec(command) {
+    var oShell=shell.Exec(command);
+    while (oShell.Status == 0) {
+        if(!oShell.StdOut.AtEndOfStream) {
+            var line = oShell.StdOut.ReadLine();
+            // XXX: Change to verbose mode 
+            // WScript.StdOut.WriteLine(line);
+        }
+        WScript.sleep(100);
+    }
+}
+
+function createAppInfoJar() {
+    if(!fso.FileExists(ROOT+"\\bin\\templates\\cordova\\appinfo.jar")) {
+        Log("Creating appinfo.jar...");
+        var cur = shell.CurrentDirectory;
+        shell.CurrentDirectory = ROOT+"\\bin\\templates\\cordova\\ApplicationInfo";
+        exec("javac ApplicationInfo.java");
+        exec("jar -cfe ..\\appinfo.jar ApplicationInfo ApplicationInfo.class");
+        shell.CurrentDirectory = cur;
+    }
+}
+
+// working dir
+var ROOT = WScript.ScriptFullName.split('\\bin\\create.js').join('');
+if (args.Count() > 0) {
+    // support help flags
+    if (args(0) == "--help" || args(0) == "/?" ||
+            args(0) == "help" || args(0) == "-help" || args(0) == "/help" || args(0) == "-h") {
+        Usage();
+        WScript.Quit(2);
+    }
+
+    PROJECT_PATH=args(0);
+    if (args.Count() > 1) {
+        PACKAGE = args(1);
+    }
+    if (args.Count() > 2) {
+        ACTIVITY = args(2);
+    }
+}
+else {
+    Log("Error : No project path provided.");
+    Usage();
+    WScript.Quit(2);
+}
+
+if(fso.FolderExists(PROJECT_PATH)) {
+    Log("Project path already exists!", true);
+    WScript.Quit(2);
+}
+
+var PACKAGE_AS_PATH=PACKAGE.replace(/\./g, '\\');
+var ACTIVITY_DIR=PROJECT_PATH + '\\src\\' + PACKAGE_AS_PATH;
+var SAFE_ACTIVITY = ACTIVITY.replace(/\W/g, '');
+var ACTIVITY_PATH=ACTIVITY_DIR+'\\'+SAFE_ACTIVITY+'.java';
+var MANIFEST_PATH=PROJECT_PATH+'\\AndroidManifest.xml';
+var STRINGS_PATH=PROJECT_PATH+'\\res\\values\\strings.xml';
+var TARGET=setTarget();
+var API_LEVEL=setApiLevel();
+var VERSION=read(ROOT+'\\VERSION').replace(/\r\n/,'').replace(/\n/,'');
+// create the project
+Log("Creating new android project...");
+exec('android.bat create project --target "'+TARGET+'" --path "'+PROJECT_PATH+'" --package "'+PACKAGE+'" --activity "'+SAFE_ACTIVITY+'"');
+
+// build from source. distro should have these files
+if (!fso.FileExists(ROOT+'\\cordova-'+VERSION+'.jar') &&
+    !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"');
+    exec('ant.bat -f "'+ ROOT +'\\framework\\build.xml" jar');
+}
+
+// copy in the project template
+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 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.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.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
+    fso.CreateFolder(PROJECT_PATH + '\\res\\xml');
+    exec('%comspec% /c copy "'+ROOT+'\\xml\\config.xml" "' + PROJECT_PATH + '\\res\\xml\\config.xml" /Y');
+}
+
+// copy cordova scripts
+fso.CreateFolder(PROJECT_PATH + '\\cordova');
+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\\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');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\list-devices.bat" "' + PROJECT_PATH + '\\cordova\\lib\\list-devices.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\list-started-emulators.bat" "' + PROJECT_PATH + '\\cordova\\lib\\list-started-emulators.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\lib\\start-emulator.bat" "' + PROJECT_PATH + '\\cordova\\lib\\start-emulator.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\cordova.bat" "' + PROJECT_PATH + '\\cordova\\cordova.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\clean.bat" "' + PROJECT_PATH + '\\cordova\\clean.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\build.bat" "' + PROJECT_PATH + '\\cordova\\build.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\log.bat" "' + PROJECT_PATH + '\\cordova\\log.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\run.bat" "' + PROJECT_PATH + '\\cordova\\run.bat" /Y');
+exec('%comspec% /c copy "'+ROOT+'\\bin\\templates\\cordova\\version.bat" "' + PROJECT_PATH + '\\cordova\\version.bat" /Y');
+
+// interpolate the activity name and package
+Log("Updating AndroidManifest.xml and Main Activity...");
+replaceInFile(ACTIVITY_PATH, /__ACTIVITY__/, ACTIVITY);
+replaceInFile(ACTIVITY_PATH, /__ID__/, PACKAGE);
+
+replaceInFile(MANIFEST_PATH, /__ACTIVITY__/, ACTIVITY);
+replaceInFile(MANIFEST_PATH, /__PACKAGE__/, PACKAGE);
+replaceInFile(MANIFEST_PATH, /__APILEVEL__/, API_LEVEL);
+
+replaceInFile(STRINGS_PATH, new RegExp('>' + SAFE_ACTIVITY + '<'), '>' + ACTIVITY + '<');
\ No newline at end of file


[05/16] android commit: Prevent NPE in case webview is lately initialized (cherry picked from commit a9ebf50b86bcb9de40cbf4013e98fd1a24be25e8)

Posted by ag...@apache.org.
Prevent NPE in case webview is lately initialized
(cherry picked from commit a9ebf50b86bcb9de40cbf4013e98fd1a24be25e8)


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

Branch: refs/heads/2.9.x
Commit: dd770ef303e8b484bfc83e8ac93d38b08f2d4ba3
Parents: 8b3fa5c
Author: denis <de...@orange.com>
Authored: Mon Jul 1 15:37:29 2013 +0800
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:09:51 2013 -0400

----------------------------------------------------------------------
 framework/src/org/apache/cordova/CordovaActivity.java | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/dd770ef3/framework/src/org/apache/cordova/CordovaActivity.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaActivity.java b/framework/src/org/apache/cordova/CordovaActivity.java
index 95cb2f1..5c90316 100755
--- a/framework/src/org/apache/cordova/CordovaActivity.java
+++ b/framework/src/org/apache/cordova/CordovaActivity.java
@@ -858,8 +858,8 @@ public class CordovaActivity extends Activity implements CordovaInterface {
         LOG.d(TAG, "Incoming Result");
         super.onActivityResult(requestCode, resultCode, intent);
         Log.d(TAG, "Request code = " + requestCode);
-        ValueCallback<Uri> mUploadMessage = this.appView.getWebChromeClient().getValueCallback();
-        if (requestCode == CordovaChromeClient.FILECHOOSER_RESULTCODE) {
+        if (appView != null && requestCode == CordovaChromeClient.FILECHOOSER_RESULTCODE) {
+        	ValueCallback<Uri> mUploadMessage = this.appView.getWebChromeClient().getValueCallback();
             Log.d(TAG, "did we get here?");
             if (null == mUploadMessage)
                 return;
@@ -1079,9 +1079,7 @@ public class CordovaActivity extends Activity implements CordovaInterface {
     @Override
     public boolean onKeyUp(int keyCode, KeyEvent event)
     {
-        //Get whatever has focus!
-        View childView = appView.getFocusedChild();
-        if ((appView.isCustomViewShowing() || childView != null ) &&
+        if (appView != null && (appView.isCustomViewShowing() || appView.getFocusedChild() != null ) &&
                 (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU)) {
             return appView.onKeyUp(keyCode, event);
         } else {
@@ -1099,10 +1097,8 @@ public class CordovaActivity extends Activity implements CordovaInterface {
     @Override
     public boolean onKeyDown(int keyCode, KeyEvent event)
     {
-        //Get whatever has focus!
-        View childView = appView.getFocusedChild();
         //Determine if the focus is on the current view or not
-        if (childView != null && (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU)) {
+        if (appView != null && appView.getFocusedChild() != null && (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU)) {
                     return appView.onKeyDown(keyCode, event);
         }
         else


[14/16] android commit: [CB-4495] Modify start-emulator script to exit immediately on a fatal emulator error. (cherry picked from commit 121b74fa0c8b5c2aea25173d128b5745c3b85390)

Posted by ag...@apache.org.
[CB-4495] Modify start-emulator script to exit immediately on a fatal emulator error.
(cherry picked from commit 121b74fa0c8b5c2aea25173d128b5745c3b85390)


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

Branch: refs/heads/2.9.x
Commit: bb7bc33a8ab2a12bcd5540b4b6420b47a9ee76c9
Parents: 64c617d
Author: Tomaz Muraus <to...@tomaz.me>
Authored: Sat Aug 3 02:52:48 2013 +0200
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:15:58 2013 -0400

----------------------------------------------------------------------
 bin/templates/cordova/lib/start-emulator | 30 ++++++++++++++++++++++-----
 1 file changed, 25 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/bb7bc33a/bin/templates/cordova/lib/start-emulator
----------------------------------------------------------------------
diff --git a/bin/templates/cordova/lib/start-emulator b/bin/templates/cordova/lib/start-emulator
index 10e73ce..c7ce01a 100755
--- a/bin/templates/cordova/lib/start-emulator
+++ b/bin/templates/cordova/lib/start-emulator
@@ -24,7 +24,24 @@ function dot {
     echo -n "."
 }
 
-function wait_for_emulator {
+function wait_for_emulator() {
+    local emulator_log_path="$1"
+    local error_string
+    local status
+
+    # Try to detect fatal errors early
+    sleep 1.5
+    error_string=$(grep -F "ERROR: " ${emulator_log_path})
+    status=$?
+
+    if [ $status -eq 0 ]; then
+        echo "Emulator failed to start, fatal error detected"
+        echo "Error: ${error_string}"
+        echo "Full log available at: ${emulator_log_path}"
+        echo "Exiting..."
+        exit 1
+    fi
+
     local i="0"
     echo -n "Waiting for emulator"
     emulator_string=$($DIR/list-started-emulators)
@@ -70,22 +87,25 @@ if [ $? != 0 ]; then
     exit 2
 fi
 
+# start first emulator
+log_path=$(mktemp -t android_emulator)
+
 # if target emulator is provided
 if [[ "$#" -eq 1 ]] ; then
     # check that it exists
     if [[ $emulator_images =~ $1 ]] ; then
         #xterm -e emulator -avd $1 &
-        emulator -avd $1 1> /dev/null 2>&1 &
+        emulator -avd $1 1> "${log_path}" 2>&1 &
     else
         echo "Could not find the provided emulator '$1', make sure the emulator exists"
         echo " by checking 'cordova/lib/list-emulator-images'"
         exit 2
     fi
 else
-    # start first emulator
     read -ra emulator_list <<< "$emulator_images"
     #xterm -e emulator -avd ${emulator_list[0]} &
-    emulator -avd ${emulator_list[0]} 1> /dev/null 2>&1 &
+    emulator -avd ${emulator_list[0]} 1> "${log_path}" 2>&1 &
 fi
 
-wait_for_emulator
+echo "Saving emulator log to: ${log_path}"
+wait_for_emulator "$log_path"


[02/16] android commit: Let subclasses override focus behavior

Posted by ag...@apache.org.
Let subclasses override focus behavior

Signed-off-by: Joe Bowser <bo...@apache.org>
(cherry picked from commit 55865a4f1dcd0f24df5292e3621b77080939e6e1)


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

Branch: refs/heads/2.9.x
Commit: 4be84fbf124639525f4d1308e29619e28096e620
Parents: e9b46e5
Author: denis <de...@orange.com>
Authored: Mon Jul 1 16:28:22 2013 +0800
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:04:52 2013 -0400

----------------------------------------------------------------------
 .../src/org/apache/cordova/CordovaWebView.java  | 21 +++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4be84fbf/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 278bfa4..648b1f8 100755
--- a/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/framework/src/org/apache/cordova/CordovaWebView.java
@@ -228,9 +228,10 @@ public class CordovaWebView extends WebView {
     private void setup() {
         this.setInitialScale(0);
         this.setVerticalScrollBarEnabled(false);
-        this.requestFocusFromTouch();
-
-        // Enable JavaScript
+        if (shouldRequestFocusOnInit()) {
+			this.requestFocusFromTouch();
+		}
+		// Enable JavaScript
         WebSettings settings = this.getSettings();
         settings.setJavaScriptEnabled(true);
         settings.setJavaScriptCanOpenWindowsAutomatically(true);
@@ -308,8 +309,18 @@ public class CordovaWebView extends WebView {
         exposedJsApi = new ExposedJsApi(pluginManager, jsMessageQueue);
         exposeJsInterface();
     }
-    
-    private void updateUserAgentString() {
+
+	/**
+	 * Override this method to decide wether or not you need to request the
+	 * focus when your application start
+	 * 
+	 * @return
+	 */
+    protected boolean shouldRequestFocusOnInit() {
+		return true;
+	}
+
+	private void updateUserAgentString() {
         this.getSettings().getUserAgentString();
     }
 


[12/16] android commit: Fix data URI decoding in CordovaResourceApi

Posted by ag...@apache.org.
Fix data URI decoding in CordovaResourceApi

It was not URI-decoding first, and so was broken for non-base64-encoded
URIs.
(cherry picked from commit 4e1aa8aa59d0a3d9c0deb1f57c9136a76535691e)


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

Branch: refs/heads/2.9.x
Commit: bcccb0c62058eb8bcbb0a54f156979945631807f
Parents: e1de55c
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Aug 13 14:08:30 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:14:36 2013 -0400

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


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/bcccb0c6/framework/src/org/apache/cordova/CordovaResourceApi.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaResourceApi.java b/framework/src/org/apache/cordova/CordovaResourceApi.java
index cb85744..f03f1b5 100644
--- a/framework/src/org/apache/cordova/CordovaResourceApi.java
+++ b/framework/src/org/apache/cordova/CordovaResourceApi.java
@@ -315,7 +315,7 @@ public class CordovaResourceApi {
     }
     
     private OpenForReadResult readDataUri(Uri uri) {
-        String uriAsString = uri.toString().substring(5);
+        String uriAsString = uri.getSchemeSpecificPart();
         int commaPos = uriAsString.indexOf(',');
         if (commaPos == -1) {
             return null;


[16/16] android commit: CB-5080 Find resources in a way that works with aapt's --rename-manifest-package (cherry picked from commit 16de12a3ba3c0ed8cfa15e9c9d7d68d384d178bb)

Posted by ag...@apache.org.
CB-5080 Find resources in a way that works with aapt's --rename-manifest-package
(cherry picked from commit 16de12a3ba3c0ed8cfa15e9c9d7d68d384d178bb)


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

Branch: refs/heads/2.9.x
Commit: 93b9b53acbf333f3cb8ba61bad732a2b9cf4d765
Parents: edb35b5
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Oct 15 12:17:14 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:18:44 2013 -0400

----------------------------------------------------------------------
 framework/src/org/apache/cordova/Config.java        | 4 ++--
 framework/src/org/apache/cordova/PluginManager.java | 7 +------
 2 files changed, 3 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/93b9b53a/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 3ef35a5..76eda1b 100644
--- a/framework/src/org/apache/cordova/Config.java
+++ b/framework/src/org/apache/cordova/Config.java
@@ -72,7 +72,7 @@ public class Config {
             return;
         }
 
-        int id = action.getResources().getIdentifier("config", "xml", action.getPackageName());
+        int id = action.getResources().getIdentifier("config", "xml", action.getClass().getPackage().getName());
         if (id == 0) {
             id = action.getResources().getIdentifier("cordova", "xml", action.getPackageName());
             LOG.i("CordovaLog", "config.xml missing, reverting to cordova.xml");
@@ -123,7 +123,7 @@ public class Config {
                         {
                             value = "splash";
                         }
-                        resource = action.getResources().getIdentifier(value, "drawable", action.getPackageName());
+                        resource = action.getResources().getIdentifier(value, "drawable", action.getClass().getPackage().getName());
                         
                         action.getIntent().putExtra(name, resource);
                     }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/93b9b53a/framework/src/org/apache/cordova/PluginManager.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/PluginManager.java b/framework/src/org/apache/cordova/PluginManager.java
index 2db9d56..5249f50 100755
--- a/framework/src/org/apache/cordova/PluginManager.java
+++ b/framework/src/org/apache/cordova/PluginManager.java
@@ -107,12 +107,7 @@ public class PluginManager {
      * Load plugins from res/xml/config.xml
      */
     public void loadPlugins() {
-        int id = this.ctx.getActivity().getResources().getIdentifier("config", "xml", this.ctx.getActivity().getPackageName());
-        if(id == 0)
-        {
-            id = this.ctx.getActivity().getResources().getIdentifier("plugins", "xml", this.ctx.getActivity().getPackageName());
-            LOG.i(TAG, "Using plugins.xml instead of config.xml.  plugins.xml will eventually be deprecated");
-        }
+        int id = this.ctx.getActivity().getResources().getIdentifier("config", "xml", this.ctx.getActivity().getClass().getPackage().getName());
         if (id == 0) {
             this.pluginConfigurationMissing();
             //We have the error, we need to exit without crashing!


[11/16] android commit: [CB-4466] fixed jscript check_reqs to get target from project.properties (cherry picked from commit 53b8da81985464b82d87e1655e6561f2076b4206)

Posted by ag...@apache.org.
[CB-4466] fixed jscript check_reqs to get target from project.properties
(cherry picked from commit 53b8da81985464b82d87e1655e6561f2076b4206)


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

Branch: refs/heads/2.9.x
Commit: e1de55cc82c050911d36b1ccd12cf6e499df8edb
Parents: 4b501a5
Author: Benn Mapes <be...@gmail.com>
Authored: Thu Aug 1 17:57:58 2013 -0700
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:14:09 2013 -0400

----------------------------------------------------------------------
 bin/check_reqs.js | 31 ++++++++++++++++++++++++++-----
 1 file changed, 26 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/e1de55cc/bin/check_reqs.js
----------------------------------------------------------------------
diff --git a/bin/check_reqs.js b/bin/check_reqs.js
index 7fc32b8..4a724a6 100644
--- a/bin/check_reqs.js
+++ b/bin/check_reqs.js
@@ -54,22 +54,28 @@ function Log(msg, error) {
     else {
         WScript.StdOut.WriteLine(msg);
     }
-} 
+}
 
 // checks that android requirements are met
 function check_requirements() {
+    var target = get_target();
+    if(target==null) {
+        Log('Unable to find android target in project.properties');
+        WScript.Quit(2);
+    }
     var result = exec_out('%comspec% /c android list target');
     if(result.error) {
         Log('The command `android` failed. Make sure you have the latest Android SDK installed, and the `android` command (inside the tools/ folder) added to your path. Output: ' + result.output, true);
         WScript.Quit(2);
     }
-    else if(!result.output.match(/android[-]18/)) {
-        Log('Please install Android target 18 (the Android 4.3 SDK). Make sure you have the latest Android tools installed as well. Run `android` from your command-line to install/update any missing SDKs or tools.', true);
-        Log('Output : ' + result.output);
+    else if(result.output.indexOf(target) == -1) {
+        Log(result.output.indexOf(target));
+        Log('Please install the latest Android target (' + target + '). Make sure you have the latest Android tools installed as well. Run `android` from your command-line to install/update any missing SDKs or tools.', true);
+        Log(result.output);
         WScript.Quit(2);
     }
     else {
-        var cmd = '%comspec% /c android update project -p ' + ROOT + '\\framework -t android-18';
+        var cmd = '%comspec% /c android update project -p ' + ROOT + '\\framework -t ' + target;
         result = exec_out(cmd);
         if(result.error) {
             Log('Error updating the Cordova library to work with your Android environment. Command run: "' + cmd + '", output: ' + result.output, true);
@@ -78,4 +84,19 @@ function check_requirements() {
     }
 }
 
+function get_target() {
+    var fso=WScript.CreateObject("Scripting.FileSystemObject");
+    var f=fso.OpenTextFile(ROOT + '\\framework\\project.properties', 1);
+    var s=f.ReadAll();
+    var lines = s.split('\n');
+    for (var line in lines) {
+        if(lines[line].match(/target=/))
+        {
+            return lines[line].split('=')[1].replace(' ', '').replace('\r', '');
+        }
+    }
+    return null;
+}
+
 check_requirements();
+


[04/16] android commit: [CB-3384] Reworked UriResolver into CordovaResourceApi.

Posted by ag...@apache.org.
[CB-3384] Reworked UriResolver into CordovaResourceApi.

Changes were made after trying to use the API for Camera, FileTransfer, Media.
The main difference is separating the concept of URI remapping from the read/write helpers.
(cherry picked from commit 77e9092108b4997abdc08afa630b8c16ee094f90)


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

Branch: refs/heads/2.9.x
Commit: 8b3fa5c91e28e8bdd8a1b3ada0f95f4da5052497
Parents: 43bf47e
Author: Andrew Grieve <ag...@chromium.org>
Authored: Sun Jul 14 21:39:55 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:09:15 2013 -0400

----------------------------------------------------------------------
 .../src/org/apache/cordova/CordovaPlugin.java   |   8 +-
 .../org/apache/cordova/CordovaResourceApi.java  | 347 +++++++++++++++++++
 .../src/org/apache/cordova/CordovaWebView.java  |  37 +-
 .../apache/cordova/CordovaWebViewClient.java    |   2 +-
 .../cordova/IceCreamCordovaWebViewClient.java   |  61 ++--
 .../src/org/apache/cordova/PluginManager.java   |   6 +-
 .../src/org/apache/cordova/UriResolver.java     |  69 ----
 .../src/org/apache/cordova/UriResolvers.java    | 341 ------------------
 test/AndroidManifest.xml                        |   2 +-
 .../apache/cordova/test/UriResolversTest.java   | 263 --------------
 10 files changed, 393 insertions(+), 743 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8b3fa5c9/framework/src/org/apache/cordova/CordovaPlugin.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaPlugin.java b/framework/src/org/apache/cordova/CordovaPlugin.java
index 22c8703..e947fcc 100644
--- a/framework/src/org/apache/cordova/CordovaPlugin.java
+++ b/framework/src/org/apache/cordova/CordovaPlugin.java
@@ -22,7 +22,6 @@ import org.apache.cordova.CordovaArgs;
 import org.apache.cordova.CordovaWebView;
 import org.apache.cordova.api.CordovaInterface;
 import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.UriResolver;
 import org.json.JSONArray;
 import org.json.JSONException;
 
@@ -165,13 +164,12 @@ public class CordovaPlugin {
     }
 
     /**
-     * Hook for overriding the default URI handling mechanism.
-     * Applies to WebView requests as well as requests made by plugins.
+     * Hook for redirecting requests. Applies to WebView requests as well as requests made by plugins.
      */
-    public UriResolver resolveUri(Uri uri) {
+    public Uri remapUri(Uri uri) {
         return null;
     }
-
+    
     /**
      * Called when the WebView does a top-level navigation or refreshes.
      *

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8b3fa5c9/framework/src/org/apache/cordova/CordovaResourceApi.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaResourceApi.java b/framework/src/org/apache/cordova/CordovaResourceApi.java
new file mode 100644
index 0000000..b891b51
--- /dev/null
+++ b/framework/src/org/apache/cordova/CordovaResourceApi.java
@@ -0,0 +1,347 @@
+/*
+       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.content.ContentResolver;
+import android.content.Context;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.AssetManager;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Looper;
+import android.util.Base64;
+import android.util.Base64InputStream;
+
+import com.squareup.okhttp.OkHttpClient;
+
+import org.apache.http.util.EncodingUtils;
+
+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.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.channels.FileChannel;
+
+public class CordovaResourceApi {
+    @SuppressWarnings("unused")
+    private static final String LOG_TAG = "CordovaResourceApi";
+
+    public static final int URI_TYPE_FILE = 0;
+    public static final int URI_TYPE_ASSET = 1;
+    public static final int URI_TYPE_CONTENT = 2;
+    public static final int URI_TYPE_RESOURCE = 3;
+    public static final int URI_TYPE_DATA = 4;
+    public static final int URI_TYPE_HTTP = 5;
+    public static final int URI_TYPE_HTTPS = 6;
+    public static final int URI_TYPE_UNKNOWN = -1;
+    
+    private static final String[] LOCAL_FILE_PROJECTION = { "_data" };
+    
+    // Creating this is light-weight.
+    private static OkHttpClient httpClient = new OkHttpClient();
+    
+    static Thread webCoreThread;
+
+    private final AssetManager assetManager;
+    private final ContentResolver contentResolver;
+    private final PluginManager pluginManager;
+    private boolean threadCheckingEnabled = true;
+
+
+    public CordovaResourceApi(Context context, PluginManager pluginManager) {
+        this.contentResolver = context.getContentResolver();
+        this.assetManager = context.getAssets();
+        this.pluginManager = pluginManager;
+    }
+    
+    public void setThreadCheckingEnabled(boolean value) {
+        threadCheckingEnabled = value;
+    }
+
+    public boolean isThreadCheckingEnabled() {
+        return threadCheckingEnabled;
+    }
+    
+    public static int getUriType(Uri uri) {
+        assertNonRelative(uri);
+        String scheme = uri.getScheme();
+        if (ContentResolver.SCHEME_CONTENT.equals(scheme)) {
+            return URI_TYPE_CONTENT;
+        }
+        if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
+            return URI_TYPE_RESOURCE;
+        }
+        if (ContentResolver.SCHEME_FILE.equals(scheme)) {
+            if (uri.getPath().startsWith("/android_asset/")) {
+                return URI_TYPE_ASSET;
+            }
+            return URI_TYPE_FILE;
+        }
+        if ("data".equals(scheme)) {
+            return URI_TYPE_DATA;
+        }
+        if ("http".equals(scheme)) {
+            return URI_TYPE_HTTP;
+        }
+        if ("https".equals(scheme)) {
+            return URI_TYPE_HTTPS;
+        }
+        return URI_TYPE_UNKNOWN;
+    }
+    
+    public Uri remapUri(Uri uri) {
+        assertNonRelative(uri);
+        Uri pluginUri = pluginManager.remapUri(uri);
+        return pluginUri != null ? pluginUri : uri;
+    }
+
+    public String remapPath(String path) {
+        return remapUri(Uri.fromFile(new File(path))).getPath();
+    }
+    
+    /**
+     * Returns a File that points to the resource, or null if the resource
+     * is not on the local filesystem.
+     */
+    public File mapUriToFile(Uri uri) {
+        assertBackgroundThread();
+        switch (getUriType(uri)) {
+            case URI_TYPE_FILE:
+                return new File(uri.getPath());
+            case URI_TYPE_CONTENT: {
+                Cursor cursor = contentResolver.query(uri, LOCAL_FILE_PROJECTION, null, null, null);
+                if (cursor != null) {
+                    try {
+                        int columnIndex = cursor.getColumnIndex(LOCAL_FILE_PROJECTION[0]);
+                        if (columnIndex != -1 && cursor.getCount() > 0) {
+                            cursor.moveToFirst();
+                            String realPath = cursor.getString(columnIndex);
+                            if (realPath != null) {
+                                return new File(realPath);
+                            }
+                        }
+                    } finally {
+                        cursor.close();
+                    }
+                }
+            }
+        }
+        return null;
+    }
+    
+    /**
+     * Opens a stream to the givne URI, also providing the MIME type & length.
+     * @return Never returns null.
+     * @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be
+     *     resolved before being passed into this function.
+     * @throws Throws an IOException if the URI cannot be opened.
+     */
+    public OpenForReadResult openForRead(Uri uri) throws IOException {
+        assertBackgroundThread();
+        switch (getUriType(uri)) {
+            case URI_TYPE_FILE: {
+                FileInputStream inputStream = new FileInputStream(uri.getPath());
+                String mimeType = FileHelper.getMimeTypeForExtension(uri.getPath());
+                long length = inputStream.getChannel().size();
+                return new OpenForReadResult(uri, inputStream, mimeType, length, null);
+            }
+            case URI_TYPE_ASSET: {
+                String assetPath = uri.getPath().substring(15);
+                AssetFileDescriptor assetFd = null;
+                InputStream inputStream;
+                long length = -1;
+                try {
+                    assetFd = assetManager.openFd(assetPath);
+                    inputStream = assetFd.createInputStream();
+                    length = assetFd.getLength();
+                } catch (FileNotFoundException e) {
+                    // Will occur if the file is compressed.
+                    inputStream = assetManager.open(assetPath);
+                }
+                String mimeType = FileHelper.getMimeTypeForExtension(assetPath);
+                return new OpenForReadResult(uri, inputStream, mimeType, length, assetFd);
+            }
+            case URI_TYPE_CONTENT:
+            case URI_TYPE_RESOURCE: {
+                String mimeType = contentResolver.getType(uri);
+                AssetFileDescriptor assetFd = contentResolver.openAssetFileDescriptor(uri, "r");
+                InputStream inputStream = assetFd.createInputStream();
+                long length = assetFd.getLength();
+                return new OpenForReadResult(uri, inputStream, mimeType, length, assetFd);
+            }
+            case URI_TYPE_DATA: {
+                OpenForReadResult ret = readDataUri(uri);
+                if (ret == null) {
+                    break;
+                }
+                return ret;
+            }
+            case URI_TYPE_HTTP:
+            case URI_TYPE_HTTPS: {
+                HttpURLConnection conn = httpClient.open(new URL(uri.toString()));
+                conn.setDoInput(true);
+                String mimeType = conn.getHeaderField("Content-Type");
+                int length = conn.getContentLength();
+                InputStream inputStream = conn.getInputStream();
+                return new OpenForReadResult(uri, inputStream, mimeType, length, null);
+            }
+        }
+        throw new FileNotFoundException("URI not supported by CordovaResourceApi: " + uri);
+    }
+
+    public OutputStream openOutputStream(Uri uri) throws IOException {
+        return openOutputStream(uri, false);
+    }
+
+    /**
+     * Opens a stream to the given URI.
+     * @return Never returns null.
+     * @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be
+     *     resolved before being passed into this function.
+     * @throws Throws an IOException if the URI cannot be opened.
+     */
+    public OutputStream openOutputStream(Uri uri, boolean append) throws IOException {
+        assertBackgroundThread();
+        switch (getUriType(uri)) {
+            case URI_TYPE_FILE: {
+                File localFile = new File(uri.getPath());
+                File parent = localFile.getParentFile();
+                if (parent != null) {
+                    parent.mkdirs();
+                }
+                return new FileOutputStream(localFile, append);
+            }
+            case URI_TYPE_CONTENT:
+            case URI_TYPE_RESOURCE: {
+                AssetFileDescriptor assetFd = contentResolver.openAssetFileDescriptor(uri, append ? "wa" : "w");
+                return assetFd.createOutputStream();
+            }
+        }
+        throw new FileNotFoundException("URI not supported by CordovaResourceApi: " + uri);
+    }
+    
+    public HttpURLConnection createHttpConnection(Uri uri) throws IOException {
+        assertBackgroundThread();
+        return httpClient.open(new URL(uri.toString()));
+    }
+    
+    // Copies the input to the output in the most efficient manner possible.
+    // Closes both streams.
+    public void copyResource(OpenForReadResult input, OutputStream outputStream) throws IOException {
+        assertBackgroundThread();
+        try {
+            InputStream inputStream = input.inputStream;
+            if (inputStream instanceof FileInputStream && outputStream instanceof FileOutputStream) {
+                FileChannel inChannel = ((FileInputStream)input.inputStream).getChannel();
+                FileChannel outChannel = ((FileOutputStream)outputStream).getChannel();
+                long offset = 0;
+                long length = input.length;
+                if (input.assetFd != null) {
+                    offset = input.assetFd.getStartOffset();
+                }
+                outChannel.transferFrom(inChannel, offset, length);
+            } else {
+                final int BUFFER_SIZE = 8192;
+                byte[] buffer = new byte[BUFFER_SIZE];
+                
+                for (;;) {
+                    int bytesRead = inputStream.read(buffer, 0, BUFFER_SIZE);
+                    
+                    if (bytesRead <= 0) {
+                        break;
+                    }
+                    outputStream.write(buffer, 0, bytesRead);
+                }
+            }            
+        } finally {
+            input.inputStream.close();
+            if (outputStream != null) {
+                outputStream.close();
+            }
+        }
+    }
+
+    public void copyResource(Uri sourceUri, OutputStream outputStream) throws IOException {
+        copyResource(openForRead(sourceUri), outputStream);
+    }
+
+    
+    private void assertBackgroundThread() {
+        if (threadCheckingEnabled) {
+            Thread curThread = Thread.currentThread();
+            if (curThread == Looper.getMainLooper().getThread()) {
+                throw new IllegalStateException("Do not perform IO operations on the UI thread. Use CordovaInterface.getThreadPool() instead.");
+            }
+            if (curThread == webCoreThread) {
+                throw new IllegalStateException("Tried to perform an IO operation on the WebCore thread. Use CordovaInterface.getThreadPool() instead.");
+            }
+        }
+    }
+    
+    private OpenForReadResult readDataUri(Uri uri) {
+        String uriAsString = uri.toString().substring(5);
+        int commaPos = uriAsString.indexOf(',');
+        if (commaPos == -1) {
+            return null;
+        }
+        String[] mimeParts = uriAsString.substring(0, commaPos).split(";");
+        String contentType = null;
+        boolean base64 = false;
+        if (mimeParts.length > 0) {
+            contentType = mimeParts[0];
+        }
+        for (int i = 1; i < mimeParts.length; ++i) {
+            if ("base64".equalsIgnoreCase(mimeParts[i])) {
+                base64 = true;
+            }
+        }
+        String dataPartAsString = uriAsString.substring(commaPos + 1);
+        byte[] data = base64 ? Base64.decode(dataPartAsString, Base64.DEFAULT) : EncodingUtils.getBytes(dataPartAsString, "UTF-8");
+        InputStream inputStream = new ByteArrayInputStream(data);
+        return new OpenForReadResult(uri, inputStream, contentType, data.length, null);
+    }
+    
+    private static void assertNonRelative(Uri uri) {
+        if (!uri.isAbsolute()) {
+            throw new IllegalArgumentException("Relative URIs are not supported.");
+        }
+    }
+    
+    public static final class OpenForReadResult {
+        public final Uri uri;
+        public final InputStream inputStream;
+        public final String mimeType;
+        public final long length;
+        public final AssetFileDescriptor assetFd;
+        
+        OpenForReadResult(Uri uri, InputStream inputStream, String mimeType, long length, AssetFileDescriptor assetFd) {
+            this.uri = uri;
+            this.inputStream = inputStream;
+            this.mimeType = mimeType;
+            this.length = length;
+            this.assetFd = assetFd;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8b3fa5c9/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 648b1f8..b97b03e 100755
--- a/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/framework/src/org/apache/cordova/CordovaWebView.java
@@ -97,6 +97,8 @@ public class CordovaWebView extends WebView {
 
     private ActivityResult mResult = null;
 
+    private CordovaResourceApi resourceApi;
+
     class ActivityResult {
         
         int request;
@@ -307,6 +309,7 @@ public class CordovaWebView extends WebView {
         pluginManager = new PluginManager(this, this.cordova);
         jsMessageQueue = new NativeToJsMessageQueue(this, cordova);
         exposedJsApi = new ExposedJsApi(pluginManager, jsMessageQueue);
+        resourceApi = new CordovaResourceApi(this.getContext(), pluginManager);
         exposeJsInterface();
     }
 
@@ -957,37 +960,7 @@ public class CordovaWebView extends WebView {
         mResult = new ActivityResult(requestCode, resultCode, intent);
     }
     
-    /**
-     * Resolves the given URI, giving plugins a chance to re-route or customly handle the URI.
-     * A white-list rejection will be returned if the URI does not pass the white-list.
-     * @return Never returns null.
-     * @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be
-     *     resolved before being passed into this function.
-     */
-    public UriResolver resolveUri(Uri uri) {
-        return resolveUri(uri, false);
-    }
-    
-    UriResolver resolveUri(Uri uri, boolean fromWebView) {
-        if (!uri.isAbsolute()) {
-            throw new IllegalArgumentException("Relative URIs are not yet supported by resolveUri.");
-        }
-        UriResolver ret = null;
-        // Check the against the white-list before delegating to plugins.
-        if (("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) && !Config.isUrlWhiteListed(uri.toString()))
-        {
-            LOG.w(TAG, "resolveUri - URL is not in whitelist: " + uri);
-            ret = UriResolvers.createError("Whitelist rejection for: " + uri);
-        } else {
-            // Give plugins a chance to handle the request.
-            ret = ((org.apache.cordova.PluginManager)pluginManager).resolveUri(uri);
-        }
-        if (ret == null && !fromWebView) {
-            ret = UriResolvers.forUri(uri, cordova.getActivity());
-            if (ret == null) {
-                ret = UriResolvers.createError("Unresolvable URI: " + uri);
-            }
-        }
-        return ret == null ? null : UriResolvers.makeThreadChecking(ret);
+    public CordovaResourceApi getResourceApi() {
+        return resourceApi;
     }
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8b3fa5c9/framework/src/org/apache/cordova/CordovaWebViewClient.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaWebViewClient.java b/framework/src/org/apache/cordova/CordovaWebViewClient.java
index c49611e..d782aa0 100755
--- a/framework/src/org/apache/cordova/CordovaWebViewClient.java
+++ b/framework/src/org/apache/cordova/CordovaWebViewClient.java
@@ -48,7 +48,7 @@ import android.webkit.WebViewClient;
  */
 public class CordovaWebViewClient extends WebViewClient {
 
-	private static final String TAG = "Cordova";
+	private static final String TAG = "CordovaWebViewClient";
 	private static final String CORDOVA_EXEC_URL_PREFIX = "http://cdv_exec/";
     CordovaInterface cordova;
     CordovaWebView appView;

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8b3fa5c9/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 c23d580..317acc2 100644
--- a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
+++ b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
@@ -19,20 +19,22 @@
 package org.apache.cordova;
 
 import java.io.IOException;
-import java.io.InputStream;
 
+import org.apache.cordova.CordovaResourceApi.OpenForReadResult;
 import org.apache.cordova.api.CordovaInterface;
 import org.apache.cordova.api.LOG;
 
 import android.annotation.TargetApi;
 import android.net.Uri;
 import android.os.Build;
+import android.util.Log;
 import android.webkit.WebResourceResponse;
 import android.webkit.WebView;
 
 @TargetApi(Build.VERSION_CODES.HONEYCOMB)
 public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
 
+    private static final String TAG = "IceCreamCordovaWebViewClient";
 
     public IceCreamCordovaWebViewClient(CordovaInterface cordova) {
         super(cordova);
@@ -44,38 +46,44 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
 
     @Override
     public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
-        // Disable checks during shouldInterceptRequest since there is no way to avoid IO here :(.
-        UriResolvers.webCoreThread = null;
+        // Tell the Thread-Checking resolve what thread the WebCore thread is.
+        CordovaResourceApi.webCoreThread = Thread.currentThread();
+        Log.e("WHAAAA", "FOOD " + CordovaResourceApi.webCoreThread);
         try {
-            UriResolver uriResolver = appView.resolveUri(Uri.parse(url), true);
-            
-            if (uriResolver == null && url.startsWith("file:///android_asset/")) {
-                if (url.contains("?") || url.contains("#") || needsIceCreamSpecialsInAssetUrlFix(url)) {
-                    uriResolver = appView.resolveUri(Uri.parse(url), false);
-                }
+            // Check the against the white-list.
+            if ((url.startsWith("http:") || url.startsWith("https:")) && !Config.isUrlWhiteListed(url)) {
+                LOG.w(TAG, "URL blocked by whitelist: " + url);
+                // Results in a 404.
+                return new WebResourceResponse("text/plain", "UTF-8", null);
             }
+
+            CordovaResourceApi resourceApi = appView.getResourceApi();
+            Uri origUri = Uri.parse(url);
+            // Allow plugins to intercept WebView requests.
+            Uri remappedUri = resourceApi.remapUri(origUri);
             
-            if (uriResolver != null) {
-                try {
-                    InputStream stream = uriResolver.getInputStream();
-                    String mimeType = uriResolver.getMimeType();
-                    // If we don't know how to open this file, let the browser continue loading
-                    return new WebResourceResponse(mimeType, "UTF-8", stream);
-                } catch (IOException e) {
-                    LOG.e("IceCreamCordovaWebViewClient", "Error occurred while loading a file.", e);
-                    // Results in a 404.
-                    return new WebResourceResponse("text/plain", "UTF-8", null);
-                }
+            if (!origUri.equals(remappedUri) || needsSpecialsInAssetUrlFix(origUri)) {
+                OpenForReadResult result = resourceApi.openForRead(remappedUri);
+                return new WebResourceResponse(result.mimeType, "UTF-8", result.inputStream);
             }
+            // If we don't need to special-case the request, let the browser load it.
             return null;
-        } finally {
-            // Tell the Thread-Checking resolve what thread the WebCore thread is.
-            UriResolvers.webCoreThread = Thread.currentThread();
+        } catch (IOException e) {
+            LOG.e("IceCreamCordovaWebViewClient", "Error occurred while loading a file.", e);
+            // Results in a 404.
+            return new WebResourceResponse("text/plain", "UTF-8", null);
         }
     }
+
+    private static boolean needsSpecialsInAssetUrlFix(Uri uri) {
+        if (CordovaResourceApi.getUriType(uri) != CordovaResourceApi.URI_TYPE_ASSET) {
+            return false;
+        }
+        if (uri.getQuery() != null || uri.getFragment() != null) {
+            return true;
+        }
         
-    private static boolean needsIceCreamSpecialsInAssetUrlFix(String url) {
-        if (!url.contains("%20")){
+        if (!uri.toString().contains("%")) {
             return false;
         }
 
@@ -83,8 +91,7 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
             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 false;
     }
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8b3fa5c9/framework/src/org/apache/cordova/PluginManager.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/PluginManager.java b/framework/src/org/apache/cordova/PluginManager.java
index 1f32ba6..2db9d56 100755
--- a/framework/src/org/apache/cordova/PluginManager.java
+++ b/framework/src/org/apache/cordova/PluginManager.java
@@ -26,7 +26,6 @@ import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.cordova.CordovaArgs;
 import org.apache.cordova.CordovaWebView;
-import org.apache.cordova.UriResolver;
 import org.apache.cordova.api.CallbackContext;
 import org.apache.cordova.api.CordovaInterface;
 import org.apache.cordova.api.CordovaPlugin;
@@ -40,7 +39,6 @@ import android.content.res.XmlResourceParser;
 
 import android.net.Uri;
 import android.util.Log;
-import android.webkit.WebResourceResponse;
 
 /**
  * PluginManager is exposed to JavaScript in the Cordova WebView.
@@ -407,10 +405,10 @@ public class PluginManager {
         LOG.e(TAG, "=====================================================================================");
     }
 
-    UriResolver resolveUri(Uri uri) {
+    Uri remapUri(Uri uri) {
         for (PluginEntry entry : this.entries.values()) {
             if (entry.plugin != null) {
-                UriResolver ret = entry.plugin.resolveUri(uri);
+                Uri ret = entry.plugin.remapUri(uri);
                 if (ret != null) {
                     return ret;
                 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8b3fa5c9/framework/src/org/apache/cordova/UriResolver.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/UriResolver.java b/framework/src/org/apache/cordova/UriResolver.java
deleted file mode 100644
index b3bfa4d..0000000
--- a/framework/src/org/apache/cordova/UriResolver.java
+++ /dev/null
@@ -1,69 +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.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-/*
- * Interface for a class that can resolve URIs.
- * See CordovaUriResolver for an example.
- */
-public abstract class UriResolver {
-
-    /** 
-     * Returns the InputStream for the resource. 
-     * Throws an exception if it cannot be read. 
-     * Never returns null.
-     */
-    public abstract InputStream getInputStream() throws IOException;
-
-    /** 
-     * Returns the MIME type of the resource.
-     * Returns null if the MIME type cannot be determined (e.g. content: that doesn't exist).
-     */
-    public abstract String getMimeType();
-
-    /** Returns whether the resource is writable. */
-    public abstract boolean isWritable();
-
-    /**
-     * Returns a File that points to the resource, or null if the resource
-     * is not on the local file system.
-     */
-    public abstract File getLocalFile();
-
-    /** 
-     * Returns the OutputStream for the resource. 
-     * Throws an exception if it cannot be written to. 
-     * Never returns null.
-     */
-    public OutputStream getOutputStream() throws IOException {
-        throw new IOException("Writing is not suppported");
-    }
-    
-    /**
-     * Returns the length of the input stream, or -1 if it is not computable.
-     */
-    public long computeLength() throws IOException {
-        return -1;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8b3fa5c9/framework/src/org/apache/cordova/UriResolvers.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/UriResolvers.java b/framework/src/org/apache/cordova/UriResolvers.java
deleted file mode 100644
index 294fc6b..0000000
--- a/framework/src/org/apache/cordova/UriResolvers.java
+++ /dev/null
@@ -1,341 +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.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.OutputStream;
-
-import org.apache.cordova.FileHelper;
-import org.apache.http.util.EncodingUtils;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.res.AssetManager;
-import android.net.Uri;
-import android.os.Looper;
-
-/*
- * UriResolver implementations.
- */
-public final class UriResolvers {
-    static Thread webCoreThread;
-
-    private UriResolvers() {}
-
-    private static long computeSizeFromResolver(UriResolver resolver) throws IOException {
-        InputStream inputStream = resolver.getInputStream();
-        if (inputStream instanceof FileInputStream) {
-            return ((FileInputStream)inputStream).getChannel().size();
-        }
-        if (inputStream instanceof ByteArrayInputStream) {
-            return ((ByteArrayInputStream)inputStream).available();
-        }
-        return -1;
-    }
-    
-    private static final class FileUriResolver extends UriResolver {
-        private final File localFile;
-        private String mimeType;
-        private FileInputStream cachedInputStream;
-    
-        FileUriResolver(Uri uri) {
-            localFile = new File(uri.getPath());
-        }
-        
-        public InputStream getInputStream() throws IOException {
-            if (cachedInputStream == null) {
-                cachedInputStream = new FileInputStream(localFile);
-            }
-            return cachedInputStream;
-        }
-        
-        public OutputStream getOutputStream() throws FileNotFoundException {
-            File parent = localFile.getParentFile();
-            if (parent != null) {
-                localFile.getParentFile().mkdirs();
-            }
-            return new FileOutputStream(localFile);
-        }
-        
-        public String getMimeType() {
-            if (mimeType == null) {
-                mimeType = FileHelper.getMimeTypeForExtension(localFile.getName());
-            }
-            return mimeType;
-        }
-        
-        public boolean isWritable() {
-            if (localFile.isDirectory()) {
-                return false;
-            }
-            if (localFile.exists()) {
-                return localFile.canWrite();
-            }
-            return localFile.getParentFile().canWrite();
-        }
-        
-        public File getLocalFile() {
-            return localFile;
-        }
-        
-        public long computeLength() throws IOException {
-            return localFile.length();
-        }
-    }
-    
-    private static final class AssetUriResolver extends UriResolver {
-        private final AssetManager assetManager;
-        private final String assetPath;
-        private String mimeType;
-        private InputStream cachedInputStream;
-    
-        AssetUriResolver(Uri uri, AssetManager assetManager) {
-            this.assetManager = assetManager;
-            this.assetPath = uri.getPath().substring(15);
-        }
-        
-        public InputStream getInputStream() throws IOException {
-            if (cachedInputStream == null) {
-                cachedInputStream = assetManager.open(assetPath);
-            }
-            return cachedInputStream;
-        }
-        
-        public OutputStream getOutputStream() throws FileNotFoundException {
-            throw new FileNotFoundException("URI not writable.");
-        }
-        
-        public String getMimeType() {
-            if (mimeType == null) {
-                mimeType = FileHelper.getMimeTypeForExtension(assetPath);
-            }
-            return mimeType;
-        }
-        
-        public boolean isWritable() {
-            return false;
-        }
-        
-        public File getLocalFile() {
-            return null;
-        }
-
-        public long computeLength() throws IOException {
-            return computeSizeFromResolver(this);
-        }
-    }
-    
-    private static final class ContentUriResolver extends UriResolver {
-        private final Uri uri;
-        private final ContentResolver contentResolver;
-        private String mimeType;
-        private InputStream cachedInputStream;
-    
-        ContentUriResolver(Uri uri, ContentResolver contentResolver) {
-            this.uri = uri;
-            this.contentResolver = contentResolver;
-        }
-        
-        public InputStream getInputStream() throws IOException {
-            if (cachedInputStream == null) {
-                cachedInputStream = contentResolver.openInputStream(uri);
-            }
-            return cachedInputStream;
-        }
-        
-        public OutputStream getOutputStream() throws FileNotFoundException {
-            return contentResolver.openOutputStream(uri);
-        }
-        
-        public String getMimeType() {
-            if (mimeType == null) {
-                mimeType = contentResolver.getType(uri);
-            }
-            return mimeType;
-        }
-        
-        public boolean isWritable() {
-            return uri.getScheme().equals(ContentResolver.SCHEME_CONTENT);
-        }
-        
-        public File getLocalFile() {
-            return null;
-        }
-        
-        public long computeLength() throws IOException {
-            return computeSizeFromResolver(this);
-        }
-    }
-    
-    private static final class ErrorUriResolver extends UriResolver {
-        final String errorMsg;
-        
-        ErrorUriResolver(String errorMsg) {
-            this.errorMsg = errorMsg;
-        }
-        
-        public boolean isWritable() {
-            return false;
-        }
-        
-        public File getLocalFile() {
-            return null;
-        }
-        
-        public OutputStream getOutputStream() throws IOException {
-            throw new FileNotFoundException(errorMsg);
-        }
-        
-        public String getMimeType() {
-            return null;
-        }
-        
-        public InputStream getInputStream() throws IOException {
-            throw new FileNotFoundException(errorMsg);
-        }
-    }
-    
-    private static final class ReadOnlyResolver extends UriResolver {
-        private InputStream inputStream;
-        private String mimeType;
-        
-        public ReadOnlyResolver(Uri uri, InputStream inputStream, String mimeType) {
-            this.inputStream = inputStream;
-            this.mimeType = mimeType;
-        }
-        
-        public boolean isWritable() {
-            return false;
-        }
-        
-        public File getLocalFile() {
-            return null;
-        }
-        
-        public OutputStream getOutputStream() throws IOException {
-            throw new FileNotFoundException("URI is not writable");
-        }
-        
-        public String getMimeType() {
-            return mimeType;
-        }
-        
-        public InputStream getInputStream() throws IOException {
-            return inputStream;
-        }
-        
-        public long computeLength() throws IOException {
-            return computeSizeFromResolver(this);
-        }
-    }
-    
-    private static final class ThreadCheckingResolver extends UriResolver {
-        final UriResolver delegate;
-        
-        ThreadCheckingResolver(UriResolver delegate) {
-            this.delegate = delegate;
-        }
-
-        private static void checkThread() {
-            Thread curThread = Thread.currentThread();
-            if (curThread == Looper.getMainLooper().getThread()) {
-                throw new IllegalStateException("Do not perform IO operations on the UI thread. Use CordovaInterface.getThreadPool() instead.");
-            }
-            if (curThread == webCoreThread) {
-                throw new IllegalStateException("Tried to perform an IO operation on the WebCore thread. Use CordovaInterface.getThreadPool() instead.");
-            }
-        }
-        
-        public boolean isWritable() {
-            checkThread();
-            return delegate.isWritable();
-        }
-        
-
-        public File getLocalFile() {
-            checkThread();
-            return delegate.getLocalFile();
-        }
-        
-        public OutputStream getOutputStream() throws IOException {
-            checkThread();
-            return delegate.getOutputStream();
-        }
-        
-        public String getMimeType() {
-            checkThread();
-            return delegate.getMimeType();
-        }
-        
-        public InputStream getInputStream() throws IOException {
-            checkThread();
-            return delegate.getInputStream();
-        }
-        
-        public long computeLength() throws IOException {
-            checkThread();
-            return delegate.computeLength();
-        }
-    }
-    
-    public static UriResolver createInline(Uri uri, String response, String mimeType) {
-        return createInline(uri, EncodingUtils.getBytes(response, "UTF-8"), mimeType);
-    }
-    
-    public static UriResolver createInline(Uri uri, byte[] response, String mimeType) {
-        return new ReadOnlyResolver(uri, new ByteArrayInputStream(response), mimeType);
-    }
-
-    public static UriResolver createReadOnly(Uri uri, InputStream inputStream, String mimeType) {
-        return new ReadOnlyResolver(uri, inputStream, mimeType);
-    }
-    
-    public static UriResolver createError(String errorMsg) {
-        return new ErrorUriResolver(errorMsg);
-    }
-    
-    /* Package-private to force clients to go through CordovaWebView.resolveUri(). */
-    static UriResolver forUri(Uri uri, Context context) {
-        String scheme = uri.getScheme();
-        if (ContentResolver.SCHEME_CONTENT.equals(scheme) || ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
-            return new ContentUriResolver(uri, context.getContentResolver());
-        }
-        if (ContentResolver.SCHEME_FILE.equals(scheme)) {
-            if (uri.getPath().startsWith("/android_asset/")) {
-                return new AssetUriResolver(uri, context.getAssets());
-            }
-            return new FileUriResolver(uri);
-        }
-        return null;
-    }
-    
-    /* Used only by CordovaWebView.resolveUri(). */
-    static UriResolver makeThreadChecking(UriResolver resolver) {
-        if (resolver instanceof ThreadCheckingResolver) {
-            return resolver;
-        }
-        return new ThreadCheckingResolver(resolver);
-    }
-}

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8b3fa5c9/test/AndroidManifest.xml
----------------------------------------------------------------------
diff --git a/test/AndroidManifest.xml b/test/AndroidManifest.xml
index f6c840e..04ef3c6 100755
--- a/test/AndroidManifest.xml
+++ b/test/AndroidManifest.xml
@@ -45,7 +45,7 @@
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
    
-    <uses-sdk android:minSdkVersion="7" />
+    <uses-sdk android:minSdkVersion="8" />
 
     <instrumentation
         android:name="android.test.InstrumentationTestRunner"

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/8b3fa5c9/test/src/org/apache/cordova/test/UriResolversTest.java
----------------------------------------------------------------------
diff --git a/test/src/org/apache/cordova/test/UriResolversTest.java b/test/src/org/apache/cordova/test/UriResolversTest.java
deleted file mode 100644
index 21584b9..0000000
--- a/test/src/org/apache/cordova/test/UriResolversTest.java
+++ /dev/null
@@ -1,263 +0,0 @@
-
-package org.apache.cordova.test;
-
-/*
- *
- * 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.
- *
- */
-
-import org.apache.cordova.CordovaWebView;
-import org.apache.cordova.UriResolver;
-import org.apache.cordova.UriResolvers;
-import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
-import org.apache.cordova.api.PluginEntry;
-import org.apache.cordova.test.actions.CordovaWebViewTestActivity;
-import org.json.JSONArray;
-import org.json.JSONException;
-
-import java.io.File;
-import java.io.IOException;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.net.Uri;
-import android.os.Environment;
-import android.provider.MediaStore;
-import android.test.ActivityInstrumentationTestCase2;
-import android.util.Log;
-
-public class UriResolversTest extends ActivityInstrumentationTestCase2<CordovaWebViewTestActivity> {
-
-    public UriResolversTest()
-    {
-        super(CordovaWebViewTestActivity.class);
-    }
-
-    CordovaWebView cordovaWebView;
-    private CordovaWebViewTestActivity activity;
-    String execPayload;
-    Integer execStatus;
-
-    protected void setUp() throws Exception {
-        super.setUp();
-        activity = this.getActivity();
-        cordovaWebView = activity.cordovaWebView;
-        cordovaWebView.pluginManager.addService(new PluginEntry("UriResolverTestPlugin1", new CordovaPlugin() {
-            @Override
-            public UriResolver resolveUri(Uri uri) {
-                if ("plugin-uri".equals(uri.getScheme())) {
-                    return cordovaWebView.resolveUri(uri.buildUpon().scheme("file").build());
-                }
-                return null;
-            }
-            public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
-                synchronized (UriResolversTest.this) {
-                    execPayload = args.getString(0);
-                    execStatus = args.getInt(1);
-                    UriResolversTest.this.notify();
-                }
-                return true;
-            }
-        }));
-        cordovaWebView.pluginManager.addService(new PluginEntry("UriResolverTestPlugin2", new CordovaPlugin() {
-            @Override
-            public UriResolver resolveUri(Uri uri) {
-                if (uri.getQueryParameter("pluginRewrite") != null) {
-                    return UriResolvers.createInline(uri, "pass", "my/mime");
-                }
-                return null;
-            }
-        }));
-    }
-
-    private Uri createTestImageContentUri() {
-        Bitmap imageBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.icon);
-        String stored = MediaStore.Images.Media.insertImage(activity.getContentResolver(),
-                imageBitmap, "app-icon", "desc");
-        return Uri.parse(stored);
-    }
-
-    private void performResolverTest(Uri uri, String expectedMimeType, File expectedLocalFile,
-            boolean expectedIsWritable,
-            boolean expectRead, boolean expectWrite) throws IOException {
-        UriResolver resolver = cordovaWebView.resolveUri(uri);
-        assertEquals(expectedLocalFile, resolver.getLocalFile());
-        assertEquals(expectedMimeType, resolver.getMimeType());
-        if (expectedIsWritable) {
-            assertTrue(resolver.isWritable());
-        } else {
-            assertFalse(resolver.isWritable());
-        }
-        try {
-            resolver.getInputStream().read();
-            if (!expectRead) {
-                fail("Expected getInputStream to throw.");
-            }
-        } catch (IOException e) {
-            if (expectRead) {
-                throw e;
-            }
-        }
-        try {
-            resolver.getOutputStream().write(123);
-            if (!expectWrite) {
-                fail("Expected getOutputStream to throw.");
-            }
-        } catch (IOException e) {
-            if (expectWrite) {
-                throw e;
-            }
-        }
-    }
-
-    public void testValidContentUri() throws IOException
-    {
-        Uri contentUri = createTestImageContentUri();
-        performResolverTest(contentUri, "image/jpeg", null, true, true, true);
-    }
-
-    public void testInvalidContentUri() throws IOException
-    {
-        Uri contentUri = Uri.parse("content://media/external/images/media/999999999");
-        performResolverTest(contentUri, null, null, true, false, false);
-    }
-
-    public void testValidAssetUri() throws IOException
-    {
-        Uri assetUri = Uri.parse("file:///android_asset/www/index.html?foo#bar"); // Also check for stripping off ? and # correctly.
-        performResolverTest(assetUri, "text/html", null, false, true, false);
-    }
-
-    public void testInvalidAssetUri() throws IOException
-    {
-        Uri assetUri = Uri.parse("file:///android_asset/www/missing.html");
-        performResolverTest(assetUri, "text/html", null, false, false, false);
-    }
-
-    public void testFileUriToExistingFile() throws IOException
-    {
-        File f = File.createTempFile("te s t", ".txt"); // Also check for dealing with spaces.
-        try {
-            Uri fileUri = Uri.parse(f.toURI().toString() + "?foo#bar"); // Also check for stripping off ? and # correctly.
-            performResolverTest(fileUri, "text/plain", f, true, true, true);
-        } finally {
-            f.delete();
-        }
-    }
-
-    public void testFileUriToMissingFile() throws IOException
-    {
-        File f = new File(Environment.getExternalStorageDirectory() + "/somefilethatdoesntexist");
-        Uri fileUri = Uri.parse(f.toURI().toString());
-        try {
-            performResolverTest(fileUri, null, f, true, false, true);
-        } finally {
-            f.delete();
-        }
-    }
-    
-    public void testFileUriToMissingFileWithMissingParent() throws IOException
-    {
-        File f = new File(Environment.getExternalStorageDirectory() + "/somedirthatismissing/somefilethatdoesntexist");
-        Uri fileUri = Uri.parse(f.toURI().toString());
-        performResolverTest(fileUri, null, f, false, false, false);
-    }
-
-    public void testUnrecognizedUri() throws IOException
-    {
-        Uri uri = Uri.parse("somescheme://foo");
-        performResolverTest(uri, null, null, false, false, false);
-    }
-
-    public void testRelativeUri()
-    {
-        try {
-            cordovaWebView.resolveUri(Uri.parse("/foo"));
-            fail("Should have thrown for relative URI 1.");
-        } catch (Throwable t) {
-        }
-        try {
-            cordovaWebView.resolveUri(Uri.parse("//foo/bar"));
-            fail("Should have thrown for relative URI 2.");
-        } catch (Throwable t) {
-        }
-        try {
-            cordovaWebView.resolveUri(Uri.parse("foo.png"));
-            fail("Should have thrown for relative URI 3.");
-        } catch (Throwable t) {
-        }
-    }
-    
-    public void testPluginOverrides1() throws IOException
-    {
-        Uri uri = Uri.parse("plugin-uri://foohost/android_asset/www/index.html");
-        performResolverTest(uri, "text/html", null, false, true, false);
-    }
-
-    public void testPluginOverrides2() throws IOException
-    {
-        Uri uri = Uri.parse("plugin-uri://foohost/android_asset/www/index.html?pluginRewrite=yes");
-        performResolverTest(uri, "my/mime", null, false, true, false);
-    }
-
-    public void testWhitelistRejection() throws IOException
-    {
-        Uri uri = Uri.parse("http://foohost.com/");
-        performResolverTest(uri, null, null, false, false, false);
-    }
-    
-    public void testWebViewRequestIntercept() throws IOException
-    {
-        cordovaWebView.sendJavascript(
-            "var x = new XMLHttpRequest;\n" +
-            "x.open('GET', 'file://foo?pluginRewrite=1', false);\n" + 
-            "x.send();\n" + 
-            "cordova.require('cordova/exec')(null,null,'UriResolverTestPlugin1', 'foo', [x.responseText, x.status])");
-        execPayload = null;
-        execStatus = null;
-        try {
-            synchronized (this) {
-                this.wait(2000);
-            }
-        } catch (InterruptedException e) {
-        }
-        assertEquals("pass", execPayload);
-        assertEquals(execStatus.intValue(), 200);
-    }
-    
-    public void testWebViewWhiteListRejection() throws IOException
-    {
-        cordovaWebView.sendJavascript(
-            "var x = new XMLHttpRequest;\n" +
-            "x.open('GET', 'http://foo/bar', false);\n" + 
-            "x.send();\n" + 
-            "cordova.require('cordova/exec')(null,null,'UriResolverTestPlugin1', 'foo', [x.responseText, x.status])");
-        execPayload = null;
-        execStatus = null;
-        try {
-            synchronized (this) {
-                this.wait(2000);
-            }
-        } catch (InterruptedException e) {
-        }
-        assertEquals("", execPayload);
-        assertEquals(execStatus.intValue(), 404);
-    }    
-}


[07/16] android commit: [CB-3384] Fix thread assertion when plugins remap URIs (cherry picked from commit b915aafb5be31912129b04c7e70b9c0a9908ee9c)

Posted by ag...@apache.org.
[CB-3384] Fix thread assertion when plugins remap URIs
(cherry picked from commit b915aafb5be31912129b04c7e70b9c0a9908ee9c)


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

Branch: refs/heads/2.9.x
Commit: 5814d666ab2b0823d1967ef9a859dd0d6a382603
Parents: 53e3a12
Author: Andrew Grieve <ag...@chromium.org>
Authored: Thu Jul 18 01:38:47 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:11:42 2013 -0400

----------------------------------------------------------------------
 .../src/org/apache/cordova/CordovaResourceApi.java | 17 ++++++++++++++++-
 .../cordova/IceCreamCordovaWebViewClient.java      |  2 +-
 2 files changed, 17 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/5814d666/framework/src/org/apache/cordova/CordovaResourceApi.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaResourceApi.java b/framework/src/org/apache/cordova/CordovaResourceApi.java
index ebf8801..cb85744 100644
--- a/framework/src/org/apache/cordova/CordovaResourceApi.java
+++ b/framework/src/org/apache/cordova/CordovaResourceApi.java
@@ -156,9 +156,24 @@ public class CordovaResourceApi {
      * @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be
      *     resolved before being passed into this function.
      * @throws Throws an IOException if the URI cannot be opened.
+     * @throws Throws an IllegalStateException if called on a foreground thread.
      */
     public OpenForReadResult openForRead(Uri uri) throws IOException {
-        assertBackgroundThread();
+        return openForRead(uri, false);
+    }
+
+    /**
+     * Opens a stream to the givne URI, also providing the MIME type & length.
+     * @return Never returns null.
+     * @throws Throws an InvalidArgumentException for relative URIs. Relative URIs should be
+     *     resolved before being passed into this function.
+     * @throws Throws an IOException if the URI cannot be opened.
+     * @throws Throws an IllegalStateException if called on a foreground thread and skipThreadCheck is false.
+     */
+    public OpenForReadResult openForRead(Uri uri, boolean skipThreadCheck) throws IOException {
+        if (!skipThreadCheck) {
+            assertBackgroundThread();
+        }
         switch (getUriType(uri)) {
             case URI_TYPE_FILE: {
                 FileInputStream inputStream = new FileInputStream(uri.getPath());

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/5814d666/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 f0f372c..3f98f56 100644
--- a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
+++ b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
@@ -59,7 +59,7 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
             Uri remappedUri = resourceApi.remapUri(origUri);
             
             if (!origUri.equals(remappedUri) || needsSpecialsInAssetUrlFix(origUri)) {
-                OpenForReadResult result = resourceApi.openForRead(remappedUri);
+                OpenForReadResult result = resourceApi.openForRead(remappedUri, true);
                 return new WebResourceResponse(result.mimeType, "UTF-8", result.inputStream);
             }
             // If we don't need to special-case the request, let the browser load it.


[06/16] android commit: [CB-3384] Use the ExposedJsApi to detect webCore thread instead of IceCreamCordovaWebViewClient.

Posted by ag...@apache.org.
[CB-3384] Use the ExposedJsApi to detect webCore thread instead of IceCreamCordovaWebViewClient.

Also removes a debug log statement.
(cherry picked from commit 6fe18ae0abe137702da2072caa749c83cf326cf5)


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

Branch: refs/heads/2.9.x
Commit: 53e3a124410e8355ba063ab0c4a8c7c0610c1e04
Parents: dd770ef
Author: Andrew Grieve <ag...@chromium.org>
Authored: Tue Jul 16 09:32:29 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:11:15 2013 -0400

----------------------------------------------------------------------
 framework/src/org/apache/cordova/CordovaResourceApi.java        | 5 ++---
 framework/src/org/apache/cordova/ExposedJsApi.java              | 3 +++
 .../src/org/apache/cordova/IceCreamCordovaWebViewClient.java    | 4 ----
 3 files changed, 5 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/53e3a124/framework/src/org/apache/cordova/CordovaResourceApi.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaResourceApi.java b/framework/src/org/apache/cordova/CordovaResourceApi.java
index b891b51..ebf8801 100644
--- a/framework/src/org/apache/cordova/CordovaResourceApi.java
+++ b/framework/src/org/apache/cordova/CordovaResourceApi.java
@@ -26,7 +26,6 @@ import android.database.Cursor;
 import android.net.Uri;
 import android.os.Looper;
 import android.util.Base64;
-import android.util.Base64InputStream;
 
 import com.squareup.okhttp.OkHttpClient;
 
@@ -62,7 +61,7 @@ public class CordovaResourceApi {
     // Creating this is light-weight.
     private static OkHttpClient httpClient = new OkHttpClient();
     
-    static Thread webCoreThread;
+    static Thread jsThread;
 
     private final AssetManager assetManager;
     private final ContentResolver contentResolver;
@@ -294,7 +293,7 @@ public class CordovaResourceApi {
             if (curThread == Looper.getMainLooper().getThread()) {
                 throw new IllegalStateException("Do not perform IO operations on the UI thread. Use CordovaInterface.getThreadPool() instead.");
             }
-            if (curThread == webCoreThread) {
+            if (curThread == jsThread) {
                 throw new IllegalStateException("Tried to perform an IO operation on the WebCore thread. Use CordovaInterface.getThreadPool() instead.");
             }
         }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/53e3a124/framework/src/org/apache/cordova/ExposedJsApi.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/ExposedJsApi.java b/framework/src/org/apache/cordova/ExposedJsApi.java
index 221dd3d..c3887cf 100755
--- a/framework/src/org/apache/cordova/ExposedJsApi.java
+++ b/framework/src/org/apache/cordova/ExposedJsApi.java
@@ -48,6 +48,9 @@ import org.json.JSONException;
 
         jsMessageQueue.setPaused(true);
         try {
+            // Tell the resourceApi what thread the JS is running on.
+            CordovaResourceApi.jsThread = Thread.currentThread();
+            
             pluginManager.exec(service, action, callbackId, arguments);
             String ret = "";
             if (!NativeToJsMessageQueue.DISABLE_EXEC_CHAINING) {

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/53e3a124/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 317acc2..f0f372c 100644
--- a/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
+++ b/framework/src/org/apache/cordova/IceCreamCordovaWebViewClient.java
@@ -27,7 +27,6 @@ import org.apache.cordova.api.LOG;
 import android.annotation.TargetApi;
 import android.net.Uri;
 import android.os.Build;
-import android.util.Log;
 import android.webkit.WebResourceResponse;
 import android.webkit.WebView;
 
@@ -46,9 +45,6 @@ public class IceCreamCordovaWebViewClient extends CordovaWebViewClient {
 
     @Override
     public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
-        // Tell the Thread-Checking resolve what thread the WebCore thread is.
-        CordovaResourceApi.webCoreThread = Thread.currentThread();
-        Log.e("WHAAAA", "FOOD " + CordovaResourceApi.webCoreThread);
         try {
             // Check the against the white-list.
             if ((url.startsWith("http:") || url.startsWith("https:")) && !Config.isUrlWhiteListed(url)) {


[15/16] android commit: Tweak the online bridge to not send excess online events.

Posted by ag...@apache.org.
Tweak the online bridge to not send excess online events.

It does so by having the JS tell it when online events have fired.
(cherry picked from commit 166b35bc6c5977cf547f4093690d554b57cb855a)


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

Branch: refs/heads/2.9.x
Commit: edb35b5a6d13159c69e1fc75ddbf8a149df6498e
Parents: bb7bc33
Author: Andrew Grieve <ag...@chromium.org>
Authored: Thu Aug 15 15:55:08 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:16:07 2013 -0400

----------------------------------------------------------------------
 .../org/apache/cordova/CordovaChromeClient.java |  2 +-
 .../src/org/apache/cordova/ExposedJsApi.java    |  6 ++--
 .../apache/cordova/NativeToJsMessageQueue.java  | 29 ++++++++++++--------
 3 files changed, 22 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/edb35b5a/framework/src/org/apache/cordova/CordovaChromeClient.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/CordovaChromeClient.java b/framework/src/org/apache/cordova/CordovaChromeClient.java
index 4d338a5..3c0abd1 100755
--- a/framework/src/org/apache/cordova/CordovaChromeClient.java
+++ b/framework/src/org/apache/cordova/CordovaChromeClient.java
@@ -234,7 +234,7 @@ public class CordovaChromeClient extends WebChromeClient {
 
         // Polling for JavaScript messages 
         else if (reqOk && defaultValue != null && defaultValue.equals("gap_poll:")) {
-            String r = this.appView.exposedJsApi.retrieveJsMessages();
+            String r = this.appView.exposedJsApi.retrieveJsMessages("1".equals(message));
             result.confirm(r == null ? "" : r);
         }
 

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/edb35b5a/framework/src/org/apache/cordova/ExposedJsApi.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/ExposedJsApi.java b/framework/src/org/apache/cordova/ExposedJsApi.java
index c3887cf..e2d730c 100755
--- a/framework/src/org/apache/cordova/ExposedJsApi.java
+++ b/framework/src/org/apache/cordova/ExposedJsApi.java
@@ -54,7 +54,7 @@ import org.json.JSONException;
             pluginManager.exec(service, action, callbackId, arguments);
             String ret = "";
             if (!NativeToJsMessageQueue.DISABLE_EXEC_CHAINING) {
-                ret = jsMessageQueue.popAndEncode();
+                ret = jsMessageQueue.popAndEncode(false);
             }
             return ret;
         } catch (Throwable e) {
@@ -71,7 +71,7 @@ import org.json.JSONException;
     }
     
     @JavascriptInterface
-    public String retrieveJsMessages() {
-        return jsMessageQueue.popAndEncode();
+    public String retrieveJsMessages(boolean fromOnlineEvent) {
+        return jsMessageQueue.popAndEncode(fromOnlineEvent);
     }
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/edb35b5a/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/NativeToJsMessageQueue.java b/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
index 8a13213..328fb33 100755
--- a/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
+++ b/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
@@ -138,8 +138,9 @@ public class NativeToJsMessageQueue {
      * Combines as many messages as possible, while staying under MAX_PAYLOAD_SIZE.
      * Returns null if the queue is empty.
      */
-    public String popAndEncode() {
+    public String popAndEncode(boolean fromOnlineEvent) {
         synchronized (this) {
+            registeredListeners[activeListenerIndex].notifyOfFlush(fromOnlineEvent);
             if (queue.isEmpty()) {
                 return null;
             }
@@ -274,12 +275,13 @@ public class NativeToJsMessageQueue {
         return paused;
     }
 
-    private interface BridgeMode {
-        void onNativeToJsMessageAvailable();
+    private abstract class BridgeMode {
+        abstract void onNativeToJsMessageAvailable();
+        void notifyOfFlush(boolean fromOnlineEvent) {}
     }
     
     /** Uses webView.loadUrl("javascript:") to execute messages. */
-    private class LoadUrlBridgeMode implements BridgeMode {
+    private class LoadUrlBridgeMode extends BridgeMode {
         final Runnable runnable = new Runnable() {
             public void run() {
                 String js = popAndEncodeAsJs();
@@ -289,18 +291,17 @@ public class NativeToJsMessageQueue {
             }
         };
         
-        public void onNativeToJsMessageAvailable() {
+        @Override void onNativeToJsMessageAvailable() {
             cordova.getActivity().runOnUiThread(runnable);
         }
     }
 
     /** Uses online/offline events to tell the JS when to poll for messages. */
-    private class OnlineEventsBridgeMode implements BridgeMode {
-        boolean online = true;
+    private class OnlineEventsBridgeMode extends BridgeMode {
+        boolean online = false;
         final Runnable runnable = new Runnable() {
             public void run() {
                 if (!queue.isEmpty()) {
-                    online = !online;
                     webView.setNetworkAvailable(online);
                 }
             }                
@@ -308,16 +309,22 @@ public class NativeToJsMessageQueue {
         OnlineEventsBridgeMode() {
             webView.setNetworkAvailable(true);
         }
-        public void onNativeToJsMessageAvailable() {
+        @Override void onNativeToJsMessageAvailable() {
             cordova.getActivity().runOnUiThread(runnable);
         }
+        // Track when online/offline events are fired so that we don't fire excess events.
+        @Override void notifyOfFlush(boolean fromOnlineEvent) {
+            if (fromOnlineEvent) {
+                online = !online;
+            }
+        }
     }
     
     /**
      * Uses Java reflection to access an API that lets us eval JS.
      * Requires Android 3.2.4 or above. 
      */
-    private class PrivateApiBridgeMode implements BridgeMode {
+    private class PrivateApiBridgeMode extends BridgeMode {
     	// Message added in commit:
     	// http://omapzoom.org/?p=platform/frameworks/base.git;a=commitdiff;h=9497c5f8c4bc7c47789e5ccde01179abc31ffeb2
     	// Which first appeared in 3.2.4ish.
@@ -355,7 +362,7 @@ public class NativeToJsMessageQueue {
     		}
     	}
     	
-        public void onNativeToJsMessageAvailable() {
+        @Override void onNativeToJsMessageAvailable() {
         	if (sendMessageMethod == null && !initFailed) {
         		initReflection();
         	}


[10/16] android commit: [CB-4463] Updated bin/check_reqs to looks for android-18 target.Also fixed an issue in unix version of script that would invoke the `android` command if an error occurred. (cherry picked from commit c2c5f71018a6821388e2516a6084818

Posted by ag...@apache.org.
[CB-4463] Updated bin/check_reqs to looks for android-18 target.Also fixed an issue in unix version of script that would invoke the `android` command if an error occurred.
(cherry picked from commit c2c5f71018a6821388e2516a6084818453b82de0)


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

Branch: refs/heads/2.9.x
Commit: 4b501a5b63885e7a83a80758f417a6964c35add3
Parents: dc494c8
Author: Fil Maj <ma...@gmail.com>
Authored: Tue Jul 30 17:14:46 2013 -0700
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:14:03 2013 -0400

----------------------------------------------------------------------
 bin/check_reqs    | 10 +++++-----
 bin/check_reqs.js |  8 ++++----
 2 files changed, 9 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4b501a5b/bin/check_reqs
----------------------------------------------------------------------
diff --git a/bin/check_reqs b/bin/check_reqs
index 0032778..cdc3fda 100755
--- a/bin/check_reqs
+++ b/bin/check_reqs
@@ -19,16 +19,16 @@
 ROOT="$( cd "$( dirname "$0" )/.." && pwd )"
 cmd=`android list target`
 if [[ $? != 0 ]]; then
-    echo "The command `android` failed. Make sure you have the latest Android SDK installed, and the `android` command (inside the tools/ folder) added to your path."
+    echo "The command \"android\" failed. Make sure you have the latest Android SDK installed, and the \"android\" command (inside the tools/ folder) added to your path."
     exit 2
-elif [[ ! $cmd =~ "android-17" ]]; then
-    echo "Please install Android target 17 (the Android 4.2 SDK). Make sure you have the latest Android tools installed as well. Run `android` from your command-line to install/update any missing SDKs or tools."
+elif [[ ! $cmd =~ "android-18" ]]; then
+    echo "Please install Android target 18 (the Android 4.3 SDK). Make sure you have the latest Android tools installed as well. Run \"android\" from your command-line to install/update any missing SDKs or tools."
     exit 2
 else
-    cmd="android update project -p $ROOT -t android-17 1> /dev/null 2>&1"
+    cmd="android update project -p $ROOT -t android-18 1> /dev/null 2>&1"
     eval $cmd
     if [[ $? != 0 ]]; then
         echo "Error updating the Cordova library to work with your Android environment."
         exit 2
     fi
-fi
\ No newline at end of file
+fi

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/4b501a5b/bin/check_reqs.js
----------------------------------------------------------------------
diff --git a/bin/check_reqs.js b/bin/check_reqs.js
index ef30991..7fc32b8 100644
--- a/bin/check_reqs.js
+++ b/bin/check_reqs.js
@@ -63,13 +63,13 @@ function check_requirements() {
         Log('The command `android` failed. Make sure you have the latest Android SDK installed, and the `android` command (inside the tools/ folder) added to your path. Output: ' + result.output, true);
         WScript.Quit(2);
     }
-    else if(!result.output.match(/android[-]17/)) {
-        Log('Please install Android target 17 (the Android 4.2 SDK). Make sure you have the latest Android tools installed as well. Run `android` from your command-line to install/update any missing SDKs or tools.', true);
+    else if(!result.output.match(/android[-]18/)) {
+        Log('Please install Android target 18 (the Android 4.3 SDK). Make sure you have the latest Android tools installed as well. Run `android` from your command-line to install/update any missing SDKs or tools.', true);
         Log('Output : ' + result.output);
         WScript.Quit(2);
     }
     else {
-        var cmd = '%comspec% /c android update project -p ' + ROOT + '\\framework -t android-17';
+        var cmd = '%comspec% /c android update project -p ' + ROOT + '\\framework -t android-18';
         result = exec_out(cmd);
         if(result.error) {
             Log('Error updating the Cordova library to work with your Android environment. Command run: "' + cmd + '", output: ' + result.output, true);
@@ -78,4 +78,4 @@ function check_requirements() {
     }
 }
 
-check_requirements();
\ No newline at end of file
+check_requirements();


[03/16] android commit: [CB-3384] Add a length getter for UriResolver. Change from interface -> abstract class.

Posted by ag...@apache.org.
[CB-3384] Add a length getter for UriResolver. Change from interface -> abstract class.

Thinking here is that we can maintain compatibility going forward with a
base class as opposed to interface by having new methods on it have
default implementations.
(cherry picked from commit 990d91360d64324ba332e821fe512d712d7d5521)


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

Branch: refs/heads/2.9.x
Commit: 43bf47ea7b44fc06d62eaef715eede581a9b0682
Parents: 4be84fb
Author: Andrew Grieve <ag...@chromium.org>
Authored: Wed Jul 10 15:11:23 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Tue Oct 22 15:05:15 2013 -0400

----------------------------------------------------------------------
 .../src/org/apache/cordova/UriResolver.java     | 35 ++++++----
 .../src/org/apache/cordova/UriResolvers.java    | 68 +++++++++++++++++---
 2 files changed, 79 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/43bf47ea/framework/src/org/apache/cordova/UriResolver.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/UriResolver.java b/framework/src/org/apache/cordova/UriResolver.java
index 8341b18..b3bfa4d 100644
--- a/framework/src/org/apache/cordova/UriResolver.java
+++ b/framework/src/org/apache/cordova/UriResolver.java
@@ -23,40 +23,47 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 
-import android.net.Uri;
-
 /*
  * Interface for a class that can resolve URIs.
  * See CordovaUriResolver for an example.
  */
-public interface UriResolver {
+public abstract class UriResolver {
 
     /** 
      * Returns the InputStream for the resource. 
      * Throws an exception if it cannot be read. 
      * Never returns null.
      */
-    InputStream getInputStream() throws IOException;
+    public abstract InputStream getInputStream() throws IOException;
 
     /** 
-     * Returns the OutputStream for the resource. 
-     * Throws an exception if it cannot be written to. 
-     * Never returns null.
-     */
-    OutputStream getOutputStream() throws IOException; 
-    
-    /** 
      * Returns the MIME type of the resource.
      * Returns null if the MIME type cannot be determined (e.g. content: that doesn't exist).
      */
-    String getMimeType();
+    public abstract String getMimeType();
 
     /** Returns whether the resource is writable. */
-    boolean isWritable();
+    public abstract boolean isWritable();
 
     /**
      * Returns a File that points to the resource, or null if the resource
      * is not on the local file system.
      */
-    File getLocalFile();
+    public abstract File getLocalFile();
+
+    /** 
+     * Returns the OutputStream for the resource. 
+     * Throws an exception if it cannot be written to. 
+     * Never returns null.
+     */
+    public OutputStream getOutputStream() throws IOException {
+        throw new IOException("Writing is not suppported");
+    }
+    
+    /**
+     * Returns the length of the input stream, or -1 if it is not computable.
+     */
+    public long computeLength() throws IOException {
+        return -1;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cordova-android/blob/43bf47ea/framework/src/org/apache/cordova/UriResolvers.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/UriResolvers.java b/framework/src/org/apache/cordova/UriResolvers.java
index dcb5001..294fc6b 100644
--- a/framework/src/org/apache/cordova/UriResolvers.java
+++ b/framework/src/org/apache/cordova/UriResolvers.java
@@ -44,19 +44,38 @@ public final class UriResolvers {
 
     private UriResolvers() {}
 
-    private static final class FileUriResolver implements UriResolver {
+    private static long computeSizeFromResolver(UriResolver resolver) throws IOException {
+        InputStream inputStream = resolver.getInputStream();
+        if (inputStream instanceof FileInputStream) {
+            return ((FileInputStream)inputStream).getChannel().size();
+        }
+        if (inputStream instanceof ByteArrayInputStream) {
+            return ((ByteArrayInputStream)inputStream).available();
+        }
+        return -1;
+    }
+    
+    private static final class FileUriResolver extends UriResolver {
         private final File localFile;
         private String mimeType;
+        private FileInputStream cachedInputStream;
     
         FileUriResolver(Uri uri) {
             localFile = new File(uri.getPath());
         }
         
         public InputStream getInputStream() throws IOException {
-            return new FileInputStream(localFile);
+            if (cachedInputStream == null) {
+                cachedInputStream = new FileInputStream(localFile);
+            }
+            return cachedInputStream;
         }
         
         public OutputStream getOutputStream() throws FileNotFoundException {
+            File parent = localFile.getParentFile();
+            if (parent != null) {
+                localFile.getParentFile().mkdirs();
+            }
             return new FileOutputStream(localFile);
         }
         
@@ -80,12 +99,17 @@ public final class UriResolvers {
         public File getLocalFile() {
             return localFile;
         }
+        
+        public long computeLength() throws IOException {
+            return localFile.length();
+        }
     }
     
-    private static final class AssetUriResolver implements UriResolver {
+    private static final class AssetUriResolver extends UriResolver {
         private final AssetManager assetManager;
         private final String assetPath;
         private String mimeType;
+        private InputStream cachedInputStream;
     
         AssetUriResolver(Uri uri, AssetManager assetManager) {
             this.assetManager = assetManager;
@@ -93,7 +117,10 @@ public final class UriResolvers {
         }
         
         public InputStream getInputStream() throws IOException {
-            return assetManager.open(assetPath);
+            if (cachedInputStream == null) {
+                cachedInputStream = assetManager.open(assetPath);
+            }
+            return cachedInputStream;
         }
         
         public OutputStream getOutputStream() throws FileNotFoundException {
@@ -114,12 +141,17 @@ public final class UriResolvers {
         public File getLocalFile() {
             return null;
         }
+
+        public long computeLength() throws IOException {
+            return computeSizeFromResolver(this);
+        }
     }
     
-    private static final class ContentUriResolver implements UriResolver {
+    private static final class ContentUriResolver extends UriResolver {
         private final Uri uri;
         private final ContentResolver contentResolver;
         private String mimeType;
+        private InputStream cachedInputStream;
     
         ContentUriResolver(Uri uri, ContentResolver contentResolver) {
             this.uri = uri;
@@ -127,7 +159,10 @@ public final class UriResolvers {
         }
         
         public InputStream getInputStream() throws IOException {
-            return contentResolver.openInputStream(uri);
+            if (cachedInputStream == null) {
+                cachedInputStream = contentResolver.openInputStream(uri);
+            }
+            return cachedInputStream;
         }
         
         public OutputStream getOutputStream() throws FileNotFoundException {
@@ -148,9 +183,13 @@ public final class UriResolvers {
         public File getLocalFile() {
             return null;
         }
+        
+        public long computeLength() throws IOException {
+            return computeSizeFromResolver(this);
+        }
     }
     
-    private static final class ErrorUriResolver implements UriResolver {
+    private static final class ErrorUriResolver extends UriResolver {
         final String errorMsg;
         
         ErrorUriResolver(String errorMsg) {
@@ -178,7 +217,7 @@ public final class UriResolvers {
         }
     }
     
-    private static final class ReadOnlyResolver implements UriResolver {
+    private static final class ReadOnlyResolver extends UriResolver {
         private InputStream inputStream;
         private String mimeType;
         
@@ -206,9 +245,13 @@ public final class UriResolvers {
         public InputStream getInputStream() throws IOException {
             return inputStream;
         }
+        
+        public long computeLength() throws IOException {
+            return computeSizeFromResolver(this);
+        }
     }
     
-    private static final class ThreadCheckingResolver implements UriResolver {
+    private static final class ThreadCheckingResolver extends UriResolver {
         final UriResolver delegate;
         
         ThreadCheckingResolver(UriResolver delegate) {
@@ -250,6 +293,11 @@ public final class UriResolvers {
             checkThread();
             return delegate.getInputStream();
         }
+        
+        public long computeLength() throws IOException {
+            checkThread();
+            return delegate.computeLength();
+        }
     }
     
     public static UriResolver createInline(Uri uri, String response, String mimeType) {
@@ -290,4 +338,4 @@ public final class UriResolvers {
         }
         return new ThreadCheckingResolver(resolver);
     }
-}
\ No newline at end of file
+}