Merge "Revert "[Media] Update background gradient scrim to use album theme colors."" into tm-dev

This commit is contained in:
Caitlin Cassidy
2022-04-28 13:14:02 +00:00
committed by Android (Google) Code Review
7 changed files with 55 additions and 153 deletions

View File

@@ -15,8 +15,6 @@
*/ */
package com.android.keyguard; package com.android.keyguard;
import static com.android.systemui.util.ColorUtilKt.getPrivateAttrColorIfUnset;
import android.animation.AnimatorSet; import android.animation.AnimatorSet;
import android.animation.ArgbEvaluator; import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator; import android.animation.ValueAnimator;
@@ -154,7 +152,7 @@ class NumPadAnimator {
ContextThemeWrapper ctw = new ContextThemeWrapper(context, mStyle); ContextThemeWrapper ctw = new ContextThemeWrapper(context, mStyle);
TypedArray a = ctw.obtainStyledAttributes(customAttrs); TypedArray a = ctw.obtainStyledAttributes(customAttrs);
mNormalColor = getPrivateAttrColorIfUnset(ctw, a, 0, 0, mNormalColor = Utils.getPrivateAttrColorIfUnset(ctw, a, 0, 0,
com.android.internal.R.attr.colorSurface); com.android.internal.R.attr.colorSurface);
mHighlightColor = a.getColor(1, 0); mHighlightColor = a.getColor(1, 0);
a.recycle(); a.recycle();

View File

@@ -21,41 +21,24 @@ import android.animation.ValueAnimator.AnimatorUpdateListener
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.content.Context import android.content.Context
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.drawable.GradientDrawable
import com.android.internal.R import com.android.internal.R
import com.android.internal.annotations.VisibleForTesting import com.android.internal.annotations.VisibleForTesting
import com.android.settingslib.Utils import com.android.settingslib.Utils
import com.android.systemui.monet.ColorScheme import com.android.systemui.monet.ColorScheme
import com.android.systemui.util.getColorWithAlpha
/** /**
* A [ColorTransition] is an object that updates the colors of views each time [updateColorScheme] * ColorTransition is responsible for managing the animation between two specific colors.
* 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 * It uses a ValueAnimator to execute the animation and interpolate between the source color and
* the target color. * the target color.
* *
* Selection of the target color from the scheme, and application of the interpolated color * Selection of the target color from the scheme, and application of the interpolated color
* are delegated to callbacks. * are delegated to callbacks.
*/ */
open class AnimatingColorTransition( open class ColorTransition(
private val defaultColor: Int, private val defaultColor: Int,
private val extractColor: (ColorScheme) -> Int, private val extractColor: (ColorScheme) -> Int,
private val applyColor: (Int) -> Unit private val applyColor: (Int) -> Unit
) : AnimatorUpdateListener, ColorTransition { ) : AnimatorUpdateListener {
private val argbEvaluator = ArgbEvaluator() private val argbEvaluator = ArgbEvaluator()
private val valueAnimator = buildAnimator() private val valueAnimator = buildAnimator()
@@ -70,7 +53,7 @@ open class AnimatingColorTransition(
applyColor(currentColor) applyColor(currentColor)
} }
override fun updateColorScheme(scheme: ColorScheme?) { fun updateColorScheme(scheme: ColorScheme?) {
val newTargetColor = if (scheme == null) defaultColor else extractColor(scheme) val newTargetColor = if (scheme == null) defaultColor else extractColor(scheme)
if (newTargetColor != targetColor) { if (newTargetColor != targetColor) {
sourceColor = currentColor sourceColor = currentColor
@@ -93,9 +76,7 @@ open class AnimatingColorTransition(
} }
} }
typealias AnimatingColorTransitionFactory = typealias ColorTransitionFactory = (Int, (ColorScheme) -> Int, (Int) -> Unit) -> ColorTransition
(Int, (ColorScheme) -> Int, (Int) -> Unit) -> AnimatingColorTransition
typealias GenericColorTransitionFactory = ((ColorScheme?) -> Unit) -> GenericColorTransition
/** /**
* ColorSchemeTransition constructs a ColorTransition for each color in the scheme * ColorSchemeTransition constructs a ColorTransition for each color in the scheme
@@ -105,26 +86,27 @@ typealias GenericColorTransitionFactory = ((ColorScheme?) -> Unit) -> GenericCol
class ColorSchemeTransition internal constructor( class ColorSchemeTransition internal constructor(
private val context: Context, private val context: Context,
mediaViewHolder: MediaViewHolder, mediaViewHolder: MediaViewHolder,
animatingColorTransitionFactory: AnimatingColorTransitionFactory, colorTransitionFactory: ColorTransitionFactory
genericColorTransitionFactory: GenericColorTransitionFactory
) { ) {
constructor(context: Context, mediaViewHolder: MediaViewHolder) : constructor(context: Context, mediaViewHolder: MediaViewHolder) :
this(context, mediaViewHolder, ::AnimatingColorTransition, ::GenericColorTransition) this(context, mediaViewHolder, ::ColorTransition)
val bgColor = context.getColor(com.android.systemui.R.color.material_dynamic_secondary95) val bgColor = context.getColor(com.android.systemui.R.color.material_dynamic_secondary95)
val surfaceColor = animatingColorTransitionFactory( val surfaceColor = colorTransitionFactory(
bgColor, bgColor,
::surfaceFromScheme ::surfaceFromScheme
) { surfaceColor -> ) { surfaceColor ->
val colorList = ColorStateList.valueOf(surfaceColor) val colorList = ColorStateList.valueOf(surfaceColor)
mediaViewHolder.player.backgroundTintList = colorList mediaViewHolder.player.backgroundTintList = colorList
mediaViewHolder.albumView.foregroundTintList = colorList
mediaViewHolder.albumView.backgroundTintList = colorList
mediaViewHolder.seamlessIcon.imageTintList = colorList mediaViewHolder.seamlessIcon.imageTintList = colorList
mediaViewHolder.seamlessText.setTextColor(surfaceColor) mediaViewHolder.seamlessText.setTextColor(surfaceColor)
mediaViewHolder.gutsViewHolder.setSurfaceColor(surfaceColor) mediaViewHolder.gutsViewHolder.setSurfaceColor(surfaceColor)
} }
val accentPrimary = animatingColorTransitionFactory( val accentPrimary = colorTransitionFactory(
loadDefaultColor(R.attr.textColorPrimary), loadDefaultColor(R.attr.textColorPrimary),
::accentPrimaryFromScheme ::accentPrimaryFromScheme
) { accentPrimary -> ) { accentPrimary ->
@@ -134,7 +116,7 @@ class ColorSchemeTransition internal constructor(
mediaViewHolder.gutsViewHolder.setAccentPrimaryColor(accentPrimary) mediaViewHolder.gutsViewHolder.setAccentPrimaryColor(accentPrimary)
} }
val textPrimary = animatingColorTransitionFactory( val textPrimary = colorTransitionFactory(
loadDefaultColor(R.attr.textColorPrimary), loadDefaultColor(R.attr.textColorPrimary),
::textPrimaryFromScheme ::textPrimaryFromScheme
) { textPrimary -> ) { textPrimary ->
@@ -150,65 +132,28 @@ class ColorSchemeTransition internal constructor(
mediaViewHolder.gutsViewHolder.setTextPrimaryColor(textPrimary) mediaViewHolder.gutsViewHolder.setTextPrimaryColor(textPrimary)
} }
val textPrimaryInverse = animatingColorTransitionFactory( val textPrimaryInverse = colorTransitionFactory(
loadDefaultColor(R.attr.textColorPrimaryInverse), loadDefaultColor(R.attr.textColorPrimaryInverse),
::textPrimaryInverseFromScheme ::textPrimaryInverseFromScheme
) { textPrimaryInverse -> ) { textPrimaryInverse ->
mediaViewHolder.actionPlayPause.imageTintList = ColorStateList.valueOf(textPrimaryInverse) mediaViewHolder.actionPlayPause.imageTintList = ColorStateList.valueOf(textPrimaryInverse)
} }
val textSecondary = animatingColorTransitionFactory( val textSecondary = colorTransitionFactory(
loadDefaultColor(R.attr.textColorSecondary), loadDefaultColor(R.attr.textColorSecondary),
::textSecondaryFromScheme ::textSecondaryFromScheme
) { textSecondary -> mediaViewHolder.artistText.setTextColor(textSecondary) } ) { textSecondary -> mediaViewHolder.artistText.setTextColor(textSecondary) }
val textTertiary = animatingColorTransitionFactory( val textTertiary = colorTransitionFactory(
loadDefaultColor(R.attr.textColorTertiary), loadDefaultColor(R.attr.textColorTertiary),
::textTertiaryFromScheme ::textTertiaryFromScheme
) { textTertiary -> ) { textTertiary ->
mediaViewHolder.seekBar.progressBackgroundTintList = ColorStateList.valueOf(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( val colorTransitions = arrayOf(
surfaceColor, surfaceColor, accentPrimary, textPrimary,
accentPrimary, textPrimaryInverse, textSecondary, textTertiary)
textPrimary,
textPrimaryInverse,
textSecondary,
textTertiary,
backgroundGradient
)
private fun loadDefaultColor(id: Int): Int { private fun loadDefaultColor(id: Int): Int {
return Utils.getColorAttr(context, id).defaultColor return Utils.getColorAttr(context, id).defaultColor

View File

@@ -35,9 +35,3 @@ internal fun textSecondaryFromScheme(scheme: ColorScheme) = scheme.neutral2[3] /
/** Returns the tertiary text color for media controls based on the scheme. */ /** Returns the tertiary text color for media controls based on the scheme. */
internal fun textTertiaryFromScheme(scheme: ColorScheme) = scheme.neutral2[5] // N2-400 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

View File

@@ -17,7 +17,6 @@ import android.util.MathUtils.lerp
import android.view.View import android.view.View
import com.android.systemui.animation.Interpolators import com.android.systemui.animation.Interpolators
import com.android.systemui.statusbar.LightRevealEffect.Companion.getPercentPastThreshold import com.android.systemui.statusbar.LightRevealEffect.Companion.getPercentPastThreshold
import com.android.systemui.util.getColorWithAlpha
import java.util.function.Consumer import java.util.function.Consumer
/** /**
@@ -368,7 +367,7 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context,
} }
if (startColorAlpha > 0f) { if (startColorAlpha > 0f) {
canvas.drawColor(getColorWithAlpha(revealGradientEndColor, startColorAlpha)) canvas.drawColor(updateColorAlpha(revealGradientEndColor, startColorAlpha))
} }
with(shaderGradientMatrix) { with(shaderGradientMatrix) {
@@ -384,7 +383,15 @@ class LightRevealScrim(context: Context?, attrs: AttributeSet?) : View(context,
private fun setPaintColorFilter() { private fun setPaintColorFilter() {
gradientPaint.colorFilter = PorterDuffColorFilter( gradientPaint.colorFilter = PorterDuffColorFilter(
getColorWithAlpha(revealGradientEndColor, revealGradientEndColorAlpha), updateColorAlpha(revealGradientEndColor, revealGradientEndColorAlpha),
PorterDuff.Mode.MULTIPLY) 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)
)
} }

View File

@@ -1,53 +0,0 @@
/*
* 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
}

View File

@@ -104,6 +104,25 @@ public class Utils {
return resources.getBoolean(R.bool.config_quickSettingsMediaLandscapeCollapsed); return resources.getBoolean(R.bool.config_quickSettingsMediaLandscapeCollapsed);
} }
/**
* 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}. * Gets the {@link R.dimen#status_bar_header_height_keyguard}.
*/ */

View File

@@ -19,9 +19,9 @@ package com.android.systemui.media
import org.mockito.Mockito.`when` as whenever import org.mockito.Mockito.`when` as whenever
import android.animation.ValueAnimator import android.animation.ValueAnimator
import android.graphics.Color import android.graphics.Color
import android.test.suitebuilder.annotation.SmallTest
import android.testing.AndroidTestingRunner import android.testing.AndroidTestingRunner
import android.testing.TestableLooper import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase import com.android.systemui.SysuiTestCase
import com.android.systemui.monet.ColorScheme import com.android.systemui.monet.ColorScheme
import junit.framework.Assert.assertEquals import junit.framework.Assert.assertEquals
@@ -46,35 +46,28 @@ class ColorSchemeTransitionTest : SysuiTestCase() {
private interface ExtractCB : (ColorScheme) -> Int private interface ExtractCB : (ColorScheme) -> Int
private interface ApplyCB : (Int) -> Unit private interface ApplyCB : (Int) -> Unit
private lateinit var colorTransition: AnimatingColorTransition private lateinit var colorTransition: ColorTransition
private lateinit var colorSchemeTransition: ColorSchemeTransition private lateinit var colorSchemeTransition: ColorSchemeTransition
@Mock private lateinit var mockAnimatingTransition: AnimatingColorTransition @Mock private lateinit var mockTransition: ColorTransition
@Mock private lateinit var mockGenericTransition: GenericColorTransition
@Mock private lateinit var valueAnimator: ValueAnimator @Mock private lateinit var valueAnimator: ValueAnimator
@Mock private lateinit var colorScheme: ColorScheme @Mock private lateinit var colorScheme: ColorScheme
@Mock private lateinit var extractColor: ExtractCB @Mock private lateinit var extractColor: ExtractCB
@Mock private lateinit var applyColor: ApplyCB @Mock private lateinit var applyColor: ApplyCB
private lateinit var animatingColorTransitionFactory: AnimatingColorTransitionFactory private lateinit var transitionFactory: ColorTransitionFactory
private lateinit var genericColorTransitionFactory: GenericColorTransitionFactory
@Mock private lateinit var mediaViewHolder: MediaViewHolder @Mock private lateinit var mediaViewHolder: MediaViewHolder
@JvmField @Rule val mockitoRule = MockitoJUnit.rule() @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
@Before @Before
fun setUp() { fun setUp() {
animatingColorTransitionFactory = { _, _, _ -> mockAnimatingTransition } transitionFactory = { default, extractColor, applyColor -> mockTransition }
genericColorTransitionFactory = { _ -> mockGenericTransition }
whenever(extractColor.invoke(colorScheme)).thenReturn(TARGET_COLOR) whenever(extractColor.invoke(colorScheme)).thenReturn(TARGET_COLOR)
colorSchemeTransition = ColorSchemeTransition( colorSchemeTransition = ColorSchemeTransition(context, mediaViewHolder, transitionFactory)
context, mediaViewHolder, animatingColorTransitionFactory, genericColorTransitionFactory
)
colorTransition = object : AnimatingColorTransition( colorTransition = object : ColorTransition(DEFAULT_COLOR, extractColor, applyColor) {
DEFAULT_COLOR, extractColor, applyColor
) {
override fun buildAnimator(): ValueAnimator { override fun buildAnimator(): ValueAnimator {
return valueAnimator return valueAnimator
} }
@@ -149,7 +142,6 @@ class ColorSchemeTransitionTest : SysuiTestCase() {
@Test @Test
fun testColorSchemeTransition_update() { fun testColorSchemeTransition_update() {
colorSchemeTransition.updateColorScheme(colorScheme) colorSchemeTransition.updateColorScheme(colorScheme)
verify(mockAnimatingTransition, times(6)).updateColorScheme(colorScheme) verify(mockTransition, times(6)).updateColorScheme(colorScheme)
verify(mockGenericTransition).updateColorScheme(colorScheme)
} }
} }