Merge "Fix Smartspace media logging bugs" into sc-v2-dev

This commit is contained in:
Jieru Shi
2021-12-01 18:57:51 +00:00
committed by Android (Google) Code Review
17 changed files with 288 additions and 199 deletions

View File

@@ -37,7 +37,7 @@ import javax.inject.Provider
private const val TAG = "MediaCarouselController"
private val settingsIntent = Intent().setAction(ACTION_MEDIA_CONTROLS_SETTINGS)
private const val DEBUG = false
private val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
/**
* Class that is responsible for keeping the view carousel up to date.
@@ -209,41 +209,56 @@ class MediaCarouselController @Inject constructor(
oldKey: String?,
data: MediaData,
immediately: Boolean,
isSsReactivated: Boolean
receivedSmartspaceCardLatency: Int
) {
if (addOrUpdatePlayer(key, oldKey, data)) {
// Log card received if a new resumable media card is added
MediaPlayerData.getMediaPlayer(key)?.let {
/* ktlint-disable max-line-length */
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
it.mInstanceId,
it.mUid,
/* isRecommendationCard */ false,
it.surfaceForSmartspaceLogging,
intArrayOf(
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN),
rank = MediaPlayerData.getMediaPlayerIndex(key))
/* ktlint-disable max-line-length */
}
}
if (isSsReactivated) {
// If resumable media is reactivated by headphone connection, update instance
// id for each card and log a receive event.
if (mediaCarouselScrollHandler.visibleToUser &&
mediaCarouselScrollHandler.visibleMediaIndex
== MediaPlayerData.getMediaPlayerIndex(key)) {
logSmartspaceImpression(mediaCarouselScrollHandler.qsExpanded)
}
} else if (receivedSmartspaceCardLatency != 0) {
// Log resume card received if resumable media card is reactivated and
// resume card is ranked first
MediaPlayerData.players().forEachIndexed { index, it ->
if (it.recommendationViewHolder == null) {
it.mInstanceId = SmallHash.hash(it.mUid +
systemClock.currentTimeMillis().toInt())
it.mIsImpressed = false
/* ktlint-disable max-line-length */
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
it.mInstanceId,
it.mUid,
/* isRecommendationCard */ false,
it.surfaceForSmartspaceLogging,
rank = index)
intArrayOf(
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN),
rank = index,
receivedLatencyMillis = receivedSmartspaceCardLatency)
/* ktlint-disable max-line-length */
}
}
// If media container area already visible to the user, log impression for
// reactivated card.
if (mediaCarouselScrollHandler.visibleToUser &&
!mediaCarouselScrollHandler.qsExpanded) {
logSmartspaceImpression(mediaCarouselScrollHandler.qsExpanded)
}
}
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
@@ -262,28 +277,51 @@ class MediaCarouselController @Inject constructor(
override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceMediaData,
shouldPrioritize: Boolean
shouldPrioritize: Boolean,
isSsReactivated: Boolean
) {
if (DEBUG) Log.d(TAG, "Loading Smartspace media update")
if (data.isActive) {
if (isSsReactivated && shouldPrioritize) {
// Log resume card received if resumable media card is reactivated and
// recommendation card is valid and ranked first
MediaPlayerData.players().forEachIndexed { index, it ->
if (it.recommendationViewHolder == null) {
it.mInstanceId = SmallHash.hash(it.mUid +
systemClock.currentTimeMillis().toInt())
it.mIsImpressed = false
/* ktlint-disable max-line-length */
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
it.mInstanceId,
it.mUid,
/* isRecommendationCard */ false,
intArrayOf(
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN),
rank = index,
receivedLatencyMillis = (systemClock.currentTimeMillis() - data.headphoneConnectionTimeMillis).toInt())
/* ktlint-disable max-line-length */
}
}
}
addSmartspaceMediaRecommendations(key, data, shouldPrioritize)
MediaPlayerData.getMediaPlayer(key)?.let {
/* ktlint-disable max-line-length */
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
it.mInstanceId,
it.mUid,
/* isRecommendationCard */ true,
it.surfaceForSmartspaceLogging,
rank = MediaPlayerData.getMediaPlayerIndex(key))
if (mediaCarouselScrollHandler.visibleToUser &&
mediaCarouselScrollHandler.visibleMediaIndex ==
MediaPlayerData.getMediaPlayerIndex(key)) {
logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN
it.mInstanceId,
it.mUid,
/* isRecommendationCard */ true,
it.surfaceForSmartspaceLogging)
}
intArrayOf(
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__SHADE,
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__DISPLAY_SURFACE__LOCKSCREEN),
rank = MediaPlayerData.getMediaPlayerIndex(key),
receivedLatencyMillis = (systemClock.currentTimeMillis() - data.headphoneConnectionTimeMillis).toInt())
/* ktlint-disable max-line-length */
}
if (mediaCarouselScrollHandler.visibleToUser &&
mediaCarouselScrollHandler.visibleMediaIndex
== MediaPlayerData.getMediaPlayerIndex(key)) {
logSmartspaceImpression(mediaCarouselScrollHandler.qsExpanded)
}
} else {
onSmartspaceMediaDataRemoved(data.targetId, immediately = true)
@@ -718,7 +756,8 @@ class MediaCarouselController @Inject constructor(
mediaControlPanel.mInstanceId,
mediaControlPanel.mUid,
isRecommendationCard,
mediaControlPanel.surfaceForSmartspaceLogging)
intArrayOf(mediaControlPanel.surfaceForSmartspaceLogging))
mediaControlPanel.mIsImpressed = true
}
}
@@ -731,12 +770,15 @@ class MediaCarouselController @Inject constructor(
* instanceId
* @param uid uid for the application that media comes from
* @param isRecommendationCard whether the card is media recommendation
* @param surface which display surface the media card is on (e.g. lockscreen, shade)
* @param surfaces list of display surfaces the media card is on (e.g. lockscreen, shade) when
* the event happened
* @param interactedSubcardRank the rank for interacted media item for recommendation card, -1
* for tapping on card but not on any media item, 0 for first media item, 1 for second, etc.
* @param interactedSubcardCardinality how many media items were shown to the user when there
* is user interaction
* @param rank the rank for media card in the media carousel, starting from 0
* @param receivedLatencyMillis latency in milliseconds for card received events. E.g. latency
* between headphone connection to sysUI displays media recommendation card
*
*/
fun logSmartspaceCardReported(
@@ -744,10 +786,11 @@ class MediaCarouselController @Inject constructor(
instanceId: Int,
uid: Int,
isRecommendationCard: Boolean,
surface: Int,
surfaces: IntArray,
interactedSubcardRank: Int = 0,
interactedSubcardCardinality: Int = 0,
rank: Int = mediaCarouselScrollHandler.visibleMediaIndex
rank: Int = mediaCarouselScrollHandler.visibleMediaIndex,
receivedLatencyMillis: Int = 0
) {
// Only log media resume card when Smartspace data is available
if (!isRecommendationCard &&
@@ -756,50 +799,52 @@ class MediaCarouselController @Inject constructor(
return
}
/* ktlint-disable max-line-length */
SysUiStatsLog.write(SysUiStatsLog.SMARTSPACE_CARD_REPORTED,
eventId,
instanceId,
// Deprecated, replaced with AiAi feature type so we don't need to create logging
// card type for each new feature.
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__UNKNOWN_CARD,
surface,
rank,
mediaContent.getChildCount(),
if (isRecommendationCard)
15 // MEDIA_RECOMMENDATION
else
31, // MEDIA_RESUME
uid,
interactedSubcardRank,
interactedSubcardCardinality,
0 // received_latency_millis
)
/* ktlint-disable max-line-length */
val cardinality = mediaContent.getChildCount()
surfaces.forEach { surface ->
/* ktlint-disable max-line-length */
SysUiStatsLog.write(SysUiStatsLog.SMARTSPACE_CARD_REPORTED,
eventId,
instanceId,
// Deprecated, replaced with AiAi feature type so we don't need to create logging
// card type for each new feature.
SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__UNKNOWN_CARD,
surface,
rank,
cardinality,
if (isRecommendationCard)
15 // MEDIA_RECOMMENDATION
else
31, // MEDIA_RESUME
uid,
interactedSubcardRank,
interactedSubcardCardinality,
receivedLatencyMillis
)
/* ktlint-disable max-line-length */
if (DEBUG) {
Log.d(TAG, "Log Smartspace card event id: $eventId instance id: $instanceId" +
" surface: $surface rank: $rank cardinality: $cardinality " +
"isRecommendationCard: $isRecommendationCard uid: $uid " +
"interactedSubcardRank: $interactedSubcardRank " +
"interactedSubcardCardinality: $interactedSubcardCardinality " +
"received_latency_millis: $receivedLatencyMillis")
}
}
}
private fun onSwipeToDismiss() {
val recommendation = MediaPlayerData.players().filter {
it.recommendationViewHolder != null
}
// Use -1 as rank value to indicate user swipe to dismiss the card
if (!recommendation.isEmpty()) {
logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
recommendation.get(0).mInstanceId,
recommendation.get(0).mUid,
true,
recommendation.get(0).surfaceForSmartspaceLogging,
rank = -1)
} else {
val visibleMediaIndex = mediaCarouselScrollHandler.visibleMediaIndex
if (MediaPlayerData.players().size > visibleMediaIndex) {
val player = MediaPlayerData.players().elementAt(visibleMediaIndex)
MediaPlayerData.players().forEachIndexed {
index, it ->
if (it.mIsImpressed) {
logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
player.mInstanceId,
player.mUid,
false,
player.surfaceForSmartspaceLogging,
it.mInstanceId,
it.mUid,
it.recommendationViewHolder != null,
intArrayOf(it.surfaceForSmartspaceLogging),
// Use -1 as rank value to indicate user swipe to dismiss the card
rank = -1)
// Reset card impressed state when swipe to dismissed
it.mIsImpressed = false
}
}
mediaManager.onSwipeToDismiss()

View File

@@ -59,6 +59,7 @@ import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.statusbar.phone.KeyguardDismissUtil;
import com.android.systemui.util.animation.TransitionLayout;
import com.android.systemui.util.time.SystemClock;
import java.net.URISyntaxException;
import java.util.List;
@@ -121,6 +122,9 @@ public class MediaControlPanel {
private MediaCarouselController mMediaCarouselController;
private final MediaOutputDialogFactory mMediaOutputDialogFactory;
private final FalsingManager mFalsingManager;
// Used for swipe-to-dismiss logging.
protected boolean mIsImpressed = false;
private SystemClock mSystemClock;
/**
* Initialize a new control panel
@@ -134,7 +138,7 @@ public class MediaControlPanel {
SeekBarViewModel seekBarViewModel, Lazy<MediaDataManager> lazyMediaDataManager,
KeyguardDismissUtil keyguardDismissUtil, MediaOutputDialogFactory
mediaOutputDialogFactory, MediaCarouselController mediaCarouselController,
FalsingManager falsingManager) {
FalsingManager falsingManager, SystemClock systemClock) {
mContext = context;
mBackgroundExecutor = backgroundExecutor;
mActivityStarter = activityStarter;
@@ -145,6 +149,8 @@ public class MediaControlPanel {
mMediaOutputDialogFactory = mediaOutputDialogFactory;
mMediaCarouselController = mediaCarouselController;
mFalsingManager = falsingManager;
mSystemClock = systemClock;
loadDimens();
mSeekBarViewModel.setLogSmartspaceClick(() -> {
@@ -291,7 +297,10 @@ public class MediaControlPanel {
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG, "Unable to look up package name", e);
}
mInstanceId = SmallHash.hash(mUid);
// Only assigns instance id if it's unassigned.
if (mInstanceId == -1) {
mInstanceId = SmallHash.hash(mUid + (int) mSystemClock.currentTimeMillis());
}
mBackgroundColor = data.getBackgroundColor();
if (mToken == null || !mToken.equals(token)) {
@@ -885,7 +894,7 @@ public class MediaControlPanel {
mInstanceId,
mUid,
isRecommendationCard,
getSurfaceForSmartspaceLogging(),
new int[]{getSurfaceForSmartspaceLogging()},
interactedSubcardRank,
interactedSubcardCardinality);
}

View File

@@ -32,7 +32,7 @@ class MediaDataCombineLatest @Inject constructor() : MediaDataManager.Listener,
oldKey: String?,
data: MediaData,
immediately: Boolean,
isSsReactivated: Boolean
receivedSmartspaceCardLatency: Int
) {
if (oldKey != null && oldKey != key && entries.contains(oldKey)) {
entries[key] = data to entries.remove(oldKey)?.second
@@ -46,7 +46,8 @@ class MediaDataCombineLatest @Inject constructor() : MediaDataManager.Listener,
override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceMediaData,
shouldPrioritize: Boolean
shouldPrioritize: Boolean,
isSsReactivated: Boolean
) {
listeners.toSet().forEach { it.onSmartspaceMediaDataLoaded(key, data) }
}

View File

@@ -56,7 +56,6 @@ internal val SMARTSPACE_MAX_AGE = SystemProperties
class MediaDataFilter @Inject constructor(
private val context: Context,
private val broadcastDispatcher: BroadcastDispatcher,
private val mediaResumeListener: MediaResumeListener,
private val lockscreenUserManager: NotificationLockscreenUserManager,
@Main private val executor: Executor,
private val systemClock: SystemClock
@@ -88,7 +87,7 @@ class MediaDataFilter @Inject constructor(
oldKey: String?,
data: MediaData,
immediately: Boolean,
isSsReactivated: Boolean
receivedSmartspaceCardLatency: Int
) {
if (oldKey != null && oldKey != key) {
allEntries.remove(oldKey)
@@ -106,14 +105,15 @@ class MediaDataFilter @Inject constructor(
// Notify listeners
listeners.forEach {
it.onMediaDataLoaded(key, oldKey, data, isSsReactivated = isSsReactivated)
it.onMediaDataLoaded(key, oldKey, data)
}
}
override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceMediaData,
shouldPrioritize: Boolean
shouldPrioritize: Boolean,
isSsReactivated: Boolean
) {
if (!data.isActive) {
Log.d(TAG, "Inactive recommendation data. Skip triggering.")
@@ -123,8 +123,6 @@ 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 {
@@ -139,18 +137,25 @@ class MediaDataFilter @Inject constructor(
smartspaceMaxAgeMillis = TimeUnit.SECONDS.toMillis(smartspaceMaxAgeSeconds)
}
}
val activeMedia = userEntries.filter { (key, value) -> value.active }
var isSsReactivatedMutable = activeMedia.isEmpty() && userEntries.isNotEmpty()
if (timeSinceActive < smartspaceMaxAgeMillis) {
val lastActiveKey = sorted.lastKey() // most recently active
// 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,
isSsReactivated = isSsReactivated)
// It could happen there are existing active media resume cards, then we don't need to
// reactivate.
if (isSsReactivatedMutable) {
val lastActiveKey = sorted.lastKey() // most recently active
// Notify listeners to consider this media active
Log.d(TAG, "reactivating $lastActiveKey instead of smartspace")
reactivatedKey = lastActiveKey
val mediaData = sorted.get(lastActiveKey)!!.copy(active = true)
listeners.forEach {
it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData,
receivedSmartspaceCardLatency =
(systemClock.currentTimeMillis() - data.headphoneConnectionTimeMillis)
.toInt())
}
}
} else {
// Mark to prioritize Smartspace card if no recent media.
@@ -161,7 +166,8 @@ class MediaDataFilter @Inject constructor(
Log.d(TAG, "Invalid recommendation data. Skip showing the rec card")
return
}
listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data, shouldPrioritizeMutable) }
listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data, shouldPrioritizeMutable,
isSsReactivatedMutable) }
}
override fun onMediaDataRemoved(key: String) {

View File

@@ -84,7 +84,7 @@ private val LOADING = MediaData(-1, false, 0, null, null, null, null, null,
emptyList(), emptyList(), "INVALID", null, null, null, true, null)
@VisibleForTesting
internal val EMPTY_SMARTSPACE_MEDIA_DATA = SmartspaceMediaData("INVALID", false, false,
"INVALID", null, emptyList(), null, 0)
"INVALID", null, emptyList(), null, 0, 0)
fun isMediaNotification(sbn: StatusBarNotification): Boolean {
return sbn.notification.isMediaNotification()
@@ -852,15 +852,16 @@ class MediaDataManager(
* 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.
* @param receivedSmartspaceCardLatency is the latency between headphone connects and sysUI
* displays Smartspace media targets. Will be 0 if the data is not activated by Smartspace
* signal.
*/
fun onMediaDataLoaded(
key: String,
oldKey: String?,
data: MediaData,
immediately: Boolean = true,
isSsReactivated: Boolean = false
receivedSmartspaceCardLatency: Int = 0
) {}
/**
@@ -869,11 +870,15 @@ class MediaDataManager(
* @param shouldPrioritize indicates the sorting priority of the Smartspace card. If true,
* it will be prioritized as the first card. Otherwise, it will show up as the last card as
* default.
*
* @param isSsReactivated indicates resume media card is reactivated by Smartspace
* recommendation signal
*/
fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceMediaData,
shouldPrioritize: Boolean = false
shouldPrioritize: Boolean = false,
isSsReactivated: Boolean = false
) {}
/** Called whenever a previously existing Media notification was removed. */
@@ -909,12 +914,13 @@ class MediaDataManager(
packageName(target)?.let {
return SmartspaceMediaData(target.smartspaceTargetId, isActive, true, it,
target.baseAction, target.iconGrid,
dismissIntent, 0)
dismissIntent, 0, target.creationTimeMillis)
}
return EMPTY_SMARTSPACE_MEDIA_DATA
.copy(targetId = target.smartspaceTargetId,
isActive = isActive,
dismissIntent = dismissIntent)
isActive = isActive,
dismissIntent = dismissIntent,
headphoneConnectionTimeMillis = target.creationTimeMillis)
}
private fun packageName(target: SmartspaceTarget): String? {

View File

@@ -68,7 +68,7 @@ class MediaDeviceManager @Inject constructor(
oldKey: String?,
data: MediaData,
immediately: Boolean,
isSsReactivated: Boolean
receivedSmartspaceCardLatency: Int
) {
if (oldKey != null && oldKey != key) {
val oldEntry = entries.remove(oldKey)
@@ -200,7 +200,7 @@ class MediaDeviceManager @Inject constructor(
@WorkerThread
private fun updateCurrent() {
val device = localMediaManager.currentConnectedDevice
val route = controller?.let { mr2manager.getRoutingSessionForMediaController(it)}
val route = controller?.let { mr2manager.getRoutingSessionForMediaController(it) }
// If we have a controller but get a null route, then don't trust the device
val enabled = device != null && (controller == null || route != null)

View File

@@ -61,7 +61,7 @@ class MediaHost constructor(
oldKey: String?,
data: MediaData,
immediately: Boolean,
isSsReactivated: Boolean
receivedSmartspaceCardLatency: Int
) {
if (immediately) {
updateViewVisibility()
@@ -71,7 +71,8 @@ class MediaHost constructor(
override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceMediaData,
shouldPrioritize: Boolean
shouldPrioritize: Boolean,
isSsReactivated: Boolean
) {
updateViewVisibility()
}

View File

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

View File

@@ -96,7 +96,7 @@ class MediaSessionBasedFilter @Inject constructor(
oldKey: String?,
data: MediaData,
immediately: Boolean,
isSsReactivated: Boolean
receivedSmartspaceCardLatency: Int
) {
backgroundExecutor.execute {
data.token?.let {
@@ -143,7 +143,8 @@ class MediaSessionBasedFilter @Inject constructor(
override fun onSmartspaceMediaDataLoaded(
key: String,
data: SmartspaceMediaData,
shouldPrioritize: Boolean
shouldPrioritize: Boolean,
isSsReactivated: Boolean
) {
backgroundExecutor.execute {
dispatchSmartspaceMediaDataLoaded(key, data)

View File

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

View File

@@ -52,5 +52,9 @@ data class SmartspaceMediaData(
/**
* View's background color.
*/
val backgroundColor: Int
val backgroundColor: Int,
/**
* The timestamp in milliseconds that headphone is connected.
*/
val headphoneConnectionTimeMillis: Long
)

View File

@@ -242,12 +242,13 @@ public class NotificationMediaManager implements Dumpable {
@Override
public void onMediaDataLoaded(@NonNull String key,
@Nullable String oldKey, @NonNull MediaData data, boolean immediately,
boolean isSsReactivated) {
int receivedSmartspaceCardLatency) {
}
@Override
public void onSmartspaceMediaDataLoaded(@NonNull String key,
@NonNull SmartspaceMediaData data, boolean shouldPrioritize) {
@NonNull SmartspaceMediaData data, boolean shouldPrioritize,
boolean isSsReactivated) {
}
@Override
@@ -316,12 +317,13 @@ public class NotificationMediaManager implements Dumpable {
@Override
public void onMediaDataLoaded(@NonNull String key,
@Nullable String oldKey, @NonNull MediaData data, boolean immediately,
boolean isSsReactivated) {
int receivedSmartspaceCardLatency) {
}
@Override
public void onSmartspaceMediaDataLoaded(@NonNull String key,
@NonNull SmartspaceMediaData data, boolean shouldPrioritize) {
@NonNull SmartspaceMediaData data, boolean shouldPrioritize,
boolean isSsReactivated) {
}

View File

@@ -123,6 +123,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
private lateinit var session: MediaSession
private val device = MediaDeviceData(true, null, DEVICE_NAME)
private val disabledDevice = MediaDeviceData(false, null, "Disabled Device")
private val clock = FakeSystemClock()
@JvmField @Rule val mockito = MockitoJUnit.rule()
@@ -134,7 +135,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
player = MediaControlPanel(context, bgExecutor, activityStarter, mediaViewController,
seekBarViewModel, Lazy { mediaDataManager }, keyguardDismissUtil,
mediaOutputDialogFactory, mediaCarouselController, falsingManager)
mediaOutputDialogFactory, mediaCarouselController, falsingManager, clock)
whenever(seekBarViewModel.progress).thenReturn(seekBarData)
// Mock out a view holder for the player to attach to.

View File

@@ -18,6 +18,7 @@ package com.android.systemui.media;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyBoolean;
import static org.mockito.Mockito.eq;
@@ -83,10 +84,10 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
public void eventNotEmittedWithoutDevice() {
// WHEN data source emits an event without device data
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */,
false /* isSsReactivated */);
0 /* receivedSmartspaceCardLatency */);
// THEN an event isn't emitted
verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean(),
anyBoolean());
anyInt());
}
@Test
@@ -95,7 +96,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
mManager.onMediaDeviceChanged(KEY, null, mDeviceData);
// THEN an event isn't emitted
verify(mListener, never()).onMediaDataLoaded(eq(KEY), any(), any(), anyBoolean(),
anyBoolean());
anyInt());
}
@Test
@@ -104,11 +105,11 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
mManager.onMediaDeviceChanged(KEY, null, mDeviceData);
// WHEN media event is received
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */,
false /* isSsReactivated */);
0 /* receivedSmartspaceCardLatency */);
// THEN the listener receives a combined event
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
verify(mListener).onMediaDataLoaded(eq(KEY), any(), captor.capture(), anyBoolean(),
anyBoolean());
anyInt());
assertThat(captor.getValue().getDevice()).isNotNull();
}
@@ -116,13 +117,13 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
public void emitEventAfterMediaFirst() {
// GIVEN that media event has already been received
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */,
false /* isSsReactivated */);
0 /* receivedSmartspaceCardLatency */);
// 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(),
anyBoolean());
anyInt());
assertThat(captor.getValue().getDevice()).isNotNull();
}
@@ -130,16 +131,16 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
public void migrateKeyMediaFirst() {
// GIVEN that media and device info has already been received
mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */,
false /* isSsReactivated */);
0 /* receivedSmartspaceCardLatency */);
mManager.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
reset(mListener);
// WHEN a key migration event is received
mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */,
false /* isSsReactivated */);
0 /* receivedSmartspaceCardLatency */);
// 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(),
anyBoolean());
anyInt());
assertThat(captor.getValue().getDevice()).isNotNull();
}
@@ -147,7 +148,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
public void migrateKeyDeviceFirst() {
// GIVEN that media and device info has already been received
mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */,
false /* isSsReactivated */);
0 /* receivedSmartspaceCardLatency */);
mManager.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
reset(mListener);
// WHEN a key migration event is received
@@ -155,7 +156,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
// 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(),
anyBoolean());
anyInt());
assertThat(captor.getValue().getDevice()).isNotNull();
}
@@ -163,17 +164,17 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
public void migrateKeyMediaAfter() {
// GIVEN that media and device info has already been received
mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */,
false /* isSsReactivated */);
0 /* receivedSmartspaceCardLatency */);
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 */,
false /* isSsReactivated */);
0 /* receivedSmartspaceCardLatency */);
// THEN the key has already been migrated
ArgumentCaptor<MediaData> captor = ArgumentCaptor.forClass(MediaData.class);
verify(mListener).onMediaDataLoaded(eq(KEY), eq(KEY), captor.capture(), anyBoolean(),
anyBoolean());
anyInt());
assertThat(captor.getValue().getDevice()).isNotNull();
}
@@ -181,17 +182,17 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
public void migrateKeyDeviceAfter() {
// GIVEN that media and device info has already been received
mManager.onMediaDataLoaded(OLD_KEY, null, mMediaData, true /* immediately */,
false /* isSsReactivated */);
0 /* receivedSmartspaceCardLatency */);
mManager.onMediaDeviceChanged(OLD_KEY, null, mDeviceData);
mManager.onMediaDataLoaded(KEY, OLD_KEY, mMediaData, true /* immediately */,
false /* isSsReactivated */);
0 /* receivedSmartspaceCardLatency */);
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(),
anyBoolean());
anyInt());
assertThat(captor.getValue().getDevice()).isNotNull();
}
@@ -206,7 +207,7 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
@Test
public void mediaDataRemovedAfterMediaEvent() {
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */,
false /* isSsReactivated */);
0 /* receivedSmartspaceCardLatency */);
mManager.onMediaDataRemoved(KEY);
verify(mListener).onMediaDataRemoved(eq(KEY));
}
@@ -222,14 +223,14 @@ public class MediaDataCombineLatestTest extends SysuiTestCase {
public void mediaDataKeyUpdated() {
// GIVEN that device and media events have already been received
mManager.onMediaDataLoaded(KEY, null, mMediaData, true /* immediately */,
false /* isSsReactivated */);
0 /* receivedSmartspaceCardLatency */);
mManager.onMediaDeviceChanged(KEY, null, mDeviceData);
// WHEN the key is changed
mManager.onMediaDataLoaded("NEW_KEY", KEY, mMediaData, true /* immediately */,
false /* isSsReactivated */);
0 /* receivedSmartspaceCardLatency */);
// 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(), anyBoolean());
eq("NEW_KEY"), any(), captor.capture(), anyBoolean(), anyInt());
}
}

