Bug 1147064 - Add colored buttons. r=margaret

This commit is contained in:
Chenxia Liu 2015-05-21 16:27:38 -07:00
parent 68367db37c
commit ae4a3b371f
12 changed files with 129 additions and 120 deletions

View File

@ -9,6 +9,7 @@ import java.util.HashSet;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.json.JSONArray;
import org.mozilla.gecko.AppConstants.Versions; import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.util.GeckoEventListener; import org.mozilla.gecko.util.GeckoEventListener;
import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.util.ThreadUtils;
@ -113,9 +114,21 @@ public class DoorHangerPopup extends AnchoredPopup
final DoorhangerConfig config = new DoorhangerConfig(tabId, id, doorhangerType, this); final DoorhangerConfig config = new DoorhangerConfig(tabId, id, doorhangerType, this);
config.setMessage(json.getString("message")); config.setMessage(json.getString("message"));
config.appendButtonsFromJSON(json.getJSONArray("buttons"));
config.setOptions(json.getJSONObject("options")); config.setOptions(json.getJSONObject("options"));
final JSONArray buttonArray = json.getJSONArray("buttons");
int numButtons = buttonArray.length();
if (numButtons > 2) {
Log.e(LOGTAG, "Doorhanger can have a maximum of two buttons!");
numButtons = 2;
}
for (int i = 0; i < numButtons; i++) {
final JSONObject buttonJSON = buttonArray.getJSONObject(i);
final boolean isPositive = buttonJSON.optBoolean("positive", false);
config.setButton(buttonJSON.getString("label"), buttonJSON.getInt("callback"), isPositive);
}
return config; return config;
} }

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<shape>
<solid android:color="@color/toolbar_menu_dark_grey" />
</shape>
</item>
<item android:state_pressed="true">
<shape>
<solid android:color="@color/toolbar_grey_pressed" />
</shape>
</item>
</selector>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="false">
<shape>
<solid android:color="@color/link_blue"/>
</shape>
</item>
<item android:state_pressed="true">
<shape>
<solid android:color="@color/link_blue_pressed" />
</shape>
</item>
</selector>

View File

@ -23,17 +23,23 @@
</LinearLayout> </LinearLayout>
<View android:id="@+id/divider_buttons" <LinearLayout android:layout_width="match_parent"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/divider_light"
android:visibility="gone"/>
<LinearLayout android:id="@+id/doorhanger_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal" android:orientation="horizontal">
android:visibility="gone"/>
<Button android:id="@+id/doorhanger_button_negative"
style="@style/Widget.Doorhanger.Button"
android:textColor="@android:color/black"
android:background="@drawable/action_bar_button_negative"
android:visibility="gone"/>
<Button android:id="@+id/doorhanger_button_positive"
style="@style/Widget.Doorhanger.Button"
android:textColor="@android:color/white"
android:background="@drawable/action_bar_button_positive"
android:visibility="gone"/>
</LinearLayout>
<View android:id="@+id/divider_doorhanger" <View android:id="@+id/divider_doorhanger"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dip"
android:textColor="@color/placeholder_active_grey"
android:textSize="14sp"
android:background="@drawable/action_bar_button"/>

View File

@ -9,6 +9,7 @@
<color name="action_orange">#E66000</color> <color name="action_orange">#E66000</color>
<color name="action_orange_pressed">#DC5600</color> <color name="action_orange_pressed">#DC5600</color>
<color name="link_blue">#0096DD</color> <color name="link_blue">#0096DD</color>
<color name="link_blue_pressed">#0082C6</color>
<color name="private_browsing_purple">#CF68FF</color> <color name="private_browsing_purple">#CF68FF</color>
<color name="placeholder_active_grey">#222222</color> <color name="placeholder_active_grey">#222222</color>

View File

