Bug 1088220 - Switch to using DoorhangerConfig. r=margaret
authorChenxia Liu <liuche@mozilla.com>
Mon, 23 Mar 2015 20:34:58 -0700
changeset 266252 e734718125b0f7aceeae8c1d17acb78887ce3308
parent 266251 c8a569d73bb0744fa7a596ed60a17b1169a20cc3
child 266253 ebf592c2fa4c57503dd4498006e20162a5133a24
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmargaret
bugs1088220
milestone39.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 1088220 - Switch to using DoorhangerConfig. r=margaret
mobile/android/base/DoorHangerPopup.java
mobile/android/base/toolbar/SiteIdentityPopup.java
mobile/android/base/widget/DefaultDoorHanger.java
mobile/android/base/widget/DoorHanger.java
--- a/mobile/android/base/DoorHangerPopup.java
+++ b/mobile/android/base/DoorHangerPopup.java
@@ -11,23 +11,23 @@ import java.util.List;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.AppConstants.Versions;
 import org.mozilla.gecko.prompts.PromptInput;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.ThreadUtils;
 import org.mozilla.gecko.widget.AnchoredPopup;
-import org.mozilla.gecko.widget.DefaultDoorHanger;
 import org.mozilla.gecko.widget.DoorHanger;
 
 import android.content.Context;
 import android.util.Log;
 import android.view.View;
 import android.widget.CheckBox;
