diff options
author | Beth Thibodeau <ethibodeau@google.com> | 2023-05-30 18:45:47 -0500 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-08-10 17:10:15 +0000 |
commit | d26544e5a4fd554b790b4d0c5964d9e95d9e626b (patch) | |
tree | f783afd38e1e95b034041806a96ae7f9148b8d68 | |
parent | 88cf23cfe50b80aa9d65cc22946de1765972cb80 (diff) | |
download | base-d26544e5a4fd554b790b4d0c5964d9e95d9e626b.tar.gz |
Add placeholder when media control title is blank
When an app posts a media control with no available title, show a
placeholder string with the app name instead
Bug: 274775190
Test: atest MediaDataManagerTest
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:a0fda1f36d04331c8d60c5540b09b1a30203581b)
Merged-In: Ie406c180af48653595e8e222a15b4dda27de2e0e
Change-Id: Ie406c180af48653595e8e222a15b4dda27de2e0e
3 files changed, 103 insertions, 3 deletions
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index af8d7ed22ed3..b0fcfcdc2f6b 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2230,6 +2230,8 @@ <string name="controls_media_smartspace_rec_item_description">Play <xliff:g id="song_name" example="Daily mix">%1$s</xliff:g> by <xliff:g id="artist_name" example="Various artists">%2$s</xliff:g> from <xliff:g id="app_label" example="Spotify">%3$s</xliff:g></string> <!-- Description for Smartspace recommendation's media item which doesn't have artist info, including information for the media's title and the source app [CHAR LIMIT=NONE]--> <string name="controls_media_smartspace_rec_item_no_artist_description">Play <xliff:g id="song_name" example="Daily mix">%1$s</xliff:g> from <xliff:g id="app_label" example="Spotify">%2$s</xliff:g></string> + <!-- Placeholder title to inform user that an app has posted media controls [CHAR_LIMIT=NONE] --> + <string name="controls_media_empty_title"><xliff:g id="app_name" example="Foo Music App">%1$s</xliff:g> is running</string> <!--- ****** Media tap-to-transfer ****** --> <!-- Text for a button to undo the media transfer. [CHAR LIMIT=20] --> diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 6a69d427929e..4c2336eeb22c 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -658,12 +658,16 @@ class MediaDataManager( // Song name var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE) - if (song == null) { + if (song.isNullOrBlank()) { song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE) } - if (song == null) { + if (song.isNullOrBlank()) { song = HybridGroupManager.resolveTitle(notif) } + if (song.isNullOrBlank()) { + // For apps that don't include a title, add a placeholder + song = context.getString(R.string.controls_media_empty_title, app) + } // Artist name var artist: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_ARTIST) diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt index 1cce7cfb5b8a..52266f983fdd 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt @@ -61,9 +61,11 @@ private const val KEY_2 = "KEY_2" private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID" private const val PACKAGE_NAME = "com.example.app" private const val SYSTEM_PACKAGE_NAME = "com.android.systemui" -private const val APP_NAME = "SystemUI" +private const val APP_NAME = "com.android.systemui.tests" private const val SESSION_ARTIST = "artist" private const val SESSION_TITLE = "title" +private const val SESSION_BLANK_TITLE = " " +private const val SESSION_EMPTY_TITLE = "" private const val USER_ID = 0 private val DISMISS_INTENT = Intent().apply { action = "dismiss" } @@ -339,6 +341,98 @@ class MediaDataManagerTest : SysuiTestCase() { } @Test + fun testOnNotificationAdded_emptyTitle_hasPlaceholder() { + // When the manager has a notification with an empty title + whenever(controller.metadata) + .thenReturn( + metadataBuilder + .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_EMPTY_TITLE) + .build() + ) + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + + // Then a media control is created with a placeholder title string + assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) + assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) + verify(listener) + .onMediaDataLoaded( + eq(KEY), + eq(null), + capture(mediaDataCaptor), + eq(true), + eq(0), + eq(false) + ) + val placeholderTitle = context.getString(R.string.controls_media_empty_title, APP_NAME) + assertThat(mediaDataCaptor.value.song).isEqualTo(placeholderTitle) + } + + @Test + fun testOnNotificationAdded_blankTitle_hasPlaceholder() { + // GIVEN that the manager has a notification with a blank title + whenever(controller.metadata) + .thenReturn( + metadataBuilder + .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_BLANK_TITLE) + .build() + ) + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + + // Then a media control is created with a placeholder title string + assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) + assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) + verify(listener) + .onMediaDataLoaded( + eq(KEY), + eq(null), + capture(mediaDataCaptor), + eq(true), + eq(0), + eq(false) + ) + val placeholderTitle = context.getString(R.string.controls_media_empty_title, APP_NAME) + assertThat(mediaDataCaptor.value.song).isEqualTo(placeholderTitle) + } + + @Test + fun testOnNotificationAdded_emptyMetadata_usesNotificationTitle() { + // When the app sets the metadata title fields to empty strings, but does include a + // non-blank notification title + whenever(controller.metadata) + .thenReturn( + metadataBuilder + .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_EMPTY_TITLE) + .putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE, SESSION_EMPTY_TITLE) + .build() + ) + mediaNotification = + SbnBuilder().run { + setPkg(PACKAGE_NAME) + modifyNotification(context).also { + it.setSmallIcon(android.R.drawable.ic_media_pause) + it.setContentTitle(SESSION_TITLE) + it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) }) + } + build() + } + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + + // Then the media control is added using the notification's title + assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) + assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) + verify(listener) + .onMediaDataLoaded( + eq(KEY), + eq(null), + capture(mediaDataCaptor), + eq(true), + eq(0), + eq(false) + ) + assertThat(mediaDataCaptor.value.song).isEqualTo(SESSION_TITLE) + } + + @Test fun testOnNotificationRemoved_withResumption() { // GIVEN that the manager has a notification with a resume action whenever(controller.metadata).thenReturn(metadataBuilder.build()) |