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

Commit 8bff5c38 authored by burakov's avatar burakov Committed by Julia Tuttle
Browse files

[bc25] Take overlays into account when updating StatusBarState.

Bug: 356596436
Bug: 359173565
Flag: com.android.systemui.scene_container
Flag: com.android.systemui.dual_shade
Test: Added unit tests.
Test: Existing unit tests still pass.
Change-Id: Ife2a0f0fe14dba2da99b1d09dc65e0411998488f
parent 5c5bc294
Loading
Loading
Loading
Loading
+94 −38
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@
package com.android.systemui.statusbar

import android.animation.ObjectAnimator
import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import android.testing.TestableLooper
import androidx.test.filters.SmallTest
@@ -47,8 +49,10 @@ import com.android.systemui.scene.data.repository.setTransition
import com.android.systemui.scene.domain.interactor.sceneBackInteractor
import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.domain.interactor.shadeInteractor
import com.android.systemui.shade.shared.flag.DualShade
import com.android.systemui.statusbar.domain.interactor.keyguardOcclusionInteractor
import com.android.systemui.testKosmos
import com.android.systemui.util.kotlin.JavaAdapter
@@ -79,6 +83,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest

    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val sceneInteractor = kosmos.sceneInteractor
    private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
    private val mockDarkAnimator = mock<ObjectAnimator>()

@@ -229,14 +234,15 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest
    @Test
    fun testSetDreamState_getterReturnsCurrentState() {
        underTest.setIsDreaming(true)
        assertTrue(underTest.isDreaming())
        assertTrue(underTest.isDreaming)

        underTest.setIsDreaming(false)
        assertFalse(underTest.isDreaming())
        assertFalse(underTest.isDreaming)
    }

    @Test
    @EnableSceneContainer
    @DisableFlags(DualShade.FLAG_NAME)
    fun start_hydratesStatusBarState_whileLocked() =
        testScope.runTest {
            var statusBarState = underTest.state
@@ -248,7 +254,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest
                }
            underTest.addCallback(listener)

            val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene)
            val currentScene by collectLastValue(sceneInteractor.currentScene)
            val deviceUnlockStatus by
                collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus)

@@ -258,45 +264,107 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest
            runCurrent()
            assertThat(deviceUnlockStatus!!.isUnlocked).isFalse()

            kosmos.sceneInteractor.changeScene(
                toScene = Scenes.Lockscreen,
                loggingReason = "reason"
            )
            sceneInteractor.changeScene(toScene = Scenes.Lockscreen, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)

            // Call start to begin hydrating based on the scene framework:
            underTest.start()

            kosmos.sceneInteractor.changeScene(toScene = Scenes.Bouncer, loggingReason = "reason")
            sceneInteractor.changeScene(toScene = Scenes.Bouncer, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
            assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD)

            kosmos.sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason")
            sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Shade)
            assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED)

            kosmos.sceneInteractor.changeScene(
                toScene = Scenes.QuickSettings,
                loggingReason = "reason"
            )
            sceneInteractor.changeScene(toScene = Scenes.QuickSettings, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
            assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED)

            kosmos.sceneInteractor.changeScene(toScene = Scenes.Communal, loggingReason = "reason")
            sceneInteractor.changeScene(toScene = Scenes.Communal, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Communal)
            assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD)

            kosmos.sceneInteractor.changeScene(
                toScene = Scenes.Lockscreen,
                loggingReason = "reason"
            sceneInteractor.changeScene(toScene = Scenes.Lockscreen, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
            assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD)
        }

    @Test
    @EnableSceneContainer
    @EnableFlags(DualShade.FLAG_NAME)
    fun start_hydratesStatusBarState_dualShade_whileLocked() =
        testScope.runTest {
            var statusBarState = underTest.state
            val listener =
                object : StatusBarStateController.StateListener {
                    override fun onStateChanged(newState: Int) {
                        statusBarState = newState
                    }
                }
            underTest.addCallback(listener)

            val currentScene by collectLastValue(sceneInteractor.currentScene)
            val currentOverlays by collectLastValue(sceneInteractor.currentOverlays)
            val deviceUnlockStatus by
                collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus)

            kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
                AuthenticationMethodModel.Password
            )
            runCurrent()
            assertThat(deviceUnlockStatus!!.isUnlocked).isFalse()

            sceneInteractor.changeScene(Scenes.Lockscreen, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)

            // Call start to begin hydrating based on the scene framework:
            underTest.start()

            sceneInteractor.changeScene(Scenes.Bouncer, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Bouncer)
            assertThat(currentOverlays).isEmpty()
            assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD)

            sceneInteractor.changeScene(Scenes.Lockscreen, loggingReason = "reason")
            runCurrent()

            sceneInteractor.showOverlay(Overlays.NotificationsShade, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
            assertThat(currentOverlays).containsExactly(Overlays.NotificationsShade)
            assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED)

            sceneInteractor.replaceOverlay(
                from = Overlays.NotificationsShade,
                to = Overlays.QuickSettingsShade,
                loggingReason = "reason",
            )
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
            assertThat(currentOverlays).containsExactly(Overlays.QuickSettingsShade)
            assertThat(statusBarState).isEqualTo(StatusBarState.SHADE_LOCKED)

            sceneInteractor.hideOverlay(Overlays.QuickSettingsShade, loggingReason = "reason")
            sceneInteractor.changeScene(Scenes.Communal, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Communal)
            assertThat(currentOverlays).isEmpty()
            assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD)

            sceneInteractor.changeScene(Scenes.Lockscreen, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
            assertThat(currentOverlays).isEmpty()
            assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD)
        }

