diff options
| author | 2022-04-22 16:41:40 +0000 | |
|---|---|---|
| committer | 2022-04-25 20:59:38 +0000 | |
| commit | 46956980554c91bea3cb6fa3148bb80febc2ff55 (patch) | |
| tree | b6a422e107144d157e590f80354586661c8326fd | |
| parent | 6e947afdab937d2bf6d8e87bc2e52d9b9d095ba2 (diff) | |
[Media] Update background gradient scrim to use album theme colors.
Fixes: 220355621
Test: manual (see screenshots in bug)
Change-Id: I5753a78d95e80ba65f77233f058c803aff0d4f70
7 files changed, 153 insertions, 55 deletions
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java index f925eaa0e40b..eb6705a2e979 100644 --- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java +++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java @@ -15,6 +15,8 @@ */ package com.android.keyguard; +import static com.android.systemui.util.ColorUtilKt.getPrivateAttrColorIfUnset; + import android.animation.AnimatorSet; import android.animation.ArgbEvaluator; import android.animation.ValueAnimator; @@ -152,7 +154,7 @@ class NumPadAnimator { ContextThemeWrapper ctw = new ContextThemeWrapper(context, mStyle); TypedArray a = ctw.obtainStyledAttributes(customAttrs); - mNormalColor = Utils.getPrivateAttrColorIfUnset(ctw, a, 0, 0, + mNormalColor = getPrivateAttrColorIfUnset(ctw, a, 0, 0, com.android.internal.R.attr.colorSurface); mHighlightColor = a.getColor(1, 0); a.recycle(); diff --git a/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt b/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt index 5a214d1cd5e0..70052fd45abf 100644 --- a/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt +++ b/packages/SystemUI/src/com/android/systemui/media/ColorSchemeTransition.kt @@ -21,24 +21,41 @@ import android.animation.ValueAnimator.AnimatorUpdateListener import android.animation.ValueAnimator import android.content.Context import android.content.res.ColorStateList +import android.graphics.drawable.GradientDrawable import com.android.internal.R import com.android.internal.annotations.VisibleForTesting import com.android.settingslib.Utils import com.android.systemui.monet.ColorScheme +import com.android.systemui.util.getColorWithAlpha /** - * ColorTransition is responsible for managing the animation between two specific colors. + * A [ColorTransition] is an object that updates the colors of views each time [updateColorScheme] + * is triggered. + */ +interface ColorTransition { + fun updateColorScheme(scheme: ColorScheme?) +} + +/** A generic implementation of [ColorTransition] so that we can define a factory method. */ +open class GenericColorTransition( + private val applyTheme: (ColorScheme?) -> Unit +) : ColorTransition { + override fun updateColorScheme(scheme: ColorScheme?) = applyTheme(scheme) +} + +/** + * A [ColorTransition] that animates between two specific colors. * It uses a ValueAnimator to execute the animation and interpolate between the source color and * the target color. * * Selection of the target color from the scheme, and application of the interpolated color * are delegated to callbacks. */ -open class ColorTransition( +open class AnimatingColorTransition( private val defaultColor: Int, private val extractColor: (ColorScheme) -> Int, private val applyColor: (Int) -> Unit -) : AnimatorUpdateListener { +) : AnimatorUpdateListener, ColorTransition { private val argbEvaluator = ArgbEvaluator() private val valueAnimator = buildAnimator() @@ -53,7 +70,7 @@ open class ColorTransition( applyColor(currentColor) } - fun updateColorScheme(scheme: ColorScheme?) { + override fun updateColorScheme(scheme: ColorScheme?) { val newTargetColor = if (scheme == null) defaultColor else extractColor(scheme) if (newTargetColor != targetColor) { sourceColor = currentColor @@ -76,7 +93,9 @@ open class ColorTransition( } } -typealias ColorTransitionFactory = (Int, (ColorScheme) -> Int, (Int) -> Unit) -> ColorTransition +typealias AnimatingColorTransitionFactory = + (Int, (ColorScheme) -> Int, (Int) -> Unit) -> AnimatingColorTransition +typealias GenericColorTransitionFactory = ((ColorScheme?) -> Unit) -> GenericColorTransition /** * ColorSchemeTransition constructs a ColorTransition for each color in the scheme @@ -86,27 +105,26 @@ typealias ColorTransitionFactory = (Int, (ColorScheme) -> Int, (Int) -> Unit) -> class ColorSchemeTransition internal constructor( private val context: Context, mediaViewHolder: MediaViewHolder, - colorTransitionFactory: ColorTransitionFactory + animatingColorTransitionFactory: AnimatingColorTransitionFactory, + genericColorTransitionFactory: GenericColorTransitionFactory ) { constructor(context: Context, mediaViewHolder: MediaViewHolder) : - this(context, mediaViewHolder, ::ColorTransition) + this(context, mediaViewHolder, ::AnimatingColorTransition, ::GenericColorTransition) val bgColor = context.getColor(com.android.systemui.R.color.material_dynamic_secondary95) - val surfaceColor = colorTransitionFactory( + val surfaceColor = animatingColorTransitionFactory( bgColor, ::surfaceFromScheme ) { surfaceColor -> val colorList = ColorStateList.valueOf(surfaceColor) mediaViewHolder.player.backgroundTintList = colorList - mediaViewHolder.albumView.foregroundTintList = colorList - mediaViewHolder.albumView.backgroundTintList = colorList mediaViewHolder.seamlessIcon.imageTintList = colorList mediaViewHolder.seamlessText.setTextColor(surfaceColor) mediaViewHolder.gutsViewHolder.setSurfaceColor(surfaceColor) } - val accentPrimary = colorTransitionFactory( + val accentPrimary = animatingColorTransitionFactory( loadDefaultColor(R.attr.textColorPrimary), ::accentPrimaryFromScheme ) { accentPrimary -> @@ -116,7 +134,7 @@ class ColorSchemeTransition internal constructor( mediaViewHolder.gutsViewHolder.setAccentPrimaryColor(accentPrimary) } - val textPrimary = colorTransitionFactory( + val textPrimary = animatingColorTransitionFactory( loadDefaultColor(R.attr.textColorPrimary), ::textPrimaryFromScheme ) { textPrimary -> @@ -132,28 +150,65 @@ class ColorSchemeTransition internal constructor( mediaViewHolder.gutsViewHolder.setTextPrimaryColor(textPrimary) } - val textPrimaryInverse = colorTransitionFactory( + val textPrimaryInverse = animatingColorTransitionFactory( loadDefaultColor(R.attr.textColorPrimaryInverse), ::textPrimaryInverseFromScheme ) { textPrimaryInverse -> mediaViewHolder.actionPlayPause.imageTintList = ColorStateList.valueOf(textPrimaryInverse) } - val textSecondary = colorTransitionFactory( + val textSecondary = animatingColorTransitionFactory( loadDefaultColor(R.attr.textColorSecondary), ::textSecondaryFromScheme ) { textSecondary -> mediaViewHolder.artistText.setTextColor(textSecondary) } - val textTertiary = colorTransitionFactory( + val textTertiary = animatingColorTransitionFactory( loadDefaultColor(R.attr.textColorTertiary), ::textTertiaryFromScheme ) { textTertiary -> mediaViewHolder.seekBar.progressBackgroundTintList = ColorStateList.valueOf(textTertiary) } + // Note: This background gradient currently doesn't animate between colors. + val backgroundGradient = genericColorTransitionFactory { scheme -> + val defaultTintColor = ColorStateList.valueOf(bgColor) + if (scheme == null) { + mediaViewHolder.albumView.foregroundTintList = defaultTintColor + mediaViewHolder.albumView.backgroundTintList = defaultTintColor + return@genericColorTransitionFactory + } + + // If there's no album art, just hide the gradient so we show the solid background. + val showGradient = mediaViewHolder.albumView.drawable != null + val startColor = getColorWithAlpha( + backgroundStartFromScheme(scheme), + alpha = if (showGradient) .25f else 0f + ) + val endColor = getColorWithAlpha( + backgroundEndFromScheme(scheme), + alpha = if (showGradient) .90f else 0f + ) + val gradientColors = intArrayOf(startColor, endColor) + + val foregroundGradient = mediaViewHolder.albumView.foreground.mutate() + if (foregroundGradient is GradientDrawable) { + foregroundGradient.colors = gradientColors + } + val backgroundGradient = mediaViewHolder.albumView.background.mutate() + if (backgroundGradient is GradientDrawable) { + backgroundGradient.colors = gradientColors + } + } + val colorTransitions = arrayOf( - surfaceColor, accentPrimary, textPrimary, - textPrimaryInverse, textSecondary, textTertiary) + surfaceColor, + accentPrimary, + textPrimary, + textPrimaryInverse, + textSecondary, + textTertiary, + backgroundGradient + ) private fun loadDefaultColor(id: Int): Int { return Utils.getColorAttr(context, id).defaultColor diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaColorSchemes.kt b/packages/SystemUI/src/com/android/systemui/media/MediaColorSchemes.kt index 97c6014c91bd..5e767b0458b9 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaColorSchemes.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaColorSchemes.kt @@ -35,3 +35,9 @@ internal fun textSecondaryFromScheme(scheme: ColorScheme) = scheme.neutral2[3] / /** Returns the tertiary text color for media controls based on the scheme. */ internal fun textTertiaryFromScheme(scheme: ColorScheme) = scheme.neutral2[5] // N2-400 + +/** Returns the color for the start of the background gradient based on the scheme. */ +internal fun backgroundStartFromScheme(scheme: ColorScheme) = scheme.accent2[8] // A2-700 + +/** Returns the color for the end of the background gradient based on the scheme. */ +internal fun backgroundEndFromScheme(scheme: ColorScheme) = scheme.accent1[8] // A1-700 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt index 270bdc785178..0a616c095551 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt @@ -17,6 +17,7 @@ import android.util.MathUtils.lerp import android.view.View import com.android.systemui.animation.Interpolators import com.android.systemui.statusbar.LightRevealEffect.Companion.getPercentPastThreshold +import com.android.systemui.util.getColorWithAlpha import java.util.function.Consumer /** @@ -367,7 +368,7 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context, } if (startColorAlpha > 0f) { - canvas.drawColor(updateColorAlpha(revealGradientEndColor, startColorAlpha)) + canvas.drawColor(getColorWithAlpha(revealGradientEndColor, startColorAlpha)) } with(shaderGradientMatrix) { @@ -383,15 +384,7 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context, private fun setPaintColorFilter() { gradientPaint.colorFilter = PorterDuffColorFilter( - updateColorAlpha(revealGradientEndColor, revealGradientEndColorAlpha), + getColorWithAlpha(revealGradientEndColor, revealGradientEndColorAlpha), PorterDuff.Mode.MULTIPLY) } - - private fun updateColorAlpha(color: Int, alpha: Float): Int = - Color.argb( - (alpha * 255).toInt(), - Color.red(color), - Color.green(color), - Color.blue(color) - ) }
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/util/ColorUtil.kt b/packages/SystemUI/src/com/android/systemui/util/ColorUtil.kt new file mode 100644 index 000000000000..27a53bf2ceda --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/util/ColorUtil.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2022 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.systemui.util + +import android.content.res.TypedArray +import android.graphics.Color +import android.view.ContextThemeWrapper + +/** Returns an ARGB color version of [color] at the given [alpha]. */ +fun getColorWithAlpha(color: Int, alpha: Float): Int = + Color.argb( + (alpha * 255).toInt(), + Color.red(color), + Color.green(color), + Color.blue(color) + ) + + +/** + * Returns the color provided at the specified {@param attrIndex} in {@param a} if it exists, + * otherwise, returns the color from the private attribute {@param privAttrId}. + */ +fun getPrivateAttrColorIfUnset( + ctw: ContextThemeWrapper, attrArray: TypedArray, + attrIndex: Int, defColor: Int, privAttrId: Int +): Int { + // If the index is specified, use that value + var a = attrArray + if (a.hasValue(attrIndex)) { + return a.getColor(attrIndex, defColor) + } + + // Otherwise fallback to the value of the private attribute + val customAttrs = intArrayOf(privAttrId) + a = ctw.obtainStyledAttributes(customAttrs) + val color = a.getColor(0, defColor) + a.recycle() + return color +} diff --git a/packages/SystemUI/src/com/android/systemui/util/Utils.java b/packages/SystemUI/src/com/android/systemui/util/Utils.java index 8e5e1d2e1b87..5b5dca30620a 100644 --- a/packages/SystemUI/src/com/android/systemui/util/Utils.java +++ b/packages/SystemUI/src/com/android/systemui/util/Utils.java @@ -105,25 +105,6 @@ public class Utils { } /** - * Returns the color provided at the specified {@param attrIndex} in {@param a} if it exists, - * otherwise, returns the color from the private attribute {@param privAttrId}. - */ - public static int getPrivateAttrColorIfUnset(ContextThemeWrapper ctw, TypedArray a, - int attrIndex, int defColor, int privAttrId) { - // If the index is specified, use that value - if (a.hasValue(attrIndex)) { - return a.getColor(attrIndex, defColor); - } - - // Otherwise fallback to the value of the private attribute - int[] customAttrs = { privAttrId }; - a = ctw.obtainStyledAttributes(customAttrs); - int color = a.getColor(0, defColor); - a.recycle(); - return color; - } - - /** * Gets the {@link R.dimen#status_bar_header_height_keyguard}. */ public static int getStatusBarHeaderHeightKeyguard(Context context) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt index 8f967ab5294f..65d501442d87 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/ColorSchemeTransitionTest.kt @@ -19,9 +19,9 @@ package com.android.systemui.media import org.mockito.Mockito.`when` as whenever import android.animation.ValueAnimator import android.graphics.Color -import android.test.suitebuilder.annotation.SmallTest import android.testing.AndroidTestingRunner import android.testing.TestableLooper +import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.monet.ColorScheme import junit.framework.Assert.assertEquals @@ -46,28 +46,35 @@ class ColorSchemeTransitionTest : SysuiTestCase() { private interface ExtractCB : (ColorScheme) -> Int private interface ApplyCB : (Int) -> Unit - private lateinit var colorTransition: ColorTransition + private lateinit var colorTransition: AnimatingColorTransition private lateinit var colorSchemeTransition: ColorSchemeTransition - @Mock private lateinit var mockTransition: ColorTransition + @Mock private lateinit var mockAnimatingTransition: AnimatingColorTransition + @Mock private lateinit var mockGenericTransition: GenericColorTransition @Mock private lateinit var valueAnimator: ValueAnimator @Mock private lateinit var colorScheme: ColorScheme @Mock private lateinit var extractColor: ExtractCB @Mock private lateinit var applyColor: ApplyCB - private lateinit var transitionFactory: ColorTransitionFactory + private lateinit var animatingColorTransitionFactory: AnimatingColorTransitionFactory + private lateinit var genericColorTransitionFactory: GenericColorTransitionFactory @Mock private lateinit var mediaViewHolder: MediaViewHolder @JvmField @Rule val mockitoRule = MockitoJUnit.rule() @Before fun setUp() { - transitionFactory = { default, extractColor, applyColor -> mockTransition } + animatingColorTransitionFactory = { _, _, _ -> mockAnimatingTransition } + genericColorTransitionFactory = { _ -> mockGenericTransition } whenever(extractColor.invoke(colorScheme)).thenReturn(TARGET_COLOR) - colorSchemeTransition = ColorSchemeTransition(context, mediaViewHolder, transitionFactory) + colorSchemeTransition = ColorSchemeTransition( + context, mediaViewHolder, animatingColorTransitionFactory, genericColorTransitionFactory + ) - colorTransition = object : ColorTransition(DEFAULT_COLOR, extractColor, applyColor) { + colorTransition = object : AnimatingColorTransition( + DEFAULT_COLOR, extractColor, applyColor + ) { override fun buildAnimator(): ValueAnimator { return valueAnimator } @@ -142,6 +149,7 @@ class ColorSchemeTransitionTest : SysuiTestCase() { @Test fun testColorSchemeTransition_update() { colorSchemeTransition.updateColorScheme(colorScheme) - verify(mockTransition, times(6)).updateColorScheme(colorScheme) + verify(mockAnimatingTransition, times(6)).updateColorScheme(colorScheme) + verify(mockGenericTransition).updateColorScheme(colorScheme) } } |