Fix timing issue for flaky tests
Inject SystemClock so that we can mock it in tests and ensure the clock
will always advance. Also switched to using elapsedRealtime, which is
guaranteed to be monotonic
Fixes: 182813365
Test: atest MediaDataManagerTest
Change-Id: I133fb48e8242dc7f8e75bfa5c585c8b6142963aa
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
index 9163044c..e5c15107 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataFilter.kt
@@ -25,6 +25,7 @@
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.settings.CurrentUserTracker
import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.util.time.SystemClock
import java.util.concurrent.Executor
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@@ -36,7 +37,8 @@
* Maximum age of a media control to re-activate on smartspace signal. If there is no media control
* available within this time window, smartspace recommendations will be shown instead.
*/
-private val SMARTSPACE_MAX_AGE = SystemProperties
+@VisibleForTesting
+internal val SMARTSPACE_MAX_AGE = SystemProperties
.getLong("debug.sysui.smartspace_max_age", TimeUnit.HOURS.toMillis(3))
/**
@@ -51,7 +53,8 @@
private val broadcastDispatcher: BroadcastDispatcher,
private val mediaResumeListener: MediaResumeListener,
private val lockscreenUserManager: NotificationLockscreenUserManager,
- @Main private val executor: Executor
+ @Main private val executor: Executor,
+ private val systemClock: SystemClock
) : MediaDataManager.Listener {
private val userTracker: CurrentUserTracker
private val _listeners: MutableSet<MediaDataManager.Listener> = mutableSetOf()
@@ -100,7 +103,7 @@
hasSmartspace = true
// Before forwarding the smartspace target, first check if we have recently inactive media
- val now = System.currentTimeMillis()
+ val now = systemClock.elapsedRealtime()
val sorted = userEntries.toSortedMap(compareBy {
userEntries.get(it)?.lastActive ?: -1
})
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
index 138c422..a45bd33 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt
@@ -56,6 +56,7 @@
import com.android.systemui.util.Assert
import com.android.systemui.util.Utils
import com.android.systemui.util.concurrency.DelayableExecutor
+import com.android.systemui.util.time.SystemClock
import java.io.FileDescriptor
import java.io.IOException
import java.io.PrintWriter
@@ -108,7 +109,8 @@
private val activityStarter: ActivityStarter,
private val smartspaceMediaDataProvider: SmartspaceMediaDataProvider,
private var useMediaResumption: Boolean,
- private val useQsMediaPlayer: Boolean
+ private val useQsMediaPlayer: Boolean,
+ private val systemClock: SystemClock
) : Dumpable, BcSmartspaceDataPlugin.SmartspaceTargetListener {
companion object {
@@ -164,12 +166,13 @@
mediaDataCombineLatest: MediaDataCombineLatest,
mediaDataFilter: MediaDataFilter,
activityStarter: ActivityStarter,
- smartspaceMediaDataProvider: SmartspaceMediaDataProvider
+ smartspaceMediaDataProvider: SmartspaceMediaDataProvider,
+ clock: SystemClock
) : this(context, backgroundExecutor, foregroundExecutor, mediaControllerFactory,
broadcastDispatcher, dumpManager, mediaTimeoutListener, mediaResumeListener,
mediaSessionBasedFilter, mediaDeviceManager, mediaDataCombineLatest, mediaDataFilter,
activityStarter, smartspaceMediaDataProvider, Utils.useMediaResumption(context),
- Utils.useQsMediaPlayer(context))
+ Utils.useQsMediaPlayer(context), clock)
private val appChangeReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
@@ -474,7 +477,7 @@
}
val mediaAction = getResumeMediaAction(resumeAction)
- val lastActive = System.currentTimeMillis()
+ val lastActive = systemClock.elapsedRealtime()
foregroundExecutor.execute {
onMediaDataLoaded(packageName, null, MediaData(userId, true, bgColor, appName,
null, desc.subtitle, desc.title, artworkIcon, listOf(mediaAction), listOf(0),
@@ -597,7 +600,7 @@
val isLocalSession = mediaController.playbackInfo?.playbackType ==
MediaController.PlaybackInfo.PLAYBACK_TYPE_LOCAL
val isPlaying = mediaController.playbackState?.let { isPlayingState(it.state) } ?: null
- val lastActive = System.currentTimeMillis()
+ val lastActive = systemClock.elapsedRealtime()
foregroundExecutor.execute {
val resumeAction: Runnable? = mediaEntries[key]?.resumeAction
val hasCheckedForResume = mediaEntries[key]?.hasCheckedForResume == true
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
index ac24cde..bfd60b96 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataFilterTest.kt
@@ -25,6 +25,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.statusbar.NotificationLockscreenUserManager
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -80,12 +81,13 @@
private lateinit var dataMain: MediaData
private lateinit var dataGuest: MediaData
private val device = MediaDeviceData(true, null, DEVICE_NAME)
+ private val clock = FakeSystemClock()
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
mediaDataFilter = MediaDataFilter(broadcastDispatcher, mediaResumeListener,
- lockscreenUserManager, executor)
+ lockscreenUserManager, executor, clock)
mediaDataFilter.mediaDataManager = mediaDataManager
mediaDataFilter.addListener(listener)
@@ -246,8 +248,9 @@
@Test
fun testOnSmartspaceMediaDataLoaded_noRecentMedia_nonEmptyRecommendation_usesSmartspace() {
- val dataOld = dataMain.copy(active = false, lastActive = 0L)
+ val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld)
+ clock.advanceTime(SMARTSPACE_MAX_AGE + 100)
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
verify(listener).onSmartspaceMediaDataLoaded(eq(SMARTSPACE_KEY), eq(smartspaceData))
@@ -258,8 +261,9 @@
fun testOnSmartspaceMediaDataLoaded_noRecentMedia_emptyRecommendation_showsNothing() {
`when`(smartspaceData.iconGrid).thenReturn(listOf())
- val dataOld = dataMain.copy(active = false, lastActive = 0L)
+ val dataOld = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataOld)
+ clock.advanceTime(SMARTSPACE_MAX_AGE + 100)
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
verify(listener, never())
@@ -270,7 +274,7 @@
@Test
fun testOnSmartspaceMediaDataLoaded_hasRecentMedia_usesMedia() {
// WHEN we have media that was recently played, but not currently active
- val dataCurrent = dataMain.copy(active = false, lastActive = System.currentTimeMillis())
+ val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), eq(dataCurrent))
@@ -294,7 +298,7 @@
@Test
fun testOnSmartspaceMediaDataRemoved_usedMedia_clearsMedia() {
- val dataCurrent = dataMain.copy(active = false, lastActive = System.currentTimeMillis())
+ val dataCurrent = dataMain.copy(active = false, lastActive = clock.elapsedRealtime())
mediaDataFilter.onMediaDataLoaded(KEY, null, dataCurrent)
mediaDataFilter.onSmartspaceMediaDataLoaded(SMARTSPACE_KEY, smartspaceData)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
index daa8b4b..acfc513 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt
@@ -81,11 +81,12 @@
lateinit var mediaDataManager: MediaDataManager
lateinit var mediaNotification: StatusBarNotification
@Captor lateinit var mediaDataCaptor: ArgumentCaptor<MediaData>
+ private val clock = FakeSystemClock()
@Before
fun setup() {
- foregroundExecutor = FakeExecutor(FakeSystemClock())
- backgroundExecutor = FakeExecutor(FakeSystemClock())
+ foregroundExecutor = FakeExecutor(clock)
+ backgroundExecutor = FakeExecutor(clock)
smartspaceMediaDataProvider = SmartspaceMediaDataProvider()
mediaDataManager = MediaDataManager(
context = context,
@@ -103,7 +104,8 @@
activityStarter = activityStarter,
smartspaceMediaDataProvider = smartspaceMediaDataProvider,
useMediaResumption = true,
- useQsMediaPlayer = true
+ useQsMediaPlayer = true,
+ systemClock = clock
)
session = MediaSession(context, "MediaDataManagerTestSession")
mediaNotification = SbnBuilder().run {
@@ -310,7 +312,7 @@
setTitle(SESSION_TITLE)
build()
}
- val currentTimeMillis = System.currentTimeMillis()
+ val currentTime = clock.elapsedRealtime()
mediaDataManager.addResumptionControls(USER_ID, desc, Runnable {}, session.sessionToken,
APP_NAME, pendingIntent, PACKAGE_NAME)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
@@ -322,7 +324,7 @@
assertThat(data.song).isEqualTo(SESSION_TITLE)
assertThat(data.app).isEqualTo(APP_NAME)
assertThat(data.actions).hasSize(1)
- assertThat(data.lastActive).isAtLeast(currentTimeMillis)
+ assertThat(data.lastActive).isAtLeast(currentTime)
}
@Test
@@ -380,12 +382,12 @@
@Test
fun testOnMediaDataChanged_updatesLastActiveTime() {
- val currentTimeMillis = System.currentTimeMillis()
+ val currentTime = clock.elapsedRealtime()
mediaDataManager.onNotificationAdded(KEY, mediaNotification)
assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
verify(listener).onMediaDataLoaded(eq(KEY), eq(null), capture(mediaDataCaptor))
- assertThat(mediaDataCaptor.value!!.lastActive).isAtLeast(currentTimeMillis)
+ assertThat(mediaDataCaptor.value!!.lastActive).isAtLeast(currentTime)
}
@Test
@@ -396,12 +398,13 @@
assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
// WHEN the notification times out
- val currentTimeMillis = System.currentTimeMillis()
+ clock.advanceTime(100)
+ val currentTime = clock.elapsedRealtime()
mediaDataManager.setTimedOut(KEY, true, true)
// THEN the last active time is not changed
verify(listener).onMediaDataLoaded(eq(KEY), eq(KEY), capture(mediaDataCaptor))
- assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTimeMillis)
+ assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime)
}
@Test
@@ -417,13 +420,14 @@
mediaDataManager.onMediaDataLoaded(KEY, null, data.copy(resumeAction = Runnable {}))
// WHEN the notification is removed
- val currentTimeMillis = System.currentTimeMillis()
+ clock.advanceTime(100)
+ val currentTime = clock.elapsedRealtime()
mediaDataManager.onNotificationRemoved(KEY)
// THEN the last active time is not changed
verify(listener).onMediaDataLoaded(eq(PACKAGE_NAME), eq(KEY), capture(mediaDataCaptor))
assertThat(mediaDataCaptor.value.resumption).isTrue()
- assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTimeMillis)
+ assertThat(mediaDataCaptor.value.lastActive).isLessThan(currentTime)
}
@Test