@@ -313,7 +381,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest
                }
            underTest.addCallback(listener)

            val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene)
            val currentScene by collectLastValue(sceneInteractor.currentScene)
            val deviceUnlockStatus by
                collectLastValue(kosmos.deviceUnlockedInteractor.deviceUnlockStatus)
            kosmos.fakeAuthenticationRepository.setAuthenticationMethod(
@@ -326,10 +394,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest

            assertThat(deviceUnlockStatus!!.isUnlocked).isTrue()

            kosmos.sceneInteractor.changeScene(
                toScene = Scenes.Lockscreen,
                loggingReason = "reason"
            )
            sceneInteractor.changeScene(toScene = Scenes.Lockscreen, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)

@@ -339,20 +404,17 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest

            assertThat(statusBarState).isEqualTo(StatusBarState.KEYGUARD)

            kosmos.sceneInteractor.changeScene(toScene = Scenes.Gone, loggingReason = "reason")
            sceneInteractor.changeScene(toScene = Scenes.Gone, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Gone)
            assertThat(statusBarState).isEqualTo(StatusBarState.SHADE)

            kosmos.sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason")
            sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Shade)
            assertThat(statusBarState).isEqualTo(StatusBarState.SHADE)

            kosmos.sceneInteractor.changeScene(
                toScene = Scenes.QuickSettings,
                loggingReason = "reason"
            )
            sceneInteractor.changeScene(toScene = Scenes.QuickSettings, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
            assertThat(statusBarState).isEqualTo(StatusBarState.SHADE)
@@ -371,7 +433,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest
                }
            underTest.addCallback(listener)

            val currentScene by collectLastValue(kosmos.sceneInteractor.currentScene)
            val currentScene by collectLastValue(sceneInteractor.currentScene)
            assertThat(currentScene).isEqualTo(Scenes.Lockscreen)
            val isOccluded by
                collectLastValue(kosmos.sceneContainerOcclusionInteractor.invisibleDueToOcclusion)
@@ -385,15 +447,12 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest
            // Call start to begin hydrating based on the scene framework:
            underTest.start()

            kosmos.sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason")
            sceneInteractor.changeScene(toScene = Scenes.Shade, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.Shade)
            assertThat(statusBarState).isEqualTo(StatusBarState.SHADE)

            kosmos.sceneInteractor.changeScene(
                toScene = Scenes.QuickSettings,
                loggingReason = "reason"
            )
            sceneInteractor.changeScene(toScene = Scenes.QuickSettings, loggingReason = "reason")
            runCurrent()
            assertThat(currentScene).isEqualTo(Scenes.QuickSettings)
            assertThat(statusBarState).isEqualTo(StatusBarState.SHADE)
@@ -415,10 +474,7 @@ class StatusBarStateControllerImplTest(flags: FlagsParameterization) : SysuiTest
            kosmos.setTransition(
                sceneTransition = Idle(Scenes.Gone),
                stateTransition =
                    TransitionStep(
                        from = KeyguardState.LOCKSCREEN,
                        to = KeyguardState.GONE,
                    )
                    TransitionStep(from = KeyguardState.LOCKSCREEN, to = KeyguardState.GONE),
            )

            assertThat(underTest.leaveOpenOnKeyguardHide()).isEqualTo(false)
+14 −4
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.view.animation.Interpolator;
import androidx.annotation.NonNull;

import com.android.app.animation.Interpolators;
import com.android.compose.animation.scene.OverlayKey;
import com.android.compose.animation.scene.SceneKey;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -60,6 +61,7 @@ import com.android.systemui.scene.domain.interactor.SceneBackInteractor;
import com.android.systemui.scene.domain.interactor.SceneContainerOcclusionInteractor;
import com.android.systemui.scene.domain.interactor.SceneInteractor;
import com.android.systemui.scene.shared.flag.SceneContainerFlag;
import com.android.systemui.scene.shared.model.Overlays;
import com.android.systemui.scene.shared.model.Scenes;
import com.android.systemui.shade.domain.interactor.ShadeInteractor;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
@@ -75,6 +77,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;

