Bug 1333589 - 3. Convert SiteIdentityPopup observers to events; r=sebastian
authorJim Chen <nchen@mozilla.com>
Wed, 25 Jan 2017 18:57:32 -0500
changeset 466669 c09b8f1c7934e6bb844a29f67d1ce6a610ee74f9
parent 466668 114c35019621332a2d5113b63db03a99526af820
child 466670 c8145ad1dcf8d8e5d8387063d8ea8f22e600cfef
push id42948
push userbmo:gasolin@mozilla.com
push dateThu, 26 Jan 2017 07:49:21 +0000
reviewerssebastian
bugs1333589
milestone54.0a1
Bug 1333589 - 3. Convert SiteIdentityPopup observers to events; r=sebastian Convert the "Permissions:*" and "Session:Reload" observers to events that go through GlobalEventDispatcher.
mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
mobile/android/base/java/org/mozilla/gecko/Tab.java
mobile/android/base/java/org/mozilla/gecko/toolbar/SiteIdentityPopup.java
mobile/android/chrome/content/PermissionsHelper.js
mobile/android/chrome/content/browser.js
mobile/android/tests/browser/robocop/testTrackingProtection.js
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -860,22 +860,26 @@ public abstract class GeckoApp
 
         builder.setPositiveButton(R.string.site_settings_clear, new DialogInterface.OnClickListener() {
             @Override
             public void onClick(DialogInterface dialog, int id) {
                 ListView listView = ((AlertDialog) dialog).getListView();
                 SparseBooleanArray checkedItemPositions = listView.getCheckedItemPositions();
 
                 // An array of the indices of the permissions we want to clear
-                JSONArray permissionsToClear = new JSONArray();
-                for (int i = 0; i < checkedItemPositions.size(); i++)
-                    if (checkedItemPositions.get(i))
-                        permissionsToClear.put(i);
-
-                GeckoAppShell.notifyObservers("Permissions:Clear", permissionsToClear.toString());
+                final ArrayList<Integer> permissionsToClear = new ArrayList<>();
+                for (int i = 0; i < checkedItemPositions.size(); i++) {
+                    if (checkedItemPositions.get(i)) {
+                        permissionsToClear.add(i);
+                    }
+                }
+
+                final GeckoBundle data = new GeckoBundle(1);
+                data.putIntArray("permissions", permissionsToClear);
+                EventDispatcher.getInstance().dispatch("Permissions:Clear", data);
             }
         });
 
         builder.setNegativeButton(R.string.site_settings_cancel, new DialogInterface.OnClickListener() {
             @Override
             public void onClick(DialogInterface dialog, int id) {
                 dialog.cancel();
             }
--- a/mobile/android/base/java/org/mozilla/gecko/Tab.java
+++ b/mobile/android/base/java/org/mozilla/gecko/Tab.java
@@ -567,17 +567,19 @@ public class Tab {
         ReadingListHelper.removeCachedReaderItem(pageUrl, mAppContext);
     }
 
     public boolean isEnteringReaderMode() {
         return mEnteringReaderMode;
     }
 
     public void doReload(boolean bypassCache) {
-        GeckoAppShell.notifyObservers("Session:Reload", "{\"bypassCache\":" + String.valueOf(bypassCache) + "}");
+        final GeckoBundle data = new GeckoBundle(1);
+        data.putBoolean("bypassCache", bypassCache);
+        EventDispatcher.getInstance().dispatch("Session:Reload", data);
     }
 
     // Our version of nsSHistory::GetCanGoBack
     public boolean canDoBack() {
         return mCanDoBack;
     }
 
     public boolean doBack() {
--- a/mobile/android/base/java/org/mozilla/gecko/toolbar/SiteIdentityPopup.java
+++ b/mobile/android/base/java/org/mozilla/gecko/toolbar/SiteIdentityPopup.java
@@ -148,17 +148,17 @@ public class SiteIdentityPopup extends A
                                          siteIdentity.getSecurityMode() == SecurityMode.VERIFIED);
         updateConnectionState(siteIdentity);
         toggleIdentityKnownContainerVisibility(isIdentityKnown);
 
         if (isIdentityKnown) {
             updateIdentityInformation(siteIdentity);
         }
 
-        GeckoAppShell.notifyObservers("Permissions:Check", null);
+        EventDispatcher.getInstance().dispatch("Permissions:Check", null);
     }
 
     @Override // BundleEventListener
     public void handleMessage(final String event, final GeckoBundle geckoObject,
                               final EventCallback callback) {
         if ("Doorhanger:Logins".equals(event)) {
             final Tab selectedTab = Tabs.getInstance().getSelectedTab();
             if (selectedTab != null) {
@@ -170,17 +170,17 @@ public class SiteIdentityPopup extends A
             }
 
         } else if ("Permissions:CheckResult".equals(event)) {
             final boolean hasPermissions = geckoObject.getBoolean("hasPermissions", false);
             if (hasPermissions) {
                 mSiteSettingsLink.setOnClickListener(new View.OnClickListener() {
                     @Override
                     public void onClick(View v) {
-                        GeckoAppShell.notifyObservers("Permissions:Get", null);
+                        EventDispatcher.getInstance().dispatch("Permissions:Get", null);
                         dismiss();
                     }
                 });
             }
             mSiteSettingsLink.setVisibility(hasPermissions ? View.VISIBLE : View.GONE);
         }
     }
 
@@ -547,13 +547,13 @@ public class SiteIdentityPopup extends A
         removeSelectLoginDoorhanger();
         TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(mTitle, null, null, null, null);
         mDivider.setVisibility(View.GONE);
     }
 
     private class ContentNotificationButtonListener implements OnButtonClickListener {
         @Override
         public void onButtonClick(final GeckoBundle response, final DoorHanger doorhanger) {
-            GeckoAppShell.notifyObservers("Session:Reload", response.toString());
+            EventDispatcher.getInstance().dispatch("Session:Reload", response);
             dismiss();
         }
     }
 }
