Merge "Media impression logging bug fix" into sc-dev
This commit is contained in:
@@ -156,6 +156,12 @@ class MediaCarouselController @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update MediaCarouselScrollHandler.visibleToUser to reflect media card container visibility.
|
||||
* It will be called when the container is out of view.
|
||||
*/
|
||||
lateinit var updateUserVisibility: () -> Unit
|
||||
|
||||
init {
|
||||
mediaFrame = inflateMediaCarousel()
|
||||
mediaCarousel = mediaFrame.requireViewById(R.id.media_carousel_scroller)
|
||||
@@ -177,6 +183,12 @@ class MediaCarouselController @Inject constructor(
|
||||
keysNeedRemoval.forEach { removePlayer(it) }
|
||||
keysNeedRemoval.clear()
|
||||
|
||||
// Update user visibility so that no extra impression will be logged when
|
||||
// activeMediaIndex resets to 0
|
||||
if (this::updateUserVisibility.isInitialized) {
|
||||
updateUserVisibility()
|
||||
}
|
||||
|
||||
// Let's reset our scroll position
|
||||
mediaCarouselScrollHandler.scrollToStart()
|
||||
}
|
||||
@@ -187,16 +199,24 @@ class MediaCarouselController @Inject constructor(
|
||||
key: String,
|
||||
oldKey: String?,
|
||||
data: MediaData,
|
||||
immediately: Boolean
|
||||
immediately: Boolean,
|
||||
isSsReactivated: Boolean
|
||||
) {
|
||||
if (addOrUpdatePlayer(key, oldKey, data)) {
|
||||
MediaPlayerData.getMediaPlayer(key, null)?.let {
|
||||
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
|
||||
it.mInstanceId,
|
||||
/* isRecommendationCard */ false,
|
||||
it.surfaceForSmartspaceLogging)
|
||||
it.surfaceForSmartspaceLogging,
|
||||
rank = MediaPlayerData.getMediaPlayerIndex(key))
|
||||
}
|
||||
}
|
||||
if (mediaCarouselScrollHandler.visibleToUser &&
|
||||
isSsReactivated && !mediaCarouselScrollHandler.qsExpanded) {
|
||||
// It could happen that reactived media player isn't visible to user because
|
||||
// of it is a resumption card.
|
||||
logSmartspaceImpression(mediaCarouselScrollHandler.qsExpanded)
|
||||
}
|
||||
val canRemove = data.isPlaying?.let { !it } ?: data.isClearable && !data.active
|
||||
if (canRemove && !Utils.useMediaResumption(context)) {
|
||||
// This view isn't playing, let's remove this! This happens e.g when
|
||||
@@ -224,10 +244,17 @@ class MediaCarouselController @Inject constructor(
|
||||
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
|
||||
it.mInstanceId,
|
||||
/* isRecommendationCard */ true,
|
||||
it.surfaceForSmartspaceLogging)
|
||||
}
|
||||
if (mediaCarouselScrollHandler.visibleToUser) {
|
||||
logSmartspaceImpression()
|
||||
it.surfaceForSmartspaceLogging,
|
||||
rank = MediaPlayerData.getMediaPlayerIndex(key))
|
||||
|
||||
if (mediaCarouselScrollHandler.visibleToUser &&
|
||||
mediaCarouselScrollHandler.visibleMediaIndex ==
|
||||
MediaPlayerData.getMediaPlayerIndex(key)) {
|
||||
logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN
|
||||
it.mInstanceId,
|
||||
/* isRecommendationCard */ true,
|
||||
it.surfaceForSmartspaceLogging)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
onSmartspaceMediaDataRemoved(data.targetId, immediately = true)
|
||||
@@ -644,17 +671,17 @@ class MediaCarouselController @Inject constructor(
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the user impression for media card.
|
||||
* Log the user impression for media card at visibleMediaIndex.
|
||||
*/
|
||||
fun logSmartspaceImpression() {
|
||||
fun logSmartspaceImpression(qsExpanded: Boolean) {
|
||||
val visibleMediaIndex = mediaCarouselScrollHandler.visibleMediaIndex
|
||||
if (MediaPlayerData.players().size > visibleMediaIndex) {
|
||||
val mediaControlPanel = MediaPlayerData.players().elementAt(visibleMediaIndex)
|
||||
val isMediaActive =
|
||||
MediaPlayerData.playerKeys().elementAt(visibleMediaIndex).data?.active
|
||||
val hasActiveMediaOrRecommendationCard =
|
||||
MediaPlayerData.hasActiveMediaOrRecommendationCard()
|
||||
val isRecommendationCard = mediaControlPanel.recommendationViewHolder != null
|
||||
if (!isRecommendationCard && !isMediaActive) {
|
||||
// Media control card time out or swiped away
|
||||
if (!hasActiveMediaOrRecommendationCard && !qsExpanded) {
|
||||
// Skip logging if on LS or QQS, and there is no active media card
|
||||
return
|
||||
}
|
||||
logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN
|
||||
@@ -672,6 +699,13 @@ class MediaCarouselController @Inject constructor(
|
||||
surface: Int,
|
||||
rank: Int = mediaCarouselScrollHandler.visibleMediaIndex
|
||||
) {
|
||||
// Only log media resume card when Smartspace data is available
|
||||
if (!isRecommendationCard &&
|
||||
!mediaManager.smartspaceMediaData.isActive &&
|
||||
MediaPlayerData.smartspaceMediaData == null) {
|
||||
return
|
||||
}
|
||||
|
||||
/* ktlint-disable max-line-length */
|
||||
SysUiStatsLog.write(SysUiStatsLog.SMARTSPACE_CARD_REPORTED,
|
||||
eventId,
|
||||
@@ -770,6 +804,16 @@ internal object MediaPlayerData {
|
||||
return mediaData.get(key)?.let { mediaPlayers.get(it) }
|
||||
}
|
||||
|
||||
fun getMediaPlayerIndex(key: String): Int {
|
||||
val sortKey = mediaData.get(key)
|
||||
mediaPlayers.entries.forEachIndexed { index, e ->
|
||||
if (e.key == sortKey) {
|
||||
return index
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
fun removeMediaPlayer(key: String) = mediaData.remove(key)?.let {
|
||||
if (it.isSsMediaRec) {
|
||||
smartspaceMediaData = null
|
||||
@@ -808,4 +852,15 @@ internal object MediaPlayerData {
|
||||
mediaData.clear()
|
||||
mediaPlayers.clear()
|
||||
}
|
||||
|
||||
/* Returns true if there is active media player card or recommendation card */
|
||||
fun hasActiveMediaOrRecommendationCard(): Boolean {
|
||||
if (smartspaceMediaData != null && smartspaceMediaData?.isActive!!) {
|
||||
return true
|
||||
}
|
||||
if (firstActiveMediaIndex() != -1) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ class MediaCarouselScrollHandler(
|
||||
private val closeGuts: (immediate: Boolean) -> Unit,
|
||||
private val falsingCollector: FalsingCollector,
|
||||
private val falsingManager: FalsingManager,
|
||||
private val logSmartspaceImpression: () -> Unit
|
||||
private val logSmartspaceImpression: (Boolean) -> Unit
|
||||
) {
|
||||
/**
|
||||
* Is the view in RTL
|
||||
@@ -195,18 +195,22 @@ class MediaCarouselScrollHandler(
|
||||
if (playerWidthPlusPadding == 0) {
|
||||
return
|
||||
}
|
||||
|
||||
val relativeScrollX = scrollView.relativeScrollX
|
||||
onMediaScrollingChanged(relativeScrollX / playerWidthPlusPadding,
|
||||
relativeScrollX % playerWidthPlusPadding)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the media card is visible to user if any
|
||||
*/
|
||||
var visibleToUser: Boolean = false
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the quick setting is expanded or not
|
||||
*/
|
||||
var qsExpanded: Boolean = false
|
||||
|
||||
init {
|
||||
gestureDetector = GestureDetectorCompat(scrollView.context, gestureListener)
|
||||
@@ -471,7 +475,7 @@ class MediaCarouselScrollHandler(
|
||||
val oldIndex = visibleMediaIndex
|
||||
visibleMediaIndex = newIndex
|
||||
if (oldIndex != visibleMediaIndex && visibleToUser) {
|
||||
logSmartspaceImpression()
|
||||
logSmartspaceImpression(qsExpanded)
|
||||
}
|
||||
closeGuts(false)
|
||||
updatePlayerVisibilities()
|
||||
|
||||
@@ -266,7 +266,7 @@ public class MediaControlPanel {
|
||||
}
|
||||
mKey = key;
|
||||
MediaSession.Token token = data.getToken();
|
||||
mInstanceId = data.getPackageName().hashCode();
|
||||
mInstanceId = SmallHash.hash(data.getPackageName());
|
||||
|
||||
mBackgroundColor = data.getBackgroundColor();
|
||||
if (mToken == null || !mToken.equals(token)) {
|
||||
@@ -504,7 +504,7 @@ public class MediaControlPanel {
|
||||
return;
|
||||
}
|
||||
|
||||
mInstanceId = data.getTargetId().hashCode();
|
||||
mInstanceId = SmallHash.hash(data.getTargetId());
|
||||
mBackgroundColor = data.getBackgroundColor();
|
||||
TransitionLayout recommendationCard = mRecommendationViewHolder.getRecommendations();
|
||||
recommendationCard.setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor));
|
||||
|
||||
@@ -31,7 +31,8 @@ class MediaDataCombineLatest @Inject constructor() : MediaDataManager.Listener,
|
||||
key: String,
|
||||
oldKey: String?,
|
||||
data: MediaData,
|
||||
immediately: Boolean
|
||||
immediately: Boolean,
|
||||
isSsReactivated: Boolean
|
||||
) {
|
||||
if (oldKey != null && oldKey != key && entries.contains(oldKey)) {
|
||||
entries[key] = data to entries.remove(oldKey)?.second
|
||||
|
||||
@@ -83,7 +83,8 @@ class MediaDataFilter @Inject constructor(
|
||||
key: String,
|
||||
oldKey: String?,
|
||||
data: MediaData,
|
||||
immediately: Boolean
|
||||
immediately: Boolean,
|
||||
isSsReactivated: Boolean
|
||||
) {
|
||||
if (oldKey != null && oldKey != key) {
|
||||
allEntries.remove(oldKey)
|
||||
@@ -101,7 +102,7 @@ class MediaDataFilter @Inject constructor(
|
||||
|
||||
// Notify listeners
|
||||
listeners.forEach {
|
||||
it.onMediaDataLoaded(key, oldKey, data)
|
||||
it.onMediaDataLoaded(key, oldKey, data, isSsReactivated = isSsReactivated)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,6 +119,8 @@ class MediaDataFilter @Inject constructor(
|
||||
// Override the pass-in value here, as the order of Smartspace card is only determined here.
|
||||
var shouldPrioritizeMutable = false
|
||||
smartspaceMediaData = data
|
||||
// Override the pass-in value here, as the Smartspace reactivation could only happen here.
|
||||
var isSsReactivated = false
|
||||
|
||||
// Before forwarding the smartspace target, first check if we have recently inactive media
|
||||
val sorted = userEntries.toSortedMap(compareBy {
|
||||
@@ -137,9 +140,13 @@ class MediaDataFilter @Inject constructor(
|
||||
// Notify listeners to consider this media active
|
||||
Log.d(TAG, "reactivating $lastActiveKey instead of smartspace")
|
||||
reactivatedKey = lastActiveKey
|
||||
if (MediaPlayerData.firstActiveMediaIndex() == -1) {
|
||||
isSsReactivated = true
|
||||
}
|
||||
val mediaData = sorted.get(lastActiveKey)!!.copy(active = true)
|
||||
listeners.forEach {
|
||||
it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData)
|
||||
it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData,
|
||||
isSsReactivated = isSsReactivated)
|
||||
}
|
||||
} else {
|
||||
// Mark to prioritize Smartspace card if no recent media.
|
||||
|
||||
@@ -148,7 +148,7 @@ class MediaDataManager(
|
||||
private val internalListeners: MutableSet<Listener> = mutableSetOf()
|
||||
private val mediaEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
|
||||
// There should ONLY be at most one Smartspace media recommendation.
|
||||
private var smartspaceMediaData: SmartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA
|
||||
var smartspaceMediaData: SmartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA
|
||||
private var smartspaceSession: SmartspaceSession? = null
|
||||
private var allowMediaRecommendations = Utils.allowMediaRecommendations(context)
|
||||
|
||||
@@ -824,12 +824,16 @@ class MediaDataManager(
|
||||
* @param immediately indicates should apply the UI changes immediately, otherwise wait
|
||||
* until the next refresh-round before UI becomes visible. True by default to take in place
|
||||
* immediately.
|
||||
*
|
||||
* @param isSsReactivated indicates transition from a state with no active media players to
|
||||
* a state with active media players upon receiving Smartspace media data.
|
||||
*/
|
||||
fun onMediaDataLoaded(
|
||||
key: String,
|
||||
oldKey: String?,
|
||||
data: MediaData,
|
||||
immediately: Boolean = true
|
||||
immediately: Boolean = true,
|
||||
isSsReactivated: Boolean = false
|
||||
) {}
|
||||
|
||||
/**
|
||||
|
||||
@@ -67,7 +67,8 @@ class MediaDeviceManager @Inject constructor(
|
||||
key: String,
|
||||
oldKey: String?,
|
||||
data: MediaData,
|
||||
immediately: Boolean
|
||||
immediately: Boolean,
|
||||
isSsReactivated: Boolean
|
||||
) {
|
||||
if (oldKey != null && oldKey != key) {
|
||||
val oldEntry = entries.remove(oldKey)
|
||||
|
||||
@@ -220,14 +220,11 @@ class MediaHierarchyManager @Inject constructor(
|
||||
set(value) {
|
||||
if (field != value) {
|
||||
field = value
|
||||
mediaCarouselController.mediaCarouselScrollHandler.qsExpanded = value
|
||||
}
|
||||
// qs is expanded on LS shade and HS shade
|
||||
if (value && (isLockScreenShadeVisibleToUser() || isHomeScreenShadeVisibleToUser())) {
|
||||
mediaCarouselController.logSmartspaceImpression()
|
||||
}
|
||||
// Release shade and back to lock screen
|
||||
if (isLockScreenVisibleToUser()) {
|
||||
mediaCarouselController.logSmartspaceImpression()
|
||||
mediaCarouselController.logSmartspaceImpression(value)
|
||||
}
|
||||
mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
|
||||
}
|
||||
@@ -409,7 +406,7 @@ class MediaHierarchyManager @Inject constructor(
|
||||
updateTargetState()
|
||||
// Enters shade from lock screen
|
||||
if (newState == StatusBarState.SHADE_LOCKED && isLockScreenShadeVisibleToUser()) {
|
||||
mediaCarouselController.logSmartspaceImpression()
|
||||
mediaCarouselController.logSmartspaceImpression(qsExpanded)
|
||||
}
|
||||
mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
|
||||
}
|
||||
@@ -423,7 +420,7 @@ class MediaHierarchyManager @Inject constructor(
|
||||
dozeAnimationRunning = false
|
||||
// Enters lock screen from screen off
|
||||
if (isLockScreenVisibleToUser()) {
|
||||
mediaCarouselController.logSmartspaceImpression()
|
||||
mediaCarouselController.logSmartspaceImpression(qsExpanded)
|
||||
}
|
||||
} else {
|
||||
updateDesiredLocation()
|
||||
@@ -436,11 +433,7 @@ class MediaHierarchyManager @Inject constructor(
|
||||
override fun onExpandedChanged(isExpanded: Boolean) {
|
||||
// Enters shade from home screen
|
||||
if (isHomeScreenShadeVisibleToUser()) {
|
||||
mediaCarouselController.logSmartspaceImpression()
|
||||
}
|
||||
// Back to lock screen from bouncer
|
||||
if (isLockScreenVisibleToUser()) {
|
||||
mediaCarouselController.logSmartspaceImpression()
|
||||
mediaCarouselController.logSmartspaceImpression(qsExpanded)
|
||||
}
|
||||
mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
|
||||
}
|
||||
@@ -465,6 +458,10 @@ class MediaHierarchyManager @Inject constructor(
|
||||
goingToSleep = false
|
||||
}
|
||||
})
|
||||
|
||||
mediaCarouselController.updateUserVisibility = {
|
||||
mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateConfiguration() {
|
||||
|
||||
@@ -60,7 +60,8 @@ class MediaHost constructor(
|
||||
key: String,
|
||||
oldKey: String?,
|
||||
data: MediaData,
|
||||
immediately: Boolean
|
||||
immediately: Boolean,
|
||||
isSsReactivated: Boolean
|
||||
) {
|
||||
if (immediately) {
|
||||
updateViewVisibility()
|
||||
|
||||
@@ -159,7 +159,8 @@ class MediaResumeListener @Inject constructor(
|
||||
key: String,
|
||||
oldKey: String?,
|
||||
data: MediaData,
|
||||
immediately: Boolean
|
||||
immediately: Boolean,
|
||||
isSsReactivated: Boolean
|
||||
) {
|
||||
if (useMediaResumption) {
|
||||
// If this had been started from a resume state, disconnect now that it's live
|
||||
|
||||
@@ -95,7 +95,8 @@ class MediaSessionBasedFilter @Inject constructor(
|
||||
key: String,
|
||||
oldKey: String?,
|
||||
data: MediaData,
|
||||
immediately: Boolean
|
||||
immediately: Boolean,
|
||||
isSsReactivated: Boolean
|
||||
) {
|
||||
backgroundExecutor.execute {
|
||||
data.token?.let {
|
||||
|
||||
@@ -54,7 +54,8 @@ class MediaTimeoutListener @Inject constructor(
|
||||
key: String,
|
||||
oldKey: String?,
|
||||
data: MediaData,
|
||||
immediately: Boolean
|
||||
immediately: Boolean,
|
||||
isSsReactivated: Boolean
|
||||
) {
|
||||
var reusedListener: PlaybackStateListener? = null
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.systemui.media;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A simple hash function for use in privacy-sensitive logging.
|
||||
*/
|
||||
public final class SmallHash {
|
||||
// Hashes will be in the range [0, MAX_HASH).
|
||||
public static final int MAX_HASH = (1 << 13);
|
||||
|
||||
/** Return Small hash of the string, if non-null, or 0 otherwise. */
|
||||
public static int hash(String in) {
|
||||
return hash(Objects.hashCode(in));
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps in to the range [0, MAX_HASH), keeping similar values distinct.
|
||||
*
|
||||
* @param in An arbitrary integer.
|
||||
* @return in mod MAX_HASH, signs chosen to stay in the range [0, MAX_HASH).
|
||||
*/
|
||||
public static int hash(int in) {
|
||||
return Math.abs(Math.floorMod(in, MAX_HASH));
|
||||
}
|
||||
|
||||
private SmallHash() {}
|
||||
}
|
||||
@@ -245,7 +245,8 @@ public class NotificationMediaManager implements Dumpable {
|
||||
mMediaDataManager.addListener(new MediaDataManager.Listener() {
|
||||
@Override
|
||||
public void onMediaDataLoaded(@NonNull String key,
|
||||
@Nullable String oldKey, @NonNull MediaData data, boolean immediately) {
|
||||
@Nullable String oldKey, @NonNull MediaData data, boolean immediately,
|
||||
boolean isSsReactivated) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -318,7 +319,8 @@ public class NotificationMediaManager implements Dumpable {
|
||||
mMediaDataManager.addListener(new MediaDataManager.Listener() {
|
||||
@Override
|
||||
public void onMediaDataLoaded(@NonNull String key,
|
||||
@Nullable String oldKey, @NonNull MediaData data, boolean immediately) {
|
||||
@Nullable String oldKey, @NonNull MediaData data, boolean immediately,
|
||||
boolean isSsReactivated) {
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -82,9 +82,11 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void eventNotEmittedWithoutDevice() {
|
||||
// WHEN data source emits an event without device data
|
||||
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */);
|
||||
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */,
|
||||
false /* isSsReactivated */);
|
||||
// THEN an event isn't emitted
|
||||
verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean());
|
||||
verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean(),
|
||||
anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -92,7 +94,8 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
|
||||
// WHEN device source emits an event without media data
|
||||
mManager.onMediaDeviceChanged(KEY, null, mDeviceData);
|
||||
// THEN an event isn't emitted
|
||||
verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean());
|
||||
verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean(),
|
||||
anyBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -100,80 +103,95 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
|
||||
// GIVEN that a device event has already been received
|
||||
mManager.onMediaDeviceChanged(KEY, null, mDeviceData);
|
||||
// WHEN media event is received
|
||||
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */);
|
||||
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */,
|
||||
false /* isSsReactivated */);
|
||||
// THEN the listener receives a combined event
|
||||
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
|
||||
verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture(), anyBoolean());
|
||||
verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture(), anyBoolean(),
|
||||
anyBoolean());
|
||||
assertThat(captor.getValue().getDevice()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emitEventAfterMediaFirst() {
|
||||
// GIVEN that media event has already been received
|
||||
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */);
|
||||
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */,
|
||||
false /* isSsReactivated */);
|
||||
// WHEN device event is received
|
||||
mManager.onMediaDeviceChanged(KEY, null, mDeviceData);
|
||||
// THEN the listener receives a combined event
|
||||
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
|
||||
verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture(), anyBoolean());
|
||||
verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture(), anyBoolean(),
|
||||
anyBoolean());
|
||||
assertThat(captor.getValue().getDevice()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrateKeyMediaFirst() {
|
||||
// GIVEN that media and device info has already been received
|
||||
mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */);
|
||||
mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */,
|
||||
false /* isSsReactivated */);
|
||||
mManager.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
|
||||
reset(mListener);
|
||||
// WHEN a key migration event is received
|
||||
mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */);
|
||||
mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */,
|
||||
false /* isSsReactivated */);
|
||||
// THEN the listener receives a combined event
|
||||
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
|
||||
verify(mListener).onMediaDataLoaded(eq(KEY), eq(OLD_KEY), captor.capture(), anyBoolean());
|
||||
verify(mListener).onMediaDataLoaded(eq(KEY), eq(OLD_KEY), captor.capture(), anyBoolean(),
|
||||
anyBoolean());
|
||||
assertThat(captor.getValue().getDevice()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrateKeyDeviceFirst() {
|
||||
// GIVEN that media and device info has already been received
|
||||
mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */);
|
||||
mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */,
|
||||
false /* isSsReactivated */);
|
||||
mManager.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
|
||||
reset(mListener);
|
||||
// WHEN a key migration event is received
|
||||
mManager.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData);
|
||||
// THEN the listener receives a combined event
|
||||
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
|
||||
verify(mListener).onMediaDataLoaded(eq(KEY), eq(OLD_KEY), captor.capture(), anyBoolean());
|
||||
verify(mListener).onMediaDataLoaded(eq(KEY), eq(OLD_KEY), captor.capture(), anyBoolean(),
|
||||
anyBoolean());
|
||||
assertThat(captor.getValue().getDevice()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrateKeyMediaAfter() {
|
||||
// GIVEN that media and device info has already been received
|
||||
mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */);
|
||||
mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */,
|
||||
false /* isSsReactivated */);
|
||||
mManager.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
|
||||
mManager.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData);
|
||||
reset(mListener);
|
||||
// WHEN a second key migration event is received for media
|
||||
mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */);
|
||||
mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */,
|
||||
false /* isSsReactivated */);
|
||||
// THEN the key has already been migrated
|
||||
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
|
||||
verify(mListener).onMediaDataLoaded(eq(KEY), eq(KEY), captor.capture(), anyBoolean());
|
||||
verify(mListener).onMediaDataLoaded(eq(KEY), eq(KEY), captor.capture(), anyBoolean(),
|
||||
anyBoolean());
|
||||
assertThat(captor.getValue().getDevice()).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void migrateKeyDeviceAfter() {
|
||||
// GIVEN that media and device info has already been received
|
||||
mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */);
|
||||
mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */,
|
||||
false /* isSsReactivated */);
|
||||
mManager.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
|
||||
mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */);
|
||||
mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */,
|
||||
false /* isSsReactivated */);
|
||||
reset(mListener);
|
||||
// WHEN a second key migration event is received for the device
|
||||
mManager.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData);
|
||||
// THEN the key has already be migrated
|
||||
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
|
||||
verify(mListener).onMediaDataLoaded(eq(KEY), eq(KEY), captor.capture(), anyBoolean());
|
||||
verify(mListener).onMediaDataLoaded(eq(KEY), eq(KEY), captor.capture(), anyBoolean(),
|
||||
anyBoolean());
|
||||
assertThat(captor.getValue().getDevice()).isNotNull();
|
||||
}
|
||||
|
||||
@@ -187,7 +205,8 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void mediaDataRemovedAfterMediaEvent() {
|
||||
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */);
|
||||
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */,
|
||||
false /* isSsReactivated */);
|
||||
mManager.onMediaDataRemoved(KEY);
|
||||
verify(mListener).onMediaDataRemoved(eq(KEY));
|
||||
}
|
||||
@@ -202,13 +221,15 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
|
||||
@Test
|
||||
public void mediaDataKeyUpdated() {
|
||||
// GIVEN that device and media events have already been received
|
||||
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */);
|
||||
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */,
|
||||
false /* isSsReactivated */);
|
||||
mManager.onMediaDeviceChanged(KEY, null, mDeviceData);
|
||||
// WHEN the key is changed
|
||||
mManager.onMediaDataLoaded("NEW_KEY", KEY, mMediaData, true /* immediately */);
|
||||
mManager.onMediaDataLoaded("NEW_KEY", KEY, mMediaData, true /* immediately */,
|
||||
false /* isSsReactivated */);
|
||||
// THEN the listener gets a load event with the correct keys
|
||||
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
|
||||
verify(mListener).onMediaDataLoaded(
|
||||
eq("NEW_KEY"), any(), captor.capture(), anyBoolean());
|
||||
eq("NEW_KEY"), any(), captor.capture(), anyBoolean(), anyBoolean());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,8 @@ class MediaDataFilterTest : SysuiTestCase() {
|
||||
mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain)
|
||||
|
||||
// THEN we should tell the listener
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataMain), eq(true))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataMain), eq(true),
|
||||
eq(false))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -129,7 +130,7 @@ class MediaDataFilterTest : SysuiTestCase() {
|
||||
mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest)
|
||||
|
||||
// THEN we should NOT tell the listener
|
||||
verify(listener, never()).onMediaDataLoaded(any(), any(), any(), anyBoolean())
|
||||
verify(listener, never()).onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyBoolean())
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -175,10 +176,12 @@ class MediaDataFilterTest : SysuiTestCase() {
|
||||
setUser(USER_GUEST)
|
||||
|
||||
// THEN we should add back the guest user media
|
||||
verify(listener).onMediaDataLoaded(eq(KEY_ALT), eq(null), eq(dataGuest), eq(true))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY_ALT), eq(null), eq(dataGuest), eq(true),
|
||||
eq(false))
|
||||
|
||||
// but not the main user's
|
||||
verify(listener, never()).onMediaDataLoaded(eq(KEY), any(), eq(dataMain), anyBoolean())
|
||||
verify(listener, never()).onMediaDataLoaded(eq(KEY), any(), eq(dataMain), anyBoolean(),
|
||||
anyBoolean())
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -245,7 +248,7 @@ class MediaDataFilterTest : SysuiTestCase() {
|
||||
|
||||
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
|
||||
|
||||
verify(listener, never()).onMediaDataLoaded(any(), any(), any(), anyBoolean())
|
||||
verify(listener, never()).onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyBoolean())
|
||||
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
|
||||
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
|
||||
}
|
||||
@@ -282,12 +285,15 @@ class MediaDataFilterTest : SysuiTestCase() {
|
||||
// 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), eq(true))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true),
|
||||
eq(false))
|
||||
|
||||
// AND we get a smartspace signal
|
||||
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
|
||||
|
||||
// THEN we should tell listeners to treat the media as active instead
|
||||
// THEN we should tell listeners to treat the media as not active instead
|
||||
verify(listener, never()).onMediaDataLoaded(eq(KEY), eq(KEY), any(), anyBoolean(),
|
||||
anyBoolean())
|
||||
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
|
||||
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
|
||||
}
|
||||
@@ -299,14 +305,16 @@ class MediaDataFilterTest : SysuiTestCase() {
|
||||
// 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), eq(true))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true),
|
||||
eq(false))
|
||||
|
||||
// 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), eq(true))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive), eq(true),
|
||||
eq(true))
|
||||
assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
|
||||
// Smartspace update shouldn't be propagated for the empty rec list.
|
||||
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
|
||||
@@ -317,14 +325,16 @@ class MediaDataFilterTest : SysuiTestCase() {
|
||||
// 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), eq(true))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true),
|
||||
eq(false))
|
||||
|
||||
// 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), eq(true))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive), eq(true),
|
||||
eq(true))
|
||||
assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
|
||||
// Smartspace update should also be propagated but not prioritized.
|
||||
verify(listener)
|
||||
@@ -344,11 +354,17 @@ class MediaDataFilterTest : SysuiTestCase() {
|
||||
fun testOnSmartspaceMediaDataRemoved_usedMediaAndSmartspace_clearsBoth() {
|
||||
val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
|
||||
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true),
|
||||
eq(false))
|
||||
|
||||
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
|
||||
|
||||
val dataCurrentAndActive = dataCurrent.copy(active = true)
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive), eq(true),
|
||||
eq(true))
|
||||
|
||||
mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
|
||||
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrent), eq(true))
|
||||
verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
|
||||
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
|
||||
}
|
||||
|
||||
@@ -185,7 +185,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
fun testOnMetaDataLoaded_callsListener() {
|
||||
mediaDataManager.onNotificationAdded(KEY, mediaNotification)
|
||||
mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = mock(MediaData::class.java))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), anyObject(), eq(true))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), anyObject(), eq(true),
|
||||
eq(false))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -196,7 +197,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
mediaDataManager.onNotificationAdded(KEY, mediaNotification)
|
||||
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
|
||||
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
|
||||
eq(false))
|
||||
assertThat(mediaDataCaptor.value!!.active).isTrue()
|
||||
}
|
||||
|
||||
@@ -215,7 +217,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
mediaDataManager.onNotificationAdded(KEY, mediaNotification)
|
||||
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
|
||||
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
|
||||
eq(false))
|
||||
val data = mediaDataCaptor.value
|
||||
assertThat(data.resumption).isFalse()
|
||||
mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
|
||||
@@ -223,7 +226,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
mediaDataManager.onNotificationRemoved(KEY)
|
||||
// THEN the media data indicates that it is for resumption
|
||||
verify(listener)
|
||||
.onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true))
|
||||
.onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true),
|
||||
eq(false))
|
||||
assertThat(mediaDataCaptor.value.resumption).isTrue()
|
||||
}
|
||||
|
||||
@@ -236,7 +240,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
assertThat(backgroundExecutor.runAllReady()).isEqualTo(2)
|
||||
assertThat(foregroundExecutor.runAllReady()).isEqualTo(2)
|
||||
verify(listener)
|
||||
.onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true))
|
||||
.onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
|
||||
eq(false))
|
||||
val data = mediaDataCaptor.value
|
||||
assertThat(data.resumption).isFalse()
|
||||
val resumableData = data.copy(resumeAction = Runnable {})
|
||||
@@ -247,7 +252,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
mediaDataManager.onNotificationRemoved(KEY)
|
||||
// THEN the data is for resumption and the key is migrated to the package name
|
||||
verify(listener)
|
||||
.onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true))
|
||||
.onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true),
|
||||
eq(false))
|
||||
assertThat(mediaDataCaptor.value.resumption).isTrue()
|
||||
verify(listener, never()).onMediaDataRemoved(eq(KEY))
|
||||
// WHEN the second is removed
|
||||
@@ -255,7 +261,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
// THEN the data is for resumption and the second key is removed
|
||||
verify(listener)
|
||||
.onMediaDataLoaded(
|
||||
eq(PACKAGE_NAME), eq(PACKAGE_NAME), capture(mediaDataCaptor), eq(true))
|
||||
eq(PACKAGE_NAME), eq(PACKAGE_NAME), capture(mediaDataCaptor), eq(true),
|
||||
eq(false))
|
||||
assertThat(mediaDataCaptor.value.resumption).isTrue()
|
||||
verify(listener).onMediaDataRemoved(eq(KEY_2))
|
||||
}
|
||||
@@ -269,7 +276,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
mediaDataManager.onNotificationAdded(KEY, mediaNotification)
|
||||
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
|
||||
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
|
||||
eq(false))
|
||||
val data = mediaDataCaptor.value
|
||||
val dataRemoteWithResume = data.copy(resumeAction = Runnable {}, isLocalSession = false)
|
||||
mediaDataManager.onMediaDataLoaded(KEY, null, dataRemoteWithResume)
|
||||
@@ -295,7 +303,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
|
||||
// THEN the media data indicates that it is for resumption
|
||||
verify(listener)
|
||||
.onMediaDataLoaded(eq(PACKAGE_NAME), eq(null), capture(mediaDataCaptor), eq(true))
|
||||
.onMediaDataLoaded(eq(PACKAGE_NAME), eq(null), capture(mediaDataCaptor), eq(true),
|
||||
eq(false))
|
||||
val data = mediaDataCaptor.value
|
||||
assertThat(data.resumption).isTrue()
|
||||
assertThat(data.song).isEqualTo(SESSION_TITLE)
|
||||
@@ -335,7 +344,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
|
||||
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
|
||||
verify(listener)
|
||||
.onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true))
|
||||
.onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
|
||||
eq(false))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -414,7 +424,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
mediaDataManager.onNotificationAdded(KEY, mediaNotification)
|
||||
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
|
||||
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
|
||||
eq(false))
|
||||
assertThat(mediaDataCaptor.value!!.lastActive).isAtLeast(currentTime)
|
||||
}
|
||||
|
||||
@@ -431,7 +442,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
mediaDataManager.setTimedOut(KEY, true, true)
|
||||
|
||||
// THEN the last active time is not changed
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), capture(mediaDataCaptor), eq(true))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), capture(mediaDataCaptor), eq(true),
|
||||
eq(false))
|
||||
assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime)
|
||||
}
|
||||
|
||||
@@ -442,7 +454,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
mediaDataManager.onNotificationAdded(KEY, mediaNotification)
|
||||
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
|
||||
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
|
||||
eq(false))
|
||||
val data = mediaDataCaptor.value
|
||||
assertThat(data.resumption).isFalse()
|
||||
mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
|
||||
@@ -454,7 +467,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
|
||||
// THEN the last active time is not changed
|
||||
verify(listener)
|
||||
.onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true))
|
||||
.onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true),
|
||||
eq(false))
|
||||
assertThat(mediaDataCaptor.value.resumption).isTrue()
|
||||
assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime)
|
||||
}
|
||||
@@ -480,7 +494,8 @@ class MediaDataManagerTest : SysuiTestCase() {
|
||||
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
|
||||
|
||||
// THEN only the first MAX_COMPACT_ACTIONS are actually set
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true))
|
||||
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
|
||||
eq(false))
|
||||
assertThat(mediaDataCaptor.value.actionsToShowInCompact.size).isEqualTo(
|
||||
MediaDataManager.MAX_COMPACT_ACTIONS)
|
||||
}
|
||||
|
||||
@@ -185,7 +185,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
|
||||
filter.onMediaDataLoaded(KEY, null, mediaData1)
|
||||
bgExecutor.runAllReady()
|
||||
fgExecutor.runAllReady()
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true))
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
|
||||
eq(false))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -207,7 +208,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
|
||||
bgExecutor.runAllReady()
|
||||
fgExecutor.runAllReady()
|
||||
// THEN the event is not filtered
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true))
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
|
||||
eq(false))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -236,7 +238,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
|
||||
bgExecutor.runAllReady()
|
||||
fgExecutor.runAllReady()
|
||||
// THEN the event is not filtered
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true))
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
|
||||
eq(false))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -251,14 +254,15 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
|
||||
bgExecutor.runAllReady()
|
||||
fgExecutor.runAllReady()
|
||||
// THEN the event is not filtered
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true))
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
|
||||
eq(false))
|
||||
// WHEN a loaded event is received that matches the local session
|
||||
filter.onMediaDataLoaded(KEY, null, mediaData2)
|
||||
bgExecutor.runAllReady()
|
||||
fgExecutor.runAllReady()
|
||||
// THEN the event is filtered
|
||||
verify(mediaListener, never()).onMediaDataLoaded(
|
||||
eq(KEY), eq(null), eq(mediaData2), anyBoolean())
|
||||
eq(KEY), eq(null), eq(mediaData2), anyBoolean(), anyBoolean())
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -274,7 +278,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
|
||||
fgExecutor.runAllReady()
|
||||
// THEN the event is not filtered because there isn't a notification for the remote
|
||||
// session.
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true))
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
|
||||
eq(false))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -291,14 +296,15 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
|
||||
bgExecutor.runAllReady()
|
||||
fgExecutor.runAllReady()
|
||||
// THEN the event is not filtered
|
||||
verify(mediaListener).onMediaDataLoaded(eq(key1), eq(null), eq(mediaData1), eq(true))
|
||||
verify(mediaListener).onMediaDataLoaded(eq(key1), eq(null), eq(mediaData1), eq(true),
|
||||
eq(false))
|
||||
// WHEN a loaded event is received that matches the local session
|
||||
filter.onMediaDataLoaded(key2, null, mediaData2)
|
||||
bgExecutor.runAllReady()
|
||||
fgExecutor.runAllReady()
|
||||
// THEN the event is filtered
|
||||
verify(mediaListener, never())
|
||||
.onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), anyBoolean())
|
||||
.onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), anyBoolean(), anyBoolean())
|
||||
// AND there should be a removed event for key2
|
||||
verify(mediaListener).onMediaDataRemoved(eq(key2))
|
||||
}
|
||||
@@ -317,13 +323,15 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
|
||||
bgExecutor.runAllReady()
|
||||
fgExecutor.runAllReady()
|
||||
// THEN the event is not filtered
|
||||
verify(mediaListener).onMediaDataLoaded(eq(key1), eq(null), eq(mediaData1), eq(true))
|
||||
verify(mediaListener).onMediaDataLoaded(eq(key1), eq(null), eq(mediaData1), eq(true),
|
||||
eq(false))
|
||||
// WHEN a loaded event is received that matches the remote session
|
||||
filter.onMediaDataLoaded(key2, null, mediaData2)
|
||||
bgExecutor.runAllReady()
|
||||
fgExecutor.runAllReady()
|
||||
// THEN the event is not filtered
|
||||
verify(mediaListener).onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), eq(true))
|
||||
verify(mediaListener).onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), eq(true),
|
||||
eq(false))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -339,13 +347,15 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
|
||||
bgExecutor.runAllReady()
|
||||
fgExecutor.runAllReady()
|
||||
// THEN the event is not filtered
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true))
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
|
||||
eq(false))
|
||||
// WHEN a loaded event is received that matches the local session
|
||||
filter.onMediaDataLoaded(KEY, null, mediaData2)
|
||||
bgExecutor.runAllReady()
|
||||
fgExecutor.runAllReady()
|
||||
// THEN the event is not filtered
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData2), eq(true))
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData2), eq(true),
|
||||
eq(false))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -363,7 +373,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
|
||||
bgExecutor.runAllReady()
|
||||
fgExecutor.runAllReady()
|
||||
// THEN the event is not filtered
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true))
|
||||
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
|
||||
eq(false))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -385,7 +396,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
|
||||
bgExecutor.runAllReady()
|
||||
fgExecutor.runAllReady()
|
||||
// THEN the key migration event is fired
|
||||
verify(mediaListener).onMediaDataLoaded(eq(key2), eq(key1), eq(mediaData2), eq(true))
|
||||
verify(mediaListener).onMediaDataLoaded(eq(key2), eq(key1), eq(mediaData2), eq(true),
|
||||
eq(false))
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -415,12 +427,13 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
|
||||
fgExecutor.runAllReady()
|
||||
// THEN the key migration event is filtered
|
||||
verify(mediaListener, never())
|
||||
.onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), anyBoolean())
|
||||
.onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), anyBoolean(), anyBoolean())
|
||||
// WHEN a loaded event is received that matches the remote session
|
||||
filter.onMediaDataLoaded(key2, null, mediaData1)
|
||||
bgExecutor.runAllReady()
|
||||
fgExecutor.runAllReady()
|
||||
// THEN the key migration event is fired
|
||||
verify(mediaListener).onMediaDataLoaded(eq(key2), eq(null), eq(mediaData1), eq(true))
|
||||
verify(mediaListener).onMediaDataLoaded(eq(key2), eq(null), eq(mediaData1), eq(true),
|
||||
eq(false))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user