Merge "Fix corner clipping on UMO" into tm-dev

This commit is contained in:
Hawkwood Glazier
2022-05-03 23:51:43 +00:00
committed by Android (Google) Code Review
9 changed files with 102 additions and 92 deletions

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#FFFFFFFF" />
<corners android:radius="@dimen/notification_corner_radius"/>
</shape>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#00000000" />
<corners android:radius="@dimen/notification_corner_radius"/>
</shape>

View File

@@ -16,7 +16,6 @@
--> -->
<shape xmlns:android="http://schemas.android.com/apk/res/android" <shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"> android:shape="rectangle">
<corners android:radius="@dimen/notification_corner_radius"/>
<!-- gradient from 25% in the center to 100% at edges --> <!-- gradient from 25% in the center to 100% at edges -->
<gradient <gradient
android:type="radial" android:type="radial"

View File

@@ -25,7 +25,8 @@
android:clipToPadding="true" android:clipToPadding="true"
android:gravity="center_horizontal|fill_vertical" android:gravity="center_horizontal|fill_vertical"
android:forceHasOverlappingRendering="false" android:forceHasOverlappingRendering="false"
android:background="@drawable/qs_media_background" android:background="@drawable/qs_media_outline_layout_bg"
android:clipToOutline="true"
android:theme="@style/MediaPlayer"> android:theme="@style/MediaPlayer">
<ImageView <ImageView
@@ -40,8 +41,8 @@
android:scaleType="centerCrop" android:scaleType="centerCrop"
android:adjustViewBounds="true" android:adjustViewBounds="true"
android:clipToOutline="true" android:clipToOutline="true"
android:background="@drawable/qs_media_outline_album_bg"
android:foreground="@drawable/qs_media_scrim" android:foreground="@drawable/qs_media_scrim"
android:background="@drawable/qs_media_scrim"
/> />
<!-- Guideline for output switcher --> <!-- Guideline for output switcher -->

View File

