diff --git a/framework/src/org/apache/cordova/AndroidWebViewClient.java b/framework/src/org/apache/cordova/AndroidWebViewClient.java
index 44862a6b..c0171774 100755
--- a/framework/src/org/apache/cordova/AndroidWebViewClient.java
+++ b/framework/src/org/apache/cordova/AndroidWebViewClient.java
@@ -197,7 +197,19 @@ public class AndroidWebViewClient extends WebViewClient {
// Clear timeout flag
appView.loadUrlTimeout++;
- // Handle error
+ // If this is a "Protocol Not Supported" error, then revert to the previous
+ // page. If there was no previous page, then punt. The application's config
+ // is likely incorrect (start page set to sms: or something like that)
+ if (errorCode == WebViewClient.ERROR_UNSUPPORTED_SCHEME) {
+ if (view.canGoBack()) {
+ view.goBack();
+ return;
+ } else {
+ super.onReceivedError(view, errorCode, description, failingUrl);
+ }
+ }
+
+ // Handle other errors by passing them to the webview in JS
JSONObject data = new JSONObject();
try {
data.put("errorCode", errorCode);
diff --git a/framework/src/org/apache/cordova/CordovaActivity.java b/framework/src/org/apache/cordova/CordovaActivity.java
index f84e4a33..fa332e5b 100755
--- a/framework/src/org/apache/cordova/CordovaActivity.java
+++ b/framework/src/org/apache/cordova/CordovaActivity.java
@@ -394,6 +394,9 @@ public class CordovaActivity extends Activity implements CordovaInterface {
if (this.appView == null) {
return;
}
+ // Force window to have focus, so application always
+ // receive user input. Workaround for some devices (Samsung Galaxy Note 3 at least)
+ this.getWindow().getDecorView().requestFocus();
this.appView.handleResume(this.keepRunning, this.activityResultKeepRunning);
diff --git a/framework/src/org/apache/cordova/CordovaUriHelper.java b/framework/src/org/apache/cordova/CordovaUriHelper.java
index 077e425e..f7d22da8 100644
--- a/framework/src/org/apache/cordova/CordovaUriHelper.java
+++ b/framework/src/org/apache/cordova/CordovaUriHelper.java
@@ -19,8 +19,11 @@
package org.apache.cordova;
+import android.annotation.TargetApi;
import android.content.Intent;
import android.net.Uri;
+import android.os.Build;
+import android.webkit.WebView;
public class CordovaUriHelper {
@@ -43,6 +46,7 @@ public class CordovaUriHelper {
* @param url The url to be loaded.
* @return true to override, false for default behavior
*/
+ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
public boolean shouldOverrideUrlLoading(String url) {
// The WebView should support http and https when going on the Internet
if(url.startsWith("http:") || url.startsWith("https:"))
@@ -68,6 +72,11 @@ public class CordovaUriHelper {
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
+ intent.addCategory(Intent.CATEGORY_BROWSABLE);
+ intent.setComponent(null);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
+ intent.setSelector(null);
+ }
this.cordova.getActivity().startActivity(intent);
} catch (android.content.ActivityNotFoundException e) {
LOG.e(TAG, "Error loading url " + url, e);
diff --git a/framework/src/org/apache/cordova/NativeToJsMessageQueue.java b/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
index 75d5d434..b9460513 100755
--- a/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
+++ b/framework/src/org/apache/cordova/NativeToJsMessageQueue.java
@@ -321,11 +321,16 @@ public class NativeToJsMessageQueue {
}
}
};
+ final Runnable resetNetworkRunnable = new Runnable() {
+ public void run() {
+ online = false;
+ // If the following call triggers a notifyOfFlush, then ignore it.
+ ignoreNextFlush = true;
+ webView.setNetworkAvailable(true);
+ }
+ };
@Override void reset() {
- online = false;
- // If the following call triggers a notifyOfFlush, then ignore it.
- ignoreNextFlush = true;
- webView.setNetworkAvailable(true);
+ cordova.getActivity().runOnUiThread(resetNetworkRunnable);
}
@Override void onNativeToJsMessageAvailable() {
cordova.getActivity().runOnUiThread(toggleNetworkRunnable);
diff --git a/framework/src/org/apache/cordova/Whitelist.java b/framework/src/org/apache/cordova/Whitelist.java
index ecbb7f61..5101ec35 100644
--- a/framework/src/org/apache/cordova/Whitelist.java
+++ b/framework/src/org/apache/cordova/Whitelist.java
@@ -124,15 +124,15 @@ public class Whitelist {
whiteList = null;
}
else { // specific access
- Pattern parts = Pattern.compile("^((\\*|[A-Za-z-]+)://)?(\\*|((\\*\\.)?[^*/:]+))?(:(\\d+))?(/.*)?");
+ Pattern parts = Pattern.compile("^((\\*|[A-Za-z-]+):(//)?)?(\\*|((\\*\\.)?[^*/:]+))?(:(\\d+))?(/.*)?");
Matcher m = parts.matcher(origin);
if (m.matches()) {
String scheme = m.group(2);
- String host = m.group(3);
+ String host = m.group(4);
// Special case for two urls which are allowed to have empty hosts
if (("file".equals(scheme) || "content".equals(scheme)) && host == null) host = "*";
- String port = m.group(7);
- String path = m.group(8);
+ String port = m.group(8);
+ String path = m.group(9);
if (scheme == null) {
// XXX making it stupid friendly for people who forget to include protocol/SSL
whiteList.add(new URLPattern("http", host, port, path));
diff --git a/test/assets/www/error.html b/test/assets/www/error.html
new file mode 100644
index 00000000..aad167dc
--- /dev/null
+++ b/test/assets/www/error.html
@@ -0,0 +1,8 @@
+
+
+ OH NOES!
+
+
+ Things went terribly wrong!
+
+
\ No newline at end of file
diff --git a/test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java b/test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java
index 6f96e839..b143521e 100644
--- a/test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java
+++ b/test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java
@@ -22,6 +22,8 @@ package org.apache.cordova.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
+import org.apache.cordova.AndroidChromeClient;
+import org.apache.cordova.AndroidWebViewClient;
import org.apache.cordova.Config;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.CordovaInterface;
@@ -45,10 +47,11 @@ public class CordovaWebViewTestActivity extends Activity implements CordovaInter
setContentView(R.layout.main);
- cordovaWebView = (CordovaWebView) findViewById(R.id.cordovaWebView);
+ //CB-7238: This has to be added now, because it got removed from somewhere else
Config.init(this);
- cordovaWebView.init(this,
- Config.getPluginEntries(), Config.getWhitelist(), Config.getPreferences());
+
+ cordovaWebView = (CordovaWebView) findViewById(R.id.cordovaWebView);
+ cordovaWebView.init(this, Config.getPluginEntries(), Config.getWhitelist(), Config.getPreferences());
cordovaWebView.loadUrl("file:///android_asset/www/index.html");
diff --git a/test/src/org/apache/cordova/test/SabotagedActivity.java b/test/src/org/apache/cordova/test/SabotagedActivity.java
new file mode 100644
index 00000000..e1170ba3
--- /dev/null
+++ b/test/src/org/apache/cordova/test/SabotagedActivity.java
@@ -0,0 +1,73 @@
+package org.apache.cordova.test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
+
+import org.apache.cordova.Config;
+import org.apache.cordova.CordovaActivity;
+
+import android.content.res.AssetManager;
+import android.os.Bundle;
+import android.os.Environment;
+import android.util.Log;
+
+public class SabotagedActivity extends CordovaActivity {
+
+ private String BAD_ASSET = "www/error.html";
+ private String LOG_TAG = "SabotagedActivity";
+
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+// copyErrorAsset();
+ super.init();
+ super.loadUrl(Config.getStartUrl());
+ }
+
+ /*
+ * Sometimes we need to move code around before we can do anything. This will
+ * copy the bad code out of the assets before we initalize Cordova so that when Cordova actually
+ * initializes, we have something for it to navigate to.
+ */
+
+ private void copyErrorAsset () {
+ AssetManager assetManager = getAssets();
+ String[] files = null;
+ try {
+ files = assetManager.list(BAD_ASSET);
+ } catch (IOException e) {
+ Log.e(LOG_TAG, e.getMessage());
+ }
+
+ for(String filename : files) {
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ in = assetManager.open(BAD_ASSET);
+ out = new FileOutputStream(Environment.getExternalStorageDirectory().toString() +"/" + filename);
+ copy(in, out);
+ in.close();
+ in = null;
+ out.flush();
+ out.close();
+ out = null;
+ } catch(Exception e) {
+ Log.e("tag", e.getMessage());
+ }
+ }
+ }
+
+
+ //Quick and Dirty Copy!
+ private void copy(InputStream in, OutputStream out) throws IOException {
+ byte[] buffer = new byte[1024];
+ int read;
+ while((read = in.read(buffer)) != -1){
+ out.write(buffer, 0, read);
+ }
+ }
+}
diff --git a/test/src/org/apache/cordova/test/junit/IntentUriOverrideTest.java b/test/src/org/apache/cordova/test/junit/IntentUriOverrideTest.java
new file mode 100644
index 00000000..aea06afe
--- /dev/null
+++ b/test/src/org/apache/cordova/test/junit/IntentUriOverrideTest.java
@@ -0,0 +1,73 @@
+package org.apache.cordova.test.junit;
+
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.test.SabotagedActivity;
+import org.apache.cordova.test.splashscreen;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.AssetManager;
+import android.test.ActivityInstrumentationTestCase2;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+
+public class IntentUriOverrideTest extends ActivityInstrumentationTestCase2 {
+
+ private int TIMEOUT = 1000;
+
+ private SabotagedActivity testActivity;
+ private FrameLayout containerView;
+ private LinearLayout innerContainer;
+ private CordovaWebView testView;
+ private Instrumentation mInstr;
+ private String BAD_URL = "file:///sdcard/download/wl-exploit.htm";
+
+
+ public IntentUriOverrideTest()
+ {
+ super("org.apache.cordova.test",SabotagedActivity.class);
+ }
+
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ mInstr = this.getInstrumentation();
+ Intent badIntent = new Intent();
+ badIntent.setClassName("org.apache.cordova.test", "org.apache.cordova.test.SabotagedActivity");
+ badIntent.putExtra("url", BAD_URL);
+ setActivityIntent(badIntent);
+ testActivity = getActivity();
+ containerView = (FrameLayout) testActivity.findViewById(android.R.id.content);
+ innerContainer = (LinearLayout) containerView.getChildAt(0);
+ testView = (CordovaWebView) innerContainer.getChildAt(0);
+ }
+
+
+ public void testPreconditions(){
+ assertNotNull(innerContainer);
+ assertNotNull(testView);
+ }
+
+ public void testChangeStartUrl() throws Throwable
+ {
+ runTestOnUiThread(new Runnable() {
+ public void run()
+ {
+ boolean isBadUrl = testView.getUrl().equals(BAD_URL);
+ assertFalse(isBadUrl);
+ }
+ });
+ }
+
+ private void sleep() {
+ try {
+ Thread.sleep(TIMEOUT);
+ } catch (InterruptedException e) {
+ fail("Unexpected Timeout");
+ }
+ }
+
+
+}