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 254756 d43113d59aabb39bc5d8c855baab358d9fc0cb8a
parent 254755 c607be4ebbd8eab060752e5cd347a494b315281b
child 254757 c2e8b03c28bcd3ed17fa46ae5041841204028450
push id16720
push userryanvm@gmail.com
push dateMon, 27 Jul 2015 19:45:38 +0000
treeherderb2g-inbound@13354b414396 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmargaret
bugs1162372
milestone42.0a1
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 {