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

Commit e3247486 authored by Michael Mikhail's avatar Michael Mikhail
Browse files

Send media controller code to background thread.

Flag: com.android.systemui.notification_media_manager_background_execution
Bug: 336612071
Test: manual.
Test: atest SystemUiRoboTests:NotificationMediaManagerTest
Change-Id: I8c3f6fbcfdf94d87ed5a9c3f2de8035ef49680c9
parent d04f7b37
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -1012,3 +1012,13 @@ flag {
     purpose: PURPOSE_BUGFIX
   }
}

flag {
  name: "notification_media_manager_background_execution"
  namespace: "systemui"
  description: "Decide whether to execute binder calls in background thread"
  bug: "336612071"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}
+37 −0
Original line number Diff line number Diff line
@@ -16,6 +16,10 @@

package com.android.systemui.statusbar

import android.media.MediaMetadata
import android.media.session.MediaController
import android.media.session.MediaSession
import android.os.fakeExecutorHandler
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.service.notification.NotificationListenerService
@@ -54,6 +58,7 @@ class NotificationMediaManagerTest : SysuiTestCase() {
    private val notifPipeline = kosmos.notifPipeline
    private val notifCollection = kosmos.mockNotifCollection
    private val dumpManager = kosmos.dumpManager
    private val handler = kosmos.fakeExecutorHandler
    private val mediaDataManager = mock<MediaDataManager>()
    private val backgroundExecutor = FakeExecutor(FakeSystemClock())

@@ -72,7 +77,11 @@ class NotificationMediaManagerTest : SysuiTestCase() {
                mediaDataManager,
                dumpManager,
                backgroundExecutor,
                handler,
            )
        val mediaSession = MediaSession(context, "TEST")
        notificationMediaManager.mMediaController =
            MediaController(context, mediaSession.sessionToken)

        verify(mediaDataManager).addListener(listenerCaptor.capture())
    }
@@ -114,4 +123,32 @@ class NotificationMediaManagerTest : SysuiTestCase() {
        verify(notifCollection).dismissNotification(notifEntryCaptor.capture(), any())
        assertThat(notifEntryCaptor.lastValue.key).isEqualTo(KEY)
    }

    @Test
    @EnableFlags(Flags.FLAG_NOTIFICATION_MEDIA_MANAGER_BACKGROUND_EXECUTION)
    fun clearMediaNotification_flagOn_resetMediaMetadata() {
        // set up media metadata.
        notificationMediaManager.mMediaListener.onMetadataChanged(MediaMetadata.Builder().build())
        backgroundExecutor.runAllReady()

        // clear media notification.
        notificationMediaManager.clearCurrentMediaNotification()
        backgroundExecutor.runAllReady()

        assertThat(notificationMediaManager.mediaMetadata).isNull()
        assertThat(notificationMediaManager.mMediaController).isNull()
    }

    @Test
    @DisableFlags(Flags.FLAG_NOTIFICATION_MEDIA_MANAGER_BACKGROUND_EXECUTION)
    fun clearMediaNotification_flagOff_resetMediaMetadata() {
        // set up media metadata.
        notificationMediaManager.mMediaListener.onMetadataChanged(MediaMetadata.Builder().build())

        // clear media notification.
        notificationMediaManager.clearCurrentMediaNotification()

        assertThat(notificationMediaManager.mediaMetadata).isNull()
        assertThat(notificationMediaManager.mMediaController).isNull()
    }
}
+56 −8
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar;

import static com.android.systemui.Flags.mediaControlsUserInitiatedDeleteintent;
import static com.android.systemui.Flags.notificationMediaManagerBackgroundExecution;

import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -26,12 +27,16 @@ import android.media.MediaMetadata;
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
import android.os.Handler;
import android.service.notification.NotificationStats;
import android.service.notification.StatusBarNotification;
import android.util.Log;

import androidx.annotation.VisibleForTesting;

