Loading packages/SystemUI/aconfig/systemui.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -1026,3 +1026,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 } } packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt +37 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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()) Loading @@ -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()) } Loading Loading @@ -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() } } packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +56 −8 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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}. */ Loading @@ -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; Loading @@ -130,6 +150,7 @@ public class NotificationMediaManager implements Dumpable { mNotifPipeline = notifPipeline; mNotifCollection = notifCollection; mBackgroundExecutor = backgroundExecutor; mHandler = handler; setupNotifPipeline(); Loading Loading @@ -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)); } Loading @@ -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(); } Loading Loading @@ -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: " Loading @@ -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); } Loading Loading @@ -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; Loading packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java +5 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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, Loading @@ -107,7 +109,8 @@ public interface CentralSurfacesDependenciesModule { notifCollection, mediaDataManager, dumpManager, backgroundExecutor); backgroundExecutor, handler); } /** */ Loading Loading
packages/SystemUI/aconfig/systemui.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -1026,3 +1026,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 } }
packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt +37 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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()) Loading @@ -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()) } Loading Loading @@ -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() } }
packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java +56 −8 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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); Loading @@ -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}. */ Loading @@ -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; Loading @@ -130,6 +150,7 @@ public class NotificationMediaManager implements Dumpable { mNotifPipeline = notifPipeline; mNotifCollection = notifCollection; mBackgroundExecutor = backgroundExecutor; mHandler = handler; setupNotifPipeline(); Loading Loading @@ -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)); } Loading @@ -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(); } Loading Loading @@ -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: " Loading @@ -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); } Loading Loading @@ -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; Loading
packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java +5 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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, Loading @@ -107,7 +109,8 @@ public interface CentralSurfacesDependenciesModule { notifCollection, mediaDataManager, dumpManager, backgroundExecutor); backgroundExecutor, handler); } /** */ Loading