Merge "Modernize LightsOutNotifController" into main
diff --git a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
index 83c16ae..6a0e882 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/FlagDependencies.kt
@@ -19,6 +19,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
 import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor
+import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
 import javax.inject.Inject
 
 /** A class in which engineers can define flag dependencies */
@@ -26,6 +27,7 @@
 class FlagDependencies @Inject constructor(featureFlags: FeatureFlagsClassic, handler: Handler) :
     FlagDependenciesBase(featureFlags, handler) {
     override fun defineDependencies() {
+        NotificationsLiveDataStoreRefactor.token dependsOn NotificationIconContainerRefactor.token
         FooterViewRefactor.token dependsOn NotificationIconContainerRefactor.token
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/model/StatusBarMode.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/model/StatusBarMode.kt
index 747efe3..933d0ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/model/StatusBarMode.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/model/StatusBarMode.kt
@@ -36,7 +36,8 @@
     /**
      * A mode where notification icons in the status bar are hidden and replaced by a dot (this mode
      * can be requested by apps). See
-     * [com.android.systemui.statusbar.phone.LightsOutNotifController].
+     * [com.android.systemui.statusbar.phone.LegacyLightsOutNotifController] and
+     * [com.android.systemui.statusbar.phone.domain.interactor.LightsOutInteractor].
      */
     LIGHTS_OUT,
     /** Similar to [LIGHTS_OUT], but also with a transparent background for the status bar. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepository.kt
index d1594ef..0415212 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/KeyguardStatusBarRepository.kt
@@ -33,7 +33,7 @@
 
 /**
  * Repository for data that's specific to the status bar **on keyguard**. For data that applies to
- * all status bars, use [StatusBarModeRepository].
+ * all status bars, use [StatusBarModeRepositoryStore].
  */
 interface KeyguardStatusBarRepository {
     /** True if we can show the user switcher on keyguard and false otherwise. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
similarity index 92%
rename from packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepository.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
index 47994d9..6429815 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModePerDisplayRepository.kt
@@ -25,10 +25,8 @@
 import android.view.WindowInsetsController.Appearance
 import com.android.internal.statusbar.LetterboxDetails
 import com.android.internal.view.AppearanceRegion
-import com.android.systemui.CoreStartable
-import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.Dumpable
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.DisplayId
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.core.StatusBarInitializer.OnStatusBarViewInitializedListener
 import com.android.systemui.statusbar.data.model.StatusBarAppearance
@@ -38,13 +36,10 @@
 import com.android.systemui.statusbar.phone.StatusBarBoundsProvider
 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent
 import com.android.systemui.statusbar.phone.ongoingcall.data.repository.OngoingCallRepository
-import dagger.Binds
-import dagger.Module
-import dagger.multibindings.ClassKey
-import dagger.multibindings.IntoMap
-import dagger.multibindings.IntoSet
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
 import java.io.PrintWriter
-import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
@@ -61,7 +56,7 @@
  * Note: These status bar modes are status bar *window* states that are sent to us from
  * WindowManager, not determined internally.
  */
-interface StatusBarModeRepository {
+interface StatusBarModePerDisplayRepository {
     /**
      * True if the status bar window is showing transiently and will disappear soon, and false
      * otherwise. ("Otherwise" in this case means the status bar is persistently hidden OR
@@ -108,16 +103,15 @@
     fun clearTransient()
 }
 
-@SysUISingleton
-class StatusBarModeRepositoryImpl
-@Inject
+class StatusBarModePerDisplayRepositoryImpl
+@AssistedInject
 constructor(
     @Application scope: CoroutineScope,
-    @DisplayId thisDisplayId: Int,
+    @Assisted("displayId") thisDisplayId: Int,
     private val commandQueue: CommandQueue,
     private val letterboxAppearanceCalculator: LetterboxAppearanceCalculator,
     ongoingCallRepository: OngoingCallRepository,
-) : StatusBarModeRepository, CoreStartable, OnStatusBarViewInitializedListener {
+) : StatusBarModePerDisplayRepository, OnStatusBarViewInitializedListener, Dumpable {
 
     private val commandQueueCallback =
         object : CommandQueue.Callbacks {
@@ -166,7 +160,7 @@
             }
         }
 
-    override fun start() {
+    fun start() {
         commandQueue.addCallback(commandQueueCallback)
     }
 
@@ -340,16 +334,7 @@
     )
 }
 
-@Module
-interface StatusBarModeRepositoryModule {
-    @Binds fun bindImpl(impl: StatusBarModeRepositoryImpl): StatusBarModeRepository
-
-    @Binds
-    @IntoMap
-    @ClassKey(StatusBarModeRepositoryImpl::class)
-    fun bindCoreStartable(impl: StatusBarModeRepositoryImpl): CoreStartable
-
-    @Binds
-    @IntoSet
-    fun bindViewInitListener(impl: StatusBarModeRepositoryImpl): OnStatusBarViewInitializedListener
+@AssistedFactory
+interface StatusBarModePerDisplayRepositoryFactory {
+    fun create(@Assisted("displayId") displayId: Int): StatusBarModePerDisplayRepositoryImpl
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt
new file mode 100644
index 0000000..962cb095
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.data.repository
+
+import com.android.systemui.CoreStartable
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.DisplayId
+import com.android.systemui.statusbar.core.StatusBarInitializer
+import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentComponent
+import dagger.Binds
+import dagger.Module
+import dagger.multibindings.ClassKey
+import dagger.multibindings.IntoMap
+import dagger.multibindings.IntoSet
+import java.io.PrintWriter
+import javax.inject.Inject
+
+interface StatusBarModeRepositoryStore {
+    val defaultDisplay: StatusBarModePerDisplayRepository
+    fun forDisplay(displayId: Int): StatusBarModePerDisplayRepository
+}
+
+@SysUISingleton
+class StatusBarModeRepositoryImpl
+@Inject
+constructor(
+    @DisplayId private val displayId: Int,
+    factory: StatusBarModePerDisplayRepositoryFactory
+) :
+    StatusBarModeRepositoryStore,
+    CoreStartable,
+    StatusBarInitializer.OnStatusBarViewInitializedListener {
+    override val defaultDisplay = factory.create(displayId)
+
+    override fun forDisplay(displayId: Int) =
+        if (this.displayId == displayId) {
+            defaultDisplay
+        } else {
+            TODO("b/127878649 implement multi-display state management")
+        }
+
+    override fun start() {
+        defaultDisplay.start()
+    }
+
+    override fun onStatusBarViewInitialized(component: StatusBarFragmentComponent) {
+        defaultDisplay.onStatusBarViewInitialized(component)
+    }
+
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
+        defaultDisplay.dump(pw, args)
+    }
+}
+
+@Module
+interface StatusBarModeRepositoryModule {
+    @Binds fun bindImpl(impl: StatusBarModeRepositoryImpl): StatusBarModeRepositoryStore
+
+    @Binds
+    @IntoMap
+    @ClassKey(StatusBarModeRepositoryStore::class)
+    fun bindCoreStartable(impl: StatusBarModeRepositoryImpl): CoreStartable
+
+    @Binds
+    @IntoSet
+    fun bindViewInitListener(
+        impl: StatusBarModeRepositoryImpl
+    ): StatusBarInitializer.OnStatusBarViewInitializedListener
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataRefactor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataStoreRefactor.kt
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataRefactor.kt
rename to packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataStoreRefactor.kt
index 44387c2..8fc7106 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataRefactor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationsLiveDataStoreRefactor.kt
@@ -50,4 +50,4 @@
      */
     @JvmStatic
     inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 645769c..2d5fe18 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -200,7 +200,7 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.core.StatusBarInitializer;
 import com.android.systemui.statusbar.data.model.StatusBarMode;
-import com.android.systemui.statusbar.data.repository.StatusBarModeRepository;
+import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
@@ -388,7 +388,7 @@
     private final NotificationShadeWindowController mNotificationShadeWindowController;
     private final StatusBarInitializer mStatusBarInitializer;
     private final StatusBarWindowController mStatusBarWindowController;
-    private final StatusBarModeRepository mStatusBarModeRepository;
+    private final StatusBarModeRepositoryStore mStatusBarModeRepository;
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @VisibleForTesting
     DozeServiceHost mDozeServiceHost;
@@ -606,7 +606,7 @@
             StatusBarInitializer statusBarInitializer,
             StatusBarWindowController statusBarWindowController,
             StatusBarWindowStateController statusBarWindowStateController,
-            StatusBarModeRepository statusBarModeRepository,
+            StatusBarModeRepositoryStore statusBarModeRepository,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             StatusBarSignalPolicy statusBarSignalPolicy,
             PulseExpansionHandler pulseExpansionHandler,
@@ -900,7 +900,7 @@
         setUpPresenter();
 
         if ((result.mTransientBarTypes & WindowInsets.Type.statusBars()) != 0) {
-            mStatusBarModeRepository.showTransient();
+            mStatusBarModeRepository.getDefaultDisplay().showTransient();
         }
         mCommandQueueCallbacks.onSystemBarAttributesChanged(mDisplayId, result.mAppearance,
                 result.mAppearanceRegions, result.mNavbarColorManagedByIme, result.mBehavior,
@@ -1147,9 +1147,10 @@
 
         mDemoModeController.addCallback(mDemoModeCallback);
         mJavaAdapter.alwaysCollectFlow(
-                mStatusBarModeRepository.isTransientShown(), this::onTransientShownChanged);
+                mStatusBarModeRepository.getDefaultDisplay().isTransientShown(),
+                this::onTransientShownChanged);
         mJavaAdapter.alwaysCollectFlow(
-                mStatusBarModeRepository.getStatusBarMode(),
+                mStatusBarModeRepository.getDefaultDisplay().getStatusBarMode(),
                 this::updateBarMode);
 
         mCommandQueueCallbacks = mCommandQueueCallbacksLazy.get();
@@ -1209,7 +1210,7 @@
 
             @Override
             public void hide() {
-                mStatusBarModeRepository.clearTransient();
+                mStatusBarModeRepository.getDefaultDisplay().clearTransient();
             }
         });
 
@@ -1657,7 +1658,7 @@
         if (mDemoModeController.isInDemoMode()) return;
         if (mStatusBarTransitions != null) {
             checkBarMode(
-                    mStatusBarModeRepository.getStatusBarMode().getValue(),
+                    mStatusBarModeRepository.getDefaultDisplay().getStatusBarMode().getValue(),
                     mStatusBarWindowState,
                     mStatusBarTransitions);
         }
@@ -1668,7 +1669,8 @@
     /** Temporarily hides Bubbles if the status bar is hidden. */
     @Override
     public void updateBubblesVisibility() {
-        StatusBarMode mode = mStatusBarModeRepository.getStatusBarMode().getValue();
+        StatusBarMode mode =
+                mStatusBarModeRepository.getDefaultDisplay().getStatusBarMode().getValue();
         mBubblesOptional.ifPresent(bubbles -> bubbles.onStatusBarVisibilityChanged(
                 mode != StatusBarMode.LIGHTS_OUT
                         && mode != StatusBarMode.LIGHTS_OUT_TRANSPARENT
@@ -2993,7 +2995,7 @@
     // End Extra BaseStatusBarMethods.
 
     boolean isTransientShown() {
-        return mStatusBarModeRepository.isTransientShown().getValue();
+        return mStatusBarModeRepository.getDefaultDisplay().isTransientShown().getValue();
     }
 
     private void updateLightRevealScrimVisibility() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifController.java
similarity index 94%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifController.java
index eba7fe0..7c871e1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightsOutNotifController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifController.java
@@ -36,6 +36,7 @@
 import com.android.internal.view.AppearanceRegion;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
+import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor;
 import com.android.systemui.statusbar.phone.fragment.dagger.StatusBarFragmentScope;
 import com.android.systemui.util.ViewController;
 
@@ -51,7 +52,7 @@
  * whether there are notifications when the device is in {@link View#SYSTEM_UI_FLAG_LOW_PROFILE}.
  */
 @StatusBarFragmentScope
-public class LightsOutNotifController extends ViewController<View> {
+public class LegacyLightsOutNotifController extends ViewController<View> {
     private final CommandQueue mCommandQueue;
     private final NotifLiveDataStore mNotifDataStore;
     private final WindowManager mWindowManager;
@@ -63,7 +64,7 @@
     private int mDisplayId;
 
     @Inject
-    LightsOutNotifController(
+    LegacyLightsOutNotifController(
             @Named(LIGHTS_OUT_NOTIF_VIEW) View lightsOutNotifView,
             WindowManager windowManager,
             NotifLiveDataStore notifDataStore,
@@ -72,7 +73,12 @@
         mWindowManager = windowManager;
         mNotifDataStore = notifDataStore;
         mCommandQueue = commandQueue;
+    }
 
+    @Override
+    protected void onInit() {
+        super.onInit();
+        NotificationsLiveDataStoreRefactor.assertInLegacyMode();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index 4d3e2ad..eec617b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -42,7 +42,7 @@
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.settings.DisplayTracker;
 import com.android.systemui.statusbar.data.model.StatusBarAppearance;
-import com.android.systemui.statusbar.data.repository.StatusBarModeRepository;
+import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.util.Compile;
 import com.android.systemui.util.kotlin.JavaAdapter;
@@ -68,7 +68,7 @@
     private final JavaAdapter mJavaAdapter;
     private final SysuiDarkIconDispatcher mStatusBarIconController;
     private final BatteryController mBatteryController;
-    private final StatusBarModeRepository mStatusBarModeRepository;
+    private final StatusBarModeRepositoryStore mStatusBarModeRepository;
     private BiometricUnlockController mBiometricUnlockController;
 
     private LightBarTransitionsController mNavigationBarController;
@@ -126,7 +126,7 @@
             DarkIconDispatcher darkIconDispatcher,
             BatteryController batteryController,
             NavigationModeController navModeController,
-            StatusBarModeRepository statusBarModeRepository,
+            StatusBarModeRepositoryStore statusBarModeRepository,
             DumpManager dumpManager,
             DisplayTracker displayTracker) {
         mJavaAdapter = javaAdapter;
@@ -146,7 +146,7 @@
     @Override
     public void start() {
         mJavaAdapter.alwaysCollectFlow(
-                mStatusBarModeRepository.getStatusBarAppearance(),
+                mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance(),
                 this::onStatusBarAppearanceChanged);
     }
 
@@ -476,7 +476,7 @@
         private final DarkIconDispatcher mDarkIconDispatcher;
         private final BatteryController mBatteryController;
         private final NavigationModeController mNavModeController;
-        private final StatusBarModeRepository mStatusBarModeRepository;
+        private final StatusBarModeRepositoryStore mStatusBarModeRepository;
         private final DumpManager mDumpManager;
         private final DisplayTracker mDisplayTracker;
 
@@ -486,7 +486,7 @@
                 DarkIconDispatcher darkIconDispatcher,
                 BatteryController batteryController,
                 NavigationModeController navModeController,
-                StatusBarModeRepository statusBarModeRepository,
+                StatusBarModeRepositoryStore statusBarModeRepository,
                 DumpManager dumpManager,
                 DisplayTracker displayTracker) {
             mJavaAdapter = javaAdapter;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractor.kt
new file mode 100644
index 0000000..ed8b3e8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractor.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.statusbar.phone.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.data.model.StatusBarMode
+import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/**
+ * Apps can request a low profile mode [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE] where status
+ * bar and navigation icons dim. In this mode, a notification dot appears where the notification
+ * icons would appear if they would be shown outside of this mode.
+ *
+ * This interactor knows whether the device is in [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE].
+ */
+@SysUISingleton
+class LightsOutInteractor
+@Inject
+constructor(private val repository: StatusBarModeRepositoryStore) {
+
+    fun isLowProfile(displayId: Int): Flow<Boolean> =
+        repository.forDisplay(displayId).statusBarMode.map {
+            when (it) {
+                StatusBarMode.LIGHTS_OUT,
+                StatusBarMode.LIGHTS_OUT_TRANSPARENT -> true
+                else -> false
+            }
+        }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index 7adc08c..49880d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -43,7 +43,6 @@
 import com.android.systemui.demomode.DemoMode;
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlagsClassic;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.res.R;
 import com.android.systemui.shade.ShadeExpansionStateManager;
@@ -139,7 +138,6 @@
     private final OngoingCallController mOngoingCallController;
     private final SystemStatusAnimationScheduler mAnimationScheduler;
     private final StatusBarLocationPublisher mLocationPublisher;
-    private final FeatureFlagsClassic mFeatureFlags;
     private final NotificationIconAreaController mNotificationIconAreaController;
     private final ShadeExpansionStateManager mShadeExpansionStateManager;
     private final StatusBarIconController mStatusBarIconController;
@@ -228,7 +226,6 @@
             StatusBarLocationPublisher locationPublisher,
             NotificationIconAreaController notificationIconAreaController,
             ShadeExpansionStateManager shadeExpansionStateManager,
-            FeatureFlagsClassic featureFlags,
             StatusBarIconController statusBarIconController,
             DarkIconManager.Factory darkIconManagerFactory,
             CollapsedStatusBarViewModel collapsedStatusBarViewModel,
@@ -258,7 +255,6 @@
         mLocationPublisher = locationPublisher;
         mNotificationIconAreaController = notificationIconAreaController;
         mShadeExpansionStateManager = shadeExpansionStateManager;
-        mFeatureFlags = featureFlags;
         mStatusBarIconController = statusBarIconController;
         mCollapsedStatusBarViewModel = collapsedStatusBarViewModel;
         mCollapsedStatusBarViewBinder = collapsedStatusBarViewBinder;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java
index 0618abb..96faa35 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentComponent.java
@@ -18,8 +18,9 @@
 
 import com.android.systemui.battery.BatteryMeterViewController;
 import com.android.systemui.dagger.qualifiers.RootView;
+import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor;
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
-import com.android.systemui.statusbar.phone.LightsOutNotifController;
+import com.android.systemui.statusbar.phone.LegacyLightsOutNotifController;
 import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions;
 import com.android.systemui.statusbar.phone.PhoneStatusBarView;
 import com.android.systemui.statusbar.phone.PhoneStatusBarViewController;
@@ -78,7 +79,9 @@
         getBatteryMeterViewController().init();
         getHeadsUpAppearanceController().init();
         getPhoneStatusBarViewController().init();
-        getLightsOutNotifController().init();
+        if (!NotificationsLiveDataStoreRefactor.isEnabled()) {
+            getLegacyLightsOutNotifController().init();
+        }
         getStatusBarDemoMode().init();
     }
 
@@ -101,7 +104,7 @@
 
     /** */
     @StatusBarFragmentScope
-    LightsOutNotifController getLightsOutNotifController();
+    LegacyLightsOutNotifController getLegacyLightsOutNotifController();
 
     /** */
     @StatusBarFragmentScope
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index b0532ce..0bdd1a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -36,7 +36,7 @@
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.data.repository.StatusBarModeRepository
+import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
 import com.android.systemui.statusbar.gesture.SwipeStatusBarAwayGestureHandler
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
@@ -68,7 +68,7 @@
     private val dumpManager: DumpManager,
     private val statusBarWindowController: StatusBarWindowController,
     private val swipeStatusBarAwayGestureHandler: SwipeStatusBarAwayGestureHandler,
-    private val statusBarModeRepository: StatusBarModeRepository,
+    private val statusBarModeRepository: StatusBarModeRepositoryStore,
 ) : CallbackController<OngoingCallListener>, Dumpable, CoreStartable {
     private var isFullscreen: Boolean = false
     /** Non-null if there's an active call notification. */
@@ -129,7 +129,7 @@
         dumpManager.registerDumpable(this)
         notifCollection.addCollectionListener(notifListener)
         scope.launch {
-            statusBarModeRepository.isInFullscreenMode.collect {
+            statusBarModeRepository.defaultDisplay.isInFullscreenMode.collect {
                 isFullscreen = it
                 updateChipClickListener()
                 updateGestureListening()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt
index da9c45a..9c78ab4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/data/repository/OngoingCallRepository.kt
@@ -27,7 +27,7 @@
  *
  * This class is used to break a dependency cycle between
  * [com.android.systemui.statusbar.phone.ongoingcall.OngoingCallController] and
- * [com.android.systemui.statusbar.data.repository.StatusBarModeRepository]. Instead, those two
+ * [com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore]. Instead, those two
  * classes both refer to this repository.
  */
 @SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
index b9b88f4..7d7f49b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/CollapsedStatusBarViewBinder.kt
@@ -16,11 +16,15 @@
 
 package com.android.systemui.statusbar.pipeline.shared.ui.binder
 
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
 import android.view.View
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
 import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.CollapsedStatusBarViewModel
 import javax.inject.Inject
 import kotlinx.coroutines.launch
@@ -61,9 +65,49 @@
                         listener.onTransitionFromLockscreenToDreamStarted()
                     }
                 }
+
+                if (NotificationsLiveDataStoreRefactor.isEnabled) {
+                    val displayId = view.display.displayId
+                    val lightsOutView: View = view.requireViewById(R.id.notification_lights_out)
+                    launch {
+                        viewModel.areNotificationsLightsOut(displayId).collect { show ->
+                            animateLightsOutView(lightsOutView, show)
+                        }
+                    }
+                }
             }
         }
     }
+
+    private fun animateLightsOutView(view: View, visible: Boolean) {
+        view.animate().cancel()
+
+        val alpha = if (visible) 1f else 0f
+        val duration = if (visible) 750L else 250L
+        val visibility = if (visible) View.VISIBLE else View.GONE
+
+        if (visible) {
+            view.alpha = 0f
+            view.visibility = View.VISIBLE
+        }
+
+        view
+            .animate()
+            .alpha(alpha)
+            .setDuration(duration)
+            .setListener(
+                object : AnimatorListenerAdapter() {
+                    override fun onAnimationEnd(animation: Animator) {
+                        view.alpha = alpha
+                        view.visibility = visibility
+                        // Unset the listener, otherwise this may persist for
+                        // another view property animation
+                        view.animate().setListener(null)
+                    }
+                }
+            )
+            .start()
+    }
 }
 
 /** Listener for various events that may affect the status bar's visibility. */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
index 15ab143..52a6d8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModel.kt
@@ -20,11 +20,17 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
+import com.android.systemui.statusbar.phone.domain.interactor.LightsOutInteractor
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
@@ -48,12 +54,25 @@
 
     /** Emits whenever a transition from lockscreen to dream has started. */
     val transitionFromLockscreenToDreamStartedEvent: Flow<Unit>
+
+    /**
+     * Apps can request a low profile mode [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE] where
+     * status bar and navigation icons dim. In this mode, a notification dot appears where the
+     * notification icons would appear if they would be shown outside of this mode.
+     *
+     * This flow tells when to show or hide the notification dot in the status bar to indicate
+     * whether there are notifications when the device is in
+     * [android.view.View.SYSTEM_UI_FLAG_LOW_PROFILE].
+     */
+    fun areNotificationsLightsOut(displayId: Int): Flow<Boolean>
 }
 
 @SysUISingleton
 class CollapsedStatusBarViewModelImpl
 @Inject
 constructor(
+    private val lightsOutInteractor: LightsOutInteractor,
+    private val notificationsInteractor: ActiveNotificationsInteractor,
     keyguardTransitionInteractor: KeyguardTransitionInteractor,
     @Application coroutineScope: CoroutineScope,
 ) : CollapsedStatusBarViewModel {
@@ -69,4 +88,17 @@
         keyguardTransitionInteractor.lockscreenToDreamingTransition
             .filter { it.transitionState == TransitionState.STARTED }
             .map {}
+
+    override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> =
+        if (NotificationsLiveDataStoreRefactor.isUnexpectedlyInLegacyMode()) {
+            emptyFlow()
+        } else {
+            combine(
+                    notificationsInteractor.areAnyNotificationsPresent,
+                    lightsOutInteractor.isLowProfile(displayId),
+                ) { hasNotifications, isLowProfile ->
+                    hasNotifications && isLowProfile
+                }
+                .distinctUntilChanged()
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt
index d1a46fc..057dcb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryImplTest.kt
@@ -62,7 +62,7 @@
     private val ongoingCallRepository = OngoingCallRepository()
 
     private val underTest =
-        StatusBarModeRepositoryImpl(
+        StatusBarModePerDisplayRepositoryImpl(
                 testScope.backgroundScope,
                 DISPLAY_ID,
                 commandQueue,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
similarity index 97%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
rename to packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
index 287ebba..bde2243 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightsOutNotifControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LegacyLightsOutNotifControllerTest.java
@@ -54,7 +54,7 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
-public class LightsOutNotifControllerTest extends SysuiTestCase {
+public class LegacyLightsOutNotifControllerTest extends SysuiTestCase {
     private static final int LIGHTS_ON = 0;
     private static final int LIGHTS_OUT = APPEARANCE_LOW_PROFILE_BARS;
 
@@ -68,7 +68,7 @@
     @Captor private ArgumentCaptor<CommandQueue.Callbacks> mCallbacksCaptor;
 
     private View mLightsOutView;
-    private LightsOutNotifController mLightsOutNotifController;
+    private LegacyLightsOutNotifController mLightsOutNotifController;
     private int mDisplayId;
     private Observer<Boolean> mHaActiveNotifsObserver;
     private CommandQueue.Callbacks mCallbacks;
@@ -83,7 +83,7 @@
         when(mNotifLiveDataStore.getHasActiveNotifs()).thenReturn(mHasActiveNotifs);
         when(mHasActiveNotifs.getValue()).thenReturn(false);
 
-        mLightsOutNotifController = new LightsOutNotifController(
+        mLightsOutNotifController = new LegacyLightsOutNotifController(
                 mLightsOutView,
                 mWindowManager,
                 mNotifLiveDataStore,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
index c45ecf3..f6419a9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/LightBarControllerTest.java
@@ -121,7 +121,7 @@
                 new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, secondBounds)
         );
 
-        mStatusBarModeRepository.getStatusBarAppearance().setValue(
+        mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
                 new StatusBarAppearance(
                         StatusBarMode.TRANSPARENT,
                         STATUS_BAR_BOUNDS,
@@ -142,7 +142,7 @@
                 new AppearanceRegion(0 /* appearance */, secondBounds)
         );
 
-        mStatusBarModeRepository.getStatusBarAppearance().setValue(
+        mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
                 new StatusBarAppearance(
                         StatusBarMode.TRANSPARENT,
                         STATUS_BAR_BOUNDS,
@@ -165,7 +165,7 @@
                 new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, secondBounds)
         );
 
-        mStatusBarModeRepository.getStatusBarAppearance().setValue(
+        mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
                 new StatusBarAppearance(
                         StatusBarMode.TRANSPARENT,
                         STATUS_BAR_BOUNDS,
@@ -190,7 +190,7 @@
                 new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, thirdBounds)
         );
 
-        mStatusBarModeRepository.getStatusBarAppearance().setValue(
+        mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
                 new StatusBarAppearance(
                         StatusBarMode.TRANSPARENT,
                         STATUS_BAR_BOUNDS,
@@ -214,7 +214,7 @@
                 new AppearanceRegion(0 /* appearance */, secondBounds)
         );
 
-        mStatusBarModeRepository.getStatusBarAppearance().setValue(
+        mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
                 new StatusBarAppearance(
                         StatusBarMode.TRANSPARENT,
                         STATUS_BAR_BOUNDS,
@@ -231,7 +231,7 @@
                 new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, new Rect(0, 0, 1, 1))
         );
 
-        mStatusBarModeRepository.getStatusBarAppearance().setValue(
+        mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
                 new StatusBarAppearance(
                         StatusBarMode.TRANSPARENT,
                         STATUS_BAR_BOUNDS,
@@ -249,7 +249,7 @@
                 new AppearanceRegion(0, new Rect(0, 0, 1, 1))
         );
 
-        mStatusBarModeRepository.getStatusBarAppearance().setValue(
+        mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
                 new StatusBarAppearance(
                         StatusBarMode.TRANSPARENT,
                         STATUS_BAR_BOUNDS,
@@ -266,7 +266,7 @@
                 new AppearanceRegion(APPEARANCE_LIGHT_STATUS_BARS, new Rect(0, 0, 1, 1))
         );
 
-        mStatusBarModeRepository.getStatusBarAppearance().setValue(
+        mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
                 new StatusBarAppearance(
                         StatusBarMode.TRANSPARENT,
                         STATUS_BAR_BOUNDS,
@@ -276,7 +276,7 @@
         reset(mStatusBarIconController);
 
         // WHEN the same appearance regions but different status bar mode is sent
-        mStatusBarModeRepository.getStatusBarAppearance().setValue(
+        mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
                 new StatusBarAppearance(
                         StatusBarMode.LIGHTS_OUT_TRANSPARENT,
                         STATUS_BAR_BOUNDS,
@@ -298,7 +298,7 @@
                 /* start= */ new Rect(0, 0, 10, 10),
                 /* end= */ new Rect(0, 0, 20, 20));
 
-        mStatusBarModeRepository.getStatusBarAppearance().setValue(
+        mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
                 new StatusBarAppearance(
                         StatusBarMode.TRANSPARENT,
                         startingBounds,
@@ -311,7 +311,7 @@
         BoundsPair newBounds = new BoundsPair(
                 /* start= */ new Rect(0, 0, 30, 30),
                 /* end= */ new Rect(0, 0, 40, 40));
-        mStatusBarModeRepository.getStatusBarAppearance().setValue(
+        mStatusBarModeRepository.getDefaultDisplay().getStatusBarAppearance().setValue(
                 new StatusBarAppearance(
                         StatusBarMode.TRANSPARENT,
                         newBounds,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
new file mode 100644
index 0000000..5a0e13d
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/domain/interactor/LightsOutInteractorTest.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.statusbar.data.model.StatusBarMode
+import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository
+import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository.Companion.DISPLAY_ID
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+
+@SmallTest
+class LightsOutInteractorTest : SysuiTestCase() {
+
+    private val statusBarModeRepository = FakeStatusBarModeRepository()
+    private val interactor: LightsOutInteractor = LightsOutInteractor(statusBarModeRepository)
+
+    @Test
+    fun isLowProfile_lightsOutStatusBarMode_false() = runTest {
+        statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.LIGHTS_OUT
+
+        val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID))
+
+        assertThat(actual).isTrue()
+    }
+
+    @Test
+    fun isLowProfile_lightsOutTransparentStatusBarMode_true() = runTest {
+        statusBarModeRepository.defaultDisplay.statusBarMode.value =
+            StatusBarMode.LIGHTS_OUT_TRANSPARENT
+
+        val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID))
+
+        assertThat(actual).isTrue()
+    }
+
+    @Test
+    fun isLowProfile_transparentStatusBarMode_false() = runTest {
+        statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.TRANSPARENT
+
+        val actual by collectLastValue(interactor.isLowProfile(DISPLAY_ID))
+
+        assertThat(actual).isFalse()
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
index 0b87fe8..17c2938 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragmentTest.java
@@ -46,7 +46,6 @@
 import com.android.systemui.common.ui.ConfigurationState;
 import com.android.systemui.demomode.DemoModeController;
 import com.android.systemui.dump.DumpManager;
-import com.android.systemui.flags.FeatureFlagsClassic;
 import com.android.systemui.log.LogBuffer;
 import com.android.systemui.log.LogcatEchoTracker;
 import com.android.systemui.plugins.DarkIconDispatcher;
@@ -695,7 +694,6 @@
                 mLocationPublisher,
                 mMockNotificationAreaController,
                 mShadeExpansionStateManager,
-                mock(FeatureFlagsClassic.class),
                 mStatusBarIconController,
                 mIconManagerFactory,
                 mCollapsedStatusBarViewModel,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
index 49de512..7b73528c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerTest.kt
@@ -549,7 +549,7 @@
     @Test
     fun fullscreenIsTrue_chipStillClickable() {
         notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
-        statusBarModeRepository.isInFullscreenMode.value = true
+        statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true
         testScope.runCurrent()
 
         assertThat(chipView.hasOnClickListeners()).isTrue()
@@ -559,7 +559,7 @@
 
     @Test
     fun callStartedInImmersiveMode_swipeGestureCallbackAdded() {
-        statusBarModeRepository.isInFullscreenMode.value = true
+        statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true
         testScope.runCurrent()
 
         notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
@@ -570,7 +570,7 @@
 
     @Test
     fun callStartedNotInImmersiveMode_swipeGestureCallbackNotAdded() {
-        statusBarModeRepository.isInFullscreenMode.value = false
+        statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = false
         testScope.runCurrent()
 
         notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
@@ -583,7 +583,7 @@
     fun transitionToImmersiveMode_swipeGestureCallbackAdded() {
         notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
 
-        statusBarModeRepository.isInFullscreenMode.value = true
+        statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true
         testScope.runCurrent()
 
         verify(mockSwipeStatusBarAwayGestureHandler)
@@ -592,11 +592,11 @@
 
     @Test
     fun transitionOutOfImmersiveMode_swipeGestureCallbackRemoved() {
-        statusBarModeRepository.isInFullscreenMode.value = true
+        statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true
         notifCollectionListener.onEntryUpdated(createOngoingCallNotifEntry())
         reset(mockSwipeStatusBarAwayGestureHandler)
 
-        statusBarModeRepository.isInFullscreenMode.value = false
+        statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = false
         testScope.runCurrent()
 
         verify(mockSwipeStatusBarAwayGestureHandler)
@@ -605,7 +605,7 @@
 
     @Test
     fun callEndedWhileInImmersiveMode_swipeGestureCallbackRemoved() {
-        statusBarModeRepository.isInFullscreenMode.value = true
+        statusBarModeRepository.defaultDisplay.isInFullscreenMode.value = true
         testScope.runCurrent()
         val ongoingCallNotifEntry = createOngoingCallNotifEntry()
         notifCollectionListener.onEntryAdded(ongoingCallNotifEntry)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
index 688f739..09dc1e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/CollapsedStatusBarViewModelImplTest.kt
@@ -17,49 +17,77 @@
 package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
 
 import androidx.test.filters.SmallTest
+import com.android.systemui.CoroutineTestScopeModule
+import com.android.systemui.Flags
+import com.android.systemui.SysUITestComponent
+import com.android.systemui.SysUITestModule
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectValues
+import com.android.systemui.collectLastValue
+import com.android.systemui.collectValues
+import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
-import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.runTest
+import com.android.systemui.statusbar.data.model.StatusBarMode
+import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository
+import com.android.systemui.statusbar.data.repository.FakeStatusBarModeRepository.Companion.DISPLAY_ID
+import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
+import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository
+import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
+import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
 import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
 import kotlinx.coroutines.ExperimentalCoroutinesApi
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
 
-@OptIn(ExperimentalCoroutinesApi::class)
 @SmallTest
 class CollapsedStatusBarViewModelImplTest : SysuiTestCase() {
 
-    private lateinit var underTest: CollapsedStatusBarViewModel
+    @SysUISingleton
+    @Component(
+        modules =
+            [
+                SysUITestModule::class,
+            ]
+    )
+    interface TestComponent : SysUITestComponent<CollapsedStatusBarViewModelImpl> {
+        val statusBarModeRepository: FakeStatusBarModeRepository
+        val activeNotificationListRepository: ActiveNotificationListRepository
+        val keyguardTransitionRepository: FakeKeyguardTransitionRepository
 
-    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
-    private lateinit var testScope: TestScope
+        @Component.Factory
+        interface Factory {
+            fun create(
+                @BindsInstance test: SysuiTestCase,
+                testScope: CoroutineTestScopeModule,
+            ): TestComponent
+        }
+    }
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    private val testComponent: TestComponent =
+        DaggerCollapsedStatusBarViewModelImplTest_TestComponent.factory()
+            .create(
+                test = this,
+                testScope = CoroutineTestScopeModule(TestScope(UnconfinedTestDispatcher())),
+            )
 
     @Before
     fun setUp() {
-        testScope = TestScope(UnconfinedTestDispatcher())
-
-        keyguardTransitionRepository = FakeKeyguardTransitionRepository()
-        val interactor =
-            KeyguardTransitionInteractorFactory.create(
-                    scope = TestScope().backgroundScope,
-                    repository = keyguardTransitionRepository,
-                )
-                .keyguardTransitionInteractor
-        underTest = CollapsedStatusBarViewModelImpl(interactor, testScope.backgroundScope)
+        mSetFlagsRule.enableFlags(Flags.FLAG_NOTIFICATIONS_LIVE_DATA_STORE_REFACTOR)
     }
 
     @Test
     fun isTransitioningFromLockscreenToOccluded_started_isTrue() =
-        testScope.runTest {
-            val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(this)
+        testComponent.runTest {
+            val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
 
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
@@ -77,8 +105,8 @@
 
     @Test
     fun isTransitioningFromLockscreenToOccluded_running_isTrue() =
-        testScope.runTest {
-            val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(this)
+        testComponent.runTest {
+            val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
 
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
@@ -96,13 +124,13 @@
 
     @Test
     fun isTransitioningFromLockscreenToOccluded_finished_isFalse() =
-        testScope.runTest {
-            val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(this)
+        testComponent.runTest {
+            val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
 
             keyguardTransitionRepository.sendTransitionSteps(
                 from = KeyguardState.LOCKSCREEN,
                 to = KeyguardState.OCCLUDED,
-                this.testScheduler,
+                testScope.testScheduler,
             )
 
             assertThat(underTest.isTransitioningFromLockscreenToOccluded.value).isFalse()
@@ -112,8 +140,8 @@
 
     @Test
     fun isTransitioningFromLockscreenToOccluded_canceled_isFalse() =
-        testScope.runTest {
-            val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(this)
+        testComponent.runTest {
+            val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
 
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
@@ -131,8 +159,8 @@
 
     @Test
     fun isTransitioningFromLockscreenToOccluded_irrelevantTransition_isFalse() =
-        testScope.runTest {
-            val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(this)
+        testComponent.runTest {
+            val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
 
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
@@ -150,8 +178,8 @@
 
     @Test
     fun isTransitioningFromLockscreenToOccluded_followsRepoUpdates() =
-        testScope.runTest {
-            val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(this)
+        testComponent.runTest {
+            val job = underTest.isTransitioningFromLockscreenToOccluded.launchIn(testScope)
 
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
@@ -182,7 +210,7 @@
 
     @Test
     fun transitionFromLockscreenToDreamStartedEvent_started_emitted() =
-        testScope.runTest {
+        testComponent.runTest {
             val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
 
             keyguardTransitionRepository.sendTransitionStep(
@@ -199,7 +227,7 @@
 
     @Test
     fun transitionFromLockscreenToDreamStartedEvent_startedMultiple_emittedMultiple() =
-        testScope.runTest {
+        testComponent.runTest {
             val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
 
             keyguardTransitionRepository.sendTransitionStep(
@@ -234,7 +262,7 @@
 
     @Test
     fun transitionFromLockscreenToDreamStartedEvent_startedThenRunning_emittedOnlyOne() =
-        testScope.runTest {
+        testComponent.runTest {
             val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
 
             keyguardTransitionRepository.sendTransitionStep(
@@ -283,7 +311,7 @@
 
     @Test
     fun transitionFromLockscreenToDreamStartedEvent_irrelevantTransition_notEmitted() =
-        testScope.runTest {
+        testComponent.runTest {
             val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
 
             keyguardTransitionRepository.sendTransitionStep(
@@ -300,7 +328,7 @@
 
     @Test
     fun transitionFromLockscreenToDreamStartedEvent_irrelevantTransitionState_notEmitted() =
-        testScope.runTest {
+        testComponent.runTest {
             val emissions by collectValues(underTest.transitionFromLockscreenToDreamStartedEvent)
 
             keyguardTransitionRepository.sendTransitionStep(
@@ -317,4 +345,65 @@
 
             assertThat(emissions).isEmpty()
         }
+
+    @Test
+    fun areNotificationsLightsOut_lowProfileWithNotifications_true() =
+        testComponent.runTest {
+            statusBarModeRepository.defaultDisplay.statusBarMode.value =
+                StatusBarMode.LIGHTS_OUT_TRANSPARENT
+            activeNotificationListRepository.activeNotifications.value =
+                activeNotificationsStore(testNotifications)
+
+            val actual by collectLastValue(underTest.areNotificationsLightsOut(DISPLAY_ID))
+
+            assertThat(actual).isTrue()
+        }
+
+    @Test
+    fun areNotificationsLightsOut_lowProfileWithoutNotifications_false() =
+        testComponent.runTest {
+            statusBarModeRepository.defaultDisplay.statusBarMode.value =
+                StatusBarMode.LIGHTS_OUT_TRANSPARENT
+            activeNotificationListRepository.activeNotifications.value =
+                activeNotificationsStore(emptyList())
+
+            val actual by collectLastValue(underTest.areNotificationsLightsOut(DISPLAY_ID))
+
+            assertThat(actual).isFalse()
+        }
+
+    @Test
+    fun areNotificationsLightsOut_defaultStatusBarModeWithoutNotifications_false() =
+        testComponent.runTest {
+            statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.TRANSPARENT
+            activeNotificationListRepository.activeNotifications.value =
+                activeNotificationsStore(emptyList())
+
+            val actual by collectLastValue(underTest.areNotificationsLightsOut(DISPLAY_ID))
+
+            assertThat(actual).isFalse()
+        }
+
+    @Test
+    fun areNotificationsLightsOut_defaultStatusBarModeWithNotifications_false() =
+        testComponent.runTest {
+            statusBarModeRepository.defaultDisplay.statusBarMode.value = StatusBarMode.TRANSPARENT
+            activeNotificationListRepository.activeNotifications.value =
+                activeNotificationsStore(testNotifications)
+
+            val actual by collectLastValue(underTest.areNotificationsLightsOut(DISPLAY_ID))
+
+            assertThat(actual).isFalse()
+        }
+
+    private fun activeNotificationsStore(notifications: List<ActiveNotificationModel>) =
+        ActiveNotificationsStore.Builder()
+            .apply { notifications.forEach(::addIndividualNotif) }
+            .build()
+
+    private val testNotifications =
+        listOf(
+            activeNotificationModel(key = "notif1"),
+            activeNotificationModel(key = "notif2"),
+        )
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
index 88587b2..bc50f79 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeCollapsedStatusBarViewModel.kt
@@ -16,11 +16,20 @@
 
 package com.android.systemui.statusbar.pipeline.shared.ui.viewmodel
 
+import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.MutableStateFlow
 
 class FakeCollapsedStatusBarViewModel : CollapsedStatusBarViewModel {
+    private val areNotificationLightsOut = MutableStateFlow(false)
+
     override val isTransitioningFromLockscreenToOccluded = MutableStateFlow(false)
 
     override val transitionFromLockscreenToDreamStartedEvent = MutableSharedFlow<Unit>()
+
+    override fun areNotificationsLightsOut(displayId: Int): Flow<Boolean> = areNotificationLightsOut
+
+    fun setNotificationLightsOut(lightsOut: Boolean) {
+        areNotificationLightsOut.value = lightsOut
+    }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
index f25d282..6069083 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeStatusBarModeRepository.kt
@@ -16,14 +16,33 @@
 
 package com.android.systemui.statusbar.data.repository
 
+import android.view.Display
+import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.statusbar.data.model.StatusBarAppearance
 import com.android.systemui.statusbar.data.model.StatusBarMode
+import com.google.common.truth.Truth.assertThat
 import dagger.Binds
 import dagger.Module
 import javax.inject.Inject
 import kotlinx.coroutines.flow.MutableStateFlow
 
-class FakeStatusBarModeRepository @Inject constructor() : StatusBarModeRepository {
+@SysUISingleton
+class FakeStatusBarModeRepository @Inject constructor() : StatusBarModeRepositoryStore {
+
+    companion object {
+        const val DISPLAY_ID = Display.DEFAULT_DISPLAY
+    }
+
+    override val defaultDisplay: FakeStatusBarModePerDisplayRepository =
+        FakeStatusBarModePerDisplayRepository()
+
+    override fun forDisplay(displayId: Int): FakeStatusBarModePerDisplayRepository {
+        assertThat(displayId).isEqualTo(DISPLAY_ID)
+        return defaultDisplay
+    }
+}
+
+class FakeStatusBarModePerDisplayRepository : StatusBarModePerDisplayRepository {
     override val isTransientShown = MutableStateFlow(false)
     override val isInFullscreenMode = MutableStateFlow(false)
     override val statusBarAppearance = MutableStateFlow<StatusBarAppearance?>(null)
@@ -39,5 +58,5 @@
 
 @Module
 interface FakeStatusBarModeRepositoryModule {
-    @Binds fun bindFake(fake: FakeStatusBarModeRepository): StatusBarModeRepository
+    @Binds fun bindFake(fake: FakeStatusBarModeRepository): StatusBarModeRepositoryStore
 }