diff options
| author | 2020-06-18 20:48:32 +0000 | |
|---|---|---|
| committer | 2020-06-18 20:48:32 +0000 | |
| commit | fe16654f21e72492df7aadf2f9305d8f160faf55 (patch) | |
| tree | d4cf49f22a80a45985cabe6203fa2bc051029a1f | |
| parent | e93d99c647f650621d6ce323975ad9af9d33e3ca (diff) | |
| parent | ae437a107500fd52b70b0b5e4da74762cf360758 (diff) | |
Merge "Do not dismiss notification, flip activity flag" into rvc-dev
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt | 69 | ||||
| -rw-r--r-- | packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt | 126 |
2 files changed, 176 insertions, 19 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 5e65a8f36bbc..1ec285a8f561 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -38,18 +38,20 @@ import android.service.notification.StatusBarNotification import android.text.TextUtils import android.util.Log import com.android.internal.graphics.ColorUtils +import com.android.systemui.Dumpable import com.android.systemui.R import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main +import com.android.systemui.dump.DumpManager import com.android.systemui.statusbar.NotificationMediaManager import com.android.systemui.statusbar.notification.MediaNotificationProcessor -import com.android.systemui.statusbar.notification.NotificationEntryManager -import com.android.systemui.statusbar.notification.NotificationEntryManager.UNDEFINED_DISMISS_REASON import com.android.systemui.statusbar.notification.row.HybridGroupManager import com.android.systemui.util.Assert import com.android.systemui.util.Utils +import java.io.FileDescriptor import java.io.IOException +import java.io.PrintWriter import java.util.concurrent.Executor import javax.inject.Inject import javax.inject.Singleton @@ -85,20 +87,35 @@ fun isMediaNotification(sbn: StatusBarNotification): Boolean { * A class that facilitates management and loading of Media Data, ready for binding. */ @Singleton -class MediaDataManager @Inject constructor( +class MediaDataManager( private val context: Context, - private val mediaControllerFactory: MediaControllerFactory, - private val notificationEntryManager: NotificationEntryManager, @Background private val backgroundExecutor: Executor, @Main private val foregroundExecutor: Executor, - broadcastDispatcher: BroadcastDispatcher, + private val mediaControllerFactory: MediaControllerFactory, + private val broadcastDispatcher: BroadcastDispatcher, + dumpManager: DumpManager, mediaTimeoutListener: MediaTimeoutListener, - mediaResumeListener: MediaResumeListener -) { + mediaResumeListener: MediaResumeListener, + private val useMediaResumption: Boolean, + private val useQsMediaPlayer: Boolean +) : Dumpable { private val listeners: MutableSet<Listener> = mutableSetOf() private val mediaEntries: LinkedHashMap<String, MediaData> = LinkedHashMap() - private val useMediaResumption: Boolean = Utils.useMediaResumption(context) + + @Inject + constructor( + context: Context, + @Background backgroundExecutor: Executor, + @Main foregroundExecutor: Executor, + mediaControllerFactory: MediaControllerFactory, + dumpManager: DumpManager, + broadcastDispatcher: BroadcastDispatcher, + mediaTimeoutListener: MediaTimeoutListener, + mediaResumeListener: MediaResumeListener + ) : this(context, backgroundExecutor, foregroundExecutor, mediaControllerFactory, + broadcastDispatcher, dumpManager, mediaTimeoutListener, mediaResumeListener, + Utils.useMediaResumption(context), Utils.useQsMediaPlayer(context)) private val userChangeReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { @@ -128,6 +145,7 @@ class MediaDataManager @Inject constructor( } init { + dumpManager.registerDumpable(TAG, this) mediaTimeoutListener.timeoutCallback = { token: String, timedOut: Boolean -> setTimedOut(token, timedOut) } addListener(mediaTimeoutListener) @@ -159,8 +177,13 @@ class MediaDataManager @Inject constructor( context.registerReceiver(appChangeReceiver, uninstallFilter) } + fun destroy() { + context.unregisterReceiver(appChangeReceiver) + broadcastDispatcher.unregisterReceiver(userChangeReceiver) + } + fun onNotificationAdded(key: String, sbn: StatusBarNotification) { - if (Utils.useQsMediaPlayer(context) && isMediaNotification(sbn)) { + if (useQsMediaPlayer && isMediaNotification(sbn)) { Assert.isMainThread() val oldKey = findExistingEntry(key, sbn.packageName) if (oldKey == null) { @@ -253,18 +276,18 @@ class MediaDataManager @Inject constructor( */ fun removeListener(listener: Listener) = listeners.remove(listener) + /** + * Called whenever the player has been paused or stopped for a while. + * This will make the player not active anymore, hiding it from QQS and Keyguard. + * @see MediaData.active + */ private fun setTimedOut(token: String, timedOut: Boolean) { mediaEntries[token]?.let { - if (Utils.useMediaResumption(context)) { - if (it.active == !timedOut) { - return - } - it.active = !timedOut - onMediaDataLoaded(token, token, it) - } else if (timedOut) { - notificationEntryManager.removeNotification(it.notificationKey, null /* ranking */, - UNDEFINED_DISMISS_REASON) + if (it.active == !timedOut) { + return } + it.active = !timedOut + onMediaDataLoaded(token, token, it) } } @@ -570,4 +593,12 @@ class MediaDataManager @Inject constructor( */ fun onMediaDataRemoved(key: String) {} } + + override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { + pw.apply { + println("listeners: $listeners") + println("mediaEntries: $mediaEntries") + println("useMediaResumption: $useMediaResumption") + } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt new file mode 100644 index 000000000000..54520be8a03f --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt @@ -0,0 +1,126 @@ +package com.android.systemui.media + +import android.app.Notification +import android.service.notification.StatusBarNotification +import android.testing.AndroidTestingRunner +import android.testing.TestableLooper.RunWithLooper +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.dump.DumpManager +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify +import org.mockito.junit.MockitoJUnit +import java.util.concurrent.Executor +import org.mockito.Mockito.`when` as whenever + +private const val KEY = "KEY" +private const val PACKAGE_NAME = "com.android.systemui" + +private fun <T> eq(value: T): T = Mockito.eq(value) ?: value +private fun <T> anyObject(): T { + return Mockito.anyObject<T>() +} + +@SmallTest +@RunWithLooper(setAsMainLooper = true) +@RunWith(AndroidTestingRunner::class) +class MediaDataManagerTest : SysuiTestCase() { + + @Mock lateinit var mediaControllerFactory: MediaControllerFactory + @Mock lateinit var backgroundExecutor: Executor + @Mock lateinit var foregroundExecutor: Executor + @Mock lateinit var dumpManager: DumpManager + @Mock lateinit var broadcastDispatcher: BroadcastDispatcher + @Mock lateinit var mediaTimeoutListener: MediaTimeoutListener + @Mock lateinit var mediaResumeListener: MediaResumeListener + @JvmField @Rule val mockito = MockitoJUnit.rule() + lateinit var mediaDataManager: MediaDataManager + lateinit var mediaNotification: StatusBarNotification + + @Before + fun setup() { + mediaDataManager = MediaDataManager(context, backgroundExecutor, foregroundExecutor, + mediaControllerFactory, broadcastDispatcher, dumpManager, + mediaTimeoutListener, mediaResumeListener, useMediaResumption = true, + useQsMediaPlayer = true) + val sbn = mock(StatusBarNotification::class.java) + val notification = mock(Notification::class.java) + whenever(notification.hasMediaSession()).thenReturn(true) + whenever(notification.notificationStyle).thenReturn(Notification.MediaStyle::class.java) + whenever(sbn.notification).thenReturn(notification) + whenever(sbn.packageName).thenReturn(PACKAGE_NAME) + mediaNotification = sbn + } + + @After + fun tearDown() { + mediaDataManager.destroy() + } + + @Test + fun testHasActiveMedia() { + assertThat(mediaDataManager.hasActiveMedia()).isFalse() + val data = mock(MediaData::class.java) + + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = data) + assertThat(mediaDataManager.hasActiveMedia()).isFalse() + + whenever(data.active).thenReturn(true) + assertThat(mediaDataManager.hasActiveMedia()).isTrue() + } + + @Test + fun testLoadsMetadataOnBackground() { + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + verify(backgroundExecutor).execute(anyObject()) + } + + @Test + fun testOnMetaDataLoaded_callsListener() { + val listener = mock(MediaDataManager.Listener::class.java) + mediaDataManager.addListener(listener) + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = mock(MediaData::class.java)) + verify(listener).onMediaDataLoaded(eq(KEY), eq(null), anyObject()) + } + + @Test + fun testHasAnyMedia_whenAddingMedia() { + assertThat(mediaDataManager.hasAnyMedia()).isFalse() + val data = mock(MediaData::class.java) + + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = data) + assertThat(mediaDataManager.hasAnyMedia()).isTrue() + } + + @Test + fun testOnNotificationRemoved_doesntHaveMedia() { + val data = mock(MediaData::class.java) + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = data) + mediaDataManager.onNotificationRemoved(KEY) + assertThat(mediaDataManager.hasAnyMedia()).isFalse() + } + + @Test + fun testOnNotificationRemoved_callsListener() { + val listener = mock(MediaDataManager.Listener::class.java) + mediaDataManager.addListener(listener) + mediaDataManager.onNotificationAdded(KEY, mediaNotification) + mediaDataManager.onMediaDataLoaded(KEY, oldKey = null, data = mock(MediaData::class.java)) + mediaDataManager.onNotificationRemoved(KEY) + + verify(listener).onMediaDataRemoved(eq(KEY)) + } +}
\ No newline at end of file |