Bug 1162372 - Load about:neterror when we can't load a uri w/ a custom scheme. r=margaret
authorMichael Comella <michael.l.comella@gmail.com>
Tue, 21 Jul 2015 14:41:37 -0700
changeset 286403 d43113d59aabb39bc5d8c855baab358d9fc0cb8a
parent 286402 c607be4ebbd8eab060752e5cd347a494b315281b
child 286404 c2e8b03c28bcd3ed17fa46ae5041841204028450
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmargaret
bugs1162372
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1162372 - Load about:neterror when we can't load a uri w/ a custom scheme. r=margaret
mobile/android/base/IntentHelper.java
--- a/mobile/android/base/IntentHelper.java
+++ b/mobile/android/base/IntentHelper.java
@@ -14,19 +14,20 @@ import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.app.Activity;
 import android.content.Intent;
 import android.net.Uri;
 import android.text.TextUtils;
 import android.util.Log;
-import android.widget.Toast;
 
+import java.io.UnsupportedEncodingException;
 import java.net.URISyntaxException;
+import java.net.URLEncoder;
 import java.util.Arrays;
 import java.util.List;
 
 public final class IntentHelper implements GeckoEventListener {
     private static final String LOGTAG = "GeckoIntentHelper";
     private static final String[] EVENTS = {
         "Intent:GetHandlers",
         "Intent:Open",
@@ -34,16 +35,19 @@ public final class IntentHelper implemen
         "Intent:OpenNoHandler",
         "WebActivity:Open"
     };
 
     // via http://developer.android.com/distribute/tools/promote/linking.html
     private static String MARKET_INTENT_URI_PACKAGE_PREFIX = "market://details?id=";
     private static String EXTRA_BROWSER_FALLBACK_URL = "browser_fallback_url";
 
+    /** A partial URI to an error page - the encoded error URI should be appended before loading. */
+    private static String UNKNOWN_PROTOCOL_URI_PREFIX = "about:neterror?e=unknownProtocolFound&u=";
+
     private static IntentHelper instance;
 
     private final Activity activity;
 
     private IntentHelper(Activity activity) {
         this.activity = activity;
         EventDispatcher.getInstance().registerGeckoThreadListener(this, EVENTS);
     }
@@ -128,29 +132,34 @@ public final class IntentHelper implemen
      * and we can bring the user directly to the application page in an app market. If a package is
      * not specified and there is a fallback url in the intent extras, we open that url. If neither
      * is present, we alert the user that we were unable to open the link.
      */
     private void openNoHandler(final JSONObject msg) {
         final String uri = msg.optString("uri");
 
         if (TextUtils.isEmpty(uri)) {
-            displayToastCannotOpenLink();
-            Log.w(LOGTAG, "Received empty URL. Ignoring...");
+            openUnknownProtocolErrorPage("");
+            Log.w(LOGTAG, "Received empty URL - loading about:neterror");
             return;
         }
 
         final Intent intent;
         try {
             // TODO (bug 1173626): This will not handle android-app uris on non 5.1 devices.
             intent = Intent.parseUri(uri, 0);
         } catch (final URISyntaxException e) {
-            displayToastCannotOpenLink();
+            try {
+                openUnknownProtocolErrorPage(URLEncoder.encode(uri, "UTF-8"));
+            } catch (final UnsupportedEncodingException encodingE) {
+                openUnknownProtocolErrorPage("");
+            }
+
             // Don't log the exception to prevent leaking URIs.
-            Log.w(LOGTAG, "Unable to parse Intent URI");
+            Log.w(LOGTAG, "Unable to parse Intent URI - loading about:neterror");
             return;
         }
 
         // For this flow, we follow Chrome's lead:
         //   https://developer.chrome.com/multidevice/android/intents
         //
         // Note on alternative flows: we could get the intent package from a component, however, for
         // security reasons, components are ignored when opening URIs (bug 1168998) so we should
@@ -167,25 +176,31 @@ public final class IntentHelper implemen
             marketIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
             activity.startActivity(marketIntent);
 
         } else if (intent.hasExtra(EXTRA_BROWSER_FALLBACK_URL)) {
             final String fallbackUrl = intent.getStringExtra(EXTRA_BROWSER_FALLBACK_URL);
             Tabs.getInstance().loadUrl(fallbackUrl);
 
         }  else {
-            displayToastCannotOpenLink();
+            openUnknownProtocolErrorPage(intent.getData().toString());
             // Don't log the URI to prevent leaking it.
-            Log.w(LOGTAG, "Unable to handle URI");
+            Log.w(LOGTAG, "Unable to open URI, default case - loading about:neterror");
         }
     }
 
-    private void displayToastCannotOpenLink() {
-        final String errText = activity.getResources().getString(R.string.intent_uri_cannot_open);
-        Toast.makeText(activity, errText, Toast.LENGTH_LONG).show();
+    /**
+     * Opens about:neterror with the unknownProtocolFound text.
+     * @param encodedUri The encoded uri. While the page does not open correctly without specifying
+     *                   a uri parameter, it happily accepts the empty String so this argument may
+     *                   be the empty String.
+     */
+    private void openUnknownProtocolErrorPage(final String encodedUri) {
+        final String errorUri = UNKNOWN_PROTOCOL_URI_PREFIX + encodedUri;
+        Tabs.getInstance().loadUrl(errorUri);
     }
 
     private void openWebActivity(JSONObject message) throws JSONException {
         final Intent intent = WebActivityMapper.getIntentForWebActivity(message.getJSONObject("activity"));
         ActivityHandlerHelper.startIntentForActivity(activity, intent, new ResultHandler(message));
     }
 
     private static class ResultHandler implements ActivityResultHandler {