Merge "Media impression logging bug fix" into sc-dev am: b247011e66

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/14728374

Change-Id: Ice6737a1073077981a1a48e96a0601a4eac8c288
This commit is contained in:
Jieru Shi
2021-06-21 23:35:32 +00:00
committed by Automerger Merge Worker
18 changed files with 295 additions and 111 deletions

View File

@@ -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 { init {
mediaFrame = inflateMediaCarousel() mediaFrame = inflateMediaCarousel()
mediaCarousel = mediaFrame.requireViewById(R.id.media_carousel_scroller) mediaCarousel = mediaFrame.requireViewById(R.id.media_carousel_scroller)
@@ -177,6 +183,12 @@ class MediaCarouselController @Inject constructor(
keysNeedRemoval.forEach { removePlayer(it) } keysNeedRemoval.forEach { removePlayer(it) }
keysNeedRemoval.clear() 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 // Let's reset our scroll position
mediaCarouselScrollHandler.scrollToStart() mediaCarouselScrollHandler.scrollToStart()
} }
@@ -187,16 +199,24 @@ class MediaCarouselController @Inject constructor(
key: String, key: String,
oldKey: String?, oldKey: String?,
data: MediaData, data: MediaData,
immediately: Boolean immediately: Boolean,
isSsReactivated: Boolean
) { ) {
if (addOrUpdatePlayer(key, oldKey, data)) { if (addOrUpdatePlayer(key, oldKey, data)) {
MediaPlayerData.getMediaPlayer(key, null)?.let { MediaPlayerData.getMediaPlayer(key, null)?.let {
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
it.mInstanceId, it.mInstanceId,
/* isRecommendationCard */ false, /* 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 val canRemove = data.isPlaying?.let { !it } ?: data.isClearable && !data.active
if (canRemove && !Utils.useMediaResumption(context)) { if (canRemove && !Utils.useMediaResumption(context)) {
// This view isn't playing, let's remove this! This happens e.g when // 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 logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
it.mInstanceId, it.mInstanceId,
/* isRecommendationCard */ true, /* isRecommendationCard */ true,
it.surfaceForSmartspaceLogging) it.surfaceForSmartspaceLogging,
} rank = MediaPlayerData.getMediaPlayerIndex(key))
if (mediaCarouselScrollHandler.visibleToUser) {
logSmartspaceImpression() if (mediaCarouselScrollHandler.visibleToUser &&
mediaCarouselScrollHandler.visibleMediaIndex ==
MediaPlayerData.getMediaPlayerIndex(key)) {
logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN
it.mInstanceId,
/* isRecommendationCard */ true,
it.surfaceForSmartspaceLogging)
}
} }
} else { } else {
onSmartspaceMediaDataRemoved(data.targetId, immediately = true) 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 val visibleMediaIndex = mediaCarouselScrollHandler.visibleMediaIndex
if (MediaPlayerData.players().size > visibleMediaIndex) { if (MediaPlayerData.players().size > visibleMediaIndex) {
val mediaControlPanel = MediaPlayerData.players().elementAt(visibleMediaIndex) val mediaControlPanel = MediaPlayerData.players().elementAt(visibleMediaIndex)
val isMediaActive = val hasActiveMediaOrRecommendationCard =
MediaPlayerData.playerKeys().elementAt(visibleMediaIndex).data?.active MediaPlayerData.hasActiveMediaOrRecommendationCard()
val isRecommendationCard = mediaControlPanel.recommendationViewHolder != null val isRecommendationCard = mediaControlPanel.recommendationViewHolder != null
if (!isRecommendationCard && !isMediaActive) { if (!hasActiveMediaOrRecommendationCard && !qsExpanded) {
// Media control card time out or swiped away // Skip logging if on LS or QQS, and there is no active media card
return return
} }
logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN
@@ -672,6 +699,13 @@ class MediaCarouselController @Inject constructor(
surface: Int, surface: Int,
rank: Int = mediaCarouselScrollHandler.visibleMediaIndex 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 */ /* ktlint-disable max-line-length */
SysUiStatsLog.write(SysUiStatsLog.SMARTSPACE_CARD_REPORTED, SysUiStatsLog.write(SysUiStatsLog.SMARTSPACE_CARD_REPORTED,
eventId, eventId,
@@ -770,6 +804,16 @@ internal object MediaPlayerData {
return mediaData.get(key)?.let { mediaPlayers.get(it) } 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 { fun removeMediaPlayer(key: String) = mediaData.remove(key)?.let {
if (it.isSsMediaRec) { if (it.isSsMediaRec) {
smartspaceMediaData = null smartspaceMediaData = null
@@ -808,4 +852,15 @@ internal object MediaPlayerData {
mediaData.clear() mediaData.clear()
mediaPlayers.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
}
} }

View File

@@ -62,7 +62,7 @@ class MediaCarouselScrollHandler(
private val closeGuts: (immediate: Boolean) -> Unit, private val closeGuts: (immediate: Boolean) -> Unit,
private val falsingCollector: FalsingCollector, private val falsingCollector: FalsingCollector,
private val falsingManager: FalsingManager, private val falsingManager: FalsingManager,
private val logSmartspaceImpression: () -> Unit private val logSmartspaceImpression: (Boolean) -> Unit
) { ) {
/** /**
* Is the view in RTL * Is the view in RTL
@@ -195,18 +195,22 @@ class MediaCarouselScrollHandler(
if (playerWidthPlusPadding == 0) { if (playerWidthPlusPadding == 0) {
return return
} }
val relativeScrollX = scrollView.relativeScrollX val relativeScrollX = scrollView.relativeScrollX
onMediaScrollingChanged(relativeScrollX / playerWidthPlusPadding, onMediaScrollingChanged(relativeScrollX / playerWidthPlusPadding,
relativeScrollX % playerWidthPlusPadding) relativeScrollX % playerWidthPlusPadding)
} }
} }
/**
* Whether the media card is visible to user if any
*/
var visibleToUser: Boolean = false var visibleToUser: Boolean = false
set(value) {
if (field != value) { /**
field = value * Whether the quick setting is expanded or not
} */
} var qsExpanded: Boolean = false
init { init {
gestureDetector = GestureDetectorCompat(scrollView.context, gestureListener) gestureDetector = GestureDetectorCompat(scrollView.context, gestureListener)
@@ -471,7 +475,7 @@ class MediaCarouselScrollHandler(
val oldIndex = visibleMediaIndex val oldIndex = visibleMediaIndex
visibleMediaIndex = newIndex visibleMediaIndex = newIndex
if (oldIndex != visibleMediaIndex && visibleToUser) { if (oldIndex != visibleMediaIndex && visibleToUser) {
logSmartspaceImpression() logSmartspaceImpression(qsExpanded)
} }
closeGuts(false) closeGuts(false)
updatePlayerVisibilities() updatePlayerVisibilities()

View File

@@ -266,7 +266,7 @@ public class MediaControlPanel {
} }
mKey = key; mKey = key;
MediaSession.Token token = data.getToken(); MediaSession.Token token = data.getToken();
mInstanceId = data.getPackageName().hashCode(); mInstanceId = SmallHash.hash(data.getPackageName());
mBackgroundColor = data.getBackgroundColor(); mBackgroundColor = data.getBackgroundColor();
if (mToken == null || !mToken.equals(token)) { if (mToken == null || !mToken.equals(token)) {
@@ -504,7 +504,7 @@ public class MediaControlPanel {
return; return;
} }
mInstanceId = data.getTargetId().hashCode(); mInstanceId = SmallHash.hash(data.getTargetId());
mBackgroundColor = data.getBackgroundColor(); mBackgroundColor = data.getBackgroundColor();
TransitionLayout recommendationCard = mRecommendationViewHolder.getRecommendations(); TransitionLayout recommendationCard = mRecommendationViewHolder.getRecommendations();
recommendationCard.setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor)); recommendationCard.setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor));

View File

@@ -31,7 +31,8 @@ class MediaDataCombineLatest @Inject constructor() : MediaDataManager.Listener,
key: String, key: String,
oldKey: String?, oldKey: String?,
data: MediaData, data: MediaData,
immediately: Boolean immediately: Boolean,
isSsReactivated: Boolean
) { ) {
if (oldKey != null && oldKey != key && entries.contains(oldKey)) { if (oldKey != null && oldKey != key && entries.contains(oldKey)) {
entries[key] = data to entries.remove(oldKey)?.second entries[key] = data to entries.remove(oldKey)?.second

View File

@@ -83,7 +83,8 @@ class MediaDataFilter @Inject constructor(
key: String, key: String,
oldKey: String?, oldKey: String?,
data: MediaData, data: MediaData,
immediately: Boolean immediately: Boolean,
isSsReactivated: Boolean
) { ) {
if (oldKey != null && oldKey != key) { if (oldKey != null && oldKey != key) {
allEntries.remove(oldKey) allEntries.remove(oldKey)
@@ -101,7 +102,7 @@ class MediaDataFilter @Inject constructor(
// Notify listeners // Notify listeners
listeners.forEach { 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. // Override the pass-in value here, as the order of Smartspace card is only determined here.
var shouldPrioritizeMutable = false var shouldPrioritizeMutable = false
smartspaceMediaData = data 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 // Before forwarding the smartspace target, first check if we have recently inactive media
val sorted = userEntries.toSortedMap(compareBy { val sorted = userEntries.toSortedMap(compareBy {
@@ -137,9 +140,13 @@ class MediaDataFilter @Inject constructor(
// 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
if (MediaPlayerData.firstActiveMediaIndex() == -1) {
isSsReactivated = true
}
val mediaData = sorted.get(lastActiveKey)!!.copy(active = true) val mediaData = sorted.get(lastActiveKey)!!.copy(active = true)
listeners.forEach { listeners.forEach {
it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData) it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData,
isSsReactivated = isSsReactivated)
} }
} else { } else {
// Mark to prioritize Smartspace card if no recent media. // Mark to prioritize Smartspace card if no recent media.

View File

@@ -148,7 +148,7 @@ class MediaDataManager(
private val internalListeners: MutableSet<Listener> = mutableSetOf() private val internalListeners: MutableSet<Listener> = mutableSetOf()
private val mediaEntries: LinkedHashMap<String, MediaData> = LinkedHashMap() private val mediaEntries: LinkedHashMap<String, MediaData> = LinkedHashMap()
// There should ONLY be at most one Smartspace media recommendation. // 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 smartspaceSession: SmartspaceSession? = null
private var allowMediaRecommendations = Utils.allowMediaRecommendations(context) private var allowMediaRecommendations = Utils.allowMediaRecommendations(context)
@@ -824,12 +824,16 @@ class MediaDataManager(
* @param immediately indicates should apply the UI changes immediately, otherwise wait * @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 * until the next refresh-round before UI becomes visible. True by default to take in place
* immediately. * 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( fun onMediaDataLoaded(
key: String, key: String,
oldKey: String?, oldKey: String?,
data: MediaData, data: MediaData,
immediately: Boolean = true immediately: Boolean = true,
isSsReactivated: Boolean = false
) {} ) {}
/** /**

View File

@@ -67,7 +67,8 @@ class MediaDeviceManager @Inject constructor(
key: String, key: String,
oldKey: String?, oldKey: String?,
data: MediaData, data: MediaData,
immediately: Boolean immediately: Boolean,
isSsReactivated: Boolean
) { ) {
if (oldKey != null && oldKey != key) { if (oldKey != null && oldKey != key) {
val oldEntry = entries.remove(oldKey) val oldEntry = entries.remove(oldKey)

View File

@@ -220,14 +220,11 @@ class MediaHierarchyManager @Inject constructor(
set(value) { set(value) {
if (field != value) { if (field != value) {
field = value field = value
mediaCarouselController.mediaCarouselScrollHandler.qsExpanded = value
} }
// qs is expanded on LS shade and HS shade // qs is expanded on LS shade and HS shade
if (value && (isLockScreenShadeVisibleToUser() || isHomeScreenShadeVisibleToUser())) { if (value && (isLockScreenShadeVisibleToUser() || isHomeScreenShadeVisibleToUser())) {
mediaCarouselController.logSmartspaceImpression() mediaCarouselController.logSmartspaceImpression(value)
}
// Release shade and back to lock screen
if (isLockScreenVisibleToUser()) {
mediaCarouselController.logSmartspaceImpression()
} }
mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser() mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
} }
@@ -409,7 +406,7 @@ class MediaHierarchyManager @Inject constructor(
updateTargetState() updateTargetState()
// Enters shade from lock screen // Enters shade from lock screen
if (newState == StatusBarState.SHADE_LOCKED && isLockScreenShadeVisibleToUser()) { if (newState == StatusBarState.SHADE_LOCKED && isLockScreenShadeVisibleToUser()) {
mediaCarouselController.logSmartspaceImpression() mediaCarouselController.logSmartspaceImpression(qsExpanded)
} }
mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser() mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
} }
@@ -423,7 +420,7 @@ class MediaHierarchyManager @Inject constructor(
dozeAnimationRunning = false dozeAnimationRunning = false
// Enters lock screen from screen off // Enters lock screen from screen off
if (isLockScreenVisibleToUser()) { if (isLockScreenVisibleToUser()) {
mediaCarouselController.logSmartspaceImpression() mediaCarouselController.logSmartspaceImpression(qsExpanded)
} }
} else { } else {
updateDesiredLocation() updateDesiredLocation()
@@ -436,11 +433,7 @@ class MediaHierarchyManager @Inject constructor(
override fun onExpandedChanged(isExpanded: Boolean) { override fun onExpandedChanged(isExpanded: Boolean) {
// Enters shade from home screen // Enters shade from home screen
if (isHomeScreenShadeVisibleToUser()) { if (isHomeScreenShadeVisibleToUser()) {
mediaCarouselController.logSmartspaceImpression() mediaCarouselController.logSmartspaceImpression(qsExpanded)
}
// Back to lock screen from bouncer
if (isLockScreenVisibleToUser()) {
mediaCarouselController.logSmartspaceImpression()
} }
mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser() mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
} }
@@ -465,6 +458,10 @@ class MediaHierarchyManager @Inject constructor(
goingToSleep = false goingToSleep = false
} }
}) })
mediaCarouselController.updateUserVisibility = {
mediaCarouselController.mediaCarouselScrollHandler.visibleToUser = isVisibleToUser()
}
} }
private fun updateConfiguration() { private fun updateConfiguration() {

View File

@@ -60,7 +60,8 @@ class MediaHost constructor(
key: String, key: String,
oldKey: String?, oldKey: String?,
data: MediaData, data: MediaData,
immediately: Boolean immediately: Boolean,
isSsReactivated: Boolean
) { ) {
if (immediately) { if (immediately) {
updateViewVisibility() updateViewVisibility()

View File

@@ -159,7 +159,8 @@ class MediaResumeListener @Inject constructor(
key: String, key: String,
oldKey: String?, oldKey: String?,
data: MediaData, data: MediaData,
immediately: Boolean immediately: Boolean,
isSsReactivated: Boolean
) { ) {
if (useMediaResumption) { if (useMediaResumption) {
// If this had been started from a resume state, disconnect now that it's live // If this had been started from a resume state, disconnect now that it's live

View File

@@ -95,7 +95,8 @@ class MediaSessionBasedFilter @Inject constructor(
key: String, key: String,
oldKey: String?, oldKey: String?,
data: MediaData, data: MediaData,
immediately: Boolean immediately: Boolean,
isSsReactivated: Boolean
) { ) {
backgroundExecutor.execute { backgroundExecutor.execute {
data.token?.let { data.token?.let {

View File

@@ -54,7 +54,8 @@ class MediaTimeoutListener @Inject constructor(
key: String, key: String,
oldKey: String?, oldKey: String?,
data: MediaData, data: MediaData,
immediately: Boolean immediately: Boolean,
isSsReactivated: Boolean
) { ) {
var reusedListener: PlaybackStateListener? = null var reusedListener: PlaybackStateListener? = null

View File

@@ -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() {}
}

View File

@@ -245,7 +245,8 @@ public class NotificationMediaManager implements Dumpable {
mMediaDataManager.addListener(new MediaDataManager.Listener() { mMediaDataManager.addListener(new MediaDataManager.Listener() {
@Override @Override
public void onMediaDataLoaded(@NonNull String key, 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 @Override
@@ -318,7 +319,8 @@ public class NotificationMediaManager implements Dumpable {
mMediaDataManager.addListener(new MediaDataManager.Listener() { mMediaDataManager.addListener(new MediaDataManager.Listener() {
@Override @Override
public void onMediaDataLoaded(@NonNull String key, 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 @Override

View File

@@ -82,9 +82,11 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test @Test
public void eventNotEmittedWithoutDevice() { public void eventNotEmittedWithoutDevice() {
// WHEN data source emits an event without device data // 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 // 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 @Test
@@ -92,7 +94,8 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
// WHEN device source emits an event without media data // WHEN device source emits an event without media data
mManager.onMediaDeviceChanged(KEY, null, mDeviceData); mManager.onMediaDeviceChanged(KEY, null, mDeviceData);
// THEN an event isn't emitted // 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 @Test
@@ -100,80 +103,95 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
// GIVEN that a device event has already been received // GIVEN that a device event has already been received
mManager.onMediaDeviceChanged(KEY, null, mDeviceData); mManager.onMediaDeviceChanged(KEY, null, mDeviceData);
// WHEN media event is received // 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 // THEN the listener receives a combined event
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); 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(); assertThat(captor.getValue().getDevice()).isNotNull();
} }
@Test @Test
public void emitEventAfterMediaFirst() { public void emitEventAfterMediaFirst() {
// GIVEN that media event has already been received // 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 // WHEN device event is received
mManager.onMediaDeviceChanged(KEY, null, mDeviceData); mManager.onMediaDeviceChanged(KEY, null, mDeviceData);
// THEN the listener receives a combined event // THEN the listener receives a combined event
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); 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(); assertThat(captor.getValue().getDevice()).isNotNull();
} }
@Test @Test
public void migrateKeyMediaFirst() { public void migrateKeyMediaFirst() {
// GIVEN that media and device info has already been received // 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(OLD_KEY, null, mDeviceData);
reset(mListener); reset(mListener);
// WHEN a key migration event is received // 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 // THEN the listener receives a combined event
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); 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(); assertThat(captor.getValue().getDevice()).isNotNull();
} }
@Test @Test
public void migrateKeyDeviceFirst() { public void migrateKeyDeviceFirst() {
// GIVEN that media and device info has already been received // 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(OLD_KEY, null, mDeviceData);
reset(mListener); reset(mListener);
// WHEN a key migration event is received // WHEN a key migration event is received
mManager.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData); mManager.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData);
// THEN the listener receives a combined event // THEN the listener receives a combined event
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); 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(); assertThat(captor.getValue().getDevice()).isNotNull();
} }
@Test @Test
public void migrateKeyMediaAfter() { public void migrateKeyMediaAfter() {
// GIVEN that media and device info has already been received // 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(OLD_KEY, null, mDeviceData);
mManager.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData); mManager.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData);
reset(mListener); reset(mListener);
// WHEN a second key migration event is received for media // 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 // THEN the key has already been migrated
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); 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(); assertThat(captor.getValue().getDevice()).isNotNull();
} }
@Test @Test
public void migrateKeyDeviceAfter() { public void migrateKeyDeviceAfter() {
// GIVEN that media and device info has already been received // 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(OLD_KEY, null, mDeviceData);
mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */); mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */,
false /* isSsReactivated */);
reset(mListener); reset(mListener);
// WHEN a second key migration event is received for the device // WHEN a second key migration event is received for the device
mManager.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData); mManager.onMediaDeviceChanged(KEY, OLD_KEY, mDeviceData);
// THEN the key has already be migrated // THEN the key has already be migrated
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); 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(); assertThat(captor.getValue().getDevice()).isNotNull();
} }
@@ -187,7 +205,8 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test @Test
public void mediaDataRemovedAfterMediaEvent() { public void mediaDataRemovedAfterMediaEvent() {
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */); mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */,
false /* isSsReactivated */);
mManager.onMediaDataRemoved(KEY); mManager.onMediaDataRemoved(KEY);
verify(mListener).onMediaDataRemoved(eq(KEY)); verify(mListener).onMediaDataRemoved(eq(KEY));
} }
@@ -202,13 +221,15 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test @Test
public void mediaDataKeyUpdated() { public void mediaDataKeyUpdated() {
// GIVEN that device and media events have already been received // 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); mManager.onMediaDeviceChanged(KEY, null, mDeviceData);
// WHEN the key is changed // 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 // THEN the listener gets a load event with the correct keys
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class); ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
verify(mListener).onMediaDataLoaded( verify(mListener).onMediaDataLoaded(
eq("NEW_KEY"), any(), captor.capture(), anyBoolean()); eq("NEW_KEY"), any(), captor.capture(), anyBoolean(), anyBoolean());
} }
} }

View File

@@ -120,7 +120,8 @@ class MediaDataFilterTest : SysuiTestCase() {
mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain) mediaDataFilter.onMediaDataLoaded(KEY, null, dataMain)
// THEN we should tell the listener // 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 @Test
@@ -129,7 +130,7 @@ class MediaDataFilterTest : SysuiTestCase() {
mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest) mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest)
// THEN we should NOT tell the listener // 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 @Test
@@ -175,10 +176,12 @@ class MediaDataFilterTest : SysuiTestCase() {
setUser(USER_GUEST) setUser(USER_GUEST)
// THEN we should add back the guest user media // 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 // 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 @Test
@@ -245,7 +248,7 @@ class MediaDataFilterTest : SysuiTestCase() {
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 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()) verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
assertThat(mediaDataFilter.hasActiveMedia()).isFalse() assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
} }
@@ -282,12 +285,15 @@ class MediaDataFilterTest : SysuiTestCase() {
// 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)
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 // AND we get a smartspace signal
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 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()) verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
assertThat(mediaDataFilter.hasActiveMedia()).isFalse() assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
} }
@@ -299,14 +305,16 @@ class MediaDataFilterTest : SysuiTestCase() {
// 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)
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 // AND we get a smartspace signal
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 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 active instead
val dataCurrentAndActive = dataCurrent.copy(active = true) 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() assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
// Smartspace update shouldn't be propagated for the empty rec list. // Smartspace update shouldn't be propagated for the empty rec list.
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean()) 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 // 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)
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 // AND we get a smartspace signal
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 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 active instead
val dataCurrentAndActive = dataCurrent.copy(active = true) 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() assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
// Smartspace update should also be propagated but not prioritized. // Smartspace update should also be propagated but not prioritized.
verify(listener) verify(listener)
@@ -344,11 +354,17 @@ class MediaDataFilterTest : SysuiTestCase() {
fun testOnSmartspaceMediaDataRemoved_usedMediaAndSmartspace_clearsBoth() { 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)
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent), eq(true),
eq(false))
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData) 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) mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrent), eq(true))
verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY) verify(listener).onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)
assertThat(mediaDataFilter.hasActiveMedia()).isFalse() assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
} }

