Bug 1367081 - Make PromptService usable from GeckoView custom tabs; r=droeh
authorJim Chen <nchen@mozilla.com>
Thu, 01 Jun 2017 15:07:16 -0400
changeset 410021 c77e79c09f1e6adf173e09ef829c96e507dbbb0d
parent 410020 3005c1464a2c90a7a2f711caf6466d1ab15cc628
child 410022 1d284663f05ddfc94fed8c44b552a383b9168610
push id7391
push usermtabara@mozilla.com
push dateMon, 12 Jun 2017 13:08:53 +0000
treeherdermozilla-beta@2191d7f87e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdroeh
bugs1367081
milestone55.0a1
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
Bug 1367081 - Make PromptService usable from GeckoView custom tabs; r=droeh Make PromptService and Prompt.jsm not depend as much on BrowserApp and the main Fennec window, so it can be used from a GeckoView-based custom tabs Activity. This approach is used because it involves a lot less work than trying to implement a PromptDelegate for Fennec. MozReview-Commit-ID: AEH0HgAOx2S
mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
mobile/android/base/java/org/mozilla/gecko/prompts/PromptService.java
mobile/android/modules/Prompt.jsm
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -1836,17 +1836,17 @@ public abstract class GeckoApp extends G
         // Check if launched from data reporting notification.
         if (ACTION_LAUNCH_SETTINGS.equals(action)) {
             Intent settingsIntent = new Intent(GeckoApp.this, GeckoPreferences.class);
             // Copy extras.
             settingsIntent.putExtras(intent.getUnsafe());
             startActivity(settingsIntent);
         }
 
-        mPromptService = new PromptService(this);
+        mPromptService = new PromptService(this, getAppEventDispatcher());
 
         // Trigger the completion of the telemetry timer that wraps activity startup,
         // then grab the duration to give to FHR.
         mJavaUiStartupTimer.stop();
         final long javaDuration = mJavaUiStartupTimer.getElapsed();
 
         ThreadUtils.getBackgroundHandler().postDelayed(new Runnable() {
             @Override
--- a/mobile/android/base/java/org/mozilla/gecko/prompts/PromptService.java
+++ b/mobile/android/base/java/org/mozilla/gecko/prompts/PromptService.java
@@ -1,50 +1,50 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * 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.prompts;
 
 import org.mozilla.gecko.EventDispatcher;
-import org.mozilla.gecko.GeckoApp;
-import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.util.BundleEventListener;
 import org.mozilla.gecko.util.EventCallback;
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.ThreadUtils;
 
 import android.content.Context;
 import android.util.Log;
 
 public class PromptService implements BundleEventListener {
     private static final String LOGTAG = "GeckoPromptService";
 
-    private final GeckoApp mGeckoApp;
+    private final Context mContext;
+    private final EventDispatcher mDispatcher;
 
-    public PromptService(GeckoApp geckoApp) {
-        mGeckoApp = geckoApp;
-        mGeckoApp.getAppEventDispatcher().registerUiThreadListener(this,
+    public PromptService(final Context context, final EventDispatcher dispatcher) {
+        mContext = context;
+        mDispatcher = dispatcher;
+        mDispatcher.registerUiThreadListener(this,
             "Prompt:Show",
             "Prompt:ShowTop");
     }
 
     public void destroy() {
-        mGeckoApp.getAppEventDispatcher().unregisterUiThreadListener(this,
+        mDispatcher.unregisterUiThreadListener(this,
             "Prompt:Show",
             "Prompt:ShowTop");
     }
 
     // BundleEventListener implementation
     @Override
     public void handleMessage(final String event, final GeckoBundle message,
                               final EventCallback callback) {
         Prompt p;
-        p = new Prompt(mGeckoApp, new Prompt.PromptCallback() {
+        p = new Prompt(mContext, new Prompt.PromptCallback() {
             @Override
             public void onPromptFinished(final GeckoBundle result) {
                 callback.sendSuccess(result);
             }
         });
         p.show(message);
     }
 }
--- a/mobile/android/modules/Prompt.jsm
+++ b/mobile/android/modules/Prompt.jsm
@@ -2,32 +2,43 @@
  * 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/. */
 "use strict"
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 
+Components.utils.import("resource://gre/modules/Messaging.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
 this.EXPORTED_SYMBOLS = ["Prompt"];
 
 function log(msg) {
   Services.console.logStringMessage(msg);
 }
 
+function getRootWindow(win) {
+  // Get the root xul window.
+  return win.QueryInterface(Ci.nsIInterfaceRequestor)
+            .getInterface(Ci.nsIDocShell).QueryInterface(Ci.nsIDocShellTreeItem)
+            .rootTreeItem.QueryInterface(Ci.nsIInterfaceRequestor)
+            .getInterface(Ci.nsIDOMWindow);
+}
+
 function Prompt(aOptions) {
   this.window = "window" in aOptions ? aOptions.window : null;
 
   this.msg = { async: true };
 
   if (this.window) {
-    let window = Services.wm.getMostRecentWindow("navigator:browser");
-    var tab = window.BrowserApp.getTabForWindow(this.window);
+    let window = getRootWindow(this.window);
+    var tab = window &&
+              window.BrowserApp &&
+              window.BrowserApp.getTabForWindow(this.window);
     if (tab) {
       this.msg.tabId = tab.id;
     }
   }
 
   if (aOptions.priority === 1)
     this.msg.type = "Prompt:ShowTop"
   else
@@ -169,21 +180,34 @@ Prompt.prototype = {
   },
 
   show: function(callback) {
     this.callback = callback;
     log("Sending message");
     this._innerShow();
   },
 
+  _getDispatcher: function(win) {
+    let root = win && getRootWindow(win);
+    try {
+      return root && (root.WindowEventDispatcher || EventDispatcher.for(root));
+    } catch (e) {
+      // No EventDispatcher for this window.
+      return null;
+    }
+  },
+
   _innerShow: function() {
-    let window = Services.wm.getMostRecentWindow("navigator:browser");
-    window.WindowEventDispatcher.sendRequestForResult(this.msg).then((data) => {
-      if (this.callback)
+    let dispatcher =
+        this._getDispatcher(this.window) ||
+        this._getDispatcher(Services.wm.getMostRecentWindow("navigator:browser"));
+    dispatcher.sendRequestForResult(this.msg).then((data) => {
+      if (this.callback) {
         this.callback(data);
+      }
     });
   },
 
   _setListItems: function(aItems) {
     let hasSelected = false;
     this.msg.listitems = [];
 
     aItems.forEach(function(item) {