diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 2b8f049a36fc7..e8ed88fc02222 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -37,6 +37,7 @@ android_library {
"SettingsLibProgressBar",
"SettingsLibAdaptiveIcon",
"SettingsLibRadioButtonPreference",
+ "SettingsLibSelectorWithWidgetPreference",
"SettingsLibDisplayDensityUtils",
"SettingsLibUtils",
"SettingsLibEmergencyNumber",
diff --git a/packages/SettingsLib/RadioButtonPreference/Android.bp b/packages/SettingsLib/RadioButtonPreference/Android.bp
index 28ff71f228402..1387daa959be9 100644
--- a/packages/SettingsLib/RadioButtonPreference/Android.bp
+++ b/packages/SettingsLib/RadioButtonPreference/Android.bp
@@ -15,6 +15,7 @@ android_library {
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 f50127f6e21ff..02d3c06dcea25 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.CheckBoxPreference;
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 @@ import androidx.preference.PreferenceViewHolder;
*
* 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 0000000000000..bcc64d3cd2346
--- /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 0000000000000..51fc7ed646602
--- /dev/null
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/AndroidManifest.xml
@@ -0,0 +1,23 @@
+
+
+
+
This is a good place to grab references to custom Views in the layout and set + * properties on them. + * + *
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 0000000000000..34efe82f25271 --- /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(); + } +}