Back out cf876b6ac843 (bug 1168980) for Android xpcshell crashes in test_redirect-caching_failure.js and test_redirect_failure.js
authorPhil Ringnalda <philringnalda@gmail.com>
Mon, 15 Jun 2015 21:00:36 -0700
changeset 249086 2271296e404ad8e3926c4bc54571dfa63fd33b16
parent 249085 7d94ea57d5a0bd964e65eb4db9b778dbfcab0dc3
child 249087 1edffee3ccb1a75039773f6bf744797489c0e7d3
push id61139
push usercbook@mozilla.com
push dateTue, 16 Jun 2015 14:53:44 +0000
treeherdermozilla-inbound@7299b8b5a8a1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1168980
milestone41.0a1
backs outcf876b6ac84324ed182b221b4f6425c10a3ce099
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
Back out cf876b6ac843 (bug 1168980) for Android xpcshell crashes in test_redirect-caching_failure.js and test_redirect_failure.js CLOSED TREE
mobile/android/base/IntentHelper.java
mobile/android/base/locales/en-US/android_strings.dtd
mobile/android/base/strings.xml.in
mobile/android/components/ContentDispatchChooser.js
mobile/android/locales/en-US/chrome/handling.properties
--- a/mobile/android/base/IntentHelper.java
+++ b/mobile/android/base/IntentHelper.java
@@ -11,39 +11,29 @@ import org.mozilla.gecko.util.JSONUtils;
 import org.mozilla.gecko.util.WebActivityMapper;
 
 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.net.URISyntaxException;
 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",
         "Intent:OpenForResult",
-        "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";
-
     private static IntentHelper instance;
 
     private final Activity activity;
 
     private IntentHelper(Activity activity) {
         this.activity = activity;
         EventDispatcher.getInstance().registerGeckoThreadListener(this, EVENTS);
     }
@@ -69,18 +59,16 @@ public final class IntentHelper implemen
     public void handleMessage(String event, JSONObject message) {
         try {
             if (event.equals("Intent:GetHandlers")) {
                 getHandlers(message);
             } else if (event.equals("Intent:Open")) {
                 open(message);
             } else if (event.equals("Intent:OpenForResult")) {
                 openForResult(message);
-            } else if (event.equals("Intent:OpenNoHandler")) {
-                openNoHandler(message);
             } else if (event.equals("WebActivity:Open")) {
                 openWebActivity(message);
             }
         } catch (JSONException e) {
             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
@@ -118,76 +106,16 @@ public final class IntentHelper implemen
         final ResultHandler handler = new ResultHandler(message);
         try {
             ActivityHandlerHelper.startIntentForActivity(activity, intent, handler);
         } catch (SecurityException e) {
             Log.w(LOGTAG, "Forbidden to launch activity.", e);
         }
     }
 
-    /**
-     * Opens a URI without any valid handlers on device. In the best case, a package is specified
-     * 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...");
-            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();
-            // Don't log the exception to prevent leaking URIs.
-            Log.w(LOGTAG, "Unable to parse Intent URI");
-            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
-        // ignore it here too.
-        //
-        // Our old flow used to prompt the user to search for their app in the market by scheme and
-        // while this could help the user find a new app, there is not always a correlation in
-        // scheme to application name and we could end up steering the user wrong (potentially to
-        // malicious software). Better to leave that one alone.
-        if (intent.getPackage() != null) {
-            final String marketUri = MARKET_INTENT_URI_PACKAGE_PREFIX + intent.getPackage();
-            final Intent marketIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(marketUri));
-            marketIntent.addCategory(Intent.CATEGORY_BROWSABLE);
-            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();
-            // Don't log the URI to prevent leaking it.
-            Log.w(LOGTAG, "Unable to handle URI");
-        }
-    }
-
-    private void displayToastCannotOpenLink() {
-        final String errText = activity.getResources().getString(R.string.intent_uri_cannot_open);
-        Toast.makeText(activity, errText, Toast.LENGTH_LONG).show();
-    }
-
     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 {
         private final JSONObject message;
 
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -654,10 +654,8 @@ just addresses the organization to follo
 <!ENTITY remote_tabs_last_synced "Last synced: &formatS;">
 <!-- Localization note: Used when the sync has not happend yet, showed in place of a date -->
 <!ENTITY remote_tabs_never_synced "Last synced: never">
 
 <!-- Find-In-Page strings -->
 <!-- LOCALIZATION NOTE (find_matchcase): This is meant to appear as an icon that changes color
      if match-case is activated. i.e. No more than two letters, one uppercase, one lowercase. -->
 <!ENTITY find_matchcase "Aa">
-
-<!ENTITY intent_uri_cannot_open "Cannot open link">
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -533,11 +533,9 @@
   <!-- Miscellaneous -->
   <string name="ellipsis">&ellipsis;</string>
 
   <string name="colon">&colon;</string>
 
   <string name="percent">&percent;</string>
 
   <string name="remote_tabs_last_synced">&remote_tabs_last_synced;</string>
-
-  <string name="intent_uri_cannot_open">&intent_uri_cannot_open;</string>
 </resources>
--- a/mobile/android/components/ContentDispatchChooser.js
+++ b/mobile/android/components/ContentDispatchChooser.js
@@ -20,35 +20,57 @@ ContentDispatchChooser.prototype =
 
   get protoSvc() {
     if (!this._protoSvc) {
       this._protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"].getService(Ci.nsIExternalProtocolService);
     }
     return this._protoSvc;
   },
 
+  _getChromeWin: function getChromeWin() {
+    try {
+      return Services.wm.getMostRecentWindow("navigator:browser");
+    } catch (e) {
+      throw Cr.NS_ERROR_FAILURE;
+    }
+  },
+
   ask: function ask(aHandler, aWindowContext, aURI, aReason) {
     let window = null;
     try {
       if (aWindowContext)
         window = aWindowContext.getInterface(Ci.nsIDOMWindow);
     } catch (e) { /* it's OK to not have a window */ }
 
     // The current list is based purely on the scheme. Redo the query using the url to get more
     // specific results.
     aHandler = this.protoSvc.getProtocolHandlerInfoFromOS(aURI.spec, {});
 
     // The first handler in the set is the Android Application Chooser (which will fall back to a default if one is set)
     // If we have more than one option, let the OS handle showing a list (if needed).
     if (aHandler.possibleApplicationHandlers.length > 1) {
       aHandler.launchWithURI(aURI, aWindowContext);
     } else {
-      let msg = {
-        type: "Intent:OpenNoHandler",
-        uri: aURI.spec,
-      };
+      let win = this._getChromeWin();
+      if (win && win.NativeWindow) {
+        let bundle = Services.strings.createBundle("chrome://browser/locale/handling.properties");
+        let failedText = bundle.GetStringFromName("protocol.failed");
+        let searchText = bundle.GetStringFromName("protocol.toast.search");
 
-      Messaging.sendRequest(msg);
+        win.NativeWindow.toast.show(failedText, "long", {
+          button: {
+            label: searchText,
+            callback: function() {
+              let message = {
+                type: "Intent:Open",
+                url: "market://search?q=" + aURI.scheme,
+              };
+
+              Messaging.sendRequest(message);
+            }
+          }
+        });
+      }
     }
   },
 };
 
 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentDispatchChooser]);
--- a/mobile/android/locales/en-US/chrome/handling.properties
+++ b/mobile/android/locales/en-US/chrome/handling.properties
@@ -1,5 +1,8 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 download.blocked=Unable to download file
+protocol.failed=Couldn't find an app to open this link
+# A very short string shown in the button toast when no application can open the url
+protocol.toast.search=Search