Merge "Always show media recommendation on headphones connection." into sc-dev
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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,39 +102,39 @@ 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)
|
||||||
|
if (timeSinceActive < SMARTSPACE_MAX_AGE) {
|
||||||
val lastActiveKey = sorted.lastKey() // most recently active
|
val lastActiveKey = sorted.lastKey() // most recently active
|
||||||
val timeSinceActive = sorted.get(lastActiveKey)?.let {
|
// Notify listeners to consider this media active
|
||||||
now - it.lastActive
|
Log.d(TAG, "reactivating $lastActiveKey instead of smartspace")
|
||||||
} ?: Long.MAX_VALUE
|
reactivatedKey = lastActiveKey
|
||||||
if (timeSinceActive < SMARTSPACE_MAX_AGE) {
|
val mediaData = sorted.get(lastActiveKey)!!.copy(active = true)
|
||||||
// Notify listeners to consider this media active
|
listeners.forEach {
|
||||||
Log.d(TAG, "reactivating $lastActiveKey instead of smartspace")
|
it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData)
|
||||||
reactivatedKey = lastActiveKey
|
|
||||||
val mediaData = sorted.get(lastActiveKey)!!.copy(active = true)
|
|
||||||
listeners.forEach {
|
|
||||||
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user