Merge "Rename RadioButtonPreference to SelectorWithWidgetPreference, and add a checkbox styling option."
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 2b8f049..e8ed88f 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -37,6 +37,7 @@
"SettingsLibProgressBar",
"SettingsLibAdaptiveIcon",
"SettingsLibRadioButtonPreference",
+ "SettingsLibSelectorWithWidgetPreference",
"SettingsLibDisplayDensityUtils",
"SettingsLibUtils",
"SettingsLibEmergencyNumber",
diff --git a/packages/SettingsLib/RadioButtonPreference/Android.bp b/packages/SettingsLib/RadioButtonPreference/Android.bp
index 28ff71f..1387daa 100644
--- a/packages/SettingsLib/RadioButtonPreference/Android.bp
+++ b/packages/SettingsLib/RadioButtonPreference/Android.bp
@@ -15,6 +15,7 @@
static_libs: [
"androidx.preference_preference",
+ "SettingsLibSelectorWithWidgetPreference",
"SettingsLibSettingsTheme",
],
diff --git a/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java b/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
index f50127f..02d3c06 100644
--- a/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
+++ b/packages/SettingsLib/RadioButtonPreference/src/com/android/settingslib/widget/RadioButtonPreference.java
@@ -26,6 +26,10 @@
import androidx.preference.PreferenceViewHolder;
/**
+ * DEPRECATED. Please use SelectorWithWidgetPreference instead.
+ *
+ * This file has been moved there and will be removed once all callers are updated.
+ *
* Check box preference with check box replaced by radio button.
*
* Functionally speaking, it's actually a CheckBoxPreference. We only modified
@@ -37,6 +41,8 @@
*
* RadioButtonPreference can assign a extraWidgetListener to show a gear icon
* on the right side that can open another page.
+ *
+ * @Deprecated
*/
public class RadioButtonPreference extends CheckBoxPreference {
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/Android.bp b/packages/SettingsLib/SelectorWithWidgetPreference/Android.bp
new file mode 100644
index 0000000..bcc64d3
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/Android.bp
@@ -0,0 +1,27 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_library {
+ name: "SettingsLibSelectorWithWidgetPreference",
+
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+
+ static_libs: [
+ "androidx.preference_preference",
+ "SettingsLibSettingsTheme",
+ ],
+
+ sdk_version: "system_current",
+ min_sdk_version: "21",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.permission",
+ ],
+}
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/AndroidManifest.xml b/packages/SettingsLib/SelectorWithWidgetPreference/AndroidManifest.xml
new file mode 100644
index 0000000..51fc7ed
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/AndroidManifest.xml
@@ -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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.settingslib.widget">
+
+ <uses-sdk android:minSdkVersion="21" />
+
+</manifest>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/drawable/ic_settings_accent.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/drawable/ic_settings_accent.xml
new file mode 100644
index 0000000..6521bc9
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/drawable/ic_settings_accent.xml
@@ -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>
\ No newline at end of file
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_selector_with_widget.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_selector_with_widget.xml
new file mode 100644
index 0000000..8bb56ff
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_selector_with_widget.xml
@@ -0,0 +1,123 @@
+<?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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:settings="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="?android:attr/selectableItemBackground"
+ android:gravity="center_vertical"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <LinearLayout
+ android:id="@android:id/widget_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:paddingHorizontal="20dp"
+ android:gravity="center"
+ android:minWidth="56dp"
+ android:orientation="vertical"/>
+
+ <LinearLayout
+ android:id="@+id/icon_frame"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:minWidth="32dp"
+ android:orientation="horizontal"
+ android:layout_marginEnd="16dp"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp">
+ <androidx.preference.internal.PreferenceImageView
+ android:id="@android:id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ settings:maxWidth="@dimen/secondary_app_icon_size"
+ settings:maxHeight="@dimen/secondary_app_icon_size"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxLines="2"
+ android:textAppearance="?android:attr/textAppearanceListItem"/>
+
+ <LinearLayout
+ android:id="@+id/summary_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone">
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAlignment="viewStart"
+ android:textColor="?android:attr/textColorSecondary"/>
+
+ <TextView
+ android:id="@+id/appendix"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAlignment="viewEnd"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="1"
+ android:visibility="gone"
+ android:ellipsize="end"/>
+ </LinearLayout>
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/selector_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="32dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="16dp"
+ android:background="?android:attr/dividerVertical" />
+ <ImageView
+ android:id="@+id/selector_extra_widget"
+ android:layout_width="match_parent"
+ android:minWidth="@dimen/two_target_min_width"
+ android:layout_height="fill_parent"
+ android:src="@drawable/ic_settings_accent"
+ android:contentDescription="@string/settings_label"
+ android:paddingStart="24dp"
+ android:paddingEnd="24dp"
+ android:layout_gravity="center"
+ android:background="?android:attr/selectableItemBackground" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_checkbox.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_checkbox.xml
new file mode 100644
index 0000000..6dd1670
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_checkbox.xml
@@ -0,0 +1,25 @@
+<?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.
+ -->
+
+<CheckBox xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:background="@null"
+ android:focusable="false"
+ android:clickable="false" />
\ No newline at end of file
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_radiobutton.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_radiobutton.xml
new file mode 100644
index 0000000..cf6371d
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout/preference_widget_radiobutton.xml
@@ -0,0 +1,25 @@
+<?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.
+ -->
+
+<RadioButton xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:background="@null"
+ android:focusable="false"
+ android:clickable="false" />
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/values/strings.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/values/strings.xml
new file mode 100644
index 0000000..ff3f90c
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/res/values/strings.xml
@@ -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>
\ No newline at end of file
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
new file mode 100644
index 0000000..1ecc422
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
@@ -0,0 +1,203 @@
+/*
+ * 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.
+ */
+
+package com.android.settingslib.widget;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.preference.CheckBoxPreference;
+import androidx.preference.PreferenceViewHolder;
+
+/**
+ * Selector preference (checkbox or radio button) with an optional additional widget.
+ *
+ * Functionally speaking, it's a CheckBoxPreference. When styled like a radio button,
+ * it only "looks like" a RadioButtonPreference.
+ *
+ * In other words, there's no "RadioButtonPreferenceGroup" in this
+ * implementation. When you check one preference, if you want to
+ * uncheck all the other preferences, you should do that by code yourself.
+ *
+ * SelectorWithWidgetPreference can assign a extraWidgetListener to show a gear icon
+ * on the right side that can open another page.
+ */
+public class SelectorWithWidgetPreference extends CheckBoxPreference {
+
+ /**
+ * Interface definition for a callback to be invoked when the preference is clicked.
+ */
+ public interface OnClickListener {
+ /**
+ * Called when a preference has been clicked.
+ *
+ * @param emiter The clicked preference
+ */
+ void onRadioButtonClicked(SelectorWithWidgetPreference emiter);
+ }
+
+ private OnClickListener mListener = null;
+ private View mAppendix;
+ private int mAppendixVisibility = -1;
+
+ private View mExtraWidgetContainer;
+ private ImageView mExtraWidget;
+ private boolean mIsCheckBox = false; // whether to display this button as a checkbox
+
+ private View.OnClickListener mExtraWidgetOnClickListener;
+
+ /**
+ * Perform inflation from XML and apply a class-specific base style.
+ *
+ * @param context The {@link Context} this is associated with, through which it can
+ * access the current theme, resources, {@link SharedPreferences}, etc.
+ * @param attrs The attributes of the XML tag that is inflating the preference
+ * @param defStyle An attribute in the current theme that contains a reference to a style
+ * resource that supplies default values for the view. Can be 0 to not
+ * look for defaults.
+ */
+ public SelectorWithWidgetPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ /**
+ * Perform inflation from XML and apply a class-specific base style.
+ *
+ * @param context The {@link Context} this is associated with, through which it can
+ * access the current theme, resources, {@link SharedPreferences}, etc.
+ * @param attrs The attributes of the XML tag that is inflating the preference
+ */
+ public SelectorWithWidgetPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ /**
+ * Constructor to create a preference, which will display with a checkbox style.
+ *
+ * @param context The {@link Context} this is associated with.
+ * @param isCheckbox Whether this preference should display as a checkbox.
+ */
+ public SelectorWithWidgetPreference(Context context, boolean isCheckbox) {
+ super(context, null);
+ mIsCheckBox = isCheckbox;
+ init();
+ }
+
+ /**
+ * Constructor to create a preference.
+ *
+ * @param context The Context this is associated with.
+ */
+ public SelectorWithWidgetPreference(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Sets the callback to be invoked when this preference is clicked by the user.
+ *
+ * @param listener The callback to be invoked
+ */
+ public void setOnClickListener(OnClickListener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Processes a click on the preference.
+ */
+ @Override
+ public void onClick() {
+ if (mListener != null) {
+ mListener.onRadioButtonClicked(this);
+ }
+ }
+
+ /**
+ * Binds the created View to the data for this preference.
+ *
+ * <p>This is a good place to grab references to custom Views in the layout and set
+ * properties on them.
+ *
+ * <p>Make sure to call through to the superclass's implementation.
+ *
+ * @param holder The ViewHolder that provides references to the views to fill in. These views
+ * will be recycled, so you should not hold a reference to them after this method
+ * returns.
+ */
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+
+ View summaryContainer = holder.findViewById(R.id.summary_container);
+ if (summaryContainer != null) {
+ summaryContainer.setVisibility(
+ TextUtils.isEmpty(getSummary()) ? View.GONE : View.VISIBLE);
+ mAppendix = holder.findViewById(R.id.appendix);
+ if (mAppendix != null && mAppendixVisibility != -1) {
+ mAppendix.setVisibility(mAppendixVisibility);
+ }
+ }
+
+ mExtraWidget = (ImageView) holder.findViewById(R.id.selector_extra_widget);
+ mExtraWidgetContainer = holder.findViewById(R.id.selector_extra_widget_container);
+
+ setExtraWidgetOnClickListener(mExtraWidgetOnClickListener);
+ }
+
+ /**
+ * Set the visibility state of appendix view.
+ *
+ * @param visibility One of {@link View#VISIBLE}, {@link View#INVISIBLE}, or {@link View#GONE}.
+ */
+ public void setAppendixVisibility(int visibility) {
+ if (mAppendix != null) {
+ mAppendix.setVisibility(visibility);
+ }
+ 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() {
+ if (mIsCheckBox) {
+ setWidgetLayoutResource(R.layout.preference_widget_checkbox);
+ } else {
+ setWidgetLayoutResource(R.layout.preference_widget_radiobutton);
+ }
+ setLayoutResource(R.layout.preference_selector_with_widget);
+ setIconSpaceReserved(false);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java
new file mode 100644
index 0000000..34efe82
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/SelectorWithWidgetPreferenceTest.java
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+package com.android.settingslib.widget;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.app.Application;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.preference.PreferenceViewHolder;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class SelectorWithWidgetPreferenceTest {
+
+ private Application mContext;
+ private SelectorWithWidgetPreference 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 SelectorWithWidgetPreference(mContext);
+
+ View view = LayoutInflater.from(mContext)
+ .inflate(R.layout.preference_selector_with_widget, null /* root */);
+ PreferenceViewHolder preferenceViewHolder =
+ PreferenceViewHolder.createInstanceForTests(view);
+ mPreference.onBindViewHolder(preferenceViewHolder);
+
+ mExtraWidgetContainer = view.findViewById(R.id.selector_extra_widget_container);
+ mExtraWidget = view.findViewById(R.id.selector_extra_widget);
+ }
+
+ @Test
+ public void shouldHaveRadioPreferenceLayout() {
+ assertThat(mPreference.getLayoutResource()).isEqualTo(
+ R.layout.preference_selector_with_widget);
+ }
+
+ @Test
+ public void shouldHaveRadioButtonWidgetLayoutByDefault() {
+ assertThat(mPreference.getWidgetLayoutResource())
+ .isEqualTo(R.layout.preference_widget_radiobutton);
+ }
+
+ @Test
+ public void shouldHaveCheckBoxWidgetLayoutIfSet() {
+ mPreference = new SelectorWithWidgetPreference(mContext, true);
+ assertThat(mPreference.getWidgetLayoutResource())
+ .isEqualTo(R.layout.preference_widget_checkbox);
+ }
+
+ @Test
+ public void iconSpaceReservedShouldBeFalse() {
+ assertThat(mPreference.isIconSpaceReserved()).isFalse();
+ }
+
+ @Test
+ 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 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());
+ }
+
+ @Test
+ public void nullSummary_containerShouldBeGone() {
+ mPreference.setSummary(null);
+ 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());
+ }
+
+ @Test
+ public void setAppendixVisibility_setGone_shouldBeGone() {
+ mPreference.setAppendixVisibility(View.GONE);
+
+ View view = LayoutInflater.from(mContext)
+ .inflate(R.layout.preference_selector_with_widget, 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();
+ }
+}