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