Bug 1330411 - 1. Convert ActionBarHandler observers to events; r=sebastian
authorJim Chen <nchen@mozilla.com>
Wed, 25 Jan 2017 18:53:58 -0500
changeset 331057 65b07eac83b329667ae01b036e7e5f5b067c31c4
parent 331056 2740c0e269054538fe69c6ed5b6afe82d9407370
child 331058 14bd5683877aca3615acb06b92edb9ec4bd31eab
push id86160
push usernchen@mozilla.com
push dateWed, 25 Jan 2017 23:54:26 +0000
treeherdermozilla-inbound@3c1089284c75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssebastian
bugs1330411
milestone54.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 1330411 - 1. Convert ActionBarHandler observers to events; r=sebastian Convert observers in ActionBarHandler.js to events that go through WindowEventDispatcher. "TextSelection:Get" now replies through the callback interface rather than a "TextSelection:Data" event. The patch also adds new lazy-loading events in browser.js to replace the lazy-loading observers that ActionBarHandler relied on.
mobile/android/base/java/org/mozilla/gecko/ActionBarTextSelection.java
mobile/android/base/java/org/mozilla/gecko/text/FloatingActionModeCallback.java
mobile/android/base/java/org/mozilla/gecko/text/FloatingToolbarTextSelection.java
mobile/android/chrome/content/ActionBarHandler.js
mobile/android/chrome/content/browser.js
mobile/android/tests/browser/robocop/testAccessibleCarets.js
--- a/mobile/android/base/java/org/mozilla/gecko/ActionBarTextSelection.java
+++ b/mobile/android/base/java/org/mozilla/gecko/ActionBarTextSelection.java
@@ -13,19 +13,16 @@ import org.mozilla.gecko.util.EventCallb
 import org.mozilla.gecko.util.GeckoBundle;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.ActionModeCompat.Callback;
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
 import android.view.MenuItem;
 
-import org.json.JSONException;
-import org.json.JSONObject;
-
 import java.util.Arrays;
 import java.util.Timer;
 import java.util.TimerTask;
 
 import android.util.Log;
 
 class ActionBarTextSelection implements TextSelection, BundleEventListener {
     private static final String LOGTAG = "GeckoTextSelection";
@@ -208,29 +205,26 @@ class ActionBarTextSelection implements 
         public boolean onCreateActionMode(ActionModeCompat mode, GeckoMenu unused) {
             mActionMode = mode;
             return true;
         }
 
         @Override
         public boolean onActionItemClicked(ActionModeCompat mode, MenuItem item) {
             final GeckoBundle obj = mItems[item.getItemId()];
-            GeckoAppShell.notifyObservers("TextSelection:Action", obj.getString("id"));
+            final GeckoBundle data = new GeckoBundle(1);
+            data.putString("id", obj.getString("id"));
+            GeckoApp.getEventDispatcher().dispatch("TextSelection:Action", data);
             return true;
         }
 
         // Called when the user exits the action mode
         @Override
         public void onDestroyActionMode(ActionModeCompat mode) {
             mActionMode = null;
             mCallback = null;
-            final JSONObject args = new JSONObject();
-            try {
-                args.put("selectionID", selectionID);
-            } catch (JSONException e) {
-                Log.e(LOGTAG, "Error building JSON arguments for TextSelection:End", e);
-                return;
-            }
 
-            GeckoAppShell.notifyObservers("TextSelection:End", args.toString());
+            final GeckoBundle data = new GeckoBundle(1);
+            data.putInt("selectionID", selectionID);
+            GeckoApp.getEventDispatcher().dispatch("TextSelection:End", data);
         }
     }
 }
--- a/mobile/android/base/java/org/mozilla/gecko/text/FloatingActionModeCallback.java
+++ b/mobile/android/base/java/org/mozilla/gecko/text/FloatingActionModeCallback.java
@@ -7,17 +7,18 @@ package org.mozilla.gecko.text;
 import android.annotation.TargetApi;
 import android.graphics.Rect;
 import android.os.Build;
 import android.view.ActionMode;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.View;
 
