[sb] use HeadsUpNotificationInteractor to control clock visibility

This brings the StatusBarRootModernization flag up-to-par with HUNs.

- Use INVISIBLE for the clock instead of GONE. This ensures that the
  aniamtions work correctly
- During HUNs, we set the clock visibilty to INVISIBLE for the view
  model
- Move 2 flows in HeadsUpNotificationInteractor from out of behind the
  SceneContainer flag, so that we can use them instead of the
  HeadsUpAppearanceController callbacks

Test: HeadsUpNotificationInteractorTest
Test: HomeStatusBarViewModelImplTest
Test: manual using Notify.apk
Bug: 364360986
Flag: com.android.systemui.status_bar_notification_chips
Change-Id: I2539124be859ee0fd50d93bc121e6670cd9828e9
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
index c03eaeb..7b04fc8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
@@ -67,9 +67,11 @@
 import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.Idle
 import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
+import com.android.systemui.statusbar.notification.data.repository.FakeHeadsUpRowRepository
 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
 import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
 import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
+import com.android.systemui.statusbar.notification.stack.data.repository.headsUpNotificationRepository
 import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.HomeStatusBarViewModel.VisibilityModel
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
@@ -504,7 +506,7 @@
         }
 
     @Test
-    fun isClockVisible_notAllowedByDisableFlags_gone() =
+    fun isClockVisible_notAllowedByDisableFlags_invisible() =
         kosmos.runTest {
             val latest by collectLastValue(underTest.isClockVisible)
             transitionKeyguardToGone()
@@ -512,7 +514,63 @@
             fakeDisableFlagsRepository.disableFlags.value =
                 DisableFlagsModel(DISABLE_CLOCK, DISABLE2_NONE)
 
-            assertThat(latest!!.visibility).isEqualTo(View.GONE)
+            assertThat(latest!!.visibility).isEqualTo(View.INVISIBLE)
+        }
+
+    @Test
+    fun isClockVisible_allowedByFlags_hunActive_notVisible() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isClockVisible)
+            transitionKeyguardToGone()
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
+            // there is an active HUN
+            headsUpNotificationRepository.setNotifications(
+                fakeHeadsUpRowRepository(isPinned = true)
+            )
+
+            assertThat(latest!!.visibility).isEqualTo(View.INVISIBLE)
+        }
+
+    @Test
+    fun isClockVisible_allowedByFlags_hunBecomesInactive_visibleAgain() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isClockVisible)
+            transitionKeyguardToGone()
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)
+            // there is an active HUN
+            headsUpNotificationRepository.setNotifications(
+                fakeHeadsUpRowRepository(isPinned = true)
+            )
+
+            // hun goes away
+            headsUpNotificationRepository.setNotifications(listOf())
+
+            assertThat(latest!!.visibility).isEqualTo(View.VISIBLE)
+        }
+
+    @Test
+    fun isClockVisible_disabledByFlags_hunBecomesInactive_neverVisible() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isClockVisible)
+            transitionKeyguardToGone()
+
+            fakeDisableFlagsRepository.disableFlags.value =
+                DisableFlagsModel(DISABLE_CLOCK, DISABLE2_NONE)
+            // there is an active HUN
+            headsUpNotificationRepository.setNotifications(
+                fakeHeadsUpRowRepository(isPinned = true)
+            )
+
+            assertThat(latest!!.visibility).isEqualTo(View.INVISIBLE)
+
+            // hun goes away
+            headsUpNotificationRepository.setNotifications(listOf())
+
+            assertThat(latest!!.visibility).isEqualTo(View.INVISIBLE)
         }
 
     @Test
@@ -634,7 +692,7 @@
                 testScope = testScope,
             )
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
@@ -649,7 +707,7 @@
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
@@ -668,7 +726,7 @@
                 testScope = testScope,
             )
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
@@ -683,7 +741,7 @@
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Bouncer)
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
@@ -780,7 +838,7 @@
 
             kosmos.shadeTestUtil.setShadeExpansion(1f)
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
@@ -796,7 +854,7 @@
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Shade)
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
@@ -817,7 +875,7 @@
             )
             kosmos.keyguardInteractor.onCameraLaunchDetected(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP)
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
@@ -835,11 +893,15 @@
             kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true, taskInfo = null)
             kosmos.keyguardInteractor.onCameraLaunchDetected(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP)
 
-            assertThat(clockVisible!!.visibility).isEqualTo(View.GONE)
+            assertThat(clockVisible!!.visibility).isEqualTo(View.INVISIBLE)
             assertThat(notifIconsVisible!!.visibility).isEqualTo(View.GONE)
             assertThat(systemInfoVisible!!.baseVisibility.visibility).isEqualTo(View.GONE)
         }
 
