Add Extra gear icon in RadioButtonPreference

- By default, gear icon is invisible
- Developer can set a click listener to gear icon

Bug: 173472216
Test: manual & robotest
Change-Id: Ic23848c6686bfe99dace1205349f0133ccff7075
This commit is contained in:
Edgar Wang
2020-11-17 13:11:34 +08:00
parent 1346575ebc
commit e8c4fa7558
5 changed files with 159 additions and 19 deletions

View File

@@ -0,0 +1,29 @@
<!--
Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?android:attr/colorAccent">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M13.85,22.25h-3.7c-0.74,0 -1.36,-0.54 -1.45,-1.27l-0.27,-1.89c-0.27,-0.14 -0.53,-0.29 -0.79,-0.46l-1.8,0.72c-0.7,0.26 -1.47,-0.03 -1.81,-0.65L2.2,15.53c-0.35,-0.66 -0.2,-1.44 0.36,-1.88l1.53,-1.19c-0.01,-0.15 -0.02,-0.3 -0.02,-0.46c0,-0.15 0.01,-0.31 0.02,-0.46l-1.52,-1.19C1.98,9.9 1.83,9.09 2.2,8.47l1.85,-3.19c0.34,-0.62 1.11,-0.9 1.79,-0.63l1.81,0.73c0.26,-0.17 0.52,-0.32 0.78,-0.46l0.27,-1.91c0.09,-0.7 0.71,-1.25 1.44,-1.25h3.7c0.74,0 1.36,0.54 1.45,1.27l0.27,1.89c0.27,0.14 0.53,0.29 0.79,0.46l1.8,-0.72c0.71,-0.26 1.48,0.03 1.82,0.65l1.84,3.18c0.36,0.66 0.2,1.44 -0.36,1.88l-1.52,1.19c0.01,0.15 0.02,0.3 0.02,0.46s-0.01,0.31 -0.02,0.46l1.52,1.19c0.56,0.45 0.72,1.23 0.37,1.86l-1.86,3.22c-0.34,0.62 -1.11,0.9 -1.8,0.63l-1.8,-0.72c-0.26,0.17 -0.52,0.32 -0.78,0.46l-0.27,1.91C15.21,21.71 14.59,22.25 13.85,22.25zM13.32,20.72c0,0.01 0,0.01 0,0.02L13.32,20.72zM10.68,20.7l0,0.02C10.69,20.72 10.69,20.71 10.68,20.7zM10.62,20.25h2.76l0.37,-2.55l0.53,-0.22c0.44,-0.18 0.88,-0.44 1.34,-0.78l0.45,-0.34l2.38,0.96l1.38,-2.4l-2.03,-1.58l0.07,-0.56c0.03,-0.26 0.06,-0.51 0.06,-0.78c0,-0.27 -0.03,-0.53 -0.06,-0.78l-0.07,-0.56l2.03,-1.58l-1.39,-2.4l-2.39,0.96l-0.45,-0.35c-0.42,-0.32 -0.87,-0.58 -1.33,-0.77L13.75,6.3l-0.37,-2.55h-2.76L10.25,6.3L9.72,6.51C9.28,6.7 8.84,6.95 8.38,7.3L7.93,7.63L5.55,6.68L4.16,9.07l2.03,1.58l-0.07,0.56C6.09,11.47 6.06,11.74 6.06,12c0,0.26 0.02,0.53 0.06,0.78l0.07,0.56l-2.03,1.58l1.38,2.4l2.39,-0.96l0.45,0.35c0.43,0.33 0.86,0.58 1.33,0.77l0.53,0.22L10.62,20.25zM18.22,17.72c0,0.01 -0.01,0.02 -0.01,0.03L18.22,17.72zM5.77,17.71l0.01,0.02C5.78,17.72 5.77,17.71 5.77,17.71zM3.93,9.47L3.93,9.47C3.93,9.47 3.93,9.47 3.93,9.47zM18.22,6.27c0,0.01 0.01,0.02 0.01,0.02L18.22,6.27zM5.79,6.25L5.78,6.27C5.78,6.27 5.79,6.26 5.79,6.25zM13.31,3.28c0,0.01 0,0.01 0,0.02L13.31,3.28zM10.69,3.26l0,0.02C10.69,3.27 10.69,3.27 10.69,3.26z"/>
<path
android:fillColor="#FFFFFFFF"
android:pathData="M12,12m-3.5,0a3.5,3.5 0,1 1,7 0a3.5,3.5 0,1 1,-7 0"/>
</vector>

View File

@@ -92,16 +92,32 @@
android:textAlignment="viewEnd"
android:textColor="?android:attr/textColorSecondary"
android:maxLines="1"
android:visibility="gone"
android:ellipsize="end"/>
</LinearLayout>
<ProgressBar
android:id="@android:id/progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:max="100"
android:visibility="gone"/>
</LinearLayout>
<LinearLayout
android:id="@+id/radio_extra_widget_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center_vertical">
<View
android:layout_width=".75dp"
android:layout_height="match_parent"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:background="?android:attr/dividerVertical" />
<ImageView
android:id="@+id/radio_extra_widget"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:src="@drawable/ic_settings_accent"
android:contentDescription="@string/settings_label"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:layout_gravity="center"
android:background="?android:attr/selectableItemBackground" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2021 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Content description for RadioButton with extra gear icon [CHAR LIMIT=NONE] -->
<string name="settings_label">Settings</string>
</resources>

View File