View File

@@ -185,7 +185,8 @@ class MediaDataManagerTest : SysuiTestCase() {
fun testOnMetaDataLoaded_callsListener() { fun testOnMetaDataLoaded_callsListener() {
mediaDataManager.onNotificationAdded(KEY, mediaNotification) mediaDataManager.onNotificationAdded(KEY, mediaNotification)
mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = mock(MediaData::class.java)) 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 @Test
@@ -196,7 +197,8 @@ class MediaDataManagerTest : SysuiTestCase() {
mediaDataManager.onNotificationAdded(KEY, mediaNotification) mediaDataManager.onNotificationAdded(KEY, mediaNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.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() assertThat(mediaDataCaptor.value!!.active).isTrue()
} }
@@ -215,7 +217,8 @@ class MediaDataManagerTest : SysuiTestCase() {
mediaDataManager.onNotificationAdded(KEY, mediaNotification) mediaDataManager.onNotificationAdded(KEY, mediaNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.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 data = mediaDataCaptor.value
assertThat(data.resumption).isFalse() assertThat(data.resumption).isFalse()
mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {})) mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
@@ -223,7 +226,8 @@ class MediaDataManagerTest : SysuiTestCase() {
mediaDataManager.onNotificationRemoved(KEY) mediaDataManager.onNotificationRemoved(KEY)
// THEN the media data indicates that it is for resumption // THEN the media data indicates that it is for resumption
verify(listener) 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.resumption).isTrue()
} }
@@ -236,7 +240,8 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(backgroundExecutor.runAllReady()).isEqualTo(2) assertThat(backgroundExecutor.runAllReady()).isEqualTo(2)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(2) assertThat(foregroundExecutor.runAllReady()).isEqualTo(2)
verify(listener) 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 val data = mediaDataCaptor.value
assertThat(data.resumption).isFalse() assertThat(data.resumption).isFalse()
val resumableData = data.copy(resumeAction = Runnable {}) val resumableData = data.copy(resumeAction = Runnable {})
@@ -247,7 +252,8 @@ class MediaDataManagerTest : SysuiTestCase() {
mediaDataManager.onNotificationRemoved(KEY) mediaDataManager.onNotificationRemoved(KEY)
// THEN the data is for resumption and the key is migrated to the package name // THEN the data is for resumption and the key is migrated to the package name
verify(listener) 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.resumption).isTrue()
verify(listener, never()).onMediaDataRemoved(eq(KEY)) verify(listener, never()).onMediaDataRemoved(eq(KEY))
// WHEN the second is removed // WHEN the second is removed
@@ -255,7 +261,8 @@ class MediaDataManagerTest : SysuiTestCase() {
// THEN the data is for resumption and the second key is removed // THEN the data is for resumption and the second key is removed
verify(listener) verify(listener)
.onMediaDataLoaded( .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() assertThat(mediaDataCaptor.value.resumption).isTrue()
verify(listener).onMediaDataRemoved(eq(KEY_2)) verify(listener).onMediaDataRemoved(eq(KEY_2))
} }
@@ -269,7 +276,8 @@ class MediaDataManagerTest : SysuiTestCase() {
mediaDataManager.onNotificationAdded(KEY, mediaNotification) mediaDataManager.onNotificationAdded(KEY, mediaNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.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 data = mediaDataCaptor.value
val dataRemoteWithResume = data.copy(resumeAction = Runnable {}, isLocalSession = false) val dataRemoteWithResume = data.copy(resumeAction = Runnable {}, isLocalSession = false)
mediaDataManager.onMediaDataLoaded(KEY, null, dataRemoteWithResume) mediaDataManager.onMediaDataLoaded(KEY, null, dataRemoteWithResume)
@@ -295,7 +303,8 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
// THEN the media data indicates that it is for resumption // THEN the media data indicates that it is for resumption
verify(listener) 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 val data = mediaDataCaptor.value
assertThat(data.resumption).isTrue() assertThat(data.resumption).isTrue()
assertThat(data.song).isEqualTo(SESSION_TITLE) assertThat(data.song).isEqualTo(SESSION_TITLE)
@@ -335,7 +344,8 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener) verify(listener)
.onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true)) .onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
eq(false))
} }
@Test @Test
@@ -414,7 +424,8 @@ class MediaDataManagerTest : SysuiTestCase() {
mediaDataManager.onNotificationAdded(KEY, mediaNotification) mediaDataManager.onNotificationAdded(KEY, mediaNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.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) assertThat(mediaDataCaptor.value!!.lastActive).isAtLeast(currentTime)
} }
@@ -431,7 +442,8 @@ class MediaDataManagerTest : SysuiTestCase() {
mediaDataManager.setTimedOut(KEY, true, true) mediaDataManager.setTimedOut(KEY, true, true)
// THEN the last active time is not changed // 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) assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime)
} }
@@ -442,7 +454,8 @@ class MediaDataManagerTest : SysuiTestCase() {
mediaDataManager.onNotificationAdded(KEY, mediaNotification) mediaDataManager.onNotificationAdded(KEY, mediaNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1) assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.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 data = mediaDataCaptor.value
assertThat(data.resumption).isFalse() assertThat(data.resumption).isFalse()
mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {})) mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
@@ -454,7 +467,8 @@ class MediaDataManagerTest : SysuiTestCase() {
// THEN the last active time is not changed // THEN the last active time is not changed
verify(listener) 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.resumption).isTrue()
assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime) assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime)
} }
@@ -480,7 +494,8 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1) assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
// THEN only the first MAX_COMPACT_ACTIONS are actually set // 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( assertThat(mediaDataCaptor.value.actionsToShowInCompact.size).isEqualTo(
MediaDataManager.MAX_COMPACT_ACTIONS) MediaDataManager.MAX_COMPACT_ACTIONS)
} }

