[conflict] [conflict] Merge "Add placeholder when media control title is blank" into rvc-dev am: 98e02fa86e am: f97d449d47
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23717227 Change-Id: I79635bb40b66edbe898afe856e2aa375da166e23 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> Merged-In: Ie406c180af48653595e8e222a15b4dda27de2e0e Merged-In: I1cb6010f19623bd7d5e5bbb5d829b9e4936894b8
This commit is contained in:
@@ -2837,6 +2837,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>
|
<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]-->
|
<!-- 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>
|
<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>
|
||||||
|
|
||||||
<!-- Error message indicating that a control timed out while waiting for an update [CHAR_LIMIT=30] -->
|
<!-- Error message indicating that a control timed out while waiting for an update [CHAR_LIMIT=30] -->
|
||||||
<string name="controls_error_timeout">Inactive, check app</string>
|
<string name="controls_error_timeout">Inactive, check app</string>
|
||||||
|
|||||||
@@ -563,12 +563,16 @@ class MediaDataManager(
|
|||||||
|
|
||||||
// Song name
|
// Song name
|
||||||
var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE)
|
var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE)
|
||||||
if (song == null) {
|
if (song.isNullOrBlank()) {
|
||||||
song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE)
|
song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE)
|
||||||
}
|
}
|
||||||
if (song == null) {
|
if (song.isNullOrBlank()) {
|
||||||
song = HybridGroupManager.resolveTitle(notif)
|
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
|
// Artist name
|
||||||
var artist: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_ARTIST)
|
var artist: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_ARTIST)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import android.service.notification.StatusBarNotification
|
|||||||
import android.testing.AndroidTestingRunner
|
import android.testing.AndroidTestingRunner
|
||||||
import android.testing.TestableLooper.RunWithLooper
|
import android.testing.TestableLooper.RunWithLooper
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
|
import com.android.systemui.R
|
||||||
import com.android.systemui.SysuiTestCase
|
import com.android.systemui.SysuiTestCase
|
||||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||||
import com.android.systemui.dump.DumpManager
|
import com.android.systemui.dump.DumpManager
|
||||||
@@ -47,9 +48,11 @@ private const val KEY = "KEY"
|
|||||||
private const val KEY_2 = "KEY_2"
|
private const val KEY_2 = "KEY_2"
|
||||||
private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID"
|
private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID"
|
||||||
private const val PACKAGE_NAME = "com.android.systemui"
|
private const val 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_ARTIST = "artist"
|
||||||
private const val SESSION_TITLE = "title"
|
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 const val USER_ID = 0
|
||||||
|
|
||||||
private fun <T> anyObject(): T {
|
private fun <T> anyObject(): T {
|
||||||
@@ -210,6 +213,95 @@ class MediaDataManagerTest : SysuiTestCase() {
|
|||||||
verify(listener).onMediaDataRemoved(eq(KEY))
|
verify(listener).onMediaDataRemoved(eq(KEY))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testOnNotificationAdded_emptyTitle_hasPlaceholder() {
|
||||||
|
// When the manager has a notification with an empty title
|
||||||
|
val listener = mock(MediaDataManager.Listener::class.java)
|
||||||
|
mediaDataManager.addListener(listener)
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
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
|
||||||
|
val listener = mock(MediaDataManager.Listener::class.java)
|
||||||
|
mediaDataManager.addListener(listener)
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
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
|
||||||
|
val listener = mock(MediaDataManager.Listener::class.java)
|
||||||
|
mediaDataManager.addListener(listener)
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
assertThat(mediaDataCaptor.value.song).isEqualTo(SESSION_TITLE)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testOnNotificationRemoved_withResumption() {
|
fun testOnNotificationRemoved_withResumption() {
|
||||||
// GIVEN that the manager has a notification with a resume action
|
// GIVEN that the manager has a notification with a resume action
|
||||||
|
|||||||
Reference in New Issue
Block a user