Loading core/java/android/service/notification/StatusBarNotification.java +10 −0 Original line number Diff line number Diff line Loading @@ -297,6 +297,16 @@ public class StatusBarNotification implements Parcelable { return (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0; } /** * @hide * * Convenience method to check the notification's flags for * {@link Notification#FLAG_NO_DISMISS}. */ public boolean isNonDismissable() { return (notification.flags & Notification.FLAG_NO_DISMISS) != 0; } /** * Convenience method to check the notification's flags for * either {@link Notification#FLAG_ONGOING_EVENT} or Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java +11 −2 Original line number Diff line number Diff line Loading @@ -96,6 +96,7 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.No import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; import com.android.systemui.statusbar.notification.collection.notifcollection.RankingAppliedEvent; import com.android.systemui.statusbar.notification.collection.notifcollection.RankingUpdatedEvent; import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider; import com.android.systemui.util.Assert; import com.android.systemui.util.time.SystemClock; Loading Loading @@ -151,6 +152,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { private final LogBufferEulogizer mEulogizer; private final DumpManager mDumpManager; private final NotifCollectionInconsistencyTracker mInconsistencyTracker; private final NotificationDismissibilityProvider mDismissibilityProvider; private final Map<String, NotificationEntry> mNotificationSet = new ArrayMap<>(); private final Collection<NotificationEntry> mReadOnlyNotificationSet = Loading Loading @@ -178,7 +180,8 @@ public class NotifCollection implements Dumpable, PipelineDumpable { @Main Handler mainHandler, @Background Executor bgExecutor, LogBufferEulogizer logBufferEulogizer, DumpManager dumpManager) { DumpManager dumpManager, NotificationDismissibilityProvider dismissibilityProvider) { mStatusBarService = statusBarService; mClock = clock; mNotifPipelineFlags = notifPipelineFlags; Loading @@ -188,6 +191,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { mEulogizer = logBufferEulogizer; mDumpManager = dumpManager; mInconsistencyTracker = new NotifCollectionInconsistencyTracker(mLogger); mDismissibilityProvider = dismissibilityProvider; } /** Initializes the NotifCollection and registers it to receive notification events. */ Loading Loading @@ -554,6 +558,10 @@ public class NotifCollection implements Dumpable, PipelineDumpable { .findFirst().orElse(null); } private boolean isDismissable(NotificationEntry entry) { return mDismissibilityProvider.isDismissable(entry); } /** * Checks if the entry is the only child in the logical group; * it need not have a summary to qualify Loading Loading @@ -1006,6 +1014,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { public class FutureDismissal implements Runnable { private final NotificationEntry mEntry; private final DismissedByUserStatsCreator mStatsCreator; @Nullable private final NotificationEntry mSummaryToDismiss; private final String mLabel; Loading @@ -1030,7 +1039,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { if (isOnlyChildInGroup(entry)) { String group = entry.getSbn().getGroupKey(); NotificationEntry summary = getGroupSummary(group); if (summary != null && summary.isDismissable()) return summary; if (summary != null && isDismissable(summary)) return summary; } return null; } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +17 −1 Original line number Diff line number Diff line Loading @@ -730,13 +730,29 @@ public final class NotificationEntry extends ListEntry { return true; } /** * Determines whether the NotificationEntry is dismissable based on the Notification flags and * the given state. It doesn't recurse children or depend on the view attach state. * * @param isLocked if the device is locked or unlocked * @return true if this NotificationEntry is dismissable. */ public boolean isDismissableForState(boolean isLocked) { if (mSbn.isNonDismissable()) { // don't dismiss exempted Notifications return false; } // don't dismiss ongoing Notifications when the device is locked return !mSbn.isOngoing() || !isLocked; } /** * @return Can the underlying notification be individually dismissed? * @see #canViewBeDismissed() */ // TODO: This logic doesn't belong on NotificationEntry. It should be moved to a controller // that can be added as a dependency to any class that needs to answer this question. public boolean isDismissable() { public boolean legacyIsDismissableRecursive() { if (mSbn.isOngoing()) { return false; } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinator.kt 0 → 100644 +81 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.statusbar.notification.collection.coordinator import com.android.systemui.statusbar.notification.collection.GroupEntry import com.android.systemui.statusbar.notification.collection.ListEntry import com.android.systemui.statusbar.notification.collection.NotifPipeline import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProviderImpl import com.android.systemui.statusbar.policy.KeyguardStateController import javax.inject.Inject /** Decides if a Notification can be dismissed by the user. */ @CoordinatorScope class DismissibilityCoordinator @Inject constructor( private val keyguardStateController: KeyguardStateController, private val provider: NotificationDismissibilityProviderImpl ) : Coordinator { override fun attach(pipeline: NotifPipeline) { pipeline.addOnBeforeRenderListListener(::onBeforeRenderListListener) } private fun onBeforeRenderListListener(entries: List<ListEntry>) { val isLocked = !keyguardStateController.isUnlocked val nonDismissableEntryKeys = mutableSetOf<String>() markNonDismissibleEntries(nonDismissableEntryKeys, entries, isLocked) provider.update(nonDismissableEntryKeys) } /** * Visits every entry and its children to mark the dismissible entries. * @param markedKeys set to store the marked entry keys * @param entries to visit * @param isLocked the locked state of the device * @return true if any of the entries were marked as non-dismissible. */ private fun markNonDismissibleEntries( markedKeys: MutableSet<String>, entries: List<ListEntry>, isLocked: Boolean ): Boolean { var anyNonDismissableEntries = false for (entry in entries) { entry.representativeEntry?.let { notifEntry -> // mark the entry if it is non-dismissible if (!notifEntry.isDismissableForState(isLocked)) { markedKeys.add(notifEntry.key) anyNonDismissableEntries = true } } if (entry is GroupEntry) { if (markNonDismissibleEntries(markedKeys, entry.children, isLocked)) { // if any child is non-dismissible, mark the parent as well entry.representativeEntry?.let { markedKeys.add(it.key) } anyNonDismissableEntries = true } } } return anyNonDismissableEntries } } packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt +2 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ class NotifCoordinatorsImpl @Inject constructor( viewConfigCoordinator: ViewConfigCoordinator, visualStabilityCoordinator: VisualStabilityCoordinator, sensitiveContentCoordinator: SensitiveContentCoordinator, dismissibilityCoordinator: DismissibilityCoordinator ) : NotifCoordinators { private val mCoordinators: MutableList<Coordinator> = ArrayList() Loading Loading @@ -93,6 +94,7 @@ class NotifCoordinatorsImpl @Inject constructor( mCoordinators.add(gutsCoordinator) mCoordinators.add(preparationCoordinator) mCoordinators.add(remoteInputCoordinator) mCoordinators.add(dismissibilityCoordinator) // Manually add Ordered Sections // HeadsUp > FGS > People > Alerting > Silent > Minimized > Unknown/Default Loading Loading
core/java/android/service/notification/StatusBarNotification.java +10 −0 Original line number Diff line number Diff line Loading @@ -297,6 +297,16 @@ public class StatusBarNotification implements Parcelable { return (notification.flags & Notification.FLAG_ONGOING_EVENT) != 0; } /** * @hide * * Convenience method to check the notification's flags for * {@link Notification#FLAG_NO_DISMISS}. */ public boolean isNonDismissable() { return (notification.flags & Notification.FLAG_NO_DISMISS) != 0; } /** * Convenience method to check the notification's flags for * either {@link Notification#FLAG_ONGOING_EVENT} or Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java +11 −2 Original line number Diff line number Diff line Loading @@ -96,6 +96,7 @@ import com.android.systemui.statusbar.notification.collection.notifcollection.No import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; import com.android.systemui.statusbar.notification.collection.notifcollection.RankingAppliedEvent; import com.android.systemui.statusbar.notification.collection.notifcollection.RankingUpdatedEvent; import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider; import com.android.systemui.util.Assert; import com.android.systemui.util.time.SystemClock; Loading Loading @@ -151,6 +152,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { private final LogBufferEulogizer mEulogizer; private final DumpManager mDumpManager; private final NotifCollectionInconsistencyTracker mInconsistencyTracker; private final NotificationDismissibilityProvider mDismissibilityProvider; private final Map<String, NotificationEntry> mNotificationSet = new ArrayMap<>(); private final Collection<NotificationEntry> mReadOnlyNotificationSet = Loading Loading @@ -178,7 +180,8 @@ public class NotifCollection implements Dumpable, PipelineDumpable { @Main Handler mainHandler, @Background Executor bgExecutor, LogBufferEulogizer logBufferEulogizer, DumpManager dumpManager) { DumpManager dumpManager, NotificationDismissibilityProvider dismissibilityProvider) { mStatusBarService = statusBarService; mClock = clock; mNotifPipelineFlags = notifPipelineFlags; Loading @@ -188,6 +191,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { mEulogizer = logBufferEulogizer; mDumpManager = dumpManager; mInconsistencyTracker = new NotifCollectionInconsistencyTracker(mLogger); mDismissibilityProvider = dismissibilityProvider; } /** Initializes the NotifCollection and registers it to receive notification events. */ Loading Loading @@ -554,6 +558,10 @@ public class NotifCollection implements Dumpable, PipelineDumpable { .findFirst().orElse(null); } private boolean isDismissable(NotificationEntry entry) { return mDismissibilityProvider.isDismissable(entry); } /** * Checks if the entry is the only child in the logical group; * it need not have a summary to qualify Loading Loading @@ -1006,6 +1014,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { public class FutureDismissal implements Runnable { private final NotificationEntry mEntry; private final DismissedByUserStatsCreator mStatsCreator; @Nullable private final NotificationEntry mSummaryToDismiss; private final String mLabel; Loading @@ -1030,7 +1039,7 @@ public class NotifCollection implements Dumpable, PipelineDumpable { if (isOnlyChildInGroup(entry)) { String group = entry.getSbn().getGroupKey(); NotificationEntry summary = getGroupSummary(group); if (summary != null && summary.isDismissable()) return summary; if (summary != null && isDismissable(summary)) return summary; } return null; } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +17 −1 Original line number Diff line number Diff line Loading @@ -730,13 +730,29 @@ public final class NotificationEntry extends ListEntry { return true; } /** * Determines whether the NotificationEntry is dismissable based on the Notification flags and * the given state. It doesn't recurse children or depend on the view attach state. * * @param isLocked if the device is locked or unlocked * @return true if this NotificationEntry is dismissable. */ public boolean isDismissableForState(boolean isLocked) { if (mSbn.isNonDismissable()) { // don't dismiss exempted Notifications return false; } // don't dismiss ongoing Notifications when the device is locked return !mSbn.isOngoing() || !isLocked; } /** * @return Can the underlying notification be individually dismissed? * @see #canViewBeDismissed() */ // TODO: This logic doesn't belong on NotificationEntry. It should be moved to a controller // that can be added as a dependency to any class that needs to answer this question. public boolean isDismissable() { public boolean legacyIsDismissableRecursive() { if (mSbn.isOngoing()) { return false; } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/DismissibilityCoordinator.kt 0 → 100644 +81 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.statusbar.notification.collection.coordinator import com.android.systemui.statusbar.notification.collection.GroupEntry import com.android.systemui.statusbar.notification.collection.ListEntry import com.android.systemui.statusbar.notification.collection.NotifPipeline import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProviderImpl import com.android.systemui.statusbar.policy.KeyguardStateController import javax.inject.Inject /** Decides if a Notification can be dismissed by the user. */ @CoordinatorScope class DismissibilityCoordinator @Inject constructor( private val keyguardStateController: KeyguardStateController, private val provider: NotificationDismissibilityProviderImpl ) : Coordinator { override fun attach(pipeline: NotifPipeline) { pipeline.addOnBeforeRenderListListener(::onBeforeRenderListListener) } private fun onBeforeRenderListListener(entries: List<ListEntry>) { val isLocked = !keyguardStateController.isUnlocked val nonDismissableEntryKeys = mutableSetOf<String>() markNonDismissibleEntries(nonDismissableEntryKeys, entries, isLocked) provider.update(nonDismissableEntryKeys) } /** * Visits every entry and its children to mark the dismissible entries. * @param markedKeys set to store the marked entry keys * @param entries to visit * @param isLocked the locked state of the device * @return true if any of the entries were marked as non-dismissible. */ private fun markNonDismissibleEntries( markedKeys: MutableSet<String>, entries: List<ListEntry>, isLocked: Boolean ): Boolean { var anyNonDismissableEntries = false for (entry in entries) { entry.representativeEntry?.let { notifEntry -> // mark the entry if it is non-dismissible if (!notifEntry.isDismissableForState(isLocked)) { markedKeys.add(notifEntry.key) anyNonDismissableEntries = true } } if (entry is GroupEntry) { if (markNonDismissibleEntries(markedKeys, entry.children, isLocked)) { // if any child is non-dismissible, mark the parent as well entry.representativeEntry?.let { markedKeys.add(it.key) } anyNonDismissableEntries = true } } } return anyNonDismissableEntries } }
packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/NotifCoordinators.kt +2 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ class NotifCoordinatorsImpl @Inject constructor( viewConfigCoordinator: ViewConfigCoordinator, visualStabilityCoordinator: VisualStabilityCoordinator, sensitiveContentCoordinator: SensitiveContentCoordinator, dismissibilityCoordinator: DismissibilityCoordinator ) : NotifCoordinators { private val mCoordinators: MutableList<Coordinator> = ArrayList() Loading Loading @@ -93,6 +94,7 @@ class NotifCoordinatorsImpl @Inject constructor( mCoordinators.add(gutsCoordinator) mCoordinators.add(preparationCoordinator) mCoordinators.add(remoteInputCoordinator) mCoordinators.add(dismissibilityCoordinator) // Manually add Ordered Sections // HeadsUp > FGS > People > Alerting > Silent > Minimized > Unknown/Default Loading