+import org.mozilla.gecko.widget.DoorhangerConfig;
 
 public class DoorHangerPopup extends AnchoredPopup
                              implements GeckoEventListener,
                                         Tabs.OnTabsChangedListener,
                                         DoorHanger.OnButtonClickListener {
     private static final String LOGTAG = "GeckoDoorHangerPopup";
 
     // Stores a set of all active DoorHanger notifications. A DoorHanger is
@@ -72,26 +72,22 @@ public class DoorHangerPopup extends Anc
         mDisabled = false;
         updatePopup();
     }
 
     @Override
     public void handleMessage(String event, JSONObject geckoObject) {
         try {
             if (event.equals("Doorhanger:Add")) {
-                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");
+                final DoorhangerConfig config = makeConfigFromJSON(geckoObject);
 
                 ThreadUtils.postToUiThread(new Runnable() {
                     @Override
                     public void run() {
-                        addDoorHanger(tabId, value, message, buttons, options);
+                        addDoorHanger(config);
                     }
                 });
             } else if (event.equals("Doorhanger:Remove")) {
                 final int tabId = geckoObject.getInt("tabID");
                 final String value = geckoObject.getString("value");
 
                 ThreadUtils.postToUiThread(new Runnable() {
                     @Override
@@ -105,16 +101,32 @@ public class DoorHangerPopup extends Anc
                     }
                 });
             }
         } catch (Exception e) {
             Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
+    private DoorhangerConfig makeConfigFromJSON(JSONObject json) throws JSONException {
+        final int tabId = json.getInt("tabID");
+        final String id = json.getString("value");
+        final DoorhangerConfig config = new DoorhangerConfig(tabId, id);
+
+        config.setMessage(json.getString("message"));
+        config.setButtons(json.getJSONArray("buttons"));
+        config.setOptions(json.getJSONObject("options"));
+        final String typeString = json.optString("category");
+        if (DoorHanger.Type.PASSWORD.toString().equals(typeString)) {
+            config.setType(DoorHanger.Type.PASSWORD);
+        }
+
+        return config;
+    }
+
     // This callback is automatically executed on the UI thread.
     @Override
     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>();
@@ -145,37 +157,36 @@ public class DoorHangerPopup extends Anc
         }
     }
 
     /**
      * 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) {
+    void addDoorHanger(DoorhangerConfig config) {
+        final int tabId = config.getTabId();
         // 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);
+        DoorHanger oldDoorHanger = getDoorHanger(tabId, config.getId());
         if (oldDoorHanger != null) {
             removeDoorHanger(oldDoorHanger);
         }
 
         if (!mInflated) {
             init();
         }
 
-        final DoorHanger newDoorHanger = new DefaultDoorHanger(mContext, tabId, value);
-        newDoorHanger.setMessage(message);
-        newDoorHanger.setOptions(options);
+        final DoorHanger newDoorHanger = DoorHanger.Get(mContext, config);
 
+        final JSONArray buttons = config.getButtons();
         for (int i = 0; i < buttons.length(); i++) {
             try {
                 JSONObject buttonObject = buttons.getJSONObject(i);
                 String label = buttonObject.getString("label");
                 String tag = String.valueOf(buttonObject.getInt("callback"));
                 newDoorHanger.addButton(label, tag, this);
             } catch (JSONException e) {
                 Log.e(LOGTAG, "Error creating doorhanger button", e);
--- a/mobile/android/base/toolbar/SiteIdentityPopup.java
+++ b/mobile/android/base/toolbar/SiteIdentityPopup.java
@@ -10,29 +10,29 @@ import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.SiteIdentity;
 import org.mozilla.gecko.SiteIdentity.SecurityMode;
 import org.mozilla.gecko.SiteIdentity.MixedMode;
 import org.mozilla.gecko.SiteIdentity.TrackingMode;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.widget.AnchoredPopup;
-import org.mozilla.gecko.widget.DefaultDoorHanger;
 import org.mozilla.gecko.widget.DoorHanger;
 import org.mozilla.gecko.widget.DoorHanger.OnButtonClickListener;
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.content.Context;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.LinearLayout;
 import android.widget.TextView;
+import org.mozilla.gecko.widget.DoorhangerConfig;
 
 /**
  * SiteIdentityPopup is a singleton class that displays site identity data in
  * an arrow panel popup hanging from the lock icon in the browser toolbar.
  */
 public class SiteIdentityPopup extends AnchoredPopup {
     private static final String LOGTAG = "GeckoSiteIdentityPopup";
 
@@ -136,32 +136,32 @@ public class SiteIdentityPopup extends A
         final String verifier = siteIdentity.getVerifier();
         final String encrypted = siteIdentity.getEncrypted();
         mVerifier.setText(verifier + "\n" + encrypted);
     }
 
     private void addMixedContentNotification(boolean blocked) {
         // Remove any existing mixed content notification.
         removeMixedContentNotification();
-        mMixedContentNotification = new DefaultDoorHanger(mContext, DoorHanger.Type.SITE);
 
+        final DoorhangerConfig config = new DoorhangerConfig();
         int icon;
-        String message;
         if (blocked) {
             icon = R.drawable.shield_enabled_doorhanger;
-            message = mContext.getString(R.string.blocked_mixed_content_message_top) + "\n\n" +
-                      mContext.getString(R.string.blocked_mixed_content_message_bottom);
+            config.setMessage(mContext.getString(R.string.blocked_mixed_content_message_top) + "\n\n" +
+                      mContext.getString(R.string.blocked_mixed_content_message_bottom));
         } else {
             icon = R.drawable.shield_disabled_doorhanger;
-            message = mContext.getString(R.string.loaded_mixed_content_message);
+            config.setMessage(mContext.getString(R.string.loaded_mixed_content_message));
         }
 
+        config.setLink(mContext.getString(R.string.learn_more), MIXED_CONTENT_SUPPORT_URL, "\n\n");
+        config.setType(DoorHanger.Type.SITE);
+        mMixedContentNotification = DoorHanger.Get(mContext, config);
         mMixedContentNotification.setIcon(icon);
-        mMixedContentNotification.setMessage(message);
-        mMixedContentNotification.addLink(mContext.getString(R.string.learn_more), MIXED_CONTENT_SUPPORT_URL, "\n\n");
 
         addNotificationButtons(mMixedContentNotification, blocked);
 
         mContent.addView(mMixedContentNotification);
         mDivider.setVisibility(View.VISIBLE);
     }
 
     private void removeMixedContentNotification() {
@@ -169,48 +169,51 @@ public class SiteIdentityPopup extends A
             mContent.removeView(mMixedContentNotification);
             mMixedContentNotification = null;
         }
     }
 
     private void addTrackingContentNotification(boolean blocked) {
         // Remove any existing tracking content notification.
         removeTrackingContentNotification();
-        mTrackingContentNotification = new DefaultDoorHanger(mContext, DoorHanger.Type.SITE);
+
+        final DoorhangerConfig config = new DoorhangerConfig();
 
         int icon;
-        String message;
         if (blocked) {
             icon = R.drawable.shield_enabled_doorhanger;
-            message = mContext.getString(R.string.blocked_tracking_content_message_top) + "\n\n" +
-                      mContext.getString(R.string.blocked_tracking_content_message_bottom);
+            config.setMessage(mContext.getString(R.string.blocked_tracking_content_message_top) + "\n\n" +
+                      mContext.getString(R.string.blocked_tracking_content_message_bottom));
         } else {
             icon = R.drawable.shield_disabled_doorhanger;
-            message = mContext.getString(R.string.loaded_tracking_content_message_top) + "\n\n" +
-                      mContext.getString(R.string.loaded_tracking_content_message_bottom);
+            config.setMessage(mContext.getString(R.string.loaded_tracking_content_message_top) + "\n\n" +
+                      mContext.getString(R.string.loaded_tracking_content_message_bottom));
         }
 
+        config.setLink(mContext.getString(R.string.learn_more), TRACKING_CONTENT_SUPPORT_URL, "\n\n");
+        config.setType(DoorHanger.Type.SITE);
+        mTrackingContentNotification = DoorHanger.Get(mContext, config);
+
         mTrackingContentNotification.setIcon(icon);
-        mTrackingContentNotification.setMessage(message);
-        mTrackingContentNotification.addLink(mContext.getString(R.string.learn_more), TRACKING_CONTENT_SUPPORT_URL, "\n\n");
 
         addNotificationButtons(mTrackingContentNotification, blocked);
 
         mContent.addView(mTrackingContentNotification);
         mDivider.setVisibility(View.VISIBLE);
     }
 
     private void removeTrackingContentNotification() {
         if (mTrackingContentNotification != null) {
             mContent.removeView(mTrackingContentNotification);
             mTrackingContentNotification = null;
         }
     }
 
     private void addNotificationButtons(DoorHanger dh, boolean blocked) {
+        // TODO: Add support for buttons in DoorHangerConfig.
         if (blocked) {
             dh.addButton(mContext.getString(R.string.disable_protection), "disable", mButtonClickListener);
             dh.addButton(mContext.getString(R.string.keep_blocking), "keepBlocking", mButtonClickListener);
         } else {
             dh.addButton(mContext.getString(R.string.enable_protection), "enable", mButtonClickListener);
         }
     }
 
