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

Commit 3df02667 authored by Evan Laird's avatar Evan Laird
Browse files

[sb] calculate overall chip visibilty in view model

When StatusBarRootModernization is on, we need to account for the
overall status bar visibility (shouldHomeStatusBarBeVisible), as well as
the possibility that a HUN is showing, when it comes to the chip
visibility.

This CL exposes a new property (canShowOngoingActivityChips) that covers
this.

It also handles an edge case where the binder might try to set something
as visible via `show()`, but the view is already visible with alpha=0.
In this case, we still want to run the show function since the alpha
needs to be updated.

Test: HomeStatusBarViewModelImplTest
Test: have ongoing call notification and go to lockscreen
Fixes: 395632689
Flag: com.android.systemui.status_bar_root_modernization
Change-Id: I91bb7e552b20895ad2e9d3848072a7779e9ff5e5
parent a90821d0
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -64,6 +64,8 @@ class FakeHomeStatusBarViewModel(

    override val isHomeStatusBarAllowedByScene = MutableStateFlow(false)

    override val canShowOngoingActivityChips: Flow<Boolean> = MutableStateFlow(false)

    override val batteryViewModelFactory: BatteryViewModel.Factory =
        object : BatteryViewModel.Factory {
            override fun create(): BatteryViewModel = mock(BatteryViewModel::class.java)
+54 −0
Original line number Diff line number Diff line
@@ -677,6 +677,60 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
            assertThat(latest).isTrue()
        }

    @Test
    fun canShowOngoingActivityChips_statusBarHidden_noSecureCamera_noHun_false() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.canShowOngoingActivityChips)

            // home status bar not allowed
            kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
            kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(false, taskInfo = null)

            assertThat(latest).isFalse()
        }

    @Test
    fun canShowOngoingActivityChips_statusBarNotHidden_noSecureCamera_noHun_true() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.canShowOngoingActivityChips)

            transitionKeyguardToGone()

            assertThat(latest).isTrue()
        }

    @Test
    fun canShowOngoingActivityChips_statusBarNotHidden_secureCamera_noHun_false() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.canShowOngoingActivityChips)

            fakeKeyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.LOCKSCREEN,
                to = KeyguardState.OCCLUDED,
                testScope = testScope,
            )
            kosmos.keyguardInteractor.onCameraLaunchDetected(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP)

            assertThat(latest).isFalse()
        }

    @Test
    fun canShowOngoingActivityChips_statusBarNotHidden_noSecureCamera_hun_false() =
        kosmos.runTest {
            val latest by collectLastValue(underTest.canShowOngoingActivityChips)

            transitionKeyguardToGone()

            headsUpNotificationRepository.setNotifications(
                UnconfinedFakeHeadsUpRowRepository(
                    key = "key",
                    pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser),
                )
            )

            assertThat(latest).isFalse()
        }

    @Test
    fun isClockVisible_allowedByDisableFlags_visible() =
        kosmos.runTest {
+75 −29
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.statusbar.chips.mediaprojection.domain.model.MediaProjectionStopDialogModel
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
import com.android.systemui.statusbar.chips.ui.binder.OngoingActivityChipBinder
import com.android.systemui.statusbar.chips.ui.binder.OngoingActivityChipViewBinding
import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModelLegacy
import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
import com.android.systemui.statusbar.core.StatusBarRootModernization
@@ -149,6 +151,7 @@ constructor(
                if (!StatusBarNotifChips.isEnabled && !StatusBarChipsModernization.isEnabled) {
                    val primaryChipViewBinding =
                        OngoingActivityChipBinder.createBinding(primaryChipView)

                    launch {
                        viewModel.primaryOngoingActivityChip.collect { primaryChipModel ->
                            OngoingActivityChipBinder.bind(
@@ -156,17 +159,13 @@ constructor(
                                primaryChipViewBinding,
                                iconViewStore,
                            )
                            if (StatusBarRootModernization.isEnabled) {
                                when (primaryChipModel) {
                                    is OngoingActivityChipModel.Active ->
                                        primaryChipViewBinding.rootView.show(
                                            shouldAnimateChange = true
                                        )

                                    is OngoingActivityChipModel.Inactive ->
                                        primaryChipViewBinding.rootView.hide(
                                            state = View.GONE,
                                            shouldAnimateChange = primaryChipModel.shouldAnimate,
                            if (StatusBarRootModernization.isEnabled) {
                                launch {
                                    bindLegacyPrimaryOngoingActivityChipWithVisibility(
                                        viewModel,
                                        primaryChipModel,
                                        primaryChipViewBinding,
                                    )
                                }
                            } else {
@@ -213,12 +212,14 @@ constructor(
                            )

                            if (StatusBarRootModernization.isEnabled) {
                                primaryChipViewBinding.rootView.adjustVisibility(
                                    chips.primary.toVisibilityModel()
                                )
                                secondaryChipViewBinding.rootView.adjustVisibility(
                                    chips.secondary.toVisibilityModel()
                                launch {
                                    bindOngoingActivityChipsWithVisibility(
                                        viewModel,
                                        chips,
                                        primaryChipViewBinding,
                                        secondaryChipViewBinding,
                                    )
                                }
                            } else {
                                listener?.onOngoingActivityStatusChanged(
                                    hasPrimaryOngoingActivity =
@@ -312,6 +313,52 @@ constructor(
        }
    }

    /** Bind the (legacy) single primary ongoing activity chip with the status bar visibility */
    private suspend fun bindLegacyPrimaryOngoingActivityChipWithVisibility(
        viewModel: HomeStatusBarViewModel,
        primaryChipModel: OngoingActivityChipModel,
        primaryChipViewBinding: OngoingActivityChipViewBinding,
    ) {
        viewModel.canShowOngoingActivityChips.collectLatest { visible ->
            if (!visible) {
                primaryChipViewBinding.rootView.hide(shouldAnimateChange = false)
            } else {
                when (primaryChipModel) {
                    is OngoingActivityChipModel.Active -> {
                        primaryChipViewBinding.rootView.show(shouldAnimateChange = true)
                    }

                    is OngoingActivityChipModel.Inactive -> {
                        primaryChipViewBinding.rootView.hide(
                            state = View.GONE,
                            shouldAnimateChange = primaryChipModel.shouldAnimate,
                        )
                    }
                }
            }
        }
    }

    /** Bind the primary/secondary chips along with the home status bar's visibility */
    private suspend fun bindOngoingActivityChipsWithVisibility(
        viewModel: HomeStatusBarViewModel,
        chips: MultipleOngoingActivityChipsModelLegacy,
        primaryChipViewBinding: OngoingActivityChipViewBinding,
        secondaryChipViewBinding: OngoingActivityChipViewBinding,
    ) {
        viewModel.canShowOngoingActivityChips.collectLatest { canShow ->
            if (!canShow) {
                primaryChipViewBinding.rootView.hide(shouldAnimateChange = false)
                secondaryChipViewBinding.rootView.hide(shouldAnimateChange = false)
            } else {
                primaryChipViewBinding.rootView.adjustVisibility(chips.primary.toVisibilityModel())
                secondaryChipViewBinding.rootView.adjustVisibility(
                    chips.secondary.toVisibilityModel()
                )
            }
        }
    }

    private fun SystemEventAnimationState.isAnimatingChip() =
        when (this) {
            AnimatingIn,
@@ -374,43 +421,42 @@ constructor(
        if (visibility == View.INVISIBLE || visibility == View.GONE) {
            return
        }
        alpha = 0f
        visibility = state
    }

    // See CollapsedStatusBarFragment#hide.
    private fun View.hide(state: Int = View.INVISIBLE, shouldAnimateChange: Boolean) {
        animate().cancel()
        if (visibility == View.INVISIBLE || visibility == View.GONE) {
            return
        }
        val v = this
        v.animate().cancel()
        if (!shouldAnimateChange) {
            v.alpha = 0f
            v.visibility = state
            alpha = 0f
            visibility = state
            return
        }

        v.animate()
        animate()
            .alpha(0f)
            .setDuration(CollapsedStatusBarFragment.FADE_OUT_DURATION.toLong())
            .setStartDelay(0)
            .setInterpolator(Interpolators.ALPHA_OUT)
            .withEndAction { v.visibility = state }
            .withEndAction { visibility = state }
    }

    // See CollapsedStatusBarFragment#show.
    private fun View.show(shouldAnimateChange: Boolean) {
        if (visibility == View.VISIBLE) {
        animate().cancel()
        if (visibility == View.VISIBLE && alpha >= 1f) {
            return
        }
        val v = this
        v.animate().cancel()
        v.visibility = View.VISIBLE
        visibility = View.VISIBLE
        if (!shouldAnimateChange) {
            v.alpha = 1f
            alpha = 1f
            return
        }
        v.animate()
        animate()
            .alpha(1f)
            .setDuration(CollapsedStatusBarFragment.FADE_IN_DURATION.toLong())
            .setInterpolator(Interpolators.ALPHA_IN)
+12 −0
Original line number Diff line number Diff line
@@ -149,6 +149,9 @@ interface HomeStatusBarViewModel : Activatable {
     */
    val isHomeStatusBarAllowedByScene: StateFlow<Boolean>

    /** True if the home status bar is showing, and there is no HUN happening */
    val canShowOngoingActivityChips: Flow<Boolean>

    /** True if the operator name view is not hidden due to HUN or other visibility state */
    val shouldShowOperatorNameView: Flow<Boolean>
    val isClockVisible: Flow<VisibilityModel>
@@ -412,6 +415,15 @@ constructor(
            )
            .flowOn(bgDispatcher)

    override val canShowOngoingActivityChips: Flow<Boolean> =
        combine(
            isHomeStatusBarAllowed,
            keyguardInteractor.isSecureCameraActive,
            headsUpNotificationInteractor.statusBarHeadsUpStatus,
        ) { isHomeStatusBarAllowed, isSecureCameraActive, headsUpState ->
            isHomeStatusBarAllowed && !isSecureCameraActive && !headsUpState.isPinned
        }

    override val isClockVisible: Flow<VisibilityModel> =
        combine(
                shouldHomeStatusBarBeVisible,