From 7c87da15b45ec2aeb18f1602d734a717fda1438f Mon Sep 17 00:00:00 2001 From: Michael Mikhail Date: Wed, 25 Jan 2023 21:22:08 +0000 Subject: Update media recommendation card layout Add new view for recommendation card that matches the new mock. And make sure it is under a flag. Bug: 264690645 Test: atest MediaControlPanelTest Test: checked the view and tested whether it works. Change-Id: I8059187fa2804e2a5d7f31815fb24cc767757e0c --- .../res/layout/media_recommendation_view.xml | 65 ++++++++++ .../SystemUI/res/layout/media_recommendations.xml | 75 +++++++++++ packages/SystemUI/res/values/dimens.xml | 5 + packages/SystemUI/res/values/strings.xml | 2 + packages/SystemUI/res/values/styles.xml | 17 +++ .../xml/media_recommendations_view_collapsed.xml | 64 +++++++++ .../xml/media_recommendations_view_expanded.xml | 71 ++++++++++ .../src/com/android/systemui/flags/Flags.kt | 4 + .../recommendation/RecommendationViewHolder.kt | 94 ++++++++++---- .../media/controls/ui/MediaCarouselController.kt | 10 +- .../media/controls/ui/MediaControlPanel.java | 143 ++++++++++++++++----- .../media/controls/ui/MediaViewController.kt | 13 +- .../systemui/media/controls/util/MediaFlags.kt | 4 + .../controls/ui/MediaCarouselControllerTest.kt | 5 +- .../media/controls/ui/MediaControlPanelTest.kt | 49 +++++++ .../media/controls/ui/MediaViewControllerTest.kt | 10 +- 16 files changed, 564 insertions(+), 67 deletions(-) create mode 100644 packages/SystemUI/res/layout/media_recommendation_view.xml create mode 100644 packages/SystemUI/res/layout/media_recommendations.xml create mode 100644 packages/SystemUI/res/xml/media_recommendations_view_collapsed.xml create mode 100644 packages/SystemUI/res/xml/media_recommendations_view_expanded.xml diff --git a/packages/SystemUI/res/layout/media_recommendation_view.xml b/packages/SystemUI/res/layout/media_recommendation_view.xml new file mode 100644 index 000000000000..101fad97beb5 --- /dev/null +++ b/packages/SystemUI/res/layout/media_recommendation_view.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/SystemUI/res/layout/media_recommendations.xml b/packages/SystemUI/res/layout/media_recommendations.xml new file mode 100644 index 000000000000..65fc19c5b2a4 --- /dev/null +++ b/packages/SystemUI/res/layout/media_recommendations.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index dfc01501a999..7d3a22c58ca5 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1068,8 +1068,13 @@ 16dp 88dp + 110dp + 108dp + 77dp 16dp 8dp + 22dp + 12dp 16dp diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index e60835cc5ea4..a1d14ac97331 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2360,6 +2360,8 @@ Play %1$s by %2$s from %3$s Play %1$s from %2$s + + For You diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 9846fc251a27..58b0234023ae 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -678,6 +678,17 @@ + + + diff --git a/packages/SystemUI/res/xml/media_recommendations_view_collapsed.xml b/packages/SystemUI/res/xml/media_recommendations_view_collapsed.xml new file mode 100644 index 000000000000..d3be3c7de5ad --- /dev/null +++ b/packages/SystemUI/res/xml/media_recommendations_view_collapsed.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/res/xml/media_recommendations_view_expanded.xml b/packages/SystemUI/res/xml/media_recommendations_view_expanded.xml new file mode 100644 index 000000000000..88c70552e9e8 --- /dev/null +++ b/packages/SystemUI/res/xml/media_recommendations_view_expanded.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt index 47c41fe1e3ba..12d36bca9a95 100644 --- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt +++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt @@ -365,6 +365,10 @@ object Flags { // TODO(b/266157412): Tracking Bug val MEDIA_RETAIN_SESSIONS = unreleasedFlag(913, "media_retain_sessions") + // TODO(b/266739309): Tracking Bug + @JvmField + val MEDIA_RECOMMENDATION_CARD_UPDATE = unreleasedFlag(914, "media_recommendation_card_update") + // 1000 - dock val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag(1000, "simulate_dock_through_charging") diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt index 1a10b18a5a69..8c1ec166fb2e 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/models/recommendation/RecommendationViewHolder.kt @@ -21,6 +21,7 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView +import com.android.internal.widget.CachingIconView import com.android.systemui.R import com.android.systemui.media.controls.models.GutsViewHolder import com.android.systemui.media.controls.ui.IlluminationDrawable @@ -29,18 +30,15 @@ import com.android.systemui.util.animation.TransitionLayout private const val TAG = "RecommendationViewHolder" /** ViewHolder for a Smartspace media recommendation. */ -class RecommendationViewHolder private constructor(itemView: View) { +class RecommendationViewHolder private constructor(itemView: View, updatedView: Boolean) { val recommendations = itemView as TransitionLayout // Recommendation screen - val cardIcon = itemView.requireViewById(R.id.recommendation_card_icon) - val mediaCoverItems = - listOf( - itemView.requireViewById(R.id.media_cover1), - itemView.requireViewById(R.id.media_cover2), - itemView.requireViewById(R.id.media_cover3) - ) + lateinit var cardIcon: ImageView + lateinit var mediaAppIcons: List + lateinit var cardTitle: TextView + val mediaCoverContainers = listOf( itemView.requireViewById(R.id.media_cover1_container), @@ -48,21 +46,45 @@ class RecommendationViewHolder private constructor(itemView: View) { itemView.requireViewById(R.id.media_cover3_container) ) val mediaTitles: List = - listOf( - itemView.requireViewById(R.id.media_title1), - itemView.requireViewById(R.id.media_title2), - itemView.requireViewById(R.id.media_title3) - ) + if (updatedView) { + mediaCoverContainers.map { it.requireViewById(R.id.media_title) } + } else { + listOf( + itemView.requireViewById(R.id.media_title1), + itemView.requireViewById(R.id.media_title2), + itemView.requireViewById(R.id.media_title3) + ) + } val mediaSubtitles: List = - listOf( - itemView.requireViewById(R.id.media_subtitle1), - itemView.requireViewById(R.id.media_subtitle2), - itemView.requireViewById(R.id.media_subtitle3) - ) + if (updatedView) { + mediaCoverContainers.map { it.requireViewById(R.id.media_subtitle) } + } else { + listOf( + itemView.requireViewById(R.id.media_subtitle1), + itemView.requireViewById(R.id.media_subtitle2), + itemView.requireViewById(R.id.media_subtitle3) + ) + } + val mediaCoverItems: List = + if (updatedView) { + mediaCoverContainers.map { it.requireViewById(R.id.media_cover) } + } else { + listOf( + itemView.requireViewById(R.id.media_cover1), + itemView.requireViewById(R.id.media_cover2), + itemView.requireViewById(R.id.media_cover3) + ) + } val gutsViewHolder = GutsViewHolder(itemView) init { + if (updatedView) { + mediaAppIcons = mediaCoverContainers.map { it.requireViewById(R.id.media_rec_app_icon) } + cardTitle = itemView.requireViewById(R.id.media_rec_title) + } else { + cardIcon = itemView.requireViewById(R.id.recommendation_card_icon) + } (recommendations.background as IlluminationDrawable).let { background -> mediaCoverContainers.forEach { background.registerLightSource(it) } background.registerLightSource(gutsViewHolder.cancel) @@ -83,36 +105,52 @@ class RecommendationViewHolder private constructor(itemView: View) { * @param parent Parent of inflated view. */ @JvmStatic - fun create(inflater: LayoutInflater, parent: ViewGroup): RecommendationViewHolder { + fun create( + inflater: LayoutInflater, + parent: ViewGroup, + updatedView: Boolean, + ): RecommendationViewHolder { val itemView = - inflater.inflate( - R.layout.media_smartspace_recommendations, - parent, - false /* attachToRoot */ - ) + if (updatedView) { + inflater.inflate( + R.layout.media_recommendations, + parent, + false /* attachToRoot */ + ) + } else { + inflater.inflate( + R.layout.media_smartspace_recommendations, + parent, + false /* attachToRoot */ + ) + } // Because this media view (a TransitionLayout) is used to measure and layout the views // in various states before being attached to its parent, we can't depend on the default // LAYOUT_DIRECTION_INHERIT to correctly resolve the ltr direction. itemView.layoutDirection = View.LAYOUT_DIRECTION_LOCALE - return RecommendationViewHolder(itemView) + return RecommendationViewHolder(itemView, updatedView) } // Res Ids for the control components on the recommendation view. val controlsIds = setOf( R.id.recommendation_card_icon, + R.id.media_rec_title, R.id.media_cover1, R.id.media_cover2, R.id.media_cover3, + R.id.media_cover, R.id.media_cover1_container, R.id.media_cover2_container, R.id.media_cover3_container, R.id.media_title1, R.id.media_title2, R.id.media_title3, + R.id.media_title, R.id.media_subtitle1, R.id.media_subtitle2, - R.id.media_subtitle3 + R.id.media_subtitle3, + R.id.media_subtitle, ) val mediaTitlesAndSubtitlesIds = @@ -120,9 +158,11 @@ class RecommendationViewHolder private constructor(itemView: View) { R.id.media_title1, R.id.media_title2, R.id.media_title3, + R.id.media_title, R.id.media_subtitle1, R.id.media_subtitle2, - R.id.media_subtitle3 + R.id.media_subtitle3, + R.id.media_subtitle, ) val mediaContainersIds = diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt index e7f7647797cd..b2ad15522743 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt @@ -43,6 +43,7 @@ import com.android.systemui.media.controls.models.recommendation.RecommendationV import com.android.systemui.media.controls.models.recommendation.SmartspaceMediaData import com.android.systemui.media.controls.pipeline.MediaDataManager import com.android.systemui.media.controls.ui.MediaControlPanel.SMARTSPACE_CARD_DISMISS_EVENT +import com.android.systemui.media.controls.util.MediaFlags import com.android.systemui.media.controls.util.MediaUiEventLogger import com.android.systemui.media.controls.util.SmallHash import com.android.systemui.plugins.ActivityStarter @@ -88,7 +89,8 @@ constructor( falsingManager: FalsingManager, dumpManager: DumpManager, private val logger: MediaUiEventLogger, - private val debugLogger: MediaCarouselControllerLogger + private val debugLogger: MediaCarouselControllerLogger, + private val mediaFlags: MediaFlags, ) : Dumpable { /** The current width of the carousel */ private var currentCarouselWidth: Int = 0 @@ -647,7 +649,11 @@ constructor( val newRecs = mediaControlPanelFactory.get() newRecs.attachRecommendation( - RecommendationViewHolder.create(LayoutInflater.from(context), mediaContent) + RecommendationViewHolder.create( + LayoutInflater.from(context), + mediaContent, + mediaFlags.isRecommendationCardUpdateEnabled() + ) ) newRecs.mediaViewController.sizeChangedListener = this::updateCarouselDimensions val lp = diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java index 45d50f0e4976..9250a580dfa0 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java @@ -61,6 +61,7 @@ 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; @@ -752,43 +753,16 @@ public class MediaControlPanel { int width = mMediaViewHolder.getAlbumView().getMeasuredWidth(); int height = mMediaViewHolder.getAlbumView().getMeasuredHeight(); - // WallpaperColors.fromBitmap takes a good amount of time. We do that work - // on the background executor to avoid stalling animations on the UI Thread. mBackgroundExecutor.execute(() -> { // Album art ColorScheme mutableColorScheme = null; Drawable artwork; boolean isArtworkBound; Icon artworkIcon = data.getArtwork(); - WallpaperColors wallpaperColors = null; - if (artworkIcon != null) { - if (artworkIcon.getType() == Icon.TYPE_BITMAP - || artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) { - // Avoids extra processing if this is already a valid bitmap - wallpaperColors = WallpaperColors - .fromBitmap(artworkIcon.getBitmap()); - } else { - Drawable artworkDrawable = artworkIcon.loadDrawable(mContext); - if (artworkDrawable != null) { - wallpaperColors = WallpaperColors - .fromDrawable(artworkIcon.loadDrawable(mContext)); - } - } - } + WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon); if (wallpaperColors != null) { mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT); - Drawable albumArt = getScaledBackground(artworkIcon, width, height); - GradientDrawable gradient = (GradientDrawable) mContext - .getDrawable(R.drawable.qs_media_scrim); - gradient.setColors(new int[] { - ColorUtilKt.getColorWithAlpha( - MediaColorSchemesKt.backgroundStartFromScheme(mutableColorScheme), - 0.25f), - ColorUtilKt.getColorWithAlpha( - MediaColorSchemesKt.backgroundEndFromScheme(mutableColorScheme), - 0.9f), - }); - artwork = new LayerDrawable(new Drawable[] { albumArt, gradient }); + artwork = addGradientToIcon(artworkIcon, mutableColorScheme, width, height); isArtworkBound = true; } else { // If there's no artwork, use colors from the app icon @@ -867,6 +841,96 @@ public class MediaControlPanel { }); } + private void bindRecommendationArtwork( + SmartspaceAction recommendation, + String packageName, + int itemIndex + ) { + final int traceCookie = recommendation.hashCode(); + final String traceName = + "MediaControlPanel#bindRecommendationArtwork<" + packageName + ">"; + 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(); + + mBackgroundExecutor.execute(() -> { + // Album art + ColorScheme mutableColorScheme = null; + Drawable artwork; + Icon artworkIcon = recommendation.getIcon(); + WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon); + if (wallpaperColors != null) { + mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT); + artwork = addGradientToIcon(artworkIcon, mutableColorScheme, width, height); + } else { + artwork = new ColorDrawable(Color.TRANSPARENT); + } + + mMainExecutor.execute(() -> { + // Bind the artwork drawable to media cover. + ImageView mediaCover = + mRecommendationViewHolder.getMediaCoverItems().get(itemIndex); + mediaCover.setImageDrawable(artwork); + + // Set up the app icon. + ImageView appIconView = mRecommendationViewHolder.getMediaAppIcons().get(itemIndex); + appIconView.clearColorFilter(); + try { + Drawable icon = mContext.getPackageManager() + .getApplicationIcon(packageName); + appIconView.setImageDrawable(icon); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Cannot find icon for package " + packageName, e); + appIconView.setImageResource(R.drawable.ic_music_note); + } + Trace.endAsyncSection(traceName, traceCookie); + }); + }); + } + + // 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) { + if (artworkIcon != null) { + if (artworkIcon.getType() == Icon.TYPE_BITMAP + || artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) { + // Avoids extra processing if this is already a valid bitmap + return WallpaperColors + .fromBitmap(artworkIcon.getBitmap()); + } else { + Drawable artworkDrawable = artworkIcon.loadDrawable(mContext); + if (artworkDrawable != null) { + return WallpaperColors + .fromDrawable(artworkIcon.loadDrawable(mContext)); + } + } + } + return null; + } + + private LayerDrawable addGradientToIcon( + 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); + gradient.setColors(new int[] { + ColorUtilKt.getColorWithAlpha( + MediaColorSchemesKt.backgroundStartFromScheme(mutableColorScheme), + 0.25f), + ColorUtilKt.getColorWithAlpha( + MediaColorSchemesKt.backgroundEndFromScheme(mutableColorScheme), + 0.9f), + }); + return new LayerDrawable(new Drawable[] { albumArt, gradient }); + } + private void scaleTransitionDrawableLayer(TransitionDrawable transitionDrawable, int layer, int targetWidth, int targetHeight) { Drawable drawable = transitionDrawable.getDrawable(layer); @@ -1224,8 +1288,10 @@ public class MediaControlPanel { PackageManager packageManager = mContext.getPackageManager(); // Set up media source app's logo. Drawable icon = packageManager.getApplicationIcon(applicationInfo); - ImageView headerLogoImageView = mRecommendationViewHolder.getCardIcon(); - headerLogoImageView.setImageDrawable(icon); + if (!mFeatureFlags.isEnabled(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE)) { + ImageView headerLogoImageView = mRecommendationViewHolder.getCardIcon(); + headerLogoImageView.setImageDrawable(icon); + } fetchAndUpdateRecommendationColors(icon); // Set up media rec card's tap action if applicable. @@ -1245,7 +1311,15 @@ public class MediaControlPanel { // Set up media item cover. ImageView mediaCoverImageView = mediaCoverItems.get(itemIndex); - mediaCoverImageView.setImageIcon(recommendation.getIcon()); + if (mFeatureFlags.isEnabled(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE)) { + bindRecommendationArtwork( + recommendation, + data.getPackageName(), + itemIndex + ); + } else { + mediaCoverImageView.setImageIcon(recommendation.getIcon()); + } // Set up the media item's click listener if applicable. ViewGroup mediaCoverContainer = mediaCoverContainers.get(itemIndex); @@ -1275,7 +1349,6 @@ public class MediaControlPanel { recommendation.getTitle(), artistName, appName)); } - // Set up title CharSequence title = recommendation.getTitle(); hasTitle |= !TextUtils.isEmpty(title); @@ -1353,6 +1426,10 @@ public class MediaControlPanel { int textPrimaryColor = MediaColorSchemesKt.textPrimaryFromScheme(colorScheme); int textSecondaryColor = MediaColorSchemesKt.textSecondaryFromScheme(colorScheme); + if (mFeatureFlags.isEnabled(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE)) { + mRecommendationViewHolder.getCardTitle().setTextColor(textPrimaryColor); + } + mRecommendationViewHolder.getRecommendations() .setBackgroundTintList(ColorStateList.valueOf(backgroundColor)); mRecommendationViewHolder.getMediaTitles().forEach( diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt index 2ec7be6eaa32..1e6002cdc717 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt @@ -25,6 +25,7 @@ import com.android.systemui.media.controls.models.GutsViewHolder import com.android.systemui.media.controls.models.player.MediaViewHolder import com.android.systemui.media.controls.models.recommendation.RecommendationViewHolder import com.android.systemui.media.controls.ui.MediaCarouselController.Companion.calculateAlpha +import com.android.systemui.media.controls.util.MediaFlags import com.android.systemui.statusbar.policy.ConfigurationController import com.android.systemui.util.animation.MeasurementOutput import com.android.systemui.util.animation.TransitionLayout @@ -45,7 +46,8 @@ constructor( private val context: Context, private val configurationController: ConfigurationController, private val mediaHostStatesManager: MediaHostStatesManager, - private val logger: MediaViewLogger + private val logger: MediaViewLogger, + private val mediaFlags: MediaFlags, ) { /** @@ -646,8 +648,13 @@ constructor( expandedLayout.load(context, R.xml.media_session_expanded) } TYPE.RECOMMENDATION -> { - collapsedLayout.load(context, R.xml.media_recommendation_collapsed) - expandedLayout.load(context, R.xml.media_recommendation_expanded) + if (mediaFlags.isRecommendationCardUpdateEnabled()) { + collapsedLayout.load(context, R.xml.media_recommendations_view_collapsed) + expandedLayout.load(context, R.xml.media_recommendations_view_expanded) + } else { + collapsedLayout.load(context, R.xml.media_recommendation_collapsed) + expandedLayout.load(context, R.xml.media_recommendation_expanded) + } } } refreshState() diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt index ab03930e42ac..81efa3688aab 100644 --- a/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt +++ b/packages/SystemUI/src/com/android/systemui/media/controls/util/MediaFlags.kt @@ -51,4 +51,8 @@ class MediaFlags @Inject constructor(private val featureFlags: FeatureFlags) { * whether the underlying notification was dismissed */ fun isRetainingPlayersEnabled() = featureFlags.isEnabled(Flags.MEDIA_RETAIN_SESSIONS) + + /** Check whether we show the updated recommendation card. */ + fun isRecommendationCardUpdateEnabled() = + featureFlags.isEnabled(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt index e4e95e580a7c..5e5dc8b20c65 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaCarouselControllerTest.kt @@ -33,6 +33,7 @@ import com.android.systemui.media.controls.models.recommendation.SmartspaceMedia 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.ui.MediaHierarchyManager.Companion.LOCATION_QS +import com.android.systemui.media.controls.util.MediaFlags import com.android.systemui.media.controls.util.MediaUiEventLogger import com.android.systemui.plugins.ActivityStarter import com.android.systemui.plugins.FalsingManager @@ -87,6 +88,7 @@ class MediaCarouselControllerTest : SysuiTestCase() { @Mock lateinit var smartspaceMediaData: SmartspaceMediaData @Mock lateinit var mediaCarousel: MediaScrollView @Mock lateinit var pageIndicator: PageIndicator + @Mock lateinit var mediaFlags: MediaFlags @Captor lateinit var listener: ArgumentCaptor @Captor lateinit var configListener: ArgumentCaptor @@ -114,7 +116,8 @@ class MediaCarouselControllerTest : SysuiTestCase() { falsingManager, dumpManager, logger, - debugLogger + debugLogger, + mediaFlags, ) verify(configurationController).addCallback(capture(configListener)) verify(mediaDataManager).addListener(capture(listener)) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt index b35dd266e422..ce22b19b3721 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt @@ -204,6 +204,9 @@ public class MediaControlPanelTest : SysuiTestCase() { @Mock private lateinit var coverContainer1: ViewGroup @Mock private lateinit var coverContainer2: ViewGroup @Mock private lateinit var coverContainer3: ViewGroup + @Mock private lateinit var recAppIconItem: CachingIconView + @Mock private lateinit var recCardTitle: TextView + @Mock private lateinit var coverItem: ImageView private lateinit var coverItem1: ImageView private lateinit var coverItem2: ImageView private lateinit var coverItem3: ImageView @@ -220,6 +223,7 @@ public class MediaControlPanelTest : SysuiTestCase() { this.set(Flags.UMO_TURBULENCE_NOISE, false) this.set(Flags.MEDIA_FALSING_PENALTY, true) this.set(Flags.MEDIA_EXPLICIT_INDICATOR, true) + this.set(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE, false) } @JvmField @Rule val mockito = MockitoJUnit.rule() @@ -2058,6 +2062,51 @@ public class MediaControlPanelTest : SysuiTestCase() { assertThat(expandedSet.getVisibility(recSubtitle3.id)).isEqualTo(ConstraintSet.GONE) } + @Test + fun bindRecommendation_setAfterExecutors() { + fakeFeatureFlag.set(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE, true) + whenever(recommendationViewHolder.mediaAppIcons) + .thenReturn(listOf(recAppIconItem, recAppIconItem, recAppIconItem)) + whenever(recommendationViewHolder.cardTitle).thenReturn(recCardTitle) + whenever(recommendationViewHolder.mediaCoverItems) + .thenReturn(listOf(coverItem, coverItem, coverItem)) + + val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bmp) + canvas.drawColor(Color.RED) + val albumArt = Icon.createWithBitmap(bmp) + val data = + smartspaceData.copy( + recommendations = + listOf( + SmartspaceAction.Builder("id1", "title1") + .setSubtitle("subtitle1") + .setIcon(albumArt) + .setExtras(Bundle.EMPTY) + .build(), + SmartspaceAction.Builder("id2", "title2") + .setSubtitle("subtitle1") + .setIcon(albumArt) + .setExtras(Bundle.EMPTY) + .build(), + SmartspaceAction.Builder("id3", "title3") + .setSubtitle("subtitle1") + .setIcon(albumArt) + .setExtras(Bundle.EMPTY) + .build() + ) + ) + + player.attachRecommendation(recommendationViewHolder) + player.bindRecommendation(data) + bgExecutor.runAllReady() + mainExecutor.runAllReady() + + verify(recCardTitle).setTextColor(any()) + verify(recAppIconItem, times(3)).setImageDrawable(any(Drawable::class.java)) + verify(coverItem, times(3)).setImageDrawable(any(Drawable::class.java)) + } + @Test fun onButtonClick_touchRippleFlagEnabled_playsTouchRipple() { fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, true) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt index 4ed6d7cf6bd0..2f7eac2ad4ae 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaViewControllerTest.kt @@ -22,6 +22,7 @@ import android.view.View import androidx.test.filters.SmallTest import com.android.systemui.R import com.android.systemui.SysuiTestCase +import com.android.systemui.media.controls.util.MediaFlags import com.android.systemui.util.animation.MeasurementInput import com.android.systemui.util.animation.TransitionLayout import com.android.systemui.util.animation.TransitionViewState @@ -55,6 +56,7 @@ class MediaViewControllerTest : SysuiTestCase() { @Mock private lateinit var mediaTitleWidgetState: WidgetState @Mock private lateinit var mediaSubTitleWidgetState: WidgetState @Mock private lateinit var mediaContainerWidgetState: WidgetState + @Mock private lateinit var mediaFlags: MediaFlags val delta = 0.1F @@ -64,7 +66,13 @@ class MediaViewControllerTest : SysuiTestCase() { fun setup() { MockitoAnnotations.initMocks(this) mediaViewController = - MediaViewController(context, configurationController, mediaHostStatesManager, logger) + MediaViewController( + context, + configurationController, + mediaHostStatesManager, + logger, + mediaFlags, + ) } @Test -- cgit v1.2.3-59-g8ed1b