@@ -20,7 +20,7 @@ import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.TextView;
import android.widget.ImageView;
import androidx.preference.CheckBoxPreference;
import androidx.preference.PreferenceViewHolder;
@@ -34,6 +34,9 @@ import androidx.preference.PreferenceViewHolder;
* In other words, there's no "RadioButtonPreferenceGroup" in this
* implementation. When you check one RadioButtonPreference, if you want to
* uncheck all the other preferences, you should do that by code yourself.
*
* RadioButtonPreference can assign a extraWidgetListener to show a gear icon
* on the right side that can open another page.
*/
public class RadioButtonPreference extends CheckBoxPreference {
@@ -53,6 +56,10 @@ public class RadioButtonPreference extends CheckBoxPreference {
private View mAppendix;
private int mAppendixVisibility = -1;
private View mExtraWidgetContainer;
private ImageView mExtraWidget;
private View.OnClickListener mExtraWidgetOnClickListener;
/**
* Perform inflation from XML and apply a class-specific base style.
@@ -69,7 +76,6 @@ public class RadioButtonPreference extends CheckBoxPreference {
init();
}
/**
* Perform inflation from XML and apply a class-specific base style.
*
@@ -136,11 +142,10 @@ public class RadioButtonPreference extends CheckBoxPreference {
}
}
TextView title = (TextView) holder.findViewById(android.R.id.title);
if (title != null) {
title.setSingleLine(false);
title.setMaxLines(3);
}
mExtraWidget = (ImageView) holder.findViewById(R.id.radio_extra_widget);
mExtraWidgetContainer = holder.findViewById(R.id.radio_extra_widget_container);
setExtraWidgetOnClickListener(mExtraWidgetOnClickListener);
}
/**
@@ -155,6 +160,24 @@ public class RadioButtonPreference extends CheckBoxPreference {
mAppendixVisibility = visibility;
}
/**
* Sets the callback to be invoked when extra widget is clicked by the user.
*
* @param listener The callback to be invoked
*/
public void setExtraWidgetOnClickListener(View.OnClickListener listener) {
mExtraWidgetOnClickListener = listener;
if (mExtraWidget == null || mExtraWidgetContainer == null) {
return;
}
mExtraWidget.setOnClickListener(mExtraWidgetOnClickListener);
mExtraWidgetContainer.setVisibility((mExtraWidgetOnClickListener != null)
? View.VISIBLE : View.GONE);
}
private void init() {
setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
setLayoutResource(R.layout.preference_radio);

View File

@@ -40,10 +40,30 @@ public class RadioButtonPreferenceTest {
private Application mContext;
private RadioButtonPreference mPreference;
private View mExtraWidgetContainer;
private View mExtraWidget;
private boolean mIsClickListenerCalled;
private View.OnClickListener mClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
mIsClickListenerCalled = true;
}
};
@Before
public void setUp() {
mContext = RuntimeEnvironment.application;
mPreference = new RadioButtonPreference(mContext);
View view = LayoutInflater.from(mContext)
.inflate(R.layout.preference_radio, null /* root */);
PreferenceViewHolder preferenceViewHolder =
PreferenceViewHolder.createInstanceForTests(view);
mPreference.onBindViewHolder(preferenceViewHolder);
mExtraWidgetContainer = view.findViewById(R.id.radio_extra_widget_container);
mExtraWidget = view.findViewById(R.id.radio_extra_widget);
}
@Test
@@ -57,26 +77,30 @@ public class RadioButtonPreferenceTest {
}
@Test
public void summary_containerShouldBeVisible() {
public void onBindViewHolder_withSummary_containerShouldBeVisible() {
mPreference.setSummary("some summary");
View summaryContainer = new View(mContext);
View view = mock(View.class);
when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
PreferenceViewHolder preferenceViewHolder =
PreferenceViewHolder.createInstanceForTests(view);
mPreference.onBindViewHolder(preferenceViewHolder);
assertEquals(View.VISIBLE, summaryContainer.getVisibility());
}
@Test
public void emptySummary_containerShouldBeGone() {
public void onBindViewHolder_emptySummary_containerShouldBeGone() {
mPreference.setSummary("");
View summaryContainer = new View(mContext);
View view = mock(View.class);
when(view.findViewById(R.id.summary_container)).thenReturn(summaryContainer);
PreferenceViewHolder preferenceViewHolder =
PreferenceViewHolder.createInstanceForTests(view);
mPreference.onBindViewHolder(preferenceViewHolder);
assertEquals(View.GONE, summaryContainer.getVisibility());
}
@@ -93,11 +117,36 @@ public class RadioButtonPreferenceTest {
}
@Test
public void hideAppendix_shouldBeGone() {
public void setAppendixVisibility_setGone_shouldBeGone() {
mPreference.setAppendixVisibility(View.GONE);
View view = LayoutInflater.from(mContext).inflate(R.layout.preference_radio, null);
View view = LayoutInflater.from(mContext)
.inflate(R.layout.preference_radio, null /* root */);
PreferenceViewHolder holder = PreferenceViewHolder.createInstanceForTests(view);
mPreference.onBindViewHolder(holder);
assertThat(holder.findViewById(R.id.appendix).getVisibility()).isEqualTo(View.GONE);
}
@Test
public void setExtraWidgetListener_setNull_extraWidgetShouldInvisible() {
mPreference.setExtraWidgetOnClickListener(null);
assertEquals(View.GONE, mExtraWidgetContainer.getVisibility());
}
@Test
public void setExtraWidgetListener_extraWidgetShouldVisible() {
mPreference.setExtraWidgetOnClickListener(mClickListener);
assertEquals(View.VISIBLE, mExtraWidgetContainer.getVisibility());
}
@Test
public void onClickListener_setExtraWidgetOnClickListener_ShouldCalled() {
mPreference.setExtraWidgetOnClickListener(mClickListener);
assertThat(mIsClickListenerCalled).isFalse();
mExtraWidget.callOnClick();
assertThat(mIsClickListenerCalled).isTrue();
}
}