Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 219e8cde authored by Evan Laird's avatar Evan Laird
Browse files

[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
parent c12a7bfd
Loading
Loading
Loading
Loading
+72 −10
Original line number Diff line number Diff line
@@ -67,9 +67,11 @@ import com.android.systemui.statusbar.events.shared.model.SystemEventAnimationSt
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 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
        }

    @Test
    fun isClockVisible_notAllowedByDisableFlags_gone() =
    fun isClockVisible_notAllowedByDisableFlags_invisible() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.isClockVisible)
            transitionKeyguardToGone()
@@ -512,7 +514,63 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
            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 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
                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 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {

            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 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
                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 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {

            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 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {

            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 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {

            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 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
            )
            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 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
            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) }
+11 −21
Original line number Diff line number Diff line
@@ -98,10 +98,7 @@ constructor(
    }

    /** Are there any pinned heads up rows to display? */
    val hasPinnedRows: Flow<Boolean> by lazy {
        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
            flowOf(false)
        } else {
    val hasPinnedRows: Flow<Boolean> =
        headsUpRepository.activeHeadsUpRows.flatMapLatest { rows ->
            if (rows.isNotEmpty()) {
                combine(rows.map { it.pinnedStatus }) { pinnedStatus ->
@@ -112,8 +109,6 @@ constructor(
                flowOf(false)
            }
        }
        }
    }

    val isHeadsUpOrAnimatingAway: Flow<Boolean> by lazy {
        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
@@ -143,15 +138,10 @@ constructor(
            }
        }

    val showHeadsUpStatusBar: Flow<Boolean> by lazy {
        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) {
            flowOf(false)
        } else {
    val showHeadsUpStatusBar =
        combine(hasPinnedRows, canShowHeadsUp) { hasPinnedRows, canShowHeadsUp ->
            hasPinnedRows && canShowHeadsUp
        }
        }
    }

    fun headsUpRow(key: HeadsUpRowKey): HeadsUpRowInteractor =
        HeadsUpRowInteractor(key as HeadsUpRowRepository)
+9 −4
Original line number Diff line number Diff line
@@ -37,19 +37,20 @@ import com.android.systemui.statusbar.CommandQueue;
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 @@ public class HeadsUpAppearanceController extends ViewController<HeadsUpStatusBar
                updateParentClipping(false /* shouldClip */);
                mView.setVisibility(View.VISIBLE);
                show(mView);
                if (!StatusBarRootModernization.isEnabled()) {
                    hide(mClockView, View.INVISIBLE);
                }
                mOperatorNameViewOptional.ifPresent(view -> hide(view, View.INVISIBLE));
            } else {
                if (!StatusBarRootModernization.isEnabled()) {
                    show(mClockView);
                }
                mOperatorNameViewOptional.ifPresent(this::show);
                hide(mView, View.GONE, () -> {
                    updateParentClipping(true /* shouldClip */);
+2 −2
Original line number Diff line number Diff line
@@ -30,13 +30,13 @@ import kotlinx.coroutines.flow.map
@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,
+16 −7
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import com.android.systemui.statusbar.events.domain.interactor.SystemStatusEvent
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 @@ constructor(
    collapsedStatusBarInteractor: CollapsedStatusBarInteractor,
    private val lightsOutInteractor: LightsOutInteractor,
    private val notificationsInteractor: ActiveNotificationsInteractor,
    headsUpNotificationInteractor: HeadsUpNotificationInteractor,
    keyguardTransitionInteractor: KeyguardTransitionInteractor,
    keyguardInteractor: KeyguardInteractor,
    sceneInteractor: SceneInteractor,
@@ -233,11 +235,13 @@ constructor(
    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 @@ constructor(
                        visibilityViaDisableFlags.areNotificationIconsAllowed
                }
            VisibilityModel(
                showNotificationIconContainer.toVisibilityInt(),
                showNotificationIconContainer.toVisibleOrGone(),
                visibilityViaDisableFlags.animate,
            )
        }

    private val isSystemInfoVisible =
        combine(
            shouldHomeStatusBarBeVisible,
@@ -264,7 +269,7 @@ constructor(
        ) { shouldStatusBarBeVisible, visibilityViaDisableFlags ->
            val showSystemInfo =
                shouldStatusBarBeVisible && visibilityViaDisableFlags.isSystemInfoAllowed
            VisibilityModel(showSystemInfo.toVisibilityInt(), visibilityViaDisableFlags.animate)
            VisibilityModel(showSystemInfo.toVisibleOrGone(), visibilityViaDisableFlags.animate)
        }

    override val systemInfoCombinedVis =
@@ -284,7 +289,11 @@ constructor(
            )

    @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
}
Loading