author | Chenxia Liu <liuche@mozilla.com> |
Mon, 30 Mar 2015 19:26:14 -0700 | |
changeset 238167 | cb1d3ae519ec05869d4e722dfb9142f391cdb7ab |
parent 238166 | 41a0c9bc40dfc529ee8f474e98f6ec61495d79f1 |
child 238168 | 904b5c1601f5d555383960a57676895c92598046 |
push id | 58133 |
push user | ryanvm@gmail.com |
push date | Wed, 08 Apr 2015 16:59:36 +0000 |
treeherder | mozilla-inbound@8911c111a6ad [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | margaret |
bugs | 1144385 |
milestone | 40.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
|
--- a/mobile/android/base/DoorHangerPopup.java +++ b/mobile/android/base/DoorHangerPopup.java @@ -1,32 +1,28 @@ /* -*- 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; import java.util.HashSet; -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.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"; @@ -104,25 +100,26 @@ 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); + + final String typeString = json.optString("category"); + final boolean isLogin = DoorHanger.Type.LOGIN.toString().equals(typeString); + final DoorHanger.Type doorhangerType = isLogin ? DoorHanger.Type.LOGIN : DoorHanger.Type.DEFAULT; + + final DoorhangerConfig config = new DoorhangerConfig(tabId, id, doorhangerType, this); config.setMessage(json.getString("message")); - config.setButtons(json.getJSONArray("buttons")); + config.appendButtonsFromJSON(json.getJSONArray("buttons")); config.setOptions(json.getJSONObject("options")); - final String typeString = json.optString("category"); - if (DoorHanger.Type.LOGIN.toString().equals(typeString)) { - config.setType(DoorHanger.Type.LOGIN); - } 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) { @@ -176,67 +173,33 @@ public class DoorHangerPopup extends Anc } if (!mInflated) { init(); } 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); - } - } - mDoorHangers.add(newDoorHanger); mContent.addView(newDoorHanger); // Only update the popup if we're adding a notification to the selected tab if (tabId == Tabs.getInstance().getSelectedTab().getId()) updatePopup(); } /* * DoorHanger.OnButtonClickListener implementation */ @Override - public void onButtonClick(DoorHanger dh, String tag) { - JSONObject response = new JSONObject(); - try { - response.put("callback", tag); - - CheckBox checkBox = dh.getCheckBox(); - // If the checkbox is being used, pass its value - if (checkBox != null) { - response.put("checked", checkBox.isChecked()); - } - - List<PromptInput> doorHangerInputs = dh.getInputs(); - if (doorHangerInputs != null) { - JSONObject inputs = new JSONObject(); - for (PromptInput input : doorHangerInputs) { - inputs.put(input.getId(), input.getValue()); - } - response.put("inputs", inputs); - } - } catch (JSONException e) { - Log.e(LOGTAG, "Error creating onClick response", e); - } - + public void onButtonClick(JSONObject response, DoorHanger doorhanger) { GeckoEvent e = GeckoEvent.createBroadcastEvent("Doorhanger:Reply", response.toString()); GeckoAppShell.sendEventToGecko(e); - removeDoorHanger(dh); + removeDoorHanger(doorhanger); updatePopup(); } /** * Gets a doorhanger. * * This method must be called on the UI thread. */
--- a/mobile/android/base/toolbar/SiteIdentityPopup.java +++ b/mobile/android/base/toolbar/SiteIdentityPopup.java @@ -12,33 +12,34 @@ 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.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 { + public static enum ButtonType { DISABLE, ENABLE, KEEP_BLOCKING }; + private static final String LOGTAG = "GeckoSiteIdentityPopup"; private static final String MIXED_CONTENT_SUPPORT_URL = "https://support.mozilla.org/kb/how-does-insecure-content-affect-safety-android"; private static final String TRACKING_CONTENT_SUPPORT_URL = "https://support.mozilla.org/kb/firefox-android-tracking-protection"; @@ -137,88 +138,87 @@ public class SiteIdentityPopup extends A final String encrypted = siteIdentity.getEncrypted(); mVerifier.setText(verifier + "\n" + encrypted); } private void addMixedContentNotification(boolean blocked) { // Remove any existing mixed content notification. removeMixedContentNotification(); - final DoorhangerConfig config = new DoorhangerConfig(); + final DoorhangerConfig config = new DoorhangerConfig(DoorHanger.Type.MIXED_CONTENT, mButtonClickListener); int icon; if (blocked) { icon = R.drawable.shield_enabled_doorhanger; 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; 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); + addNotificationButtons(config, blocked); + mMixedContentNotification = DoorHanger.Get(mContext, config); mMixedContentNotification.setIcon(icon); - addNotificationButtons(mMixedContentNotification, blocked); mContent.addView(mMixedContentNotification); mDivider.setVisibility(View.VISIBLE); } private void removeMixedContentNotification() { if (mMixedContentNotification != null) { mContent.removeView(mMixedContentNotification); mMixedContentNotification = null; } } private void addTrackingContentNotification(boolean blocked) { // Remove any existing tracking content notification. removeTrackingContentNotification(); - final DoorhangerConfig config = new DoorhangerConfig(); + final DoorhangerConfig config = new DoorhangerConfig(DoorHanger.Type.TRACKING, mButtonClickListener); int icon; if (blocked) { icon = R.drawable.shield_enabled_doorhanger; 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; 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); + addNotificationButtons(config, blocked); + mTrackingContentNotification = DoorHanger.Get(mContext, config); mTrackingContentNotification.setIcon(icon); - 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. + private void addNotificationButtons(DoorhangerConfig config, boolean blocked) { if (blocked) { - dh.addButton(mContext.getString(R.string.disable_protection), "disable", mButtonClickListener); - dh.addButton(mContext.getString(R.string.keep_blocking), "keepBlocking", mButtonClickListener); + config.appendButton(mContext.getString(R.string.disable_protection), ButtonType.DISABLE.ordinal()); + config.appendButton(mContext.getString(R.string.keep_blocking), ButtonType.KEEP_BLOCKING.ordinal()); } else { - dh.addButton(mContext.getString(R.string.enable_protection), "enable", mButtonClickListener); + config.appendButton(mContext.getString(R.string.enable_protection), ButtonType.ENABLE.ordinal()); } } /* * @param identityData A JSONObject that holds the current tab's identity data. */ void setSiteIdentity(SiteIdentity siteIdentity) { mSiteIdentity = siteIdentity; @@ -285,24 +285,15 @@ public class SiteIdentityPopup extends A super.dismiss(); removeMixedContentNotification(); removeTrackingContentNotification(); mDivider.setVisibility(View.GONE); } private class PopupButtonListener implements OnButtonClickListener { @Override - public void onButtonClick(DoorHanger dh, String tag) { - try { - JSONObject data = new JSONObject(); - data.put("allowContent", tag.equals("disable")); - data.put("contentType", (dh == mMixedContentNotification ? "mixed" : "tracking")); - - GeckoEvent e = GeckoEvent.createBroadcastEvent("Session:Reload", data.toString()); - GeckoAppShell.sendEventToGecko(e); - } catch (JSONException e) { - Log.e(LOGTAG, "Exception creating message to enable/disable content blocking", e); - } - + public void onButtonClick(JSONObject response, DoorHanger doorhanger) { + GeckoEvent e = GeckoEvent.createBroadcastEvent("Session:Reload", response.toString()); + GeckoAppShell.sendEventToGecko(e); dismiss(); } } }
--- a/mobile/android/base/widget/DefaultDoorHanger.java +++ b/mobile/android/base/widget/DefaultDoorHanger.java @@ -1,45 +1,45 @@ /* -*- 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; +import android.util.Log; +import android.view.LayoutInflater; +import android.widget.Button; import org.mozilla.gecko.R; import org.mozilla.gecko.prompts.PromptInput; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import android.content.res.Resources; import android.text.TextUtils; import android.view.View; import android.view.ViewGroup; import android.widget.CheckBox; +import org.mozilla.gecko.toolbar.SiteIdentityPopup; import java.util.ArrayList; import java.util.List; public class DefaultDoorHanger extends DoorHanger { 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, DoorhangerConfig config) { - this(context, config, Type.DEFAULT); - } - 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); } @@ -57,25 +57,25 @@ public class DefaultDoorHanger extends D if (options != null) { setOptions(options); } final DoorhangerConfig.Link link = config.getLink(); if (link != null) { addLink(link.label, link.url, link.delimiter); } + + setButtons(config); } - @Override - public List<PromptInput> getInputs() { + private List<PromptInput> getInputs() { return mInputs; } - @Override - public CheckBox getCheckBox() { + private CheckBox getCheckBox() { return mCheckBox; } @Override public void setOptions(final JSONObject options) { super.setOptions(options); final JSONObject link = options.optJSONObject("link"); if (link != null) { @@ -110,16 +110,64 @@ public class DefaultDoorHanger extends D final String checkBoxText = options.optString("checkbox"); if (!TextUtils.isEmpty(checkBoxText)) { mCheckBox = (CheckBox) findViewById(R.id.doorhanger_checkbox); mCheckBox.setText(checkBoxText); mCheckBox.setVisibility(VISIBLE); } } + @Override + protected Button createButtonInstance(final String text, final int id) { + final Button button = (Button) LayoutInflater.from(getContext()).inflate(R.layout.doorhanger_button, null); + button.setText(text); + + button.setOnClickListener(new Button.OnClickListener() { + @Override + public void onClick(View v) { + final JSONObject response = new JSONObject(); + try { + // TODO: Bug 1149359 - Split this into each Doorhanger Type class. + switch (mType) { + case MIXED_CONTENT: + response.put("allowContent", (id == SiteIdentityPopup.ButtonType.DISABLE.ordinal())); + response.put("contentType", ("mixed")); + break; + case TRACKING: + response.put("allowContent", (id == SiteIdentityPopup.ButtonType.DISABLE.ordinal())); + response.put("contentType", ("tracking")); + break; + default: + response.put("callback", id); + + CheckBox checkBox = getCheckBox(); + // If the checkbox is being used, pass its value + if (checkBox != null) { + response.put("checked", checkBox.isChecked()); + } + + List<PromptInput> doorHangerInputs = getInputs(); + if (doorHangerInputs != null) { + JSONObject inputs = new JSONObject(); + for (PromptInput input : doorHangerInputs) { + inputs.put(input.getId(), input.getValue()); + } + response.put("inputs", inputs); + } + } + mOnButtonClickListener.onButtonClick(response, DefaultDoorHanger.this); + } catch (JSONException e) { + Log.e(LOGTAG, "Error creating onClick response", e); + } + } + }); + + return button; + } + private void styleInput(PromptInput input, View view) { if (input instanceof PromptInput.MenulistInput) { styleDropdownInputs(input, view); } view.setPadding(0, 0, 0, mResources.getDimensionPixelSize(R.dimen.doorhanger_padding)); } private void styleDropdownInputs(PromptInput input, View view) {
--- a/mobile/android/base/widget/DoorHanger.java +++ b/mobile/android/base/widget/DoorHanger.java @@ -7,70 +7,70 @@ 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; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; -import android.widget.CheckBox; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import org.json.JSONArray; +import org.json.JSONException; 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 LOGIN: - return new LoginDoorHanger(context, config); - case SITE: - return new DefaultDoorHanger(context, config, type); - } + switch (type) { + case LOGIN: + return new LoginDoorHanger(context, config); + case TRACKING: + case MIXED_CONTENT: + return new DefaultDoorHanger(context, config, type); } - - return new DefaultDoorHanger(context, config); + return new DefaultDoorHanger(context, config, type); } - public static enum Type { DEFAULT, LOGIN, SITE } + public static enum Type { DEFAULT, LOGIN, TRACKING, MIXED_CONTENT} public interface OnButtonClickListener { - public void onButtonClick(DoorHanger dh, String tag); + public void onButtonClick(JSONObject response, DoorHanger doorhanger); } - private static final LayoutParams sButtonParams; + protected static final LayoutParams sButtonParams; static { sButtonParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1.0f); } private static final String LOGTAG = "GeckoDoorHanger"; // Divider between doorhangers. private final View mDivider; - private final LinearLayout mButtonsContainer; + protected final LinearLayout mButtonsContainer; + protected final OnButtonClickListener mOnButtonClickListener; // The tab this doorhanger is associated with. private final int mTabId; // DoorHanger identifier. private final String mIdentifier; + protected final Type mType; + private final ImageView mIcon; private final TextView mMessage; protected Context mContext; protected int mDividerColor; protected boolean mPersistWhileVisible; @@ -91,39 +91,60 @@ public abstract class DoorHanger extends default: resource = R.layout.doorhanger; } LayoutInflater.from(context).inflate(resource, this); mDivider = findViewById(R.id.divider_doorhanger); mIcon = (ImageView) findViewById(R.id.doorhanger_icon); mMessage = (TextView) findViewById(R.id.doorhanger_message); - if (type == Type.SITE) { + + // TODO: Bug 1149359 - split this into DoorHanger subclasses. + if (type == Type.TRACKING || type == Type.MIXED_CONTENT) { mMessage.setTextAppearance(getContext(), R.style.TextAppearance_DoorHanger_Small); } + + mType = type; + mButtonsContainer = (LinearLayout) findViewById(R.id.doorhanger_buttons); + mOnButtonClickListener = config.getButtonClickListener(); mDividerColor = getResources().getColor(R.color.divider_light); setOrientation(VERTICAL); } - abstract protected void loadConfig(DoorhangerConfig config); + protected abstract 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"); if (timeout > 0) { mTimeout = timeout; } + } + + protected void setButtons(DoorhangerConfig config) { + final JSONArray buttons = config.getButtons(); + final OnButtonClickListener listener = config.getButtonClickListener(); + for (int i = 0; i < buttons.length(); i++) { + try { + final JSONObject buttonObject = buttons.getJSONObject(i); + final String label = buttonObject.getString("label"); + final int callbackId = buttonObject.getInt("callback"); + addButtonToLayout(label, callbackId); + } catch (JSONException e) { + Log.e(LOGTAG, "Error creating doorhanger button", e); + } + } } public int getTabId() { return mTabId; } public String getIdentifier() { return mIdentifier; @@ -161,28 +182,23 @@ public abstract class DoorHanger extends ForegroundColorSpan colorSpan = new ForegroundColorSpan(mMessage.getCurrentTextColor()); titleWithLink.setSpan(colorSpan, 0, title.length(), 0); titleWithLink.setSpan(linkSpan, title.length() + 1, titleWithLink.length(), 0); mMessage.setText(titleWithLink); mMessage.setMovementMethod(LinkMovementMethod.getInstance()); } - public void addButton(final String text, final String tag, final OnButtonClickListener listener) { - final Button button = (Button) LayoutInflater.from(getContext()).inflate(R.layout.doorhanger_button, null); - button.setText(text); - button.setTag(tag); - - button.setOnClickListener(new Button.OnClickListener() { - @Override - public void onClick(View v) { - listener.onButtonClick(DoorHanger.this, tag); - } - }); - + /** + * Creates and adds a button into the DoorHanger. + * @param text Button text + * @param id Identifier associated with the button + */ + private void addButtonToLayout(String text, int id) { + final Button button = createButtonInstance(text, id); if (mButtonsContainer.getChildCount() == 0) { // If this is the first button we're adding, make the choices layout visible. mButtonsContainer.setVisibility(View.VISIBLE); // Make the divider above the buttons visible. View divider = findViewById(R.id.divider_buttons); divider.setVisibility(View.VISIBLE); } else { // Add a vertical divider between additional buttons. @@ -190,16 +206,18 @@ public abstract class DoorHanger extends divider.setOrientation(Divider.Orientation.VERTICAL); divider.setBackgroundColor(mDividerColor); mButtonsContainer.addView(divider); } mButtonsContainer.addView(button, sButtonParams); } + protected abstract Button createButtonInstance(String text, int id); + /* * Checks with persistence and timeout options to see if it's okay to remove a doorhanger. * * @param isShowing Whether or not this doorhanger is currently visible to the user. * (e.g. the DoorHanger view might be VISIBLE, but its parent could be hidden) */ public boolean shouldRemove(boolean isShowing) { if (mPersistWhileVisible && isShowing) { @@ -217,19 +235,9 @@ public abstract class DoorHanger extends } if (System.currentTimeMillis() <= mTimeout) { return false; } return true; } - - // TODO: remove and expose through instance Button Handler. - public List<PromptInput> getInputs() { - return null; - } - - public CheckBox getCheckBox() { - return null; - } - }
--- a/mobile/android/base/widget/DoorhangerConfig.java +++ b/mobile/android/base/widget/DoorhangerConfig.java @@ -1,16 +1,18 @@ /* -*- 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; +import android.util.Log; import org.json.JSONArray; +import org.json.JSONException; import org.json.JSONObject; import org.mozilla.gecko.widget.DoorHanger.Type; public class DoorhangerConfig { public static class Link { public final String label; @@ -19,47 +21,49 @@ public class DoorhangerConfig { private Link(String label, String url, String delimiter) { this.label = label; this.url = url; this.delimiter = delimiter; } } + private static final String LOGTAG = "DoorhangerConfig"; + private final int tabId; private final String id; - private DoorHanger.Type type; + private final DoorHanger.OnButtonClickListener buttonClickListener; + private final DoorHanger.Type type; private String message; private JSONObject options; private Link link; - private JSONArray buttons; + private JSONArray buttons = new JSONArray(); - public DoorhangerConfig() { + public DoorhangerConfig(Type type, DoorHanger.OnButtonClickListener listener) { // XXX: This should only be used by SiteIdentityPopup doorhangers which // don't need tab or id references, until bug 1141904 unifies doorhangers. - this(-1, null); + + this(-1, null, type, listener); } - public DoorhangerConfig(int tabId, String id) { + public DoorhangerConfig(int tabId, String id, DoorHanger.Type type, DoorHanger.OnButtonClickListener buttonClickListener) { this.tabId = tabId; this.id = id; + this.type = type; + this.buttonClickListener = buttonClickListener; } public int getTabId() { return tabId; } public String getId() { return id; } - public void setType(Type type) { - this.type = type; - } - public Type getType() { return type; } public void setMessage(String message) { this.message = message; } @@ -70,18 +74,43 @@ public class DoorhangerConfig { public void setOptions(JSONObject options) { this.options = options; } public JSONObject getOptions() { return options; } - public void setButtons(JSONArray buttons) { - this.buttons = buttons; + /** + * Add buttons from JSON to the Config object. + * @param buttons JSONArray of JSONObjects of the form { label: <label>, callback: <callback_id> } + */ + public void appendButtonsFromJSON(JSONArray buttons) { + try { + for (int i = 0; i < buttons.length(); i++) { + this.buttons.put(buttons.get(i)); + } + } catch (JSONException e) { + Log.e(LOGTAG, "Error parsing buttons from JSON", e); + } + } + + public void appendButton(String label, int callbackId) { + final JSONObject button = new JSONObject(); + try { + button.put("label", label); + button.put("callback", callbackId); + this.buttons.put(button); + } catch (JSONException e) { + Log.e(LOGTAG, "Error creating button", e); + } + } + + public DoorHanger.OnButtonClickListener getButtonClickListener() { + return this.buttonClickListener; } public JSONArray getButtons() { return buttons; } public void setLink(String label, String url, String delimiter) { this.link = new Link(label, url, delimiter);
--- a/mobile/android/base/widget/LoginDoorHanger.java +++ b/mobile/android/base/widget/LoginDoorHanger.java @@ -4,17 +4,19 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ package org.mozilla.gecko.widget; import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.util.Log; +import android.view.LayoutInflater; import android.view.View; +import android.widget.Button; import android.widget.TextView; import ch.boye.httpclientandroidlib.util.TextUtils; import org.json.JSONException; import org.json.JSONObject; import org.mozilla.gecko.R; import org.mozilla.gecko.favicons.Favicons; import org.mozilla.gecko.favicons.OnFaviconLoadedListener; @@ -32,17 +34,17 @@ public class LoginDoorHanger extends Doo loadConfig(config); } @Override protected void loadConfig(DoorhangerConfig config) { setOptions(config.getOptions()); setMessage(config.getMessage()); - + setButtons(config); } @Override protected void setOptions(final JSONObject options) { super.setOptions(options); final JSONObject titleObj = options.optJSONObject("title"); if (titleObj != null) { @@ -71,9 +73,30 @@ public class LoginDoorHanger extends Doo final String subtext = options.optString("subtext"); if (!TextUtils.isEmpty(subtext)) { mLogin.setText(subtext); mLogin.setVisibility(View.VISIBLE); } else { mLogin.setVisibility(View.GONE); } } + + @Override + protected Button createButtonInstance(final String text, final int id) { + final Button button = (Button) LayoutInflater.from(getContext()).inflate(R.layout.doorhanger_button, null); + button.setText(text); + + button.setOnClickListener(new Button.OnClickListener() { + @Override + public void onClick(View v) { + final JSONObject response = new JSONObject(); + try { + response.put("callback", id); + } catch (JSONException e) { + Log.e(LOGTAG, "Error making doorhanger response message"); + } + mOnButtonClickListener.onButtonClick(response, LoginDoorHanger.this); + } + }); + + return button; + } }