@ -281,6 +281,14 @@
<item name="android:textSize">18sp</item> <item name="android:textSize">18sp</item>
</style> </style>
<style name="Widget.Doorhanger.Button" parent="Widget.BaseButton">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">1</item>
<item name="android:minHeight">48dp</item>
<item name="android:textSize">14sp</item>
</style>
<!-- <!--
TextAppearance TextAppearance
Note: Gecko uses light theme as default, while Android uses dark. Note: Gecko uses light theme as default, while Android uses dark.

View File

@ -202,8 +202,8 @@ public class SiteIdentityPopup extends AnchoredPopup implements GeckoEventListen
final DoorhangerConfig config = new DoorhangerConfig(DoorHanger.Type.LOGIN, buttonClickListener); final DoorhangerConfig config = new DoorhangerConfig(DoorHanger.Type.LOGIN, buttonClickListener);
// Set buttons. // Set buttons.
config.appendButton(mContext.getString(R.string.button_cancel), ButtonType.CANCEL.ordinal()); config.setButton(mContext.getString(R.string.button_cancel), ButtonType.CANCEL.ordinal(), false);
config.appendButton(mContext.getString(R.string.button_copy), ButtonType.COPY.ordinal()); config.setButton(mContext.getString(R.string.button_copy), ButtonType.COPY.ordinal(), true);
// Set message. // Set message.
String username = ((JSONObject) logins.get(0)).getString("username"); String username = ((JSONObject) logins.get(0)).getString("username");
@ -361,10 +361,10 @@ public class SiteIdentityPopup extends AnchoredPopup implements GeckoEventListen
private void addNotificationButtons(DoorhangerConfig config, boolean blocked) { private void addNotificationButtons(DoorhangerConfig config, boolean blocked) {
if (blocked) { if (blocked) {
config.appendButton(mContext.getString(R.string.disable_protection), ButtonType.DISABLE.ordinal()); config.setButton(mContext.getString(R.string.disable_protection), ButtonType.DISABLE.ordinal(), false);
config.appendButton(mContext.getString(R.string.keep_blocking), ButtonType.KEEP_BLOCKING.ordinal()); config.setButton(mContext.getString(R.string.keep_blocking), ButtonType.KEEP_BLOCKING.ordinal(), true);
} else { } else {
config.appendButton(mContext.getString(R.string.enable_protection), ButtonType.ENABLE.ordinal()); config.setButton(mContext.getString(R.string.enable_protection), ButtonType.ENABLE.ordinal(), true);
} }
} }

View File

@ -69,7 +69,7 @@ public class DefaultDoorHanger extends DoorHanger {
addLink(link.label, link.url, link.delimiter); addLink(link.label, link.url, link.delimiter);
} }
setButtons(config); addButtonsToLayout(config);
} }
@Override @Override

View File

