Create interface for NotifInterruptStateProvider

Take #2
Original CL disabled HUNs because NotificationAlertingManager was
removed from the StatusBar constructor (but never injected elsewhere;
therefore it was never instantiated).

bcb499478af43fa6bd7626da45f5ba937e8abf2e

Test: atest SystemUITests
Bug: 151050224
Bug: 150797570
Change-Id: I601d58bfff4422bd0c52e56ebdb4192ce9a8f880
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index 6f985a4..22c3acf 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -24,7 +24,6 @@
 import com.android.keyguard.KeyguardViewController;
 import com.android.systemui.car.CarDeviceProvisionedController;
 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;
@@ -41,7 +40,6 @@
 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;
@@ -65,10 +63,6 @@
 @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 447e579..0000000
--- 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 b2e2104..411f14d 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -95,13 +95,15 @@
 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.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.phone.AutoHideController;
@@ -249,7 +251,7 @@
             RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
             NotificationGutsManager notificationGutsManager,
             NotificationLogger notificationLogger,
-            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+            NotificationInterruptStateProvider notificationInterruptStateProvider,
             NotificationViewHierarchyManager notificationViewHierarchyManager,
             KeyguardViewMediator keyguardViewMediator,
             NotificationAlertingManager notificationAlertingManager,
@@ -335,7 +337,7 @@
                 remoteInputQuickSettingsDisabler,
                 notificationGutsManager,
                 notificationLogger,
-                notificationInterruptionStateProvider,
+                notificationInterruptStateProvider,
                 notificationViewHierarchyManager,
                 keyguardViewMediator,
                 notificationAlertingManager,
@@ -488,6 +490,22 @@
                                 .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 4754118..160268b 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -62,13 +62,13 @@
 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.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.notification.row.NotificationRowModule;
@@ -146,7 +146,7 @@
             RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
             NotificationGutsManager notificationGutsManager,
             NotificationLogger notificationLogger,
-            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+            NotificationInterruptStateProvider notificationInterruptionStateProvider,
             NotificationViewHierarchyManager notificationViewHierarchyManager,
             KeyguardViewMediator keyguardViewMediator,
             NotificationAlertingManager notificationAlertingManager,
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index a868cf5..b6152da 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.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 @@
     @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 @@
         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 22c2c7e..77aea427 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.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 @@
     // 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 @@
             ShadeController shadeController,
             BubbleData data,
             ConfigurationController configurationController,
-            NotificationInterruptionStateProvider interruptionStateProvider,
+            NotificationInterruptStateProvider interruptionStateProvider,
             ZenModeController zenModeController,
             NotificationLockscreenUserManager notifUserManager,
             NotificationGroupManager groupManager,
@@ -304,7 +304,7 @@
             BubbleData data,
             @Nullable BubbleStackView.SurfaceSynchronizer synchronizer,
             ConfigurationController configurationController,
-            NotificationInterruptionStateProvider interruptionStateProvider,
+            NotificationInterruptStateProvider interruptionStateProvider,
             ZenModeController zenModeController,
             NotificationLockscreenUserManager notifUserManager,
             NotificationGroupManager groupManager,
@@ -316,7 +316,7 @@
         dumpManager.registerDumpable(TAG, this);
         mContext = context;
         mShadeController = shadeController;
-        mNotificationInterruptionStateProvider = interruptionStateProvider;
+        mNotificationInterruptStateProvider = interruptionStateProvider;
         mNotifUserManager = notifUserManager;
         mZenModeController = zenModeController;
         mFloatingContentCoordinator = floatingContentCoordinator;
@@ -632,7 +632,7 @@
         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 @@
         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 @@
         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 ac97d8a..27c9e98 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.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 @@
             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 6c502d2..3a4b273 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 @@
 
     /** */
     @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 8a23e37..2747696 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.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 @@
 
 @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 @@
             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 @@
         }
 
     private var collapsedEnoughToHide: Boolean = false
-    lateinit var iconAreaController : NotificationIconAreaController
+    lateinit var iconAreaController: NotificationIconAreaController
 
     var pulsing: Boolean = false
         set(value) {
@@ -132,8 +130,8 @@
             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 @@
         }
 
     init {
-        mHeadsUpManagerPhone.addListener(this)
+        mHeadsUpManager.addListener(this)
         statusBarStateController.addCallback(this)
         addListener(object : WakeUpListener {
             override fun onFullyHiddenChanged(isFullyHidden: Boolean) {
@@ -155,7 +153,7 @@
                             increaseSpeed = false)
                 }
             }
-        });
+        })
     }
 
     fun setStackScroller(stackScroller: NotificationStackScrollLayout) {
@@ -178,46 +176,55 @@
      * @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 @@
         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 @@
         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 @@
     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 @@
         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 @@
         mLinearVisibilityAmount = visibilityAmount
         mVisibilityAmount = mVisibilityInterpolator.getInterpolation(
                 visibilityAmount)
-        handleAnimationFinished();
+        handleAnimationFinished()
         updateHideAmount()
     }
 
