diff options
30 files changed, 730 insertions, 660 deletions
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java index 7cc4257f26a5..bae42b5027f8 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java @@ -23,7 +23,6 @@ import android.content.Context; import com.android.keyguard.KeyguardViewController; import com.android.systemui.car.CarDeviceProvisionedControllerImpl; -import com.android.systemui.car.CarNotificationInterruptionStateProvider; import com.android.systemui.dagger.SystemUIRootComponent; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerImpl; @@ -40,7 +39,6 @@ import com.android.systemui.statusbar.car.CarShadeControllerImpl; import com.android.systemui.statusbar.car.CarStatusBar; import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.KeyguardEnvironmentImpl; @@ -64,10 +62,6 @@ import dagger.Provides; @Module(includes = {DividerModule.class}) abstract class CarSystemUIModule { - @Binds - abstract NotificationInterruptionStateProvider bindNotificationInterruptionStateProvider( - CarNotificationInterruptionStateProvider notificationInterruptionStateProvider); - @Singleton @Provides @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java deleted file mode 100644 index 447e579ece42..000000000000 --- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationInterruptionStateProvider.java +++ /dev/null @@ -1,54 +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.car; - -import android.content.Context; - -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.notification.NotificationFilter; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.policy.BatteryController; - -import javax.inject.Inject; -import javax.inject.Singleton; - -/** Auto-specific implementation of {@link NotificationInterruptionStateProvider}. */ -@Singleton -public class CarNotificationInterruptionStateProvider extends - NotificationInterruptionStateProvider { - - @Inject - public CarNotificationInterruptionStateProvider(Context context, - NotificationFilter filter, - StatusBarStateController stateController, - BatteryController batteryController) { - super(context, filter, stateController, batteryController); - } - - @Override - public boolean shouldHeadsUp(NotificationEntry entry) { - // Because space is usually constrained in the auto use-case, there should not be a - // pinned notification when the shade has been expanded. Ensure this by not pinning any - // notification if the shade is already opened. - if (!getPresenter().isPresenterFullyCollapsed()) { - return false; - } - - return super.shouldHeadsUp(entry); - } -} 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 83248f4d867b..7ad3d45afbe1 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -97,13 +97,14 @@ import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; -import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; import com.android.systemui.statusbar.notification.DynamicPrivacyController; -import com.android.systemui.statusbar.notification.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; 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.NotificationInterruptStateProvider; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.phone.AutoHideController; @@ -267,10 +268,9 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, NotificationGutsManager notificationGutsManager, NotificationLogger notificationLogger, - NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationInterruptStateProvider notificationInterruptStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, - NotificationAlertingManager notificationAlertingManager, DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, @@ -350,10 +350,9 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt remoteInputQuickSettingsDisabler, notificationGutsManager, notificationLogger, - notificationInterruptionStateProvider, + notificationInterruptStateProvider, notificationViewHierarchyManager, keyguardViewMediator, - notificationAlertingManager, displayMetrics, metricsLogger, uiBgExecutor, @@ -491,6 +490,22 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt .isCurrentUserSetupInProgress(); } }); + + mNotificationInterruptStateProvider.addSuppressor(new NotificationInterruptSuppressor() { + @Override + public String getName() { + return TAG; + } + + @Override + public boolean suppressInterruptions(NotificationEntry entry) { + // Because space is usually constrained in the auto use-case, there should not be a + // pinned notification when the shade has been expanded. + // Ensure this by not allowing any interruptions (ie: pinning any notifications) if + // the shade is already opened. + return !getPresenter().isPresenterFullyCollapsed(); + } + }); } @Override 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 aea4bd497527..9798ee7a4490 100644 --- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java @@ -58,13 +58,12 @@ import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.dagger.StatusBarDependenciesModule; -import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; import com.android.systemui.statusbar.notification.DynamicPrivacyController; -import com.android.systemui.statusbar.notification.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; 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.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.NotificationRowModule; @@ -143,10 +142,9 @@ public class CarStatusBarModule { RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, NotificationGutsManager notificationGutsManager, NotificationLogger notificationLogger, - NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationInterruptStateProvider notificationInterruptionStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, - NotificationAlertingManager notificationAlertingManager, DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, @@ -228,7 +226,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 a868cf58cf7c..b6152dae33d6 100644 --- a/packages/SystemUI/src/com/android/systemui/Dependency.java +++ b/packages/SystemUI/src/com/android/systemui/Dependency.java @@ -71,12 +71,11 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationViewHierarchyManager; import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.VibratorHelper; -import com.android.systemui.statusbar.notification.NotificationAlertingManager; 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.NotificationInterruptionStateProvider; 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; @@ -289,7 +288,6 @@ public class Dependency { @Inject Lazy<NotificationLogger> mNotificationLogger; @Inject Lazy<NotificationViewHierarchyManager> mNotificationViewHierarchyManager; @Inject Lazy<NotificationFilter> mNotificationFilter; - @Inject Lazy<NotificationInterruptionStateProvider> mNotificationInterruptionStateProvider; @Inject Lazy<KeyguardDismissUtil> mKeyguardDismissUtil; @Inject Lazy<SmartReplyController> mSmartReplyController; @Inject Lazy<RemoteInputQuickSettingsDisabler> mRemoteInputQuickSettingsDisabler; @@ -489,8 +487,6 @@ public class Dependency { mProviders.put(NotificationViewHierarchyManager.class, mNotificationViewHierarchyManager::get); mProviders.put(NotificationFilter.class, mNotificationFilter::get); - mProviders.put(NotificationInterruptionStateProvider.class, - mNotificationInterruptionStateProvider::get); mProviders.put(KeyguardDismissUtil.class, mKeyguardDismissUtil::get); mProviders.put(SmartReplyController.class, mSmartReplyController::get); mProviders.put(RemoteInputQuickSettingsDisabler.class, diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index 48457f627e83..f873f42dd918 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -83,11 +83,11 @@ import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationRemoveInterceptor; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotifCollection; 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.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.ShadeController; @@ -169,7 +169,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi // Callback that updates BubbleOverflowActivity on data change. @Nullable private Runnable mOverflowCallback = null; - private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; + private final NotificationInterruptStateProvider mNotificationInterruptStateProvider; private IStatusBarService mBarService; // Used for determining view rect for touch interaction @@ -279,7 +279,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi ShadeController shadeController, BubbleData data, ConfigurationController configurationController, - NotificationInterruptionStateProvider interruptionStateProvider, + NotificationInterruptStateProvider interruptionStateProvider, ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager, NotificationGroupManager groupManager, @@ -304,7 +304,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer, ConfigurationController configurationController, - NotificationInterruptionStateProvider interruptionStateProvider, + NotificationInterruptStateProvider interruptionStateProvider, ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager, NotificationGroupManager groupManager, @@ -316,7 +316,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi dumpManager.registerDumpable(TAG, this); mContext = context; mShadeController = shadeController; - mNotificationInterruptionStateProvider = interruptionStateProvider; + mNotificationInterruptStateProvider = interruptionStateProvider; mNotifUserManager = notifUserManager; mZenModeController = zenModeController; mFloatingContentCoordinator = floatingContentCoordinator; @@ -632,7 +632,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi for (NotificationEntry e : mNotificationEntryManager.getActiveNotificationsForCurrentUser()) { if (savedBubbleKeys.contains(e.getKey()) - && mNotificationInterruptionStateProvider.shouldBubbleUp(e) + && mNotificationInterruptStateProvider.shouldBubbleUp(e) && canLaunchInActivityView(mContext, e)) { updateBubble(e, /* suppressFlyout= */ true); } @@ -894,7 +894,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments( mContext, entry, previouslyUserCreated, userBlocked); - if (mNotificationInterruptionStateProvider.shouldBubbleUp(entry) + if (mNotificationInterruptStateProvider.shouldBubbleUp(entry) && (canLaunchInActivityView(mContext, entry) || wasAdjusted)) { if (wasAdjusted && !previouslyUserCreated) { // Gotta treat the auto-bubbled / whitelisted packaged bubbles as usercreated @@ -910,7 +910,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi boolean wasAdjusted = BubbleExperimentConfig.adjustForExperiments( mContext, entry, previouslyUserCreated, userBlocked); - boolean shouldBubble = mNotificationInterruptionStateProvider.shouldBubbleUp(entry) + boolean shouldBubble = mNotificationInterruptStateProvider.shouldBubbleUp(entry) && (canLaunchInActivityView(mContext, entry) || wasAdjusted); if (!shouldBubble && mBubbleData.hasBubbleWithKey(entry.getKey())) { // It was previously a bubble but no longer a bubble -- lets remove it diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java index ac97d8aab326..27c9e9895324 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java @@ -25,8 +25,8 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotifPipeline; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.ShadeController; @@ -54,7 +54,7 @@ public interface BubbleModule { ShadeController shadeController, BubbleData data, ConfigurationController configurationController, - NotificationInterruptionStateProvider interruptionStateProvider, + NotificationInterruptStateProvider interruptionStateProvider, ZenModeController zenModeController, NotificationLockscreenUserManager notifUserManager, NotificationGroupManager groupManager, diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index 6c502d273a1c..3a4b273e1c98 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -90,7 +90,7 @@ public class DependencyProvider { /** */ @Provides - public AmbientDisplayConfiguration provideAmbientDispalyConfiguration(Context context) { + public AmbientDisplayConfiguration provideAmbientDisplayConfiguration(Context context) { return new AmbientDisplayConfiguration(context); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt index 8a23e3796e9b..27476964b9af 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.notification import android.animation.ObjectAnimator -import android.content.Context import android.util.FloatProperty import com.android.systemui.Interpolators import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -26,10 +25,10 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout import com.android.systemui.statusbar.notification.stack.StackStateAnimator import com.android.systemui.statusbar.phone.DozeParameters -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone import com.android.systemui.statusbar.phone.KeyguardBypassController import com.android.systemui.statusbar.phone.NotificationIconAreaController import com.android.systemui.statusbar.phone.PanelExpansionListener +import com.android.systemui.statusbar.policy.HeadsUpManager import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener import javax.inject.Inject @@ -37,15 +36,14 @@ import javax.inject.Singleton @Singleton class NotificationWakeUpCoordinator @Inject constructor( - private val mHeadsUpManagerPhone: HeadsUpManagerPhone, - private val statusBarStateController: StatusBarStateController, - private val bypassController: KeyguardBypassController, - private val dozeParameters: DozeParameters) - : OnHeadsUpChangedListener, StatusBarStateController.StateListener, - PanelExpansionListener { + private val mHeadsUpManager: HeadsUpManager, + private val statusBarStateController: StatusBarStateController, + private val bypassController: KeyguardBypassController, + private val dozeParameters: DozeParameters +) : OnHeadsUpChangedListener, StatusBarStateController.StateListener, PanelExpansionListener { - private val mNotificationVisibility - = object : FloatProperty<NotificationWakeUpCoordinator>("notificationVisibility") { + private val mNotificationVisibility = object : FloatProperty<NotificationWakeUpCoordinator>( + "notificationVisibility") { override fun setValue(coordinator: NotificationWakeUpCoordinator, value: Float) { coordinator.setVisibilityAmount(value) @@ -78,10 +76,10 @@ class NotificationWakeUpCoordinator @Inject constructor( field = value willWakeUp = false if (value) { - if (mNotificationsVisible && !mNotificationsVisibleForExpansion - && !bypassController.bypassEnabled) { + if (mNotificationsVisible && !mNotificationsVisibleForExpansion && + !bypassController.bypassEnabled) { // We're waking up while pulsing, let's make sure the animation looks nice - mStackScroller.wakeUpFromPulse(); + mStackScroller.wakeUpFromPulse() } if (bypassController.bypassEnabled && !mNotificationsVisible) { // Let's make sure our huns become visible once we are waking up in case @@ -100,7 +98,7 @@ class NotificationWakeUpCoordinator @Inject constructor( } private var collapsedEnoughToHide: Boolean = false - lateinit var iconAreaController : NotificationIconAreaController + lateinit var iconAreaController: NotificationIconAreaController var pulsing: Boolean = false set(value) { @@ -132,8 +130,8 @@ class NotificationWakeUpCoordinator @Inject constructor( var canShow = pulsing if (bypassController.bypassEnabled) { // We also allow pulsing on the lock screen! - canShow = canShow || (wakingUp || willWakeUp || fullyAwake) - && statusBarStateController.state == StatusBarState.KEYGUARD + canShow = canShow || (wakingUp || willWakeUp || fullyAwake) && + statusBarStateController.state == StatusBarState.KEYGUARD // We want to hide the notifications when collapsed too much if (collapsedEnoughToHide) { canShow = false @@ -143,7 +141,7 @@ class NotificationWakeUpCoordinator @Inject constructor( } init { - mHeadsUpManagerPhone.addListener(this) + mHeadsUpManager.addListener(this) statusBarStateController.addCallback(this) addListener(object : WakeUpListener { override fun onFullyHiddenChanged(isFullyHidden: Boolean) { @@ -155,7 +153,7 @@ class NotificationWakeUpCoordinator @Inject constructor( increaseSpeed = false) } } - }); + }) } fun setStackScroller(stackScroller: NotificationStackScrollLayout) { @@ -178,46 +176,55 @@ class NotificationWakeUpCoordinator @Inject constructor( * @param animate should this change be animated * @param increaseSpeed should the speed be increased of the animation */ - fun setNotificationsVisibleForExpansion(visible: Boolean, animate: Boolean, - increaseSpeed: Boolean) { + fun setNotificationsVisibleForExpansion( + visible: Boolean, + animate: Boolean, + increaseSpeed: Boolean + ) { mNotificationsVisibleForExpansion = visible updateNotificationVisibility(animate, increaseSpeed) if (!visible && mNotificationsVisible) { // If we stopped expanding and we're still visible because we had a pulse that hasn't // times out, let's release them all to make sure were not stuck in a state where // notifications are visible - mHeadsUpManagerPhone.releaseAllImmediately() + mHeadsUpManager.releaseAllImmediately() } } fun addListener(listener: WakeUpListener) { - wakeUpListeners.add(listener); + wakeUpListeners.add(listener) } fun removeListener(listener: WakeUpListener) { - wakeUpListeners.remove(listener); + wakeUpListeners.remove(listener) } - private fun updateNotificationVisibility(animate: Boolean, increaseSpeed: Boolean) { + private fun updateNotificationVisibility( + animate: Boolean, + increaseSpeed: Boolean + ) { // TODO: handle Lockscreen wakeup for bypass when we're not pulsing anymore - var visible = mNotificationsVisibleForExpansion || mHeadsUpManagerPhone.hasNotifications() + var visible = mNotificationsVisibleForExpansion || mHeadsUpManager.hasNotifications() visible = visible && canShowPulsingHuns if (!visible && mNotificationsVisible && (wakingUp || willWakeUp) && mDozeAmount != 0.0f) { // let's not make notifications invisible while waking up, otherwise the animation // is strange - return; + return } setNotificationsVisible(visible, animate, increaseSpeed) } - private fun setNotificationsVisible(visible: Boolean, animate: Boolean, - increaseSpeed: Boolean) { + private fun setNotificationsVisible( + visible: Boolean, + animate: Boolean, + increaseSpeed: Boolean + ) { if (mNotificationsVisible == visible) { return } mNotificationsVisible = visible - mVisibilityAnimator?.cancel(); + mVisibilityAnimator?.cancel() if (animate) { notifyAnimationStart(visible) startVisibilityAnimation(increaseSpeed) @@ -230,8 +237,8 @@ class NotificationWakeUpCoordinator @Inject constructor( if (updateDozeAmountIfBypass()) { return } - if (linear != 1.0f && linear != 0.0f - && (mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) { + if (linear != 1.0f && linear != 0.0f && + (mLinearDozeAmount == 0.0f || mLinearDozeAmount == 1.0f)) { // Let's notify the scroller that an animation started notifyAnimationStart(mLinearDozeAmount == 1.0f) } @@ -245,17 +252,17 @@ class NotificationWakeUpCoordinator @Inject constructor( mStackScroller.setDozeAmount(mDozeAmount) updateHideAmount() if (changed && linear == 0.0f) { - setNotificationsVisible(visible = false, animate = false, increaseSpeed = false); + setNotificationsVisible(visible = false, animate = false, increaseSpeed = false) setNotificationsVisibleForExpansion(visible = false, animate = false, increaseSpeed = false) } } override fun onStateChanged(newState: Int) { - updateDozeAmountIfBypass(); + updateDozeAmountIfBypass() if (bypassController.bypassEnabled && - newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED - && (!statusBarStateController.isDozing || shouldAnimateVisibility())) { + newState == StatusBarState.KEYGUARD && state == StatusBarState.SHADE_LOCKED && + (!statusBarStateController.isDozing || shouldAnimateVisibility())) { // We're leaving shade locked. Let's animate the notifications away setNotificationsVisible(visible = true, increaseSpeed = false, animate = false) setNotificationsVisible(visible = false, increaseSpeed = false, animate = true) @@ -266,23 +273,23 @@ class NotificationWakeUpCoordinator @Inject constructor( override fun onPanelExpansionChanged(expansion: Float, tracking: Boolean) { val collapsedEnough = expansion <= 0.9f if (collapsedEnough != this.collapsedEnoughToHide) { - val couldShowPulsingHuns = canShowPulsingHuns; + val couldShowPulsingHuns = canShowPulsingHuns this.collapsedEnoughToHide = collapsedEnough if (couldShowPulsingHuns && !canShowPulsingHuns) { updateNotificationVisibility(animate = true, increaseSpeed = true) - mHeadsUpManagerPhone.releaseAllImmediately() + mHeadsUpManager.releaseAllImmediately() } } } private fun updateDozeAmountIfBypass(): Boolean { if (bypassController.bypassEnabled) { - var amount = 1.0f; - if (statusBarStateController.state == StatusBarState.SHADE - || statusBarStateController.state == StatusBarState.SHADE_LOCKED) { - amount = 0.0f; + var amount = 1.0f + if (statusBarStateController.state == StatusBarState.SHADE || + statusBarStateController.state == StatusBarState.SHADE_LOCKED) { + amount = 0.0f } - setDozeAmount(amount, amount) + setDozeAmount(amount, amount) return true } return false @@ -300,7 +307,7 @@ class NotificationWakeUpCoordinator @Inject constructor( visibilityAnimator.setInterpolator(Interpolators.LINEAR) var duration = StackStateAnimator.ANIMATION_DURATION_WAKEUP.toLong() if (increaseSpeed) { - duration = (duration.toFloat() / 1.5F).toLong(); + duration = (duration.toFloat() / 1.5F).toLong() } visibilityAnimator.setDuration(duration) visibilityAnimator.start() @@ -311,7 +318,7 @@ class NotificationWakeUpCoordinator @Inject constructor( mLinearVisibilityAmount = visibilityAmount mVisibilityAmount = mVisibilityInterpolator.getInterpolation( visibilityAmount) - handleAnimationFinished(); + handleAnimationFinished() updateHideAmount() } @@ -322,7 +329,7 @@ class NotificationWakeUpCoordinator @Inject constructor( } } - fun getWakeUpHeight() : Float { + fun getWakeUpHeight(): Float { return mStackScroller.wakeUpHeight } @@ -330,7 +337,7 @@ class NotificationWakeUpCoordinator @Inject constructor( val linearAmount = Math.min(1.0f - mLinearVisibilityAmount, mLinearDozeAmount) val amount = Math.min(1.0f - mVisibilityAmount, mDozeAmount) mStackScroller.setHideAmount(linearAmount, amount) - notificationsFullyHidden = linearAmount == 1.0f; + notificationsFullyHidden = linearAmount == 1.0f } private fun notifyAnimationStart(awake: Boolean) { @@ -361,7 +368,7 @@ class NotificationWakeUpCoordinator @Inject constructor( // if we animate, we see the shelf briefly visible. Instead we fully animate // the notification and its background out animate = false - } else if (!wakingUp && !willWakeUp){ + } else if (!wakingUp && !willWakeUp) { // TODO: look that this is done properly and not by anyone else entry.setHeadsUpAnimatingAway(true) mEntrySetToClearWhenFinished.add(entry) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java index e8a62e48e75e..4beeedecfdf5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java @@ -37,8 +37,8 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.NotificationUiAdjustment; import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.NotificationClicker; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; import com.android.systemui.statusbar.notification.row.NotifBindPipeline; @@ -66,7 +66,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { private static final String TAG = "NotificationViewManager"; - private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; + private final NotificationInterruptStateProvider mNotificationInterruptStateProvider; private final Context mContext; private final NotifBindPipeline mNotifBindPipeline; @@ -97,7 +97,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { StatusBarStateController statusBarStateController, NotificationGroupManager notificationGroupManager, NotificationGutsManager notificationGutsManager, - NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationInterruptStateProvider notificationInterruptionStateProvider, Provider<RowInflaterTask> rowInflaterTaskProvider, ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder) { mContext = context; @@ -106,7 +106,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { mMessagingUtil = notificationMessagingUtil; mNotificationRemoteInputManager = notificationRemoteInputManager; mNotificationLockscreenUserManager = notificationLockscreenUserManager; - mNotificationInterruptionStateProvider = notificationInterruptionStateProvider; + mNotificationInterruptStateProvider = notificationInterruptionStateProvider; mRowInflaterTaskProvider = rowInflaterTaskProvider; mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder; } @@ -243,7 +243,7 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { params.setUseIncreasedHeadsUpHeight(useIncreasedHeadsUp); params.setUseLowPriority(entry.isAmbient()); - if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) { + if (mNotificationInterruptStateProvider.shouldHeadsUp(entry)) { params.requireContentViews(FLAG_CONTENT_VIEW_HEADS_UP); } //TODO: Replace this API with RowContentBindParams directly 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 d0b553db2100..33aa3f80061f 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 @@ -29,10 +29,8 @@ import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationListener; import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.notification.ForegroundServiceDismissalFeatureController; -import com.android.systemui.statusbar.notification.NotificationAlertingManager; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; @@ -42,6 +40,9 @@ 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; import com.android.systemui.statusbar.notification.row.NotificationBlockingHelperManager; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -54,6 +55,7 @@ import java.util.concurrent.Executor; import javax.inject.Singleton; +import dagger.Binds; import dagger.Lazy; import dagger.Module; import dagger.Provides; @@ -123,7 +125,7 @@ public interface NotificationsModule { NotificationRemoteInputManager remoteInputManager, VisualStabilityManager visualStabilityManager, StatusBarStateController statusBarStateController, - NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationInterruptStateProvider notificationInterruptStateProvider, NotificationListener notificationListener, HeadsUpManager headsUpManager) { return new NotificationAlertingManager( @@ -131,7 +133,7 @@ public interface NotificationsModule { remoteInputManager, visualStabilityManager, statusBarStateController, - notificationInterruptionStateProvider, + notificationInterruptStateProvider, notificationListener, headsUpManager); } @@ -190,4 +192,9 @@ public interface NotificationsModule { NotificationEntryManager entryManager) { return featureFlags.isNewNotifPipelineRenderingEnabled() ? pipeline.get() : entryManager; } + + /** */ + @Binds + NotificationInterruptStateProvider bindNotificationInterruptStateProvider( + NotificationInterruptStateProviderImpl notificationInterruptStateProviderImpl); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt index 269a7a59f1b7..88888d10e283 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt @@ -14,7 +14,7 @@ * limitations under the License */ -package com.android.systemui.statusbar.notification +package com.android.systemui.statusbar.notification.interruption import android.content.Context import android.media.MediaMetadata @@ -24,6 +24,7 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController import com.android.systemui.statusbar.NotificationLockscreenUserManager import com.android.systemui.statusbar.NotificationMediaManager import com.android.systemui.statusbar.StatusBarState +import com.android.systemui.statusbar.notification.NotificationEntryManager import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.phone.HeadsUpManagerPhone import com.android.systemui.statusbar.phone.KeyguardBypassController diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java index df21f0b21ec1..b5725029450d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification; +package com.android.systemui.statusbar.notification.interruption; import static com.android.systemui.statusbar.NotificationRemoteInputManager.FORCE_REMOTE_INPUT_HISTORY; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP; @@ -27,6 +27,9 @@ 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; @@ -39,7 +42,7 @@ public class NotificationAlertingManager { private final NotificationRemoteInputManager mRemoteInputManager; private final VisualStabilityManager mVisualStabilityManager; private final StatusBarStateController mStatusBarStateController; - private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; + private final NotificationInterruptStateProvider mNotificationInterruptStateProvider; private final NotificationListener mNotificationListener; private HeadsUpManager mHeadsUpManager; @@ -52,13 +55,13 @@ public class NotificationAlertingManager { NotificationRemoteInputManager remoteInputManager, VisualStabilityManager visualStabilityManager, StatusBarStateController statusBarStateController, - NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationInterruptStateProvider notificationInterruptionStateProvider, NotificationListener notificationListener, HeadsUpManager headsUpManager) { mRemoteInputManager = remoteInputManager; mVisualStabilityManager = visualStabilityManager; mStatusBarStateController = statusBarStateController; - mNotificationInterruptionStateProvider = notificationInterruptionStateProvider; + mNotificationInterruptStateProvider = notificationInterruptionStateProvider; mNotificationListener = notificationListener; mHeadsUpManager = headsUpManager; @@ -94,7 +97,7 @@ public class NotificationAlertingManager { if (entry.getRow().getPrivateLayout().getHeadsUpChild() != null) { // Possible for shouldHeadsUp to change between the inflation starting and ending. // If it does and we no longer need to heads up, we should free the view. - if (mNotificationInterruptionStateProvider.shouldHeadsUp(entry)) { + if (mNotificationInterruptStateProvider.shouldHeadsUp(entry)) { mHeadsUpManager.showNotification(entry); if (!mStatusBarStateController.isDozing()) { // Mark as seen immediately @@ -109,7 +112,7 @@ public class NotificationAlertingManager { private void updateAlertState(NotificationEntry entry) { boolean alertAgain = alertAgain(entry, entry.getSbn().getNotification()); // includes check for whether this notification should be filtered: - boolean shouldAlert = mNotificationInterruptionStateProvider.shouldHeadsUp(entry); + boolean shouldAlert = mNotificationInterruptStateProvider.shouldHeadsUp(entry); final boolean wasAlerting = mHeadsUpManager.isAlerting(entry.getKey()); if (wasAlerting) { if (shouldAlert) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java new file mode 100644 index 000000000000..3292a8fcdb50 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProvider.java @@ -0,0 +1,59 @@ +/* + * 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 com.android.systemui.statusbar.notification.collection.NotificationEntry; + +/** + * Provides bubble-up and heads-up state for notification entries. + * + * When a notification is heads-up when dozing, this is also called "pulsing." + */ +public interface NotificationInterruptStateProvider { + /** + * If the device is awake (not dozing): + * Whether the notification should peek in from the top and alert the user. + * + * If the device is dozing: + * Whether the notification should show the ambient view of the notification ("pulse"). + * + * @param entry the entry to check + * @return true if the entry should heads up, false otherwise + */ + boolean shouldHeadsUp(NotificationEntry entry); + + /** + * Whether the notification should appear as a bubble with a fly-out on top of the screen. + * + * @param entry the entry to check + * @return true if the entry should bubble up, false otherwise + */ + boolean shouldBubbleUp(NotificationEntry entry); + + /** + * Whether to launch the entry's full screen intent when the entry is added. + * + * @param entry the entry that was added + * @return {@code true} if we should launch the full screen intent + */ + boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry); + + /** + * Add a component that can suppress visual interruptions. + */ + void addSuppressor(NotificationInterruptSuppressor suppressor); +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java index bbf2dde80040..46d50441c06b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java @@ -14,33 +14,35 @@ * limitations under the License. */ -package com.android.systemui.statusbar.notification; +package com.android.systemui.statusbar.notification.interruption; import static com.android.systemui.statusbar.StatusBarState.SHADE; import android.app.NotificationManager; -import android.content.Context; +import android.content.ContentResolver; import android.database.ContentObserver; import android.hardware.display.AmbientDisplayConfiguration; +import android.os.Handler; import android.os.PowerManager; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.UserHandle; import android.provider.Settings; -import android.service.dreams.DreamService; import android.service.dreams.IDreamManager; import android.service.notification.StatusBarNotification; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.Dependency; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.StatusBarState; +import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.HeadsUpManager; +import java.util.ArrayList; +import java.util.List; + import javax.inject.Inject; import javax.inject.Singleton; @@ -48,120 +50,84 @@ import javax.inject.Singleton; * Provides heads-up and pulsing state for notification entries. */ @Singleton -public class NotificationInterruptionStateProvider { - +public class NotificationInterruptStateProviderImpl implements NotificationInterruptStateProvider { private static final String TAG = "InterruptionStateProvider"; - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; //false; private static final boolean DEBUG_HEADS_UP = true; private static final boolean ENABLE_HEADS_UP = true; private static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up"; + private final List<NotificationInterruptSuppressor> mSuppressors = new ArrayList<>(); private final StatusBarStateController mStatusBarStateController; private final NotificationFilter mNotificationFilter; - private final AmbientDisplayConfiguration mAmbientDisplayConfiguration; - - private final Context mContext; + private final ContentResolver mContentResolver; private final PowerManager mPowerManager; private final IDreamManager mDreamManager; + private final AmbientDisplayConfiguration mAmbientDisplayConfiguration; private final BatteryController mBatteryController; - - private NotificationPresenter mPresenter; + private final ContentObserver mHeadsUpObserver; private HeadsUpManager mHeadsUpManager; - private HeadsUpSuppressor mHeadsUpSuppressor; - private ContentObserver mHeadsUpObserver; @VisibleForTesting protected boolean mUseHeadsUp = false; - private boolean mDisableNotificationAlerts; @Inject - public NotificationInterruptionStateProvider(Context context, NotificationFilter filter, - StatusBarStateController stateController, BatteryController batteryController) { - this(context, - (PowerManager) context.getSystemService(Context.POWER_SERVICE), - IDreamManager.Stub.asInterface( - ServiceManager.checkService(DreamService.DREAM_SERVICE)), - new AmbientDisplayConfiguration(context), - filter, - batteryController, - stateController); - } - - @VisibleForTesting - protected NotificationInterruptionStateProvider( - Context context, + public NotificationInterruptStateProviderImpl( + ContentResolver contentResolver, PowerManager powerManager, IDreamManager dreamManager, AmbientDisplayConfiguration ambientDisplayConfiguration, NotificationFilter notificationFilter, BatteryController batteryController, - StatusBarStateController statusBarStateController) { - mContext = context; + StatusBarStateController statusBarStateController, + HeadsUpManager headsUpManager, + @Main Handler mainHandler) { + mContentResolver = contentResolver; mPowerManager = powerManager; mDreamManager = dreamManager; mBatteryController = batteryController; mAmbientDisplayConfiguration = ambientDisplayConfiguration; mNotificationFilter = notificationFilter; mStatusBarStateController = statusBarStateController; - } - - /** Sets up late-binding dependencies for this component. */ - public void setUpWithPresenter( - NotificationPresenter notificationPresenter, - HeadsUpManager headsUpManager, - HeadsUpSuppressor headsUpSuppressor) { - setUpWithPresenter(notificationPresenter, headsUpManager, headsUpSuppressor, - new ContentObserver(Dependency.get(Dependency.MAIN_HANDLER)) { - @Override - public void onChange(boolean selfChange) { - boolean wasUsing = mUseHeadsUp; - mUseHeadsUp = ENABLE_HEADS_UP && !mDisableNotificationAlerts - && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt( - mContext.getContentResolver(), - Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, - Settings.Global.HEADS_UP_OFF); - Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled")); - if (wasUsing != mUseHeadsUp) { - if (!mUseHeadsUp) { - Log.d(TAG, - "dismissing any existing heads up notification on disable" - + " event"); - mHeadsUpManager.releaseAllImmediately(); - } - } - } - }); - } - - /** Sets up late-binding dependencies for this component. */ - public void setUpWithPresenter( - NotificationPresenter notificationPresenter, - HeadsUpManager headsUpManager, - HeadsUpSuppressor headsUpSuppressor, - ContentObserver observer) { - mPresenter = notificationPresenter; mHeadsUpManager = headsUpManager; - mHeadsUpSuppressor = headsUpSuppressor; - mHeadsUpObserver = observer; + mHeadsUpObserver = new ContentObserver(mainHandler) { + @Override + public void onChange(boolean selfChange) { + boolean wasUsing = mUseHeadsUp; + mUseHeadsUp = ENABLE_HEADS_UP + && Settings.Global.HEADS_UP_OFF != Settings.Global.getInt( + mContentResolver, + Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED, + Settings.Global.HEADS_UP_OFF); + Log.d(TAG, "heads up is " + (mUseHeadsUp ? "enabled" : "disabled")); + if (wasUsing != mUseHeadsUp) { + if (!mUseHeadsUp) { + Log.d(TAG, "dismissing any existing heads up notification on " + + "disable event"); + mHeadsUpManager.releaseAllImmediately(); + } + } + } + }; if (ENABLE_HEADS_UP) { - mContext.getContentResolver().registerContentObserver( + mContentResolver.registerContentObserver( Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED), true, mHeadsUpObserver); - mContext.getContentResolver().registerContentObserver( + mContentResolver.registerContentObserver( Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true, mHeadsUpObserver); } mHeadsUpObserver.onChange(true); // set up } - /** - * Whether the notification should appear as a bubble with a fly-out on top of the screen. - * - * @param entry the entry to check - * @return true if the entry should bubble up, false otherwise - */ + @Override + public void addSuppressor(NotificationInterruptSuppressor suppressor) { + mSuppressors.add(suppressor); + } + + @Override public boolean shouldBubbleUp(NotificationEntry entry) { final StatusBarNotification sbn = entry.getSbn(); @@ -201,12 +167,8 @@ public class NotificationInterruptionStateProvider { return true; } - /** - * Whether the notification should peek in from the top and alert the user. - * - * @param entry the entry to check - * @return true if the entry should heads up, false otherwise - */ + + @Override public boolean shouldHeadsUp(NotificationEntry entry) { if (mStatusBarStateController.isDozing()) { return shouldHeadsUpWhenDozing(entry); @@ -215,6 +177,17 @@ public class NotificationInterruptionStateProvider { } } + /** + * When an entry was added, should we launch its fullscreen intent? Examples are Alarms or + * incoming calls. + */ + @Override + public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) { + return entry.getSbn().getNotification().fullScreenIntent != null + && (!shouldHeadsUp(entry) + || mStatusBarStateController.getState() == StatusBarState.KEYGUARD); + } + private boolean shouldHeadsUpWhenAwake(NotificationEntry entry) { StatusBarNotification sbn = entry.getSbn(); @@ -271,13 +244,15 @@ public class NotificationInterruptionStateProvider { return false; } - if (!mHeadsUpSuppressor.canHeadsUp(entry, sbn)) { - if (DEBUG_HEADS_UP) { - Log.d(TAG, "No heads up: aborted by suppressor: " + sbn.getKey()); + for (int i = 0; i < mSuppressors.size(); i++) { + if (mSuppressors.get(i).suppressAwakeHeadsUp(entry)) { + if (DEBUG_HEADS_UP) { + Log.d(TAG, "No heads up: aborted by suppressor: " + + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey()); + } + return false; } - return false; } - return true; } @@ -325,7 +300,7 @@ public class NotificationInterruptionStateProvider { } return false; } - return true; + return true; } /** @@ -334,8 +309,7 @@ public class NotificationInterruptionStateProvider { * @param entry the entry to check * @return true if these checks pass, false if the notification should not alert */ - @VisibleForTesting - public boolean canAlertCommon(NotificationEntry entry) { + private boolean canAlertCommon(NotificationEntry entry) { StatusBarNotification sbn = entry.getSbn(); if (mNotificationFilter.shouldFilterOut(entry)) { @@ -352,6 +326,16 @@ public class NotificationInterruptionStateProvider { } return false; } + + for (int i = 0; i < mSuppressors.size(); i++) { + if (mSuppressors.get(i).suppressInterruptions(entry)) { + if (DEBUG_HEADS_UP) { + Log.d(TAG, "No alerting: aborted by suppressor: " + + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey()); + } + return false; + } + } return true; } @@ -361,15 +345,17 @@ public class NotificationInterruptionStateProvider { * @param entry the entry to check * @return true if these checks pass, false if the notification should not alert */ - @VisibleForTesting - public boolean canAlertAwakeCommon(NotificationEntry entry) { + private boolean canAlertAwakeCommon(NotificationEntry entry) { StatusBarNotification sbn = entry.getSbn(); - if (mPresenter.isDeviceInVrMode()) { - if (DEBUG_HEADS_UP) { - Log.d(TAG, "No alerting: no huns or vr mode"); + for (int i = 0; i < mSuppressors.size(); i++) { + if (mSuppressors.get(i).suppressAwakeInterruptions(entry)) { + if (DEBUG_HEADS_UP) { + Log.d(TAG, "No alerting: aborted by suppressor: " + + mSuppressors.get(i).getName() + " sbnKey=" + sbn.getKey()); + } + return false; } - return false; } if (isSnoozedPackage(sbn)) { @@ -392,54 +378,4 @@ public class NotificationInterruptionStateProvider { private boolean isSnoozedPackage(StatusBarNotification sbn) { return mHeadsUpManager.isSnoozed(sbn.getPackageName()); } - - /** Sets whether to disable all alerts. */ - public void setDisableNotificationAlerts(boolean disableNotificationAlerts) { - mDisableNotificationAlerts = disableNotificationAlerts; - mHeadsUpObserver.onChange(true); - } - - /** Whether all alerts are disabled. */ - @VisibleForTesting - public boolean areNotificationAlertsDisabled() { - return mDisableNotificationAlerts; - } - - /** Whether HUNs should be used. */ - @VisibleForTesting - public boolean getUseHeadsUp() { - return mUseHeadsUp; - } - - protected NotificationPresenter getPresenter() { - return mPresenter; - } - - /** - * When an entry was added, should we launch its fullscreen intent? Examples are Alarms or - * incoming calls. - * - * @param entry the entry that was added - * @return {@code true} if we should launch the full screen intent - */ - public boolean shouldLaunchFullScreenIntentWhenAdded(NotificationEntry entry) { - return entry.getSbn().getNotification().fullScreenIntent != null - && (!shouldHeadsUp(entry) - || mStatusBarStateController.getState() == StatusBarState.KEYGUARD); - } - - /** A component which can suppress heads-up notifications due to the overall state of the UI. */ - public interface HeadsUpSuppressor { - /** - * Returns false if the provided notification is ineligible for heads-up according to this - * component. - * - * @param entry entry of the notification that might be heads upped - * @param sbn notification that might be heads upped - * @return false if the notification can not be heads upped - */ - boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn); - - } - } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptSuppressor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptSuppressor.java new file mode 100644 index 000000000000..c19f8bd1994a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptSuppressor.java @@ -0,0 +1,64 @@ +/* + * 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 com.android.systemui.statusbar.notification.collection.NotificationEntry; + +/** A component which can suppress visual interruptions of notifications such as heads-up and + * bubble-up. + */ +public interface NotificationInterruptSuppressor { + /** + * A unique name to identify this suppressor. + */ + default String getName() { + return this.getClass().getName(); + } + + /** + * Returns true if the provided notification is, when the device is awake, ineligible for + * heads-up according to this component. + * + * @param entry entry of the notification that might heads-up + * @return true if the heads up interruption should be suppressed when the device is awake + */ + default boolean suppressAwakeHeadsUp(NotificationEntry entry) { + return false; + } + + /** + * Returns true if the provided notification is, when the device is awake, ineligible for + * heads-up or bubble-up according to this component. + * + * @param entry entry of the notification that might heads-up or bubble-up + * @return true if interruptions should be suppressed when the device is awake + */ + default boolean suppressAwakeInterruptions(NotificationEntry entry) { + return false; + } + + /** + * Returns true if the provided notification is, regardless of awake/dozing state, + * ineligible for heads-up or bubble-up according to this component. + * + * @param entry entry of the notification that might heads-up or bubble-up + * @return true if interruptions should be suppressed + */ + default boolean suppressInterruptions(NotificationEntry entry) { + return false; + } +} 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 3e6e027d6c59..287ede48fa06 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -185,15 +185,14 @@ import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; -import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; import com.android.systemui.statusbar.notification.DynamicPrivacyController; import com.android.systemui.statusbar.notification.NotificationActivityStarter; -import com.android.systemui.statusbar.notification.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; 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.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -404,10 +403,9 @@ public class StatusBar extends SystemUI implements DemoMode, private final NotificationGutsManager mGutsManager; private final NotificationLogger mNotificationLogger; - private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; private final NotificationViewHierarchyManager mViewHierarchyManager; private final KeyguardViewMediator mKeyguardViewMediator; - private final NotificationAlertingManager mNotificationAlertingManager; + protected final NotificationInterruptStateProvider mNotificationInterruptStateProvider; // for disabling the status bar private int mDisabled1 = 0; @@ -621,10 +619,9 @@ public class StatusBar extends SystemUI implements DemoMode, RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, NotificationGutsManager notificationGutsManager, NotificationLogger notificationLogger, - NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationInterruptStateProvider notificationInterruptStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, - NotificationAlertingManager notificationAlertingManager, DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, @@ -701,10 +698,9 @@ public class StatusBar extends SystemUI implements DemoMode, mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler; mGutsManager = notificationGutsManager; mNotificationLogger = notificationLogger; - mNotificationInterruptionStateProvider = notificationInterruptionStateProvider; + mNotificationInterruptStateProvider = notificationInterruptStateProvider; mViewHierarchyManager = notificationViewHierarchyManager; mKeyguardViewMediator = keyguardViewMediator; - mNotificationAlertingManager = notificationAlertingManager; mDisplayMetrics = displayMetrics; mMetricsLogger = metricsLogger; mUiBgExecutor = uiBgExecutor; @@ -1238,9 +1234,9 @@ public class StatusBar extends SystemUI implements DemoMode, mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController, mHeadsUpManager, mNotificationShadeWindowView, mStackScroller, mDozeScrimController, mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController, - mNotificationAlertingManager, mKeyguardStateController, - mKeyguardIndicationController, - this /* statusBar */, mShadeController, mCommandQueue, mInitController); + mKeyguardStateController, mKeyguardIndicationController, + this /* statusBar */, mShadeController, mCommandQueue, mInitController, + mNotificationInterruptStateProvider); mNotificationShelf.setOnActivatedListener(mPresenter); mRemoteInputManager.getController().addCallback(mNotificationShadeWindowController); @@ -1589,8 +1585,9 @@ public class StatusBar extends SystemUI implements DemoMode, } if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) { - mNotificationInterruptionStateProvider.setDisableNotificationAlerts( - (state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0); + if (areNotificationAlertsDisabled()) { + mHeadsUpManager.releaseAllImmediately(); + } } if ((diff2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) { @@ -1605,6 +1602,10 @@ public class StatusBar extends SystemUI implements DemoMode, } } + boolean areNotificationAlertsDisabled() { + return (mDisabled1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0; + } + protected H createHandler() { return new StatusBar.H(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index e1a20b6ac5d3..53fa2630a9c3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -68,12 +68,12 @@ import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.policy.HeadsUpUtil; @@ -108,7 +108,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final NotifCollection mNotifCollection; private final FeatureFlags mFeatureFlags; private final StatusBarStateController mStatusBarStateController; - private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; + private final NotificationInterruptStateProvider mNotificationInterruptStateProvider; private final MetricsLogger mMetricsLogger; private final Context mContext; private final NotificationPanelViewController mNotificationPanel; @@ -142,7 +142,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit NotificationLockscreenUserManager lockscreenUserManager, ShadeController shadeController, StatusBar statusBar, KeyguardStateController keyguardStateController, - NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationInterruptStateProvider notificationInterruptStateProvider, MetricsLogger metricsLogger, LockPatternUtils lockPatternUtils, Handler mainThreadHandler, Handler backgroundHandler, Executor uiBgExecutor, ActivityIntentHelper activityIntentHelper, BubbleController bubbleController, @@ -167,7 +167,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mActivityStarter = activityStarter; mEntryManager = entryManager; mStatusBarStateController = statusBarStateController; - mNotificationInterruptionStateProvider = notificationInterruptionStateProvider; + mNotificationInterruptStateProvider = notificationInterruptStateProvider; mMetricsLogger = metricsLogger; mAssistManagerLazy = assistManagerLazy; mGroupManager = groupManager; @@ -436,7 +436,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit } private void handleFullScreenIntent(NotificationEntry entry) { - if (mNotificationInterruptionStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) { + if (mNotificationInterruptStateProvider.shouldLaunchFullScreenIntentWhenAdded(entry)) { if (shouldSuppressFullScreenIntent(entry)) { if (DEBUG) { Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + entry.getKey()); @@ -603,7 +603,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit private final ActivityIntentHelper mActivityIntentHelper; private final BubbleController mBubbleController; private NotificationPanelViewController mNotificationPanelViewController; - private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; + private NotificationInterruptStateProvider mNotificationInterruptStateProvider; private final ShadeController mShadeController; private NotificationPresenter mNotificationPresenter; private ActivityLaunchAnimator mActivityLaunchAnimator; @@ -626,7 +626,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit NotificationGroupManager groupManager, NotificationLockscreenUserManager lockscreenUserManager, KeyguardStateController keyguardStateController, - NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationInterruptStateProvider notificationInterruptStateProvider, MetricsLogger metricsLogger, LockPatternUtils lockPatternUtils, @Main Handler mainThreadHandler, @@ -654,7 +654,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mGroupManager = groupManager; mLockscreenUserManager = lockscreenUserManager; mKeyguardStateController = keyguardStateController; - mNotificationInterruptionStateProvider = notificationInterruptionStateProvider; + mNotificationInterruptStateProvider = notificationInterruptStateProvider; mMetricsLogger = metricsLogger; mLockPatternUtils = lockPatternUtils; mMainThreadHandler = mainThreadHandler; @@ -712,7 +712,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mShadeController, mStatusBar, mKeyguardStateController, - mNotificationInterruptionStateProvider, + mNotificationInterruptStateProvider, mMetricsLogger, mLockPatternUtils, mMainThreadHandler, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index 30d6b5079166..79cea91b8612 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -60,13 +60,13 @@ import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.AboveShelfObserver; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.DynamicPrivacyController; -import com.android.systemui.statusbar.notification.NotificationAlertingManager; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; @@ -98,8 +98,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class); private final NotificationEntryManager mEntryManager = Dependency.get(NotificationEntryManager.class); - private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider = - Dependency.get(NotificationInterruptionStateProvider.class); private final NotificationMediaManager mMediaManager = Dependency.get(NotificationMediaManager.class); private final VisualStabilityManager mVisualStabilityManager = @@ -140,13 +138,13 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, ScrimController scrimController, ActivityLaunchAnimator activityLaunchAnimator, DynamicPrivacyController dynamicPrivacyController, - NotificationAlertingManager notificationAlertingManager, KeyguardStateController keyguardStateController, KeyguardIndicationController keyguardIndicationController, StatusBar statusBar, ShadeController shadeController, CommandQueue commandQueue, - InitController initController) { + InitController initController, + NotificationInterruptStateProvider notificationInterruptStateProvider) { mContext = context; mKeyguardStateController = keyguardStateController; mNotificationPanel = panel; @@ -216,8 +214,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, mEntryManager.addNotificationLifetimeExtender(mGutsManager); mEntryManager.addNotificationLifetimeExtenders( remoteInputManager.getLifetimeExtenders()); - mNotificationInterruptionStateProvider.setUpWithPresenter( - this, mHeadsUpManager, this::canHeadsUp); + notificationInterruptStateProvider.addSuppressor(mInterruptSuppressor); mLockscreenUserManager.setUpWithPresenter(this); mMediaManager.setUpWithPresenter(this); mVisualStabilityManager.setUpWithPresenter(this); @@ -336,39 +333,6 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, return mEntryManager.hasActiveNotifications(); } - public boolean canHeadsUp(NotificationEntry entry, StatusBarNotification sbn) { - if (mStatusBar.isOccluded()) { - boolean devicePublic = mLockscreenUserManager. - isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId()); - boolean userPublic = devicePublic - || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId()); - boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry); - if (userPublic && needsRedaction) { - // TODO(b/135046837): we can probably relax this with dynamic privacy - return false; - } - } - - if (!mCommandQueue.panelsEnabled()) { - if (DEBUG) { - Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey()); - } - return false; - } - - if (sbn.getNotification().fullScreenIntent != null) { - if (mAccessibilityManager.isTouchExplorationEnabled()) { - if (DEBUG) Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey()); - return false; - } else { - // we only allow head-up on the lockscreen if it doesn't have a fullscreen intent - return !mKeyguardStateController.isShowing() - || mStatusBar.isOccluded(); - } - } - return true; - } - @Override public void onUserSwitched(int newUserId) { // Begin old BaseStatusBar.userSwitched @@ -507,4 +471,66 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, } } }; + + private final NotificationInterruptSuppressor mInterruptSuppressor = + new NotificationInterruptSuppressor() { + @Override + public String getName() { + return TAG; + } + + @Override + public boolean suppressAwakeHeadsUp(NotificationEntry entry) { + final StatusBarNotification sbn = entry.getSbn(); + if (mStatusBar.isOccluded()) { + boolean devicePublic = mLockscreenUserManager + .isLockscreenPublicMode(mLockscreenUserManager.getCurrentUserId()); + boolean userPublic = devicePublic + || mLockscreenUserManager.isLockscreenPublicMode(sbn.getUserId()); + boolean needsRedaction = mLockscreenUserManager.needsRedaction(entry); + if (userPublic && needsRedaction) { + // TODO(b/135046837): we can probably relax this with dynamic privacy + return true; + } + } + + if (!mCommandQueue.panelsEnabled()) { + if (DEBUG) { + Log.d(TAG, "No heads up: disabled panel : " + sbn.getKey()); + } + return true; + } + + if (sbn.getNotification().fullScreenIntent != null) { + // we don't allow head-up on the lockscreen (unless there's a + // "showWhenLocked" activity currently showing) if + // the potential HUN has a fullscreen intent + if (mKeyguardStateController.isShowing() && !mStatusBar.isOccluded()) { + if (DEBUG) { + Log.d(TAG, "No heads up: entry has fullscreen intent on lockscreen " + + sbn.getKey()); + } + return true; + } + + if (mAccessibilityManager.isTouchExplorationEnabled()) { + if (DEBUG) { + Log.d(TAG, "No heads up: accessible fullscreen: " + sbn.getKey()); + } + return true; + } + } + return false; + } + + @Override + public boolean suppressAwakeInterruptions(NotificationEntry entry) { + return isDeviceInVrMode(); + } + + @Override + public boolean suppressInterruptions(NotificationEntry entry) { + return mStatusBar.areNotificationAlertsDisabled(); + } + }; } 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 eec8d50f00de..824e0f0d4295 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 @@ -56,13 +56,12 @@ import com.android.systemui.statusbar.PulseExpansionHandler; import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; -import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; import com.android.systemui.statusbar.notification.DynamicPrivacyController; -import com.android.systemui.statusbar.notification.NotificationAlertingManager; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; 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.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.phone.AutoHideController; @@ -139,10 +138,9 @@ public interface StatusBarPhoneModule { RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, NotificationGutsManager notificationGutsManager, NotificationLogger notificationLogger, - NotificationInterruptionStateProvider notificationInterruptionStateProvider, + NotificationInterruptStateProvider notificationInterruptStateProvider, NotificationViewHierarchyManager notificationViewHierarchyManager, KeyguardViewMediator keyguardViewMediator, - NotificationAlertingManager notificationAlertingManager, DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, @@ -218,10 +216,9 @@ public interface StatusBarPhoneModule { remoteInputQuickSettingsDisabler, notificationGutsManager, notificationLogger, - notificationInterruptionStateProvider, + notificationInterruptStateProvider, notificationViewHierarchyManager, keyguardViewMediator, - notificationAlertingManager, displayMetrics, metricsLogger, uiBgExecutor, diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index 742e652a7189..977d0bbd0004 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -45,7 +45,11 @@ import android.app.IActivityManager; import android.app.Notification; import android.app.PendingIntent; import android.content.res.Resources; +import android.hardware.display.AmbientDisplayConfiguration; import android.hardware.face.FaceManager; +import android.os.Handler; +import android.os.PowerManager; +import android.service.dreams.IDreamManager; import android.service.notification.ZenModeConfig; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -61,14 +65,12 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.NotificationRemoveInterceptor; import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationFilter; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; @@ -227,15 +229,17 @@ public class BubbleControllerTest extends SysuiTestCase { mZenModeConfig.suppressedVisualEffects = 0; when(mZenModeController.getConfig()).thenReturn(mZenModeConfig); - TestableNotificationInterruptionStateProvider interruptionStateProvider = - new TestableNotificationInterruptionStateProvider(mContext, + TestableNotificationInterruptStateProviderImpl interruptionStateProvider = + new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(), + mock(PowerManager.class), + mock(IDreamManager.class), + mock(AmbientDisplayConfiguration.class), mock(NotificationFilter.class), mock(StatusBarStateController.class), - mock(BatteryController.class)); - interruptionStateProvider.setUpWithPresenter( - mock(NotificationPresenter.class), - mock(HeadsUpManager.class), - mock(NotificationInterruptionStateProvider.HeadsUpSuppressor.class)); + mock(BatteryController.class), + mock(HeadsUpManager.class), + mock(Handler.class) + ); mBubbleData = new BubbleData(mContext); when(mFeatureFlagsOldPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(false); mBubbleController = new TestableBubbleController( diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java index 22ef3f34cb4d..7fc83dac0280 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java @@ -41,7 +41,11 @@ import android.app.IActivityManager; import android.app.Notification; import android.app.PendingIntent; import android.content.res.Resources; +import android.hardware.display.AmbientDisplayConfiguration; import android.hardware.face.FaceManager; +import android.os.Handler; +import android.os.PowerManager; +import android.service.dreams.IDreamManager; import android.service.notification.ZenModeConfig; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -57,12 +61,10 @@ import com.android.systemui.dump.DumpManager; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLockscreenUserManager; -import com.android.systemui.statusbar.NotificationPresenter; import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationFilter; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; 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; @@ -216,15 +218,17 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { mZenModeConfig.suppressedVisualEffects = 0; when(mZenModeController.getConfig()).thenReturn(mZenModeConfig); - TestableNotificationInterruptionStateProvider interruptionStateProvider = - new TestableNotificationInterruptionStateProvider(mContext, + TestableNotificationInterruptStateProviderImpl interruptionStateProvider = + new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(), + mock(PowerManager.class), + mock(IDreamManager.class), + mock(AmbientDisplayConfiguration.class), mock(NotificationFilter.class), mock(StatusBarStateController.class), - mock(BatteryController.class)); - interruptionStateProvider.setUpWithPresenter( - mock(NotificationPresenter.class), - mock(HeadsUpManager.class), - mock(NotificationInterruptionStateProvider.HeadsUpSuppressor.class)); + mock(BatteryController.class), + mock(HeadsUpManager.class), + mock(Handler.class) + ); mBubbleData = new BubbleData(mContext); when(mFeatureFlagsNewPipeline.isNewNotifPipelineRenderingEnabled()).thenReturn(true); mBubbleController = new TestableBubbleController( diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java index de1fb41ddbbd..d3d90c408468 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java @@ -23,8 +23,8 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotifPipeline; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.ShadeController; @@ -44,7 +44,7 @@ public class TestableBubbleController extends BubbleController { ShadeController shadeController, BubbleData data, ConfigurationController configurationController, - NotificationInterruptionStateProvider interruptionStateProvider, + NotificationInterruptStateProvider interruptionStateProvider, ZenModeController zenModeController, NotificationLockscreenUserManager lockscreenUserManager, NotificationGroupManager groupManager, diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java new file mode 100644 index 000000000000..17dc76b38a56 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptStateProviderImpl.java @@ -0,0 +1,55 @@ +/* + * 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.bubbles; + +import android.content.ContentResolver; +import android.hardware.display.AmbientDisplayConfiguration; +import android.os.Handler; +import android.os.PowerManager; +import android.service.dreams.IDreamManager; + +import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.statusbar.notification.NotificationFilter; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl; +import com.android.systemui.statusbar.policy.BatteryController; +import com.android.systemui.statusbar.policy.HeadsUpManager; + +public class TestableNotificationInterruptStateProviderImpl + extends NotificationInterruptStateProviderImpl { + + TestableNotificationInterruptStateProviderImpl( + ContentResolver contentResolver, + PowerManager powerManager, + IDreamManager dreamManager, + AmbientDisplayConfiguration ambientDisplayConfiguration, + NotificationFilter filter, + StatusBarStateController statusBarStateController, + BatteryController batteryController, + HeadsUpManager headsUpManager, + Handler mainHandler) { + super(contentResolver, + powerManager, + dreamManager, + ambientDisplayConfiguration, + filter, + batteryController, + statusBarStateController, + headsUpManager, + mainHandler); + mUseHeadsUp = true; + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptionStateProvider.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptionStateProvider.java deleted file mode 100644 index 5d192b2071b5..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableNotificationInterruptionStateProvider.java +++ /dev/null @@ -1,35 +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.bubbles; - -import android.content.Context; - -import com.android.systemui.plugins.statusbar.StatusBarStateController; -import com.android.systemui.statusbar.notification.NotificationFilter; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; -import com.android.systemui.statusbar.policy.BatteryController; - -public class TestableNotificationInterruptionStateProvider - extends NotificationInterruptionStateProvider { - - TestableNotificationInterruptionStateProvider(Context context, - NotificationFilter filter, StatusBarStateController controller, - BatteryController batteryController) { - super(context, filter, controller, batteryController); - mUseHeadsUp = true; - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java index 1693e7f4df7f..f9c62e1ab604 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.android.systemui.statusbar; +package com.android.systemui.statusbar.notification.interruption; import static android.app.Notification.FLAG_BUBBLE; @@ -30,15 +30,14 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Notification; import android.app.PendingIntent; -import android.content.Context; import android.content.Intent; import android.graphics.drawable.Icon; import android.hardware.display.AmbientDisplayConfiguration; +import android.os.Handler; import android.os.PowerManager; import android.os.RemoteException; import android.service.dreams.IDreamManager; @@ -50,7 +49,6 @@ import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.notification.NotificationFilter; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; import com.android.systemui.statusbar.policy.BatteryController; @@ -68,7 +66,7 @@ import org.mockito.MockitoAnnotations; */ @RunWith(AndroidTestingRunner.class) @SmallTest -public class NotificationInterruptionStateProviderTest extends SysuiTestCase { +public class NotificationInterruptStateProviderImplTest extends SysuiTestCase { @Mock PowerManager mPowerManager; @@ -81,38 +79,36 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { @Mock StatusBarStateController mStatusBarStateController; @Mock - NotificationPresenter mPresenter; - @Mock HeadsUpManager mHeadsUpManager; @Mock - NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor; - @Mock BatteryController mBatteryController; + @Mock + Handler mMockHandler; - private NotificationInterruptionStateProvider mNotifInterruptionStateProvider; + private NotificationInterruptStateProviderImpl mNotifInterruptionStateProvider; @Before public void setup() { MockitoAnnotations.initMocks(this); mNotifInterruptionStateProvider = - new TestableNotificationInterruptionStateProvider(mContext, + new NotificationInterruptStateProviderImpl( + mContext.getContentResolver(), mPowerManager, mDreamManager, mAmbientDisplayConfiguration, mNotificationFilter, + mBatteryController, mStatusBarStateController, - mBatteryController); + mHeadsUpManager, + mMockHandler); - mNotifInterruptionStateProvider.setUpWithPresenter( - mPresenter, - mHeadsUpManager, - mHeadsUpSuppressor); + mNotifInterruptionStateProvider.mUseHeadsUp = true; } /** * Sets up the state such that any requests to - * {@link NotificationInterruptionStateProvider#canAlertCommon(NotificationEntry)} will + * {@link NotificationInterruptStateProviderImpl#canAlertCommon(NotificationEntry)} will * pass as long its provided NotificationEntry fulfills group suppression check. */ private void ensureStateForAlertCommon() { @@ -121,17 +117,16 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { /** * Sets up the state such that any requests to - * {@link NotificationInterruptionStateProvider#canAlertAwakeCommon(NotificationEntry)} will + * {@link NotificationInterruptStateProviderImpl#canAlertAwakeCommon(NotificationEntry)} will * pass as long its provided NotificationEntry fulfills launch fullscreen check. */ private void ensureStateForAlertAwakeCommon() { - when(mPresenter.isDeviceInVrMode()).thenReturn(false); when(mHeadsUpManager.isSnoozed(any())).thenReturn(false); } /** * Sets up the state such that any requests to - * {@link NotificationInterruptionStateProvider#shouldHeadsUp(NotificationEntry)} will + * {@link NotificationInterruptStateProviderImpl#shouldHeadsUp(NotificationEntry)} will * pass as long its provided NotificationEntry fulfills importance & DND checks. */ private void ensureStateForHeadsUpWhenAwake() throws RemoteException { @@ -141,12 +136,11 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { when(mStatusBarStateController.isDozing()).thenReturn(false); when(mDreamManager.isDreaming()).thenReturn(false); when(mPowerManager.isScreenOn()).thenReturn(true); - when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true); } /** * Sets up the state such that any requests to - * {@link NotificationInterruptionStateProvider#shouldHeadsUp(NotificationEntry)} will + * {@link NotificationInterruptStateProviderImpl#shouldHeadsUp(NotificationEntry)} will * pass as long its provided NotificationEntry fulfills importance & DND checks. */ private void ensureStateForHeadsUpWhenDozing() { @@ -158,7 +152,7 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { /** * Sets up the state such that any requests to - * {@link NotificationInterruptionStateProvider#shouldBubbleUp(NotificationEntry)} will + * {@link NotificationInterruptStateProviderImpl#shouldBubbleUp(NotificationEntry)} will * pass as long its provided NotificationEntry fulfills importance & bubble checks. */ private void ensureStateForBubbleUp() { @@ -166,75 +160,53 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { ensureStateForAlertAwakeCommon(); } - /** - * Ensure that the disabled state is set correctly. - */ @Test - public void testDisableNotificationAlerts() { - // Enabled by default - assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isFalse(); + public void testDefaultSuppressorDoesNotSuppress() { + // GIVEN a suppressor without any overrides + final NotificationInterruptSuppressor defaultSuppressor = + new NotificationInterruptSuppressor() { + @Override + public String getName() { + return "defaultSuppressor"; + } + }; - // Disable alerts - mNotifInterruptionStateProvider.setDisableNotificationAlerts(true); - assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isTrue(); + NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); - // Enable alerts - mNotifInterruptionStateProvider.setDisableNotificationAlerts(false); - assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isFalse(); + // THEN this suppressor doesn't suppress anything by default + assertThat(defaultSuppressor.suppressAwakeHeadsUp(entry)).isFalse(); + assertThat(defaultSuppressor.suppressAwakeInterruptions(entry)).isFalse(); + assertThat(defaultSuppressor.suppressInterruptions(entry)).isFalse(); } - /** - * Ensure that the disabled alert state effects whether HUNs are enabled. - */ @Test - public void testHunSettingsChange_enabled_butAlertsDisabled() { - // Set up but without a mock change observer - mNotifInterruptionStateProvider.setUpWithPresenter( - mPresenter, - mHeadsUpManager, - mHeadsUpSuppressor); - - // HUNs enabled by default - assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isTrue(); - - // Set alerts disabled - mNotifInterruptionStateProvider.setDisableNotificationAlerts(true); + public void testShouldHeadsUpAwake() throws RemoteException { + ensureStateForHeadsUpWhenAwake(); - // No more HUNs - assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isFalse(); + NotificationEntry entry = createNotification(IMPORTANCE_HIGH); + assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue(); } - /** - * Alerts can happen. - */ @Test - public void testCanAlertCommon_true() { - ensureStateForAlertCommon(); - - NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); - assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isTrue(); - } + public void testShouldNotHeadsUpAwake_flteredOut() throws RemoteException { + // GIVEN state for "heads up when awake" is true + ensureStateForHeadsUpWhenAwake(); - /** - * Filtered out notifications don't alert. - */ - @Test - public void testCanAlertCommon_false_filteredOut() { - ensureStateForAlertCommon(); - when(mNotificationFilter.shouldFilterOut(any())).thenReturn(true); + // WHEN this entry should be filtered out + NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); + when(mNotificationFilter.shouldFilterOut(entry)).thenReturn(true); - NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); - assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isFalse(); + // THEN we shouldn't heads up this entry + assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); } - /** - * Grouped notifications have different alerting behaviours, sometimes the alert for a - * grouped notification may be suppressed {@link android.app.Notification#GROUP_ALERT_CHILDREN}. - */ @Test - public void testCanAlertCommon_false_suppressedForGroups() { - ensureStateForAlertCommon(); + public void testShouldNotHeadsUp_suppressedForGroups() throws RemoteException { + // GIVEN state for "heads up when awake" is true + ensureStateForHeadsUpWhenAwake(); + // WHEN the alert for a grouped notification is suppressed + // see {@link android.app.Notification#GROUP_ALERT_CHILDREN} NotificationEntry entry = new NotificationEntryBuilder() .setPkg("a") .setOpPkg("a") @@ -247,40 +219,40 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { .setImportance(IMPORTANCE_DEFAULT) .build(); - assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isFalse(); + // THEN this entry shouldn't HUN + assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); } - /** - * HUNs while dozing can happen. - */ @Test - public void testShouldHeadsUpWhenDozing_true() { + public void testShouldHeadsUpWhenDozing() { ensureStateForHeadsUpWhenDozing(); NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue(); } - /** - * Ambient display can show HUNs for new notifications, this may be disabled. - */ @Test - public void testShouldHeadsUpWhenDozing_false_pulseDisabled() { + public void testShouldNotHeadsUpWhenDozing_pulseDisabled() { + // GIVEN state for "heads up when dozing" is true ensureStateForHeadsUpWhenDozing(); + + // WHEN pulsing (HUNs when dozing) is disabled when(mAmbientDisplayConfiguration.pulseOnNotificationEnabled(anyInt())).thenReturn(false); + // THEN this entry shouldn't HUN NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); } - /** - * If the device is not in ambient display or sleeping then we don't HUN. - */ @Test - public void testShouldHeadsUpWhenDozing_false_notDozing() { + public void testShouldNotHeadsUpWhenDozing_notDozing() { + // GIVEN state for "heads up when dozing" is true ensureStateForHeadsUpWhenDozing(); + + // WHEN we're not dozing (in ambient display or sleeping) when(mStatusBarStateController.isDozing()).thenReturn(false); + // THEN this entry shouldn't HUN NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); } @@ -290,7 +262,7 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { * {@link android.app.NotificationManager.Policy#SUPPRESSED_EFFECT_AMBIENT}. */ @Test - public void testShouldHeadsUpWhenDozing_false_suppressingAmbient() { + public void testShouldNotHeadsUpWhenDozing_suppressingAmbient() { ensureStateForHeadsUpWhenDozing(); NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); @@ -301,23 +273,18 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); } - /** - * Notifications that are < {@link android.app.NotificationManager#IMPORTANCE_DEFAULT} don't - * get to pulse. - */ @Test - public void testShouldHeadsUpWhenDozing_false_lessImportant() { + public void testShouldNotHeadsUpWhenDozing_lessImportant() { ensureStateForHeadsUpWhenDozing(); + // Notifications that are < {@link android.app.NotificationManager#IMPORTANCE_DEFAULT} don't + // get to pulse NotificationEntry entry = createNotification(IMPORTANCE_LOW); assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); } - /** - * Heads up can happen. - */ @Test - public void testShouldHeadsUp_true() throws RemoteException { + public void testShouldHeadsUp() throws RemoteException { ensureStateForHeadsUpWhenAwake(); NotificationEntry entry = createNotification(IMPORTANCE_HIGH); @@ -325,38 +292,11 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { } /** - * Heads up notifications can be disabled in general. - */ - @Test - public void testShouldHeadsUp_false_noHunsAllowed() throws RemoteException { - ensureStateForHeadsUpWhenAwake(); - - // Set alerts disabled, this should cause heads up to be false - mNotifInterruptionStateProvider.setDisableNotificationAlerts(true); - assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isFalse(); - - NotificationEntry entry = createNotification(IMPORTANCE_HIGH); - assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); - } - - /** - * If the device is dozing, we don't show as heads up. - */ - @Test - public void testShouldHeadsUp_false_dozing() throws RemoteException { - ensureStateForHeadsUpWhenAwake(); - when(mStatusBarStateController.isDozing()).thenReturn(true); - - NotificationEntry entry = createNotification(IMPORTANCE_HIGH); - assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); - } - - /** * If the notification is a bubble, and the user is not on AOD / lockscreen, then * the bubble is shown rather than the heads up. */ @Test - public void testShouldHeadsUp_false_bubble() throws RemoteException { + public void testShouldNotHeadsUp_bubble() throws RemoteException { ensureStateForHeadsUpWhenAwake(); // Bubble bit only applies to interruption when we're in the shade @@ -369,7 +309,7 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { * If we're not allowed to alert in general, we shouldn't be shown as heads up. */ @Test - public void testShouldHeadsUp_false_alertCommonFalse() throws RemoteException { + public void testShouldNotHeadsUp_filtered() throws RemoteException { ensureStateForHeadsUpWhenAwake(); // Make canAlertCommon false by saying it's filtered out when(mNotificationFilter.shouldFilterOut(any())).thenReturn(true); @@ -383,7 +323,7 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { * {@link android.app.NotificationManager.Policy#SUPPRESSED_EFFECT_PEEK}. */ @Test - public void testShouldHeadsUp_false_suppressPeek() throws RemoteException { + public void testShouldNotHeadsUp_suppressPeek() throws RemoteException { ensureStateForHeadsUpWhenAwake(); NotificationEntry entry = createNotification(IMPORTANCE_HIGH); @@ -399,7 +339,7 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { * to show as a heads up. */ @Test - public void testShouldHeadsUp_false_lessImportant() throws RemoteException { + public void testShouldNotHeadsUp_lessImportant() throws RemoteException { ensureStateForHeadsUpWhenAwake(); NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); @@ -410,7 +350,7 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { * If the device is not in use then we shouldn't be shown as heads up. */ @Test - public void testShouldHeadsUp_false_deviceNotInUse() throws RemoteException { + public void testShouldNotHeadsUp_deviceNotInUse() throws RemoteException { ensureStateForHeadsUpWhenAwake(); NotificationEntry entry = createNotification(IMPORTANCE_HIGH); @@ -424,61 +364,58 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); } - /** - * If something wants to suppress this heads up, then it shouldn't be shown as a heads up. - */ @Test - public void testShouldHeadsUp_false_suppressed() throws RemoteException { + public void testShouldNotHeadsUp_headsUpSuppressed() throws RemoteException { ensureStateForHeadsUpWhenAwake(); - when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(false); + + // If a suppressor is suppressing heads up, then it shouldn't be shown as a heads up. + mNotifInterruptionStateProvider.addSuppressor(mSuppressAwakeHeadsUp); NotificationEntry entry = createNotification(IMPORTANCE_HIGH); assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); - verify(mHeadsUpSuppressor).canHeadsUp(any(), any()); } - /** - * On screen alerts don't happen when the device is in VR Mode. - */ @Test - public void testCanAlertAwakeCommon__false_vrMode() { - ensureStateForAlertAwakeCommon(); - when(mPresenter.isDeviceInVrMode()).thenReturn(true); + public void testShouldNotHeadsUpAwake_awakeInterruptsSuppressed() throws RemoteException { + ensureStateForHeadsUpWhenAwake(); - NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); - assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse(); + // If a suppressor is suppressing heads up, then it shouldn't be shown as a heads up. + mNotifInterruptionStateProvider.addSuppressor(mSuppressAwakeInterruptions); + + NotificationEntry entry = createNotification(IMPORTANCE_HIGH); + assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); } /** * On screen alerts don't happen when the notification is snoozed. */ @Test - public void testCanAlertAwakeCommon_false_snoozedPackage() { + public void testShouldNotHeadsUp_snoozedPackage() { + NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); ensureStateForAlertAwakeCommon(); - when(mHeadsUpManager.isSnoozed(any())).thenReturn(true); - NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); - assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse(); + when(mHeadsUpManager.isSnoozed(entry.getSbn().getPackageName())).thenReturn(true); + + assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); } - /** - * On screen alerts don't happen when that package has just launched fullscreen. - */ + @Test - public void testCanAlertAwakeCommon_false_justLaunchedFullscreen() { + public void testShouldNotHeadsUp_justLaunchedFullscreen() { ensureStateForAlertAwakeCommon(); + // On screen alerts don't happen when that package has just launched fullscreen. NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT); entry.notifyFullScreenIntentLaunched(); - assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse(); + assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse(); } /** * Bubbles can happen. */ @Test - public void testShouldBubbleUp_true() { + public void testShouldBubbleUp() { ensureStateForBubbleUp(); assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(createBubble())).isTrue(); } @@ -487,7 +424,7 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { * If the notification doesn't have permission to bubble, it shouldn't bubble. */ @Test - public void shouldBubbleUp_false_notAllowedToBubble() { + public void shouldNotBubbleUp_notAllowedToBubble() { ensureStateForBubbleUp(); NotificationEntry entry = createBubble(); @@ -502,7 +439,7 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { * If the notification isn't a bubble, it should definitely not show as a bubble. */ @Test - public void shouldBubbleUp_false_notABubble() { + public void shouldNotBubbleUp_notABubble() { ensureStateForBubbleUp(); NotificationEntry entry = createNotification(IMPORTANCE_HIGH); @@ -517,7 +454,7 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { * If the notification doesn't have bubble metadata, it shouldn't bubble. */ @Test - public void shouldBubbleUp_false_invalidMetadata() { + public void shouldNotBubbleUp_invalidMetadata() { ensureStateForBubbleUp(); NotificationEntry entry = createNotification(IMPORTANCE_HIGH); @@ -529,24 +466,18 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(entry)).isFalse(); } - /** - * If the notification can't heads up in general, it shouldn't bubble. - */ @Test - public void shouldBubbleUp_false_alertAwakeCommonFalse() { + public void shouldNotBubbleUp_suppressedInterruptions() { ensureStateForBubbleUp(); - // Make alert common return false by pretending we're in VR mode - when(mPresenter.isDeviceInVrMode()).thenReturn(true); + // If the notification can't heads up in general, it shouldn't bubble. + mNotifInterruptionStateProvider.addSuppressor(mSuppressInterruptions); assertThat(mNotifInterruptionStateProvider.shouldBubbleUp(createBubble())).isFalse(); } - /** - * If the notification can't heads up in general, it shouldn't bubble. - */ @Test - public void shouldBubbleUp_false_alertCommonFalse() { + public void shouldNotBubbleUp_filteredOut() { ensureStateForBubbleUp(); // Make canAlertCommon false by saying it's filtered out @@ -592,20 +523,45 @@ public class NotificationInterruptionStateProviderTest extends SysuiTestCase { .build(); } - /** - * Testable class overriding constructor. - */ - public static class TestableNotificationInterruptionStateProvider extends - NotificationInterruptionStateProvider { - - TestableNotificationInterruptionStateProvider(Context context, - PowerManager powerManager, IDreamManager dreamManager, - AmbientDisplayConfiguration ambientDisplayConfiguration, - NotificationFilter notificationFilter, - StatusBarStateController statusBarStateController, - BatteryController batteryController) { - super(context, powerManager, dreamManager, ambientDisplayConfiguration, - notificationFilter, batteryController, statusBarStateController); + private final NotificationInterruptSuppressor + mSuppressAwakeHeadsUp = + new NotificationInterruptSuppressor() { + @Override + public String getName() { + return "suppressAwakeHeadsUp"; } - } + + @Override + public boolean suppressAwakeHeadsUp(NotificationEntry entry) { + return true; + } + }; + + private final NotificationInterruptSuppressor + mSuppressAwakeInterruptions = + new NotificationInterruptSuppressor() { + @Override + public String getName() { + return "suppressAwakeInterruptions"; + } + + @Override + public boolean suppressAwakeInterruptions(NotificationEntry entry) { + return true; + } + }; + + private final NotificationInterruptSuppressor + mSuppressInterruptions = + new NotificationInterruptSuppressor() { + @Override + public String getName() { + return "suppressInterruptions"; + } + + @Override + public boolean suppressInterruptions(NotificationEntry entry) { + return true; + } + }; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java index 5d0349dbbb60..a21a047d9a70 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationEntryManagerInflationTest.java @@ -56,12 +56,12 @@ import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationEntryManagerLogger; import com.android.systemui.statusbar.notification.NotificationFilter; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationRankingManager; import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; @@ -108,7 +108,7 @@ public class NotificationEntryManagerInflationTest extends SysuiTestCase { @Mock private NotificationEntryListener mEntryListener; @Mock private NotificationRowBinderImpl.BindRowCallback mBindCallback; @Mock private HeadsUpManager mHeadsUpManager; - @Mock private NotificationInterruptionStateProvider mNotificationInterruptionStateProvider; + @Mock private NotificationInterruptStateProvider mNotificationInterruptionStateProvider; @Mock private NotificationLockscreenUserManager mLockscreenUserManager; @Mock private NotificationGutsManager mGutsManager; @Mock private NotificationRemoteInputManager mRemoteInputManager; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index 1e4df272b02b..b9c5b7c02b1c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -67,10 +67,10 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.NotificationActivityStarter; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.collection.NotifCollection; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -183,7 +183,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mock(StatusBarRemoteInputCallback.class), mock(NotificationGroupManager.class), mock(NotificationLockscreenUserManager.class), mKeyguardStateController, - mock(NotificationInterruptionStateProvider.class), mock(MetricsLogger.class), + mock(NotificationInterruptStateProvider.class), mock(MetricsLogger.class), mock(LockPatternUtils.class), mHandler, mHandler, mUiBgExecutor, mActivityIntentHelper, mBubbleController, mShadeController, mFeatureFlags, mNotifPipeline, mNotifCollection) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java index b9d2d229cd69..318e9b87fa70 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java @@ -16,8 +16,9 @@ package com.android.systemui.statusbar.phone; import static android.view.Display.DEFAULT_DISPLAY; -import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Notification; @@ -35,6 +36,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.testing.FakeMetricsLogger; +import com.android.systemui.ForegroundServiceNotificationListener; import com.android.systemui.InitController; import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -48,12 +50,12 @@ import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.DynamicPrivacyController; -import com.android.systemui.statusbar.notification.NotificationAlertingManager; import com.android.systemui.statusbar.notification.NotificationEntryManager; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider; +import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; @@ -62,6 +64,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import java.util.ArrayList; @@ -72,6 +75,9 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { private StatusBarNotificationPresenter mStatusBarNotificationPresenter; + private NotificationInterruptStateProvider mNotificationInterruptStateProvider = + mock(NotificationInterruptStateProvider.class); + private NotificationInterruptSuppressor mInterruptSuppressor; private CommandQueue mCommandQueue; private FakeMetricsLogger mMetricsLogger; private ShadeController mShadeController = mock(ShadeController.class); @@ -95,11 +101,11 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { mDependency.injectMockDependency(NotificationViewHierarchyManager.class); mDependency.injectMockDependency(NotificationRemoteInputManager.Callback.class); mDependency.injectMockDependency(NotificationLockscreenUserManager.class); - mDependency.injectMockDependency(NotificationInterruptionStateProvider.class); mDependency.injectMockDependency(NotificationMediaManager.class); mDependency.injectMockDependency(VisualStabilityManager.class); mDependency.injectMockDependency(NotificationGutsManager.class); mDependency.injectMockDependency(NotificationShadeWindowController.class); + mDependency.injectMockDependency(ForegroundServiceNotificationListener.class); NotificationEntryManager entryManager = mDependency.injectMockDependency(NotificationEntryManager.class); when(entryManager.getActiveNotificationsForCurrentUser()).thenReturn(new ArrayList<>()); @@ -107,18 +113,25 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { NotificationShadeWindowView notificationShadeWindowView = mock(NotificationShadeWindowView.class); when(notificationShadeWindowView.getResources()).thenReturn(mContext.getResources()); + mStatusBarNotificationPresenter = new StatusBarNotificationPresenter(mContext, mock(NotificationPanelViewController.class), mock(HeadsUpManagerPhone.class), notificationShadeWindowView, mock(NotificationListContainerViewGroup.class), mock(DozeScrimController.class), mock(ScrimController.class), mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class), - mock(NotificationAlertingManager.class), mock(KeyguardStateController.class), + mock(KeyguardStateController.class), mock(KeyguardIndicationController.class), mStatusBar, - mock(ShadeControllerImpl.class), mCommandQueue, mInitController); + mock(ShadeControllerImpl.class), mCommandQueue, mInitController, + mNotificationInterruptStateProvider); + mInitController.executePostInitTasks(); + ArgumentCaptor<NotificationInterruptSuppressor> suppressorCaptor = + ArgumentCaptor.forClass(NotificationInterruptSuppressor.class); + verify(mNotificationInterruptStateProvider).addSuppressor(suppressorCaptor.capture()); + mInterruptSuppressor = suppressorCaptor.getValue(); } @Test - public void testHeadsUp_disabledStatusBar() { + public void testSuppressHeadsUp_disabledStatusBar() { Notification n = new Notification.Builder(getContext(), "a").build(); NotificationEntry entry = new NotificationEntryBuilder() .setPkg("a") @@ -130,12 +143,12 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { false /* animate */); TestableLooper.get(this).processAllMessages(); - assertFalse("The panel shouldn't allow heads up while disabled", - mStatusBarNotificationPresenter.canHeadsUp(entry, entry.getSbn())); + assertTrue("The panel should suppress heads up while disabled", + mInterruptSuppressor.suppressAwakeHeadsUp(entry)); } @Test - public void testHeadsUp_disabledNotificationShade() { + public void testSuppressHeadsUp_disabledNotificationShade() { Notification n = new Notification.Builder(getContext(), "a").build(); NotificationEntry entry = new NotificationEntryBuilder() .setPkg("a") @@ -147,8 +160,39 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { false /* animate */); TestableLooper.get(this).processAllMessages(); - assertFalse("The panel shouldn't allow heads up while notitifcation shade disabled", - mStatusBarNotificationPresenter.canHeadsUp(entry, entry.getSbn())); + assertTrue("The panel should suppress interruptions while notification shade " + + "disabled", + mInterruptSuppressor.suppressAwakeHeadsUp(entry)); + } + + @Test + public void testSuppressInterruptions_vrMode() { + Notification n = new Notification.Builder(getContext(), "a").build(); + NotificationEntry entry = new NotificationEntryBuilder() + .setPkg("a") + .setOpPkg("a") + .setTag("a") + .setNotification(n) + .build(); + mStatusBarNotificationPresenter.mVrMode = true; + + assertTrue("Vr mode should suppress interruptions", + mInterruptSuppressor.suppressAwakeInterruptions(entry)); + } + + @Test + public void testSuppressInterruptions_statusBarAlertsDisabled() { + Notification n = new Notification.Builder(getContext(), "a").build(); + NotificationEntry entry = new NotificationEntryBuilder() + .setPkg("a") + .setOpPkg("a") + .setTag("a") + .setNotification(n) + .build(); + when(mStatusBar.areNotificationAlertsDisabled()).thenReturn(true); + + assertTrue("StatusBar alerts disabled shouldn't allow interruptions", + mInterruptSuppressor.suppressInterruptions(entry)); } @Test @@ -172,4 +216,3 @@ public class StatusBarNotificationPresenterTest extends SysuiTestCase { } } } - 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 0d7734e13621..d9f4d4b8f758 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 @@ -42,7 +42,7 @@ import android.app.Notification; import android.app.StatusBarManager; import android.app.trust.TrustManager; import android.content.BroadcastReceiver; -import android.content.Context; +import android.content.ContentResolver; import android.content.IntentFilter; import android.hardware.display.AmbientDisplayConfiguration; import android.hardware.fingerprint.FingerprintManager; @@ -109,18 +109,17 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.StatusBarStateControllerImpl; import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.VibratorHelper; -import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier; import com.android.systemui.statusbar.notification.DynamicPrivacyController; -import com.android.systemui.statusbar.notification.NotificationAlertingManager; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationFilter; -import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.VisualStabilityManager; 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.NotificationInterruptStateProviderImpl; import com.android.systemui.statusbar.notification.logging.NotificationLogger; import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; @@ -129,6 +128,7 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import com.android.systemui.statusbar.policy.ExtensionController; +import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.KeyguardStateController; import com.android.systemui.statusbar.policy.NetworkController; import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; @@ -160,7 +160,7 @@ public class StatusBarTest extends SysuiTestCase { private StatusBar mStatusBar; private FakeMetricsLogger mMetricsLogger; private PowerManager mPowerManager; - private TestableNotificationInterruptionStateProvider mNotificationInterruptionStateProvider; + private TestableNotificationInterruptStateProviderImpl mNotificationInterruptStateProvider; @Mock private NotificationsController mNotificationsController; @Mock private LightBarController mLightBarController; @@ -178,7 +178,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private DozeScrimController mDozeScrimController; @Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy; @Mock private BiometricUnlockController mBiometricUnlockController; - @Mock private NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor; @Mock private VisualStabilityManager mVisualStabilityManager; @Mock private NotificationListener mNotificationListener; @Mock private KeyguardViewMediator mKeyguardViewMediator; @@ -191,10 +190,9 @@ 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; - @Mock private AmbientDisplayConfiguration mAmbientDisplayConfiguration; @Mock private NotificationShadeWindowView mNotificationShadeWindowView; @Mock private BroadcastDispatcher mBroadcastDispatcher; @Mock private AssistManager mAssistManager; @@ -262,10 +260,12 @@ public class StatusBarTest extends SysuiTestCase { mPowerManager = new PowerManager(mContext, powerManagerService, thermalService, Handler.createAsync(Looper.myLooper())); - mNotificationInterruptionStateProvider = - new TestableNotificationInterruptionStateProvider(mContext, mPowerManager, + mNotificationInterruptStateProvider = + new TestableNotificationInterruptStateProviderImpl(mContext.getContentResolver(), + mPowerManager, mDreamManager, mAmbientDisplayConfiguration, mNotificationFilter, - mStatusBarStateController, mBatteryController); + mStatusBarStateController, mBatteryController, mHeadsUpManager, + new Handler(TestableLooper.get(this).getLooper())); mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class)); mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class)); @@ -298,9 +298,6 @@ public class StatusBarTest extends SysuiTestCase { return null; }).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any()); - mNotificationInterruptionStateProvider.setUpWithPresenter(mNotificationPresenter, - mHeadsUpManager, mHeadsUpSuppressor); - when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController); WakefulnessLifecycle wakefulnessLifecycle = new WakefulnessLifecycle(); @@ -347,10 +344,9 @@ public class StatusBarTest extends SysuiTestCase { ), mNotificationGutsManager, notificationLogger, - mNotificationInterruptionStateProvider, + mNotificationInterruptStateProvider, mNotificationViewHierarchyManager, mKeyguardViewMediator, - mNotificationAlertingManager, new DisplayMetrics(), mMetricsLogger, mUiBgExecutor, @@ -561,7 +557,6 @@ public class StatusBarTest extends SysuiTestCase { when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false); when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false); when(mDreamManager.isDreaming()).thenReturn(false); - when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true); Notification n = new Notification.Builder(getContext(), "a") .setGroup("a") @@ -577,7 +572,7 @@ public class StatusBarTest extends SysuiTestCase { .setImportance(IMPORTANCE_HIGH) .build(); - assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry)); + assertTrue(mNotificationInterruptStateProvider.shouldHeadsUp(entry)); } @Test @@ -586,7 +581,6 @@ public class StatusBarTest extends SysuiTestCase { when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false); when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false); when(mDreamManager.isDreaming()).thenReturn(false); - when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true); Notification n = new Notification.Builder(getContext(), "a") .setGroup("a") @@ -602,7 +596,7 @@ public class StatusBarTest extends SysuiTestCase { .setImportance(IMPORTANCE_HIGH) .build(); - assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry)); + assertFalse(mNotificationInterruptStateProvider.shouldHeadsUp(entry)); } @Test @@ -611,7 +605,6 @@ public class StatusBarTest extends SysuiTestCase { when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false); when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false); when(mDreamManager.isDreaming()).thenReturn(false); - when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true); Notification n = new Notification.Builder(getContext(), "a").build(); @@ -624,7 +617,7 @@ public class StatusBarTest extends SysuiTestCase { .setSuppressedVisualEffects(SUPPRESSED_EFFECT_PEEK) .build(); - assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry)); + assertFalse(mNotificationInterruptStateProvider.shouldHeadsUp(entry)); } @Test @@ -633,7 +626,6 @@ public class StatusBarTest extends SysuiTestCase { when(mHeadsUpManager.isSnoozed(anyString())).thenReturn(false); when(mNotificationFilter.shouldFilterOut(any())).thenReturn(false); when(mDreamManager.isDreaming()).thenReturn(false); - when(mHeadsUpSuppressor.canHeadsUp(any(), any())).thenReturn(true); Notification n = new Notification.Builder(getContext(), "a").build(); @@ -645,7 +637,7 @@ public class StatusBarTest extends SysuiTestCase { .setImportance(IMPORTANCE_HIGH) .build(); - assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry)); + assertTrue(mNotificationInterruptStateProvider.shouldHeadsUp(entry)); } @Test @@ -871,19 +863,21 @@ public class StatusBarTest extends SysuiTestCase { verify(mDozeServiceHost).setDozeSuppressed(false); } - public static class TestableNotificationInterruptionStateProvider extends - NotificationInterruptionStateProvider { + public static class TestableNotificationInterruptStateProviderImpl extends + NotificationInterruptStateProviderImpl { - TestableNotificationInterruptionStateProvider( - Context context, + TestableNotificationInterruptStateProviderImpl( + ContentResolver contentResolver, PowerManager powerManager, IDreamManager dreamManager, AmbientDisplayConfiguration ambientDisplayConfiguration, NotificationFilter filter, StatusBarStateController controller, - BatteryController batteryController) { - super(context, powerManager, dreamManager, ambientDisplayConfiguration, filter, - batteryController, controller); + BatteryController batteryController, + HeadsUpManager headsUpManager, + Handler mainHandler) { + super(contentResolver, powerManager, dreamManager, ambientDisplayConfiguration, filter, + batteryController, controller, headsUpManager, mainHandler); mUseHeadsUp = true; } } |