Bug 1388724 - 5. Make RuntimePermissions not depend on GeckoApp; r=sebastian draft
authorJim Chen <nchen@mozilla.com>
Fri, 18 Aug 2017 14:27:31 -0400
changeset 649165 b6d4613ee53eeb847759adb51e2eb4633641082b
parent 649164 83aff805bd08c820a9b79aea8ba418c226b32c79
child 649166 3b3007899bb791b09b35a6a7ab35924468acb6f1
push id74974
push userbmo:nchen@mozilla.com
push dateFri, 18 Aug 2017 18:32:22 +0000
reviewerssebastian
bugs1388724
milestone57.0a1
Bug 1388724 - 5. Make RuntimePermissions not depend on GeckoApp; r=sebastian Move the check permission event from `GeckoApp` to `GeckoApplication`, and use the current activity if possible, so that we can use `RuntimePermissions` in custom tabs and PWA. Also implement `onRequestPermissionsResult` for custom tabs and PWA, in order to forward the result back to `RuntimePermissions`. MozReview-Commit-ID: Bg4BoXAUCz6
mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
mobile/android/modules/RuntimePermissions.jsm
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -735,39 +735,16 @@ public abstract class GeckoApp extends G
 
         } else if ("Permissions:Data".equals(event)) {
             final GeckoBundle[] permissions = message.getBundleArray("permissions");
             showSiteSettingsDialog(permissions);
 
         } else if ("PrivateBrowsing:Data".equals(event)) {
             mPrivateBrowsingSession = message.getString("session");
 
-        } else if ("RuntimePermissions:Check".equals(event)) {
-            final String[] permissions = message.getStringArray("permissions");
-            final boolean shouldPrompt = message.getBoolean("shouldPrompt", false);
-            if (callback == null || permissions == null) {
-                return;
-            }
-
-            Permissions.from(this)
-                    .withPermissions(permissions)
-                    .doNotPromptIf(!shouldPrompt)
-                    .andFallback(new Runnable() {
-                        @Override
-                        public void run() {
-                            callback.sendSuccess(false);
-                        }
-                    })
-                    .run(new Runnable() {
-                        @Override
-                        public void run() {
-                            callback.sendSuccess(true);
-                        }
-                    });
-
         } else if ("Share:Text".equals(event)) {
             final String text = message.getString("text");
             final Tab tab = Tabs.getInstance().getSelectedTab();
             String title = "";
             if (tab != null) {
                 title = tab.getDisplayTitle();
             }
             IntentHelper.openUriExternal(text, "text/plain", "", "", Intent.ACTION_SEND, title, false);
@@ -1244,17 +1221,16 @@ public abstract class GeckoApp extends G
             "DevToolsAuth:Scan",
             "DOMFullScreen:Start",
             "DOMFullScreen:Stop",
             "Mma:reader_available",
             "Mma:web_save_image",
             "Mma:web_save_media",
             "Permissions:Data",
             "PrivateBrowsing:Data",
-            "RuntimePermissions:Check",
             "Share:Text",
             "SystemUI:Visibility",
             "ToggleChrome:Focus",
             "ToggleChrome:Hide",
             "ToggleChrome:Show",
             null);
 
         Tabs.getInstance().attachToContext(this, mLayerView, getAppEventDispatcher());
@@ -2237,17 +2213,16 @@ public abstract class GeckoApp extends G
             "DevToolsAuth:Scan",
             "DOMFullScreen:Start",
             "DOMFullScreen:Stop",
             "Mma:reader_available",
             "Mma:web_save_image",
             "Mma:web_save_media",
             "Permissions:Data",
             "PrivateBrowsing:Data",
