Bug 1253399 - Avoid crashes by checking for QR scanner app. r=sebastian
authorJ. Ryan Stinnett <jryans@gmail.com>
Fri, 10 Jun 2016 16:02:59 -0500
changeset 380938 7e6896f7bed599ef9121b5cc005162614ebf961f
parent 380903 a7e793ef71a31643eddd1bf7cb7a80b580cb8284
child 381127 1008f5b88e6bd223c16c3ec191302e5395187dc6
push id21354
push userbmo:jryans@gmail.com
push dateThu, 23 Jun 2016 18:06:20 +0000
reviewerssebastian
bugs1253399
milestone50.0a1
Bug 1253399 - Avoid crashes by checking for QR scanner app. r=sebastian MozReview-Commit-ID: 6bFrYyt4pzX
mobile/android/base/java/org/mozilla/gecko/DevToolsAuthHelper.java
mobile/android/chrome/content/RemoteDebugger.js
mobile/android/locales/en-US/chrome/browser.properties
--- a/mobile/android/base/java/org/mozilla/gecko/DevToolsAuthHelper.java
+++ b/mobile/android/base/java/org/mozilla/gecko/DevToolsAuthHelper.java
@@ -3,32 +3,45 @@
  * 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/. */
 
 package org.mozilla.gecko;
 
 import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.util.Log;
 import org.mozilla.gecko.util.ActivityResultHandler;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.InputOptionsUtils;
 
 /**
  * Supports the DevTools WiFi debugging authentication flow by invoking a QR decoder.
  */
 public class DevToolsAuthHelper {
 
+    private static final String LOGTAG = "GeckoDevToolsAuthHelper";
+
     public static void scan(Context context, final EventCallback callback) {
         final Intent intent = InputOptionsUtils.createQRCodeReaderIntent();
 
         intent.putExtra("PROMPT_MESSAGE", context.getString(R.string.devtools_auth_scan_header));
 
-        Activity activity = GeckoAppShell.getGeckoInterface().getActivity();
-        ActivityHandlerHelper.startIntentForActivity(activity, intent, new ActivityResultHandler() {
+        // Check ahead of time if an activity exists for the intent.  This
+        // avoids a case where we get both an ActivityNotFoundException *and*
+        // an activity result when the activity is missing.
+        PackageManager pm = context.getPackageManager();
+        if (pm.resolveActivity(intent, 0) == null) {
+            Log.w(LOGTAG, "PackageManager can't resolve the activity.");
+            callback.sendError("PackageManager can't resolve the activity.");
+            return;
+        }
+
+        ActivityHandlerHelper.startIntent(intent, new ActivityResultHandler() {
             @Override
             public void onActivityResult(int resultCode, Intent intent) {
                 if (resultCode == Activity.RESULT_OK) {
                     String text = intent.getStringExtra("SCAN_RESULT");
                     callback.sendSuccess(text);
                 } else {
                     callback.sendError(resultCode);
                 }
--- a/mobile/android/chrome/content/RemoteDebugger.js
+++ b/mobile/android/chrome/content/RemoteDebugger.js
@@ -150,16 +150,29 @@ var RemoteDebugger = {
     if (this._receivingOOB) {
       return this._receivingOOB;
     }
 
     this._receivingOOB = Messaging.sendRequestForResult({
       type: "DevToolsAuth:Scan"
     }).then(data => {
       return JSON.parse(data);
+    }, () => {
+      let title = Strings.browser.GetStringFromName("remoteQRScanFailedPromptTitle");
+      let msg = Strings.browser.GetStringFromName("remoteQRScanFailedPromptMessage");
+      let ok = Strings.browser.GetStringFromName("remoteQRScanFailedPromptOK");
+      let prompt = new Prompt({
+        window: null,
+        hint: "remotedebug",
+        title: title,
+        message: msg,
+        buttons: [ ok ],
+        priority: 1
+      });
+      prompt.show();
     });
 
     this._receivingOOB.then(() => this._receivingOOB = null);
 
     return this._receivingOOB;
   },
 
   initServer: function() {
--- a/mobile/android/locales/en-US/chrome/browser.properties
+++ b/mobile/android/locales/en-US/chrome/browser.properties
@@ -353,16 +353,28 @@ remoteIncomingPromptAllow=Allow
 # connection will be allowed assuming the scan succeeds.
 remoteIncomingPromptScan=Scan
 # LOCALIZATION NOTE (remoteIncomingPromptScanAndRemember): This button will
 # start a QR code scanner to authenticate an incoming remote debugger
 # connection.  The connection will be allowed assuming the scan succeeds, and
 # the other endpoint's certificate will be saved to skip future scans for this
 # client.
 remoteIncomingPromptScanAndRemember=Scan and Remember
+# LOCALIZATION NOTE (remoteQRScanFailedPromptTitle): The title displayed in a
+# dialog when we are unable to complete the QR code scan for an incoming remote
+# debugging connection.
+remoteQRScanFailedPromptTitle=QR Scan Failed
+# LOCALIZATION NOTE (remoteQRScanFailedPromptMessage): The message displayed in
+# a dialog when we are unable to complete the QR code scan for an incoming
+# remote debugging connection.
+remoteQRScanFailedPromptMessage=Unable to scan QR code for remote debugging. Verify that the Barcode Scanner app is installed and retry connecting.
+# LOCALIZATION NOTE (remoteQRScanFailedPromptOK): This button dismisses the
+# dialog that appears when we are unable to complete the QR code scan for an
+# incoming remote debugging connection.
+remoteQRScanFailedPromptOK=OK
 
 # LOCALIZATION NOTE (remoteNotificationTitle): %S is the name of the app.
 remoteNotificationTitle=%S debugging enabled
 # LOCALIZATION NOTE (remoteNotificationGenericName): a generic name to use
 # if the name of the app is not available.
 remoteNotificationGenericName=App
 # LOCALIZATION NOTE (remoteNotificationMessage): %S is the port on which
 # the remote debugger server is listening.