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
This commit is contained in:
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.settings.notification.modes;
|
package com.android.settings.notification.modes;
|
||||||
|
|
||||||
|
import static com.google.common.base.Preconditions.checkNotNull;
|
||||||
|
|
||||||
import android.app.Flags;
|
import android.app.Flags;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
@@ -22,8 +24,8 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
@@ -32,13 +34,15 @@ import com.android.settingslib.notification.modes.ZenIconLoader;
|
|||||||
import com.android.settingslib.notification.modes.ZenMode;
|
import com.android.settingslib.notification.modes.ZenMode;
|
||||||
import com.android.settingslib.widget.LayoutPreference;
|
import com.android.settingslib.widget.LayoutPreference;
|
||||||
|
|
||||||
import java.util.function.Consumer;
|
import com.google.common.base.Objects;
|
||||||
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
abstract class AbstractZenModeHeaderController extends AbstractZenModePreferenceController {
|
abstract class AbstractZenModeHeaderController extends AbstractZenModePreferenceController {
|
||||||
|
|
||||||
private final DashboardFragment mFragment;
|
private final DashboardFragment mFragment;
|
||||||
private EntityHeaderController mHeaderController;
|
private EntityHeaderController mHeaderController;
|
||||||
|
private String mCurrentIconKey;
|
||||||
|
|
||||||
AbstractZenModeHeaderController(
|
AbstractZenModeHeaderController(
|
||||||
@NonNull Context context,
|
@NonNull Context context,
|
||||||
@@ -53,40 +57,44 @@ abstract class AbstractZenModeHeaderController extends AbstractZenModePreference
|
|||||||
return Flags.modesApi() && Flags.modesUi();
|
return Flags.modesApi() && Flags.modesUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateIcon(Preference preference, @NonNull ZenMode zenMode, int iconSizePx,
|
protected void setUpHeader(PreferenceScreen screen, int iconSizePx) {
|
||||||
Function<Drawable, Drawable> modeIconStylist,
|
LayoutPreference preference = checkNotNull(screen.findPreference(getPreferenceKey()));
|
||||||
@Nullable Consumer<ImageView> iconViewCustomizer) {
|
|
||||||
if (mFragment == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
preference.setSelectable(false);
|
preference.setSelectable(false);
|
||||||
|
|
||||||
if (mHeaderController == null) {
|
if (mHeaderController == null) {
|
||||||
final LayoutPreference pref = (LayoutPreference) preference;
|
|
||||||
mHeaderController = EntityHeaderController.newInstance(
|
mHeaderController = EntityHeaderController.newInstance(
|
||||||
mFragment.getActivity(),
|
mFragment.getActivity(),
|
||||||
mFragment,
|
mFragment,
|
||||||
pref.findViewById(R.id.entity_header));
|
preference.findViewById(R.id.entity_header));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageView iconView = ((LayoutPreference) preference).findViewById(R.id.entity_header_icon);
|
ImageView iconView = checkNotNull(preference.findViewById(R.id.entity_header_icon));
|
||||||
if (iconView != null) {
|
ViewGroup.LayoutParams layoutParams = iconView.getLayoutParams();
|
||||||
if (iconViewCustomizer != null) {
|
if (layoutParams.width != iconSizePx || layoutParams.height != iconSizePx) {
|
||||||
iconViewCustomizer.accept(iconView);
|
layoutParams.width = iconSizePx;
|
||||||
}
|
layoutParams.height = iconSizePx;
|
||||||
ViewGroup.LayoutParams layoutParams = iconView.getLayoutParams();
|
iconView.setLayoutParams(layoutParams);
|
||||||
if (layoutParams.width != iconSizePx || layoutParams.height != iconSizePx) {
|
|
||||||
layoutParams.width = iconSizePx;
|
|
||||||
layoutParams.height = iconSizePx;
|
|
||||||
iconView.setLayoutParams(layoutParams);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FutureUtil.whenDone(
|
protected void updateIcon(Preference preference, @NonNull ZenMode zenMode,
|
||||||
zenMode.getIcon(mContext, ZenIconLoader.getInstance()),
|
Function<Drawable, Drawable> iconStylist, boolean isSelected) {
|
||||||
icon -> mHeaderController
|
|
||||||
.setIcon(modeIconStylist.apply(icon))
|
ImageView iconView = checkNotNull(
|
||||||
.done(/* rebindActions= */ false),
|
((LayoutPreference) preference).findViewById(R.id.entity_header_icon));
|
||||||
mContext.getMainExecutor());
|
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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,9 @@ import android.graphics.drawable.BitmapDrawable;
|
|||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.graphics.drawable.LayerDrawable;
|
import android.graphics.drawable.LayerDrawable;
|
||||||
import android.graphics.drawable.ShapeDrawable;
|
import android.graphics.drawable.ShapeDrawable;
|
||||||
|
import android.graphics.drawable.StateListDrawable;
|
||||||
import android.graphics.drawable.shapes.OvalShape;
|
import android.graphics.drawable.shapes.OvalShape;
|
||||||
|
import android.util.StateSet;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
|
|
||||||
import androidx.annotation.AttrRes;
|
import androidx.annotation.AttrRes;
|
||||||
@@ -65,20 +67,42 @@ class IconUtil {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a variant of the supplied mode icon to be used as the header in the mode page. The
|
* 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
|
* mode icon is contained in a 12-sided-cookie. The color combination is "material secondary"
|
||||||
* tinted with the "material secondary" color combination and the "selected" color variant
|
* when unselected and "material primary" when selected; the switch between these two color sets
|
||||||
* should be used for modes currently active.
|
* 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) {
|
static Drawable makeModeHeader(@NonNull Context context, Drawable modeIcon) {
|
||||||
return composeIcons(
|
Resources res = context.getResources();
|
||||||
checkNotNull(context.getDrawable(R.drawable.ic_zen_mode_icon_cookie)),
|
Drawable background = checkNotNull(context.getDrawable(R.drawable.ic_zen_mode_icon_cookie));
|
||||||
context.getColorStateList(R.color.modes_icon_selectable_background),
|
@Px int outerSizePx = res.getDimensionPixelSize(R.dimen.zen_mode_header_size);
|
||||||
context.getResources().getDimensionPixelSize(
|
@Px int innerSizePx = res.getDimensionPixelSize(R.dimen.zen_mode_header_inner_icon_size);
|
||||||
R.dimen.zen_mode_header_size),
|
|
||||||
|
Drawable base = composeIcons(
|
||||||
|
background,
|
||||||
|
Utils.getColorAttr(context,
|
||||||
|
com.android.internal.R.attr.materialColorSecondaryContainer),
|
||||||
|
outerSizePx,
|
||||||
modeIcon,
|
modeIcon,
|
||||||
context.getColorStateList(R.color.modes_icon_selectable_icon),
|
Utils.getColorAttr(context,
|
||||||
context.getResources().getDimensionPixelSize(
|
com.android.internal.R.attr.materialColorOnSecondaryContainer),
|
||||||
R.dimen.zen_mode_header_inner_icon_size));
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -19,6 +19,7 @@ import android.content.Context;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
@@ -33,11 +34,17 @@ class ZenModeHeaderController extends AbstractZenModeHeaderController {
|
|||||||
super(context, key, fragment);
|
super(context, key, fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
|
super.displayPreference(screen);
|
||||||
|
setUpHeader(screen,
|
||||||
|
mContext.getResources().getDimensionPixelSize(R.dimen.zen_mode_header_size));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateState(Preference preference, @NonNull ZenMode zenMode) {
|
public void updateState(Preference preference, @NonNull ZenMode zenMode) {
|
||||||
updateIcon(preference, zenMode,
|
updateIcon(preference, zenMode,
|
||||||
mContext.getResources().getDimensionPixelSize(R.dimen.zen_mode_header_size),
|
|
||||||
icon -> IconUtil.makeModeHeader(mContext, icon),
|
icon -> IconUtil.makeModeHeader(mContext, icon),
|
||||||
iconView -> iconView.setSelected(zenMode.isActive()));
|
/* isSelected= */ zenMode.isActive());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@ import android.content.Context;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.dashboard.DashboardFragment;
|
import com.android.settings.dashboard.DashboardFragment;
|
||||||
@@ -33,12 +34,17 @@ class ZenModeIconPickerIconPreferenceController extends AbstractZenModeHeaderCon
|
|||||||
super(context, key, fragment);
|
super(context, key, fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void displayPreference(PreferenceScreen screen) {
|
||||||
|
super.displayPreference(screen);
|
||||||
|
setUpHeader(screen, mContext.getResources().getDimensionPixelSize(
|
||||||
|
R.dimen.zen_mode_icon_list_header_circle_diameter));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
void updateState(Preference preference, @NonNull ZenMode zenMode) {
|
void updateState(Preference preference, @NonNull ZenMode zenMode) {
|
||||||
updateIcon(preference, zenMode,
|
updateIcon(preference, zenMode,
|
||||||
mContext.getResources().getDimensionPixelSize(
|
|
||||||
R.dimen.zen_mode_icon_list_header_circle_diameter),
|
|
||||||
icon -> IconUtil.makeIconPickerHeader(mContext, icon),
|
icon -> IconUtil.makeIconPickerHeader(mContext, icon),
|
||||||
null);
|
/* isSelected= */ false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user