--- a/mobile/android/chrome/content/PermissionsHelper.js
+++ b/mobile/android/chrome/content/PermissionsHelper.js
@@ -50,23 +50,25 @@ var PermissionsHelper = {
     },
     "native-intent": {
       label: "helperapps.openWithList2",
       allowed: "helperapps.always",
       denied: "helperapps.never"
     }
   },
 
-  observe: function observe(aSubject, aTopic, aData) {
+  onEvent: function onEvent(event, data, callback) {
     let uri = BrowserApp.selectedBrowser.currentURI;
     let check = false;
 
-    switch (aTopic) {
+    switch (event) {
       case "Permissions:Check":
         check = true;
+        // fall-through
+
       case "Permissions:Get":
         let permissions = [];
         for (let i = 0; i < this._permissonTypes.length; i++) {
           let type = this._permissonTypes[i];
           let value = this.getPermission(uri, type);
 
           // Only add the permission if it was set by the user
           if (value == Services.perms.UNKNOWN_ACTION)
@@ -109,17 +111,17 @@ var PermissionsHelper = {
         WindowEventDispatcher.sendRequest({
           type: "Permissions:Data",
           permissions: permissions
         });
         break;
  
       case "Permissions:Clear":
         // An array of the indices of the permissions we want to clear
-        let permissionsToClear = JSON.parse(aData);
+        let permissionsToClear = data.permissions;
         let privacyContext = BrowserApp.selectedBrowser.docShell
                                .QueryInterface(Ci.nsILoadContext);
 
         for (let i = 0; i < permissionsToClear.length; i++) {
           let indexToClear = permissionsToClear[i];
           let permissionType = this._currentPermissions[indexToClear]["type"];
           this.clearPermission(uri, permissionType, privacyContext);
         }
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -150,17 +150,16 @@ lazilyLoadedBrowserScripts.forEach(funct
     Services.scriptloader.loadSubScript(script, sandbox);
     return sandbox[name];
   });
 });
 
 var lazilyLoadedObserverScripts = [
   ["MemoryObserver", ["memory-pressure", "Memory:Dump"], "chrome://browser/content/MemoryObserver.js"],
   ["ConsoleAPI", ["console-api-log-event"], "chrome://browser/content/ConsoleAPI.js"],
-  ["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"],
 ];
 
 if (AppConstants.MOZ_WEBRTC) {
@@ -238,16 +237,19 @@ lazilyLoadedObserverScripts.forEach(func
    "chrome://browser/content/ActionBarHandler.js"],
   ["FindHelper", GlobalEventDispatcher,
    ["FindInPage:Opened", "FindInPage:Closed"],
    "chrome://browser/content/FindHelper.js"],
   ["Home", GlobalEventDispatcher,
    ["HomeBanner:Get", "HomePanels:Get", "HomePanels:Authenticate",
     "HomePanels:RefreshView", "HomePanels:Installed", "HomePanels:Uninstalled"],
    "resource://gre/modules/Home.jsm"],
+  ["PermissionsHelper", GlobalEventDispatcher,
+   ["Permissions:Check", "Permissions:Get", "Permissions:Clear"],
+   "chrome://browser/content/PermissionsHelper.js"],
 ].forEach(module => {
   let [name, dispatcher, events, script] = module;
   XPCOMUtils.defineLazyGetter(window, name, function() {
     let sandbox = {};
     if (script.endsWith(".jsm")) {
       Cu.import(script, sandbox);
     } else {
       Services.scriptloader.loadSubScript(script, sandbox);
@@ -377,24 +379,24 @@ var BrowserApp = {
 
     Services.androidBridge.browserApp = this;
 
     GlobalEventDispatcher.registerListener(this, [
       "Tab:Load",
       "Tab:Selected",
       "Tab:Closed",
       "Browser:LoadManifest",
+      "Session:Reload",
     ]);
 
     Services.obs.addObserver(this, "Locale:OS", false);
     Services.obs.addObserver(this, "Locale:Changed", false);
     Services.obs.addObserver(this, "Session:Back", false);
     Services.obs.addObserver(this, "Session:Forward", false);
     Services.obs.addObserver(this, "Session:Navigate", false);
-    Services.obs.addObserver(this, "Session:Reload", false);
     Services.obs.addObserver(this, "Session:Stop", false);
     Services.obs.addObserver(this, "SaveAs:PDF", false);
     Services.obs.addObserver(this, "Browser:Quit", false);
     Services.obs.addObserver(this, "ScrollTo:FocusedInput", false);
     Services.obs.addObserver(this, "Sanitize:ClearData", false);
     Services.obs.addObserver(this, "FullScreen:Exit", false);
     Services.obs.addObserver(this, "Passwords:Init", false);
     Services.obs.addObserver(this, "FormHistory:Init", false);
@@ -1633,16 +1635,68 @@ var BrowserApp = {
             start_url: manifest.data.start_url
           });
         }).catch(err => {
           Cu.reportError("Failed to install " + data.src);
         });
         break;
       }
 
+      case "Session:Reload": {
+        let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
+
+        // Check to see if this is a message to enable/disable mixed content blocking.
+        if (data) {
+          if (data.bypassCache) {
+            flags |= Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE |
+                     Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY;
+          }
+
+          if (data.contentType === "tracking") {
+            // Convert document URI into the format used by
+            // nsChannelClassifier::ShouldEnableTrackingProtection
+            // (any scheme turned into https is correct)
+            let normalizedUrl = Services.io.newURI("https://" + browser.currentURI.hostPort);
+            if (data.allowContent) {
+              // Add the current host in the 'trackingprotection' consumer of
+              // the permission manager using a normalized URI. This effectively
+              // places this host on the tracking protection white list.
+              if (PrivateBrowsingUtils.isBrowserPrivate(browser)) {
+                PrivateBrowsingUtils.addToTrackingAllowlist(normalizedUrl);
+              } else {
+                Services.perms.add(normalizedUrl, "trackingprotection", Services.perms.ALLOW_ACTION);
+                Telemetry.addData("TRACKING_PROTECTION_EVENTS", 1);
+              }
+            } else {
+              // Remove the current host from the 'trackingprotection' consumer
+              // of the permission manager. This effectively removes this host
+              // from the tracking protection white list (any list actually).
+              if (PrivateBrowsingUtils.isBrowserPrivate(browser)) {
+                PrivateBrowsingUtils.removeFromTrackingAllowlist(normalizedUrl);
+              } else {
+                Services.perms.remove(normalizedUrl, "trackingprotection");
+                Telemetry.addData("TRACKING_PROTECTION_EVENTS", 2);
+              }
+            }
+          }
+        }
+
+        // Try to use the session history to reload so that framesets are
+        // handled properly. If the window has no session history, fall back
+        // to using the web navigation's reload method.
+        let webNav = browser.webNavigation;
+        try {
+          let sh = webNav.sessionHistory;
+          if (sh)
+            webNav = sh.QueryInterface(Ci.nsIWebNavigation);
+        } catch (e) {}
+        webNav.reload(flags);
+        break;
+      }
+
       case "Tab:Load": {
         let url = data.url;
         let flags = Ci.nsIWebNavigation.LOAD_FLAGS_ALLOW_THIRD_PARTY_FIXUP
                   | Ci.nsIWebNavigation.LOAD_FLAGS_FIXUP_SCHEME_TYPOS;
 
         // Pass LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL to prevent any loads from
         // inheriting the currently loaded document's principal.
         if (data.userEntered) {
@@ -1722,70 +1776,16 @@ var BrowserApp = {
           } else if (index >= historySize) {
             Log.e("Browser", "Incorrect index " + index + " truncated to " + historySize - 1);
             index = historySize - 1;
           }
 
           browser.gotoIndex(index);
           break;
 
-      case "Session:Reload": {
-        let flags = Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
-
-        // Check to see if this is a message to enable/disable mixed content blocking.
-        if (aData) {
-          let data = JSON.parse(aData);
-
-          if (data.bypassCache) {
-            flags |= Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE |
-                     Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_PROXY;
-          }
-
-          if (data.contentType === "tracking") {
-            // Convert document URI into the format used by
-            // nsChannelClassifier::ShouldEnableTrackingProtection
-            // (any scheme turned into https is correct)
-            let normalizedUrl = Services.io.newURI("https://" + browser.currentURI.hostPort);
-            if (data.allowContent) {
-              // Add the current host in the 'trackingprotection' consumer of
-              // the permission manager using a normalized URI. This effectively
-              // places this host on the tracking protection white list.
-              if (PrivateBrowsingUtils.isBrowserPrivate(browser)) {
-                PrivateBrowsingUtils.addToTrackingAllowlist(normalizedUrl);
-              } else {
-                Services.perms.add(normalizedUrl, "trackingprotection", Services.perms.ALLOW_ACTION);
-                Telemetry.addData("TRACKING_PROTECTION_EVENTS", 1);
-              }
-            } else {
-              // Remove the current host from the 'trackingprotection' consumer
-              // of the permission manager. This effectively removes this host
-              // from the tracking protection white list (any list actually).
-              if (PrivateBrowsingUtils.isBrowserPrivate(browser)) {
-                PrivateBrowsingUtils.removeFromTrackingAllowlist(normalizedUrl);
-              } else {
-                Services.perms.remove(normalizedUrl, "trackingprotection");
-                Telemetry.addData("TRACKING_PROTECTION_EVENTS", 2);
-              }
-            }
-          }
-        }
-
-        // Try to use the session history to reload so that framesets are
-        // handled properly. If the window has no session history, fall back
-        // to using the web navigation's reload method.
-        let webNav = browser.webNavigation;
-        try {
-          let sh = webNav.sessionHistory;
-          if (sh)
-            webNav = sh.QueryInterface(Ci.nsIWebNavigation);
-        } catch (e) {}
-        webNav.reload(flags);
-        break;
-      }
-
       case "Session:Stop":
         browser.stop();
         break;
 
       case "keyword-search":
         // This event refers to a search via the URL bar, not a bookmarks
         // keyword search. Note that this code assumes that the user can only
         // perform a keyword search on the selected tab.
@@ -2169,18 +2169,20 @@ var BrowserApp = {
       "historyItems": listitems,
       "toIndex": toIndex
     };
   },
 };
 
 var NativeWindow = {
   init: function() {
+    GlobalEventDispatcher.registerListener(this, [
+      "Doorhanger:Reply",
+    ]);
     Services.obs.addObserver(this, "Menu:Clicked", false);
-    Services.obs.addObserver(this, "Doorhanger:Reply", false);
     this.contextmenus.init();
   },
 
   loadDex: function(zipFile, implClass) {
     GlobalEventDispatcher.sendRequest({
       type: "Dex:Load",
       zipfile: zipFile,
       impl: implClass || "Main"
@@ -2302,22 +2304,18 @@ var NativeWindow = {
       WindowEventDispatcher.sendRequest({
         type: "Doorhanger:Remove",
         value: aValue,
         tabID: aTabID
       });
     }
   },
 
-  observe: function(aSubject, aTopic, aData) {
-    if (aTopic == "Menu:Clicked") {
-      if (this.menu._callbacks[aData])
-        this.menu._callbacks[aData]();
-    } else if (aTopic == "Doorhanger:Reply") {
-      let data = JSON.parse(aData);
+  onEvent: function (event, data, callback) {
+    if (event == "Doorhanger:Reply") {
       let reply_id = data["callback"];
 
       if (this.doorhanger._callbacks[reply_id]) {
         // Pass the value of the optional checkbox to the callback
         let checked = data["checked"];
         this.doorhanger._callbacks[reply_id].cb(checked, data.inputs);
 
         let prompt = this.doorhanger._callbacks[reply_id].prompt;
@@ -2325,16 +2323,23 @@ var NativeWindow = {
           if (this.doorhanger._callbacks[id].prompt == prompt) {
             delete this.doorhanger._callbacks[id];
           }
         }
       }
     }
   },
 
+  observe: function(aSubject, aTopic, aData) {
+    if (aTopic == "Menu:Clicked") {
+      if (this.menu._callbacks[aData])
+        this.menu._callbacks[aData]();
+    }
+  },
+
   contextmenus: {
     items: {}, //  a list of context menu items that we may show
     DEFAULT_HTML5_ORDER: -1, // Sort order for HTML5 context menu items
 
     init: function() {
       // Accessing "NativeWindow.contextmenus" initializes context menus if needed.
       BrowserApp.deck.addEventListener(
           "contextmenu", (e) => NativeWindow.contextmenus.show(e));
--- a/mobile/android/tests/browser/robocop/testTrackingProtection.js
+++ b/mobile/android/tests/browser/robocop/testTrackingProtection.js
@@ -106,23 +106,29 @@ add_task(function* test_tracking_pb() {
 
   // Point tab to a test page containing tracking elements
   yield promiseLoadEvent(browser, "http://tracking.example.org/tests/robocop/tracking_bad.html");
   Messaging.sendRequest({ type: "Test:Expected", expected: "tracking_content_blocked" });
 
   // Simulate a click on the "Disable protection" button in the site identity popup.
   // We need to wait for a "load" event because "Session:Reload" will cause a full page reload.
   yield promiseLoadEvent(browser, undefined, undefined, () => {
-    Services.obs.notifyObservers(null, "Session:Reload", "{\"allowContent\":true,\"contentType\":\"tracking\"}");
+    EventDispatcher.instance.dispatch("Session:Reload", {
+      allowContent: true,
+      contentType: "tracking",
+    });
   });
   Messaging.sendRequest({ type: "Test:Expected", expected: "tracking_content_loaded" });
 
   // Simulate a click on the "Enable protection" button in the site identity popup.
   yield promiseLoadEvent(browser, undefined, undefined, () => {
-    Services.obs.notifyObservers(null, "Session:Reload", "{\"allowContent\":false,\"contentType\":\"tracking\"}");
+    EventDispatcher.instance.dispatch("Session:Reload", {
+      allowContent: false,
+      contentType: "tracking",
+    });
   });
   Messaging.sendRequest({ type: "Test:Expected", expected: "tracking_content_blocked" });
 
   // Disable tracking protection to make sure we don't show the UI when the pref is disabled.
   Services.prefs.setBoolPref("privacy.trackingprotection.pbmode.enabled", false);
 
   // Point tab to a test page containing tracking elements
   yield promiseLoadEvent(browser, "http://tracking.example.org/tests/robocop/tracking_bad.html");