View File

@@ -87,7 +87,7 @@ class MediaDataFilterTest : SysuiTestCase() {
fun setup() {
MockitoAnnotations.initMocks(this)
MediaPlayerData.clear()
mediaDataFilter = MediaDataFilter(context, broadcastDispatcher, mediaResumeListener,
mediaDataFilter = MediaDataFilter(context, broadcastDispatcher,
lockscreenUserManager, executor, clock)
mediaDataFilter.mediaDataManager = mediaDataManager
mediaDataFilter.addListener(listener)
@@ -107,6 +107,8 @@ class MediaDataFilterTest : SysuiTestCase() {
`when`(smartspaceData.isValid).thenReturn(true)
`when`(smartspaceData.packageName).thenReturn(PACKAGE)
`when`(smartspaceData.recommendations).thenReturn(listOf(smartspaceMediaRecommendationItem))
`when`(smartspaceData.headphoneConnectionTimeMillis).thenReturn(
clock.currentTimeMillis() - 100)
}
private fun setUser(id: Int) {
@@ -122,7 +124,7 @@ class MediaDataFilterTest : SysuiTestCase() {
// THEN we should tell the listener
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataMain), eq(true),
eq(false))
eq(0))
}
@Test
@@ -131,7 +133,7 @@ class MediaDataFilterTest : SysuiTestCase() {
mediaDataFilter.onMediaDataLoaded(KEY, null, dataGuest)
// THEN we should NOT tell the listener
verify(listener, never()).onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyBoolean())
verify(listener, never()).onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt())
}
@Test
@@ -178,11 +180,11 @@ class MediaDataFilterTest : SysuiTestCase() {
// THEN we should add back the guest user media
verify(listener).onMediaDataLoaded(eq(KEY_ALT), eq(null), eq(dataGuest), eq(true),
eq(false))
eq(0))
// but not the main user's
verify(listener, never()).onMediaDataLoaded(eq(KEY), any(), eq(dataMain), anyBoolean(),
anyBoolean())
anyInt())
}
@Test
@@ -239,7 +241,8 @@ class MediaDataFilterTest : SysuiTestCase() {
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
verify(listener)
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true))
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true),
eq(false))
assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
}
@@ -249,8 +252,9 @@ class MediaDataFilterTest : SysuiTestCase() {
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
verify(listener, never()).onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyBoolean())
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
verify(listener, never()).onMediaDataLoaded(any(), any(), any(), anyBoolean(), anyInt())
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean(),
anyBoolean())
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
}
@@ -262,7 +266,8 @@ class MediaDataFilterTest : SysuiTestCase() {
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
verify(listener)
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true))
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true),
eq(true))
assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
}
@@ -275,7 +280,8 @@ class MediaDataFilterTest : SysuiTestCase() {
clock.advanceTime(SMARTSPACE_MAX_AGE + 100)
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean(),
anyBoolean())
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
}
@@ -287,15 +293,16 @@ class MediaDataFilterTest : SysuiTestCase() {
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))
eq(0))
// AND we get a smartspace signal
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
// THEN we should tell listeners to treat the media as not active instead
verify(listener, never()).onMediaDataLoaded(eq(KEY), eq(KEY), any(), anyBoolean(),
anyInt())
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean(),
anyBoolean())
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
}
@@ -307,7 +314,7 @@ class MediaDataFilterTest : SysuiTestCase() {
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))
eq(0))
// AND we get a smartspace signal
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
@@ -315,10 +322,11 @@ class MediaDataFilterTest : SysuiTestCase() {
// 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),
eq(true))
eq(100))
assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
// 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(),
anyBoolean())
}
@Test
@@ -327,7 +335,7 @@ class MediaDataFilterTest : SysuiTestCase() {
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))
eq(0))
// AND we get a smartspace signal
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
@@ -335,11 +343,12 @@ class MediaDataFilterTest : SysuiTestCase() {
// 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),
eq(true))
eq(100))
assertThat(mediaDataFilter.hasActiveMedia()).isTrue()
// Smartspace update should also be propagated but not prioritized.
verify(listener)
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false),
eq(true))
}
@Test
@@ -356,13 +365,13 @@ class MediaDataFilterTest : SysuiTestCase() {
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))
eq(0))
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
val dataCurrentAndActive = dataCurrent.copy(active = true)
verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), eq(dataCurrentAndActive), eq(true),
eq(true))
eq(100))
mediaDataFilter.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY)

