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

Commit 3a0cc824 authored by Darrell Shi's avatar Darrell Shi Committed by Android (Google) Code Review
Browse files

Merge "Disable device rotation on glanceable hub on mobile" into main

parents bdb52367 6832a9fd
Loading
Loading
Loading
Loading
+0 −19
Original line number Diff line number Diff line
package com.android.systemui.communal.ui.compose

import android.content.res.Configuration
import androidx.compose.animation.core.CubicBezierEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
@@ -17,7 +16,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
@@ -29,7 +27,6 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.semantics.clearAndSetSemantics
import androidx.compose.ui.semantics.disabled
@@ -303,20 +300,6 @@ fun CommunalContainer(
    Box(modifier = Modifier.fillMaxSize().allowGestures(touchesAllowed))
}

/** Listens to orientation changes on communal scene and reset when scene is disposed. */
@Composable
fun ObserveOrientationChange(viewModel: CommunalViewModel) {
    val configuration = LocalConfiguration.current

    LaunchedEffect(configuration.orientation) {
        viewModel.onOrientationChange(configuration.orientation)
    }

    DisposableEffect(Unit) {
        onDispose { viewModel.onOrientationChange(Configuration.ORIENTATION_UNDEFINED) }
    }
}

/** Scene containing the glanceable hub UI. */
@Composable
fun ContentScope.CommunalScene(
@@ -329,8 +312,6 @@ fun ContentScope.CommunalScene(
) {
    val isFocusable by viewModel.isFocusable.collectAsStateWithLifecycle(initialValue = false)

    // Observe screen rotation while Communal Scene is active.
    ObserveOrientationChange(viewModel)
    Box(
        modifier =
            Modifier.element(Communal.Elements.Scrim)
+0 −113
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import android.provider.Settings
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.internal.logging.uiEventLoggerFake
import com.android.systemui.Flags.FLAG_COMMUNAL_HUB
import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
@@ -39,13 +38,8 @@ import com.android.systemui.flags.Flags.COMMUNAL_SERVICE_ENABLED
import com.android.systemui.flags.andSceneContainer
import com.android.systemui.flags.fakeFeatureFlagsClassic
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
import com.android.systemui.kosmos.collectLastValue
@@ -62,15 +56,11 @@ import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.advanceTimeBy
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.kotlin.verify
import platform.test.runner.parameterized.ParameterizedAndroidJunit4
import platform.test.runner.parameterized.Parameters

@@ -103,12 +93,10 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase()
                communalInteractor = communalInteractor,
                communalSettingsInteractor = communalSettingsInteractor,
                communalSceneInteractor = communalSceneInteractor,
                keyguardTransitionInteractor = keyguardTransitionInteractor,
                keyguardInteractor = keyguardInteractor,
                systemSettings = fakeSettings,
                notificationShadeWindowController = notificationShadeWindowController,
                bgScope = applicationCoroutineScope,
                applicationScope = applicationCoroutineScope,
                mainDispatcher = testDispatcher,
                uiEventLogger = uiEventLoggerFake,
            )
@@ -426,107 +414,6 @@ class CommunalSceneStartableTest(flags: FlagsParameterization) : SysuiTestCase()
            assertThat(uiEventLoggerFake.numLogs()).isEqualTo(1)
        }

    @Test
    @DisableFlags(FLAG_SCENE_CONTAINER)
    @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
    fun glanceableHubOrientationAware_idleOnCommunal() =
        kosmos.runTest {
            communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")

            val scene by collectLastValue(communalSceneInteractor.currentScene)
            assertThat(scene).isEqualTo(CommunalScenes.Communal)

            verify(notificationShadeWindowController).setGlanceableHubOrientationAware(true)
        }

    @Test
    @DisableFlags(FLAG_SCENE_CONTAINER)
    @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
    fun glanceableHubOrientationAware_transitioningToCommunal() =
        kosmos.runTest {
            val progress = MutableStateFlow(0f)
            val targetScene = CommunalScenes.Communal
            val currentScene = CommunalScenes.Blank
            val transitionState =
                MutableStateFlow(
                    ObservableTransitionState.Transition(
                        fromScene = currentScene,
                        toScene = targetScene,
                        currentScene = flowOf(targetScene),
                        progress = progress,
                        isInitiatedByUserInput = false,
                        isUserInputOngoing = flowOf(false),
                    )
                )
            communalSceneInteractor.setTransitionState(transitionState)

            // Partially transition.
            progress.value = .4f

            val scene by collectLastValue(communalSceneInteractor.currentScene)
            assertThat(scene).isEqualTo(CommunalScenes.Blank)

            verify(notificationShadeWindowController).setGlanceableHubOrientationAware(true)
        }

    @Test
    @DisableFlags(FLAG_SCENE_CONTAINER)
    @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
    fun glanceableHubOrientationAware_communalToDreaming() =
        kosmos.runTest {
            communalSceneInteractor.changeScene(CommunalScenes.Communal, "test")

            verify(notificationShadeWindowController).setGlanceableHubOrientationAware(true)
            Mockito.clearInvocations(notificationShadeWindowController)

            val progress = MutableStateFlow(0f)
            val currentScene = CommunalScenes.Communal
            val targetScene = CommunalScenes.Blank
            val transitionState =
                MutableStateFlow(
                    ObservableTransitionState.Transition(
                        fromScene = currentScene,
                        toScene = targetScene,
                        currentScene = flowOf(targetScene),
                        progress = progress,
                        isInitiatedByUserInput = false,
                        isUserInputOngoing = flowOf(false),
                    )
                )
            communalSceneInteractor.setTransitionState(transitionState)

            // Partially transitioned out of Communal scene
            progress.value = .4f

            // Started keyguard transitioning from hub -> dreaming.
            fakeKeyguardTransitionRepository.sendTransitionStep(
                TransitionStep(
                    from = KeyguardState.GLANCEABLE_HUB,
                    to = KeyguardState.DREAMING,
                    transitionState = TransitionState.STARTED,
                )
            )
            verify(notificationShadeWindowController).setGlanceableHubOrientationAware(true)
            Mockito.clearInvocations(notificationShadeWindowController)

            fakeKeyguardTransitionRepository.sendTransitionStep(
                from = KeyguardState.GLANCEABLE_HUB,
                to = KeyguardState.DREAMING,
                transitionState = TransitionState.RUNNING,
                value = 0.5f,
            )

            // Transitioned to dreaming.
            fakeKeyguardTransitionRepository.sendTransitionStep(
                from = KeyguardState.GLANCEABLE_HUB,
                to = KeyguardState.DREAMING,
                transitionState = TransitionState.FINISHED,
                value = 1f,
            )
            // Not on hub anymore, let other states take control
            verify(notificationShadeWindowController).setGlanceableHubOrientationAware(false)
        }

    /**
     * Advances time by duration + 1 millisecond, to ensure that tasks scheduled to run at
     * currentTime + duration are scheduled.
+2 −0
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ import com.android.systemui.log.logcatLogBuffer
import com.android.systemui.media.controls.ui.controller.mediaCarouselController
import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.settings.fakeUserTracker
import com.android.systemui.statusbar.policy.keyguardStateController
import com.android.systemui.testKosmos
import com.android.systemui.user.data.repository.fakeUserRepository
import com.google.common.truth.Truth.assertThat
@@ -95,6 +96,7 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
                communalInteractor,
                communalSettingsInteractor,
                keyguardTransitionInteractor,
                keyguardStateController,
                mock<MediaHost>(),
                uiEventLogger,
                logcatLogBuffer("CommunalEditModeViewModelTest"),
+0 −29
Original line number Diff line number Diff line
@@ -29,17 +29,10 @@ import com.android.systemui.communal.shared.model.CommunalScenes
import com.android.systemui.communal.shared.model.CommunalScenes.isCommunal
import com.android.systemui.communal.shared.model.CommunalTransitionKeys
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
import com.android.systemui.keyguard.shared.model.KeyguardState.GLANCEABLE_HUB
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.NotificationShadeWindowController
import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf
import com.android.systemui.util.kotlin.emitOnStart
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.settings.SettingsProxyExt.observerFlow
@@ -52,7 +45,6 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.withContext
@@ -68,12 +60,10 @@ constructor(
    private val communalInteractor: CommunalInteractor,
    private val communalSettingsInteractor: CommunalSettingsInteractor,
    private val communalSceneInteractor: CommunalSceneInteractor,
    private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
    private val keyguardInteractor: KeyguardInteractor,
    private val systemSettings: SystemSettings,
    private val notificationShadeWindowController: NotificationShadeWindowController,
    @Background private val bgScope: CoroutineScope,
    @Application private val applicationScope: CoroutineScope,
    @Main private val mainDispatcher: CoroutineDispatcher,
    private val uiEventLogger: UiEventLogger,
) : CoreStartable {
@@ -164,25 +154,6 @@ constructor(
                    }
            }
        }

        if (communalSettingsInteractor.isV2FlagEnabled()) {
            applicationScope.launch(context = mainDispatcher) {
                anyOf(
                        communalSceneInteractor.isTransitioningToOrIdleOnCommunal,
                        // when transitioning from hub to dream, allow hub to stay at the current
                        // orientation, as keyguard doesn't allow rotation by default.
                        keyguardTransitionInteractor.isInTransition(
                            edge = Edge.create(from = Scenes.Communal, to = DREAMING),
                            edgeWithoutSceneContainer =
                                Edge.create(from = GLANCEABLE_HUB, to = DREAMING),
                        ),
                    )
                    .distinctUntilChanged()
                    .collectLatest {
                        notificationShadeWindowController.setGlanceableHubOrientationAware(it)
                    }
            }
        }
    }

    private fun cancelHubTimeout() {
+5 −0
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ import com.android.systemui.media.controls.ui.view.MediaHost
import com.android.systemui.media.dagger.MediaModule
import com.android.systemui.res.R
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf
import com.android.systemui.util.kotlin.BooleanFlowOperators.not
import javax.inject.Inject
@@ -73,6 +74,7 @@ constructor(
    private val communalInteractor: CommunalInteractor,
    private val communalSettingsInteractor: CommunalSettingsInteractor,
    keyguardTransitionInteractor: KeyguardTransitionInteractor,
    private val keyguardStateController: KeyguardStateController,
    @Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost,
    private val uiEventLogger: UiEventLogger,
    @CommunalLog logBuffer: LogBuffer,
@@ -281,6 +283,9 @@ constructor(
        persistScrollPosition()
    }

    /** Whether screen rotation is allowed. If false, screen orientation should remain portrait. */
    fun isScreenRotationAllowed(): Boolean = keyguardStateController.isKeyguardScreenRotationAllowed

    companion object {
        private const val TAG = "CommunalEditModeViewModel"

Loading