Merge changes from topic "presubmit-am-32f14c30420c44f88650ca750b09d4d7" into tm-mainline-prod

* changes:
  [automerge] Add logging for media recommendation events 2p: f000c437a8
  Add logging for media recommendation events
This commit is contained in:
Beth Thibodeau
2022-04-11 15:36:17 +00:00
committed by Android (Google) Code Review
10 changed files with 367 additions and 60 deletions

View File

@@ -508,6 +508,11 @@ class MediaCarouselController @Inject constructor(
dismissMediaData: Boolean = true,
dismissRecommendation: Boolean = true
) {
if (key == MediaPlayerData.smartspaceMediaKey()) {
MediaPlayerData.smartspaceMediaData?.let {
logger.logRecommendationRemoved(it.packageName, it.instanceId)
}
}
val removed = MediaPlayerData.removeMediaPlayer(key)
removed?.apply {
mediaCarouselScrollHandler.onPrePlayerRemoved(removed)

View File

@@ -331,6 +331,7 @@ public class MediaControlPanel {
});
mRecommendationViewHolder.getSettings().setOnClickListener(v -> {
if (!mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
mLogger.logLongPressSettings(mUid, mPackageName, mInstanceId);
mActivityStarter.startActivity(SETTINGS_INTENT, true /* dismissShade */);
}
});
@@ -940,6 +941,8 @@ public class MediaControlPanel {
mSmartspaceId = SmallHash.hash(data.getTargetId());
mBackgroundColor = data.getBackgroundColor();
mPackageName = data.getPackageName();
mInstanceId = data.getInstanceId();
TransitionLayout recommendationCard = mRecommendationViewHolder.getRecommendations();
recommendationCard.setBackgroundTintList(ColorStateList.valueOf(mBackgroundColor));
@@ -1068,6 +1071,7 @@ public class MediaControlPanel {
mRecommendationViewHolder.getDismiss().setOnClickListener(v -> {
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
mLogger.logLongPressDismiss(mUid, mPackageName, mInstanceId);
logSmartspaceCardReported(
761 // SMARTSPACE_CARD_DISMISS
);
@@ -1204,6 +1208,11 @@ public class MediaControlPanel {
view.setOnClickListener(v -> {
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
if (interactedSubcardRank == -1) {
mLogger.logRecommendationCardTap(mPackageName, mInstanceId);
} else {
mLogger.logRecommendationItemTap(mPackageName, mInstanceId, interactedSubcardRank);
}
logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT,
interactedSubcardRank,
getSmartspaceSubCardCardinality());

View File

@@ -60,7 +60,8 @@ class MediaDataFilter @Inject constructor(
private val broadcastSender: BroadcastSender,
private val lockscreenUserManager: NotificationLockscreenUserManager,
@Main private val executor: Executor,
private val systemClock: SystemClock
private val systemClock: SystemClock,
private val logger: MediaUiEventLogger
) : MediaDataManager.Listener {
private val userTracker: CurrentUserTracker
private val _listeners: MutableSet<MediaDataManager.Listener> = mutableSetOf()
@@ -151,6 +152,8 @@ class MediaDataFilter @Inject constructor(
Log.d(TAG, "reactivating $lastActiveKey instead of smartspace")
reactivatedKey = lastActiveKey
val mediaData = sorted.get(lastActiveKey)!!.copy(active = true)
logger.logRecommendationActivated(mediaData.appUid, mediaData.packageName,
mediaData.instanceId)
listeners.forEach {
it.onMediaDataLoaded(lastActiveKey, lastActiveKey, mediaData,
receivedSmartspaceCardLatency =
@@ -167,6 +170,8 @@ class MediaDataFilter @Inject constructor(
Log.d(TAG, "Invalid recommendation data. Skip showing the rec card")
return
}
logger.logRecommendationAdded(smartspaceMediaData.packageName,
smartspaceMediaData.instanceId)
listeners.forEach { it.onSmartspaceMediaDataLoaded(key, data, shouldPrioritizeMutable) }
}
@@ -197,7 +202,9 @@ class MediaDataFilter @Inject constructor(
if (smartspaceMediaData.isActive) {
smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
targetId = smartspaceMediaData.targetId, isValid = smartspaceMediaData.isValid)
targetId = smartspaceMediaData.targetId,
isValid = smartspaceMediaData.isValid,
instanceId = smartspaceMediaData.instanceId)
}
listeners.forEach { it.onSmartspaceMediaDataRemoved(key, immediately) }
}
@@ -252,9 +259,12 @@ class MediaDataFilter @Inject constructor(
broadcastSender.sendBroadcast(dismissIntent)
}
smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
targetId = smartspaceMediaData.targetId, isValid = smartspaceMediaData.isValid)
targetId = smartspaceMediaData.targetId,
isValid = smartspaceMediaData.isValid,
instanceId = smartspaceMediaData.instanceId)
mediaDataManager.dismissSmartspaceRecommendation(smartspaceMediaData.targetId,
delay = 0L)
}
mediaDataManager.dismissSmartspaceRecommendation(smartspaceMediaData.targetId, delay = 0L)
}
/**

View File

@@ -103,8 +103,17 @@ private val LOADING = MediaData(
appUid = Process.INVALID_UID)
@VisibleForTesting
internal val EMPTY_SMARTSPACE_MEDIA_DATA = SmartspaceMediaData("INVALID", false, false,
"INVALID", null, emptyList(), null, 0, 0)
internal val EMPTY_SMARTSPACE_MEDIA_DATA = SmartspaceMediaData(
targetId = "INVALID",
isActive = false,
isValid = false,
packageName = "INVALID",
cardAction = null,
recommendations = emptyList(),
dismissIntent = null,
backgroundColor = 0,
headphoneConnectionTimeMillis = 0,
instanceId = InstanceId.fakeInstanceId(-1))
fun isMediaNotification(sbn: StatusBarNotification): Boolean {
return sbn.notification.isMediaNotification()
@@ -532,14 +541,16 @@ class MediaDataManager(
* connection session.
*/
fun dismissSmartspaceRecommendation(key: String, delay: Long) {
if (smartspaceMediaData.targetId != key) {
if (smartspaceMediaData.targetId != key || !smartspaceMediaData.isValid) {
// If this doesn't match, or we've already invalidated the data, no action needed
return
}
if (DEBUG) Log.d(TAG, "Dismissing Smartspace media target")
if (smartspaceMediaData.isActive) {
smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
targetId = smartspaceMediaData.targetId)
targetId = smartspaceMediaData.targetId,
instanceId = smartspaceMediaData.instanceId)
}
foregroundExecutor.executeDelayed(
{ notifySmartspaceMediaDataRemoved(
@@ -1035,7 +1046,8 @@ class MediaDataManager(
Log.d(TAG, "Set Smartspace media to be inactive for the data update")
}
smartspaceMediaData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
targetId = smartspaceMediaData.targetId)
targetId = smartspaceMediaData.targetId,
instanceId = smartspaceMediaData.instanceId)
notifySmartspaceMediaDataRemoved(smartspaceMediaData.targetId, immediately = false)
}
1 -> {
@@ -1214,15 +1226,24 @@ class MediaDataManager(
.getParcelable(EXTRAS_SMARTSPACE_DISMISS_INTENT_KEY) as Intent?
}
packageName(target)?.let {
return SmartspaceMediaData(target.smartspaceTargetId, isActive, true, it,
target.baseAction, target.iconGrid,
dismissIntent, 0, target.creationTimeMillis)
return SmartspaceMediaData(
targetId = target.smartspaceTargetId,
isActive = isActive,
isValid = true,
packageName = it,
cardAction = target.baseAction,
recommendations = target.iconGrid,
dismissIntent = dismissIntent,
backgroundColor = 0,
headphoneConnectionTimeMillis = target.creationTimeMillis,
instanceId = logger.getNewInstanceId())
}
return EMPTY_SMARTSPACE_MEDIA_DATA
.copy(targetId = target.smartspaceTargetId,
isActive = isActive,
dismissIntent = dismissIntent,
headphoneConnectionTimeMillis = target.creationTimeMillis)
headphoneConnectionTimeMillis = target.creationTimeMillis,
instanceId = logger.getNewInstanceId())
}
private fun packageName(target: SmartspaceTarget): String? {

View File

@@ -151,6 +151,31 @@ class MediaUiEventLogger @Inject constructor(private val logger: UiEventLogger)
}
logger.log(event)
}
fun logRecommendationAdded(packageName: String, instanceId: InstanceId) {
logger.logWithInstanceId(MediaUiEvent.MEDIA_RECOMMENDATION_ADDED, 0, packageName,
instanceId)
}
fun logRecommendationRemoved(packageName: String, instanceId: InstanceId) {
logger.logWithInstanceId(MediaUiEvent.MEDIA_RECOMMENDATION_REMOVED, 0, packageName,
instanceId)
}
fun logRecommendationActivated(uid: Int, packageName: String, instanceId: InstanceId) {
logger.logWithInstanceId(MediaUiEvent.MEDIA_RECOMMENDATION_ACTIVATED, uid, packageName,
instanceId)
}
fun logRecommendationItemTap(packageName: String, instanceId: InstanceId, position: Int) {
logger.logWithInstanceIdAndPosition(MediaUiEvent.MEDIA_RECOMMENDATION_ITEM_TAP, 0,
packageName, instanceId, position)
}
fun logRecommendationCardTap(packageName: String, instanceId: InstanceId) {
logger.logWithInstanceId(MediaUiEvent.MEDIA_RECOMMENDATION_CARD_TAP, 0, packageName,
instanceId)
}
}
enum class MediaUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum {
@@ -233,7 +258,22 @@ enum class MediaUiEvent(val metricId: Int) : UiEventLogger.UiEventEnum {
MEDIA_CAROUSEL_LOCATION_LOCKSCREEN(1039),
@UiEvent(doc = "The media carousel moved to the dream state")
MEDIA_CAROUSEL_LOCATION_DREAM(1040);
MEDIA_CAROUSEL_LOCATION_DREAM(1040),
@UiEvent(doc = "A media recommendation card was added to the media carousel")
MEDIA_RECOMMENDATION_ADDED(1041),
@UiEvent(doc = "A media recommendation card was removed from the media carousel")
MEDIA_RECOMMENDATION_REMOVED(1042),
@UiEvent(doc = "An existing media control was made active as a recommendation")
MEDIA_RECOMMENDATION_ACTIVATED(1043),
@UiEvent(doc = "User tapped on an item in a media recommendation card")
MEDIA_RECOMMENDATION_ITEM_TAP(1044),
@UiEvent(doc = "User tapped on a media recommendation card")
MEDIA_RECOMMENDATION_CARD_TAP(1045);
override fun getId() = metricId
}

View File

@@ -18,6 +18,7 @@ package com.android.systemui.media
import android.app.smartspace.SmartspaceAction
import android.content.Intent
import com.android.internal.logging.InstanceId
/** State of a Smartspace media recommendations view. */
data class SmartspaceMediaData(
@@ -56,5 +57,9 @@ data class SmartspaceMediaData(
/**
* The timestamp in milliseconds that headphone is connected.
*/
val headphoneConnectionTimeMillis: Long
val headphoneConnectionTimeMillis: Long,
/**
* Instance ID for [MediaUiEventLogger]
*/
val instanceId: InstanceId
)

View File

@@ -19,6 +19,7 @@ package com.android.systemui.media
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.systemui.SysuiTestCase
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.dagger.qualifiers.Main
@@ -28,6 +29,7 @@ import com.android.systemui.plugins.FalsingManager
import com.android.systemui.statusbar.notification.collection.provider.VisualStabilityProvider
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.time.FakeSystemClock
import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertTrue
@@ -225,4 +227,19 @@ class MediaCarouselControllerTest : SysuiTestCase() {
animate = false)
verify(logger).logCarouselPosition(MediaHierarchyManager.LOCATION_DREAM_OVERLAY)
}
@Test
fun testRecommendationRemoved_logged() {
val packageName = "smartspace package"
val instanceId = InstanceId.fakeInstanceId(123)
val smartspaceData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
packageName = packageName,
instanceId = instanceId
)
MediaPlayerData.addMediaRecommendation(SMARTSPACE_KEY, smartspaceData, panel, true, clock)
mediaCarouselController.removePlayer(SMARTSPACE_KEY)
verify(logger).logRecommendationRemoved(eq(packageName), eq(instanceId!!))
}
}