View File

@@ -160,6 +160,7 @@ class MediaDataManagerTest : SysuiTestCase() {
whenever(mediaSmartspaceTarget.smartspaceTargetId).thenReturn(KEY_MEDIA_SMARTSPACE)
whenever(mediaSmartspaceTarget.featureType).thenReturn(SmartspaceTarget.FEATURE_MEDIA)
whenever(mediaSmartspaceTarget.iconGrid).thenReturn(listOf(mediaRecommendationItem))
whenever(mediaSmartspaceTarget.creationTimeMillis).thenReturn(1234L)
}
@After
@@ -213,7 +214,7 @@ class MediaDataManagerTest : SysuiTestCase() {
mediaDataManager.onNotificationAdded(KEY, mediaNotification)
mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = mock(MediaData::class.java))
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), anyObject(), eq(true),
eq(false))
eq(0))
}
@Test
@@ -225,7 +226,7 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
eq(false))
eq(0))
assertThat(mediaDataCaptor.value!!.active).isTrue()
}
@@ -248,7 +249,7 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
eq(false))
eq(0))
assertThat(mediaDataCaptor.value!!.playbackLocation).isEqualTo(
MediaData.PLAYBACK_CAST_REMOTE)
}
@@ -269,7 +270,7 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
eq(false))
eq(0))
val data = mediaDataCaptor.value
assertThat(data.resumption).isFalse()
mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
@@ -278,7 +279,7 @@ class MediaDataManagerTest : SysuiTestCase() {
// THEN the media data indicates that it is for resumption
verify(listener)
.onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true),
eq(false))
eq(0))
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.isPlaying).isFalse()
}
@@ -293,7 +294,7 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(foregroundExecutor.runAllReady()).isEqualTo(2)
verify(listener)
.onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
eq(false))
eq(0))
val data = mediaDataCaptor.value
assertThat(data.resumption).isFalse()
val resumableData = data.copy(resumeAction = Runnable {})
@@ -305,7 +306,7 @@ class MediaDataManagerTest : SysuiTestCase() {
// 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),
eq(false))
eq(0))
assertThat(mediaDataCaptor.value.resumption).isTrue()
verify(listener, never()).onMediaDataRemoved(eq(KEY))
// WHEN the second is removed
@@ -314,7 +315,7 @@ class MediaDataManagerTest : SysuiTestCase() {
verify(listener)
.onMediaDataLoaded(
eq(PACKAGE_NAME), eq(PACKAGE_NAME), capture(mediaDataCaptor), eq(true),
eq(false))
eq(0))
assertThat(mediaDataCaptor.value.resumption).isTrue()
verify(listener).onMediaDataRemoved(eq(KEY_2))
}
@@ -329,7 +330,7 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
eq(false))
eq(0))
val data = mediaDataCaptor.value
val dataRemoteWithResume = data.copy(resumeAction = Runnable {},
playbackLocation = MediaData.PLAYBACK_CAST_LOCAL)
@@ -357,7 +358,7 @@ class MediaDataManagerTest : SysuiTestCase() {
// THEN the media data indicates that it is for resumption
verify(listener)
.onMediaDataLoaded(eq(PACKAGE_NAME), eq(null), capture(mediaDataCaptor), eq(true),
eq(false))
eq(0))
val data = mediaDataCaptor.value
assertThat(data.resumption).isTrue()
assertThat(data.song).isEqualTo(SESSION_TITLE)
@@ -405,7 +406,7 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener)
.onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
eq(false))
eq(0))
}
@Test
@@ -415,8 +416,8 @@ class MediaDataManagerTest : SysuiTestCase() {
eq(KEY_MEDIA_SMARTSPACE),
eq(SmartspaceMediaData(KEY_MEDIA_SMARTSPACE, true /* isActive */, true /*isValid */,
PACKAGE_NAME, mediaSmartspaceBaseAction, listOf(mediaRecommendationItem),
DISMISS_INTENT, 0)),
eq(false))
DISMISS_INTENT, 0, 1234L)),
eq(false), eq(false))
}
@Test
@@ -427,8 +428,9 @@ class MediaDataManagerTest : SysuiTestCase() {
eq(KEY_MEDIA_SMARTSPACE),
eq(EMPTY_SMARTSPACE_MEDIA_DATA
.copy(targetId = KEY_MEDIA_SMARTSPACE, isActive = true,
isValid = false, dismissIntent = DISMISS_INTENT)),
eq(false))
isValid = false, dismissIntent = DISMISS_INTENT,
headphoneConnectionTimeMillis = 1234L)),
eq(false), eq(false))
}
@Test
@@ -447,15 +449,15 @@ class MediaDataManagerTest : SysuiTestCase() {
eq(KEY_MEDIA_SMARTSPACE),
eq(EMPTY_SMARTSPACE_MEDIA_DATA
.copy(targetId = KEY_MEDIA_SMARTSPACE, isActive = true,
isValid = false, dismissIntent = null)),
eq(false))
isValid = false, dismissIntent = null, headphoneConnectionTimeMillis = 1234L)),
eq(false), eq(false))
}
@Test
fun testOnSmartspaceMediaDataLoaded_hasNoneMediaTarget_notCallsListener() {
smartspaceMediaDataProvider.onTargetsAvailable(listOf())
verify(listener, never())
.onSmartspaceMediaDataLoaded(anyObject(), anyObject(), anyBoolean())
.onSmartspaceMediaDataLoaded(anyObject(), anyObject(), anyBoolean(), anyBoolean())
}
@Test
@@ -479,7 +481,7 @@ class MediaDataManagerTest : SysuiTestCase() {
// THEN smartspace signal is ignored
verify(listener, never())
.onSmartspaceMediaDataLoaded(anyObject(), anyObject(), anyBoolean())
.onSmartspaceMediaDataLoaded(anyObject(), anyObject(), anyBoolean(), anyBoolean())
}
@Test
@@ -487,7 +489,7 @@ class MediaDataManagerTest : SysuiTestCase() {
// GIVEN a media recommendation card is present
smartspaceMediaDataProvider.onTargetsAvailable(listOf(mediaSmartspaceTarget))
verify(listener).onSmartspaceMediaDataLoaded(eq(KEY_MEDIA_SMARTSPACE), anyObject(),
anyBoolean())
anyBoolean(), anyBoolean())
// WHEN the media recommendation setting is turned off
Settings.Secure.putInt(context.contentResolver,
@@ -507,7 +509,7 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
eq(false))
eq(0))
assertThat(mediaDataCaptor.value!!.lastActive).isAtLeast(currentTime)
}
@@ -525,7 +527,7 @@ class MediaDataManagerTest : SysuiTestCase() {
// THEN the last active time is not changed
verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), capture(mediaDataCaptor), eq(true),
eq(false))
eq(0))
assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime)
}
@@ -537,7 +539,7 @@ class MediaDataManagerTest : SysuiTestCase() {
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
eq(false))
eq(0))
val data = mediaDataCaptor.value
assertThat(data.resumption).isFalse()
mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
@@ -550,7 +552,7 @@ class MediaDataManagerTest : SysuiTestCase() {
// THEN the last active time is not changed
verify(listener)
.onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor), eq(true),
eq(false))
eq(0))
assertThat(mediaDataCaptor.value.resumption).isTrue()
assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime)
}
@@ -577,7 +579,7 @@ class MediaDataManagerTest : SysuiTestCase() {
// THEN only the first MAX_COMPACT_ACTIONS are actually set
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor), eq(true),
eq(false))
eq(0))
assertThat(mediaDataCaptor.value.actionsToShowInCompact.size).isEqualTo(
MediaDataManager.MAX_COMPACT_ACTIONS)
}

