Merge "Always show media recommendation on headphones connection." into sc-dev

This commit is contained in:
Cecilia Hong
2021-05-18 14:45:19 +00:00
committed by Android (Google) Code Review
9 changed files with 140 additions and 52 deletions

View File

@@ -208,9 +208,13 @@ class MediaCarouselController @Inject constructor(
} }
} }
override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) { override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceTarget,
shouldPrioritize: Boolean
) {
Log.d(TAG, "My Smartspace media update is here") Log.d(TAG, "My Smartspace media update is here")
addSmartspaceMediaRecommendations(key, data) addSmartspaceMediaRecommendations(key, data, shouldPrioritize)
MediaPlayerData.getMediaPlayer(key, null)?.let { MediaPlayerData.getMediaPlayer(key, null)?.let {
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
it.mInstanceId, it.mInstanceId,
@@ -327,7 +331,11 @@ class MediaCarouselController @Inject constructor(
return existingPlayer == null return existingPlayer == null
} }
private fun addSmartspaceMediaRecommendations(key: String, data: SmartspaceTarget) { private fun addSmartspaceMediaRecommendations(
key: String,
data: SmartspaceTarget,
shouldPrioritize: Boolean
) {
Log.d(TAG, "Updating smartspace target in carousel") Log.d(TAG, "Updating smartspace target in carousel")
if (MediaPlayerData.getMediaPlayer(key, null) != null) { if (MediaPlayerData.getMediaPlayer(key, null) != null) {
Log.w(TAG, "Skip adding smartspace target in carousel") Log.w(TAG, "Skip adding smartspace target in carousel")
@@ -342,7 +350,7 @@ class MediaCarouselController @Inject constructor(
ViewGroup.LayoutParams.WRAP_CONTENT) ViewGroup.LayoutParams.WRAP_CONTENT)
newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp) newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp)
newRecs.bindRecommendation(data, bgColor) newRecs.bindRecommendation(data, bgColor)
MediaPlayerData.addMediaRecommendation(key, newRecs) MediaPlayerData.addMediaRecommendation(key, newRecs, shouldPrioritize)
updatePlayerToState(newRecs, noAnimation = true) updatePlayerToState(newRecs, noAnimation = true)
reorderAllPlayers() reorderAllPlayers()
updatePageIndicator() updatePageIndicator()
@@ -671,17 +679,19 @@ class MediaCarouselController @Inject constructor(
internal object MediaPlayerData { internal object MediaPlayerData {
private val EMPTY = MediaData(-1, false, 0, null, null, null, null, null, private val EMPTY = MediaData(-1, false, 0, null, null, null, null, null,
emptyList(), emptyList(), "INVALID", null, null, null, true, null) emptyList(), emptyList(), "INVALID", null, null, null, true, null)
// Whether should prioritize Smartspace card.
private var shouldPrioritizeSs: Boolean = false
data class MediaSortKey( data class MediaSortKey(
// Is Smartspace media recommendation. When the Smartspace media is present, it should // Whether the item represents a Smartspace media recommendation.
// always be the first card in carousel.
val isSsMediaRec: Boolean, val isSsMediaRec: Boolean,
val data: MediaData, val data: MediaData,
val updateTime: Long = 0 val updateTime: Long = 0
) )
private val comparator = private val comparator =
compareByDescending<MediaSortKey> { it.isSsMediaRec } compareByDescending<MediaSortKey>
{ if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec }
.thenByDescending { it.data.isPlaying } .thenByDescending { it.data.isPlaying }
.thenByDescending { it.data.isLocalSession } .thenByDescending { it.data.isLocalSession }
.thenByDescending { !it.data.resumption } .thenByDescending { !it.data.resumption }
@@ -697,7 +707,8 @@ internal object MediaPlayerData {
mediaPlayers.put(sortKey, player) mediaPlayers.put(sortKey, player)
} }
fun addMediaRecommendation(key: String, player: MediaControlPanel) { fun addMediaRecommendation(key: String, player: MediaControlPanel, shouldPrioritize: Boolean) {
shouldPrioritizeSs = shouldPrioritize
removeMediaPlayer(key) removeMediaPlayer(key)
val sortKey = MediaSortKey(isSsMediaRec = true, EMPTY, System.currentTimeMillis()) val sortKey = MediaSortKey(isSsMediaRec = true, EMPTY, System.currentTimeMillis())
mediaData.put(key, sortKey) mediaData.put(key, sortKey)

View File

@@ -38,7 +38,11 @@ class MediaDataCombineLatest @Inject constructor() : MediaDataManager.Listener,
} }
} }
override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) { override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceTarget,
shouldPrioritize: Boolean
) {
listeners.toSet().forEach { it.onSmartspaceMediaDataLoaded(key, data) } listeners.toSet().forEach { it.onSmartspaceMediaDataLoaded(key, data) }
} }

View File

@@ -26,9 +26,11 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.CurrentUserTracker import com.android.systemui.settings.CurrentUserTracker
import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.NotificationLockscreenUserManager
import com.android.systemui.util.time.SystemClock import com.android.systemui.util.time.SystemClock
import java.util.SortedMap
import java.util.concurrent.Executor import java.util.concurrent.Executor
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
import kotlin.collections.LinkedHashMap
private const val TAG = "MediaDataFilter" private const val TAG = "MediaDataFilter"
private const val DEBUG = true private const val DEBUG = true
@@ -39,7 +41,7 @@ private const val DEBUG = true
*/ */
@VisibleForTesting @VisibleForTesting
internal val SMARTSPACE_MAX_AGE = SystemProperties internal val SMARTSPACE_MAX_AGE = SystemProperties
.getLong("debug.sysui.smartspace_max_age", TimeUnit.HOURS.toMillis(3)) .getLong("debug.sysui.smartspace_max_age", TimeUnit.MINUTES.toMillis(30))
/** /**
* Filters data updates from [MediaDataCombineLatest] based on the current user ID, and handles user * Filters data updates from [MediaDataCombineLatest] based on the current user ID, and handles user
@@ -65,7 +67,8 @@ class MediaDataFilter @Inject constructor(
private val allEntries: LinkedHashMap<String, MediaData> = LinkedHashMap() private val allEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
// The filtered userEntries, which will be a subset of all userEntries in MediaDataManager // The filtered userEntries, which will be a subset of all userEntries in MediaDataManager
private val userEntries: LinkedHashMap<String, MediaData> = LinkedHashMap() private val userEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
private var hasSmartspace: Boolean = false var hasSmartspace: Boolean = false
private set
private var reactivatedKey: String? = null private var reactivatedKey: String? = null
init { init {
@@ -99,20 +102,21 @@ class MediaDataFilter @Inject constructor(
} }
} }
override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) { override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceTarget,
shouldPrioritize: Boolean
) {
var shouldPrioritizeMutable = shouldPrioritize
hasSmartspace = true hasSmartspace = true
// Before forwarding the smartspace target, first check if we have recently inactive media // Before forwarding the smartspace target, first check if we have recently inactive media
val now = systemClock.elapsedRealtime()
val sorted = userEntries.toSortedMap(compareBy { val sorted = userEntries.toSortedMap(compareBy {
userEntries.get(it)?.lastActive ?: -1 userEntries.get(it)?.lastActive ?: -1
}) })
if (sorted.size > 0) { val timeSinceActive = timeSinceActiveForMostRecentMedia(sorted)
val lastActiveKey = sorted.lastKey() // most recently active
val timeSinceActive = sorted.get(lastActiveKey)?.let {
now - it.lastActive
} ?: Long.MAX_VALUE
if (timeSinceActive < SMARTSPACE_MAX_AGE) { if (timeSinceActive < SMARTSPACE_MAX_AGE) {
val lastActiveKey = sorted.lastKey() // most recently active
// Notify listeners to consider this media active // Notify listeners to consider this media active
Log.d(TAG, "reactivating $lastActiveKey instead of smartspace") Log.d(TAG, "reactivating $lastActiveKey instead of smartspace")
reactivatedKey = lastActiveKey reactivatedKey = lastActiveKey
@@ -120,18 +124,17 @@ class MediaDataFilter @Inject constructor(
listeners.forEach { listeners.forEach {
it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData) it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData)
} }
return } else {
} // Mark to prioritize Smartspace card if no recent media.
shouldPrioritizeMutable = true
} }
// If no recent media, continue with smartspace update // Only proceed with the Smartspace update if the recommendation is not empty.
if (isMediaRecommendationEmpty(data)) { if (isMediaRecommendationEmpty(data)) {
Log.d(TAG, "Empty media recommendations. Skip showing the card") Log.d(TAG, "Empty media recommendations. Skip showing the card")
return return
} }
listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data, shouldPrioritizeMutable) }
// Proceed only if the Smartspace recommendation is not empty.
listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data) }
} }
override fun onMediaDataRemoved(key: String) { override fun onMediaDataRemoved(key: String) {
@@ -158,7 +161,6 @@ class MediaDataFilter @Inject constructor(
it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData) it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData)
} }
} }
return
} }
listeners.forEach { it.onSmartspaceMediaDataRemoved(key) } listeners.forEach { it.onSmartspaceMediaDataRemoved(key) }
@@ -230,4 +232,26 @@ class MediaDataFilter @Inject constructor(
val mediaRecommendationList: List<SmartspaceAction> = data.getIconGrid() val mediaRecommendationList: List<SmartspaceAction> = data.getIconGrid()
return mediaRecommendationList == null || mediaRecommendationList.isEmpty() return mediaRecommendationList == null || mediaRecommendationList.isEmpty()
} }
/**
* Return the time since last active for the most-recent media.
*
* @param sortedEntries userEntries sorted from the earliest to the most-recent.
*
* @return The duration in milliseconds from the most-recent media's last active timestamp to
* the present. MAX_VALUE will be returned if there is no media.
*/
private fun timeSinceActiveForMostRecentMedia(
sortedEntries: SortedMap<String, MediaData>
): Long {
if (sortedEntries.isEmpty()) {
return Long.MAX_VALUE
}
val now = systemClock.elapsedRealtime()
val lastActiveKey = sortedEntries.lastKey() // most recently active
return sortedEntries.get(lastActiveKey)?.let {
now - it.lastActive
} ?: Long.MAX_VALUE
}
} }