-import org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.GeckoApp;
+import org.mozilla.gecko.util.GeckoBundle;
 
 import java.util.List;
 
 @TargetApi(Build.VERSION_CODES.M)
 public class FloatingActionModeCallback extends ActionMode.Callback2 {
     private FloatingToolbarTextSelection textSelection;
     private List<TextAction> actions;
 
@@ -46,17 +47,19 @@ public class FloatingActionModeCallback 
 
         return true;
     }
 
     @Override
     public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
         final TextAction action = actions.get(item.getItemId());
 
-        GeckoAppShell.notifyObservers("TextSelection:Action", action.getId());
+        final GeckoBundle data = new GeckoBundle(1);
+        data.putString("id", action.getId());
+        GeckoApp.getEventDispatcher().dispatch("TextSelection:Action", data);
 
         return true;
     }
 
     @Override
     public void onDestroyActionMode(ActionMode mode) {}
 
     @Override
--- a/mobile/android/base/java/org/mozilla/gecko/text/FloatingToolbarTextSelection.java
+++ b/mobile/android/base/java/org/mozilla/gecko/text/FloatingToolbarTextSelection.java
@@ -7,19 +7,16 @@ package org.mozilla.gecko.text;
 import android.annotation.TargetApi;
 import android.app.Activity;
 import android.graphics.Rect;
 import android.os.Build;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.ActionMode;
 
-import org.json.JSONException;
-import org.json.JSONObject;
-
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.GeckoApp;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.util.BundleEventListener;
 import org.mozilla.gecko.util.EventCallback;
@@ -68,25 +65,19 @@ public class FloatingToolbarTextSelectio
         return false;
     }
 
     private void endTextSelection() {
         if (selectionID == 0) {
             return;
         }
 
-        final JSONObject args = new JSONObject();
-        try {
-            args.put("selectionID", selectionID);
-        } catch (JSONException e) {
-            Log.e(LOGTAG, "Error building JSON arguments for TextSelection:End", e);
-            return;
-        }
-
-        GeckoAppShell.notifyObservers("TextSelection:End", args.toString());
+        final GeckoBundle data = new GeckoBundle(1);
+        data.putInt("selectionID", selectionID);
+        GeckoApp.getEventDispatcher().dispatch("TextSelection:End", data);
     }
 
     @Override
     public void create() {
         registerForEvents();
     }
 
     @Override
--- a/mobile/android/chrome/content/ActionBarHandler.js
+++ b/mobile/android/chrome/content/ActionBarHandler.js
@@ -83,49 +83,48 @@ var ActionBarHandler = {
         this._init(e.boundingClientRect);
       }
     }
   },
 
   /**
    * ActionBarHandler notification observers.
    */
