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)