From 46f1013eb91e645e78d40f7abce693e4c6fa563f Mon Sep 17 00:00:00 2001 From: Kevin Han Date: Fri, 10 Apr 2020 21:42:24 -0700 Subject: Combine AlertingManager and HeadsUpBindController Previously, it was difficult to tell when a notification was inflated before trying to show the heads up, and we got around it with a (now flawed) heuristic based off if a notification was just inflated and it has a heads up view. This issue stems from having two control classes that are not really communicating with each other. By combining these classes into one heads up controller, the logic becomes more readable and we can directly put a callback to show the HUN when the HUN content is inflated. Bug: 149028421 Test: HUN smoke test Change-Id: Ibb75597cfe26ccaf7e4d5247dc69d69bdf421ee6 --- .../systemui/statusbar/car/CarStatusBar.java | 3 - .../systemui/statusbar/car/CarStatusBarModule.java | 3 - .../src/com/android/systemui/Dependency.java | 4 - .../collection/coordinator/HeadsUpCoordinator.java | 4 +- .../notification/dagger/NotificationsModule.java | 23 --- .../headsup/HeadsUpBindController.java | 95 ----------- .../notification/headsup/HeadsUpViewBinder.java | 112 ------------- .../init/NotificationsControllerImpl.kt | 8 +- .../interruption/HeadsUpController.java | 185 +++++++++++++++++++++ .../interruption/HeadsUpViewBinder.java | 112 +++++++++++++ .../interruption/NotificationAlertingManager.java | 160 ------------------ .../systemui/statusbar/phone/StatusBar.java | 2 - .../phone/dagger/StatusBarPhoneModule.java | 3 - .../coordinator/HeadsUpCoordinatorTest.java | 2 +- .../systemui/statusbar/phone/StatusBarTest.java | 3 - 15 files changed, 304 insertions(+), 415 deletions(-) delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpBindController.java delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpViewBinder.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java create mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java delete mode 100644 packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index cd45fc908db4..d8111d04348b 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -77,7 +77,6 @@ import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor; import com.android.systemui.statusbar.notification.logging.NotificationLogger; @@ -170,7 +169,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt NotificationInterruptStateProvider notificationInterruptStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, - NotificationAlertingManager notificationAlertingManager, DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, @@ -251,7 +249,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt notificationInterruptStateProvider, notificationViewHierarchyManager, keyguardViewMediator, - notificationAlertingManager, displayMetrics, metricsLogger, uiBgExecutor, diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java index e163173daefb..f72ab25a8028 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java @@ -63,7 +63,6 @@ import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -145,7 +144,6 @@ public class CarStatusBarModule { NotificationInterruptStateProvider notificationInterruptionStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, - NotificationAlertingManager notificationAlertingManager, DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, @@ -225,7 +223,6 @@ public class CarStatusBarModule { notificationInterruptionStateProvider, notificationViewHierarchyManager, keyguardViewMediator, - notificationAlertingManager, displayMetrics, metricsLogger, uiBgExecutor, diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java index b6152dae33d6..0af026eb3509 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -75,7 +75,6 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationEntryManager.KeyguardEnvironment; import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ChannelEditorDialogController; import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; @@ -293,8 +292,6 @@ public class Dependency { @Inject Lazy mRemoteInputQuickSettingsDisabler; @Inject Lazy mBubbleController; @Inject Lazy mNotificationEntryManager; - @Inject - Lazy mNotificationAlertingManager; @Inject Lazy mSensorPrivacyManager; @Inject Lazy mAutoHideController; @Inject Lazy mForegroundServiceNotificationListener; @@ -493,7 +490,6 @@ public class Dependency { mRemoteInputQuickSettingsDisabler::get); mProviders.put(BubbleController.class, mBubbleController::get); mProviders.put(NotificationEntryManager.class, mNotificationEntryManager::get); - mProviders.put(NotificationAlertingManager.class, mNotificationAlertingManager::get); mProviders.put(ForegroundServiceNotificationListener.class, mForegroundServiceNotificationListener::get); mProviders.put(ClockManager.class, mClockManager::get); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java index 2a3b2b7d815d..3fde2ed249d9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.java @@ -17,7 +17,7 @@ package com.android.systemui.statusbar.notification.collection.coordinator; import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY; -import static com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager.alertAgain; +import static com.android.systemui.statusbar.notification.interruption.HeadsUpController.alertAgain; import android.annotation.Nullable; @@ -29,7 +29,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; -import com.android.systemui.statusbar.notification.headsup.HeadsUpViewBinder; +import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index 565a082533a7..605d8bda1016 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -45,7 +45,6 @@ import com.android.systemui.statusbar.notification.collection.provider.HighPrior import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl; import com.android.systemui.statusbar.notification.init.NotificationsControllerStub; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl; import com.android.systemui.statusbar.notification.logging.NotificationLogger; @@ -55,7 +54,6 @@ import com.android.systemui.statusbar.notification.row.NotificationBlockingHelpe import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.StatusBar; -import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.util.leak.LeakDetector; import java.util.concurrent.Executor; @@ -130,27 +128,6 @@ public interface NotificationsModule { return new VisualStabilityManager(notificationEntryManager, handler); } - /** Provides an instance of {@link NotificationAlertingManager} */ - @Singleton - @Provides - static NotificationAlertingManager provideNotificationAlertingManager( - NotificationEntryManager notificationEntryManager, - NotificationRemoteInputManager remoteInputManager, - VisualStabilityManager visualStabilityManager, - StatusBarStateController statusBarStateController, - NotificationInterruptStateProvider notificationInterruptStateProvider, - NotificationListener notificationListener, - HeadsUpManager headsUpManager) { - return new NotificationAlertingManager( - notificationEntryManager, - remoteInputManager, - visualStabilityManager, - statusBarStateController, - notificationInterruptStateProvider, - notificationListener, - headsUpManager); - } - /** Provides an instance of {@link NotificationLogger} */ @Singleton @Provides diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpBindController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpBindController.java deleted file mode 100644 index a7b1f37edf0e..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpBindController.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (C) 2020 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.headsup; - -import androidx.annotation.NonNull; - -import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator; -import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; -import com.android.systemui.statusbar.policy.HeadsUpManager; -import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * Controller class for old pipeline heads up view binding. It listens to - * {@link NotificationEntryManager} entry events and appropriately binds or unbinds the heads up - * view. - * - * This has a subtle contract with {@link NotificationAlertingManager} where this controller handles - * the heads up binding, but {@link NotificationAlertingManager} listens for general inflation - * events to actually mark it heads up/update. In the new pipeline, we combine the classes. - * See {@link HeadsUpCoordinator}. - */ -@Singleton -public class HeadsUpBindController { - private final HeadsUpViewBinder mHeadsUpViewBinder; - private final NotificationInterruptStateProvider mInterruptStateProvider; - - @Inject - HeadsUpBindController( - HeadsUpViewBinder headsUpViewBinder, - NotificationInterruptStateProvider notificationInterruptStateProvider) { - mInterruptStateProvider = notificationInterruptStateProvider; - mHeadsUpViewBinder = headsUpViewBinder; - } - - /** - * Attach this controller and add its listeners. - */ - public void attach( - NotificationEntryManager entryManager, - HeadsUpManager headsUpManager) { - entryManager.addCollectionListener(mCollectionListener); - headsUpManager.addListener(mOnHeadsUpChangedListener); - } - - private NotifCollectionListener mCollectionListener = new NotifCollectionListener() { - @Override - public void onEntryAdded(NotificationEntry entry) { - if (mInterruptStateProvider.shouldHeadsUp(entry)) { - mHeadsUpViewBinder.bindHeadsUpView(entry, null); - } - } - - @Override - public void onEntryUpdated(NotificationEntry entry) { - if (mInterruptStateProvider.shouldHeadsUp(entry)) { - mHeadsUpViewBinder.bindHeadsUpView(entry, null); - } - } - - @Override - public void onEntryCleanUp(NotificationEntry entry) { - mHeadsUpViewBinder.abortBindCallback(entry); - } - }; - - private OnHeadsUpChangedListener mOnHeadsUpChangedListener = new OnHeadsUpChangedListener() { - @Override - public void onHeadsUpStateChanged(@NonNull NotificationEntry entry, boolean isHeadsUp) { - if (!isHeadsUp) { - mHeadsUpViewBinder.unbindHeadsUpView(entry); - } - } - }; -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpViewBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpViewBinder.java deleted file mode 100644 index 37acfa8dc0a4..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpViewBinder.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2020 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.headsup; - -import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP; - -import android.util.ArrayMap; - -import androidx.annotation.Nullable; -import androidx.core.os.CancellationSignal; - -import com.android.internal.util.NotificationMessagingUtil; -import com.android.systemui.statusbar.NotificationPresenter; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator; -import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback; -import com.android.systemui.statusbar.notification.row.RowContentBindParams; -import com.android.systemui.statusbar.notification.row.RowContentBindStage; - -import java.util.Map; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** - * Wrapper around heads up view binding logic. {@link HeadsUpViewBinder} is responsible for - * figuring out the right heads up inflation parameters and inflating/freeing the heads up - * content view. - * - * TODO: This should be moved into {@link HeadsUpCoordinator} when the old pipeline is deprecated - * (i.e. when {@link HeadsUpBindController} is removed). - */ -@Singleton -public class HeadsUpViewBinder { - private final RowContentBindStage mStage; - private final NotificationMessagingUtil mNotificationMessagingUtil; - private final Map mOngoingBindCallbacks = - new ArrayMap<>(); - - private NotificationPresenter mNotificationPresenter; - - @Inject - HeadsUpViewBinder( - NotificationMessagingUtil notificationMessagingUtil, - RowContentBindStage bindStage) { - mNotificationMessagingUtil = notificationMessagingUtil; - mStage = bindStage; - } - - /** - * Set notification presenter to determine parameters for heads up view inflation. - */ - public void setPresenter(NotificationPresenter presenter) { - mNotificationPresenter = presenter; - } - - /** - * Bind heads up view to the notification row. - * @param callback callback after heads up view is bound - */ - public void bindHeadsUpView(NotificationEntry entry, @Nullable BindCallback callback) { - RowContentBindParams params = mStage.getStageParams(entry); - final boolean isImportantMessage = mNotificationMessagingUtil.isImportantMessaging( - entry.getSbn(), entry.getImportance()); - final boolean useIncreasedHeadsUp = isImportantMessage - && !mNotificationPresenter.isPresenterFullyCollapsed(); - params.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp); - params.requireContentViews(FLAG_CONTENT_VIEW_HEADS_UP); - CancellationSignal signal = mStage.requestRebind(entry, en -> { - en.getRow().setUsesIncreasedHeadsUpHeight(params.useIncreasedHeadsUpHeight()); - if (callback != null) { - callback.onBindFinished(en); - } - }); - abortBindCallback(entry); - mOngoingBindCallbacks.put(entry, signal); - } - - /** - * Abort any callbacks waiting for heads up view binding to finish for a given notification. - * @param entry notification with bind in progress - */ - public void abortBindCallback(NotificationEntry entry) { - CancellationSignal ongoingBindCallback = mOngoingBindCallbacks.remove(entry); - if (ongoingBindCallback != null) { - ongoingBindCallback.cancel(); - } - } - - /** - * Unbind the heads up view from the notification row. - */ - public void unbindHeadsUpView(NotificationEntry entry) { - abortBindCallback(entry); - mStage.getStageParams(entry).markContentViewsFreeable(FLAG_CONTENT_VIEW_HEADS_UP); - mStage.requestRebind(entry, null); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt index 5fac5b1cf159..7f2f898565d8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt @@ -28,7 +28,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager import com.android.systemui.statusbar.notification.NotificationListController import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer -import com.android.systemui.statusbar.notification.headsup.HeadsUpBindController +import com.android.systemui.statusbar.notification.interruption.HeadsUpController import com.android.systemui.statusbar.notification.row.NotifBindPipelineInitializer import com.android.systemui.statusbar.notification.stack.NotificationListContainer import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper @@ -36,7 +36,7 @@ import com.android.systemui.statusbar.phone.NotificationGroupManager import com.android.systemui.statusbar.phone.StatusBar import com.android.systemui.statusbar.policy.DeviceProvisionedController import com.android.systemui.statusbar.policy.HeadsUpManager -import com.android.systemui.statusbar.notification.headsup.HeadsUpViewBinder +import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder import com.android.systemui.statusbar.policy.RemoteInputUriController import dagger.Lazy import java.io.FileDescriptor @@ -66,7 +66,7 @@ class NotificationsControllerImpl @Inject constructor( private val groupManager: NotificationGroupManager, private val groupAlertTransferHelper: NotificationGroupAlertTransferHelper, private val headsUpManager: HeadsUpManager, - private val headsUpBindController: HeadsUpBindController, + private val headsUpController: HeadsUpController, private val headsUpViewBinder: HeadsUpViewBinder ) : NotificationsController { @@ -112,7 +112,7 @@ class NotificationsControllerImpl @Inject constructor( groupAlertTransferHelper.bind(entryManager, groupManager) headsUpManager.addListener(groupManager) headsUpManager.addListener(groupAlertTransferHelper) - headsUpBindController.attach(entryManager, headsUpManager) + headsUpController.attach(entryManager, headsUpManager) groupManager.setHeadsUpManager(headsUpManager) groupAlertTransferHelper.setHeadsUpManager(headsUpManager) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java new file mode 100644 index 000000000000..6d14ccf85716 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpController.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2020 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.interruption; + +import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY; + +import android.app.Notification; +import android.service.notification.StatusBarNotification; +import android.util.Log; + +import androidx.annotation.NonNull; + +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.NotificationListener; +import com.android.systemui.statusbar.NotificationRemoteInputManager; +import com.android.systemui.statusbar.notification.NotificationEntryManager; +import com.android.systemui.statusbar.notification.VisualStabilityManager; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.policy.HeadsUpManager; +import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Controller class for old pipeline heads up logic. It listens to {@link NotificationEntryManager} + * entry events and appropriately binds or unbinds the heads up view and promotes it to the top + * of the screen. + */ +@Singleton +public class HeadsUpController { + private final HeadsUpViewBinder mHeadsUpViewBinder; + private final NotificationInterruptStateProvider mInterruptStateProvider; + private final NotificationRemoteInputManager mRemoteInputManager; + private final VisualStabilityManager mVisualStabilityManager; + private final StatusBarStateController mStatusBarStateController; + private final NotificationListener mNotificationListener; + private final HeadsUpManager mHeadsUpManager; + + @Inject + HeadsUpController( + HeadsUpViewBinder headsUpViewBinder, + NotificationInterruptStateProvider notificationInterruptStateProvider, + HeadsUpManager headsUpManager, + NotificationRemoteInputManager remoteInputManager, + StatusBarStateController statusBarStateController, + VisualStabilityManager visualStabilityManager, + NotificationListener notificationListener) { + mHeadsUpViewBinder = headsUpViewBinder; + mHeadsUpManager = headsUpManager; + mInterruptStateProvider = notificationInterruptStateProvider; + mRemoteInputManager = remoteInputManager; + mStatusBarStateController = statusBarStateController; + mVisualStabilityManager = visualStabilityManager; + mNotificationListener = notificationListener; + } + + /** + * Attach this controller and add its listeners. + */ + public void attach( + NotificationEntryManager entryManager, + HeadsUpManager headsUpManager) { + entryManager.addCollectionListener(mCollectionListener); + headsUpManager.addListener(mOnHeadsUpChangedListener); + } + + private NotifCollectionListener mCollectionListener = new NotifCollectionListener() { + @Override + public void onEntryAdded(NotificationEntry entry) { + if (mInterruptStateProvider.shouldHeadsUp(entry)) { + mHeadsUpViewBinder.bindHeadsUpView( + entry, HeadsUpController.this::showAlertingView); + } + } + + @Override + public void onEntryUpdated(NotificationEntry entry) { + updateHunState(entry); + } + + @Override + public void onEntryRemoved(NotificationEntry entry, int reason) { + stopAlerting(entry); + } + + @Override + public void onEntryCleanUp(NotificationEntry entry) { + mHeadsUpViewBinder.abortBindCallback(entry); + } + }; + + /** + * Adds the entry to the HUN manager and show it for the first time. + */ + private void showAlertingView(NotificationEntry entry) { + mHeadsUpManager.showNotification(entry); + if (!mStatusBarStateController.isDozing()) { + // Mark as seen immediately + setNotificationShown(entry.getSbn()); + } + } + + private void updateHunState(NotificationEntry entry) { + boolean hunAgain = alertAgain(entry, entry.getSbn().getNotification()); + // includes check for whether this notification should be filtered: + boolean shouldHeadsUp = mInterruptStateProvider.shouldHeadsUp(entry); + final boolean wasHeadsUp = mHeadsUpManager.isAlerting(entry.getKey()); + if (wasHeadsUp) { + if (shouldHeadsUp) { + mHeadsUpManager.updateNotification(entry.getKey(), hunAgain); + } else if (!mHeadsUpManager.isEntryAutoHeadsUpped(entry.getKey())) { + // We don't want this to be interrupting anymore, let's remove it + mHeadsUpManager.removeNotification(entry.getKey(), false /* removeImmediately */); + } + } else if (shouldHeadsUp && hunAgain) { + mHeadsUpViewBinder.bindHeadsUpView(entry, mHeadsUpManager::showNotification); + } + } + + private void setNotificationShown(StatusBarNotification n) { + try { + mNotificationListener.setNotificationsShown(new String[]{n.getKey()}); + } catch (RuntimeException e) { + Log.d(TAG, "failed setNotificationsShown: ", e); + } + } + + private void stopAlerting(NotificationEntry entry) { + // Attempt to remove notifications from their HUN manager. + // Though the remove itself may fail, it lets the manager know to remove as soon as + // possible. + String key = entry.getKey(); + if (mHeadsUpManager.isAlerting(key)) { + // A cancel() in response to a remote input shouldn't be delayed, as it makes the + // sending look longer than it takes. + // Also we should not defer the removal if reordering isn't allowed since otherwise + // some notifications can't disappear before the panel is closed. + boolean ignoreEarliestRemovalTime = + mRemoteInputManager.getController().isSpinning(key) + && !FORCE_REMOTE_INPUT_HISTORY + || !mVisualStabilityManager.isReorderingAllowed(); + mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime); + } + } + + /** + * Checks whether an update for a notification warrants an alert for the user. + * + * @param oldEntry the entry for this notification. + * @param newNotification the new notification for this entry. + * @return whether this notification should alert the user. + */ + public static boolean alertAgain( + NotificationEntry oldEntry, Notification newNotification) { + return oldEntry == null || !oldEntry.hasInterrupted() + || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0; + } + + private OnHeadsUpChangedListener mOnHeadsUpChangedListener = new OnHeadsUpChangedListener() { + @Override + public void onHeadsUpStateChanged(@NonNull NotificationEntry entry, boolean isHeadsUp) { + if (!isHeadsUp) { + mHeadsUpViewBinder.unbindHeadsUpView(entry); + } + } + }; + + private static final String TAG = "HeadsUpBindController"; +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java new file mode 100644 index 000000000000..ff139957031a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/HeadsUpViewBinder.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2020 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.interruption; + +import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP; + +import android.util.ArrayMap; + +import androidx.annotation.Nullable; +import androidx.core.os.CancellationSignal; + +import com.android.internal.util.NotificationMessagingUtil; +import com.android.systemui.statusbar.NotificationPresenter; +import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator; +import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback; +import com.android.systemui.statusbar.notification.row.RowContentBindParams; +import com.android.systemui.statusbar.notification.row.RowContentBindStage; + +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Wrapper around heads up view binding logic. {@link HeadsUpViewBinder} is responsible for + * figuring out the right heads up inflation parameters and inflating/freeing the heads up + * content view. + * + * TODO: This should be moved into {@link HeadsUpCoordinator} when the old pipeline is deprecated + * (i.e. when {@link HeadsUpController} is removed). + */ +@Singleton +public class HeadsUpViewBinder { + private final RowContentBindStage mStage; + private final NotificationMessagingUtil mNotificationMessagingUtil; + private final Map mOngoingBindCallbacks = + new ArrayMap<>(); + + private NotificationPresenter mNotificationPresenter; + + @Inject + HeadsUpViewBinder( + NotificationMessagingUtil notificationMessagingUtil, + RowContentBindStage bindStage) { + mNotificationMessagingUtil = notificationMessagingUtil; + mStage = bindStage; + } + + /** + * Set notification presenter to determine parameters for heads up view inflation. + */ + public void setPresenter(NotificationPresenter presenter) { + mNotificationPresenter = presenter; + } + + /** + * Bind heads up view to the notification row. + * @param callback callback after heads up view is bound + */ + public void bindHeadsUpView(NotificationEntry entry, @Nullable BindCallback callback) { + RowContentBindParams params = mStage.getStageParams(entry); + final boolean isImportantMessage = mNotificationMessagingUtil.isImportantMessaging( + entry.getSbn(), entry.getImportance()); + final boolean useIncreasedHeadsUp = isImportantMessage + && !mNotificationPresenter.isPresenterFullyCollapsed(); + params.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp); + params.requireContentViews(FLAG_CONTENT_VIEW_HEADS_UP); + CancellationSignal signal = mStage.requestRebind(entry, en -> { + en.getRow().setUsesIncreasedHeadsUpHeight(params.useIncreasedHeadsUpHeight()); + if (callback != null) { + callback.onBindFinished(en); + } + }); + abortBindCallback(entry); + mOngoingBindCallbacks.put(entry, signal); + } + + /** + * Abort any callbacks waiting for heads up view binding to finish for a given notification. + * @param entry notification with bind in progress + */ + public void abortBindCallback(NotificationEntry entry) { + CancellationSignal ongoingBindCallback = mOngoingBindCallbacks.remove(entry); + if (ongoingBindCallback != null) { + ongoingBindCallback.cancel(); + } + } + + /** + * Unbind the heads up view from the notification row. + */ + public void unbindHeadsUpView(NotificationEntry entry) { + abortBindCallback(entry); + mStage.getStageParams(entry).markContentViewsFreeable(FLAG_CONTENT_VIEW_HEADS_UP); + mStage.requestRebind(entry, null); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java deleted file mode 100644 index 5d070981f81b..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 2018 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.interruption; - -import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY; - -import android.app.Notification; -import android.service.notification.StatusBarNotification; -import android.util.Log; - -import com.android.internal.statusbar.NotificationVisibility; -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.NotificationListener; -import com.android.systemui.statusbar.NotificationRemoteInputManager; -import com.android.systemui.statusbar.notification.NotificationEntryListener; -import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.dagger.NotificationsModule; -import com.android.systemui.statusbar.policy.HeadsUpManager; - -/** Handles heads-up and pulsing behavior driven by notification changes. */ -public class NotificationAlertingManager { - - private static final String TAG = "NotifAlertManager"; - - private final NotificationRemoteInputManager mRemoteInputManager; - private final VisualStabilityManager mVisualStabilityManager; - private final StatusBarStateController mStatusBarStateController; - private final NotificationInterruptStateProvider mNotificationInterruptStateProvider; - private final NotificationListener mNotificationListener; - - private HeadsUpManager mHeadsUpManager; - - /** - * Injected constructor. See {@link NotificationsModule}. - */ - public NotificationAlertingManager( - NotificationEntryManager notificationEntryManager, - NotificationRemoteInputManager remoteInputManager, - VisualStabilityManager visualStabilityManager, - StatusBarStateController statusBarStateController, - NotificationInterruptStateProvider notificationInterruptionStateProvider, - NotificationListener notificationListener, - HeadsUpManager headsUpManager) { - mRemoteInputManager = remoteInputManager; - mVisualStabilityManager = visualStabilityManager; - mStatusBarStateController = statusBarStateController; - mNotificationInterruptStateProvider = notificationInterruptionStateProvider; - mNotificationListener = notificationListener; - mHeadsUpManager = headsUpManager; - - notificationEntryManager.addNotificationEntryListener(new NotificationEntryListener() { - @Override - public void onEntryInflated(NotificationEntry entry) { - showAlertingView(entry); - } - - @Override - public void onPreEntryUpdated(NotificationEntry entry) { - updateAlertState(entry); - } - - @Override - public void onEntryRemoved( - NotificationEntry entry, - NotificationVisibility visibility, - boolean removedByUser, - int reason) { - stopAlerting(entry.getKey()); - } - }); - } - - /** - * Adds the entry to the respective alerting manager if the content view was inflated and - * the entry should still alert. - */ - private void showAlertingView(NotificationEntry entry) { - // TODO: Instead of this back and forth, we should listen to changes in heads up and - // cancel on-going heads up view inflation using the bind pipeline. - if (entry.getRow().getPrivateLayout().getHeadsUpChild() != null) { - mHeadsUpManager.showNotification(entry); - if (!mStatusBarStateController.isDozing()) { - // Mark as seen immediately - setNotificationShown(entry.getSbn()); - } - } - } - - private void updateAlertState(NotificationEntry entry) { - boolean alertAgain = alertAgain(entry, entry.getSbn().getNotification()); - // includes check for whether this notification should be filtered: - boolean shouldAlert = mNotificationInterruptStateProvider.shouldHeadsUp(entry); - final boolean wasAlerting = mHeadsUpManager.isAlerting(entry.getKey()); - if (wasAlerting) { - if (shouldAlert) { - mHeadsUpManager.updateNotification(entry.getKey(), alertAgain); - } else if (!mHeadsUpManager.isEntryAutoHeadsUpped(entry.getKey())) { - // We don't want this to be interrupting anymore, let's remove it - mHeadsUpManager.removeNotification(entry.getKey(), false /* removeImmediately */); - } - } else if (shouldAlert && alertAgain) { - // This notification was updated to be alerting, show it! - mHeadsUpManager.showNotification(entry); - } - } - - /** - * Checks whether an update for a notification warrants an alert for the user. - * - * @param oldEntry the entry for this notification. - * @param newNotification the new notification for this entry. - * @return whether this notification should alert the user. - */ - public static boolean alertAgain( - NotificationEntry oldEntry, Notification newNotification) { - return oldEntry == null || !oldEntry.hasInterrupted() - || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0; - } - - private void setNotificationShown(StatusBarNotification n) { - try { - mNotificationListener.setNotificationsShown(new String[]{n.getKey()}); - } catch (RuntimeException e) { - Log.d(TAG, "failed setNotificationsShown: ", e); - } - } - - private void stopAlerting(final String key) { - // Attempt to remove notifications from their alert manager. - // Though the remove itself may fail, it lets the manager know to remove as soon as - // possible. - if (mHeadsUpManager.isAlerting(key)) { - // A cancel() in response to a remote input shouldn't be delayed, as it makes the - // sending look longer than it takes. - // Also we should not defer the removal if reordering isn't allowed since otherwise - // some notifications can't disappear before the panel is closed. - boolean ignoreEarliestRemovalTime = - mRemoteInputManager.getController().isSpinning(key) - && !FORCE_REMOTE_INPUT_HISTORY - || !mVisualStabilityManager.isReorderingAllowed(); - mHeadsUpManager.removeNotification(key, ignoreEarliestRemovalTime); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 900b3ea97010..ca65665d4ae5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -193,7 +193,6 @@ import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -623,7 +622,6 @@ public class StatusBar extends SystemUI implements DemoMode, NotificationInterruptStateProvider notificationInterruptStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, - NotificationAlertingManager notificationAlertingManager, // need to inject for now DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index b81a5198b498..02e031217904 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -62,7 +62,6 @@ import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -143,7 +142,6 @@ public interface StatusBarPhoneModule { NotificationInterruptStateProvider notificationInterruptStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, - NotificationAlertingManager notificationAlertingManager, DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, @@ -223,7 +221,6 @@ public interface StatusBarPhoneModule { notificationInterruptStateProvider, notificationViewHierarchyManager, keyguardViewMediator, - notificationAlertingManager, displayMetrics, metricsLogger, uiBgExecutor, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java index f3038ce051cd..730481afe638 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.java @@ -39,7 +39,7 @@ import com.android.systemui.statusbar.notification.collection.listbuilder.plugga import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSection; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifLifetimeExtender; -import com.android.systemui.statusbar.notification.headsup.HeadsUpViewBinder; +import com.android.systemui.statusbar.notification.interruption.HeadsUpViewBinder; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.row.NotifBindPipeline.BindCallback; import com.android.systemui.statusbar.policy.HeadsUpManager; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index b905bddb98f5..5a08c9ca017b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -120,7 +120,6 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.interruption.BypassHeadsUpNotifier; -import com.android.systemui.statusbar.notification.interruption.NotificationAlertingManager; import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerFake; @@ -193,7 +192,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private StatusBarNotificationPresenter mNotificationPresenter; @Mock private NotificationEntryListener mEntryListener; @Mock private NotificationFilter mNotificationFilter; - @Mock private NotificationAlertingManager mNotificationAlertingManager; @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration; @Mock private NotificationLogger.ExpansionStateLogger mExpansionStateLogger; @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor; @@ -352,7 +350,6 @@ public class StatusBarTest extends SysuiTestCase { mNotificationInterruptStateProvider, mNotificationViewHierarchyManager, mKeyguardViewMediator, - mNotificationAlertingManager, new DisplayMetrics(), mMetricsLogger, mUiBgExecutor, -- cgit v1.2.3-59-g8ed1b