Bug 1322586 - 4. Add and implement PermissionDelegate support; r=esawin draft
authorJim Chen <nchen@mozilla.com>
Thu, 20 Jul 2017 17:52:14 -0400
changeset 612609 7c0a4489b136100ca57740512436bb8cccc62f3a
parent 612608 fe949fde01ddba207b12f2bd49e52ea2bc8b8c5e
child 612610 3b4b770c606a9be3326bca3acd87770c5f8bb4fa
push id69550
push userbmo:nchen@mozilla.com
push dateThu, 20 Jul 2017 21:53:06 +0000
reviewersesawin
bugs1322586
milestone56.0a1
Bug 1322586 - 4. Add and implement PermissionDelegate support; r=esawin Add PermissionDelegate interface and implement support for Android and content permissions (WebRTC permissions will be implemented later). MozReview-Commit-ID: 1B2DUjh8Ajw
mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
@@ -183,16 +183,119 @@ public class GeckoView extends LayerView
                 if ("GeckoView:ScrollChanged".equals(event)) {
                     listener.onScrollChanged(GeckoView.this,
                                              message.getInt("scrollX"),
                                              message.getInt("scrollY"));
                 }
             }
         };
 
+    private final GeckoViewHandler<PermissionDelegate> mPermissionHandler =
+        new GeckoViewHandler<PermissionDelegate>(
+            "GeckoViewPermission", this,
+            new String[] {
+                "GeckoView:AndroidPermission",
+                "GeckoView:ContentPermission",
+                "GeckoView:MediaPermission"
+            }, /* alwaysListen */ true
+        ) {
+            @Override
+            public void handleMessage(final PermissionDelegate listener,
+                                      final String event,
+                                      final GeckoBundle message,
+                                      final EventCallback callback) {
+
+                if (listener == null) {
+                    callback.sendSuccess(/* granted */ false);
+                    return;
+                }
+                if ("GeckoView:AndroidPermission".equals(event)) {
+                    listener.requestAndroidPermissions(
+                            GeckoView.this, message.getStringArray("perms"),
+                            new PermissionCallback("android", callback));
+                } else if ("GeckoView:ContentPermission".equals(event)) {
+                    final String type = message.getString("perm");
+                    listener.requestContentPermission(
+                            GeckoView.this, message.getString("uri"),
+                            type, message.getString("access"),
+                            new PermissionCallback(type, callback));
+                } else if ("GeckoView:MediaPermission".equals(event)) {
+                    listener.requestMediaPermission(
+                            GeckoView.this, message.getString("uri"),
+                            message.getBundleArray("video"), message.getBundleArray("audio"),
+                            new PermissionCallback("media", callback));
+                }
+            }
+        };
+
+    private static class PermissionCallback implements
+        PermissionDelegate.Callback, PermissionDelegate.MediaCallback {
+
+        private final String mType;
+        private EventCallback mCallback;
+
+        public PermissionCallback(final String type, final EventCallback callback) {
+            mType = type;
+            mCallback = callback;
+        }
+
+        private void submit(final Object response) {
+            if (mCallback != null) {
+                mCallback.sendSuccess(response);
+                mCallback = null;
+            }
+        }
+
+        @Override // PermissionDelegate.Callback
+        public void grant() {
+            if ("media".equals(mType)) {
+                throw new UnsupportedOperationException();
+            }
+            submit(/* response */ true);
+        }
+
+        @Override // PermissionDelegate.Callback, PermissionDelegate.MediaCallback
+        public void reject() {
+            submit(/* response */ false);
+        }
+
+        @Override // PermissionDelegate.MediaCallback
+        public void grant(final String video, final String audio) {
+            if (!"media".equals(mType)) {
+                throw new UnsupportedOperationException();
+            }
+            final GeckoBundle response = new GeckoBundle(2);
+            response.putString("video", video);
+            response.putString("audio", audio);
+            submit(response);
+        }
+
+        @Override // PermissionDelegate.MediaCallback
+        public void grant(final GeckoBundle video, final GeckoBundle audio) {
+            grant(video != null ? video.getString("id") : null,
+                  audio != null ? audio.getString("id") : null);
+        }
+    }
+
+    /**
+     * Get the current prompt delegate for this GeckoView.
+     * @return PromptDelegate instance or null if using default delegate.
+     */
+    public PermissionDelegate getPermissionDelegate() {
+        return mPermissionHandler.getListener();
+    }
+
+    /**
+     * Set the current permission delegate for this GeckoView.
+     * @param delegate PermissionDelegate instance or null to use the default delegate.
+     */
+    public void setPermissionDelegate(final PermissionDelegate delegate) {
+        mPermissionHandler.setListener(delegate, this);
+    }
+
     private PromptDelegate mPromptDelegate;
     private InputConnectionListener mInputConnectionListener;
 
     private GeckoViewSettings mSettings;
 
     protected boolean mOnAttachedToWindowCalled;
     protected String mChromeUri;
     protected int mScreenId = 0; // default to the primary screen
