summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Lucas Dupin <dupin@google.com> 2020-06-18 20:48:32 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2020-06-18 20:48:32 +0000
commitfe16654f21e72492df7aadf2f9305d8f160faf55 (patch)
treed4cf49f22a80a45985cabe6203fa2bc051029a1f
parente93d99c647f650621d6ce323975ad9af9d33e3ca (diff)
parentae437a107500fd52b70b0b5e4da74762cf360758 (diff)
Merge "Do not dismiss notification, flip activity flag" into rvc-dev
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt69
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/MediaDataManagerTest.kt126
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