Show a message when disabled switch preferences are clicked
Now preference is not disabled but view within the preferences are disabled. So the preference can still get the clicks and a message will be displayed.
Bug: 168308383
Fix: 141482424
Test: Manual, paintbooth
Change-Id: I0c46dd779a813d2e182cb4c1b416bd8d68ece081
Merged-In: I0c46dd779a813d2e182cb4c1b416bd8d68ece081
diff --git a/car-ui-lib/src/com/android/car/ui/preference/CarUiPreference.java b/car-ui-lib/src/com/android/car/ui/preference/CarUiPreference.java
index 2fbbacb..7956219 100644
--- a/car-ui-lib/src/com/android/car/ui/preference/CarUiPreference.java
+++ b/car-ui-lib/src/com/android/car/ui/preference/CarUiPreference.java
@@ -21,27 +21,25 @@
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.Toast;
-import androidx.core.view.ViewCompat;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
import com.android.car.ui.R;
+import com.android.car.ui.utils.CarUiUtils;
/**
* This class extends the base {@link Preference} class. Adds the support to add a drawable icon to
* the preference if there is one of fragment, intent or onPreferenceClickListener set.
*/
-public class CarUiPreference extends Preference {
+public class CarUiPreference extends Preference implements IDisabledPreferenceCallback {
private Context mContext;
private boolean mShowChevron;
private String mMessageToShowWhenDisabledPreferenceClicked;
private boolean mShouldShowRippleOnDisabledPreference;
- private boolean mEnabledAppearance = true;
private Drawable mBackground;
private View mPreference;
@@ -82,37 +80,9 @@
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
boolean viewEnabled = isEnabled();
- if (viewEnabled) {
- if (mBackground != null) {
- ViewCompat.setBackground(holder.itemView, mBackground);
- }
- enableView(holder.itemView, true, false);
- } else {
- holder.itemView.setEnabled(true);
- mPreference = holder.itemView;
- if (mBackground == null) {
- // store the original background.
- mBackground = mPreference.getBackground();
- }
- if (!mShouldShowRippleOnDisabledPreference) {
- ViewCompat.setBackground(mPreference, null);
- } else if (mBackground != null) {
- ViewCompat.setBackground(mPreference, mBackground);
- }
- enableView(holder.itemView, false, true);
- }
- }
-
- private void enableView(View view, boolean enabled, boolean isRootView) {
- if (!isRootView) {
- view.setEnabled(enabled);
- }
- if (view instanceof ViewGroup) {
- ViewGroup grp = (ViewGroup) view;
- for (int index = 0; index < grp.getChildCount(); index++) {
- enableView(grp.getChildAt(index), enabled, false);
- }
- }
+ mPreference = holder.itemView;
+ mBackground = CarUiUtils.setPreferenceViewEnabled(viewEnabled, holder.itemView, mBackground,
+ mShouldShowRippleOnDisabledPreference);
}
@Override
@@ -142,9 +112,8 @@
super.performClick();
} else if (mMessageToShowWhenDisabledPreferenceClicked != null
&& !mMessageToShowWhenDisabledPreferenceClicked.isEmpty()) {
- Toast toast = Toast.makeText(mContext, mMessageToShowWhenDisabledPreferenceClicked,
- Toast.LENGTH_LONG);
- toast.show();
+ Toast.makeText(mContext, mMessageToShowWhenDisabledPreferenceClicked,
+ Toast.LENGTH_LONG).show();
}
}
@@ -155,22 +124,14 @@
/**
* Sets the ripple on the disabled preference.
*/
+ @Override
public void setShouldShowRippleOnDisabledPreference(boolean showRipple) {
mShouldShowRippleOnDisabledPreference = showRipple;
- updateRippleStateOnDisabledPreference();
+ CarUiUtils.updateRippleStateOnDisabledPreference(isEnabled(),
+ mShouldShowRippleOnDisabledPreference, mBackground, mPreference);
}
- private void updateRippleStateOnDisabledPreference() {
- if (isEnabled()) {
- return;
- }
- if (mShouldShowRippleOnDisabledPreference && mPreference != null) {
- ViewCompat.setBackground(mPreference, mBackground);
- } else if (mPreference != null) {
- ViewCompat.setBackground(mPreference, null);
- }
- }
-
+ @Override
public void setMessageToShowWhenDisabledPreferenceClicked(String message) {
mMessageToShowWhenDisabledPreferenceClicked = message;
}
diff --git a/car-ui-lib/src/com/android/car/ui/preference/CarUiSwitchPreference.java b/car-ui-lib/src/com/android/car/ui/preference/CarUiSwitchPreference.java
new file mode 100644
index 0000000..25d1c5c
--- /dev/null
+++ b/car-ui-lib/src/com/android/car/ui/preference/CarUiSwitchPreference.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2020 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.car.ui.preference;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.Toast;
+
+import androidx.preference.PreferenceViewHolder;
+import androidx.preference.SwitchPreference;
+
+import com.android.car.ui.R;
+import com.android.car.ui.utils.CarUiUtils;
+
+/**
+ * This class extends the base {@link SwitchPreference} class. Adds the functionality to show
+ * message when preference is disabled.
+ */
+public class CarUiSwitchPreference extends SwitchPreference implements IDisabledPreferenceCallback {
+
+ private String mMessageToShowWhenDisabledPreferenceClicked;
+
+ private boolean mShouldShowRippleOnDisabledPreference;
+ private Drawable mBackground;
+ private View mPreference;
+ private Context mContext;
+
+ public CarUiSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init(context, attrs);
+ }
+
+ public CarUiSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ init(context, attrs);
+ }
+
+ public CarUiSwitchPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(context, attrs);
+ }
+
+ public CarUiSwitchPreference(Context context) {
+ super(context);
+ init(context, null);
+ }
+
+ private void init(Context context, AttributeSet attrs) {
+ mContext = context;
+ TypedArray preferenceAttributes = getContext().obtainStyledAttributes(attrs,
+ R.styleable.CarUiPreference);
+ mShouldShowRippleOnDisabledPreference = preferenceAttributes.getBoolean(
+ R.styleable.CarUiPreference_showRippleOnDisabledPreference, false);
+ }
+
+ @Override
+ public void onBindViewHolder(PreferenceViewHolder holder) {
+ super.onBindViewHolder(holder);
+ mPreference = holder.itemView;
+ mBackground = CarUiUtils.setPreferenceViewEnabled(isEnabled(), holder.itemView, mBackground,
+ mShouldShowRippleOnDisabledPreference);
+ }
+
+ /**
+ * This is similar to {@link Preference#performClick()} with the only difference that we do not
+ * return when view is not enabled.
+ */
+ @Override
+ public void performClick() {
+ if (isEnabled()) {
+ super.performClick();
+ } else if (mMessageToShowWhenDisabledPreferenceClicked != null
+ && !mMessageToShowWhenDisabledPreferenceClicked.isEmpty()) {
+ Toast.makeText(mContext, mMessageToShowWhenDisabledPreferenceClicked,
+ Toast.LENGTH_LONG).show();
+ }
+ }
+
+ /**
+ * Sets the ripple on the disabled preference.
+ */
+ @Override
+ public void setShouldShowRippleOnDisabledPreference(boolean showRipple) {
+ mShouldShowRippleOnDisabledPreference = showRipple;
+ CarUiUtils.updateRippleStateOnDisabledPreference(isEnabled(),
+ mShouldShowRippleOnDisabledPreference, mBackground, mPreference);
+ }
+
+ @Override
+ public void setMessageToShowWhenDisabledPreferenceClicked(String message) {
+ mMessageToShowWhenDisabledPreferenceClicked = message;
+ }
+}
diff --git a/car-ui-lib/src/com/android/car/ui/preference/IDisabledPreferenceCallback.java b/car-ui-lib/src/com/android/car/ui/preference/IDisabledPreferenceCallback.java
new file mode 100644
index 0000000..39b5bc2
--- /dev/null
+++ b/car-ui-lib/src/com/android/car/ui/preference/IDisabledPreferenceCallback.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2020 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.car.ui.preference;
+
+/**
+ * Interface for preferences to handle clicks when its disabled.
+ */
+public interface IDisabledPreferenceCallback {
+
+ /**
+ * Sets if the ripple effect should be shown on disabled preference.
+ */
+ default void setShouldShowRippleOnDisabledPreference(boolean showRipple) {}
+
+ /**
+ * Sets the message to be displayed when the disabled preference is clicked.
+ */
+ default void setMessageToShowWhenDisabledPreferenceClicked(String message) {}
+}
diff --git a/car-ui-lib/src/com/android/car/ui/preference/PreferenceFragment.java b/car-ui-lib/src/com/android/car/ui/preference/PreferenceFragment.java
index 6bc95f2..260cf6f 100644
--- a/car-ui-lib/src/com/android/car/ui/preference/PreferenceFragment.java
+++ b/car-ui-lib/src/com/android/car/ui/preference/PreferenceFragment.java
@@ -36,6 +36,7 @@
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
import androidx.recyclerview.widget.RecyclerView;
import com.android.car.ui.R;
@@ -241,6 +242,7 @@
new Pair<>(ListPreference.class, CarUiListPreference.class),
new Pair<>(MultiSelectListPreference.class, CarUiMultiSelectListPreference.class),
new Pair<>(EditTextPreference.class, CarUiEditTextPreference.class),
+ new Pair<>(SwitchPreference.class, CarUiSwitchPreference.class),
new Pair<>(Preference.class, CarUiPreference.class)
);
diff --git a/car-ui-lib/src/com/android/car/ui/utils/CarUiUtils.java b/car-ui-lib/src/com/android/car/ui/utils/CarUiUtils.java
index 54d64f1..497d028 100644
--- a/car-ui-lib/src/com/android/car/ui/utils/CarUiUtils.java
+++ b/car-ui-lib/src/com/android/car/ui/utils/CarUiUtils.java
@@ -20,8 +20,10 @@
import android.content.ContextWrapper;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
import android.util.TypedValue;
import android.view.View;
+import android.view.ViewGroup;
import androidx.annotation.DimenRes;
import androidx.annotation.IdRes;
@@ -29,13 +31,15 @@
import androidx.annotation.Nullable;
import androidx.annotation.StyleRes;
import androidx.annotation.UiThread;
+import androidx.core.view.ViewCompat;
/**
* Collection of utility methods
*/
public final class CarUiUtils {
/** This is a utility class */
- private CarUiUtils() {}
+ private CarUiUtils() {
+ }
/**
* Reads a float value from a dimens resource. This is necessary as {@link Resources#getFloat}
@@ -118,4 +122,68 @@
}
return view;
}
+
+ /**
+ * Updates the preference view enabled state. If the view is disabled we just disable the child
+ * of preference like TextView, ImageView. The preference itself is always enabled to get the
+ * click events. Ripple effect in background is also removed by default. If the ripple is
+ * needed see
+ * {@link IDisabledPreferenceCallback#setShouldShowRippleOnDisabledPreference(boolean)}
+ */
+ public static Drawable setPreferenceViewEnabled(boolean viewEnabled, View itemView,
+ Drawable background, boolean shouldShowRippleOnDisabledPreference) {
+ if (viewEnabled) {
+ if (background != null) {
+ ViewCompat.setBackground(itemView, background);
+ }
+ setChildViewsEnabled(itemView, true, false);
+ } else {
+ itemView.setEnabled(true);
+ if (background == null) {
+ // store the original background.
+ background = itemView.getBackground();
+ }
+ updateRippleStateOnDisabledPreference(false, shouldShowRippleOnDisabledPreference,
+ background, itemView);
+ setChildViewsEnabled(itemView, false, true);
+ }
+ return background;
+ }
+
+ /**
+ * Sets the enabled state on the views of the preference. If the view is being disabled we want
+ * only child views of preference to be disabled.
+ */
+ private static void setChildViewsEnabled(View view, boolean enabled, boolean isRootView) {
+ if (!isRootView) {
+ view.setEnabled(enabled);
+ }
+ if (view instanceof ViewGroup) {
+ ViewGroup grp = (ViewGroup) view;
+ for (int index = 0; index < grp.getChildCount(); index++) {
+ setChildViewsEnabled(grp.getChildAt(index), enabled, false);
+ }
+ }
+ }
+
+ /**
+ * Updates the ripple state on the given preference.
+ *
+ * @param isEnabled whether the preference is enabled or not
+ * @param shouldShowRippleOnDisabledPreference should ripple be displayed when the preference is
+ * clicked
+ * @param background drawable that represents the ripple
+ * @param preference preference on which drawable will be applied
+ */
+ public static void updateRippleStateOnDisabledPreference(boolean isEnabled,
+ boolean shouldShowRippleOnDisabledPreference, Drawable background, View preference) {
+ if (isEnabled || preference == null) {
+ return;
+ }
+ if (shouldShowRippleOnDisabledPreference && background != null) {
+ ViewCompat.setBackground(preference, background);
+ } else {
+ ViewCompat.setBackground(preference, null);
+ }
+ }
}
diff --git a/car-ui-lib/tests/paintbooth/res/xml/preference_samples.xml b/car-ui-lib/tests/paintbooth/res/xml/preference_samples.xml
index 0a0836a..e483435 100644
--- a/car-ui-lib/tests/paintbooth/res/xml/preference_samples.xml
+++ b/car-ui-lib/tests/paintbooth/res/xml/preference_samples.xml
@@ -87,11 +87,6 @@
android:summary="@string/summary_switch_preference"
android:title="@string/title_switch_preference"/>
- <com.android.car.ui.preference.CarUiTwoActionPreference
- android:key="twoaction"
- android:summary="@string/summary_twoaction_preference"
- android:title="@string/title_twoaction_preference"
- android:widgetLayout="@layout/details_preference_widget"/>
</PreferenceCategory>
<PreferenceCategory
@@ -119,11 +114,6 @@
android:summary="@string/summary_multi_list_preference"
android:title="@string/title_multi_list_preference"/>
- <com.android.car.ui.preference.CarUiSeekBarDialogPreference
- android:dialogTitle="Seekbar Dialog"
- android:key="seekbarDialog"
- android:summary="@string/summary_seekbar_preference"
- android:title="@string/title_seekbar_preference"/>
</PreferenceCategory>
<PreferenceCategory
diff --git a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/preferences/PreferenceDemoFragment.java b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/preferences/PreferenceDemoFragment.java
index e9f990d..233c873 100644
--- a/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/preferences/PreferenceDemoFragment.java
+++ b/car-ui-lib/tests/paintbooth/src/com/android/car/ui/paintbooth/preferences/PreferenceDemoFragment.java
@@ -20,6 +20,7 @@
import com.android.car.ui.paintbooth.R;
import com.android.car.ui.preference.CarUiPreference;
+import com.android.car.ui.preference.CarUiSwitchPreference;
import com.android.car.ui.preference.PreferenceFragment;
/**
@@ -44,5 +45,10 @@
preferenceDisabledWithRipple.setMessageToShowWhenDisabledPreferenceClicked(
"I am disabled because...");
preferenceDisabledWithRipple.setShouldShowRippleOnDisabledPreference(true);
+
+ CarUiSwitchPreference carUiSwitchPreference = findPreference("switch");
+ carUiSwitchPreference.setEnabled(false);
+ carUiSwitchPreference.setMessageToShowWhenDisabledPreferenceClicked(
+ "I am disabled because...");
}
}