@@ -322,7 +329,7 @@
         }
     }
 
-    fun getWakeUpHeight() : Float {
+    fun getWakeUpHeight(): Float {
         return mStackScroller.wakeUpHeight
     }
 
@@ -330,7 +337,7 @@
         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 @@
                     // 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 e8a62e4..4beeede 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.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 @@
 
     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 @@
             StatusBarStateController statusBarStateController,
             NotificationGroupManager notificationGroupManager,
             NotificationGutsManager notificationGutsManager,
-            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+            NotificationInterruptStateProvider notificationInterruptionStateProvider,
             Provider<RowInflaterTask> rowInflaterTaskProvider,
             ExpandableNotificationRowComponent.Builder expandableNotificationRowComponentBuilder) {
         mContext = context;
@@ -106,7 +106,7 @@
         mMessagingUtil = notificationMessagingUtil;
         mNotificationRemoteInputManager = notificationRemoteInputManager;
         mNotificationLockscreenUserManager = notificationLockscreenUserManager;
-        mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+        mNotificationInterruptStateProvider = notificationInterruptionStateProvider;
         mRowInflaterTaskProvider = rowInflaterTaskProvider;
         mExpandableNotificationRowComponentBuilder = expandableNotificationRowComponentBuilder;
     }
@@ -243,7 +243,7 @@
         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 3c0ac7e..cd6affd 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
@@ -31,10 +31,8 @@
 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;
@@ -44,6 +42,9 @@
 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;
@@ -56,6 +57,7 @@
 
 import javax.inject.Singleton;
 
+import dagger.Binds;
 import dagger.Lazy;
 import dagger.Module;
 import dagger.Provides;
@@ -125,7 +127,7 @@
             NotificationRemoteInputManager remoteInputManager,
             VisualStabilityManager visualStabilityManager,
             StatusBarStateController statusBarStateController,
-            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+            NotificationInterruptStateProvider notificationInterruptStateProvider,
             NotificationListener notificationListener,
             HeadsUpManager headsUpManager) {
         return new NotificationAlertingManager(
@@ -133,7 +135,7 @@
                 remoteInputManager,
                 visualStabilityManager,
                 statusBarStateController,
-                notificationInterruptionStateProvider,
+                notificationInterruptStateProvider,
                 notificationListener,
                 headsUpManager);
     }
@@ -199,4 +201,9 @@
             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
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/BypassHeadsUpNotifier.kt
index 269a7a5..88888d1 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.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
similarity index 90%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationAlertingManager.java
index df21f0b..b572502 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.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 @@
     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 @@
             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 @@
         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 @@
     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 0000000..3292a8f
--- /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
similarity index 63%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index bbf2dde..46d5044 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 @@
  * 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 @@
         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 @@
         }
     }
 