@@ -21,6 +21,7 @@ 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.Color
import android.graphics.drawable.GradientDrawable import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.RippleDrawable import android.graphics.drawable.RippleDrawable
import com.android.internal.R import com.android.internal.R
@@ -37,13 +38,6 @@ interface ColorTransition {
fun updateColorScheme(scheme: ColorScheme?) 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. * 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
@@ -96,7 +90,6 @@ open class AnimatingColorTransition(
typealias AnimatingColorTransitionFactory = typealias AnimatingColorTransitionFactory =
(Int, (ColorScheme) -> Int, (Int) -> Unit) -> AnimatingColorTransition (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,23 +98,22 @@ typealias GenericColorTransitionFactory = ((ColorScheme?) -> Unit) -> GenericCol
*/ */
class ColorSchemeTransition internal constructor( class ColorSchemeTransition internal constructor(
private val context: Context, private val context: Context,
mediaViewHolder: MediaViewHolder, private val mediaViewHolder: MediaViewHolder,
animatingColorTransitionFactory: AnimatingColorTransitionFactory, animatingColorTransitionFactory: AnimatingColorTransitionFactory
genericColorTransitionFactory: GenericColorTransitionFactory
) { ) {
constructor(context: Context, mediaViewHolder: MediaViewHolder) : constructor(context: Context, mediaViewHolder: MediaViewHolder) :
this(context, mediaViewHolder, ::AnimatingColorTransition, ::GenericColorTransition) this(context, mediaViewHolder, ::AnimatingColorTransition)
private var isGradientEnabled = true
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 = animatingColorTransitionFactory(
bgColor, bgColor,
::surfaceFromScheme ::surfaceFromScheme
) { surfaceColor -> ) { surfaceColor ->
val colorList = ColorStateList.valueOf(surfaceColor) val colorList = ColorStateList.valueOf(surfaceColor)
mediaViewHolder.player.backgroundTintList = colorList
mediaViewHolder.seamlessIcon.imageTintList = colorList mediaViewHolder.seamlessIcon.imageTintList = colorList
mediaViewHolder.seamlessText.setTextColor(surfaceColor) mediaViewHolder.seamlessText.setTextColor(surfaceColor)
mediaViewHolder.albumView.backgroundTintList = colorList
mediaViewHolder.gutsViewHolder.setSurfaceColor(surfaceColor) mediaViewHolder.gutsViewHolder.setSurfaceColor(surfaceColor)
} }
@@ -181,36 +173,15 @@ class ColorSchemeTransition internal constructor(
mediaViewHolder.seekBar.progressBackgroundTintList = ColorStateList.valueOf(textTertiary) mediaViewHolder.seekBar.progressBackgroundTintList = ColorStateList.valueOf(textTertiary)
} }
// Note: This background gradient currently doesn't animate between colors. val bgGradientStart = animatingColorTransitionFactory(
val backgroundGradient = genericColorTransitionFactory { scheme -> bgColor,
val defaultTintColor = ColorStateList.valueOf(bgColor) albumGradientPicker(::backgroundStartFromScheme, 0.25f)
if (scheme == null) { ) { _ -> updateAlbumGradient() }
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 bgGradientEnd = animatingColorTransitionFactory(
val showGradient = mediaViewHolder.albumView.drawable != null bgColor,
val startColor = getColorWithAlpha( albumGradientPicker(::backgroundEndFromScheme, 0.9f)
backgroundStartFromScheme(scheme), ) { _ -> updateAlbumGradient() }
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,
@@ -220,14 +191,37 @@ class ColorSchemeTransition internal constructor(
textPrimaryInverse, textPrimaryInverse,
textSecondary, textSecondary,
textTertiary, textTertiary,
backgroundGradient bgGradientStart,
bgGradientEnd
) )
private fun updateAlbumGradient() {
val gradient = mediaViewHolder.albumView.foreground?.mutate()
if (gradient is GradientDrawable) {
gradient.colors = intArrayOf(
bgGradientStart?.currentColor ?: 0,
bgGradientEnd?.currentColor ?: 0)
}
}
private fun albumGradientPicker(
inner: (ColorScheme) -> Int,
targetAlpha: Float
): (ColorScheme) -> Int {
return { scheme ->
if (isGradientEnabled)
getColorWithAlpha(inner(scheme), targetAlpha)
else
Color.TRANSPARENT
}
}
private fun loadDefaultColor(id: Int): Int { private fun loadDefaultColor(id: Int): Int {
return Utils.getColorAttr(context, id).defaultColor return Utils.getColorAttr(context, id).defaultColor
} }
fun updateColorScheme(colorScheme: ColorScheme?) { fun updateColorScheme(colorScheme: ColorScheme?, enableGradient: Boolean) {
isGradientEnabled = enableGradient
colorTransitions.forEach { it.updateColorScheme(colorScheme) } colorTransitions.forEach { it.updateColorScheme(colorScheme) }
} }
} }

View File

@@ -341,6 +341,10 @@ public class MediaControlPanel {
} }
}); });
// AlbumView uses a hardware layer so that clipping of the foreground is handled
// with clipping the album art. Otherwise album art shows through at the edges.
mMediaViewHolder.getAlbumView().setLayerType(View.LAYER_TYPE_HARDWARE, null);
TextView titleText = mMediaViewHolder.getTitleText(); TextView titleText = mMediaViewHolder.getTitleText();
TextView artistText = mMediaViewHolder.getArtistText(); TextView artistText = mMediaViewHolder.getArtistText();
AnimatorSet enter = loadAnimator(R.anim.media_metadata_enter, AnimatorSet enter = loadAnimator(R.anim.media_metadata_enter,
@@ -571,8 +575,8 @@ public class MediaControlPanel {
} }
// Capture width & height from views in foreground for artwork scaling in background // Capture width & height from views in foreground for artwork scaling in background
int width = mMediaViewHolder.getPlayer().getWidth(); int width = mMediaViewHolder.getAlbumView().getMeasuredWidth();
int height = mMediaViewHolder.getPlayer().getHeight(); int height = mMediaViewHolder.getAlbumView().getMeasuredHeight();
// WallpaperColors.fromBitmap takes a good amount of time. We do that work // WallpaperColors.fromBitmap takes a good amount of time. We do that work
// on the background executor to avoid stalling animations on the UI Thread. // on the background executor to avoid stalling animations on the UI Thread.
@@ -610,7 +614,6 @@ public class MediaControlPanel {
// Bind the album view to the artwork or a transition drawable // Bind the album view to the artwork or a transition drawable
ImageView albumView = mMediaViewHolder.getAlbumView(); ImageView albumView = mMediaViewHolder.getAlbumView();
albumView.setPadding(0, 0, 0, 0); albumView.setPadding(0, 0, 0, 0);
albumView.setClipToOutline(true);
if (updateBackground || (!mIsArtworkBound && isArtworkBound)) { if (updateBackground || (!mIsArtworkBound && isArtworkBound)) {
if (mPrevArtwork == null) { if (mPrevArtwork == null) {
albumView.setImageDrawable(artwork); albumView.setImageDrawable(artwork);
@@ -634,7 +637,7 @@ public class MediaControlPanel {
} }
// Transition Colors to current color scheme // Transition Colors to current color scheme
mColorSchemeTransition.updateColorScheme(colorScheme); mColorSchemeTransition.updateColorScheme(colorScheme, mIsArtworkBound);
// App icon - use notification icon // App icon - use notification icon
ImageView appIconView = mMediaViewHolder.getAppIcon(); ImageView appIconView = mMediaViewHolder.getAppIcon();
@@ -925,7 +928,7 @@ public class MediaControlPanel {
InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER) { InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER) {
@Override @Override
protected float getCurrentTopCornerRadius() { protected float getCurrentTopCornerRadius() {
return ((IlluminationDrawable) player.getBackground()).getCornerRadius(); return mContext.getResources().getDimension(R.dimen.notification_corner_radius);
} }
@Override @Override
@@ -933,20 +936,6 @@ public class MediaControlPanel {
// TODO(b/184121838): Make IlluminationDrawable support top and bottom radius. // TODO(b/184121838): Make IlluminationDrawable support top and bottom radius.
return getCurrentTopCornerRadius(); return getCurrentTopCornerRadius();
} }
@Override
protected void setBackgroundCornerRadius(Drawable background, float topCornerRadius,
float bottomCornerRadius) {
// TODO(b/184121838): Make IlluminationDrawable support top and bottom radius.
float radius = Math.min(topCornerRadius, bottomCornerRadius);
((IlluminationDrawable) background).setCornerRadiusOverride(radius);
}
@Override
public void onLaunchAnimationEnd(boolean isExpandingFullyAbove) {
super.onLaunchAnimationEnd(isExpandingFullyAbove);
((IlluminationDrawable) player.getBackground()).setCornerRadiusOverride(null);
}
}; };
} }

View File

@@ -69,23 +69,6 @@ class MediaViewHolder constructor(itemView: View) {
val actionsTopBarrier = itemView.requireViewById<Barrier>(R.id.media_action_barrier_top) val actionsTopBarrier = itemView.requireViewById<Barrier>(R.id.media_action_barrier_top)
init {
(player.background as IlluminationDrawable).let {
it.registerLightSource(seamless)
it.registerLightSource(gutsViewHolder.cancel)
it.registerLightSource(gutsViewHolder.dismiss)
it.registerLightSource(gutsViewHolder.settings)
it.registerLightSource(actionPlayPause)
it.registerLightSource(actionNext)
it.registerLightSource(actionPrev)
it.registerLightSource(action0)
it.registerLightSource(action1)
it.registerLightSource(action2)
it.registerLightSource(action3)
it.registerLightSource(action4)
}
}
fun getAction(id: Int): ImageButton { fun getAction(id: Int): ImageButton {
return when (id) { return when (id) {
R.id.actionPlayPause -> actionPlayPause R.id.actionPlayPause -> actionPlayPause
@@ -161,7 +144,6 @@ class MediaViewHolder constructor(itemView: View) {
R.id.media_scrubbing_total_time R.id.media_scrubbing_total_time
) )
// Buttons used for notification-based actions // Buttons used for notification-based actions
val genericButtonIds = setOf( val genericButtonIds = setOf(
R.id.action0, R.id.action0,

View File

@@ -50,14 +50,12 @@ class ColorSchemeTransitionTest : SysuiTestCase() {
private lateinit var colorSchemeTransition: ColorSchemeTransition private lateinit var colorSchemeTransition: ColorSchemeTransition
@Mock private lateinit var mockAnimatingTransition: AnimatingColorTransition @Mock private lateinit var mockAnimatingTransition: AnimatingColorTransition
@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 animatingColorTransitionFactory: AnimatingColorTransitionFactory
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()
@@ -65,11 +63,10 @@ class ColorSchemeTransitionTest : SysuiTestCase() {
@Before @Before
fun setUp() { fun setUp() {
animatingColorTransitionFactory = { _, _, _ -> mockAnimatingTransition } animatingColorTransitionFactory = { _, _, _ -> mockAnimatingTransition }
genericColorTransitionFactory = { _ -> mockGenericTransition }
whenever(extractColor.invoke(colorScheme)).thenReturn(TARGET_COLOR) whenever(extractColor.invoke(colorScheme)).thenReturn(TARGET_COLOR)
colorSchemeTransition = ColorSchemeTransition( colorSchemeTransition = ColorSchemeTransition(
context, mediaViewHolder, animatingColorTransitionFactory, genericColorTransitionFactory context, mediaViewHolder, animatingColorTransitionFactory
) )
colorTransition = object : AnimatingColorTransition( colorTransition = object : AnimatingColorTransition(
@@ -148,8 +145,7 @@ class ColorSchemeTransitionTest : SysuiTestCase() {
@Test @Test
fun testColorSchemeTransition_update() { fun testColorSchemeTransition_update() {
colorSchemeTransition.updateColorScheme(colorScheme) colorSchemeTransition.updateColorScheme(colorScheme, true)
verify(mockAnimatingTransition, times(7)).updateColorScheme(colorScheme) verify(mockAnimatingTransition, times(9)).updateColorScheme(colorScheme)
verify(mockGenericTransition).updateColorScheme(colorScheme)
} }
} }

View File

@@ -536,6 +536,13 @@ public class MediaControlPanelTest : SysuiTestCase() {
verify(expandedSet).setVisibility(R.id.actionNext, ConstraintSet.INVISIBLE) verify(expandedSet).setVisibility(R.id.actionNext, ConstraintSet.INVISIBLE)
} }
@Test
fun bindAlbumView_testHardwareAfterAttach() {
player.attachPlayer(viewHolder)
verify(albumView).setLayerType(View.LAYER_TYPE_HARDWARE, null)
}
@Test @Test
fun bindAlbumView_setAfterExecutors() { fun bindAlbumView_setAfterExecutors() {
val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)