View File

@@ -17,16 +17,22 @@
package com.android.systemui.media
import android.app.PendingIntent
import android.app.smartspace.SmartspaceAction
import android.content.Context
import org.mockito.Mockito.`when` as whenever
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.graphics.Color
import android.graphics.drawable.Animatable2
import android.graphics.drawable.AnimatedVectorDrawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.Icon
import android.graphics.drawable.RippleDrawable
import android.media.MediaMetadata
import android.media.session.MediaSession
import android.media.session.PlaybackState
import android.os.Bundle
import android.os.Handler
import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
import android.testing.AndroidTestingRunner
@@ -67,6 +73,7 @@ import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyLong
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.anyString
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
@@ -107,6 +114,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Mock private lateinit var collapsedSet: ConstraintSet
@Mock private lateinit var mediaOutputDialogFactory: MediaOutputDialogFactory
@Mock private lateinit var mediaCarouselController: MediaCarouselController
@Mock private lateinit var mediaCarouselScrollHandler: MediaCarouselScrollHandler
@Mock private lateinit var falsingManager: FalsingManager
@Mock private lateinit var transitionParent: ViewGroup
private lateinit var appIcon: ImageView
@@ -145,6 +153,14 @@ public class MediaControlPanelTest : SysuiTestCase() {
private val clock = FakeSystemClock()
@Mock private lateinit var logger: MediaUiEventLogger
@Mock private lateinit var instanceId: InstanceId
@Mock private lateinit var packageManager: PackageManager
@Mock private lateinit var applicationInfo: ApplicationInfo
@Mock private lateinit var recommendationViewHolder: RecommendationViewHolder
@Mock private lateinit var smartspaceAction: SmartspaceAction
private lateinit var smartspaceData: SmartspaceMediaData
@Mock private lateinit var coverContainer: ViewGroup
private lateinit var coverItem: ImageView
@JvmField @Rule val mockito = MockitoJUnit.rule()
@@ -155,6 +171,16 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(mediaViewController.expandedLayout).thenReturn(expandedSet)
whenever(mediaViewController.collapsedLayout).thenReturn(collapsedSet)
// Set up package manager mocks
val icon = context.getDrawable(R.drawable.ic_android)
whenever(packageManager.getApplicationIcon(anyString())).thenReturn(icon)
whenever(packageManager.getApplicationIcon(any(ApplicationInfo::class.java)))
.thenReturn(icon)
whenever(packageManager.getApplicationInfo(eq(PACKAGE), anyInt()))
.thenReturn(applicationInfo)
whenever(packageManager.getApplicationLabel(any())).thenReturn(PACKAGE)
context.setMockPackageManager(packageManager)
player = MediaControlPanel(
context,
bgExecutor,
@@ -170,7 +196,60 @@ public class MediaControlPanelTest : SysuiTestCase() {
clock,
logger
)
initMediaViewHolderMocks()
// Create media session
val metadataBuilder = MediaMetadata.Builder().apply {
putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
}
val playbackBuilder = PlaybackState.Builder().apply {
setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
setActions(PlaybackState.ACTION_PLAY)
}
session = MediaSession(context, SESSION_KEY).apply {
setMetadata(metadataBuilder.build())
setPlaybackState(playbackBuilder.build())
}
session.setActive(true)
mediaData = MediaTestUtils.emptyMediaData.copy(
backgroundColor = BG_COLOR,
artist = ARTIST,
song = TITLE,
packageName = PACKAGE,
token = session.sessionToken,
device = device,
instanceId = instanceId)
// Set up recommendation view
initRecommendationViewHolderMocks()
// Set valid recommendation data
val extras = Bundle()
val intent = Intent().apply {
putExtras(extras)
setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
whenever(smartspaceAction.intent).thenReturn(intent)
whenever(smartspaceAction.extras).thenReturn(extras)
smartspaceData = EMPTY_SMARTSPACE_MEDIA_DATA.copy(
packageName = PACKAGE,
instanceId = instanceId,
recommendations = listOf(smartspaceAction),
cardAction = smartspaceAction
)
}
/**
* Initialize elements in media view holder
*/
private fun initMediaViewHolderMocks() {
whenever(seekBarViewModel.progress).thenReturn(seekBarData)
whenever(mediaCarouselController.mediaCarouselScrollHandler)
.thenReturn(mediaCarouselScrollHandler)
whenever(mediaCarouselScrollHandler.qsExpanded).thenReturn(false)
// Set up mock views for the players
appIcon = ImageView(context)
@@ -218,37 +297,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
action4.id)
}
initMediaViewHolderMocks()
// Create media session
val metadataBuilder = MediaMetadata.Builder().apply {
putString(MediaMetadata.METADATA_KEY_ARTIST, SESSION_ARTIST)
putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_TITLE)
}
val playbackBuilder = PlaybackState.Builder().apply {
setState(PlaybackState.STATE_PAUSED, 6000L, 1f)
setActions(PlaybackState.ACTION_PLAY)
}
session = MediaSession(context, SESSION_KEY).apply {
setMetadata(metadataBuilder.build())
setPlaybackState(playbackBuilder.build())
}
session.setActive(true)
mediaData = MediaTestUtils.emptyMediaData.copy(
backgroundColor = BG_COLOR,
artist = ARTIST,
song = TITLE,
packageName = PACKAGE,
token = session.sessionToken,
device = device,
instanceId = instanceId)
}
/**
* Initialize elements in media view holder
*/
private fun initMediaViewHolderMocks() {
whenever(viewHolder.player).thenReturn(view)
whenever(viewHolder.appIcon).thenReturn(appIcon)
whenever(viewHolder.albumView).thenReturn(albumView)
@@ -297,6 +345,38 @@ public class MediaControlPanelTest : SysuiTestCase() {
whenever(viewHolder.actionsTopBarrier).thenReturn(actionsTopBarrier)
}
/**
* Initialize elements for the recommendation view holder
*/
private fun initRecommendationViewHolderMocks() {
whenever(recommendationViewHolder.recommendations).thenReturn(view)
whenever(recommendationViewHolder.cardIcon).thenReturn(appIcon)
whenever(recommendationViewHolder.cardText).thenReturn(titleText)
// Add a recommendation item
coverItem = ImageView(context).also { it.setId(R.id.media_cover1) }
whenever(coverContainer.id).thenReturn(R.id.media_cover1_container)
whenever(recommendationViewHolder.mediaCoverItems).thenReturn(listOf(coverItem))
whenever(recommendationViewHolder.mediaCoverContainers).thenReturn(listOf(coverContainer))
whenever(recommendationViewHolder.mediaCoverItemsResIds)
.thenReturn(listOf(R.id.media_cover1))
whenever(recommendationViewHolder.mediaCoverContainersResIds)
.thenReturn(listOf(R.id.media_cover1_container))
// Long press menu
whenever(recommendationViewHolder.settings).thenReturn(settings)
whenever(recommendationViewHolder.cancel).thenReturn(cancel)
whenever(recommendationViewHolder.dismiss).thenReturn(dismiss)
val actionIcon = Icon.createWithResource(context, R.drawable.ic_android)
whenever(smartspaceAction.icon).thenReturn(actionIcon)
// Needed for card and item action click
val mockContext = mock(Context::class.java)
whenever(view.context).thenReturn(mockContext)
whenever(coverContainer.context).thenReturn(mockContext)
}
@After
fun tearDown() {
session.release()
@@ -923,6 +1003,67 @@ public class MediaControlPanelTest : SysuiTestCase() {
verify(logger).logSeek(anyInt(), eq(PACKAGE), eq(instanceId))
}
@Test
fun recommendation_gutsClosed_longPressOpens() {
player.attachRecommendation(recommendationViewHolder)
player.bindRecommendation(smartspaceData)
whenever(mediaViewController.isGutsVisible).thenReturn(false)
val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
verify(recommendationViewHolder.recommendations).setOnLongClickListener(captor.capture())
captor.value.onLongClick(recommendationViewHolder.recommendations)
verify(mediaViewController).openGuts()
verify(logger).logLongPressOpen(anyInt(), eq(PACKAGE), eq(instanceId))
}
@Test
fun recommendation_settingsButtonClick_isLogged() {
player.attachRecommendation(recommendationViewHolder)
player.bindRecommendation(smartspaceData)
settings.callOnClick()
verify(logger).logLongPressSettings(anyInt(), eq(PACKAGE), eq(instanceId))
val captor = ArgumentCaptor.forClass(Intent::class.java)
verify(activityStarter).startActivity(captor.capture(), eq(true))
assertThat(captor.value.action).isEqualTo(ACTION_MEDIA_CONTROLS_SETTINGS)
}
@Test
fun recommendation_dismissButton_isLogged() {
player.attachRecommendation(recommendationViewHolder)
player.bindRecommendation(smartspaceData)
dismiss.callOnClick()
verify(logger).logLongPressDismiss(anyInt(), eq(PACKAGE), eq(instanceId))
}
@Test
fun recommendation_tapOnCard_isLogged() {
val captor = ArgumentCaptor.forClass(View.OnClickListener::class.java)
player.attachRecommendation(recommendationViewHolder)
player.bindRecommendation(smartspaceData)
verify(recommendationViewHolder.recommendations).setOnClickListener(captor.capture())
captor.value.onClick(recommendationViewHolder.recommendations)
verify(logger).logRecommendationCardTap(eq(PACKAGE), eq(instanceId))
}
@Test
fun recommendation_tapOnItem_isLogged() {
val captor = ArgumentCaptor.forClass(View.OnClickListener::class.java)
player.attachRecommendation(recommendationViewHolder)
player.bindRecommendation(smartspaceData)
verify(coverContainer).setOnClickListener(captor.capture())
captor.value.onClick(recommendationViewHolder.recommendations)
verify(logger).logRecommendationItemTap(eq(PACKAGE), eq(instanceId), eq(0))
}
private fun getScrubbingChangeListener(): SeekBarViewModel.ScrubbingChangeListener =
withArgCaptor { verify(seekBarViewModel).setScrubbingChangeListener(capture()) }
}

View File

@@ -20,6 +20,7 @@ import android.app.smartspace.SmartspaceAction
import androidx.test.filters.SmallTest
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import com.android.internal.logging.InstanceId
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.broadcast.BroadcastSender
@@ -46,7 +47,11 @@ private const val KEY_ALT = "TEST_KEY_2"
private const val USER_MAIN = 0
private const val USER_GUEST = 10
private const val PACKAGE = "PKG"
private val INSTANCE_ID = InstanceId.fakeInstanceId(123)!!
private const val APP_UID = 99
private const val SMARTSPACE_KEY = "SMARTSPACE_KEY"
private const val SMARTSPACE_PACKAGE = "SMARTSPACE_PKG"
private val SMARTSPACE_INSTANCE_ID = InstanceId.fakeInstanceId(456)!!
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -69,6 +74,8 @@ class MediaDataFilterTest : SysuiTestCase() {
private lateinit var smartspaceData: SmartspaceMediaData
@Mock
private lateinit var smartspaceMediaRecommendationItem: SmartspaceAction
@Mock
private lateinit var logger: MediaUiEventLogger
private lateinit var mediaDataFilter: MediaDataFilter
private lateinit var dataMain: MediaData
@@ -79,8 +86,14 @@ class MediaDataFilterTest : SysuiTestCase() {
fun setup() {
MockitoAnnotations.initMocks(this)
MediaPlayerData.clear()
mediaDataFilter = MediaDataFilter(context, broadcastDispatcher, broadcastSender,
lockscreenUserManager, executor, clock)
mediaDataFilter = MediaDataFilter(
context,
broadcastDispatcher,
broadcastSender,
lockscreenUserManager,
executor,
clock,
logger)
mediaDataFilter.mediaDataManager = mediaDataManager
mediaDataFilter.addListener(listener)
@@ -90,16 +103,19 @@ class MediaDataFilterTest : SysuiTestCase() {
// Set up test media data
dataMain = MediaTestUtils.emptyMediaData.copy(
userId = USER_MAIN,
packageName = PACKAGE)
packageName = PACKAGE,
instanceId = INSTANCE_ID,
appUid = APP_UID)
dataGuest = dataMain.copy(userId = USER_GUEST)
`when`(smartspaceData.targetId).thenReturn(SMARTSPACE_KEY)
`when`(smartspaceData.isActive).thenReturn(true)
`when`(smartspaceData.isValid).thenReturn(true)
`when`(smartspaceData.packageName).thenReturn(PACKAGE)
`when`(smartspaceData.packageName).thenReturn(SMARTSPACE_PACKAGE)
`when`(smartspaceData.recommendations).thenReturn(listOf(smartspaceMediaRecommendationItem))
`when`(smartspaceData.headphoneConnectionTimeMillis).thenReturn(
clock.currentTimeMillis() - 100)
`when`(smartspaceData.instanceId).thenReturn(SMARTSPACE_INSTANCE_ID)
}
private fun setUser(id: Int) {
@@ -241,6 +257,8 @@ class MediaDataFilterTest : SysuiTestCase() {
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true))
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue()
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID)
verify(logger, never()).logRecommendationActivated(any(), any(), any())
}
@Test
@@ -254,6 +272,8 @@ class MediaDataFilterTest : SysuiTestCase() {
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse()
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
verify(logger, never()).logRecommendationAdded(any(), any())
verify(logger, never()).logRecommendationActivated(any(), any(), any())
}
@Test
@@ -267,6 +287,8 @@ class MediaDataFilterTest : SysuiTestCase() {
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(true))
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isTrue()
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID)
verify(logger, never()).logRecommendationActivated(any(), any(), any())
}
@Test
@@ -281,6 +303,8 @@ class MediaDataFilterTest : SysuiTestCase() {
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse()
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
verify(logger, never()).logRecommendationAdded(any(), any())
verify(logger, never()).logRecommendationActivated(any(), any(), any())
}
@Test
@@ -302,6 +326,8 @@ class MediaDataFilterTest : SysuiTestCase() {
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse()
assertThat(mediaDataFilter.hasActiveMedia()).isFalse()
verify(logger, never()).logRecommendationAdded(any(), any())
verify(logger, never()).logRecommendationActivated(any(), any(), any())
}
@Test
@@ -324,6 +350,8 @@ class MediaDataFilterTest : SysuiTestCase() {
assertThat(mediaDataFilter.hasActiveMediaOrRecommendation()).isFalse()
// Smartspace update shouldn't be propagated for the empty rec list.
verify(listener, never()).onSmartspaceMediaDataLoaded(any(), any(), anyBoolean())
verify(logger, never()).logRecommendationAdded(any(), any())
verify(logger).logRecommendationActivated(eq(APP_UID), eq(PACKAGE), eq(INSTANCE_ID))
}
@Test
@@ -345,6 +373,8 @@ class MediaDataFilterTest : SysuiTestCase() {
// Smartspace update should also be propagated but not prioritized.
verify(listener)
.onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData), eq(false))
verify(logger).logRecommendationAdded(SMARTSPACE_PACKAGE, SMARTSPACE_INSTANCE_ID)
verify(logger).logRecommendationActivated(eq(APP_UID), eq(PACKAGE), eq(INSTANCE_ID))
}
@Test