View File

@@ -185,7 +185,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
filter.onMediaDataLoaded(KEY, null, mediaData1) filter.onMediaDataLoaded(KEY, null, mediaData1)
bgExecutor.runAllReady() bgExecutor.runAllReady()
fgExecutor.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 @Test
@@ -207,7 +208,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady() bgExecutor.runAllReady()
fgExecutor.runAllReady() fgExecutor.runAllReady()
// THEN the event is not filtered // 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 @Test
@@ -236,7 +238,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady() bgExecutor.runAllReady()
fgExecutor.runAllReady() fgExecutor.runAllReady()
// THEN the event is not filtered // 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 @Test
@@ -251,14 +254,15 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady() bgExecutor.runAllReady()
fgExecutor.runAllReady() fgExecutor.runAllReady()
// THEN the event is not filtered // 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 // WHEN a loaded event is received that matches the local session
filter.onMediaDataLoaded(KEY, null, mediaData2) filter.onMediaDataLoaded(KEY, null, mediaData2)
bgExecutor.runAllReady() bgExecutor.runAllReady()
fgExecutor.runAllReady() fgExecutor.runAllReady()
// THEN the event is filtered // THEN the event is filtered
verify(mediaListener, never()).onMediaDataLoaded( verify(mediaListener, never()).onMediaDataLoaded(
eq(KEY), eq(null), eq(mediaData2), anyBoolean()) eq(KEY), eq(null), eq(mediaData2), anyBoolean(), anyBoolean())
} }
@Test @Test
@@ -274,7 +278,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
fgExecutor.runAllReady() fgExecutor.runAllReady()
// THEN the event is not filtered because there isn't a notification for the remote // THEN the event is not filtered because there isn't a notification for the remote
// session. // 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 @Test
@@ -291,14 +296,15 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady() bgExecutor.runAllReady()
fgExecutor.runAllReady() fgExecutor.runAllReady()
// THEN the event is not filtered // 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 // WHEN a loaded event is received that matches the local session
filter.onMediaDataLoaded(key2, null, mediaData2) filter.onMediaDataLoaded(key2, null, mediaData2)
bgExecutor.runAllReady() bgExecutor.runAllReady()
fgExecutor.runAllReady() fgExecutor.runAllReady()
// THEN the event is filtered // THEN the event is filtered
verify(mediaListener, never()) 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 // AND there should be a removed event for key2
verify(mediaListener).onMediaDataRemoved(eq(key2)) verify(mediaListener).onMediaDataRemoved(eq(key2))
} }
@@ -317,13 +323,15 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady() bgExecutor.runAllReady()
fgExecutor.runAllReady() fgExecutor.runAllReady()
// THEN the event is not filtered // 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 // WHEN a loaded event is received that matches the remote session
filter.onMediaDataLoaded(key2, null, mediaData2) filter.onMediaDataLoaded(key2, null, mediaData2)
bgExecutor.runAllReady() bgExecutor.runAllReady()
fgExecutor.runAllReady() fgExecutor.runAllReady()
// THEN the event is not filtered // 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 @Test
@@ -339,13 +347,15 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady() bgExecutor.runAllReady()
fgExecutor.runAllReady() fgExecutor.runAllReady()
// THEN the event is not filtered // 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 // WHEN a loaded event is received that matches the local session
filter.onMediaDataLoaded(KEY, null, mediaData2) filter.onMediaDataLoaded(KEY, null, mediaData2)
bgExecutor.runAllReady() bgExecutor.runAllReady()
fgExecutor.runAllReady() fgExecutor.runAllReady()
// THEN the event is not filtered // 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 @Test
@@ -363,7 +373,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady() bgExecutor.runAllReady()
fgExecutor.runAllReady() fgExecutor.runAllReady()
// THEN the event is not filtered // 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 @Test
@@ -385,7 +396,8 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady() bgExecutor.runAllReady()
fgExecutor.runAllReady() fgExecutor.runAllReady()
// THEN the key migration event is fired // 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 @Test
@@ -415,12 +427,13 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
fgExecutor.runAllReady() fgExecutor.runAllReady()
// THEN the key migration event is filtered // THEN the key migration event is filtered
verify(mediaListener, never()) 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 // WHEN a loaded event is received that matches the remote session
filter.onMediaDataLoaded(key2, null, mediaData1) filter.onMediaDataLoaded(key2, null, mediaData1)
bgExecutor.runAllReady() bgExecutor.runAllReady()
fgExecutor.runAllReady() fgExecutor.runAllReady()
// THEN the key migration event is fired // 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))
} }
} }