Media impression logging bug fix

1. Remove redundant LS impressions: Bouncer->LS, Shade LS->LS (User has to visit LS first in order to visit Bouncer and Shade LS)
2. Remove extra impression when user is on second media card, tap to app
or turn off screen (previously there will be an impression logged for
first media card)
3. Fix logging for resumption media card, previously they were not
logged.
4. Fix impression logging for reactivated media card when user connect headphone on
QQS, previously they were not logged
5. Use SmallHash to compute instanceid according to b/190640624
6. Remove media resume card logging when Smartspace data is not
available

Bug: 181364757
Test: manual
Change-Id: I6e2e7bc00ecd3f21fefedb2c47315b1e85e5beeb
This commit is contained in:
Jieru Shi
2021-05-25 17:21:53 -07:00
parent 60ec24eb1e
commit 594551f419
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 {
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
}
}

View File

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

View File

@@ -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));

View File

@@ -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

View File

@@ -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.

View File

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

View File

@@ -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)

View File

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

View File

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

View File

@@ -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

View File

@@ -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 {

View File

@@ -54,7 +54,8 @@ class MediaTimeoutListener @Inject constructor(
key: String,
oldKey: String?,
data: MediaData,
immediately: Boolean
immediately: Boolean,
isSsReactivated: Boolean
) {
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() {
@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

View File

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

View File

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

View File

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

View File

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