Commit 116f9522 authored by Brandon Wylie's avatar Brandon Wylie Committed by Commit Bot

Add layout for RadioButtonWithDescription to allow programmatic uses

RadioButtonWithDescription & friends don't support adding via code.
This change wraps up the view properly to allow for inflation and adds
a layout to host the buttons and proxy checked events between the
custom code and the standard callbacks.

Bug: 1015218
Change-Id: Ic4bc5e1d01ee982a4513f9c9b202c40646b8739f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1869024
Commit-Queue: Brandon Wylie <wylieb@chromium.org>
Reviewed-by: default avatarTheresa  <twellington@chromium.org>
Reviewed-by: default avatarEnder <ender@google.com>
Reviewed-by: default avatarPatrick Noland <pnoland@chromium.org>
Cr-Commit-Position: refs/heads/master@{#711479}
parent fb3d10c1
...@@ -10,35 +10,41 @@ ...@@ -10,35 +10,41 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:focusable="false"> android:focusable="false">
<org.chromium.chrome.browser.ui.widget.RadioButtonWithDescriptionLayout
<org.chromium.chrome.browser.ui.widget.RadioButtonWithDescription android:id="@+id/radio_button_layout"
android:id="@+id/system_default"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent">
android:background="?attr/selectableItemBackground"
app:titleText="@string/themes_system_default_title"
app:descriptionText="@string/themes_system_default_summary" />
<!-- override default padding top and bottom --> <org.chromium.chrome.browser.ui.widget.RadioButtonWithDescription
<org.chromium.chrome.browser.ui.widget.RadioButtonWithDescription android:id="@+id/system_default"
android:id="@+id/light" android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:background="?attr/selectableItemBackground"
android:minHeight="@dimen/min_touch_target_size" app:titleText="@string/themes_system_default_title"
android:paddingTop="8dp" app:descriptionText="@string/themes_system_default_summary" />
android:paddingBottom="8dp"
android:background="?attr/selectableItemBackground"
app:titleText="@string/light_mode" />
<org.chromium.chrome.browser.ui.widget.RadioButtonWithDescription <!-- override default padding top and bottom -->
android:id="@+id/dark" <org.chromium.chrome.browser.ui.widget.RadioButtonWithDescription
android:layout_width="match_parent" android:id="@+id/light"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:minHeight="@dimen/min_touch_target_size" android:layout_height="wrap_content"
android:paddingTop="8dp" android:minHeight="@dimen/min_touch_target_size"
android:paddingBottom="8dp" android:paddingTop="8dp"
android:background="?attr/selectableItemBackground" android:paddingBottom="8dp"
app:titleText="@string/dark_mode" /> android:background="?attr/selectableItemBackground"
app:titleText="@string/light_mode" />
<org.chromium.chrome.browser.ui.widget.RadioButtonWithDescription
android:id="@+id/dark"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/min_touch_target_size"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:background="?attr/selectableItemBackground"
app:titleText="@string/dark_mode" />
</org.chromium.chrome.browser.ui.widget.RadioButtonWithDescriptionLayout>
<!-- Make the row clickable --> <!-- Make the row clickable -->
<LinearLayout <LinearLayout
......
...@@ -13,27 +13,35 @@ ...@@ -13,27 +13,35 @@
android:focusable="false" android:focusable="false"
android:orientation="vertical"> android:orientation="vertical">
<org.chromium.chrome.browser.ui.widget.RadioButtonWithDescription <org.chromium.chrome.browser.ui.widget.RadioButtonWithDescriptionLayout
android:id="@+id/allowed" android:id="@+id/radio_button_layout"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="match_parent">
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:background="?android:attr/selectableItemBackground"
app:titleText="@string/website_settings_category_allowed" />
<org.chromium.chrome.browser.ui.widget.RadioButtonWithDescription
android:id="@+id/ask"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:background="?android:attr/selectableItemBackground"
app:titleText="@string/website_settings_category_ask" />
<org.chromium.chrome.browser.ui.widget.RadioButtonWithDescription <org.chromium.chrome.browser.ui.widget.RadioButtonWithDescription
android:id="@+id/blocked" android:id="@+id/allowed"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingStart="?android:attr/listPreferredItemPaddingStart" android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:background="?android:attr/selectableItemBackground" android:background="?android:attr/selectableItemBackground"
app:titleText="@string/website_settings_category_blocked" /> app:titleText="@string/website_settings_category_allowed" />
<org.chromium.chrome.browser.ui.widget.RadioButtonWithDescription
android:id="@+id/ask"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:background="?android:attr/selectableItemBackground"
app:titleText="@string/website_settings_category_ask" />
<org.chromium.chrome.browser.ui.widget.RadioButtonWithDescription
android:id="@+id/blocked"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:background="?android:attr/selectableItemBackground"
app:titleText="@string/website_settings_category_blocked" />
</org.chromium.chrome.browser.ui.widget.RadioButtonWithDescriptionLayout>
</LinearLayout> </LinearLayout>
...@@ -11,6 +11,7 @@ import android.util.AttributeSet; ...@@ -11,6 +11,7 @@ import android.util.AttributeSet;
import android.view.View; import android.view.View;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.RadioGroup;
import org.chromium.base.BuildInfo; import org.chromium.base.BuildInfo;
import org.chromium.base.VisibleForTesting; import org.chromium.base.VisibleForTesting;
...@@ -28,13 +29,14 @@ import java.util.Collections; ...@@ -28,13 +29,14 @@ import java.util.Collections;
* Light, and Dark. * Light, and Dark.
*/ */
public class RadioButtonGroupThemePreference public class RadioButtonGroupThemePreference
extends Preference implements RadioButtonWithDescription.OnCheckedChangeListener { extends Preference implements RadioGroup.OnCheckedChangeListener {
private @ThemeSetting int mSetting; private @ThemeSetting int mSetting;
private ArrayList<RadioButtonWithDescription> mButtons; private ArrayList<RadioButtonWithDescription> mButtons;
private boolean mDarkenWebsitesEnabled; private boolean mDarkenWebsitesEnabled;
private CheckBox mCheckBox; private CheckBox mCheckBox;
private LinearLayout mLayoutContainer; private LinearLayout mLayoutContainer;
private LinearLayout mCheckboxContainer; private LinearLayout mCheckboxContainer;
private RadioGroup mRadioGroup;
public RadioButtonGroupThemePreference(Context context, AttributeSet attrs) { public RadioButtonGroupThemePreference(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
...@@ -61,6 +63,9 @@ public class RadioButtonGroupThemePreference ...@@ -61,6 +63,9 @@ public class RadioButtonGroupThemePreference
mCheckBox = (CheckBox) holder.findViewById(R.id.darken_websites); mCheckBox = (CheckBox) holder.findViewById(R.id.darken_websites);
mLayoutContainer = (LinearLayout) holder.itemView; mLayoutContainer = (LinearLayout) holder.itemView;
mRadioGroup = (RadioGroup) holder.findViewById(R.id.radio_button_layout);
mRadioGroup.setOnCheckedChangeListener(this);
mCheckboxContainer.setOnClickListener(x -> { mCheckboxContainer.setOnClickListener(x -> {
mCheckBox.setChecked(!mCheckBox.isChecked()); mCheckBox.setChecked(!mCheckBox.isChecked());
callChangeListener(mSetting); callChangeListener(mSetting);
...@@ -81,11 +86,6 @@ public class RadioButtonGroupThemePreference ...@@ -81,11 +86,6 @@ public class RadioButtonGroupThemePreference
mButtons.set( mButtons.set(
ThemeSetting.DARK, (RadioButtonWithDescription) holder.findViewById(R.id.dark)); ThemeSetting.DARK, (RadioButtonWithDescription) holder.findViewById(R.id.dark));
for (int i = 0; i < ThemeSetting.NUM_ENTRIES; i++) {
mButtons.get(i).setRadioButtonGroup(mButtons);
mButtons.get(i).setOnCheckedChangeListener(this);
}
mButtons.get(mSetting).setChecked(true); mButtons.get(mSetting).setChecked(true);
positionCheckbox(); positionCheckbox();
} }
...@@ -107,7 +107,7 @@ public class RadioButtonGroupThemePreference ...@@ -107,7 +107,7 @@ public class RadioButtonGroupThemePreference
} }
@Override @Override
public void onCheckedChanged() { public void onCheckedChanged(RadioGroup group, int checkedId) {
for (int i = 0; i < ThemeSetting.NUM_ENTRIES; i++) { for (int i = 0; i < ThemeSetting.NUM_ENTRIES; i++) {
if (mButtons.get(i).isChecked()) { if (mButtons.get(i).isChecked()) {
mSetting = i; mSetting = i;
......
...@@ -8,23 +8,22 @@ import android.content.Context; ...@@ -8,23 +8,22 @@ import android.content.Context;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder; import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.RadioGroup;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.ui.widget.RadioButtonWithDescription; import org.chromium.chrome.browser.ui.widget.RadioButtonWithDescription;
import java.util.Arrays;
import java.util.List;
/** /**
* A 3-state Allowed/Ask/Blocked radio group Preference used for SiteSettings. * A 3-state Allowed/Ask/Blocked radio group Preference used for SiteSettings.
*/ */
public class TriStateSiteSettingsPreference public class TriStateSiteSettingsPreference
extends Preference implements RadioButtonWithDescription.OnCheckedChangeListener { extends Preference implements RadioGroup.OnCheckedChangeListener {
private @ContentSettingValues int mSetting = ContentSettingValues.DEFAULT; private @ContentSettingValues int mSetting = ContentSettingValues.DEFAULT;
private int[] mDescriptionIds; private int[] mDescriptionIds;
private RadioButtonWithDescription mAllowed; private RadioButtonWithDescription mAllowed;
private RadioButtonWithDescription mAsk; private RadioButtonWithDescription mAsk;
private RadioButtonWithDescription mBlocked; private RadioButtonWithDescription mBlocked;
private RadioGroup mRadioGroup;
public TriStateSiteSettingsPreference(Context context, AttributeSet attrs) { public TriStateSiteSettingsPreference(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
...@@ -57,7 +56,7 @@ public class TriStateSiteSettingsPreference ...@@ -57,7 +56,7 @@ public class TriStateSiteSettingsPreference
} }
@Override @Override
public void onCheckedChanged() { public void onCheckedChanged(RadioGroup group, int checkedId) {
if (mAllowed.isChecked()) { if (mAllowed.isChecked()) {
mSetting = ContentSettingValues.ALLOW; mSetting = ContentSettingValues.ALLOW;
} else if (mAsk.isChecked()) { } else if (mAsk.isChecked()) {
...@@ -76,6 +75,8 @@ public class TriStateSiteSettingsPreference ...@@ -76,6 +75,8 @@ public class TriStateSiteSettingsPreference
mAllowed = (RadioButtonWithDescription) holder.findViewById(R.id.allowed); mAllowed = (RadioButtonWithDescription) holder.findViewById(R.id.allowed);
mAsk = (RadioButtonWithDescription) holder.findViewById(R.id.ask); mAsk = (RadioButtonWithDescription) holder.findViewById(R.id.ask);
mBlocked = (RadioButtonWithDescription) holder.findViewById(R.id.blocked); mBlocked = (RadioButtonWithDescription) holder.findViewById(R.id.blocked);
mRadioGroup = (RadioGroup) holder.findViewById(R.id.radio_button_layout);
mRadioGroup.setOnCheckedChangeListener(this);
if (mDescriptionIds != null) { if (mDescriptionIds != null) {
mAllowed.setDescriptionText(getContext().getText(mDescriptionIds[0])); mAllowed.setDescriptionText(getContext().getText(mDescriptionIds[0]));
...@@ -83,12 +84,6 @@ public class TriStateSiteSettingsPreference ...@@ -83,12 +84,6 @@ public class TriStateSiteSettingsPreference
mBlocked.setDescriptionText(getContext().getText(mDescriptionIds[2])); mBlocked.setDescriptionText(getContext().getText(mDescriptionIds[2]));
} }
List<RadioButtonWithDescription> radioGroup = Arrays.asList(mAllowed, mAsk, mBlocked);
for (RadioButtonWithDescription option : radioGroup) {
option.setRadioButtonGroup(radioGroup);
option.setOnCheckedChangeListener(this);
}
RadioButtonWithDescription radioButton = findRadioButton(mSetting); RadioButtonWithDescription radioButton = findRadioButton(mSetting);
if (radioButton != null) radioButton.setChecked(true); if (radioButton != null) radioButton.setChecked(true);
} }
......
...@@ -25,6 +25,7 @@ android_library("java") { ...@@ -25,6 +25,7 @@ android_library("java") {
"java/src/org/chromium/chrome/browser/ui/widget/MoreProgressButton.java", "java/src/org/chromium/chrome/browser/ui/widget/MoreProgressButton.java",
"java/src/org/chromium/chrome/browser/ui/widget/RadioButtonLayout.java", "java/src/org/chromium/chrome/browser/ui/widget/RadioButtonLayout.java",
"java/src/org/chromium/chrome/browser/ui/widget/RadioButtonWithDescription.java", "java/src/org/chromium/chrome/browser/ui/widget/RadioButtonWithDescription.java",
"java/src/org/chromium/chrome/browser/ui/widget/RadioButtonWithDescriptionLayout.java",
"java/src/org/chromium/chrome/browser/ui/widget/RoundedCornerImageView.java", "java/src/org/chromium/chrome/browser/ui/widget/RoundedCornerImageView.java",
"java/src/org/chromium/chrome/browser/ui/widget/RoundedIconGenerator.java", "java/src/org/chromium/chrome/browser/ui/widget/RoundedIconGenerator.java",
"java/src/org/chromium/chrome/browser/ui/widget/TintedDrawable.java", "java/src/org/chromium/chrome/browser/ui/widget/TintedDrawable.java",
...@@ -157,6 +158,7 @@ android_library("ui_widget_java_tests") { ...@@ -157,6 +158,7 @@ android_library("ui_widget_java_tests") {
"java/src/org/chromium/chrome/browser/ui/widget/DualControlLayoutTest.java", "java/src/org/chromium/chrome/browser/ui/widget/DualControlLayoutTest.java",
"java/src/org/chromium/chrome/browser/ui/widget/PromoDialogTest.java", "java/src/org/chromium/chrome/browser/ui/widget/PromoDialogTest.java",
"java/src/org/chromium/chrome/browser/ui/widget/RadioButtonLayoutTest.java", "java/src/org/chromium/chrome/browser/ui/widget/RadioButtonLayoutTest.java",
"java/src/org/chromium/chrome/browser/ui/widget/RadioButtonWithDescriptionLayoutTest.java",
"java/src/org/chromium/chrome/browser/ui/widget/RoundedIconGeneratorTest.java", "java/src/org/chromium/chrome/browser/ui/widget/RoundedIconGeneratorTest.java",
"java/src/org/chromium/chrome/browser/ui/widget/highlight/ViewHighlighterTest.java", "java/src/org/chromium/chrome/browser/ui/widget/highlight/ViewHighlighterTest.java",
"java/src/org/chromium/chrome/browser/ui/widget/MoreProgressButtonTest.java", "java/src/org/chromium/chrome/browser/ui/widget/MoreProgressButtonTest.java",
......
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
found in the LICENSE file. --> found in the LICENSE file. -->
<!-- RadioButtonWithDescription extends RelativeLayout --> <!-- RadioButtonWithDescription extends RelativeLayout -->
<merge xmlns:android="http://schemas.android.com/apk/res/android"> <merge
xmlns:android="http://schemas.android.com/apk/res/android">
<RadioButton <RadioButton
android:id="@+id/radio_button" android:id="@+id/radio_button"
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
<!-- DualControlLayout dimensions --> <!-- DualControlLayout dimensions -->
<dimen name="dual_control_margin_between_items">8dp</dimen> <dimen name="dual_control_margin_between_items">8dp</dimen>
<!-- RadioButton(WithDescription)Layout dimensions -->
<dimen name="default_vertical_margin_between_items">8dp</dimen>
<!-- RadioButtonWithDescription dimensions --> <!-- RadioButtonWithDescription dimensions -->
<dimen name="radio_button_with_description_lateral_padding">16dp</dimen> <dimen name="radio_button_with_description_lateral_padding">16dp</dimen>
<dimen name="radio_button_with_description_vertical_padding">10dp</dimen> <dimen name="radio_button_with_description_vertical_padding">10dp</dimen>
......
...@@ -36,7 +36,7 @@ public final class RadioButtonLayout extends RadioGroup { ...@@ -36,7 +36,7 @@ public final class RadioButtonLayout extends RadioGroup {
public RadioButtonLayout(Context context, AttributeSet attrs) { public RadioButtonLayout(Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
mMarginBetweenRows = context.getResources().getDimensionPixelSize( mMarginBetweenRows = context.getResources().getDimensionPixelSize(
R.dimen.dual_control_margin_between_items); R.dimen.default_vertical_margin_between_items);
} }
/** /**
......
...@@ -27,12 +27,18 @@ public class RadioButtonWithDescription extends RelativeLayout implements OnClic ...@@ -27,12 +27,18 @@ public class RadioButtonWithDescription extends RelativeLayout implements OnClic
/** /**
* Interface to listen to radio button changes. * Interface to listen to radio button changes.
*/ */
public interface OnCheckedChangeListener { abstract void onCheckedChanged(); } interface ButtonCheckedStateChangedListener {
/**
* Invoked when a {@link RadioButtonWithDescription} is selected.
* @param checkedRadioButton The radio button that was selected.
*/
void onButtonCheckedStateChanged(RadioButtonWithDescription checkedRadioButton);
}
private RadioButton mRadioButton; private RadioButton mRadioButton;
private TextView mTitle; private TextView mTitle;
private TextView mDescription; private TextView mDescription;
private OnCheckedChangeListener mOnCheckedChangeListener; private ButtonCheckedStateChangedListener mButtonCheckedStateChangedListener;
private List<RadioButtonWithDescription> mGroup; private List<RadioButtonWithDescription> mGroup;
...@@ -100,8 +106,8 @@ public class RadioButtonWithDescription extends RelativeLayout implements OnClic ...@@ -100,8 +106,8 @@ public class RadioButtonWithDescription extends RelativeLayout implements OnClic
setChecked(true); setChecked(true);
if (mOnCheckedChangeListener != null) { if (mButtonCheckedStateChangedListener != null) {
mOnCheckedChangeListener.onCheckedChanged(); mButtonCheckedStateChangedListener.onButtonCheckedStateChanged(this);
} }
} }
...@@ -112,6 +118,13 @@ public class RadioButtonWithDescription extends RelativeLayout implements OnClic ...@@ -112,6 +118,13 @@ public class RadioButtonWithDescription extends RelativeLayout implements OnClic
mTitle.setText(text); mTitle.setText(text);
} }
/**
* @return The text shown in the title section.
*/
public CharSequence getTitleText() {
return mTitle.getText();
}
/** /**
* Sets the text shown in the description section. * Sets the text shown in the description section.
*/ */
...@@ -127,6 +140,13 @@ public class RadioButtonWithDescription extends RelativeLayout implements OnClic ...@@ -127,6 +140,13 @@ public class RadioButtonWithDescription extends RelativeLayout implements OnClic
} }
} }
/**
* @return The text shown in the description section.
*/
public CharSequence getDescriptionText() {
return mDescription.getText();
}
/** /**
* Returns true if checked. * Returns true if checked.
*/ */
...@@ -145,8 +165,8 @@ public class RadioButtonWithDescription extends RelativeLayout implements OnClic ...@@ -145,8 +165,8 @@ public class RadioButtonWithDescription extends RelativeLayout implements OnClic
if (checked) requestFocus(); if (checked) requestFocus();
} }
public void setOnCheckedChangeListener(OnCheckedChangeListener listener) { public void setOnCheckedChangeListener(ButtonCheckedStateChangedListener listener) {
mOnCheckedChangeListener = listener; mButtonCheckedStateChangedListener = listener;
} }
/** /**
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.ui.widget;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.RadioGroup;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* Manages a group of exclusive RadioButtonWithDescriptions, automatically inserting a margin in
* between the rows to prevent them from squishing together.
*
* -------------------------------------------------
* | O | MESSAGE #1 |
* description_1 |
* | O | MESSAGE #N |
* description_n |
* -------------------------------------------------
*/
public final class RadioButtonWithDescriptionLayout
extends RadioGroup implements RadioButtonWithDescription.ButtonCheckedStateChangedListener {
/** Encapsulates information required to build a layout. */
public static class Option {
private final CharSequence mTitle;
private final CharSequence mDescription;
private final Object mTag;
/**
* @param title The title for this option. This will be displayed as the main text for the
* checkbox.
* @param description The description for this option. This will be displayed as the subtext
* under the main text for the checkbox.
* @param tag The tag for this option. This can be used to identify the checkbox in event
* listeners.
*/
public Option(CharSequence title, CharSequence description, @Nullable Object tag) {
mTitle = title;
mDescription = description;
mTag = tag;
}
public CharSequence getTitle() {
return mTitle;
}
public CharSequence getDescription() {
return mDescription;
}
public Object getTag() {
return mTag;
}
}
private final int mMarginBetweenRows;
private final List<RadioButtonWithDescription> mRadioButtonsWithDescriptions;
private OnCheckedChangeListener mOnCheckedChangeListener;
public RadioButtonWithDescriptionLayout(Context context) {
this(context, null);
}
public RadioButtonWithDescriptionLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mMarginBetweenRows = context.getResources().getDimensionPixelSize(
R.dimen.default_vertical_margin_between_items);
mRadioButtonsWithDescriptions = new ArrayList<>();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
RadioButtonWithDescription b = (RadioButtonWithDescription) getChildAt(i);
setupButton(b);
}
updateMargins();
}
/**
* @see RadioGroup.OnCheckedChangeListener
*/
@Override
public void setOnCheckedChangeListener(OnCheckedChangeListener onCheckedChangeListener) {
mOnCheckedChangeListener = onCheckedChangeListener;
}
/**
* @see RadioButtonWithDescription.ButtonCheckedStateChangedListener
*/
@Override
public void onButtonCheckedStateChanged(RadioButtonWithDescription checkedRadioButton) {
mOnCheckedChangeListener.onCheckedChanged(this, checkedRadioButton.getId());
}
/**
* Given a set of {@link Option} creates a set of {@link RadioButtonWithDescription}. When lists
* are built this way, there are two options for getting the checkbox you want in an event
* listener callback.
* 1. Set a tag on the Option and use that with {@link View#findViewWithTag).
* 2. Use the id passed through to {@link RadioGroup.OnCheckedChangeListener#onCheckedChanged}.
* with {@link View#findViewById}.
*
* @param options List of options to add to this group.
*/
public void addOptions(List<Option> options) {
for (Option option : options) {
RadioButtonWithDescription b = new RadioButtonWithDescription(getContext(), null);
b.setTitleText(option.getTitle());
b.setDescriptionText(option.getDescription());
b.setTag(option.getTag());
setupButton(b);
addView(b, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
}
updateMargins();
}
/** Sets margins between each of the radio buttons. */
private void updateMargins() {
int childCount = getChildCount();
for (int i = 0; i < childCount - 1; i++) {
View child = getChildAt(i);
MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();
params.bottomMargin = mMarginBetweenRows;
}
// LayoutParam changes only take effect after the next layout pass.
requestLayout();
}
private void setupButton(RadioButtonWithDescription radioButton) {
radioButton.setOnCheckedChangeListener(this);
// Give the button a unique id to allow for calling onCheckedChanged (see
// #onCheckedChanged).
if (radioButton.getId() == NO_ID) radioButton.setId(generateViewId());
radioButton.setRadioButtonGroup(mRadioButtonsWithDescriptions);
mRadioButtonsWithDescriptions.add(radioButton);
}
/**
* Marks a RadioButton child as being checked.
*
* @param childIndex Index of the child to select.
*/
void selectChildAtIndexForTesting(int childIndex) {
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
RadioButtonWithDescription b = (RadioButtonWithDescription) getChildAt(i);
b.setChecked(i == childIndex);
}
}
}
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.ui.widget;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.annotation.UiThreadTest;
import android.support.test.filters.SmallTest;
import android.support.test.rule.UiThreadTestRule;
import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import java.util.ArrayList;
import java.util.List;
/**
* Tests for {@link RadioButtonLayout}.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
public class RadioButtonWithDescriptionLayoutTest {
private static final String NON_ZERO_MARGIN_ASSERT_MESSAGE =
"First N-1 items should have a non-zero margin";
private static final String ZERO_MARGIN_ASSERT_MESSAGE =
"The last item should have a zero margin";
private static final String TITLE_MATCH_ASSERT_MESSAGE =
"Title set through addOptions should match the view's title.";
private static final String DESCRIPTION_MATCH_ASSERT_MESSAGE =
"Description set through addOptions should match the view's description.";
private static final String TAG_MATCH_ASSERT_MESSAGE =
"Tag set through addOptions should match the view's tag.";
@Rule
public UiThreadTestRule mRule = new UiThreadTestRule();
private Context mContext;
@Before
public void setUp() {
mContext = InstrumentationRegistry.getTargetContext();
}
@Test
@SmallTest
@UiThreadTest
public void testMargins() {
RadioButtonWithDescriptionLayout layout = new RadioButtonWithDescriptionLayout(mContext);
// Add one set of options.
List<RadioButtonWithDescriptionLayout.Option> options = new ArrayList<>();
options.add(new RadioButtonWithDescriptionLayout.Option("a", "a_desc", "a_tag"));
options.add(new RadioButtonWithDescriptionLayout.Option("b", "b_desc", "b_tag"));
options.add(new RadioButtonWithDescriptionLayout.Option("c", "c_desc", "c_tag"));
layout.addOptions(options);
Assert.assertEquals(3, layout.getChildCount());
// Test the margins.
for (int i = 0; i < layout.getChildCount(); i++) {
View child = layout.getChildAt(i);
MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();
if (i < layout.getChildCount() - 1) {
Assert.assertNotEquals(NON_ZERO_MARGIN_ASSERT_MESSAGE, 0, params.bottomMargin);
} else {
Assert.assertEquals(ZERO_MARGIN_ASSERT_MESSAGE, 0, params.bottomMargin);
}
}
// Add more options.
List<RadioButtonWithDescriptionLayout.Option> moreOptions = new ArrayList<>();
moreOptions.add(new RadioButtonWithDescriptionLayout.Option("d", "d_desc", null));
moreOptions.add(new RadioButtonWithDescriptionLayout.Option("e", "e_desc", null));
moreOptions.add(new RadioButtonWithDescriptionLayout.Option("f", "f_desc", null));
layout.addOptions(moreOptions);
Assert.assertEquals(6, layout.getChildCount());
// Test the margins.
for (int i = 0; i < layout.getChildCount(); i++) {
View child = layout.getChildAt(i);
MarginLayoutParams params = (MarginLayoutParams) child.getLayoutParams();
if (i < layout.getChildCount() - 1) {
Assert.assertNotEquals(NON_ZERO_MARGIN_ASSERT_MESSAGE, 0, params.bottomMargin);
} else {
Assert.assertEquals(ZERO_MARGIN_ASSERT_MESSAGE, 0, params.bottomMargin);
}
}
}
@Test
@SmallTest
@UiThreadTest
public void testAddOptions() {
RadioButtonWithDescriptionLayout layout = new RadioButtonWithDescriptionLayout(mContext);
// Add one set of options.
List<RadioButtonWithDescriptionLayout.Option> options = new ArrayList<>();
options.add(new RadioButtonWithDescriptionLayout.Option("a", "a_desc", "a_tag"));
options.add(new RadioButtonWithDescriptionLayout.Option("b", "b_desc", "b_tag"));
options.add(new RadioButtonWithDescriptionLayout.Option("c", "c_desc", "c_tag"));
layout.addOptions(options);
Assert.assertEquals(3, layout.getChildCount());
for (int i = 0; i < layout.getChildCount(); i++) {
RadioButtonWithDescription b = (RadioButtonWithDescription) layout.getChildAt(i);
Assert.assertEquals(
TITLE_MATCH_ASSERT_MESSAGE, options.get(i).getTitle(), b.getTitleText());
Assert.assertEquals(DESCRIPTION_MATCH_ASSERT_MESSAGE, options.get(i).getDescription(),
b.getDescriptionText());
Assert.assertEquals(TAG_MATCH_ASSERT_MESSAGE, options.get(i).getTag(), b.getTag());
}
// Add even more options, but without tags.
List<RadioButtonWithDescriptionLayout.Option> moreOptions = new ArrayList<>();
moreOptions.add(new RadioButtonWithDescriptionLayout.Option("d", "d_desc", null));
moreOptions.add(new RadioButtonWithDescriptionLayout.Option("e", "e_desc", null));
moreOptions.add(new RadioButtonWithDescriptionLayout.Option("f", "f_desc", null));
layout.addOptions(moreOptions);
Assert.assertEquals(6, layout.getChildCount());
for (int i = 0; i < 3; i++) {
RadioButtonWithDescription b = (RadioButtonWithDescription) layout.getChildAt(i);
Assert.assertEquals(
TITLE_MATCH_ASSERT_MESSAGE, options.get(i).getTitle(), b.getTitleText());
Assert.assertEquals(DESCRIPTION_MATCH_ASSERT_MESSAGE, options.get(i).getDescription(),
b.getDescriptionText());
Assert.assertEquals(TAG_MATCH_ASSERT_MESSAGE, options.get(i).getTag(), b.getTag());
}
for (int i = 3; i < 6; i++) {
RadioButtonWithDescription b = (RadioButtonWithDescription) layout.getChildAt(i);
Assert.assertEquals(TITLE_MATCH_ASSERT_MESSAGE, moreOptions.get(i - 3).getTitle(),
b.getTitleText());
Assert.assertEquals(DESCRIPTION_MATCH_ASSERT_MESSAGE,
moreOptions.get(i - 3).getDescription(), b.getDescriptionText());
Assert.assertEquals(
TAG_MATCH_ASSERT_MESSAGE, moreOptions.get(i - 3).getTag(), b.getTag());
}
}
@Test
@SmallTest
@UiThreadTest
public void testSelection() {
final RadioButtonWithDescriptionLayout layout =
new RadioButtonWithDescriptionLayout(mContext);
// Add one set of options.
List<RadioButtonWithDescriptionLayout.Option> options = new ArrayList<>();
options.add(new RadioButtonWithDescriptionLayout.Option("a", "a_desc", null));
options.add(new RadioButtonWithDescriptionLayout.Option("b", "b_desc", null));
options.add(new RadioButtonWithDescriptionLayout.Option("c", "c_desc", null));
layout.addOptions(options);
Assert.assertEquals(3, layout.getChildCount());
// Nothing should be selected by default.
for (int i = 0; i < layout.getChildCount(); i++) {
RadioButtonWithDescription child = (RadioButtonWithDescription) layout.getChildAt(i);
Assert.assertFalse(child.isChecked());
}
// Select the second one.
layout.selectChildAtIndexForTesting(1);
for (int i = 0; i < layout.getChildCount(); i++) {
RadioButtonWithDescription child = (RadioButtonWithDescription) layout.getChildAt(i);
Assert.assertEquals(i == 1, child.isChecked());
}
// Add even more options.
List<RadioButtonWithDescriptionLayout.Option> moreOptions = new ArrayList<>();
moreOptions.add(new RadioButtonWithDescriptionLayout.Option("d", "d_desc", null));
moreOptions.add(new RadioButtonWithDescriptionLayout.Option("e", "e_desc", null));
moreOptions.add(new RadioButtonWithDescriptionLayout.Option("f", "f_desc", null));
layout.addOptions(moreOptions);
Assert.assertEquals(6, layout.getChildCount());
// Second child should still be checked.
for (int i = 0; i < layout.getChildCount(); i++) {
RadioButtonWithDescription child = (RadioButtonWithDescription) layout.getChildAt(i);
Assert.assertEquals(i == 1, child.isChecked());
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment