Merge "Do not retain album art in NotificationMediaManager if unused" into udc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
1c16aa4cf4
@@ -71,6 +71,8 @@ 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;
|
||||
@@ -80,8 +82,6 @@ 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.
|
||||
@@ -161,11 +161,48 @@ public class NotificationMediaManager implements Dumpable {
|
||||
Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
|
||||
}
|
||||
mMediaArtworkProcessor.clearCache();
|
||||
mMediaMetadata = metadata;
|
||||
mMediaMetadata = cleanMetadata(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}.
|
||||
*/
|
||||
@@ -313,6 +350,7 @@ public class NotificationMediaManager implements Dumpable {
|
||||
return mMediaNotificationKey;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public MediaMetadata getMediaMetadata() {
|
||||
return mMediaMetadata;
|
||||
}
|
||||
@@ -350,7 +388,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).
|
||||
*/
|
||||
boolean findPlayingMediaNotification(
|
||||
private boolean findPlayingMediaNotification(
|
||||
@NonNull Collection<NotificationEntry> allNotifications) {
|
||||
boolean metaDataChanged = false;
|
||||
// Promote the media notification with a controller in 'playing' state, if any.
|
||||
@@ -383,7 +421,7 @@ public class NotificationMediaManager implements Dumpable {
|
||||
clearCurrentMediaNotificationSession();
|
||||
mMediaController = controller;
|
||||
mMediaController.registerCallback(mMediaListener);
|
||||
mMediaMetadata = mMediaController.getMetadata();
|
||||
mMediaMetadata = cleanMetadata(mMediaController.getMetadata());
|
||||
if (DEBUG_MEDIA) {
|
||||
Log.v(TAG, "DEBUG_MEDIA: insert listener, found new controller: "
|
||||
+ mMediaController + ", receive metadata: " + mMediaMetadata);
|
||||
|
||||
@@ -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 = true;
|
||||
boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = false;
|
||||
String ACTION_FAKE_ARTWORK = "fake_artwork";
|
||||
int FADE_KEYGUARD_START_DELAY = 100;
|
||||
int FADE_KEYGUARD_DURATION = 300;
|
||||
|
||||
@@ -16,11 +16,34 @@
|
||||
|
||||
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 org.junit.After
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import dagger.Lazy
|
||||
import java.util.Optional
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
@@ -32,39 +55,121 @@ 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 notificationMediaManager: NotificationMediaManager
|
||||
@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
|
||||
|
||||
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(notificationMediaManager)
|
||||
.updateMediaMetaData(anyBoolean(), anyBoolean())
|
||||
doReturn(mockBackDropView).whenever(notificationMediaManager).backDropView
|
||||
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,
|
||||
)
|
||||
}
|
||||
|
||||
@After fun tearDown() {}
|
||||
|
||||
/** Check that updateMediaMetaData is a no-op with mIsLockscreenLiveWallpaperEnabled = true */
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@Test
|
||||
fun testUpdateMediaMetaDataDisabled() {
|
||||
notificationMediaManager.mIsLockscreenLiveWallpaperEnabled = true
|
||||
mockManager.mIsLockscreenLiveWallpaperEnabled = true
|
||||
for (metaDataChanged in listOf(true, false)) {
|
||||
for (allowEnterAnimation in listOf(true, false)) {
|
||||
notificationMediaManager.updateMediaMetaData(metaDataChanged, allowEnterAnimation)
|
||||
verify(notificationMediaManager, never()).mediaMetadata
|
||||
mockManager.updateMediaMetaData(metaDataChanged, allowEnterAnimation)
|
||||
verify(mockManager, 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()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user