View File

@@ -817,8 +817,17 @@ class MediaDataManager(
*/ */
fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {} fun onMediaDataLoaded(key: String, oldKey: String?, data: MediaData) {}
/** Called whenever there's new Smartspace media data loaded. */ /**
fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) {} * Called whenever there's new Smartspace media data loaded.
*
* shouldPrioritize indicates the sorting priority of the Smartspace card. If true, it will
* be prioritized as the first card. Otherwise, it will show up as the last card as default.
*/
fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceTarget,
shouldPrioritize: Boolean = false
) {}
/** /**
* Called whenever a previously existing Media notification was removed * Called whenever a previously existing Media notification was removed

View File

@@ -56,7 +56,11 @@ class MediaHost constructor(
updateViewVisibility() updateViewVisibility()
} }
override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) { override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceTarget,
shouldPrioritize: Boolean
) {
updateViewVisibility() updateViewVisibility()
} }

View File

@@ -135,7 +135,11 @@ class MediaSessionBasedFilter @Inject constructor(
} }
} }
override fun onSmartspaceMediaDataLoaded(key: String, data: SmartspaceTarget) { override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceTarget,
shouldPrioritize: Boolean
) {
backgroundExecutor.execute { backgroundExecutor.execute {
dispatchSmartspaceMediaDataLoaded(key, data) dispatchSmartspaceMediaDataLoaded(key, data)
} }

View File

@@ -250,7 +250,8 @@ public class NotificationMediaManager implements Dumpable {
@Override @Override
public void onSmartspaceMediaDataLoaded(@NonNull String key, public void onSmartspaceMediaDataLoaded(@NonNull String key,
@NonNull SmartspaceTarget data) { @NonNull SmartspaceTarget data, boolean shouldPrioritize) {
} }
@Override @Override
@@ -323,7 +324,8 @@ public class NotificationMediaManager implements Dumpable {
@Override @Override
public void onSmartspaceMediaDataLoaded(@NonNull String key, public void onSmartspaceMediaDataLoaded(@NonNull String key,
@NonNull SmartspaceTarget data) { @NonNull SmartspaceTarget data, boolean shouldPrioritize) {
} }
@Override @Override

View File

@@ -30,6 +30,7 @@ import com.google.common.truth.Truth.assertThat
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito import org.mockito.Mockito
@@ -228,37 +229,39 @@ class MediaDataFilterTest : SysuiTestCase() {
} }
@Test @Test
fun testOnSmartspaceMediaDataLoaded_noMedia_nonEmptyRecommendation_usesSmartspace() { fun testOnSmartspaceMediaDataLoaded_noMedia_nonEmptyRec_prioritizesSmartspace() {
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
verify(listener).onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData)) verify(listener)
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true))
assertThat(mediaDataFilter.hasActiveMedia()).isTrue() assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
} }
@Test @Test
fun testOnSmartspaceMediaDataLoaded_noMedia_emptyRecommendation_showsNothing() { fun testOnSmartspaceMediaDataLoaded_noMedia_emptyRec_showsNothing() {
`when`(smartspaceData.iconGrid).thenReturn(listOf()) `when`(smartspaceData.iconGrid).thenReturn(listOf())
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
verify(listener, never()) verify(listener, never())
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData)) .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), anyBoolean())
assertThat(mediaDataFilter.hasActiveMedia()).isTrue() assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
} }
@Test @Test
fun testOnSmartspaceMediaDataLoaded_noRecentMedia_nonEmptyRecommendation_usesSmartspace() { fun testOnSmartspaceMediaDataLoaded_noRecentMedia_nonEmptyRec_prioritizesSmartspace() {
val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld) mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld)
clock.advanceTime(SMARTSPACE_MAX_AGE + 100) clock.advanceTime(SMARTSPACE_MAX_AGE + 100)
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
verify(listener).onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData)) verify(listener)
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true))
assertThat(mediaDataFilter.hasActiveMedia()).isTrue() assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
} }
@Test @Test
fun testOnSmartspaceMediaDataLoaded_noRecentMedia_emptyRecommendation_showsNothing() { fun testOnSmartspaceMediaDataLoaded_noRecentMedia_emptyRec_showsNothing() {
`when`(smartspaceData.iconGrid).thenReturn(listOf()) `when`(smartspaceData.iconGrid).thenReturn(listOf())
val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
@@ -267,12 +270,14 @@ class MediaDataFilterTest : SysuiTestCase() {
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
verify(listener, never()) verify(listener, never())
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData)) .onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), anyBoolean())
assertThat(mediaDataFilter.hasActiveMedia()).isTrue() assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
} }
@Test @Test
fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_usesMedia() { fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_emptyRec_usesMedia() {
`when`(smartspaceData.iconGrid).thenReturn(listOf())
// WHEN we have media that was recently played, but not currently active // WHEN we have media that was recently played, but not currently active
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
@@ -285,19 +290,41 @@ class MediaDataFilterTest : SysuiTestCase() {
val dataCurrentAndActive = dataCurrent.copy(active = true) val dataCurrentAndActive = dataCurrent.copy(active = true)
verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive)) verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive))
assertThat(mediaDataFilter.hasActiveMedia()).isTrue() assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
// Smartspace update shouldn't be propagated for the empty rec list.
verify(listener, never())
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), anyBoolean())
} }
@Test @Test
fun testOnSmartspaceMediaDataRemoved_usedSmartspace_clearsMedia() { fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_nonEmptyRec_usesBoth() {
// WHEN we have media that was recently played, but not currently active
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent))
// AND we get a smartspace signal
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
// THEN we should tell listeners to treat the media as active instead
val dataCurrentAndActive = dataCurrent.copy(active = true)
verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive))
assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
// Smartspace update should also be propagated but not prioritized.
verify(listener)
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
}
@Test
fun testOnSmartspaceMediaDataRemoved_usedSmartspace_clearsSmartspace() {
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
assertThat(mediaDataFilter.hasActiveMedia()).isFalse() assertThat(mediaDataFilter.hasSmartspace).isFalse()
} }
@Test @Test
fun testOnSmartspaceMediaDataRemoved_usedMedia_clearsMedia() { fun testOnSmartspaceMediaDataRemoved_usedMediaAndSmartspace_clearsBoth() {
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime()) val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent) mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
@@ -305,6 +332,8 @@ class MediaDataFilterTest : SysuiTestCase() {
mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrent)) verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrent))
verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
assertThat(mediaDataFilter.hasActiveMedia()).isFalse() assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
assertThat(mediaDataFilter.hasSmartspace).isFalse()
} }
} }

View File

@@ -28,6 +28,7 @@ import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.Captor import org.mockito.Captor
import org.mockito.Mock import org.mockito.Mock
import org.mockito.Mockito import org.mockito.Mockito
@@ -41,7 +42,6 @@ import org.mockito.Mockito.`when` as whenever
private const val KEY = "KEY" 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 KEY_NONE_MEDIA_SMARTSPACE = "NONE_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 = "SystemUI"
private const val SESSION_ARTIST = "artist" private const val SESSION_ARTIST = "artist"
@@ -364,13 +364,14 @@ class MediaDataManagerTest : SysuiTestCase() {
fun testOnSmartspaceMediaDataLoaded_hasNewMediaTarget_callsListener() { fun testOnSmartspaceMediaDataLoaded_hasNewMediaTarget_callsListener() {
smartspaceMediaDataProvider.onTargetsAvailable(listOf(mediaSmartspaceTarget)) smartspaceMediaDataProvider.onTargetsAvailable(listOf(mediaSmartspaceTarget))
verify(listener).onSmartspaceMediaDataLoaded( verify(listener).onSmartspaceMediaDataLoaded(
eq(KEY_MEDIA_SMARTSPACE), eq(mediaSmartspaceTarget)) eq(KEY_MEDIA_SMARTSPACE), eq(mediaSmartspaceTarget), eq(false))
} }
@Test @Test
fun testOnSmartspaceMediaDataLoaded_hasNoneMediaTarget_notCallsListener() { fun testOnSmartspaceMediaDataLoaded_hasNoneMediaTarget_notCallsListener() {
smartspaceMediaDataProvider.onTargetsAvailable(listOf()) smartspaceMediaDataProvider.onTargetsAvailable(listOf())
verify(listener, never()).onSmartspaceMediaDataLoaded(anyObject(), anyObject()) verify(listener, never())
.onSmartspaceMediaDataLoaded(anyObject(), anyObject(), anyBoolean())
} }
@Test @Test