Animate the color transition (active<->inactive) in the mode header icon
Also, don't apply the layout params, etc on each call to updateState - once per displayPreference is enough.
Fixes: 356399449
Bug: 357861830
Test: manual
Flag: android.app.modes_ui
Change-Id: I6967ea1745377d0f514ca0f68101043f017a8fd7
diff --git a/src/com/android/settings/notification/modes/AbstractZenModeHeaderController.java b/src/com/android/settings/notification/modes/AbstractZenModeHeaderController.java
index 06a30fa..81b53cc 100644
--- a/src/com/android/settings/notification/modes/AbstractZenModeHeaderController.java
+++ b/src/com/android/settings/notification/modes/AbstractZenModeHeaderController.java
@@ -15,6 +15,8 @@
*/
package com.android.settings.notification.modes;
+import static com.google.common.base.Preconditions.checkNotNull;
+
import android.app.Flags;
import android.content.Context;
import android.graphics.drawable.Drawable;
@@ -22,8 +24,8 @@
import android.widget.ImageView;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
@@ -32,13 +34,15 @@
import com.android.settingslib.notification.modes.ZenMode;
import com.android.settingslib.widget.LayoutPreference;
-import java.util.function.Consumer;
+import com.google.common.base.Objects;
+
import java.util.function.Function;
abstract class AbstractZenModeHeaderController extends AbstractZenModePreferenceController {
private final DashboardFragment mFragment;
private EntityHeaderController mHeaderController;
+ private String mCurrentIconKey;
AbstractZenModeHeaderController(
@NonNull Context context,
@@ -53,40 +57,44 @@
return Flags.modesApi() && Flags.modesUi();
}
- protected void updateIcon(Preference preference, @NonNull ZenMode zenMode, int iconSizePx,
- Function<Drawable, Drawable> modeIconStylist,
- @Nullable Consumer<ImageView> iconViewCustomizer) {
- if (mFragment == null) {
- return;
- }
+ protected void setUpHeader(PreferenceScreen screen, int iconSizePx) {
+ LayoutPreference preference = checkNotNull(screen.findPreference(getPreferenceKey()));
preference.setSelectable(false);
if (mHeaderController == null) {
- final LayoutPreference pref = (LayoutPreference) preference;
mHeaderController = EntityHeaderController.newInstance(
mFragment.getActivity(),
mFragment,
- pref.findViewById(R.id.entity_header));
+ preference.findViewById(R.id.entity_header));
}
- ImageView iconView = ((LayoutPreference) preference).findViewById(R.id.entity_header_icon);
- if (iconView != null) {
- if (iconViewCustomizer != null) {
- iconViewCustomizer.accept(iconView);
- }
- ViewGroup.LayoutParams layoutParams = iconView.getLayoutParams();
- if (layoutParams.width != iconSizePx || layoutParams.height != iconSizePx) {
- layoutParams.width = iconSizePx;
- layoutParams.height = iconSizePx;
- iconView.setLayoutParams(layoutParams);
- }
+ ImageView iconView = checkNotNull(preference.findViewById(R.id.entity_header_icon));
+ ViewGroup.LayoutParams layoutParams = iconView.getLayoutParams();
+ if (layoutParams.width != iconSizePx || layoutParams.height != iconSizePx) {
+ layoutParams.width = iconSizePx;
+ layoutParams.height = iconSizePx;
+ iconView.setLayoutParams(layoutParams);
}
+ }
- FutureUtil.whenDone(
- zenMode.getIcon(mContext, ZenIconLoader.getInstance()),
- icon -> mHeaderController
- .setIcon(modeIconStylist.apply(icon))
- .done(/* rebindActions= */ false),
- mContext.getMainExecutor());
+ protected void updateIcon(Preference preference, @NonNull ZenMode zenMode,
+ Function<Drawable, Drawable> iconStylist, boolean isSelected) {
+
+ ImageView iconView = checkNotNull(
+ ((LayoutPreference) preference).findViewById(R.id.entity_header_icon));
+ iconView.setSelected(isSelected);
+
+ if (!Objects.equal(mCurrentIconKey, zenMode.getIconKey())) {
+ mCurrentIconKey = zenMode.getIconKey();
+ FutureUtil.whenDone(
+ zenMode.getIcon(mContext, ZenIconLoader.getInstance()),
+ icon -> {
+ checkNotNull(mHeaderController)
+ .setIcon(iconStylist.apply(icon))
+ .done(/* rebindActions= */ false);
+ iconView.jumpDrawablesToCurrentState(); // Skip animation on first load.
+ },
+ mContext.getMainExecutor());
+ }
}
}
diff --git a/src/com/android/settings/notification/modes/IconUtil.java b/src/com/android/settings/notification/modes/IconUtil.java
index 43161ce..dc4d875 100644
--- a/src/com/android/settings/notification/modes/IconUtil.java
+++ b/src/com/android/settings/notification/modes/IconUtil.java
@@ -30,7 +30,9 @@
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.StateListDrawable;
import android.graphics.drawable.shapes.OvalShape;
+import android.util.StateSet;
import android.view.Gravity;
import androidx.annotation.AttrRes;
@@ -65,20 +67,42 @@
/**
* Returns a variant of the supplied mode icon to be used as the header in the mode page. The
- * inner icon is 64x64 dp and it's contained in a 12-sided-cookie of 136dp diameter. It's
- * tinted with the "material secondary" color combination and the "selected" color variant
- * should be used for modes currently active.
+ * mode icon is contained in a 12-sided-cookie. The color combination is "material secondary"
+ * when unselected and "material primary" when selected; the switch between these two color sets
+ * is animated with a cross-fade. The selected colors should be used when the mode is currently
+ * active.
*/
static Drawable makeModeHeader(@NonNull Context context, Drawable modeIcon) {
- return composeIcons(
- checkNotNull(context.getDrawable(R.drawable.ic_zen_mode_icon_cookie)),
- context.getColorStateList(R.color.modes_icon_selectable_background),
- context.getResources().getDimensionPixelSize(
- R.dimen.zen_mode_header_size),
+ Resources res = context.getResources();
+ Drawable background = checkNotNull(context.getDrawable(R.drawable.ic_zen_mode_icon_cookie));
+ @Px int outerSizePx = res.getDimensionPixelSize(R.dimen.zen_mode_header_size);
+ @Px int innerSizePx = res.getDimensionPixelSize(R.dimen.zen_mode_header_inner_icon_size);
+
+ Drawable base = composeIcons(
+ background,
+ Utils.getColorAttr(context,
+ com.android.internal.R.attr.materialColorSecondaryContainer),
+ outerSizePx,
modeIcon,
- context.getColorStateList(R.color.modes_icon_selectable_icon),
- context.getResources().getDimensionPixelSize(
- R.dimen.zen_mode_header_inner_icon_size));
+ Utils.getColorAttr(context,
+ com.android.internal.R.attr.materialColorOnSecondaryContainer),
+ innerSizePx);
+
+ Drawable selected = composeIcons(
+ background,
+ Utils.getColorAttr(context, com.android.internal.R.attr.materialColorPrimary),
+ outerSizePx,
+ modeIcon,
+ Utils.getColorAttr(context, com.android.internal.R.attr.materialColorOnPrimary),
+ innerSizePx);
+
+ StateListDrawable result = new StateListDrawable();
+ result.setEnterFadeDuration(res.getInteger(android.R.integer.config_mediumAnimTime));
+ result.setExitFadeDuration(res.getInteger(android.R.integer.config_mediumAnimTime));
+ result.addState(new int[] { android.R.attr.state_selected }, selected);
+ result.addState(StateSet.WILD_CARD, base);
+ result.setBounds(0, 0, outerSizePx, outerSizePx);
+ return result;
}
/**
diff --git a/src/com/android/settings/notification/modes/ZenModeHeaderController.java b/src/com/android/settings/notification/modes/ZenModeHeaderController.java
index c4f3dd1..ae6eacc 100644
--- a/src/com/android/settings/notification/modes/ZenModeHeaderController.java
+++ b/src/com/android/settings/notification/modes/ZenModeHeaderController.java
@@ -19,6 +19,7 @@
import androidx.annotation.NonNull;
import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
@@ -34,10 +35,16 @@
}
@Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ setUpHeader(screen,
+ mContext.getResources().getDimensionPixelSize(R.dimen.zen_mode_header_size));
+ }
+
+ @Override
public void updateState(Preference preference, @NonNull ZenMode zenMode) {
updateIcon(preference, zenMode,
- mContext.getResources().getDimensionPixelSize(R.dimen.zen_mode_header_size),
icon -> IconUtil.makeModeHeader(mContext, icon),
- iconView -> iconView.setSelected(zenMode.isActive()));
+ /* isSelected= */ zenMode.isActive());
}
}
diff --git a/src/com/android/settings/notification/modes/ZenModeIconPickerIconPreferenceController.java b/src/com/android/settings/notification/modes/ZenModeIconPickerIconPreferenceController.java
index a7adf6c..6c8d41f 100644
--- a/src/com/android/settings/notification/modes/ZenModeIconPickerIconPreferenceController.java
+++ b/src/com/android/settings/notification/modes/ZenModeIconPickerIconPreferenceController.java
@@ -20,6 +20,7 @@
import androidx.annotation.NonNull;
import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
@@ -34,11 +35,16 @@
}
@Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ setUpHeader(screen, mContext.getResources().getDimensionPixelSize(
+ R.dimen.zen_mode_icon_list_header_circle_diameter));
+ }
+
+ @Override
void updateState(Preference preference, @NonNull ZenMode zenMode) {
updateIcon(preference, zenMode,
- mContext.getResources().getDimensionPixelSize(
- R.dimen.zen_mode_icon_list_header_circle_diameter),
icon -> IconUtil.makeIconPickerHeader(mContext, icon),
- null);
+ /* isSelected= */ false);
}
}