+    /**
+     * 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 @@
             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 @@
             }
             return false;
         }
-         return true;
+        return true;
     }
 
     /**
@@ -334,8 +309,7 @@
      * @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 @@
             }
             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 @@
      * @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 @@
     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 0000000..c19f8bd
--- /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 b3a62d8..e6f24c2 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,15 @@
 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.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -404,10 +404,9 @@
 
     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 +620,10 @@
             RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
             NotificationGutsManager notificationGutsManager,
             NotificationLogger notificationLogger,
-            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+            NotificationInterruptStateProvider notificationInterruptStateProvider,
             NotificationViewHierarchyManager notificationViewHierarchyManager,
             KeyguardViewMediator keyguardViewMediator,
-            NotificationAlertingManager notificationAlertingManager,
+            NotificationAlertingManager notificationAlertingManager, // need to inject for now
             DisplayMetrics displayMetrics,
             MetricsLogger metricsLogger,
             @UiBackground Executor uiBgExecutor,
@@ -701,10 +700,9 @@
         mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
         mGutsManager = notificationGutsManager;
         mNotificationLogger = notificationLogger;
-        mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+        mNotificationInterruptStateProvider = notificationInterruptStateProvider;
         mViewHierarchyManager = notificationViewHierarchyManager;
         mKeyguardViewMediator = keyguardViewMediator;
-        mNotificationAlertingManager = notificationAlertingManager;
         mDisplayMetrics = displayMetrics;
         mMetricsLogger = metricsLogger;
         mUiBgExecutor = uiBgExecutor;
@@ -1238,9 +1236,9 @@
         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 +1587,9 @@
         }
 
         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 +1604,10 @@
         }
     }
 
+    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 e1a20b6..53fa263 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.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 @@
     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 @@
             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 @@
         mActivityStarter = activityStarter;
         mEntryManager = entryManager;
         mStatusBarStateController = statusBarStateController;
-        mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+        mNotificationInterruptStateProvider = notificationInterruptStateProvider;
         mMetricsLogger = metricsLogger;
         mAssistManagerLazy = assistManagerLazy;
         mGroupManager = groupManager;
@@ -436,7 +436,7 @@
     }
 
     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 @@
         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 @@
                 NotificationGroupManager groupManager,
                 NotificationLockscreenUserManager lockscreenUserManager,
                 KeyguardStateController keyguardStateController,
-                NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+                NotificationInterruptStateProvider notificationInterruptStateProvider,
                 MetricsLogger metricsLogger,
                 LockPatternUtils lockPatternUtils,
                 @Main Handler mainThreadHandler,
@@ -654,7 +654,7 @@
             mGroupManager = groupManager;
             mLockscreenUserManager = lockscreenUserManager;
             mKeyguardStateController = keyguardStateController;
-            mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
+            mNotificationInterruptStateProvider = notificationInterruptStateProvider;
             mMetricsLogger = metricsLogger;
             mLockPatternUtils = lockPatternUtils;
             mMainThreadHandler = mainThreadHandler;
@@ -712,7 +712,7 @@
                     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 30d6b507..79cea91 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.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 @@
             (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 @@
             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 @@
             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 @@
         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 @@
             }
         }
     };
+
+    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 eec8d50..bbc7e7a 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,13 @@
 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.NotificationAlertingManager;
+import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
 import com.android.systemui.statusbar.notification.logging.NotificationLogger;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.phone.AutoHideController;
@@ -139,7 +139,7 @@
             RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
             NotificationGutsManager notificationGutsManager,
             NotificationLogger notificationLogger,
-            NotificationInterruptionStateProvider notificationInterruptionStateProvider,
+            NotificationInterruptStateProvider notificationInterruptStateProvider,
             NotificationViewHierarchyManager notificationViewHierarchyManager,
             KeyguardViewMediator keyguardViewMediator,
             NotificationAlertingManager notificationAlertingManager,
@@ -218,7 +218,7 @@
                 remoteInputQuickSettingsDisabler,
                 notificationGutsManager,
                 notificationLogger,
-                notificationInterruptionStateProvider,
+                notificationInterruptStateProvider,
                 notificationViewHierarchyManager,
                 keyguardViewMediator,
                 notificationAlertingManager,
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 78160c4..6e612d7 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.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.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 @@
         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 5ef4cd2..6244644 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.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.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;
@@ -212,15 +214,17 @@
         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 de1fb41..d3d90c4 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.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 @@
             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 0000000..17dc76b
--- /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 5d192b2..0000000
--- 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
similarity index 63%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInterruptionStateProviderTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index 1693e7f..f9c62e1 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 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.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 @@
  */
 @RunWith(AndroidTestingRunner.class)
 @SmallTest