-            "RuntimePermissions:Check",
             "Share:Text",
             "SystemUI:Visibility",
             "ToggleChrome:Focus",
             "ToggleChrome:Hide",
             "ToggleChrome:Show",
             null);
 
         if (mPromptService != null) {
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApplication.java
@@ -1,14 +1,15 @@
 /* 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/. */
 
 package org.mozilla.gecko;
 
+import android.app.Activity;
 import android.app.Application;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -36,16 +37,17 @@ import org.mozilla.gecko.icons.IconCallb
 import org.mozilla.gecko.icons.IconResponse;
 import org.mozilla.gecko.icons.Icons;
 import org.mozilla.gecko.lwt.LightweightTheme;
 import org.mozilla.gecko.mdns.MulticastDNSManager;
 import org.mozilla.gecko.media.AudioFocusAgent;
 import org.mozilla.gecko.media.RemoteManager;
 import org.mozilla.gecko.notifications.NotificationClient;
 import org.mozilla.gecko.notifications.NotificationHelper;
+import org.mozilla.gecko.permissions.Permissions;
 import org.mozilla.gecko.preferences.DistroSharedPrefsImport;
 import org.mozilla.gecko.util.ActivityUtils;
 import org.mozilla.gecko.telemetry.TelemetryBackgroundReceiver;
 import org.mozilla.gecko.util.BundleEventListener;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.HardwareUtils;
 import org.mozilla.gecko.util.PRNGFixes;
@@ -276,16 +278,17 @@ public class GeckoApplication extends Ap
 
         MulticastDNSManager.getInstance(context).init();
 
         GeckoService.register();
 
         final EventListener listener = new EventListener();
         EventDispatcher.getInstance().registerUiThreadListener(listener,
                 "Gecko:Exited",
+                "RuntimePermissions:Check",
                 null);
         EventDispatcher.getInstance().registerBackgroundThreadListener(listener,
                 "Profile:Create",
                 null);
 
         super.onCreate();
     }
 
@@ -410,16 +413,40 @@ public class GeckoApplication extends Ap
                 if (message.getBoolean("restart")) {
                     restartIntent = new Intent(Intent.ACTION_MAIN);
                     restartIntent.setClassName(GeckoAppShell.getApplicationContext(),
                                                AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS);
                 } else {
                     restartIntent = null;
                 }
                 shutdown(restartIntent);
+
+            } else if ("RuntimePermissions:Check".equals(event)) {
+                final String[] permissions = message.getStringArray("permissions");
+                final boolean shouldPrompt = message.getBoolean("shouldPrompt", false);
+                final Activity currentActivity =
+                        GeckoActivityMonitor.getInstance().getCurrentActivity();
+                final Context context = (currentActivity != null) ?
+                        currentActivity : GeckoAppShell.getApplicationContext();
+
+                Permissions.from(context)
+                           .withPermissions(permissions)
+                           .doNotPromptIf(!shouldPrompt || currentActivity == null)
+                           .andFallback(new Runnable() {
+                               @Override
+                               public void run() {
+                                   callback.sendSuccess(false);
+                               }
+                           })
+                           .run(new Runnable() {
+                               @Override
+                               public void run() {
+                                   callback.sendSuccess(true);
+                               }
+                           });
             }
         }
     }
 
     public boolean isApplicationInBackground() {
         return mInBackground;
     }
 
--- a/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/customtabs/CustomTabsActivity.java
@@ -37,16 +37,17 @@ import org.mozilla.gecko.GeckoView;
 import org.mozilla.gecko.GeckoViewSettings;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.SnackbarBuilder;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.menu.GeckoMenu;
 import org.mozilla.gecko.menu.GeckoMenuInflater;
 import org.mozilla.gecko.mozglue.SafeIntent;
+import org.mozilla.gecko.permissions.Permissions;
 import org.mozilla.gecko.prompts.PromptService;
 import org.mozilla.gecko.util.ActivityUtils;
 import org.mozilla.gecko.util.Clipboard;
 import org.mozilla.gecko.util.ColorUtil;
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.IntentUtils;
 import org.mozilla.gecko.widget.GeckoPopupMenu;
 
@@ -133,16 +134,22 @@ public class CustomTabsActivity extends 
 
     @Override
     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
         if (!ActivityHandlerHelper.handleActivityResult(requestCode, resultCode, data)) {
             super.onActivityResult(requestCode, resultCode, data);
         }
     }
 