View File

@@ -37,6 +37,7 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers.anyBoolean
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.any
@@ -186,7 +187,7 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
bgExecutor.runAllReady()
fgExecutor.runAllReady()
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
eq(false))
eq(0))
}
@Test
@@ -209,7 +210,7 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
fgExecutor.runAllReady()
// THEN the event is not filtered
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
eq(false))
eq(0))
}
@Test
@@ -239,7 +240,7 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
fgExecutor.runAllReady()
// THEN the event is not filtered
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
eq(false))
eq(0))
}
@Test
@@ -255,14 +256,14 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
fgExecutor.runAllReady()
// THEN the event is not filtered
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
eq(false))
eq(0))
// 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(), anyBoolean())
eq(KEY), eq(null), eq(mediaData2), anyBoolean(), anyInt())
}
@Test
@@ -279,7 +280,7 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
// 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),
eq(false))
eq(0))
}
@Test
@@ -297,14 +298,14 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
fgExecutor.runAllReady()
// THEN the event is not filtered
verify(mediaListener).onMediaDataLoaded(eq(key1), eq(null), eq(mediaData1), eq(true),
eq(false))
eq(0))
// 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(), anyBoolean())
.onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), anyBoolean(), anyInt())
// AND there should be a removed event for key2
verify(mediaListener).onMediaDataRemoved(eq(key2))
}
@@ -324,14 +325,14 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
fgExecutor.runAllReady()
// THEN the event is not filtered
verify(mediaListener).onMediaDataLoaded(eq(key1), eq(null), eq(mediaData1), eq(true),
eq(false))
eq(0))
// 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),
eq(false))
eq(0))
}
@Test
@@ -348,14 +349,14 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
fgExecutor.runAllReady()
// THEN the event is not filtered
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
eq(false))
eq(0))
// 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),
eq(false))
eq(0))
}
@Test
@@ -374,7 +375,7 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
fgExecutor.runAllReady()
// THEN the event is not filtered
verify(mediaListener).onMediaDataLoaded(eq(KEY), eq(null), eq(mediaData1), eq(true),
eq(false))
eq(0))
}
@Test
@@ -397,7 +398,7 @@ public class MediaSessionBasedFilterTest : SysuiTestCase() {
fgExecutor.runAllReady()
// THEN the key migration event is fired
verify(mediaListener).onMediaDataLoaded(eq(key2), eq(key1), eq(mediaData2), eq(true),
eq(false))
eq(0))
}
@Test
@@ -427,13 +428,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(), anyBoolean())
.onMediaDataLoaded(eq(key2), eq(null), eq(mediaData2), anyBoolean(), anyInt())
// 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),
eq(false))
eq(0))
}
}