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

Commit 69644153 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Close LS media player when session is destroyed" into rvc-dev am: 0dcd72e1

Change-Id: I4b1dcead8785d2c8d4b340c3859b66d7150e75a0
parents 91c7ab0b 0dcd72e1
Loading
Loading
Loading
Loading
+20 −3
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.media.MediaMetadata;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
@@ -40,6 +42,7 @@ import androidx.palette.graphics.Palette;
import com.android.internal.util.ContrastColorUtil;
import com.android.systemui.R;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.media.MediaControllerFactory;
import com.android.systemui.statusbar.notification.MediaNotificationProcessor;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.stack.MediaHeaderView;
@@ -71,10 +74,11 @@ public class KeyguardMediaPlayer {
    private KeyguardMediaObserver mObserver;

    @Inject
    public KeyguardMediaPlayer(Context context, @Background Executor backgroundExecutor) {
    public KeyguardMediaPlayer(Context context, MediaControllerFactory factory,
            @Background Executor backgroundExecutor) {
        mContext = context;
        mBackgroundExecutor = backgroundExecutor;
        mViewModel = new KeyguardMediaViewModel(context);
        mViewModel = new KeyguardMediaViewModel(context, factory);
    }

    /** Binds media controls to a view hierarchy. */
@@ -139,14 +143,16 @@ public class KeyguardMediaPlayer {
    private static final class KeyguardMediaViewModel {

        private final Context mContext;
        private final MediaControllerFactory mMediaControllerFactory;
        private final MutableLiveData<KeyguardMedia> mMedia = new MutableLiveData<>();
        private final Object mActionsLock = new Object();
        private List<PendingIntent> mActions;
        private float mAlbumArtRadius;
        private int mAlbumArtSize;

        KeyguardMediaViewModel(Context context) {
        KeyguardMediaViewModel(Context context, MediaControllerFactory factory) {
            mContext = context;
            mMediaControllerFactory = factory;
            loadDimens();
        }

@@ -162,6 +168,17 @@ public class KeyguardMediaPlayer {
        public void updateControls(NotificationEntry entry, Icon appIcon,
                MediaMetadata mediaMetadata) {

            // Check the playback state of the media controller. If it is null, then the session was
            // probably destroyed. Don't update in this case.
            final MediaSession.Token token = entry.getSbn().getNotification().extras
                    .getParcelable(Notification.EXTRA_MEDIA_SESSION);
            final MediaController controller = token != null
                    ? mMediaControllerFactory.create(token) : null;
            if (controller != null && controller.getPlaybackState() == null) {
                clearControls();
                return;
            }

            // Foreground and Background colors computed from album art
            Notification notif = entry.getSbn().getNotification();
            int fgColor = notif.color;
+45 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.media;

import android.content.Context;
import android.media.session.MediaController;
import android.media.session.MediaSession;

import javax.inject.Inject;

/**
 * Testable wrapper around {@link MediaController} constructor.
 */
public class MediaControllerFactory {

    private final Context mContext;

    @Inject
    public MediaControllerFactory(Context context) {
        mContext = context;
    }

    /**
     * Creates a new MediaController from a session's token.
     *
     * @param token The token for the session. This value must never be null.
     */
    public MediaController create(MediaSession.Token token) {
        return new MediaController(mContext, token);
    }
}
+37 −6
Original line number Diff line number Diff line
@@ -16,8 +16,12 @@

package com.android.keyguard

import android.app.Notification
import android.graphics.drawable.Icon
import android.media.MediaMetadata
import android.media.session.MediaController
import android.media.session.MediaSession
import android.media.session.PlaybackState
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.View
@@ -28,7 +32,9 @@ import androidx.test.filters.SmallTest

import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.media.MediaControllerFactory
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
@@ -38,6 +44,7 @@ import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.Mockito.`when` as whenever
@@ -48,9 +55,12 @@ import org.mockito.Mockito.`when` as whenever
public class KeyguardMediaPlayerTest : SysuiTestCase() {

    private lateinit var keyguardMediaPlayer: KeyguardMediaPlayer
    @Mock private lateinit var mockMediaFactory: MediaControllerFactory
    @Mock private lateinit var mockMediaController: MediaController
    private lateinit var playbackState: PlaybackState
    private lateinit var fakeExecutor: FakeExecutor
    private lateinit var mediaMetadata: MediaMetadata.Builder
    private lateinit var entry: NotificationEntryBuilder
    private lateinit var entry: NotificationEntry
    @Mock private lateinit var mockView: View
    private lateinit var songView: TextView
    private lateinit var artistView: TextView
@@ -70,8 +80,16 @@ public class KeyguardMediaPlayerTest : SysuiTestCase() {

    @Before
    public fun setup() {
        playbackState = PlaybackState.Builder().run {
            build()
        }
        mockMediaController = mock(MediaController::class.java)
        whenever(mockMediaController.getPlaybackState()).thenReturn(playbackState)
        mockMediaFactory = mock(MediaControllerFactory::class.java)
        whenever(mockMediaFactory.create(any())).thenReturn(mockMediaController)

        fakeExecutor = FakeExecutor(FakeSystemClock())
        keyguardMediaPlayer = KeyguardMediaPlayer(context, fakeExecutor)
        keyguardMediaPlayer = KeyguardMediaPlayer(context, mockMediaFactory, fakeExecutor)
        mockIcon = mock(Icon::class.java)

        mockView = mock(View::class.java)
@@ -81,7 +99,9 @@ public class KeyguardMediaPlayerTest : SysuiTestCase() {
        whenever<TextView>(mockView.findViewById(R.id.header_artist)).thenReturn(artistView)

        mediaMetadata = MediaMetadata.Builder()
        entry = NotificationEntryBuilder()
        entry = NotificationEntryBuilder().build()
        entry.getSbn().getNotification().extras.putParcelable(Notification.EXTRA_MEDIA_SESSION,
                MediaSession.Token(1, null))

        ArchTaskExecutor.getInstance().setDelegate(taskExecutor)

@@ -109,7 +129,7 @@ public class KeyguardMediaPlayerTest : SysuiTestCase() {

    @Test
    public fun testUpdateControls() {
        keyguardMediaPlayer.updateControls(entry.build(), mockIcon, mediaMetadata.build())
        keyguardMediaPlayer.updateControls(entry, mockIcon, mediaMetadata.build())
        FakeExecutor.exhaustExecutors(fakeExecutor)
        verify(mockView).setVisibility(View.VISIBLE)
    }
@@ -121,12 +141,23 @@ public class KeyguardMediaPlayerTest : SysuiTestCase() {
        verify(mockView).setVisibility(View.GONE)
    }

    @Test
    public fun testUpdateControlsNullPlaybackState() {
        // GIVEN that the playback state is null (ie. the media session was destroyed)
        whenever(mockMediaController.getPlaybackState()).thenReturn(null)
        // WHEN updated
        keyguardMediaPlayer.updateControls(entry, mockIcon, mediaMetadata.build())
        FakeExecutor.exhaustExecutors(fakeExecutor)
        // THEN the controls are cleared (ie. visibility is set to GONE)
        verify(mockView).setVisibility(View.GONE)
    }

    @Test
    public fun testSongName() {
        val song: String = "Song"
        mediaMetadata.putText(MediaMetadata.METADATA_KEY_TITLE, song)

        keyguardMediaPlayer.updateControls(entry.build(), mockIcon, mediaMetadata.build())
        keyguardMediaPlayer.updateControls(entry, mockIcon, mediaMetadata.build())

        assertThat(fakeExecutor.runAllReady()).isEqualTo(1)
        assertThat(songView.getText()).isEqualTo(song)
@@ -137,7 +168,7 @@ public class KeyguardMediaPlayerTest : SysuiTestCase() {
        val artist: String = "Artist"
        mediaMetadata.putText(MediaMetadata.METADATA_KEY_ARTIST, artist)

        keyguardMediaPlayer.updateControls(entry.build(), mockIcon, mediaMetadata.build())
        keyguardMediaPlayer.updateControls(entry, mockIcon, mediaMetadata.build())

        assertThat(fakeExecutor.runAllReady()).isEqualTo(1)
        assertThat(artistView.getText()).isEqualTo(artist)