diff options
6 files changed, 258 insertions, 63 deletions
diff --git a/packages/SystemUI/res/layout/media_session_view.xml b/packages/SystemUI/res/layout/media_session_view.xml index 7962e22d6b7f..534c80de73f4 100644 --- a/packages/SystemUI/res/layout/media_session_view.xml +++ b/packages/SystemUI/res/layout/media_session_view.xml @@ -80,7 +80,7 @@ android:background="@drawable/qs_media_light_source" android:forceHasOverlappingRendering="false" android:layout_width="wrap_content" - android:layout_height="48dp" + android:layout_height="@dimen/min_clickable_item_size" android:layout_marginStart="@dimen/qs_center_guideline_padding" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" @@ -92,8 +92,9 @@ <LinearLayout android:id="@+id/media_seamless_button" android:layout_width="wrap_content" - android:layout_height="@dimen/qs_seamless_height" + android:layout_height="wrap_content" android:minHeight="@dimen/qs_seamless_height" + android:maxHeight="@dimen/min_clickable_item_size" android:theme="@style/MediaPlayer.SolidButton" android:background="@drawable/qs_media_seamless_background" android:orientation="horizontal" diff --git a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml index 659a578aa61f..79ba7ead1ec3 100644 --- a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml +++ b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml @@ -16,6 +16,8 @@ --> <!-- Layout for media recommendations inside QSPanel carousel --> +<!-- See media_recommendation_expanded.xml and media_recommendation_collapsed.xml for the + constraints. --> <com.android.systemui.util.animation.TransitionLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" @@ -46,14 +48,6 @@ <FrameLayout android:id="@+id/media_cover1_container" style="@style/MediaPlayer.Recommendation.AlbumContainer" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@+id/media_title1" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toStartOf="@id/media_cover2_container" - android:layout_marginEnd="@dimen/qs_media_rec_album_side_margin" - app:layout_constraintHorizontal_chainStyle="packed" - app:layout_constraintHorizontal_bias="1.0" - app:layout_constraintVertical_bias="0.5" > <ImageView android:id="@+id/media_cover1" @@ -71,31 +65,16 @@ <TextView android:id="@+id/media_title1" style="@style/MediaPlayer.Recommendation.Text.Title" - app:layout_constraintStart_toStartOf="@+id/media_cover1_container" - app:layout_constraintEnd_toEndOf="@+id/media_cover1_container" - app:layout_constraintTop_toBottomOf="@+id/media_cover1_container" - app:layout_constraintBottom_toTopOf="@+id/media_subtitle1" /> <TextView android:id="@+id/media_subtitle1" style="@style/MediaPlayer.Recommendation.Text.Subtitle" - app:layout_constraintStart_toStartOf="@+id/media_cover1_container" - app:layout_constraintEnd_toEndOf="@+id/media_cover1_container" - app:layout_constraintTop_toBottomOf="@+id/media_title1" - app:layout_constraintBottom_toBottomOf="parent" - android:layout_marginBottom="@dimen/qs_media_padding" /> <FrameLayout android:id="@+id/media_cover2_container" style="@style/MediaPlayer.Recommendation.AlbumContainer" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@id/media_title2" - app:layout_constraintStart_toEndOf="@id/media_cover1_container" - app:layout_constraintEnd_toStartOf="@id/media_cover3_container" - android:layout_marginEnd="@dimen/qs_media_rec_album_side_margin" - app:layout_constraintVertical_bias="0.5" > <ImageView android:id="@+id/media_cover2" @@ -111,31 +90,16 @@ <TextView android:id="@+id/media_title2" style="@style/MediaPlayer.Recommendation.Text.Title" - app:layout_constraintStart_toStartOf="@+id/media_cover2_container" - app:layout_constraintEnd_toEndOf="@+id/media_cover2_container" - app:layout_constraintTop_toBottomOf="@+id/media_cover2_container" - app:layout_constraintBottom_toTopOf="@+id/media_subtitle2" /> <TextView android:id="@+id/media_subtitle2" style="@style/MediaPlayer.Recommendation.Text.Subtitle" - app:layout_constraintStart_toStartOf="@+id/media_cover2_container" - app:layout_constraintEnd_toEndOf="@+id/media_cover2_container" - app:layout_constraintTop_toBottomOf="@+id/media_title2" - app:layout_constraintBottom_toBottomOf="parent" - android:layout_marginBottom="@dimen/qs_media_padding" /> <FrameLayout android:id="@+id/media_cover3_container" style="@style/MediaPlayer.Recommendation.AlbumContainer" - app:layout_constraintTop_toTopOf="parent" - app:layout_constraintBottom_toTopOf="@id/media_title3" - app:layout_constraintStart_toEndOf="@id/media_cover2_container" - app:layout_constraintEnd_toEndOf="parent" - android:layout_marginEnd="@dimen/qs_media_padding" - app:layout_constraintVertical_bias="0.5" > <ImageView android:id="@+id/media_cover3" @@ -151,20 +115,11 @@ <TextView android:id="@+id/media_title3" style="@style/MediaPlayer.Recommendation.Text.Title" - app:layout_constraintStart_toStartOf="@+id/media_cover3_container" - app:layout_constraintEnd_toEndOf="@+id/media_cover3_container" - app:layout_constraintTop_toBottomOf="@+id/media_cover3_container" - app:layout_constraintBottom_toTopOf="@+id/media_subtitle3" /> <TextView android:id="@+id/media_subtitle3" style="@style/MediaPlayer.Recommendation.Text.Subtitle" - app:layout_constraintStart_toStartOf="@+id/media_cover3_container" - app:layout_constraintEnd_toEndOf="@+id/media_cover3_container" - app:layout_constraintTop_toBottomOf="@+id/media_title3" - app:layout_constraintBottom_toBottomOf="parent" - android:layout_marginBottom="@dimen/qs_media_padding" /> <include diff --git a/packages/SystemUI/res/xml/media_recommendation_collapsed.xml b/packages/SystemUI/res/xml/media_recommendation_collapsed.xml index a6113473b065..b7d4b3aac079 100644 --- a/packages/SystemUI/res/xml/media_recommendation_collapsed.xml +++ b/packages/SystemUI/res/xml/media_recommendation_collapsed.xml @@ -25,8 +25,10 @@ /> <!-- Only the constraintBottom and marginBottom are different. The rest of the constraints are - the same as the constraints in media_smartspace_recommendations. But due to how - ConstraintSets work, all the constraints need to be in the same place. + the same as the constraints in media_recommendations_expanded.xml. But, due to how + ConstraintSets work, all the constraints need to be in the same place. So, the shared + constraints can't be put in the shared layout file media_smartspace_recommendations.xml and + the constraints are instead duplicated between here and media_recommendations_expanded.xml. Ditto for the other cover containers. --> <Constraint android:id="@+id/media_cover1_container" diff --git a/packages/SystemUI/res/xml/media_recommendation_expanded.xml b/packages/SystemUI/res/xml/media_recommendation_expanded.xml index 09ffebb8b4a9..ce25a7d01bf7 100644 --- a/packages/SystemUI/res/xml/media_recommendation_expanded.xml +++ b/packages/SystemUI/res/xml/media_recommendation_expanded.xml @@ -15,7 +15,9 @@ ~ limitations under the License --> <ConstraintSet - xmlns:android="http://schemas.android.com/apk/res/android" > + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + > <Constraint android:id="@+id/sizing_view" @@ -23,4 +25,99 @@ android:layout_height="@dimen/qs_media_session_height_expanded" /> + <Constraint + android:id="@+id/media_cover1_container" + style="@style/MediaPlayer.Recommendation.AlbumContainer" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toTopOf="@+id/media_title1" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintEnd_toStartOf="@id/media_cover2_container" + android:layout_marginEnd="@dimen/qs_media_rec_album_side_margin" + app:layout_constraintHorizontal_chainStyle="packed" + app:layout_constraintVertical_chainStyle="packed" + app:layout_constraintHorizontal_bias="1.0" + app:layout_constraintVertical_bias="0.4" + /> + + <Constraint + android:id="@+id/media_title1" + style="@style/MediaPlayer.Recommendation.Text.Title" + app:layout_constraintStart_toStartOf="@+id/media_cover1_container" + app:layout_constraintEnd_toEndOf="@+id/media_cover1_container" + app:layout_constraintTop_toBottomOf="@+id/media_cover1_container" + app:layout_constraintBottom_toTopOf="@+id/media_subtitle1" + /> + + <Constraint + android:id="@+id/media_subtitle1" + style="@style/MediaPlayer.Recommendation.Text.Subtitle" + app:layout_constraintStart_toStartOf="@+id/media_cover1_container" + app:layout_constraintEnd_toEndOf="@+id/media_cover1_container" + app:layout_constraintTop_toBottomOf="@+id/media_title1" + app:layout_constraintBottom_toBottomOf="parent" + android:layout_marginBottom="@dimen/qs_media_padding" + /> + + <Constraint + android:id="@+id/media_cover2_container" + style="@style/MediaPlayer.Recommendation.AlbumContainer" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toTopOf="@id/media_title2" + app:layout_constraintStart_toEndOf="@id/media_cover1_container" + app:layout_constraintEnd_toStartOf="@id/media_cover3_container" + android:layout_marginEnd="@dimen/qs_media_rec_album_side_margin" + app:layout_constraintVertical_chainStyle="packed" + app:layout_constraintVertical_bias="0.4" + /> + + <Constraint + android:id="@+id/media_title2" + style="@style/MediaPlayer.Recommendation.Text.Title" + app:layout_constraintStart_toStartOf="@+id/media_cover2_container" + app:layout_constraintEnd_toEndOf="@+id/media_cover2_container" + app:layout_constraintTop_toBottomOf="@+id/media_cover2_container" + app:layout_constraintBottom_toTopOf="@+id/media_subtitle2" + /> + + <Constraint + android:id="@+id/media_subtitle2" + style="@style/MediaPlayer.Recommendation.Text.Subtitle" + app:layout_constraintStart_toStartOf="@+id/media_cover2_container" + app:layout_constraintEnd_toEndOf="@+id/media_cover2_container" + app:layout_constraintTop_toBottomOf="@+id/media_title2" + app:layout_constraintBottom_toBottomOf="parent" + android:layout_marginBottom="@dimen/qs_media_padding" + /> + + <Constraint + android:id="@+id/media_cover3_container" + style="@style/MediaPlayer.Recommendation.AlbumContainer" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintBottom_toTopOf="@id/media_title3" + app:layout_constraintStart_toEndOf="@id/media_cover2_container" + app:layout_constraintEnd_toEndOf="parent" + android:layout_marginEnd="@dimen/qs_media_padding" + app:layout_constraintVertical_chainStyle="packed" + app:layout_constraintVertical_bias="0.4" + /> + + <Constraint + android:id="@+id/media_title3" + style="@style/MediaPlayer.Recommendation.Text.Title" + app:layout_constraintStart_toStartOf="@+id/media_cover3_container" + app:layout_constraintEnd_toEndOf="@+id/media_cover3_container" + app:layout_constraintTop_toBottomOf="@+id/media_cover3_container" + app:layout_constraintBottom_toTopOf="@+id/media_subtitle3" + /> + + <Constraint + android:id="@+id/media_subtitle3" + style="@style/MediaPlayer.Recommendation.Text.Subtitle" + app:layout_constraintStart_toStartOf="@+id/media_cover3_container" + app:layout_constraintEnd_toEndOf="@+id/media_cover3_container" + app:layout_constraintTop_toBottomOf="@+id/media_title3" + app:layout_constraintBottom_toBottomOf="parent" + android:layout_marginBottom="@dimen/qs_media_padding" + /> + </ConstraintSet> diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index af54e966ed9c..d2c35bd96d5a 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -991,6 +991,9 @@ public class MediaControlPanel { List<ViewGroup> mediaCoverContainers = mRecommendationViewHolder.getMediaCoverContainers(); int mediaRecommendationNum = Math.min(mediaRecommendationList.size(), MEDIA_RECOMMENDATION_MAX_NUM); + + boolean hasTitle = false; + boolean hasSubtitle = false; int uiComponentIndex = 0; for (int itemIndex = 0; itemIndex < mediaRecommendationNum && uiComponentIndex < mediaRecommendationNum; @@ -1036,26 +1039,33 @@ public class MediaControlPanel { // Set up title CharSequence title = recommendation.getTitle(); + hasTitle |= !TextUtils.isEmpty(title); TextView titleView = mRecommendationViewHolder.getMediaTitles().get(uiComponentIndex); titleView.setText(title); - // TODO(b/223603970): If none of them have titles, should we then hide the views? // Set up subtitle - CharSequence subtitle = recommendation.getSubtitle(); - TextView subtitleView = - mRecommendationViewHolder.getMediaSubtitles().get(uiComponentIndex); // It would look awkward to show a subtitle if we don't have a title. boolean shouldShowSubtitleText = !TextUtils.isEmpty(title); - CharSequence subtitleText = shouldShowSubtitleText ? subtitle : ""; - subtitleView.setText(subtitleText); - // TODO(b/223603970): If none of them have subtitles, should we then hide the views? + CharSequence subtitle = shouldShowSubtitleText ? recommendation.getSubtitle() : ""; + hasSubtitle |= !TextUtils.isEmpty(subtitle); + TextView subtitleView = + mRecommendationViewHolder.getMediaSubtitles().get(uiComponentIndex); + subtitleView.setText(subtitle); uiComponentIndex++; } - mSmartspaceMediaItemsCount = uiComponentIndex; + // If there's no subtitles and/or titles for any of the albums, hide those views. + ConstraintSet expandedSet = mMediaViewController.getExpandedLayout(); + final boolean titlesVisible = hasTitle; + final boolean subtitlesVisible = hasSubtitle; + mRecommendationViewHolder.getMediaTitles().forEach((titleView) -> + setVisibleAndAlpha(expandedSet, titleView.getId(), titlesVisible)); + mRecommendationViewHolder.getMediaSubtitles().forEach((subtitleView) -> + setVisibleAndAlpha(expandedSet, subtitleView.getId(), subtitlesVisible)); + // Guts Runnable onDismissClickedRunnable = () -> { closeGuts(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt index 83fb82c1c493..6a9c3e349522 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt @@ -1401,22 +1401,23 @@ public class MediaControlPanelTest : SysuiTestCase() { val subtitle1 = "Subtitle1" val subtitle2 = "Subtitle2" val subtitle3 = "Subtitle3" + val icon = Icon.createWithResource(context, R.drawable.ic_1x_mobiledata) val data = smartspaceData.copy( recommendations = listOf( SmartspaceAction.Builder("id1", title1) .setSubtitle(subtitle1) - .setIcon(Icon.createWithResource(context, R.drawable.ic_1x_mobiledata)) + .setIcon(icon) .setExtras(Bundle.EMPTY) .build(), SmartspaceAction.Builder("id2", title2) .setSubtitle(subtitle2) - .setIcon(Icon.createWithResource(context, R.drawable.ic_alarm)) + .setIcon(icon) .setExtras(Bundle.EMPTY) .build(), SmartspaceAction.Builder("id3", title3) .setSubtitle(subtitle3) - .setIcon(Icon.createWithResource(context, R.drawable.ic_3g_mobiledata)) + .setIcon(icon) .setExtras(Bundle.EMPTY) .build() ) @@ -1449,6 +1450,135 @@ public class MediaControlPanelTest : SysuiTestCase() { assertThat(recSubtitle1.text).isEqualTo("") } + @Test + fun bindRecommendation_someHaveTitles_allTitleViewsShown() { + useRealConstraintSets() + player.attachRecommendation(recommendationViewHolder) + + val icon = Icon.createWithResource(context, R.drawable.ic_1x_mobiledata) + val data = smartspaceData.copy( + recommendations = listOf( + SmartspaceAction.Builder("id1", "") + .setSubtitle("fake subtitle") + .setIcon(icon) + .setExtras(Bundle.EMPTY) + .build(), + SmartspaceAction.Builder("id2", "title2") + .setSubtitle("fake subtitle") + .setIcon(icon) + .setExtras(Bundle.EMPTY) + .build(), + SmartspaceAction.Builder("id3", "") + .setSubtitle("fake subtitle") + .setIcon(icon) + .setExtras(Bundle.EMPTY) + .build() + ) + ) + player.bindRecommendation(data) + + assertThat(expandedSet.getVisibility(recTitle1.id)).isEqualTo(ConstraintSet.VISIBLE) + assertThat(expandedSet.getVisibility(recTitle2.id)).isEqualTo(ConstraintSet.VISIBLE) + assertThat(expandedSet.getVisibility(recTitle3.id)).isEqualTo(ConstraintSet.VISIBLE) + } + + @Test + fun bindRecommendation_someHaveSubtitles_allSubtitleViewsShown() { + useRealConstraintSets() + player.attachRecommendation(recommendationViewHolder) + + val icon = Icon.createWithResource(context, R.drawable.ic_1x_mobiledata) + val data = smartspaceData.copy( + recommendations = listOf( + SmartspaceAction.Builder("id1", "") + .setSubtitle("") + .setIcon(icon) + .setExtras(Bundle.EMPTY) + .build(), + SmartspaceAction.Builder("id2", "title2") + .setSubtitle("") + .setIcon(icon) + .setExtras(Bundle.EMPTY) + .build(), + SmartspaceAction.Builder("id3", "title3") + .setSubtitle("subtitle3") + .setIcon(icon) + .setExtras(Bundle.EMPTY) + .build() + ) + ) + player.bindRecommendation(data) + + assertThat(expandedSet.getVisibility(recSubtitle1.id)).isEqualTo(ConstraintSet.VISIBLE) + assertThat(expandedSet.getVisibility(recSubtitle2.id)).isEqualTo(ConstraintSet.VISIBLE) + assertThat(expandedSet.getVisibility(recSubtitle3.id)).isEqualTo(ConstraintSet.VISIBLE) + } + + @Test + fun bindRecommendation_noneHaveSubtitles_subtitleViewsGone() { + useRealConstraintSets() + player.attachRecommendation(recommendationViewHolder) + val data = smartspaceData.copy( + recommendations = listOf( + SmartspaceAction.Builder("id1", "title1") + .setSubtitle("") + .setIcon(Icon.createWithResource(context, R.drawable.ic_1x_mobiledata)) + .setExtras(Bundle.EMPTY) + .build(), + SmartspaceAction.Builder("id2", "title2") + .setSubtitle("") + .setIcon(Icon.createWithResource(context, R.drawable.ic_alarm)) + .setExtras(Bundle.EMPTY) + .build(), + SmartspaceAction.Builder("id3", "title3") + .setSubtitle("") + .setIcon(Icon.createWithResource(context, R.drawable.ic_3g_mobiledata)) + .setExtras(Bundle.EMPTY) + .build() + ) + ) + + player.bindRecommendation(data) + + assertThat(expandedSet.getVisibility(recSubtitle1.id)).isEqualTo(ConstraintSet.GONE) + assertThat(expandedSet.getVisibility(recSubtitle2.id)).isEqualTo(ConstraintSet.GONE) + assertThat(expandedSet.getVisibility(recSubtitle3.id)).isEqualTo(ConstraintSet.GONE) + } + + @Test + fun bindRecommendation_noneHaveTitles_titleAndSubtitleViewsGone() { + useRealConstraintSets() + player.attachRecommendation(recommendationViewHolder) + val data = smartspaceData.copy( + recommendations = listOf( + SmartspaceAction.Builder("id1", "") + .setSubtitle("subtitle1") + .setIcon(Icon.createWithResource(context, R.drawable.ic_1x_mobiledata)) + .setExtras(Bundle.EMPTY) + .build(), + SmartspaceAction.Builder("id2", "") + .setSubtitle("subtitle2") + .setIcon(Icon.createWithResource(context, R.drawable.ic_alarm)) + .setExtras(Bundle.EMPTY) + .build(), + SmartspaceAction.Builder("id3", "") + .setSubtitle("subtitle3") + .setIcon(Icon.createWithResource(context, R.drawable.ic_3g_mobiledata)) + .setExtras(Bundle.EMPTY) + .build() + ) + ) + + player.bindRecommendation(data) + + assertThat(expandedSet.getVisibility(recTitle1.id)).isEqualTo(ConstraintSet.GONE) + assertThat(expandedSet.getVisibility(recTitle2.id)).isEqualTo(ConstraintSet.GONE) + assertThat(expandedSet.getVisibility(recTitle3.id)).isEqualTo(ConstraintSet.GONE) + assertThat(expandedSet.getVisibility(recSubtitle1.id)).isEqualTo(ConstraintSet.GONE) + assertThat(expandedSet.getVisibility(recSubtitle2.id)).isEqualTo(ConstraintSet.GONE) + assertThat(expandedSet.getVisibility(recSubtitle3.id)).isEqualTo(ConstraintSet.GONE) + } + private fun getScrubbingChangeListener(): SeekBarViewModel.ScrubbingChangeListener = withArgCaptor { verify(seekBarViewModel).setScrubbingChangeListener(capture()) } |