@ -7,15 +7,12 @@ package org.mozilla.gecko.widget;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewStub; import android.view.ViewStub;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.mozilla.gecko.R; import org.mozilla.gecko.R;
@ -39,17 +36,13 @@ public abstract class DoorHanger extends LinearLayout {
public void onButtonClick(JSONObject response, DoorHanger doorhanger); public void onButtonClick(JSONObject response, DoorHanger doorhanger);
} }
protected static final LayoutParams sButtonParams;
static {
sButtonParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 1.0f);
}
private static final String LOGTAG = "GeckoDoorHanger"; private static final String LOGTAG = "GeckoDoorHanger";
// Divider between doorhangers. // Divider between doorhangers.
private final View mDivider; private final View mDivider;
protected final LinearLayout mButtonsContainer; private final Button mNegativeButton;
private final Button mPositiveButton;
protected final OnButtonClickListener mOnButtonClickListener; protected final OnButtonClickListener mOnButtonClickListener;
// The tab this doorhanger is associated with. // The tab this doorhanger is associated with.
@ -89,7 +82,8 @@ public abstract class DoorHanger extends LinearLayout {
mDivider = findViewById(R.id.divider_doorhanger); mDivider = findViewById(R.id.divider_doorhanger);
mIcon = (ImageView) findViewById(R.id.doorhanger_icon); mIcon = (ImageView) findViewById(R.id.doorhanger_icon);
mButtonsContainer = (LinearLayout) findViewById(R.id.doorhanger_buttons); mNegativeButton = (Button) findViewById(R.id.doorhanger_button_negative);
mPositiveButton = (Button) findViewById(R.id.doorhanger_button_positive);
mOnButtonClickListener = config.getButtonClickListener(); mOnButtonClickListener = config.getButtonClickListener();
mDividerColor = mResources.getColor(R.color.divider_light); mDividerColor = mResources.getColor(R.color.divider_light);
@ -113,17 +107,21 @@ public abstract class DoorHanger extends LinearLayout {
} }
} }
protected void setButtons(DoorhangerConfig config) { protected void addButtonsToLayout(DoorhangerConfig config) {
final JSONArray buttons = config.getButtons(); final DoorhangerConfig.ButtonConfig negativeButtonConfig = config.getNegativeButtonConfig();
for (int i = 0; i < buttons.length(); i++) { final DoorhangerConfig.ButtonConfig positiveButtonConfig = config.getPositiveButtonConfig();
try {
final JSONObject buttonObject = buttons.getJSONObject(i); if (negativeButtonConfig != null) {
final String label = buttonObject.getString("label"); mNegativeButton.setText(negativeButtonConfig.label);
final int callbackId = buttonObject.getInt("callback"); mNegativeButton.setOnClickListener(makeOnButtonClickListener(negativeButtonConfig.callback));
addButtonToLayout(label, callbackId); mNegativeButton.setVisibility(VISIBLE);
} catch (JSONException e) { }
Log.e(LOGTAG, "Error creating doorhanger button", e);
} if (positiveButtonConfig != null) {
mPositiveButton.setText(positiveButtonConfig.label);
mPositiveButton.setOnClickListener(makeOnButtonClickListener(positiveButtonConfig.callback));
mPositiveButton.setVisibility(VISIBLE);
// TODO: set positive button click listener for LoginDoorhanger callback
} }
} }
@ -148,37 +146,6 @@ public abstract class DoorHanger extends LinearLayout {
mIcon.setVisibility(View.VISIBLE); mIcon.setVisibility(View.VISIBLE);
} }
/**
* 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.
Divider divider = new Divider(getContext(), null);
divider.setOrientation(Divider.Orientation.VERTICAL);
divider.setBackgroundColor(mDividerColor);
mButtonsContainer.addView(divider);
}
mButtonsContainer.addView(button, sButtonParams);
}
protected Button createButtonInstance(String text, int id) {
final Button button = (Button) LayoutInflater.from(getContext()).inflate(R.layout.doorhanger_button, null);
button.setText(text);
button.setOnClickListener(makeOnButtonClickListener(id));
return button;
}
protected abstract OnClickListener makeOnButtonClickListener(final int id); protected abstract OnClickListener makeOnButtonClickListener(final int id);
/* /*

View File

@ -5,9 +5,6 @@
package org.mozilla.gecko.widget; package org.mozilla.gecko.widget;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.mozilla.gecko.widget.DoorHanger.Type; import org.mozilla.gecko.widget.DoorHanger.Type;
@ -26,6 +23,15 @@ public class DoorhangerConfig {
} }
} }
public static class ButtonConfig {
public final String label;
public final int callback;
public ButtonConfig(String label, int callback) {
this.label = label;
this.callback = callback;
}
}
private static final String LOGTAG = "DoorhangerConfig"; private static final String LOGTAG = "DoorhangerConfig";
private final int tabId; private final int tabId;
@ -35,7 +41,8 @@ public class DoorhangerConfig {
private String message; private String message;
private JSONObject options; private JSONObject options;
private Link link; private Link link;
private JSONArray buttons = new JSONArray(); private ButtonConfig positiveButtonConfig;
private ButtonConfig negativeButtonConfig;
public DoorhangerConfig(Type type, DoorHanger.OnButtonClickListener listener) { public DoorhangerConfig(Type type, DoorHanger.OnButtonClickListener listener) {
// XXX: This should only be used by SiteIdentityPopup doorhangers which // XXX: This should only be used by SiteIdentityPopup doorhangers which
@ -79,39 +86,27 @@ public class DoorhangerConfig {
return options; return options;
} }
/** public void setButton(String label, int callbackId, boolean isPositive) {
* Add buttons from JSON to the Config object. final ButtonConfig buttonConfig = new ButtonConfig(label, callbackId);
* @param buttons JSONArray of JSONObjects of the form { label: <label>, callback: <callback_id> } if (isPositive) {
*/ positiveButtonConfig = buttonConfig;
public void appendButtonsFromJSON(JSONArray buttons) { } else {
try { negativeButtonConfig = buttonConfig;
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) { public ButtonConfig getPositiveButtonConfig() {
final JSONObject button = new JSONObject(); return positiveButtonConfig;
try { }
button.put("label", label);
button.put("callback", callbackId); public ButtonConfig getNegativeButtonConfig() {
this.buttons.put(button); return negativeButtonConfig;
} catch (JSONException e) {
Log.e(LOGTAG, "Error creating button", e);
}
} }
public DoorHanger.OnButtonClickListener getButtonClickListener() { public DoorHanger.OnButtonClickListener getButtonClickListener() {
return this.buttonClickListener; return this.buttonClickListener;
} }
public JSONArray getButtons() {
return buttons;
}
public void setLink(String label, String url, String delimiter) { public void setLink(String label, String url, String delimiter) {
this.link = new Link(label, url, delimiter); this.link = new Link(label, url, delimiter);
} }

View File

@ -7,8 +7,6 @@ package org.mozilla.gecko.widget;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog; import android.app.Dialog;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.graphics.Bitmap; import android.graphics.Bitmap;
@ -29,7 +27,6 @@ import ch.boye.httpclientandroidlib.util.TextUtils;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.json.JSONArray; import org.json.JSONArray;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.R; import org.mozilla.gecko.R;
import org.mozilla.gecko.favicons.Favicons; import org.mozilla.gecko.favicons.Favicons;
import org.mozilla.gecko.favicons.OnFaviconLoadedListener; import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
@ -42,6 +39,7 @@ public class LoginDoorHanger extends DoorHanger {
private final TextView mTitle; private final TextView mTitle;
private final TextView mMessage; private final TextView mMessage;
private final TextView mLink; private final TextView mLink;
// TODO: Fix callback for pos/neg button.
private int mCallbackID; private int mCallbackID;
public LoginDoorHanger(Context context, DoorhangerConfig config) { public LoginDoorHanger(Context context, DoorhangerConfig config) {
@ -65,7 +63,7 @@ public class LoginDoorHanger extends DoorHanger {
protected void loadConfig(DoorhangerConfig config) { protected void loadConfig(DoorhangerConfig config) {
setOptions(config.getOptions()); setOptions(config.getOptions());
setMessage(config.getMessage()); setMessage(config.getMessage());
setButtons(config); addButtonsToLayout(config);
} }
@Override @Override
@ -105,13 +103,6 @@ public class LoginDoorHanger extends DoorHanger {
addActionText(actionText); addActionText(actionText);
} }
@Override
protected Button createButtonInstance(final String text, final int id) {
// HACK: Confirm button will the the rightmost/last button added. Bug 1147064 should add differentiation of the two.
mCallbackID = id;
return super.createButtonInstance(text, id);
}
@Override @Override
protected OnClickListener makeOnButtonClickListener(final int id) { protected OnClickListener makeOnButtonClickListener(final int id) {
return new Button.OnClickListener() { return new Button.OnClickListener() {