Loading packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +5 −43 Original line number Diff line number Diff line Loading @@ -71,8 +71,6 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.Utils; import com.android.systemui.util.concurrency.DelayableExecutor; import dagger.Lazy; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; Loading @@ -82,6 +80,8 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import dagger.Lazy; /** * Handles tasks and state related to media notifications. For example, there is a 'current' media * notification, which this class keeps track of. Loading Loading @@ -161,48 +161,11 @@ public class NotificationMediaManager implements Dumpable { Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata); } mMediaArtworkProcessor.clearCache(); mMediaMetadata = cleanMetadata(metadata); mMediaMetadata = metadata; dispatchUpdateMediaMetaData(true /* changed */, true /* allowAnimation */); } }; /** * If this build is not configured for lockscreen artwork, clear artwork references from the * metadata to avoid excess memory usage. Otherwise, return as is. * @param data Original metadata * @return a copy without artwork data, or original */ private MediaMetadata cleanMetadata(MediaMetadata data) { if (SHOW_LOCKSCREEN_MEDIA_ARTWORK) { return data; } if (data == null) { return null; } if (DEBUG_MEDIA) { String[] artKeys = new String[] { MediaMetadata.METADATA_KEY_ART, MediaMetadata.METADATA_KEY_ALBUM_ART, MediaMetadata.METADATA_KEY_DISPLAY_ICON, MediaMetadata.METADATA_KEY_ALBUM_ART_URI, MediaMetadata.METADATA_KEY_ART_URI, MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI }; Log.v(TAG, "DEBUG_MEDIA: removing artwork from metadata"); for (String key: artKeys) { Log.v(TAG, " " + key + ": " + data.containsKey(key)); } } return new MediaMetadata.Builder(data) .putBitmap(MediaMetadata.METADATA_KEY_ART, null) .putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, null) .putBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON, null) .putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, null) .putString(MediaMetadata.METADATA_KEY_ART_URI, null) .putString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, null) .build(); } /** * Injected constructor. See {@link CentralSurfacesModule}. */ Loading Loading @@ -350,7 +313,6 @@ public class NotificationMediaManager implements Dumpable { return mMediaNotificationKey; } @VisibleForTesting public MediaMetadata getMediaMetadata() { return mMediaMetadata; } Loading Loading @@ -388,7 +350,7 @@ public class NotificationMediaManager implements Dumpable { * update this manager's internal state. * @return whether the current MediaMetadata changed (and needs to be announced to listeners). */ private boolean findPlayingMediaNotification( boolean findPlayingMediaNotification( @NonNull Collection<NotificationEntry> allNotifications) { boolean metaDataChanged = false; // Promote the media notification with a controller in 'playing' state, if any. Loading Loading @@ -421,7 +383,7 @@ public class NotificationMediaManager implements Dumpable { clearCurrentMediaNotificationSession(); mMediaController = controller; mMediaController.registerCallback(mMediaListener); mMediaMetadata = cleanMetadata(mMediaController.getMetadata()); mMediaMetadata = mMediaController.getMetadata(); if (DEBUG_MEDIA) { Log.v(TAG, "DEBUG_MEDIA: insert listener, found new controller: " + mMediaController + ", receive metadata: " + mMediaMetadata); Loading packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +1 −1 Original line number Diff line number Diff line Loading @@ -75,7 +75,7 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn boolean DEBUG_WAKEUP_DELAY = Compile.IS_DEBUG; // additional instrumentation for testing purposes; intended to be left on during development boolean CHATTY = DEBUG; boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = false; boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true; String ACTION_FAKE_ARTWORK = "fake_artwork"; int FADE_KEYGUARD_START_DELAY = 100; int FADE_KEYGUARD_DURATION = 300; Loading packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt +17 −122 Original line number Diff line number Diff line Loading @@ -16,34 +16,11 @@ package com.android.systemui.statusbar import android.app.Notification import android.app.WallpaperManager import android.graphics.Bitmap import android.media.MediaMetadata import android.media.session.MediaSession import android.media.session.PlaybackState import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.colorextraction.SysuiColorExtractor import com.android.systemui.dump.DumpManager import com.android.systemui.media.controls.pipeline.MediaDataManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.notification.collection.NotifCollection import com.android.systemui.statusbar.notification.collection.NotifPipeline import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import dagger.Lazy import java.util.Optional import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith Loading @@ -55,121 +32,39 @@ import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations /** * Temporary test for the lock screen live wallpaper project. * * TODO(b/273443374): remove this test */ @RunWith(AndroidTestingRunner::class) @SmallTest @RunWithLooper class NotificationMediaManagerTest : SysuiTestCase() { @Mock private lateinit var centralSurfaces: CentralSurfaces @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController @Mock private lateinit var visibilityProvider: NotificationVisibilityProvider @Mock private lateinit var mediaArtworkProcessor: MediaArtworkProcessor @Mock private lateinit var keyguardBypassController: KeyguardBypassController @Mock private lateinit var notifPipeline: NotifPipeline @Mock private lateinit var notifCollection: NotifCollection @Mock private lateinit var mediaDataManager: MediaDataManager @Mock private lateinit var statusBarStateController: StatusBarStateController @Mock private lateinit var colorExtractor: SysuiColorExtractor @Mock private lateinit var keyguardStateController: KeyguardStateController @Mock private lateinit var dumpManager: DumpManager @Mock private lateinit var wallpaperManager: WallpaperManager @Mock private lateinit var notificationEntry: NotificationEntry @Mock private lateinit var notificationMediaManager: NotificationMediaManager lateinit var manager: NotificationMediaManager val clock = FakeSystemClock() val mainExecutor: DelayableExecutor = FakeExecutor(clock) @Mock private lateinit var mockManager: NotificationMediaManager @Mock private lateinit var mockBackDropView: BackDropView @Before fun setUp() { MockitoAnnotations.initMocks(this) doCallRealMethod().whenever(mockManager).updateMediaMetaData(anyBoolean(), anyBoolean()) doReturn(mockBackDropView).whenever(mockManager).backDropView manager = NotificationMediaManager( context, Lazy { Optional.of(centralSurfaces) }, Lazy { notificationShadeWindowController }, visibilityProvider, mediaArtworkProcessor, keyguardBypassController, notifPipeline, notifCollection, mainExecutor, mediaDataManager, statusBarStateController, colorExtractor, keyguardStateController, dumpManager, wallpaperManager, ) doCallRealMethod() .whenever(notificationMediaManager) .updateMediaMetaData(anyBoolean(), anyBoolean()) doReturn(mockBackDropView).whenever(notificationMediaManager).backDropView } /** * Check that updateMediaMetaData is a no-op with mIsLockscreenLiveWallpaperEnabled = true * Temporary test for the lock screen live wallpaper project. * * TODO(b/273443374): remove this test */ @After fun tearDown() {} /** Check that updateMediaMetaData is a no-op with mIsLockscreenLiveWallpaperEnabled = true */ @Test fun testUpdateMediaMetaDataDisabled() { mockManager.mIsLockscreenLiveWallpaperEnabled = true notificationMediaManager.mIsLockscreenLiveWallpaperEnabled = true for (metaDataChanged in listOf(true, false)) { for (allowEnterAnimation in listOf(true, false)) { mockManager.updateMediaMetaData(metaDataChanged, allowEnterAnimation) verify(mockManager, never()).mediaMetadata notificationMediaManager.updateMediaMetaData(metaDataChanged, allowEnterAnimation) verify(notificationMediaManager, never()).mediaMetadata } } } @Test fun testMetadataUpdated_doesNotRetainArtwork() { val artBmp = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888) val artUri = "content://example" val inputMetadata = MediaMetadata.Builder() .putBitmap(MediaMetadata.METADATA_KEY_ART, artBmp) .putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, artBmp) .putBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON, artBmp) .putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, artUri) .putString(MediaMetadata.METADATA_KEY_ART_URI, artUri) .putString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, artUri) .build() // Create a playing media notification val state = PlaybackState.Builder().setState(PlaybackState.STATE_PLAYING, 0L, 1f).build() val session = MediaSession(context, "NotificationMediaManagerTest") session.setMetadata(inputMetadata) session.setPlaybackState(state) val sbn = SbnBuilder().run { modifyNotification(context).also { it.setSmallIcon(android.R.drawable.ic_media_play) it.setStyle( Notification.MediaStyle().apply { setMediaSession(session.sessionToken) } ) } build() } whenever(notificationEntry.sbn).thenReturn(sbn) val collection = ArrayList<NotificationEntry>() collection.add(notificationEntry) whenever(notifPipeline.allNotifs).thenReturn(collection) // Trigger update in NotificationMediaManager manager.findAndUpdateMediaNotifications() // Verify that there is no artwork data retained val metadata = manager.mediaMetadata assertThat(metadata.getBitmap(MediaMetadata.METADATA_KEY_ART)).isNull() assertThat(metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART)).isNull() assertThat(metadata.getBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON)).isNull() assertThat(metadata.getString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI)).isNull() assertThat(metadata.getString(MediaMetadata.METADATA_KEY_ART_URI)).isNull() assertThat(metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI)).isNull() } } Loading
packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +5 −43 Original line number Diff line number Diff line Loading @@ -71,8 +71,6 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.util.Utils; import com.android.systemui.util.concurrency.DelayableExecutor; import dagger.Lazy; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; Loading @@ -82,6 +80,8 @@ import java.util.Objects; import java.util.Optional; import java.util.Set; import dagger.Lazy; /** * Handles tasks and state related to media notifications. For example, there is a 'current' media * notification, which this class keeps track of. Loading Loading @@ -161,48 +161,11 @@ public class NotificationMediaManager implements Dumpable { Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata); } mMediaArtworkProcessor.clearCache(); mMediaMetadata = cleanMetadata(metadata); mMediaMetadata = metadata; dispatchUpdateMediaMetaData(true /* changed */, true /* allowAnimation */); } }; /** * If this build is not configured for lockscreen artwork, clear artwork references from the * metadata to avoid excess memory usage. Otherwise, return as is. * @param data Original metadata * @return a copy without artwork data, or original */ private MediaMetadata cleanMetadata(MediaMetadata data) { if (SHOW_LOCKSCREEN_MEDIA_ARTWORK) { return data; } if (data == null) { return null; } if (DEBUG_MEDIA) { String[] artKeys = new String[] { MediaMetadata.METADATA_KEY_ART, MediaMetadata.METADATA_KEY_ALBUM_ART, MediaMetadata.METADATA_KEY_DISPLAY_ICON, MediaMetadata.METADATA_KEY_ALBUM_ART_URI, MediaMetadata.METADATA_KEY_ART_URI, MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI }; Log.v(TAG, "DEBUG_MEDIA: removing artwork from metadata"); for (String key: artKeys) { Log.v(TAG, " " + key + ": " + data.containsKey(key)); } } return new MediaMetadata.Builder(data) .putBitmap(MediaMetadata.METADATA_KEY_ART, null) .putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, null) .putBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON, null) .putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, null) .putString(MediaMetadata.METADATA_KEY_ART_URI, null) .putString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, null) .build(); } /** * Injected constructor. See {@link CentralSurfacesModule}. */ Loading Loading @@ -350,7 +313,6 @@ public class NotificationMediaManager implements Dumpable { return mMediaNotificationKey; } @VisibleForTesting public MediaMetadata getMediaMetadata() { return mMediaMetadata; } Loading Loading @@ -388,7 +350,7 @@ public class NotificationMediaManager implements Dumpable { * update this manager's internal state. * @return whether the current MediaMetadata changed (and needs to be announced to listeners). */ private boolean findPlayingMediaNotification( boolean findPlayingMediaNotification( @NonNull Collection<NotificationEntry> allNotifications) { boolean metaDataChanged = false; // Promote the media notification with a controller in 'playing' state, if any. Loading Loading @@ -421,7 +383,7 @@ public class NotificationMediaManager implements Dumpable { clearCurrentMediaNotificationSession(); mMediaController = controller; mMediaController.registerCallback(mMediaListener); mMediaMetadata = cleanMetadata(mMediaController.getMetadata()); mMediaMetadata = mMediaController.getMetadata(); if (DEBUG_MEDIA) { Log.v(TAG, "DEBUG_MEDIA: insert listener, found new controller: " + mMediaController + ", receive metadata: " + mMediaMetadata); Loading
packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java +1 −1 Original line number Diff line number Diff line Loading @@ -75,7 +75,7 @@ public interface CentralSurfaces extends Dumpable, ActivityStarter, LifecycleOwn boolean DEBUG_WAKEUP_DELAY = Compile.IS_DEBUG; // additional instrumentation for testing purposes; intended to be left on during development boolean CHATTY = DEBUG; boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = false; boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true; String ACTION_FAKE_ARTWORK = "fake_artwork"; int FADE_KEYGUARD_START_DELAY = 100; int FADE_KEYGUARD_DURATION = 300; Loading
packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt +17 −122 Original line number Diff line number Diff line Loading @@ -16,34 +16,11 @@ package com.android.systemui.statusbar import android.app.Notification import android.app.WallpaperManager import android.graphics.Bitmap import android.media.MediaMetadata import android.media.session.MediaSession import android.media.session.PlaybackState import android.testing.AndroidTestingRunner import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase import com.android.systemui.colorextraction.SysuiColorExtractor import com.android.systemui.dump.DumpManager import com.android.systemui.media.controls.pipeline.MediaDataManager import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.notification.collection.NotifCollection import com.android.systemui.statusbar.notification.collection.NotifPipeline import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider import com.android.systemui.statusbar.phone.CentralSurfaces import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.mockito.whenever import com.android.systemui.util.time.FakeSystemClock import com.google.common.truth.Truth.assertThat import dagger.Lazy import java.util.Optional import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith Loading @@ -55,121 +32,39 @@ import org.mockito.Mockito.never import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations /** * Temporary test for the lock screen live wallpaper project. * * TODO(b/273443374): remove this test */ @RunWith(AndroidTestingRunner::class) @SmallTest @RunWithLooper class NotificationMediaManagerTest : SysuiTestCase() { @Mock private lateinit var centralSurfaces: CentralSurfaces @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController @Mock private lateinit var visibilityProvider: NotificationVisibilityProvider @Mock private lateinit var mediaArtworkProcessor: MediaArtworkProcessor @Mock private lateinit var keyguardBypassController: KeyguardBypassController @Mock private lateinit var notifPipeline: NotifPipeline @Mock private lateinit var notifCollection: NotifCollection @Mock private lateinit var mediaDataManager: MediaDataManager @Mock private lateinit var statusBarStateController: StatusBarStateController @Mock private lateinit var colorExtractor: SysuiColorExtractor @Mock private lateinit var keyguardStateController: KeyguardStateController @Mock private lateinit var dumpManager: DumpManager @Mock private lateinit var wallpaperManager: WallpaperManager @Mock private lateinit var notificationEntry: NotificationEntry @Mock private lateinit var notificationMediaManager: NotificationMediaManager lateinit var manager: NotificationMediaManager val clock = FakeSystemClock() val mainExecutor: DelayableExecutor = FakeExecutor(clock) @Mock private lateinit var mockManager: NotificationMediaManager @Mock private lateinit var mockBackDropView: BackDropView @Before fun setUp() { MockitoAnnotations.initMocks(this) doCallRealMethod().whenever(mockManager).updateMediaMetaData(anyBoolean(), anyBoolean()) doReturn(mockBackDropView).whenever(mockManager).backDropView manager = NotificationMediaManager( context, Lazy { Optional.of(centralSurfaces) }, Lazy { notificationShadeWindowController }, visibilityProvider, mediaArtworkProcessor, keyguardBypassController, notifPipeline, notifCollection, mainExecutor, mediaDataManager, statusBarStateController, colorExtractor, keyguardStateController, dumpManager, wallpaperManager, ) doCallRealMethod() .whenever(notificationMediaManager) .updateMediaMetaData(anyBoolean(), anyBoolean()) doReturn(mockBackDropView).whenever(notificationMediaManager).backDropView } /** * Check that updateMediaMetaData is a no-op with mIsLockscreenLiveWallpaperEnabled = true * Temporary test for the lock screen live wallpaper project. * * TODO(b/273443374): remove this test */ @After fun tearDown() {} /** Check that updateMediaMetaData is a no-op with mIsLockscreenLiveWallpaperEnabled = true */ @Test fun testUpdateMediaMetaDataDisabled() { mockManager.mIsLockscreenLiveWallpaperEnabled = true notificationMediaManager.mIsLockscreenLiveWallpaperEnabled = true for (metaDataChanged in listOf(true, false)) { for (allowEnterAnimation in listOf(true, false)) { mockManager.updateMediaMetaData(metaDataChanged, allowEnterAnimation) verify(mockManager, never()).mediaMetadata notificationMediaManager.updateMediaMetaData(metaDataChanged, allowEnterAnimation) verify(notificationMediaManager, never()).mediaMetadata } } } @Test fun testMetadataUpdated_doesNotRetainArtwork() { val artBmp = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888) val artUri = "content://example" val inputMetadata = MediaMetadata.Builder() .putBitmap(MediaMetadata.METADATA_KEY_ART, artBmp) .putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, artBmp) .putBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON, artBmp) .putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, artUri) .putString(MediaMetadata.METADATA_KEY_ART_URI, artUri) .putString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI, artUri) .build() // Create a playing media notification val state = PlaybackState.Builder().setState(PlaybackState.STATE_PLAYING, 0L, 1f).build() val session = MediaSession(context, "NotificationMediaManagerTest") session.setMetadata(inputMetadata) session.setPlaybackState(state) val sbn = SbnBuilder().run { modifyNotification(context).also { it.setSmallIcon(android.R.drawable.ic_media_play) it.setStyle( Notification.MediaStyle().apply { setMediaSession(session.sessionToken) } ) } build() } whenever(notificationEntry.sbn).thenReturn(sbn) val collection = ArrayList<NotificationEntry>() collection.add(notificationEntry) whenever(notifPipeline.allNotifs).thenReturn(collection) // Trigger update in NotificationMediaManager manager.findAndUpdateMediaNotifications() // Verify that there is no artwork data retained val metadata = manager.mediaMetadata assertThat(metadata.getBitmap(MediaMetadata.METADATA_KEY_ART)).isNull() assertThat(metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART)).isNull() assertThat(metadata.getBitmap(MediaMetadata.METADATA_KEY_DISPLAY_ICON)).isNull() assertThat(metadata.getString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI)).isNull() assertThat(metadata.getString(MediaMetadata.METADATA_KEY_ART_URI)).isNull() assertThat(metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI)).isNull() } }