NotificationMediaManager populates media player when using new pipeline.

Test: manual
Change-Id: I25e623c28e991fa907541cb553ba8f9f74e60fe0
This commit is contained in:
Jeff DeCew
2020-09-25 11:16:26 -04:00
parent bf881172ff
commit 75d60f7a79
2 changed files with 169 additions and 90 deletions

View File

@@ -40,6 +40,7 @@ import android.os.Trace;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.DeviceConfig.Properties;
import android.service.notification.StatusBarNotification;
import android.util.ArraySet;
import android.util.Log;
import android.view.View;
@@ -57,6 +58,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.dagger.StatusBarModule;
import com.android.systemui.statusbar.notification.NotificationEntryListener;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
@@ -77,6 +79,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import dagger.Lazy;
@@ -106,6 +109,8 @@ public class NotificationMediaManager implements Dumpable {
private final NotificationEntryManager mEntryManager;
private final MediaDataManager mMediaDataManager;
private final NotifPipeline mNotifPipeline;
private final boolean mUsingNotifPipeline;
@Nullable
private Lazy<NotificationShadeWindowController> mNotificationShadeWindowController;
@@ -189,6 +194,8 @@ public class NotificationMediaManager implements Dumpable {
NotificationEntryManager notificationEntryManager,
MediaArtworkProcessor mediaArtworkProcessor,
KeyguardBypassController keyguardBypassController,
NotifPipeline notifPipeline,
FeatureFlags featureFlags,
@Main DelayableExecutor mainExecutor,
DeviceConfigProxy deviceConfig,
MediaDataManager mediaDataManager) {
@@ -206,17 +213,65 @@ public class NotificationMediaManager implements Dumpable {
mEntryManager = notificationEntryManager;
mMainExecutor = mainExecutor;
mMediaDataManager = mediaDataManager;
mNotifPipeline = notifPipeline;
notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
if (!featureFlags.isNewNotifPipelineRenderingEnabled()) {
setupNEM();
mUsingNotifPipeline = false;
} else {
setupNotifPipeline();
mUsingNotifPipeline = true;
}
mShowCompactMediaSeekbar = "true".equals(
DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED));
deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
mContext.getMainExecutor(),
mPropertiesChangedListener);
}
private void setupNotifPipeline() {
mNotifPipeline.addCollectionListener(new NotifCollectionListener() {
@Override
public void onEntryAdded(@NonNull NotificationEntry entry) {
mMediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
}
@Override
public void onEntryUpdated(NotificationEntry entry) {
mMediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
}
@Override
public void onEntryBind(NotificationEntry entry, StatusBarNotification sbn) {
findAndUpdateMediaNotifications();
}
@Override
public void onEntryRemoved(@NonNull NotificationEntry entry, int reason) {
removeEntry(entry);
}
@Override
public void onEntryCleanUp(@NonNull NotificationEntry entry) {
removeEntry(entry);
}
});
}
private void setupNEM() {
mEntryManager.addNotificationEntryListener(new NotificationEntryListener() {
@Override
public void onPendingEntryAdded(NotificationEntry entry) {
mediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
mMediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
}
@Override
public void onPreEntryUpdated(NotificationEntry entry) {
mediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
mMediaDataManager.onNotificationAdded(entry.getKey(), entry.getSbn());
}
@Override
@@ -231,8 +286,8 @@ public class NotificationMediaManager implements Dumpable {
@Override
public void onEntryRemoved(
NotificationEntry entry,
NotificationVisibility visibility,
@NonNull NotificationEntry entry,
@Nullable NotificationVisibility visibility,
boolean removedByUser,
int reason) {
removeEntry(entry);
@@ -242,20 +297,12 @@ public class NotificationMediaManager implements Dumpable {
// Pending entries are never inflated, and will never generate a call to onEntryRemoved().
// This can happen when notifications are added and canceled before inflation. Add this
// separate listener for cleanup, since media inflation occurs onPendingEntryAdded().
notificationEntryManager.addCollectionListener(new NotifCollectionListener() {
mEntryManager.addCollectionListener(new NotifCollectionListener() {
@Override
public void onEntryCleanUp(@NonNull NotificationEntry entry) {
removeEntry(entry);
}
});
mShowCompactMediaSeekbar = "true".equals(
DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.COMPACT_MEDIA_SEEKBAR_ENABLED));
deviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
mContext.getMainExecutor(),
mPropertiesChangedListener);
}
private void removeEntry(NotificationEntry entry) {
@@ -299,14 +346,24 @@ public class NotificationMediaManager implements Dumpable {
if (mMediaNotificationKey == null) {
return null;
}
synchronized (mEntryManager) {
NotificationEntry entry = mEntryManager
if (mUsingNotifPipeline) {
// TODO(b/169655596): Either add O(1) lookup, or cache this icon?
return mNotifPipeline.getAllNotifs().stream()
.filter(entry -> Objects.equals(entry.getKey(), mMediaNotificationKey))
.findAny()
.map(entry -> entry.getIcons().getShelfIcon())
.map(StatusBarIconView::getSourceIcon)
.orElse(null);
} else {
synchronized (mEntryManager) {
NotificationEntry entry = mEntryManager
.getActiveNotificationUnfiltered(mMediaNotificationKey);
if (entry == null || entry.getIcons().getShelfIcon() == null) {
return null;
}
if (entry == null || entry.getIcons().getShelfIcon() == null) {
return null;
}
return entry.getIcons().getShelfIcon().getSourceIcon();
return entry.getIcons().getShelfIcon().getSourceIcon();
}
}
}
@@ -321,94 +378,110 @@ public class NotificationMediaManager implements Dumpable {
}
public void findAndUpdateMediaNotifications() {
boolean metaDataChanged;
if (mUsingNotifPipeline) {
// TODO(b/169655907): get the semi-filtered notifications for current user
Collection<NotificationEntry> allNotifications = mNotifPipeline.getAllNotifs();
metaDataChanged = findPlayingMediaNotification(allNotifications);
} else {
synchronized (mEntryManager) {
Collection<NotificationEntry> allNotifications = mEntryManager.getAllNotifs();
metaDataChanged = findPlayingMediaNotification(allNotifications);
}
if (metaDataChanged) {
mEntryManager.updateNotifications("NotificationMediaManager - metaDataChanged");
}
}
dispatchUpdateMediaMetaData(metaDataChanged, true /* allowEnterAnimation */);
}
/**
* Find a notification and media controller associated with the playing media session, and
* update this manager's internal state.
* @return whether the current MediaMetadata changed (and needs to be announced to listeners).
*/
private boolean findPlayingMediaNotification(
@NonNull Collection<NotificationEntry> allNotifications) {
boolean metaDataChanged = false;
// Promote the media notification with a controller in 'playing' state, if any.
NotificationEntry mediaNotification = null;
MediaController controller = null;
for (NotificationEntry entry : allNotifications) {
if (entry.isMediaNotification()) {
final MediaSession.Token token =
entry.getSbn().getNotification().extras.getParcelable(
Notification.EXTRA_MEDIA_SESSION);
if (token != null) {
MediaController aController = new MediaController(mContext, token);
if (PlaybackState.STATE_PLAYING
== getMediaControllerPlaybackState(aController)) {
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching "
+ entry.getSbn().getKey());
}
mediaNotification = entry;
controller = aController;
break;
}
}
}
}
if (mediaNotification == null) {
// Still nothing? OK, let's just look for live media sessions and see if they match
// one of our notifications. This will catch apps that aren't (yet!) using media
// notifications.
synchronized (mEntryManager) {
Collection<NotificationEntry> allNotifications = mEntryManager.getAllNotifs();
if (mMediaSessionManager != null) {
// TODO: Should this really be for all users? It appears that inactive users
// can't have active sessions, which would mean it is fine.
final List<MediaController> sessions =
mMediaSessionManager.getActiveSessionsForUser(null, UserHandle.USER_ALL);
// Promote the media notification with a controller in 'playing' state, if any.
NotificationEntry mediaNotification = null;
MediaController controller = null;
for (NotificationEntry entry : allNotifications) {
if (entry.isMediaNotification()) {
final MediaSession.Token token =
entry.getSbn().getNotification().extras.getParcelable(
Notification.EXTRA_MEDIA_SESSION);
if (token != null) {
MediaController aController = new MediaController(mContext, token);
if (PlaybackState.STATE_PLAYING ==
getMediaControllerPlaybackState(aController)) {
for (MediaController aController : sessions) {
// now to see if we have one like this
final String pkg = aController.getPackageName();
for (NotificationEntry entry : allNotifications) {
if (entry.getSbn().getPackageName().equals(pkg)) {
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching "
Log.v(TAG, "DEBUG_MEDIA: found controller matching "
+ entry.getSbn().getKey());
}
mediaNotification = entry;
controller = aController;
mediaNotification = entry;
break;
}
}
}
}
if (mediaNotification == null) {
// Still nothing? OK, let's just look for live media sessions and see if they match
// one of our notifications. This will catch apps that aren't (yet!) using media
// notifications.
}
if (mMediaSessionManager != null) {
// TODO: Should this really be for all users?
final List<MediaController> sessions
= mMediaSessionManager.getActiveSessionsForUser(
null,
UserHandle.USER_ALL);
for (MediaController aController : sessions) {
// now to see if we have one like this
final String pkg = aController.getPackageName();
for (NotificationEntry entry : allNotifications) {
if (entry.getSbn().getPackageName().equals(pkg)) {
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: found controller matching "
+ entry.getSbn().getKey());
}
controller = aController;
mediaNotification = entry;
break;
}
}
}
}
if (controller != null && !sameSessions(mMediaController, controller)) {
// We have a new media session
clearCurrentMediaNotificationSession();
mMediaController = controller;
mMediaController.registerCallback(mMediaListener);
mMediaMetadata = mMediaController.getMetadata();
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: insert listener, found new controller: "
+ mMediaController + ", receive metadata: " + mMediaMetadata);
}
if (controller != null && !sameSessions(mMediaController, controller)) {
// We have a new media session
clearCurrentMediaNotificationSession();
mMediaController = controller;
mMediaController.registerCallback(mMediaListener);
mMediaMetadata = mMediaController.getMetadata();
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: insert listener, found new controller: "
+ mMediaController + ", receive metadata: " + mMediaMetadata);
}
metaDataChanged = true;
}
metaDataChanged = true;
}
if (mediaNotification != null
&& !mediaNotification.getSbn().getKey().equals(mMediaNotificationKey)) {
mMediaNotificationKey = mediaNotification.getSbn().getKey();
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
+ mMediaNotificationKey);
}
if (mediaNotification != null
&& !mediaNotification.getSbn().getKey().equals(mMediaNotificationKey)) {
mMediaNotificationKey = mediaNotification.getSbn().getKey();
if (DEBUG_MEDIA) {
Log.v(TAG, "DEBUG_MEDIA: Found new media notification: key="
+ mMediaNotificationKey);
}
}
if (metaDataChanged) {
mEntryManager.updateNotifications("NotificationMediaManager - metaDataChanged");
}
dispatchUpdateMediaMetaData(metaDataChanged, true /* allowEnterAnimation */);
return metaDataChanged;
}
public void clearCurrentMediaNotification() {
@@ -428,7 +501,7 @@ public class NotificationMediaManager implements Dumpable {
}
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
pw.print(" mMediaSessionManager=");
pw.println(mMediaSessionManager);
pw.print(" mMediaNotificationKey=");

View File

@@ -28,6 +28,7 @@ import com.android.systemui.media.MediaDataManager;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.ActionClickLogger;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.MediaArtworkProcessor;
import com.android.systemui.statusbar.NotificationClickNotifier;
import com.android.systemui.statusbar.NotificationListener;
@@ -43,6 +44,7 @@ import com.android.systemui.statusbar.notification.AssistantFeedbackController;
import com.android.systemui.statusbar.notification.DynamicChildBindController;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotifPipeline;
import com.android.systemui.statusbar.notification.collection.inflation.LowPriorityInflationHelper;
import com.android.systemui.statusbar.notification.collection.legacy.NotificationGroupManagerLegacy;
import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager;
@@ -108,6 +110,8 @@ public interface StatusBarDependenciesModule {
NotificationEntryManager notificationEntryManager,
MediaArtworkProcessor mediaArtworkProcessor,
KeyguardBypassController keyguardBypassController,
NotifPipeline notifPipeline,
FeatureFlags featureFlags,
@Main DelayableExecutor mainExecutor,
DeviceConfigProxy deviceConfigProxy,
MediaDataManager mediaDataManager) {
@@ -118,6 +122,8 @@ public interface StatusBarDependenciesModule {
notificationEntryManager,
mediaArtworkProcessor,
keyguardBypassController,
notifPipeline,
featureFlags,
mainExecutor,
deviceConfigProxy,
mediaDataManager);