Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bf2a7c7f authored by Bart Sears's avatar Bart Sears Committed by Android (Google) Code Review
Browse files

Merge "Revert "Do not retain album art in NotificationMediaManager if unused"" into udc-dev

parents f475b533 b20d1951
Loading
Loading
Loading
Loading
+5 −43
Original line number Diff line number Diff line
@@ -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;
@@ -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.
@@ -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}.
     */
@@ -350,7 +313,6 @@ public class NotificationMediaManager implements Dumpable {
        return mMediaNotificationKey;
    }

    @VisibleForTesting
    public MediaMetadata getMediaMetadata() {
        return mMediaMetadata;
    }
@@ -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.
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -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;
+17 −122
Original line number Diff line number Diff line
@@ -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
@@ -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()
    }
}