Merge "Intensify recommendation gradient and scale the cover." into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
7ef14ecb39
25
packages/SystemUI/res/drawable/qs_media_rec_scrim.xml
Normal file
25
packages/SystemUI/res/drawable/qs_media_rec_scrim.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2023 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">
|
||||
<!-- gradient from 25% in the center to 100% at edges -->
|
||||
<gradient
|
||||
android:type="radial"
|
||||
android:gradientRadius="40%p"
|
||||
android:startColor="#AE000000"
|
||||
android:endColor="#00000000" />
|
||||
</shape>
|
||||
@@ -22,9 +22,10 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:translationZ="0dp"
|
||||
android:scaleType="centerCrop"
|
||||
android:scaleType="matrix"
|
||||
android:adjustViewBounds="true"
|
||||
android:clipToOutline="true"
|
||||
android:layerType="hardware"
|
||||
android:background="@drawable/bg_smartspace_media_item"/>
|
||||
|
||||
<!-- App icon -->
|
||||
|
||||
@@ -31,12 +31,15 @@ import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BlendMode;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.ColorMatrix;
|
||||
import android.graphics.ColorMatrixColorFilter;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.GradientDrawable;
|
||||
@@ -62,7 +65,6 @@ import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.constraintlayout.widget.ConstraintSet;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
@@ -145,6 +147,12 @@ public class MediaControlPanel {
|
||||
private static final int SMARTSPACE_CARD_CLICK_EVENT = 760;
|
||||
protected static final int SMARTSPACE_CARD_DISMISS_EVENT = 761;
|
||||
|
||||
private static final float REC_MEDIA_COVER_SCALE_FACTOR = 1.25f;
|
||||
private static final float MEDIA_SCRIM_START_ALPHA = 0.25f;
|
||||
private static final float MEDIA_REC_SCRIM_START_ALPHA = 0.15f;
|
||||
private static final float MEDIA_PLAYER_SCRIM_END_ALPHA = 0.9f;
|
||||
private static final float MEDIA_REC_SCRIM_END_ALPHA = 1.0f;
|
||||
|
||||
private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS);
|
||||
|
||||
// Buttons to show in small player when using semantic actions
|
||||
@@ -776,7 +784,7 @@ public class MediaControlPanel {
|
||||
WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon);
|
||||
if (wallpaperColors != null) {
|
||||
mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT);
|
||||
artwork = addGradientToIcon(artworkIcon, mutableColorScheme, width, height);
|
||||
artwork = addGradientToPlayerAlbum(artworkIcon, mutableColorScheme, width, height);
|
||||
isArtworkBound = true;
|
||||
} else {
|
||||
// If there's no artwork, use colors from the app icon
|
||||
@@ -866,8 +874,9 @@ public class MediaControlPanel {
|
||||
Trace.beginAsyncSection(traceName, traceCookie);
|
||||
|
||||
// Capture width & height from views in foreground for artwork scaling in background
|
||||
int width = mRecommendationViewHolder.getMediaCoverContainers().get(0).getMeasuredWidth();
|
||||
int height = mRecommendationViewHolder.getMediaCoverContainers().get(0).getMeasuredHeight();
|
||||
int width = mContext.getResources().getDimensionPixelSize(R.dimen.qs_media_rec_album_width);
|
||||
int height = mContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.qs_media_rec_album_height_expanded);
|
||||
|
||||
mBackgroundExecutor.execute(() -> {
|
||||
// Album art
|
||||
@@ -877,7 +886,8 @@ public class MediaControlPanel {
|
||||
WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon);
|
||||
if (wallpaperColors != null) {
|
||||
mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT);
|
||||
artwork = addGradientToIcon(artworkIcon, mutableColorScheme, width, height);
|
||||
artwork = addGradientToRecommendationAlbum(artworkIcon, mutableColorScheme, width,
|
||||
height);
|
||||
} else {
|
||||
artwork = new ColorDrawable(Color.TRANSPARENT);
|
||||
}
|
||||
@@ -886,6 +896,11 @@ public class MediaControlPanel {
|
||||
// Bind the artwork drawable to media cover.
|
||||
ImageView mediaCover =
|
||||
mRecommendationViewHolder.getMediaCoverItems().get(itemIndex);
|
||||
// Rescale media cover
|
||||
Matrix coverMatrix = new Matrix(mediaCover.getImageMatrix());
|
||||
coverMatrix.postScale(REC_MEDIA_COVER_SCALE_FACTOR, REC_MEDIA_COVER_SCALE_FACTOR,
|
||||
0.5f * width, 0.5f * height);
|
||||
mediaCover.setImageMatrix(coverMatrix);
|
||||
mediaCover.setImageDrawable(artwork);
|
||||
|
||||
// Set up the app icon.
|
||||
@@ -907,7 +922,8 @@ public class MediaControlPanel {
|
||||
// This method should be called from a background thread. WallpaperColors.fromBitmap takes a
|
||||
// good amount of time. We do that work on the background executor to avoid stalling animations
|
||||
// on the UI Thread.
|
||||
private WallpaperColors getWallpaperColor(Icon artworkIcon) {
|
||||
@VisibleForTesting
|
||||
protected WallpaperColors getWallpaperColor(Icon artworkIcon) {
|
||||
if (artworkIcon != null) {
|
||||
if (artworkIcon.getType() == Icon.TYPE_BITMAP
|
||||
|| artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) {
|
||||
@@ -925,22 +941,40 @@ public class MediaControlPanel {
|
||||
return null;
|
||||
}
|
||||
|
||||
private LayerDrawable addGradientToIcon(
|
||||
Icon artworkIcon,
|
||||
ColorScheme mutableColorScheme,
|
||||
int width,
|
||||
int height
|
||||
) {
|
||||
@VisibleForTesting
|
||||
protected LayerDrawable addGradientToPlayerAlbum(Icon artworkIcon,
|
||||
ColorScheme mutableColorScheme, int width, int height) {
|
||||
Drawable albumArt = getScaledBackground(artworkIcon, width, height);
|
||||
GradientDrawable gradient = (GradientDrawable) AppCompatResources
|
||||
.getDrawable(mContext, R.drawable.qs_media_scrim);
|
||||
GradientDrawable gradient = (GradientDrawable) mContext.getDrawable(
|
||||
R.drawable.qs_media_scrim).mutate();
|
||||
return setupGradientColorOnDrawable(albumArt, gradient, mutableColorScheme,
|
||||
MEDIA_SCRIM_START_ALPHA, MEDIA_PLAYER_SCRIM_END_ALPHA);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected LayerDrawable addGradientToRecommendationAlbum(Icon artworkIcon,
|
||||
ColorScheme mutableColorScheme, int width, int height) {
|
||||
// First try scaling rec card using bitmap drawable.
|
||||
// If returns null, set drawable bounds.
|
||||
Drawable albumArt = getScaledRecommendationCover(artworkIcon, width, height);
|
||||
if (albumArt == null) {
|
||||
albumArt = getScaledBackground(artworkIcon, width, height);
|
||||
}
|
||||
GradientDrawable gradient = (GradientDrawable) mContext.getDrawable(
|
||||
R.drawable.qs_media_rec_scrim).mutate();
|
||||
return setupGradientColorOnDrawable(albumArt, gradient, mutableColorScheme,
|
||||
MEDIA_REC_SCRIM_START_ALPHA, MEDIA_REC_SCRIM_END_ALPHA);
|
||||
}
|
||||
|
||||
private LayerDrawable setupGradientColorOnDrawable(Drawable albumArt, GradientDrawable gradient,
|
||||
ColorScheme mutableColorScheme, float startAlpha, float endAlpha) {
|
||||
gradient.setColors(new int[] {
|
||||
ColorUtilKt.getColorWithAlpha(
|
||||
MediaColorSchemesKt.backgroundStartFromScheme(mutableColorScheme),
|
||||
0.25f),
|
||||
startAlpha),
|
||||
ColorUtilKt.getColorWithAlpha(
|
||||
MediaColorSchemesKt.backgroundEndFromScheme(mutableColorScheme),
|
||||
0.9f),
|
||||
endAlpha),
|
||||
});
|
||||
return new LayerDrawable(new Drawable[] { albumArt, gradient });
|
||||
}
|
||||
@@ -1585,6 +1619,29 @@ public class MediaControlPanel {
|
||||
return drawable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale artwork to fill the background of media covers in recommendation card.
|
||||
*/
|
||||
@UiThread
|
||||
private Drawable getScaledRecommendationCover(Icon artworkIcon, int width, int height) {
|
||||
if (width == 0 || height == 0) {
|
||||
return null;
|
||||
}
|
||||
if (artworkIcon != null) {
|
||||
Bitmap bitmap;
|
||||
if (artworkIcon.getType() == Icon.TYPE_BITMAP
|
||||
|| artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) {
|
||||
Bitmap artworkBitmap = artworkIcon.getBitmap();
|
||||
if (artworkBitmap != null) {
|
||||
bitmap = Bitmap.createScaledBitmap(artworkIcon.getBitmap(), width,
|
||||
height, false);
|
||||
return new BitmapDrawable(mContext.getResources(), bitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current media controller
|
||||
*
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.content.pm.PackageManager
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Matrix
|
||||
import android.graphics.drawable.Animatable2
|
||||
import android.graphics.drawable.AnimatedVectorDrawable
|
||||
import android.graphics.drawable.Drawable
|
||||
@@ -78,6 +79,8 @@ import com.android.systemui.media.controls.pipeline.EMPTY_SMARTSPACE_MEDIA_DATA
|
||||
import com.android.systemui.media.controls.pipeline.MediaDataManager
|
||||
import com.android.systemui.media.controls.util.MediaUiEventLogger
|
||||
import com.android.systemui.media.dialog.MediaOutputDialogFactory
|
||||
import com.android.systemui.monet.ColorScheme
|
||||
import com.android.systemui.monet.Style
|
||||
import com.android.systemui.plugins.ActivityStarter
|
||||
import com.android.systemui.plugins.FalsingManager
|
||||
import com.android.systemui.statusbar.NotificationLockscreenUserManager
|
||||
@@ -214,6 +217,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
||||
@Mock private lateinit var recSubtitleMock2: TextView
|
||||
@Mock private lateinit var recSubtitleMock3: TextView
|
||||
@Mock private lateinit var coverItem: ImageView
|
||||
@Mock private lateinit var matrix: Matrix
|
||||
private lateinit var coverItem1: ImageView
|
||||
private lateinit var coverItem2: ImageView
|
||||
private lateinit var coverItem3: ImageView
|
||||
@@ -699,6 +703,33 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
||||
verify(albumView, times(3)).setImageDrawable(any(Drawable::class.java))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun addTwoPlayerGradients_differentStates() {
|
||||
// Setup redArtwork and its color scheme.
|
||||
val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
|
||||
val redCanvas = Canvas(redBmp)
|
||||
redCanvas.drawColor(Color.RED)
|
||||
val redArt = Icon.createWithBitmap(redBmp)
|
||||
val redWallpaperColor = player.getWallpaperColor(redArt)
|
||||
val redColorScheme = ColorScheme(redWallpaperColor, true, Style.CONTENT)
|
||||
|
||||
// Setup greenArt and its color scheme.
|
||||
val greenBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
|
||||
val greenCanvas = Canvas(greenBmp)
|
||||
greenCanvas.drawColor(Color.GREEN)
|
||||
val greenArt = Icon.createWithBitmap(greenBmp)
|
||||
val greenWallpaperColor = player.getWallpaperColor(greenArt)
|
||||
val greenColorScheme = ColorScheme(greenWallpaperColor, true, Style.CONTENT)
|
||||
|
||||
// Add gradient to both icons.
|
||||
val redArtwork = player.addGradientToPlayerAlbum(redArt, redColorScheme, 10, 10)
|
||||
val greenArtwork = player.addGradientToPlayerAlbum(greenArt, greenColorScheme, 10, 10)
|
||||
|
||||
// They should have different constant states as they have different gradient color.
|
||||
assertThat(redArtwork.getDrawable(1).constantState)
|
||||
.isNotEqualTo(greenArtwork.getDrawable(1).constantState)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun bind_seekBarDisabled_hasActions_seekBarVisibilityIsSetToInvisible() {
|
||||
useRealConstraintSets()
|
||||
@@ -2092,6 +2123,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
||||
.thenReturn(listOf(recProgressBar1, recProgressBar2, recProgressBar3))
|
||||
whenever(recommendationViewHolder.mediaSubtitles)
|
||||
.thenReturn(listOf(recSubtitleMock1, recSubtitleMock2, recSubtitleMock3))
|
||||
whenever(coverItem.imageMatrix).thenReturn(matrix)
|
||||
|
||||
val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
|
||||
val canvas = Canvas(bmp)
|
||||
@@ -2127,6 +2159,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
||||
verify(recCardTitle).setTextColor(any<Int>())
|
||||
verify(recAppIconItem, times(3)).setImageDrawable(any(Drawable::class.java))
|
||||
verify(coverItem, times(3)).setImageDrawable(any(Drawable::class.java))
|
||||
verify(coverItem, times(3)).imageMatrix = any()
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -2188,6 +2221,34 @@ public class MediaControlPanelTest : SysuiTestCase() {
|
||||
verify(recSubtitleMock3).visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
@Test
|
||||
fun addTwoRecommendationGradients_differentStates() {
|
||||
// Setup redArtwork and its color scheme.
|
||||
val redBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
|
||||
val redCanvas = Canvas(redBmp)
|
||||
redCanvas.drawColor(Color.RED)
|
||||
val redArt = Icon.createWithBitmap(redBmp)
|
||||
val redWallpaperColor = player.getWallpaperColor(redArt)
|
||||
val redColorScheme = ColorScheme(redWallpaperColor, true, Style.CONTENT)
|
||||
|
||||
// Setup greenArt and its color scheme.
|
||||
val greenBmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
|
||||
val greenCanvas = Canvas(greenBmp)
|
||||
greenCanvas.drawColor(Color.GREEN)
|
||||
val greenArt = Icon.createWithBitmap(greenBmp)
|
||||
val greenWallpaperColor = player.getWallpaperColor(greenArt)
|
||||
val greenColorScheme = ColorScheme(greenWallpaperColor, true, Style.CONTENT)
|
||||
|
||||
// Add gradient to both icons.
|
||||
val redArtwork = player.addGradientToRecommendationAlbum(redArt, redColorScheme, 10, 10)
|
||||
val greenArtwork =
|
||||
player.addGradientToRecommendationAlbum(greenArt, greenColorScheme, 10, 10)
|
||||
|
||||
// They should have different constant states as they have different gradient color.
|
||||
assertThat(redArtwork.getDrawable(1).constantState)
|
||||
.isNotEqualTo(greenArtwork.getDrawable(1).constantState)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun onButtonClick_touchRippleFlagEnabled_playsTouchRipple() {
|
||||
fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, true)
|
||||
|
||||
Reference in New Issue
Block a user