-public class NotificationInterruptionStateProviderTest extends SysuiTestCase {
+public class NotificationInterruptStateProviderImplTest extends SysuiTestCase {
 
     @Mock
     PowerManager mPowerManager;
@@ -81,38 +79,36 @@
     @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 @@
 
     /**
      * 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 @@
         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 @@
 
     /**
      * 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 @@
         ensureStateForAlertAwakeCommon();
     }
 
-    /**
-     * Ensure that the disabled state is set correctly.
-     */
     @Test
-    public void testDisableNotificationAlerts() {
-        // Enabled by default
-        assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isFalse();
-
-        // Disable alerts
-        mNotifInterruptionStateProvider.setDisableNotificationAlerts(true);
-        assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).isTrue();
-
-        // Enable alerts
-        mNotifInterruptionStateProvider.setDisableNotificationAlerts(false);
-        assertThat(mNotifInterruptionStateProvider.areNotificationAlertsDisabled()).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);
-
-        // No more HUNs
-        assertThat(mNotifInterruptionStateProvider.getUseHeadsUp()).isFalse();
-    }
-
-    /**
-     * Alerts can happen.
-     */
-    @Test
-    public void testCanAlertCommon_true() {
-        ensureStateForAlertCommon();
+    public void testDefaultSuppressorDoesNotSuppress() {
+        // GIVEN a suppressor without any overrides
+        final NotificationInterruptSuppressor defaultSuppressor =
+                new NotificationInterruptSuppressor() {
+                    @Override
+                    public String getName() {
+                        return "defaultSuppressor";
+                    }
+                };
 
         NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
-        assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isTrue();
+
+        // THEN this suppressor doesn't suppress anything by default
+        assertThat(defaultSuppressor.suppressAwakeHeadsUp(entry)).isFalse();
+        assertThat(defaultSuppressor.suppressAwakeInterruptions(entry)).isFalse();
+        assertThat(defaultSuppressor.suppressInterruptions(entry)).isFalse();
     }
 
-    /**
-     * Filtered out notifications don't alert.
-     */
     @Test
-    public void testCanAlertCommon_false_filteredOut() {
-        ensureStateForAlertCommon();
-        when(mNotificationFilter.shouldFilterOut(any())).thenReturn(true);
+    public void testShouldHeadsUpAwake() throws RemoteException {
+        ensureStateForHeadsUpWhenAwake();
 
-        NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
-        assertThat(mNotifInterruptionStateProvider.canAlertCommon(entry)).isFalse();
+        NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
     }
 
-    /**
-     * 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 testShouldNotHeadsUpAwake_flteredOut() throws RemoteException {
+        // GIVEN state for "heads up when awake" is true
+        ensureStateForHeadsUpWhenAwake();
 
+        // WHEN this entry should be filtered out
+        NotificationEntry entry  = createNotification(IMPORTANCE_DEFAULT);
+        when(mNotificationFilter.shouldFilterOut(entry)).thenReturn(true);
+
+        // THEN we shouldn't heads up this entry
+        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+    }
+
+    @Test
+    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 @@
                 .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 @@
      * {@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 @@
         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 @@
     }
 
     /**
-     * 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 @@
      * 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 @@
      * {@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 @@
      * 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 @@
      * 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 @@
         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() {
-        ensureStateForAlertAwakeCommon();
-        when(mHeadsUpManager.isSnoozed(any())).thenReturn(true);
-
+    public void testShouldNotHeadsUp_snoozedPackage() {
         NotificationEntry entry = createNotification(IMPORTANCE_DEFAULT);
-        assertThat(mNotifInterruptionStateProvider.canAlertAwakeCommon(entry)).isFalse();
+        ensureStateForAlertAwakeCommon();
+
+        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 @@
      * 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 @@
      * 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 @@
      * 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 @@
         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 @@
                 .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 5d0349d..a21a047 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.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 @@
     @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 1e4df27..b9c5b7c 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.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 @@
                 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 b9d2d22..318e9b8 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 @@
 
 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 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.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 org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 
 import java.util.ArrayList;
 
@@ -72,6 +75,9 @@
 
 
     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 @@
         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 @@
         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 @@
                 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 @@
                 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 @@
         }
     }
 }
-
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 0d7734e..ccd2357 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.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,18 @@
 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.NotificationAlertingManager;
+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 +129,7 @@
 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 +161,7 @@
     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 +179,6 @@
     @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;
@@ -192,9 +192,9 @@
     @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 +262,12 @@
         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 +300,6 @@
             return null;
         }).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
 
-        mNotificationInterruptionStateProvider.setUpWithPresenter(mNotificationPresenter,
-                mHeadsUpManager, mHeadsUpSuppressor);
-
         when(mRemoteInputManager.getController()).thenReturn(mRemoteInputController);
 
         WakefulnessLifecycle wakefulnessLifecycle = new WakefulnessLifecycle();
@@ -347,7 +346,7 @@
                 ),
                 mNotificationGutsManager,
                 notificationLogger,
-                mNotificationInterruptionStateProvider,
+                mNotificationInterruptStateProvider,
                 mNotificationViewHierarchyManager,
                 mKeyguardViewMediator,
                 mNotificationAlertingManager,
@@ -561,7 +560,6 @@
         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 +575,7 @@
                 .setImportance(IMPORTANCE_HIGH)
                 .build();
 
-        assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
+        assertTrue(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
     }
 
     @Test
@@ -586,7 +584,6 @@
         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 +599,7 @@
                 .setImportance(IMPORTANCE_HIGH)
                 .build();
 
-        assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
+        assertFalse(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
     }
 
     @Test
@@ -611,7 +608,6 @@
         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 +620,7 @@
                 .setSuppressedVisualEffects(SUPPRESSED_EFFECT_PEEK)
                 .build();
 
-        assertFalse(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
+        assertFalse(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
     }
 
     @Test
@@ -633,7 +629,6 @@
         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 +640,7 @@
                 .setImportance(IMPORTANCE_HIGH)
                 .build();
 
-        assertTrue(mNotificationInterruptionStateProvider.shouldHeadsUp(entry));
+        assertTrue(mNotificationInterruptStateProvider.shouldHeadsUp(entry));
     }
 
     @Test
@@ -871,19 +866,21 @@
         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;
         }
     }