-  observe: function(subject, topic, data) {
-    switch (topic) {
+  onEvent: function(event, data, callback) {
+    switch (event) {
       // User click an ActionBar button.
       case "TextSelection:Action": {
         if (!this._selectionID) {
           break;
         }
         for (let type in this.actions) {
           let action = this.actions[type];
-          if (action.id == data) {
+          if (action.id == data.id) {
             action.action(this._targetElement, this._contentWindow);
             break;
           }
         }
         break;
       }
 
       // Provide selected text to FindInPageBar on request.
       case "TextSelection:Get": {
-        Messaging.sendRequest({
-          type: "TextSelection:Data",
-          requestId: data,
-          text: this._getSelectedText(),
-        });
-
+        try {
+          callback.onSuccess(this._getSelectedText());
+        } catch (e) {
+          callback.onError(e.toString());
+        }
         this._uninit();
         break;
       }
 
       // User closed ActionBar by clicking "checkmark" button.
       case "TextSelection:End": {
         // End the requested selection only.
-        if (this._selectionID == JSON.parse(data).selectionID) {
+        if (this._selectionID == data.selectionID) {
           this._uninit();
         }
         break;
       }
     }
   },
 
   /**
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -4,22 +4,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 "use strict";
 
 var Cc = Components.classes;
 var Ci = Components.interfaces;
 var Cu = Components.utils;
 var Cr = Components.results;
 
+Cu.import("resource://gre/modules/AddonManager.jsm");
 Cu.import("resource://gre/modules/AppConstants.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/AddonManager.jsm");
 Cu.import("resource://gre/modules/AsyncPrefs.jsm");
 Cu.import("resource://gre/modules/DelayedInit.jsm");
+Cu.import("resource://gre/modules/Messaging.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 if (AppConstants.ACCESSIBILITY) {
   XPCOMUtils.defineLazyModuleGetter(this, "AccessFu",
                                     "resource://gre/modules/accessibility/AccessFu.jsm");
 }
 
 XPCOMUtils.defineLazyModuleGetter(this, "Manifest",
                                   "resource://gre/modules/Manifest.jsm");
@@ -40,22 +41,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/UITelemetry.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "PluralForm",
                                   "resource://gre/modules/PluralForm.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "Downloads",
                                   "resource://gre/modules/Downloads.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "EventDispatcher",
-                                  "resource://gre/modules/Messaging.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Messaging",
-                                  "resource://gre/modules/Messaging.jsm");
-
 XPCOMUtils.defineLazyModuleGetter(this, "UserAgentOverrides",
                                   "resource://gre/modules/UserAgentOverrides.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerContent",
                                   "resource://gre/modules/LoginManagerContent.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "LoginManagerParent",
                                   "resource://gre/modules/LoginManagerParent.jsm");
@@ -125,16 +120,19 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "RuntimePermissions", "resource://gre/modules/RuntimePermissions.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "WebsiteMetadata", "resource://gre/modules/WebsiteMetadata.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "FontEnumerator",
   "@mozilla.org/gfx/fontenumerator;1",
   "nsIFontEnumerator");
 
+var GlobalEventDispatcher = EventDispatcher.instance;
+var WindowEventDispatcher = EventDispatcher.for(window);
+
 var lazilyLoadedBrowserScripts = [
   ["SelectHelper", "chrome://browser/content/SelectHelper.js"],
   ["InputWidgetHelper", "chrome://browser/content/InputWidgetHelper.js"],
   ["MasterPassword", "chrome://browser/content/MasterPassword.js"],
   ["PluginHelper", "chrome://browser/content/PluginHelper.js"],
   ["OfflineApps", "chrome://browser/content/OfflineApps.js"],
   ["Linkifier", "chrome://browser/content/Linkify.js"],
   ["CastingApps", "chrome://browser/content/CastingApps.js"],
@@ -161,21 +159,16 @@ var lazilyLoadedObserverScripts = [
   ["PermissionsHelper", ["Permissions:Check", "Permissions:Get", "Permissions:Clear"], "chrome://browser/content/PermissionsHelper.js"],
   ["FeedHandler", ["Feeds:Subscribe"], "chrome://browser/content/FeedHandler.js"],
   ["Feedback", ["Feedback:Show"], "chrome://browser/content/Feedback.js"],
   ["EmbedRT", ["GeckoView:ImportScript"], "chrome://browser/content/EmbedRT.js"],
   ["Reader", ["Reader:AddToCache", "Reader:RemoveFromCache"], "chrome://browser/content/Reader.js"],
   ["PrintHelper", ["Print:PDF"], "chrome://browser/content/PrintHelper.js"],
 ];
 
-lazilyLoadedObserverScripts.push(
-["ActionBarHandler", ["TextSelection:Get", "TextSelection:Action", "TextSelection:End"],
-  "chrome://browser/content/ActionBarHandler.js"]
-);
-
 if (AppConstants.MOZ_WEBRTC) {
   lazilyLoadedObserverScripts.push(
     ["WebrtcUI", ["getUserMedia:request",
                   "PeerConnection:request",
                   "recording-device-events",
                   "VideoCapture:Paused",
                   "VideoCapture:Resumed"], "chrome://browser/content/WebrtcUI.js"])
 }
@@ -251,16 +244,36 @@ lazilyLoadedObserverScripts.forEach(func
     Services.obs.addObserver(this[name], t, false);
     this[name].observe(s, t, d); // Explicitly notify new observer
   };
   notifications.forEach(notification => {
     Services.obs.addObserver(observer, notification, false);
   });
 });
 
+// Lazily-loaded JS subscripts that use global/window EventDispatcher.
+[
+  ["ActionBarHandler", WindowEventDispatcher,
+   ["TextSelection:Get", "TextSelection:Action", "TextSelection:End"],
+   "chrome://browser/content/ActionBarHandler.js"],
+].forEach(module => {
+  let [name, dispatcher, events, script] = module;
+  XPCOMUtils.defineLazyGetter(window, name, function() {
+    let sandbox = {};
+    Services.scriptloader.loadSubScript(script, sandbox);
+    return sandbox[name];
+  });
+  let listener = (event, message, callback) => {
+    dispatcher.unregisterListener(listener, event);
+    dispatcher.registerListener(window[name], event);
+    window[name].onEvent(event, message, callback); // Explicitly notify new listener
+  };
+  dispatcher.registerListener(listener, events);
+});
+
 XPCOMUtils.defineLazyServiceGetter(this, "Haptic",
   "@mozilla.org/widget/hapticfeedback;1", "nsIHapticFeedback");
 
 XPCOMUtils.defineLazyServiceGetter(this, "ParentalControls",
   "@mozilla.org/parental-controls-service;1", "nsIParentalControlsService");
 
 XPCOMUtils.defineLazyServiceGetter(this, "DOMUtils",
   "@mozilla.org/inspector/dom-utils;1", "inIDOMUtils");
@@ -335,19 +348,16 @@ const kFormHelperModeDisabled = 0;
 const kFormHelperModeEnabled = 1;
 const kFormHelperModeDynamic = 2;   // disabled on tablets
 const kMaxHistoryListSize = 50;
 
 function InitLater(fn, object, name) {
   return DelayedInit.schedule(fn, object, name, 15000 /* 15s max wait */);
 }
 
-XPCOMUtils.defineLazyGetter(this, "GlobalEventDispatcher", () => EventDispatcher.instance);
-XPCOMUtils.defineLazyGetter(this, "WindowEventDispatcher", () => EventDispatcher.for(window));
-
 var BrowserApp = {
   _tabs: [],
   _selectedTab: null,
 
   get isTablet() {
     let sysInfo = Cc["@mozilla.org/system-info;1"].getService(Ci.nsIPropertyBag2);
     delete this.isTablet;
     return this.isTablet = sysInfo.get("tablet");
--- a/mobile/android/tests/browser/robocop/testAccessibleCarets.js
+++ b/mobile/android/tests/browser/robocop/testAccessibleCarets.js
@@ -139,18 +139,18 @@ function UIhasActionByID(expectedActionI
     return action.id === expectedActionID;
   });
 }
 
 /**
  * Messages the ActionBarHandler to close the Selection UI.
  */
 function closeSelectionUI() {
-  Services.obs.notifyObservers(null, "TextSelection:End",
-    JSON.stringify({selectionID: gChromeWin.ActionBarHandler._selectionID}));
+  gChromeWin.WindowEventDispatcher.dispatch("TextSelection:End",
+    {selectionID: gChromeWin.ActionBarHandler._selectionID});
 }
 
 /**
  * Main test method.
  */
 add_task(function* testAccessibleCarets() {
   // Wait to start loading our test page until after the initial browser tab is
   // completely loaded. This allows each tab to complete its layer initialization,