+    @Override
+    public void onRequestPermissionsResult(final int requestCode, final String[] permissions,
+                                           final int[] grantResults) {
+        Permissions.onRequestPermissionsResult(this, permissions, grantResults);
+    }
+
     private void sendTelemetry() {
         final SafeIntent startIntent = new SafeIntent(getIntent());
 
         Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT, "customtab");
         if (IntentUtil.hasToolbarColor(startIntent)) {
             Telemetry.sendUIEvent(TelemetryContract.Event.LOAD_URL, TelemetryContract.Method.INTENT, "customtab-hasToolbarColor");
         }
         if (IntentUtil.hasActionButton(startIntent)) {
--- a/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
+++ b/mobile/android/base/java/org/mozilla/gecko/webapps/WebAppActivity.java
@@ -32,16 +32,17 @@ import org.json.JSONException;
 import org.mozilla.gecko.ActivityHandlerHelper;
 import org.mozilla.gecko.AppConstants;
 import org.mozilla.gecko.DoorHangerPopup;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoView;
 import org.mozilla.gecko.GeckoViewSettings;
 import org.mozilla.gecko.icons.decoders.FaviconDecoder;
 import org.mozilla.gecko.icons.decoders.LoadFaviconResult;
+import org.mozilla.gecko.permissions.Permissions;
 import org.mozilla.gecko.prompts.PromptService;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.util.ColorUtil;
 import org.mozilla.gecko.util.FileUtils;
 
 public class WebAppActivity extends AppCompatActivity
                             implements GeckoView.NavigationListener {
     private static final String LOGTAG = "WebAppActivity";
@@ -116,16 +117,22 @@ public class WebAppActivity extends AppC
     @Override
     public void onActivityResult(int requestCode, int resultCode, Intent data) {
         if (!ActivityHandlerHelper.handleActivityResult(requestCode, resultCode, data)) {
             super.onActivityResult(requestCode, resultCode, data);
         }
     }
 
     @Override
+    public void onRequestPermissionsResult(final int requestCode, final String[] permissions,
+                                           final int[] grantResults) {
+        Permissions.onRequestPermissionsResult(this, permissions, grantResults);
+    }
+
+    @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
 
         outState.putParcelable(SAVED_INTENT, getIntent());
     }
 
     private void loadManifest(String manifestPath) {
         if (AppConstants.Versions.feature21Plus) {
--- a/mobile/android/modules/RuntimePermissions.jsm
+++ b/mobile/android/modules/RuntimePermissions.jsm
@@ -3,17 +3,20 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 this.EXPORTED_SYMBOLS = ["RuntimePermissions"];
 
-Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "EventDispatcher",
+                                  "resource://gre/modules/Messaging.jsm");
 
 // See: http://developer.android.com/reference/android/Manifest.permission.html
 const ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION";
 const CAMERA = "android.permission.CAMERA";
 const RECORD_AUDIO = "android.permission.RECORD_AUDIO";
 const WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE";
 
 var RuntimePermissions = {
@@ -32,18 +35,17 @@ var RuntimePermissions = {
     let permissions = [].concat(permission);
 
     let msg = {
       type: "RuntimePermissions:Check",
       permissions: permissions,
       shouldPrompt: true
     };
 
-    let window = Services.wm.getMostRecentWindow("navigator:browser");
-    return window.WindowEventDispatcher.sendRequestForResult(msg);
+    return EventDispatcher.instance.sendRequestForResult(msg);
   },
 
   /**
     * Check whether the specified permissions have already been granted or not.
     *
     * @returns A promise resolving to true if all the permissions are already granted or false if any of the
     *          permissions are not granted.
     */
@@ -51,12 +53,11 @@ var RuntimePermissions = {
     let permissions = [].concat(permission);
 
     let msg = {
       type: "RuntimePermissions:Check",
       permissions: permissions,
       shouldPrompt: false
     };
 
-    let window = Services.wm.getMostRecentWindow("navigator:browser");
-    return window.WindowEventDispatcher.sendRequestForResult(msg);
+    return EventDispatcher.instance.sendRequestForResult(msg);
   }
 };