Bug 781259 - Move DoorHangerPopup code to UI thread. r=mfinkle
authorBrian Nicholson <bnicholson@mozilla.com>
Tue, 30 Oct 2012 10:31:29 -0700
changeset 111886 c6cccc9e83fabb2bd6a9a2d85b6f2d4af199bbf4
parent 111885 a2a201dd7a85b0a123ad929d146f76a0a3491b9e
child 111887 a5ab93cf9feaaecd2d983536d3c29830ea00c48a
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersmfinkle
bugs781259
milestone19.0a1
Bug 781259 - Move DoorHangerPopup code to UI thread. r=mfinkle
mobile/android/base/DoorHangerPopup.java
mobile/android/chrome/content/browser.js
--- a/mobile/android/base/DoorHangerPopup.java
+++ b/mobile/android/base/DoorHangerPopup.java
@@ -61,43 +61,49 @@ public class DoorHangerPopup extends Pop
 
     void setAnchor(View aAnchor) {
         mAnchor = aAnchor;
     }
 
     public void handleMessage(String event, JSONObject geckoObject) {
         try {
             if (event.equals("Doorhanger:Add")) {
-                int tabId = geckoObject.getInt("tabID");
-                String value = geckoObject.getString("value");
-                String message = geckoObject.getString("message");
-                JSONArray buttons = geckoObject.getJSONArray("buttons");
-                JSONObject options = geckoObject.getJSONObject("options");
+                final int tabId = geckoObject.getInt("tabID");
+                final String value = geckoObject.getString("value");
+                final String message = geckoObject.getString("message");
+                final JSONArray buttons = geckoObject.getJSONArray("buttons");
+                final JSONObject options = geckoObject.getJSONObject("options");
 
-                addDoorHanger(tabId, value, message, buttons, options);
-            } else if (event.equals("Doorhanger:Remove")) {
-                int tabId = geckoObject.getInt("tabID");
-                String value = geckoObject.getString("value");
-                DoorHanger doorHanger = getDoorHanger(tabId, value);
-                if (doorHanger == null)
-                    return;
-
-                removeDoorHanger(doorHanger);
                 mActivity.runOnUiThread(new Runnable() {
                     public void run() {
+                        addDoorHanger(tabId, value, message, buttons, options);
+                    }
+                });
+            } else if (event.equals("Doorhanger:Remove")) {
+                final int tabId = geckoObject.getInt("tabID");
+                final String value = geckoObject.getString("value");
+
+                mActivity.runOnUiThread(new Runnable() {
+                    public void run() {
+                        DoorHanger doorHanger = getDoorHanger(tabId, value);
+                        if (doorHanger == null)
+                            return;
+
+                        removeDoorHanger(doorHanger);
                         updatePopup();
                     }
                 });
             }
         } catch (Exception e) {
             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
-    public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
+    // This callback is automatically executed on the UI thread.
+    public void onTabChanged(final Tab tab, final Tabs.TabEvents msg, final Object data) {
         switch(msg) {
             case CLOSED:
                 // Remove any doorhangers for a tab when it's closed (make
                 // a temporary set to avoid a ConcurrentModificationException)
                 HashSet<DoorHanger> doorHangersToRemove = new HashSet<DoorHanger>();
                 for (DoorHanger dh : mDoorHangers) {
                     if (dh.getTabId() == tab.getId())
                         doorHangersToRemove.add(dh);
@@ -135,81 +141,95 @@ public class DoorHangerPopup extends Pop
         RelativeLayout layout = (RelativeLayout) inflater.inflate(R.layout.doorhangerpopup, null);
         mArrow = (ImageView) layout.findViewById(R.id.doorhanger_arrow);
         mContent = (LinearLayout) layout.findViewById(R.id.doorhanger_container);
         
         setContentView(layout);
         mInflated = true;
     }
 
+    /**
+     * Adds a doorhanger.
+     *
+     * This method must be called on the UI thread.
+     */
     void addDoorHanger(final int tabId, final String value, final String message,
                        final JSONArray buttons, final JSONObject options) {
         // Don't add a doorhanger for a tab that doesn't exist
         if (Tabs.getInstance().getTab(tabId) == null)
             return;
 
         // Replace the doorhanger if it already exists
         DoorHanger oldDoorHanger = getDoorHanger(tabId, value);
         if (oldDoorHanger != null)
             removeDoorHanger(oldDoorHanger);
 
         final DoorHanger newDoorHanger = new DoorHanger(mActivity, this, tabId, value);
         mDoorHangers.add(newDoorHanger);
 
-        // Update the UI bits on the main thread
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                if (!mInflated)
-                    init();
+        if (!mInflated)
+            init();
 
-                newDoorHanger.init(message, buttons, options);
-                mContent.addView(newDoorHanger);
+        newDoorHanger.init(message, buttons, options);
+        mContent.addView(newDoorHanger);
 
-                // Only update the popup if we're adding a notifcation to the selected tab
-                if (tabId == Tabs.getInstance().getSelectedTab().getId())
-                    updatePopup();
-            }
-        });
+        // Only update the popup if we're adding a notifcation to the selected tab
+        if (tabId == Tabs.getInstance().getSelectedTab().getId())
+            updatePopup();
     }
 
+    /**
+     * Gets a doorhanger.
+     *
+     * This method must be called on the UI thread.
+     */
     DoorHanger getDoorHanger(int tabId, String value) {
         for (DoorHanger dh : mDoorHangers) {
             if (dh.getTabId() == tabId && dh.getValue().equals(value))
                 return dh;
         }
 
         // If there's no doorhanger for the given tabId and value, return null
         return null;
     }
 
+    /**
+     * Removes a doorhanger.
+     *
+     * This method must be called on the UI thread.
+     */
     void removeDoorHanger(final DoorHanger doorHanger) {
         mDoorHangers.remove(doorHanger);
-
-        // Update the UI on the main thread
-        mActivity.runOnUiThread(new Runnable() {
-            public void run() {
-                mContent.removeView(doorHanger);
-            }
-        });        
+        mContent.removeView(doorHanger);
     }
 
+    /**
+     * Removes doorhangers for a given tab.
+     *
+     * This method must be called on the UI thread.
+     */
     void removeTransientDoorHangers(int tabId) {
         // Make a temporary set to avoid a ConcurrentModificationException
         HashSet<DoorHanger> doorHangersToRemove = new HashSet<DoorHanger>();
         for (DoorHanger dh : mDoorHangers) {
             // Only remove transient doorhangers for the given tab
             if (dh.getTabId() == tabId && dh.shouldRemove())
                 doorHangersToRemove.add(dh);
         }
 
         for (DoorHanger dh : doorHangersToRemove) {
             removeDoorHanger(dh);
         }
     }
 
+    /**
+     * Updates the popup state.
+     *
+     * This method must be called on the UI thread.
+     */
     void updatePopup() {
         // Bail if the selected tab is null, if there are no active doorhangers,
         // or if we haven't inflated the layout yet (this can happen if updatePopup()
         // is called before the runnable from addDoorHanger() runs). 
         Tab tab = Tabs.getInstance().getSelectedTab();
         if (tab == null || mDoorHangers.size() == 0 || !mInflated) {
             dismiss();
             return;
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -6940,20 +6940,17 @@ var Telemetry = {
     let message = Strings.browser.formatStringFromName("telemetry.optin.message2", [serverOwner, brandShortName], 2);
     let learnMoreLabel = Strings.browser.GetStringFromName("telemetry.optin.learnMore");
     let learnMoreUrl = Services.urlFormatter.formatURLPref("app.support.baseURL");
     learnMoreUrl += "how-can-i-help-submitting-performance-data";
     let options = {
       link: {
         label: learnMoreLabel,
         url: learnMoreUrl
-      },
-      // We're adding this doorhanger during startup, before the initial onLocationChange
-      // event fires, so we need to set persistence to make sure it doesn't disappear.
-      persistence: 1
+      }
     };
     NativeWindow.doorhanger.show(message, "telemetry-optin", buttons, BrowserApp.selectedTab.id, options);
   },
 };
 
 let Reader = {
   // Version of the cache database schema
   DB_VERSION: 1,