+    // Cribbed from [HeadsUpNotificationInteractorTest.kt]
+    private fun fakeHeadsUpRowRepository(key: String = "test key", isPinned: Boolean = false) =
+        FakeHeadsUpRowRepository(key = key, isPinned = isPinned)
+
     private fun activeNotificationsStore(notifications: List<ActiveNotificationModel>) =
         ActiveNotificationsStore.Builder()
             .apply { notifications.forEach(::addIndividualNotif) }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt
index 8133565..64e78e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/domain/interactor/HeadsUpNotificationInteractor.kt
@@ -98,22 +98,17 @@
     }
 
     /** Are there any pinned heads up rows to display? */
-    val hasPinnedRows: Flow<Boolean> by lazy {
-        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
-            flowOf(false)
-        } else {
-            headsUpRepository.activeHeadsUpRows.flatMapLatest { rows ->
-                if (rows.isNotEmpty()) {
-                    combine(rows.map { it.pinnedStatus }) { pinnedStatus ->
-                        pinnedStatus.any { it.isPinned }
-                    }
-                } else {
-                    // if the set is empty, there are no flows to combine
-                    flowOf(false)
+    val hasPinnedRows: Flow<Boolean> =
+        headsUpRepository.activeHeadsUpRows.flatMapLatest { rows ->
+            if (rows.isNotEmpty()) {
+                combine(rows.map { it.pinnedStatus }) { pinnedStatus ->
+                    pinnedStatus.any { it.isPinned }
                 }
+            } else {
+                // if the set is empty, there are no flows to combine
+                flowOf(false)
             }
         }
-    }
 
     val isHeadsUpOrAnimatingAway: Flow<Boolean> by lazy {
         if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
@@ -143,15 +138,10 @@
             }
         }
 
-    val showHeadsUpStatusBar: Flow<Boolean> by lazy {
-        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
-            flowOf(false)
-        } else {
-            combine(hasPinnedRows, canShowHeadsUp) { hasPinnedRows, canShowHeadsUp ->
-                hasPinnedRows && canShowHeadsUp
-            }
+    val showHeadsUpStatusBar =
+        combine(hasPinnedRows, canShowHeadsUp) { hasPinnedRows, canShowHeadsUp ->
+            hasPinnedRows && canShowHeadsUp
         }
-    }
 
     fun headsUpRow(key: HeadsUpRowKey): HeadsUpRowInteractor =
         HeadsUpRowInteractor(key as HeadsUpRowRepository)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index b9639a7..677ed9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -37,19 +37,20 @@
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.core.StatusBarRootModernization;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
 import com.android.systemui.statusbar.notification.SourceType;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationIconInteractor;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
 import com.android.systemui.statusbar.notification.stack.NotificationRoundnessManager;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
 import com.android.systemui.statusbar.phone.fragment.dagger.HomeStatusBarScope;
 import com.android.systemui.statusbar.policy.Clock;
-import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.statusbar.notification.headsup.OnHeadsUpChangedListener;
 import com.android.systemui.util.ViewController;
 
 import java.util.ArrayList;
@@ -249,10 +250,14 @@
                 updateParentClipping(false /* shouldClip */);
                 mView.setVisibility(View.VISIBLE);
                 show(mView);
-                hide(mClockView, View.INVISIBLE);
+                if (!StatusBarRootModernization.isEnabled()) {
+                    hide(mClockView, View.INVISIBLE);
+                }
                 mOperatorNameViewOptional.ifPresent(view -> hide(view, View.INVISIBLE));
             } else {
-                show(mClockView);
+                if (!StatusBarRootModernization.isEnabled()) {
+                    show(mClockView);
+                }
                 mOperatorNameViewOptional.ifPresent(this::show);
                 hide(mView, View.GONE, () -> {
                     updateParentClipping(true /* shouldClip */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt
index b2a0272..a0cb829 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/domain/interactor/CollapsedStatusBarInteractor.kt
@@ -30,13 +30,13 @@
 @SysUISingleton
 class CollapsedStatusBarInteractor
 @Inject
-constructor(DisableFlagsInteractor: DisableFlagsInteractor) {
+constructor(disableFlagsInteractor: DisableFlagsInteractor) {
     /**
      * The visibilities of various status bar child views, based only on the information we received
      * from disable flags.
      */
     val visibilityViaDisableFlags: Flow<StatusBarDisableFlagsVisibilityModel> =
-        DisableFlagsInteractor.disableFlags.map {
+        disableFlagsInteractor.disableFlags.map {
             StatusBarDisableFlagsVisibilityModel(
                 isClockAllowed = it.isClockEnabled,
                 areNotificationIconsAllowed = it.areNotificationIconsEnabled,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
index 133bba4..c52275a9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
@@ -40,6 +40,7 @@
 import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState
 import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationState.Idle
 import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
+import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
 import com.android.systemui.statusbar.notification.shared.NotificationsLiveDataStoreRefactor
 import com.android.systemui.statusbar.phone.domain.interactor.LightsOutInteractor
 import com.android.systemui.statusbar.pipeline.shared.domain.interactor.CollapsedStatusBarInteractor
@@ -138,6 +139,7 @@
     collapsedStatusBarInteractor: CollapsedStatusBarInteractor,
     private val lightsOutInteractor: LightsOutInteractor,
     private val notificationsInteractor: ActiveNotificationsInteractor,
+    headsUpNotificationInteractor: HeadsUpNotificationInteractor,
     keyguardTransitionInteractor: KeyguardTransitionInteractor,
     keyguardInteractor: KeyguardInteractor,
     sceneInteractor: SceneInteractor,
@@ -233,11 +235,13 @@
     override val isClockVisible: Flow<VisibilityModel> =
         combine(
             shouldHomeStatusBarBeVisible,
+            headsUpNotificationInteractor.showHeadsUpStatusBar,
             collapsedStatusBarInteractor.visibilityViaDisableFlags,
-        ) { shouldStatusBarBeVisible, visibilityViaDisableFlags ->
-            val showClock = shouldStatusBarBeVisible && visibilityViaDisableFlags.isClockAllowed
-            // TODO(b/364360986): Take CollapsedStatusBarFragment.clockHiddenMode into account.
-            VisibilityModel(showClock.toVisibilityInt(), visibilityViaDisableFlags.animate)
+        ) { shouldStatusBarBeVisible, showHeadsUp, visibilityViaDisableFlags ->
+            val showClock =
+                shouldStatusBarBeVisible && visibilityViaDisableFlags.isClockAllowed && !showHeadsUp
+            // Always use View.INVISIBLE here, so that animations work
+            VisibilityModel(showClock.toVisibleOrInvisible(), visibilityViaDisableFlags.animate)
         }
     override val isNotificationIconContainerVisible: Flow<VisibilityModel> =
         combine(
@@ -253,10 +257,11 @@
                         visibilityViaDisableFlags.areNotificationIconsAllowed
                 }
             VisibilityModel(
-                showNotificationIconContainer.toVisibilityInt(),
+                showNotificationIconContainer.toVisibleOrGone(),
                 visibilityViaDisableFlags.animate,
             )
         }
+
     private val isSystemInfoVisible =
         combine(
             shouldHomeStatusBarBeVisible,
@@ -264,7 +269,7 @@
         ) { shouldStatusBarBeVisible, visibilityViaDisableFlags ->
             val showSystemInfo =
                 shouldStatusBarBeVisible && visibilityViaDisableFlags.isSystemInfoAllowed
-            VisibilityModel(showSystemInfo.toVisibilityInt(), visibilityViaDisableFlags.animate)
+            VisibilityModel(showSystemInfo.toVisibleOrGone(), visibilityViaDisableFlags.animate)
         }
 
     override val systemInfoCombinedVis =
@@ -284,7 +289,11 @@
             )
 
     @View.Visibility
-    private fun Boolean.toVisibilityInt(): Int {
+    private fun Boolean.toVisibleOrGone(): Int {
         return if (this) View.VISIBLE else View.GONE
     }
+
+    // Similar to the above, but uses INVISIBLE in place of GONE
+    @View.Visibility
+    private fun Boolean.toVisibleOrInvisible(): Int = if (this) View.VISIBLE else View.INVISIBLE
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
index 03e4c89..eb17237 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
 import com.android.systemui.statusbar.events.domain.interactor.systemStatusEventAnimationInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
+import com.android.systemui.statusbar.notification.stack.domain.interactor.headsUpNotificationInteractor
 import com.android.systemui.statusbar.phone.domain.interactor.lightsOutInteractor
 import com.android.systemui.statusbar.pipeline.shared.domain.interactor.collapsedStatusBarInteractor
 
@@ -35,6 +36,7 @@
             collapsedStatusBarInteractor,
             lightsOutInteractor,
             activeNotificationsInteractor,
+            headsUpNotificationInteractor,
             keyguardTransitionInteractor,
             keyguardInteractor,
             sceneInteractor,