From 45680a562e31364d8cf0c386a703531884281bcd Mon Sep 17 00:00:00 2001 From: "Juan G. Hurtado" Date: Wed, 16 May 2012 08:37:40 +0200 Subject: [PATCH 1/3] Add Android 4.0 workaround for links with params Android 4.0.x has a known bug [1] while accessing local files with params: file://file.html?param=2 This commit adds a workaround for this problem by removing the params part of the local URI before accessing the file. [1] http://code.google.com/p/android/issues/detail?id=17535 --- .../apache/cordova/CordovaWebViewClient.java | 88 +++++++++++++------ 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/framework/src/org/apache/cordova/CordovaWebViewClient.java b/framework/src/org/apache/cordova/CordovaWebViewClient.java index 6bddfc35..7abaff5a 100755 --- a/framework/src/org/apache/cordova/CordovaWebViewClient.java +++ b/framework/src/org/apache/cordova/CordovaWebViewClient.java @@ -38,35 +38,35 @@ import android.webkit.WebViewClient; * This class is the WebViewClient that implements callbacks for our web view. */ public class CordovaWebViewClient extends WebViewClient { - + private static final String TAG = "Cordova"; DroidGap ctx; private boolean doClearHistory = false; /** * Constructor. - * + * * @param ctx */ public CordovaWebViewClient(DroidGap ctx) { this.ctx = ctx; } - + /** - * Give the host application a chance to take over the control when a new url + * Give the host application a chance to take over the control when a new url * is about to be loaded in the current WebView. - * + * * @param view The WebView that is initiating the callback. * @param url The url to be loaded. * @return true to override, false for default behavior */ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { - + // First give any plugins the chance to handle the url themselves if ((this.ctx.pluginManager != null) && this.ctx.pluginManager.onOverrideUrlLoading(url)) { } - + // If dialing phone (tel:5551212) else if (url.startsWith(WebView.SCHEME_TEL)) { try { @@ -154,11 +154,11 @@ public class CordovaWebViewClient extends WebViewClient { } return true; } - + /** * On received http auth request. - * The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination - * + * The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination + * * @param view * the view * @param handler @@ -171,27 +171,27 @@ public class CordovaWebViewClient extends WebViewClient { @Override public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) { - + // get the authentication token AuthenticationToken token = ctx.getAuthenticationToken(host,realm); - + if(token != null) { handler.proceed(token.getUserName(), token.getPassword()); } } - + @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { - // Clear history so history.back() doesn't do anything. + // Clear history so history.back() doesn't do anything. // So we can reinit() native side CallbackServer & PluginManager. - view.clearHistory(); + view.clearHistory(); this.doClearHistory = true; } - + /** * Notify the host application that a page has finished loading. - * + * * @param view The webview initiating the callback. * @param url The url of the page. */ @@ -200,8 +200,8 @@ public class CordovaWebViewClient extends WebViewClient { super.onPageFinished(view, url); /** - * Because of a timing issue we need to clear this history in onPageFinished as well as - * onPageStarted. However we only want to do this if the doClearHistory boolean is set to + * Because of a timing issue we need to clear this history in onPageFinished as well as + * onPageStarted. However we only want to do this if the doClearHistory boolean is set to * true. You see when you load a url with a # in it which is common in jQuery applications * onPageStared is not called. Clearing the history at that point would break jQuery apps. */ @@ -252,15 +252,15 @@ public class CordovaWebViewClient extends WebViewClient { this.ctx.endActivity(); } } - + /** - * Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable). + * Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable). * The errorCode parameter corresponds to one of the ERROR_* constants. * * @param view The WebView that is initiating the callback. * @param errorCode The error code corresponding to an ERROR_* value. * @param description A String describing the error. - * @param failingUrl The url that failed to load. + * @param failingUrl The url that failed to load. */ @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { @@ -275,9 +275,9 @@ public class CordovaWebViewClient extends WebViewClient { // Handle error this.ctx.onReceivedError(errorCode, description, failingUrl); } - + public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { - + final String packageName = this.ctx.getPackageName(); final PackageManager pm = this.ctx.getPackageManager(); ApplicationInfo appInfo; @@ -289,7 +289,7 @@ public class CordovaWebViewClient extends WebViewClient { return; } else { // debug = false - super.onReceivedSslError(view, handler, error); + super.onReceivedSslError(view, handler, error); } } catch (NameNotFoundException e) { // When it doubt, lock it out! @@ -299,7 +299,7 @@ public class CordovaWebViewClient extends WebViewClient { @Override public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) { - /* + /* * If you do a document.location.href the url does not get pushed on the stack * so we do a check here to see if the url should be pushed. */ @@ -307,4 +307,40 @@ public class CordovaWebViewClient extends WebViewClient { this.ctx.pushUrl(url); } } + + @Override + public WebResourceResponse shouldInterceptRequest(WebView view, String url) { + if(url.contains("?")){ + return generateWebResourceResponse(url); + } else { + return super.shouldInterceptRequest(view, url); + } + } + + private WebResourceResponse generateWebResourceResponse(String url) { + final String ANDROID_ASSET = "file:///android_asset/"; + if (url.startsWith(ANDROID_ASSET)) { + String niceUrl = url; + niceUrl = url.replaceFirst(ANDROID_ASSET, ""); + if(niceUrl.contains("?")){ + niceUrl = niceUrl.split("\\?")[0]; + } + + String mimetype = null; + if(niceUrl.endsWith(".html")){ + mimetype = "text/html"; + } + + try { + AssetManager assets = ctx.getAssets(); + Uri uri = Uri.parse(niceUrl); + InputStream stream = assets.open(uri.getPath(), AssetManager.ACCESS_STREAMING); + WebResourceResponse response = new WebResourceResponse(mimetype, "UTF-8", stream); + return response; + } catch (IOException e) { + Log.e("generateWebResourceResponse", e.getMessage(), e); + } + } + return null; + } } From 6de66b87cb84c4ad4e9c4bb0f1e053be70fabf59 Mon Sep 17 00:00:00 2001 From: "Juan G. Hurtado" Date: Wed, 16 May 2012 08:37:40 +0200 Subject: [PATCH 2/3] Add Android 4.0 workaround for links with params Android 4.0.x has a known bug [1] while accessing local files with params: file://file.html?param=2 This commit adds a workaround for this problem by removing the params part of the local URI before accessing the file. [1] http://code.google.com/p/android/issues/detail?id=17535 --- .../apache/cordova/CordovaWebViewClient.java | 88 +++++++++++++------ 1 file changed, 62 insertions(+), 26 deletions(-) diff --git a/framework/src/org/apache/cordova/CordovaWebViewClient.java b/framework/src/org/apache/cordova/CordovaWebViewClient.java index 6bddfc35..7abaff5a 100755 --- a/framework/src/org/apache/cordova/CordovaWebViewClient.java +++ b/framework/src/org/apache/cordova/CordovaWebViewClient.java @@ -38,35 +38,35 @@ import android.webkit.WebViewClient; * This class is the WebViewClient that implements callbacks for our web view. */ public class CordovaWebViewClient extends WebViewClient { - + private static final String TAG = "Cordova"; DroidGap ctx; private boolean doClearHistory = false; /** * Constructor. - * + * * @param ctx */ public CordovaWebViewClient(DroidGap ctx) { this.ctx = ctx; } - + /** - * Give the host application a chance to take over the control when a new url + * Give the host application a chance to take over the control when a new url * is about to be loaded in the current WebView. - * + * * @param view The WebView that is initiating the callback. * @param url The url to be loaded. * @return true to override, false for default behavior */ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { - + // First give any plugins the chance to handle the url themselves if ((this.ctx.pluginManager != null) && this.ctx.pluginManager.onOverrideUrlLoading(url)) { } - + // If dialing phone (tel:5551212) else if (url.startsWith(WebView.SCHEME_TEL)) { try { @@ -154,11 +154,11 @@ public class CordovaWebViewClient extends WebViewClient { } return true; } - + /** * On received http auth request. - * The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination - * + * The method reacts on all registered authentication tokens. There is one and only one authentication token for any host + realm combination + * * @param view * the view * @param handler @@ -171,27 +171,27 @@ public class CordovaWebViewClient extends WebViewClient { @Override public void onReceivedHttpAuthRequest(WebView view, HttpAuthHandler handler, String host, String realm) { - + // get the authentication token AuthenticationToken token = ctx.getAuthenticationToken(host,realm); - + if(token != null) { handler.proceed(token.getUserName(), token.getPassword()); } } - + @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { - // Clear history so history.back() doesn't do anything. + // Clear history so history.back() doesn't do anything. // So we can reinit() native side CallbackServer & PluginManager. - view.clearHistory(); + view.clearHistory(); this.doClearHistory = true; } - + /** * Notify the host application that a page has finished loading. - * + * * @param view The webview initiating the callback. * @param url The url of the page. */ @@ -200,8 +200,8 @@ public class CordovaWebViewClient extends WebViewClient { super.onPageFinished(view, url); /** - * Because of a timing issue we need to clear this history in onPageFinished as well as - * onPageStarted. However we only want to do this if the doClearHistory boolean is set to + * Because of a timing issue we need to clear this history in onPageFinished as well as + * onPageStarted. However we only want to do this if the doClearHistory boolean is set to * true. You see when you load a url with a # in it which is common in jQuery applications * onPageStared is not called. Clearing the history at that point would break jQuery apps. */ @@ -252,15 +252,15 @@ public class CordovaWebViewClient extends WebViewClient { this.ctx.endActivity(); } } - + /** - * Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable). + * Report an error to the host application. These errors are unrecoverable (i.e. the main resource is unavailable). * The errorCode parameter corresponds to one of the ERROR_* constants. * * @param view The WebView that is initiating the callback. * @param errorCode The error code corresponding to an ERROR_* value. * @param description A String describing the error. - * @param failingUrl The url that failed to load. + * @param failingUrl The url that failed to load. */ @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { @@ -275,9 +275,9 @@ public class CordovaWebViewClient extends WebViewClient { // Handle error this.ctx.onReceivedError(errorCode, description, failingUrl); } - + public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) { - + final String packageName = this.ctx.getPackageName(); final PackageManager pm = this.ctx.getPackageManager(); ApplicationInfo appInfo; @@ -289,7 +289,7 @@ public class CordovaWebViewClient extends WebViewClient { return; } else { // debug = false - super.onReceivedSslError(view, handler, error); + super.onReceivedSslError(view, handler, error); } } catch (NameNotFoundException e) { // When it doubt, lock it out! @@ -299,7 +299,7 @@ public class CordovaWebViewClient extends WebViewClient { @Override public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) { - /* + /* * If you do a document.location.href the url does not get pushed on the stack * so we do a check here to see if the url should be pushed. */ @@ -307,4 +307,40 @@ public class CordovaWebViewClient extends WebViewClient { this.ctx.pushUrl(url); } } + + @Override + public WebResourceResponse shouldInterceptRequest(WebView view, String url) { + if(url.contains("?")){ + return generateWebResourceResponse(url); + } else { + return super.shouldInterceptRequest(view, url); + } + } + + private WebResourceResponse generateWebResourceResponse(String url) { + final String ANDROID_ASSET = "file:///android_asset/"; + if (url.startsWith(ANDROID_ASSET)) { + String niceUrl = url; + niceUrl = url.replaceFirst(ANDROID_ASSET, ""); + if(niceUrl.contains("?")){ + niceUrl = niceUrl.split("\\?")[0]; + } + + String mimetype = null; + if(niceUrl.endsWith(".html")){ + mimetype = "text/html"; + } + + try { + AssetManager assets = ctx.getAssets(); + Uri uri = Uri.parse(niceUrl); + InputStream stream = assets.open(uri.getPath(), AssetManager.ACCESS_STREAMING); + WebResourceResponse response = new WebResourceResponse(mimetype, "UTF-8", stream); + return response; + } catch (IOException e) { + Log.e("generateWebResourceResponse", e.getMessage(), e); + } + } + return null; + } } From 8ff48b371e6090e0af942efdd66f32be6911d4bf Mon Sep 17 00:00:00 2001 From: "Juan G. Hurtado" Date: Fri, 18 May 2012 08:45:39 +0200 Subject: [PATCH 3/3] Fix imports for changes in 45680a5 Commit 45680a5 had errors importing packages. This commit fix them. --- framework/src/org/apache/cordova/CordovaWebViewClient.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/framework/src/org/apache/cordova/CordovaWebViewClient.java b/framework/src/org/apache/cordova/CordovaWebViewClient.java index 7abaff5a..63ea3012 100755 --- a/framework/src/org/apache/cordova/CordovaWebViewClient.java +++ b/framework/src/org/apache/cordova/CordovaWebViewClient.java @@ -18,12 +18,17 @@ */ package org.apache.cordova; +import java.io.IOException; +import java.io.InputStream; + import org.apache.cordova.api.LOG; +import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.AssetManager; import android.graphics.Bitmap; import android.net.Uri; import android.net.http.SslError; @@ -31,6 +36,7 @@ import android.util.Log; import android.view.View; import android.webkit.HttpAuthHandler; import android.webkit.SslErrorHandler; +import android.webkit.WebResourceResponse; import android.webkit.WebView; import android.webkit.WebViewClient;