import com.android.systemui.Dumpable;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.media.controls.domain.pipeline.MediaDataManager;
import com.android.systemui.media.controls.shared.model.MediaData;
@@ -48,6 +53,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.Executor;
@@ -80,13 +86,16 @@ public class NotificationMediaManager implements Dumpable {
    private final ArrayList<MediaListener> mMediaListeners;

    private final Executor mBackgroundExecutor;
    private final Handler mHandler;

    protected NotificationPresenter mPresenter;
    private MediaController mMediaController;
    @VisibleForTesting
    MediaController mMediaController;
    private String mMediaNotificationKey;
    private MediaMetadata mMediaMetadata;

    private final MediaController.Callback mMediaListener = new MediaController.Callback() {
    @VisibleForTesting
    final MediaController.Callback mMediaListener = new MediaController.Callback() {
        @Override
        public void onPlaybackStateChanged(PlaybackState state) {
            super.onPlaybackStateChanged(state);
@@ -107,11 +116,20 @@ public class NotificationMediaManager implements Dumpable {
            if (DEBUG_MEDIA) {
                Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
            }
            mMediaMetadata = metadata;
            if (notificationMediaManagerBackgroundExecution()) {
                mBackgroundExecutor.execute(() -> setMediaMetadata(metadata));
            } else {
                setMediaMetadata(metadata);
            }

            dispatchUpdateMediaMetaData();
        }
    };

    private void setMediaMetadata(MediaMetadata metadata) {
        mMediaMetadata = metadata;
    }

    /**
     * Injected constructor. See {@link CentralSurfacesModule}.
     */
@@ -122,7 +140,9 @@ public class NotificationMediaManager implements Dumpable {
            NotifCollection notifCollection,
            MediaDataManager mediaDataManager,
            DumpManager dumpManager,
            @Background Executor backgroundExecutor) {
            @Background Executor backgroundExecutor,
            @Main Handler handler
    ) {
        mContext = context;
        mMediaListeners = new ArrayList<>();
        mVisibilityProvider = visibilityProvider;
@@ -130,6 +150,7 @@ public class NotificationMediaManager implements Dumpable {
        mNotifPipeline = notifPipeline;
        mNotifCollection = notifCollection;
        mBackgroundExecutor = backgroundExecutor;
        mHandler = handler;

        setupNotifPipeline();

@@ -262,6 +283,14 @@ public class NotificationMediaManager implements Dumpable {

    public void addCallback(MediaListener callback) {
        mMediaListeners.add(callback);
        if (notificationMediaManagerBackgroundExecution()) {
            mBackgroundExecutor.execute(() -> updateMediaMetaData(callback));
        } else {
            updateMediaMetaData(callback);
        }
    }

    private void updateMediaMetaData(MediaListener callback) {
        callback.onPrimaryMetadataOrStateChanged(mMediaMetadata,
                getMediaControllerPlaybackState(mMediaController));
    }
@@ -273,7 +302,11 @@ public class NotificationMediaManager implements Dumpable {
    public void findAndUpdateMediaNotifications() {
        // TODO(b/169655907): get the semi-filtered notifications for current user
        Collection<NotificationEntry> allNotifications = mNotifPipeline.getAllNotifs();
        if (notificationMediaManagerBackgroundExecution()) {
            mBackgroundExecutor.execute(() -> findPlayingMediaNotification(allNotifications));
        } else {
            findPlayingMediaNotification(allNotifications);
        }
        dispatchUpdateMediaMetaData();
    }

@@ -312,7 +345,7 @@ public class NotificationMediaManager implements Dumpable {
            // We have a new media session
            clearCurrentMediaNotificationSession();
            mMediaController = controller;
            mMediaController.registerCallback(mMediaListener);
            mMediaController.registerCallback(mMediaListener, mHandler);
            mMediaMetadata = mMediaController.getMetadata();
            if (DEBUG_MEDIA) {
                Log.v(TAG, "DEBUG_MEDIA: insert listener, found new controller: "
@@ -331,13 +364,29 @@ public class NotificationMediaManager implements Dumpable {
    }

    public void clearCurrentMediaNotification() {
        if (notificationMediaManagerBackgroundExecution()) {
            mBackgroundExecutor.execute(this::clearMediaNotification);
        } else {
            clearMediaNotification();
        }
    }

    private void clearMediaNotification() {
        mMediaNotificationKey = null;
        clearCurrentMediaNotificationSession();
    }

    private void dispatchUpdateMediaMetaData() {
        @PlaybackState.State int state = getMediaControllerPlaybackState(mMediaController);
        ArrayList<MediaListener> callbacks = new ArrayList<>(mMediaListeners);
        if (notificationMediaManagerBackgroundExecution()) {
            mBackgroundExecutor.execute(() -> updateMediaMetaData(callbacks));
        } else {
            updateMediaMetaData(callbacks);
        }
    }

    private void updateMediaMetaData(List<MediaListener> callbacks) {
        @PlaybackState.State int state = getMediaControllerPlaybackState(mMediaController);
        for (int i = 0; i < callbacks.size(); i++) {
            callbacks.get(i).onPrimaryMetadataOrStateChanged(mMediaMetadata, state);
        }
@@ -393,7 +442,6 @@ public class NotificationMediaManager implements Dumpable {
                Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: "
                        + mMediaController.getPackageName());
            }
            // TODO(b/336612071): move to background thread
            mMediaController.unregisterCallback(mMediaListener);
        }
        mMediaController = null;
+5 −2
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.dagger;
import static com.android.systemui.Flags.predictiveBackAnimateDialogs;

import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
import android.service.dreams.IDreamManager;
import android.util.Log;
@@ -99,7 +100,8 @@ public interface CentralSurfacesDependenciesModule {
            NotifCollection notifCollection,
            MediaDataManager mediaDataManager,
            DumpManager dumpManager,
            @Background Executor backgroundExecutor) {
            @Background Executor backgroundExecutor,
            @Main Handler handler) {
        return new NotificationMediaManager(
                context,
                visibilityProvider,
@@ -107,7 +109,8 @@ public interface CentralSurfacesDependenciesModule {
                notifCollection,
                mediaDataManager,
                dumpManager,
                backgroundExecutor);
                backgroundExecutor,
                handler);
    }

    /** */