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

Commit c9c0f670 authored by Evan Laird's avatar Evan Laird
Browse files

[sb] Expose a top-level `shouldHomeStatusBarBeVisible` flow

When inflating the top-level StatusBarRoot's AndroidView, everything is
visible at first and there is no way to hide it until all of the
view-binders start up.

The fix here is to allow for StatusBarRoot to watch for the top-level
visibility and hide the entire android view. Then when that value
changes, we can update it.

Also, add the case of HUN, which does require the status bar to be
showing.

Test: `adb shell kill com.android.systemui` with the flag on
Test: HomeStatusBarViewModelImplTest
Bug: 364360986
Flag: com.android.systemui.status_bar_root_modernization
Change-Id: I04cb436c1d2b63f4e24ab9588757be5941728c16
parent af694e91
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@ class FakeHomeStatusBarViewModel(

    override val isHomeStatusBarAllowedByScene = MutableStateFlow(false)

    override val shouldHomeStatusBarBeVisible = MutableStateFlow(false)

    override val shouldShowOperatorNameView = MutableStateFlow(false)

    override val isClockVisible =
+92 −0
Original line number Diff line number Diff line
@@ -574,6 +574,98 @@ class HomeStatusBarViewModelImplTest : SysuiTestCase() {
            assertThat(latest).isFalse()
        }

    @Test
    fun shouldHomeStatusBarBeVisible_keyguardNotGone_noHun_false() =
        kosmos.runTest {
            // Do not transition from keyguard. i.e., we don't call transitionKeyguardToGone()

            // Nothing disabled
            fakeDisableFlagsRepository.disableFlags.value =
                DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)

            val latest by collectLastValue(underTest.shouldHomeStatusBarBeVisible)
            assertThat(latest).isFalse()
        }

    @Test
    fun shouldHomeStatusBarBeVisible_keyguardNotGone_hun_true() =
        kosmos.runTest {
            // Keyguard gone
            transitionKeyguardToGone()

            // Nothing disabled
            fakeDisableFlagsRepository.disableFlags.value =
                DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)

            // there is an active HUN
            headsUpNotificationRepository.setNotifications(
                UnconfinedFakeHeadsUpRowRepository(
                    key = "key",
                    pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser),
                )
            )

            val latest by collectLastValue(underTest.shouldHomeStatusBarBeVisible)
            assertThat(latest).isTrue()
        }

    @Test
    fun shouldHomeStatusBarBeVisible_keyguardGone_noHun_notInCamera_true() =
        kosmos.runTest {
            // Keyguard gone
            transitionKeyguardToGone()

            // Nothing disabled
            fakeDisableFlagsRepository.disableFlags.value =
                DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)

            val latest by collectLastValue(underTest.shouldHomeStatusBarBeVisible)
            assertThat(latest).isTrue()
        }

    @Test
    fun shouldHomeStatusBarBeVisible_keyguardGone_hun_notInCamera_true() =
        kosmos.runTest {
            // Keyguard gone
            transitionKeyguardToGone()

            // Nothing disabled
            fakeDisableFlagsRepository.disableFlags.value =
                DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)

            // there is an active HUN
            headsUpNotificationRepository.setNotifications(
                UnconfinedFakeHeadsUpRowRepository(
                    key = "key",
                    pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser),
                )
            )

            val latest by collectLastValue(underTest.shouldHomeStatusBarBeVisible)
            assertThat(latest).isTrue()
        }

    @Test
    fun shouldHomeStatusBarBeVisible_keyguardGone_noHun_inCamera_false() =
        kosmos.runTest {
            // Keyguard gone
            transitionKeyguardToGone()

            // Nothing disabled
            fakeDisableFlagsRepository.disableFlags.value =
                DisableFlagsModel(DISABLE_NONE, DISABLE2_NONE)

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

            val latest by collectLastValue(underTest.shouldHomeStatusBarBeVisible)
            assertThat(latest).isFalse()
        }

    @Test
    fun isClockVisible_allowedByDisableFlags_visible() =
        kosmos.runTest {
+2 −0
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ object StatusBarRootModernization {
    /** Aconfig flag for removing the fragment */
    const val FLAG_NAME = Flags.FLAG_STATUS_BAR_ROOT_MODERNIZATION

    const val SHOW_DISAMBIGUATION = true

    /** A token used for dependency declaration */
    val token: FlagToken
        get() = FlagToken(FLAG_NAME, isEnabled)
+10 −1
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.view.isVisible
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.compose.theme.PlatformTheme
@@ -39,6 +40,7 @@ import com.android.keyguard.AlphaOptimizedLinearLayout
import com.android.systemui.plugins.DarkIconDispatcher
import com.android.systemui.res.R
import com.android.systemui.statusbar.chips.ui.compose.OngoingActivityChips
import com.android.systemui.statusbar.core.StatusBarRootModernization
import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore
import com.android.systemui.statusbar.events.domain.interactor.SystemStatusEventAnimationInteractor
import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips
@@ -146,6 +148,8 @@ fun StatusBarRoot(

        Row(Modifier.fillMaxSize()) {
            val scope = rememberCoroutineScope()
            val visible =
                statusBarViewModel.shouldHomeStatusBarBeVisible.collectAsStateWithLifecycle(false)
            AndroidView(
                factory = { context ->
                    val inflater = LayoutInflater.from(context)
@@ -280,7 +284,12 @@ fun StatusBarRoot(
                    }
                    onViewCreated(phoneStatusBarView)
                    phoneStatusBarView
                }
                },
                update = { view ->
                    // Show or hide the entire status bar. This is important so that we aren't
                    // visible when first inflated
                    view.isVisible = visible.value
                },
            )
        }
    }
+9 −4
Original line number Diff line number Diff line
@@ -80,6 +80,9 @@ import kotlinx.coroutines.flow.stateIn
 * so that it's all in one place and easily testable outside of the fragment.
 */
interface HomeStatusBarViewModel {
    /** Should the entire status bar be hidden? */
    val shouldHomeStatusBarBeVisible: Flow<Boolean>

    /**
     * True if the device is currently transitioning from lockscreen to occluded and false
     * otherwise.
@@ -271,10 +274,12 @@ constructor(
            isHomeScreenStatusBarAllowedLegacy
        }

    private val shouldHomeStatusBarBeVisible =
        combine(isHomeStatusBarAllowed, keyguardInteractor.isSecureCameraActive) {
    override val shouldHomeStatusBarBeVisible =
        combine(
            isHomeStatusBarAllowed,
            isSecureCameraActive ->
            keyguardInteractor.isSecureCameraActive,
            headsUpNotificationInteractor.statusBarHeadsUpStatus,
        ) { isHomeStatusBarAllowed, isSecureCameraActive, headsUpState ->
            // When launching the camera over the lockscreen, the status icons would typically
            // become visible momentarily before animating out, since we're not yet aware that the
            // launching camera activity is fullscreen. Even once the activity finishes launching,
@@ -282,7 +287,7 @@ constructor(
            // tells us to hide them.
            // To ensure that this high-visibility animation is smooth, keep the icons hidden during
            // a camera launch. See b/257292822.
            isHomeStatusBarAllowed && !isSecureCameraActive
            headsUpState.isPinned || (isHomeStatusBarAllowed && !isSecureCameraActive)
        }

    private val isAnyChipVisible =