View File

@@ -19,6 +19,7 @@ import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.media.utils.MediaConstants
import androidx.test.filters.SmallTest
import com.android.internal.logging.InstanceId
import com.android.systemui.InstanceIdSequenceFake
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
@@ -47,6 +48,7 @@ import org.mockito.Mockito
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.junit.MockitoJUnit
import org.mockito.Mockito.`when` as whenever
@@ -452,11 +454,22 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testOnSmartspaceMediaDataLoaded_hasNewValidMediaTarget_callsListener() {
smartspaceMediaDataProvider.onTargetsAvailable(listOf(mediaSmartspaceTarget))
verify(logger).getNewInstanceId()
val instanceId = instanceIdSequence.lastInstanceId
verify(listener).onSmartspaceMediaDataLoaded(
eq(KEY_MEDIA_SMARTSPACE),
eq(SmartspaceMediaData(KEY_MEDIA_SMARTSPACE, true /* isActive */, true /*isValid */,
PACKAGE_NAME, mediaSmartspaceBaseAction, listOf(mediaRecommendationItem),
DISMISS_INTENT, 0, 1234L)),
eq(SmartspaceMediaData(
targetId = KEY_MEDIA_SMARTSPACE,
isActive = true,
isValid = true,
packageName = PACKAGE_NAME,
cardAction = mediaSmartspaceBaseAction,
recommendations = listOf(mediaRecommendationItem),
dismissIntent = DISMISS_INTENT,
backgroundColor = 0,
headphoneConnectionTimeMillis = 1234L,
instanceId = InstanceId.fakeInstanceId(instanceId))),
eq(false))
}
@@ -464,12 +477,18 @@ class MediaDataManagerTest : SysuiTestCase() {
fun testOnSmartspaceMediaDataLoaded_hasNewInvalidMediaTarget_callsListener() {
whenever(mediaSmartspaceTarget.iconGrid).thenReturn(listOf())
smartspaceMediaDataProvider.onTargetsAvailable(listOf(mediaSmartspaceTarget))
verify(logger).getNewInstanceId()
val instanceId = instanceIdSequence.lastInstanceId
verify(listener).onSmartspaceMediaDataLoaded(
eq(KEY_MEDIA_SMARTSPACE),
eq(EMPTY_SMARTSPACE_MEDIA_DATA
.copy(targetId = KEY_MEDIA_SMARTSPACE, isActive = true,
isValid = false, dismissIntent = DISMISS_INTENT,
headphoneConnectionTimeMillis = 1234L)),
eq(EMPTY_SMARTSPACE_MEDIA_DATA.copy(
targetId = KEY_MEDIA_SMARTSPACE,
isActive = true,
isValid = false,
dismissIntent = DISMISS_INTENT,
headphoneConnectionTimeMillis = 1234L,
instanceId = InstanceId.fakeInstanceId(instanceId))),
eq(false))
}
@@ -484,18 +503,25 @@ class MediaDataManagerTest : SysuiTestCase() {
whenever(mediaSmartspaceTarget.iconGrid).thenReturn(listOf())
smartspaceMediaDataProvider.onTargetsAvailable(listOf(mediaSmartspaceTarget))
verify(logger).getNewInstanceId()
val instanceId = instanceIdSequence.lastInstanceId
verify(listener).onSmartspaceMediaDataLoaded(
eq(KEY_MEDIA_SMARTSPACE),
eq(EMPTY_SMARTSPACE_MEDIA_DATA
.copy(targetId = KEY_MEDIA_SMARTSPACE, isActive = true,
isValid = false, dismissIntent = null, headphoneConnectionTimeMillis = 1234L)),
eq(EMPTY_SMARTSPACE_MEDIA_DATA.copy(
targetId = KEY_MEDIA_SMARTSPACE,
isActive = true,
isValid = false,
dismissIntent = null,
headphoneConnectionTimeMillis = 1234L,
instanceId = InstanceId.fakeInstanceId(instanceId))),
eq(false))
}
@Test
fun testOnSmartspaceMediaDataLoaded_hasNoneMediaTarget_notCallsListener() {
smartspaceMediaDataProvider.onTargetsAvailable(listOf())
verify(logger, never()).getNewInstanceId()
verify(listener, never())
.onSmartspaceMediaDataLoaded(anyObject(), anyObject(), anyBoolean())
}
@@ -503,11 +529,14 @@ class MediaDataManagerTest : SysuiTestCase() {
@Test
fun testOnSmartspaceMediaDataLoaded_hasNoneMediaTarget_callsRemoveListener() {
smartspaceMediaDataProvider.onTargetsAvailable(listOf(mediaSmartspaceTarget))
verify(logger).getNewInstanceId()
smartspaceMediaDataProvider.onTargetsAvailable(listOf())
foregroundExecutor.advanceClockToLast()
foregroundExecutor.runAllReady()
verify(listener).onSmartspaceMediaDataRemoved(eq(KEY_MEDIA_SMARTSPACE), eq(false))
verifyNoMoreInteractions(logger)
}
@Test