import javax.inject.Inject;

@@ -230,6 +233,7 @@ public class StatusBarStateControllerImpl implements
                    combineFlows(
                        mDeviceUnlockedInteractorLazy.get().getDeviceUnlockStatus(),
                        mSceneInteractorLazy.get().getCurrentScene(),
                        mSceneInteractorLazy.get().getCurrentOverlays(),
                        mSceneBackInteractorLazy.get().getBackStack(),
                        mSceneContainerOcclusionInteractorLazy.get().getInvisibleDueToOcclusion(),
                        this::calculateStateFromSceneFramework),
@@ -690,19 +694,25 @@ public class StatusBarStateControllerImpl implements
    private int calculateStateFromSceneFramework(
            DeviceUnlockStatus deviceUnlockStatus,
            SceneKey currentScene,
            Set<OverlayKey> currentOverlays,
            SceneStack backStack,
            boolean isOccluded) {
        SceneContainerFlag.isUnexpectedlyInLegacyMode();
        if (currentScene.equals(Scenes.Lockscreen)) {
            if (currentOverlays.contains(Overlays.NotificationsShade) || currentOverlays.contains(
                    Overlays.QuickSettingsShade)) {
                return StatusBarState.SHADE_LOCKED;
            }
            return StatusBarState.KEYGUARD;
        } else if (currentScene.equals(Scenes.Shade)
        }
        if (currentScene.equals(Scenes.Shade)
                && SceneStackKt.contains(backStack, Scenes.Lockscreen)) {
            return StatusBarState.SHADE_LOCKED;
        } else if (deviceUnlockStatus.isUnlocked() || isOccluded) {
        }
        if (deviceUnlockStatus.isUnlocked() || isOccluded) {
            return StatusBarState.SHADE;
        } else {
            return Preconditions.checkNotNull(sStatusBarStateByLockedSceneKey.get(currentScene));
        }
        return Preconditions.checkNotNull(sStatusBarStateByLockedSceneKey.get(currentScene));
    }

    /** Notifies that the {@link StatusBarState} has changed to the given new state. */
+16 −12
Original line number Diff line number Diff line
@@ -39,11 +39,7 @@ import kotlinx.coroutines.launch

/** A class allowing Java classes to collect on Kotlin flows. */
@SysUISingleton
class JavaAdapter
@Inject
constructor(
    @Application private val scope: CoroutineScope,
) {
class JavaAdapter @Inject constructor(@Application private val scope: CoroutineScope) {
    /**
     * Collect information for the given [flow], calling [consumer] for each emitted event.
     *
@@ -55,10 +51,7 @@ constructor(
     * Do *not* call this method in a class's constructor. Instead, call it in
     * [com.android.systemui.CoreStartable.start] or similar method.
     */
    fun <T> alwaysCollectFlow(
        flow: Flow<T>,
        consumer: Consumer<T>,
    ): Job {
    fun <T> alwaysCollectFlow(flow: Flow<T>, consumer: Consumer<T>): Job {
        return scope.launch { flow.collect { consumer.accept(it) } }
    }

@@ -66,7 +59,7 @@ constructor(
    fun <T> stateInApp(
        flow: Flow<T>,
        initialValue: T,
        started: SharingStarted = SharingStarted.Eagerly
        started: SharingStarted = SharingStarted.Eagerly,
    ): StateFlow<T> {
        return flow.stateIn(scope, started, initialValue)
    }
@@ -117,7 +110,7 @@ fun <A, B, C, R> combineFlows(
    flow1: Flow<A>,
    flow2: Flow<B>,
    flow3: Flow<C>,
    trifunction: (A, B, C) -> R
    trifunction: (A, B, C) -> R,
): Flow<R> {
    return combine(flow1, flow2, flow3, trifunction)
}
@@ -127,7 +120,18 @@ fun <T1, T2, T3, T4, R> combineFlows(
    flow2: Flow<T2>,
    flow3: Flow<T3>,
    flow4: Flow<T4>,
    transform: (T1, T2, T3, T4) -> R
    transform: (T1, T2, T3, T4) -> R,
): Flow<R> {
    return combine(flow, flow2, flow3, flow4, transform)
}

fun <T1, T2, T3, T4, T5, R> combineFlows(
    flow: Flow<T1>,
    flow2: Flow<T2>,
    flow3: Flow<T3>,
    flow4: Flow<T4>,
    flow5: Flow<T5>,
    transform: (T1, T2, T3, T4, T5) -> R,
): Flow<R> {
    return combine(flow, flow2, flow3, flow4, flow5, transform)
}