--- a/mobile/android/base/widget/DefaultDoorHanger.java
+++ b/mobile/android/base/widget/DefaultDoorHanger.java
@@ -26,40 +26,48 @@ public class DefaultDoorHanger extends D
     private static final String LOGTAG = "GeckoDefaultDoorHanger";
 
     private final Resources mResources;
     private static int sSpinnerTextColor = -1;
 
     private List<PromptInput> mInputs;
     private CheckBox mCheckBox;
 
-    public DefaultDoorHanger(Context context) {
-
-        this(context, 0, null);
+    public DefaultDoorHanger(Context context, DoorhangerConfig config) {
+        this(context, config, Type.DEFAULT);
     }
 
-    public DefaultDoorHanger(Context context, Type type) {
-        this(context, 0, null, type);
-    }
-
-    public DefaultDoorHanger(Context context, int tabId, String id) {
-        this(context, tabId, id, Type.DEFAULT);
-    }
-
-    public DefaultDoorHanger(Context context, int tabId, String id, Type type) {
-
-        super(context, tabId, id, type);
+    public DefaultDoorHanger(Context context, DoorhangerConfig config, Type type) {
+        super(context, config, type);
 
         mResources = getResources();
 
         if (sSpinnerTextColor == -1) {
             sSpinnerTextColor = getResources().getColor(R.color.text_color_primary_disable_only);
         }
+        loadConfig(config);
     }
 
+    @Override
+    protected void loadConfig(DoorhangerConfig config) {
+        final String message = config.getMessage();
+        if (message != null) {
+            setMessage(message);
+        }
+
+        final JSONObject options = config.getOptions();
+        if (options != null) {
+            setOptions(options);
+        }
+
+        final DoorhangerConfig.Link link = config.getLink();
+        if (link != null) {
+            addLink(link.label, link.url, link.delimiter);
+        }
+    }
 
     @Override
     public List<PromptInput> getInputs() {
         return mInputs;
     }
 
     @Override
     public CheckBox getCheckBox() {
--- a/mobile/android/base/widget/DoorHanger.java
+++ b/mobile/android/base/widget/DoorHanger.java
@@ -1,14 +1,14 @@
 /* -*- 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.widget;
+package org.mozilla.gecko.widget;
 
 import android.content.Context;
 import android.text.Html;
 import android.text.SpannableString;
 import android.text.Spanned;
 import android.text.method.LinkMovementMethod;
 import android.text.style.ForegroundColorSpan;
 import android.text.style.URLSpan;
@@ -23,17 +23,31 @@ import org.json.JSONObject;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Tabs;
 import org.mozilla.gecko.prompts.PromptInput;
 
 import java.util.List;
 
 public abstract class DoorHanger extends LinearLayout {
 
+    public static DoorHanger Get(Context context, DoorhangerConfig config) {
+        final Type type = config.getType();
+        if (type != null) {
+            switch (type) {
+                case PASSWORD:
+                case SITE:
+                    return new DefaultDoorHanger(context, config, type);
+            }
+        }
+
+        return new DefaultDoorHanger(context, config);
+    }
+
     public static enum Type { DEFAULT, PASSWORD, SITE }
+
     public interface OnButtonClickListener {
         public void onButtonClick(DoorHanger dh, String tag);
     }
 
     private static final LayoutParams sButtonParams;
     static {
         sButtonParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1.0f);
     }
@@ -49,38 +63,29 @@ public abstract class DoorHanger extends
     private final int mTabId;
 
     // DoorHanger identifier.
     private final String mIdentifier;
 
     private final ImageView mIcon;
     private final TextView mMessage;
 
+    protected Context mContext;
+
     protected int mDividerColor;
 
     protected boolean mPersistWhileVisible;
     protected int mPersistenceCount;
     protected long mTimeout;
 
-    public DoorHanger(Context context) {
-        this(context, 0, null);
-    }
-
-    public DoorHanger(Context context, int tabId, String id) {
-        this(context, tabId, id, Type.DEFAULT);
-    }
-    public DoorHanger(Context context, int tabId, String id, Type type) {
-        this(context, tabId, id, type, null);
-    }
-
-    public DoorHanger(Context context, int tabId, String id, Type type, JSONObject options) {
+    protected DoorHanger(Context context, DoorhangerConfig config, Type type) {
         super(context);
-
-        mTabId = tabId;
-        mIdentifier = id;
+        mContext = context;
+        mTabId = config.getTabId();
+        mIdentifier = config.getId();
 
         int resource;
         switch (type) {
             case PASSWORD:
                 // TODO: switch to R.layout.password
                 resource = R.layout.doorhanger;
                 break;
             default:
@@ -92,25 +97,22 @@ public abstract class DoorHanger extends
         mIcon = (ImageView) findViewById(R.id.doorhanger_icon);
         mMessage = (TextView) findViewById(R.id.doorhanger_message);
         if (type == Type.SITE) {
             mMessage.setTextAppearance(getContext(), R.style.TextAppearance_Widget_DoorHanger_Small);
         }
         mButtonsContainer = (LinearLayout) findViewById(R.id.doorhanger_buttons);
 
         mDividerColor = getResources().getColor(R.color.divider_light);
-
-        if (options != null) {
-            setOptions(options);
-        }
-
         setOrientation(VERTICAL);
     }
 
-    public void setOptions(final JSONObject options) {
+    abstract protected void loadConfig(DoorhangerConfig config);
+
+    protected void setOptions(final JSONObject options) {
         final int persistence = options.optInt("persistence");
         if (persistence > 0) {
             mPersistenceCount = persistence;
         }
 
         mPersistWhileVisible = options.optBoolean("persistWhileVisible");
 
         final long timeout = options.optLong("timeout");
@@ -135,23 +137,22 @@ public abstract class DoorHanger extends
         mDivider.setVisibility(View.GONE);
     }
 
     public void setIcon(int resId) {
         mIcon.setImageResource(resId);
         mIcon.setVisibility(View.VISIBLE);
     }
 
-    public void setMessage(String message) {
+    protected void setMessage(String message) {
         Spanned markupMessage = Html.fromHtml(message);
         mMessage.setText(markupMessage);
-        mMessage.setMovementMethod(LinkMovementMethod.getInstance());
     }
 
-    public void addLink(String label, String url, String delimiter) {
+    protected void addLink(String label, String url, String delimiter) {
         String title = mMessage.getText().toString();
         SpannableString titleWithLink = new SpannableString(title + delimiter + label);
         URLSpan linkSpan = new URLSpan(url) {
             @Override
             public void onClick(View view) {
                 Tabs.getInstance().loadUrlInTab(getURL());
             }
         };