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
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 36bad5e..9c20345 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1012,3 +1012,13 @@
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
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
index a67a8ab..fed6131 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
@@ -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 @@
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 @@
mediaDataManager,
dumpManager,
backgroundExecutor,
+ handler,
)
+ val mediaSession = MediaSession(context, "TEST")
+ notificationMediaManager.mMediaController =
+ MediaController(context, mediaSession.sessionToken)
verify(mediaDataManager).addListener(listenerCaptor.capture())
}
@@ -114,4 +123,32 @@
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()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 03c6670..6d34a0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -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.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.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 @@
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 @@
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 @@
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 @@
mNotifPipeline = notifPipeline;
mNotifCollection = notifCollection;
mBackgroundExecutor = backgroundExecutor;
+ mHandler = handler;
setupNotifPipeline();
@@ -262,6 +283,14 @@
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 void findAndUpdateMediaNotifications() {
// TODO(b/169655907): get the semi-filtered notifications for current user
Collection<NotificationEntry> allNotifications = mNotifPipeline.getAllNotifs();
- findPlayingMediaNotification(allNotifications);
+ if (notificationMediaManagerBackgroundExecution()) {
+ mBackgroundExecutor.execute(() -> findPlayingMediaNotification(allNotifications));
+ } else {
+ findPlayingMediaNotification(allNotifications);
+ }
dispatchUpdateMediaMetaData();
}
@@ -312,7 +345,7 @@
// 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 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 @@
Log.v(TAG, "DEBUG_MEDIA: Disconnecting from old controller: "
+ mMediaController.getPackageName());
}
- // TODO(b/336612071): move to background thread
mMediaController.unregisterCallback(mMediaListener);
}
mMediaController = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
index 0524589..7df7ef1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/dagger/CentralSurfacesDependenciesModule.java
@@ -19,6 +19,7 @@
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 @@
NotifCollection notifCollection,
MediaDataManager mediaDataManager,
DumpManager dumpManager,
- @Background Executor backgroundExecutor) {
+ @Background Executor backgroundExecutor,
+ @Main Handler handler) {
return new NotificationMediaManager(
context,
visibilityProvider,
@@ -107,7 +109,8 @@
notifCollection,
mediaDataManager,
dumpManager,
- backgroundExecutor);
+ backgroundExecutor,
+ handler);
}
/** */