@@ -1572,9 +1675,128 @@ public class GeckoView extends LayerView
          * The scroll position of the content has changed.
          *
         * @param view The GeckoView that initiated the callback.
         * @param scrollX The new horizontal scroll position in pixels.
         * @param scrollY The new vertical scroll position in pixels.
         */
         public void onScrollChanged(GeckoView view, int scrollX, int scrollY);
     }
+
+    /**
+     * GeckoView applications implement this interface to handle requests for permissions
+     * from content, such as geolocation and notifications. For each permission, usually
+     * two requests are generated: one request for the Android app permission through
+     * requestAppPermissions, which is typically handled by a system permission dialog;
+     * and another request for the content permission (e.g. through
+     * requestContentPermission), which is typically handled by an app-specific
+     * permission dialog.
+     **/
+    public interface PermissionDelegate {
+        /**
+         * Callback interface for notifying the result of a permission request.
+         */
+        interface Callback {
+            /**
+             * Called by the implementation after permissions are granted; the
+             * implementation must call either grant() or reject() for every request.
+             */
+            void grant();
+
+            /**
+             * Called by the implementation when permissions are not granted; the
+             * implementation must call either grant() or reject() for every request.
+             */
+            void reject();
+        }
+
+        /**
+         * Request Android app permissions.
+         *
+         * @param view GeckoView instance requesting the permissions.
+         * @param permissions List of permissions to request; possible values are,
+         *                    android.Manifest.permission.ACCESS_FINE_LOCATION
+         *                    android.Manifest.permission.CAMERA
+         *                    android.Manifest.permission.RECORD_AUDIO
+         * @param callback Callback interface.
+         */
+        void requestAndroidPermissions(GeckoView view, String[] permissions,
+                                       Callback callback);
+
+        /**
+         * Request content permission.
+         *
+         * @param view GeckoView instance requesting the permission.
+         * @param uri The URI of the content requesting the permission.
+         * @param type The type of the requested permission; possible values are,
+         *             "geolocation": permission for using the geolocation API
+         *             "desktop-notification": permission for using the notifications API
+         * @param access Not used.
+         * @param callback Callback interface.
+         */
+        void requestContentPermission(GeckoView view, String uri, String type,
+                                      String access, Callback callback);
+
+        /**
+         * Callback interface for notifying the result of a media permission request,
+         * including which media source(s) to use.
+         */
+        interface MediaCallback {
+            /**
+             * Called by the implementation after permissions are granted; the
+             * implementation must call one of grant() or reject() for every request.
+             *
+             * @param video "id" value from the bundle for the video source to use,
+             *              or null when video is not requested.
+             * @param audio "id" value from the bundle for the audio source to use,
+             *              or null when audio is not requested.
+             */
+            void grant(final String video, final String audio);
+
+            /**
+             * Called by the implementation after permissions are granted; the
+             * implementation must call one of grant() or reject() for every request.
+             *
+             * @param video Bundle for the video source to use (must be an original
+             *              GeckoBundle object that was passed to the implementation);
+             *              or null when video is not requested.
+             * @param audio Bundle for the audio source to use (must be an original
+             *              GeckoBundle object that was passed to the implementation);
+             *              or null when audio is not requested.
+             */
+            void grant(final GeckoBundle video, final GeckoBundle audio);
+
+            /**
+             * Called by the implementation when permissions are not granted; the
+             * implementation must call one of grant() or reject() for every request.
+             */
+            void reject();
+        }
+
+        /**
+         * Request content media permissions, including request for which video and/or
+         * audio source to use.
+         *
+         * @param view GeckoView instance requesting the permission.
+         * @param uri The URI of the content requesting the permission.
+         * @param video List of video sources, or null if not requesting video.
+         *              Each bundle represents a video source, with keys,
+         *              "id": String, the origin-specific source identifier;
+         *              "rawId": String, the non-origin-specific source identifier;
+         *              "name": String, the name of the video source from the system
+         *                      (for example, "Camera 0, Facing back, Orientation 90");
+         *                      may be empty;
+         *              "mediaSource": String, the media source type; possible values are,
+         *                             "camera", "screen", "application", "window",
+         *                             "browser", and "other";
+         *              "type": String, always "video";
+         * @param audio List of audio sources, or null if not requesting audio.
+         *              Each bundle represents an audio source with same keys and possible
+         *              values as video source bundles above, except for:
+         *              "mediaSource", String; possible values are "microphone",
+         *                             "audioCapture", and "other";
+         *              "type", String, always "audio";
+         * @param callback Callback interface.
+         */
+        void requestMediaPermission(GeckoView view, String uri, GeckoBundle[] video,
+                                    GeckoBundle[] audio, MediaCallback callback);
+    }
 }