diff --git a/packages/SystemUI/res/layout/media_recommendation_view.xml b/packages/SystemUI/res/layout/media_recommendation_view.xml
index 101fad97beb52..b2aabc77a1dce 100644
--- a/packages/SystemUI/res/layout/media_recommendation_view.xml
+++ b/packages/SystemUI/res/layout/media_recommendation_view.xml
@@ -62,4 +62,24 @@
android:textSize="11sp"
android:gravity="center_vertical"
android:layout_gravity="bottom"/>
+
+
+
\ No newline at end of file
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 8c1ec166fb2eb..70f2dee006edd 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
@@ -20,6 +20,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
+import android.widget.SeekBar
import android.widget.TextView
import com.android.internal.widget.CachingIconView
import com.android.systemui.R
@@ -37,6 +38,7 @@ class RecommendationViewHolder private constructor(itemView: View, updatedView:
// Recommendation screen
lateinit var cardIcon: ImageView
lateinit var mediaAppIcons: List
+ lateinit var mediaProgressBars: List
lateinit var cardTitle: TextView
val mediaCoverContainers =
@@ -82,6 +84,13 @@ class RecommendationViewHolder private constructor(itemView: View, updatedView:
if (updatedView) {
mediaAppIcons = mediaCoverContainers.map { it.requireViewById(R.id.media_rec_app_icon) }
cardTitle = itemView.requireViewById(R.id.media_rec_title)
+ mediaProgressBars =
+ mediaCoverContainers.map {
+ it.requireViewById(R.id.media_progress_bar).apply {
+ // Media playback is in the direction of tape, not time, so it stays LTR
+ layoutDirection = View.LAYOUT_DIRECTION_LTR
+ }
+ }
} else {
cardIcon = itemView.requireViewById(R.id.recommendation_card_icon)
}
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 d26f239e0f1a1..901e2308744f2 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
@@ -56,6 +56,7 @@ import android.view.ViewGroup;
import android.view.animation.Interpolator;
import android.widget.ImageButton;
import android.widget.ImageView;
+import android.widget.SeekBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
@@ -1366,6 +1367,24 @@ public class MediaControlPanel {
hasSubtitle |= !TextUtils.isEmpty(subtitle);
TextView subtitleView = mRecommendationViewHolder.getMediaSubtitles().get(itemIndex);
subtitleView.setText(subtitle);
+
+ // Set up progress bar
+ if (mFeatureFlags.isEnabled(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE)) {
+ SeekBar mediaProgressBar =
+ mRecommendationViewHolder.getMediaProgressBars().get(itemIndex);
+ TextView mediaSubtitle =
+ mRecommendationViewHolder.getMediaSubtitles().get(itemIndex);
+ // show progress bar if the recommended album is played.
+ Double progress = MediaDataUtils.getDescriptionProgress(recommendation.getExtras());
+ if (progress == null || progress <= 0.0) {
+ mediaProgressBar.setVisibility(View.GONE);
+ mediaSubtitle.setVisibility(View.VISIBLE);
+ } else {
+ mediaProgressBar.setProgress((int) (progress * 100));
+ mediaProgressBar.setVisibility(View.VISIBLE);
+ mediaSubtitle.setVisibility(View.GONE);
+ }
+ }
}
mSmartspaceMediaItemsCount = NUM_REQUIRED_RECOMMENDATIONS;
@@ -1440,6 +1459,12 @@ public class MediaControlPanel {
(title) -> title.setTextColor(textPrimaryColor));
mRecommendationViewHolder.getMediaSubtitles().forEach(
(subtitle) -> subtitle.setTextColor(textSecondaryColor));
+ if (mFeatureFlags.isEnabled(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE)) {
+ mRecommendationViewHolder.getMediaProgressBars().forEach(
+ (progressBar) -> progressBar.setProgressTintList(
+ ColorStateList.valueOf(textPrimaryColor))
+ );
+ }
mRecommendationViewHolder.getGutsViewHolder().setColors(colorScheme);
}
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 26b9204f383f0..55a33b6636e0f 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
@@ -52,6 +52,7 @@ import android.widget.TextView
import androidx.constraintlayout.widget.Barrier
import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.LiveData
+import androidx.media.utils.MediaConstants
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.internal.widget.CachingIconView
@@ -206,6 +207,12 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Mock private lateinit var coverContainer3: ViewGroup
@Mock private lateinit var recAppIconItem: CachingIconView
@Mock private lateinit var recCardTitle: TextView
+ @Mock private lateinit var recProgressBar1: SeekBar
+ @Mock private lateinit var recProgressBar2: SeekBar
+ @Mock private lateinit var recProgressBar3: SeekBar
+ @Mock private lateinit var recSubtitleMock1: TextView
+ @Mock private lateinit var recSubtitleMock2: TextView
+ @Mock private lateinit var recSubtitleMock3: TextView
@Mock private lateinit var coverItem: ImageView
private lateinit var coverItem1: ImageView
private lateinit var coverItem2: ImageView
@@ -2081,6 +2088,10 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(recommendationViewHolder.cardTitle).thenReturn(recCardTitle)
whenever(recommendationViewHolder.mediaCoverItems)
.thenReturn(listOf(coverItem, coverItem, coverItem))
+ whenever(recommendationViewHolder.mediaProgressBars)
+ .thenReturn(listOf(recProgressBar1, recProgressBar2, recProgressBar3))
+ whenever(recommendationViewHolder.mediaSubtitles)
+ .thenReturn(listOf(recSubtitleMock1, recSubtitleMock2, recSubtitleMock3))
val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bmp)
@@ -2118,6 +2129,65 @@ public class MediaControlPanelTest : SysuiTestCase() {
verify(coverItem, times(3)).setImageDrawable(any(Drawable::class.java))
}
+ @Test
+ fun bindRecommendationWithProgressBars() {
+ 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))
+ whenever(recommendationViewHolder.mediaProgressBars)
+ .thenReturn(listOf(recProgressBar1, recProgressBar2, recProgressBar3))
+ whenever(recommendationViewHolder.mediaSubtitles)
+ .thenReturn(listOf(recSubtitleMock1, recSubtitleMock2, recSubtitleMock3))
+
+ val bmp = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888)
+ val canvas = Canvas(bmp)
+ canvas.drawColor(Color.RED)
+ val albumArt = Icon.createWithBitmap(bmp)
+ val bundle =
+ Bundle().apply {
+ putInt(
+ MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS,
+ MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED
+ )
+ putDouble(MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.5)
+ }
+ val data =
+ smartspaceData.copy(
+ recommendations =
+ listOf(
+ SmartspaceAction.Builder("id1", "title1")
+ .setSubtitle("subtitle1")
+ .setIcon(albumArt)
+ .setExtras(bundle)
+ .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)
+
+ verify(recProgressBar1).setProgress(50)
+ verify(recProgressBar1).visibility = View.VISIBLE
+ verify(recProgressBar2).visibility = View.GONE
+ verify(recProgressBar3).visibility = View.GONE
+ verify(recSubtitleMock1).visibility = View.GONE
+ verify(recSubtitleMock2).visibility = View.VISIBLE
+ verify(recSubtitleMock3).visibility = View.VISIBLE
+ }
+
@Test
fun onButtonClick_touchRippleFlagEnabled_playsTouchRipple() {
fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, true)