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

Commit 53575a31 authored by Beth Thibodeau's avatar Beth Thibodeau Committed by Automerger Merge Worker
Browse files

Merge "Do not retain album art in NotificationMediaManager if unused" into udc-dev am: 1c16aa4c

parents 9770d6fe 1c16aa4c
Loading
Loading
Loading
Loading
+43 −5
Original line number Diff line number Diff line
@@ -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);
+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 = true;
    boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = false;
    String ACTION_FAKE_ARTWORK = "fake_artwork";
    int FADE_KEYGUARD_START_DELAY = 100;
    int FADE_KEYGUARD_DURATION = 300;
+122 −17
Original line number Diff line number Diff line
@@ -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

    @After fun tearDown() {}
        manager =
            NotificationMediaManager(
                context,
                Lazy { Optional.of(centralSurfaces) },
                Lazy { notificationShadeWindowController },
                visibilityProvider,
                mediaArtworkProcessor,
                keyguardBypassController,
                notifPipeline,
                notifCollection,
                mainExecutor,
                mediaDataManager,
                statusBarStateController,
                colorExtractor,
                keyguardStateController,
                dumpManager,
                wallpaperManager,
            )
    }

    /** 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()
    }
}