diff options
| author | 2025-01-31 20:56:51 -0800 | |
|---|---|---|
| committer | 2025-01-31 20:56:51 -0800 | |
| commit | cacd557c781996a092faca122ae2f95389f6b377 (patch) | |
| tree | 7f739fcb657db59ab69c7de0560e4eac0d8c18f3 | |
| parent | abccf87d9fb33e87e105abbca35f921535eb19ed (diff) | |
| parent | b3d5a84ac5bf4c3a346a1d266c425053b33346cc (diff) | |
Merge changes I5a85e152,Iaa9f6743 into main
* changes:
Allow showing hub immediately on view load
Resolve circular dependency
| -rw-r--r-- | packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt | 3 | ||||
| -rw-r--r-- | packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSceneRepositoryImplTest.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt) | 60 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java | 6 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt | 44 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt | 23 | ||||
| -rw-r--r-- | packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt | 2 | ||||
| -rw-r--r-- | packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java | 3 | ||||
| -rw-r--r-- | packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt | 7 |
8 files changed, 119 insertions, 29 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt index 3ffbabb09710..4a4607b6e8fc 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt @@ -159,8 +159,7 @@ fun CommunalContainer( content: CommunalContent, ) { val coroutineScope = rememberCoroutineScope() - val currentSceneKey: SceneKey by - viewModel.currentScene.collectAsStateWithLifecycle(CommunalScenes.Blank) + val currentSceneKey: SceneKey by viewModel.currentScene.collectAsStateWithLifecycle() val touchesAllowed by viewModel.touchesAllowed.collectAsStateWithLifecycle() val backgroundType by viewModel.communalBackground.collectAsStateWithLifecycle( diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSceneRepositoryImplTest.kt index fd0bf4dae198..293d32471713 100644 --- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalRepositoryImplTest.kt +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/data/repository/CommunalSceneRepositoryImplTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 The Android Open Source Project + * Copyright (C) 2025 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,34 +21,44 @@ import androidx.test.filters.SmallTest import com.android.compose.animation.scene.ObservableTransitionState import com.android.systemui.SysuiTestCase import com.android.systemui.communal.shared.model.CommunalScenes -import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository +import com.android.systemui.kosmos.Kosmos import com.android.systemui.kosmos.applicationCoroutineScope -import com.android.systemui.kosmos.testScope -import com.android.systemui.scene.shared.model.sceneDataSource +import com.android.systemui.kosmos.backgroundScope +import com.android.systemui.kosmos.collectLastValue +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.scene.shared.model.SceneDataSource +import com.android.systemui.scene.shared.model.SceneDataSourceDelegator import com.android.systemui.testKosmos import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.flow.flowOf -import kotlinx.coroutines.test.runTest import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.mock +import org.mockito.kotlin.verify @SmallTest @RunWith(AndroidJUnit4::class) -class CommunalRepositoryImplTest : SysuiTestCase() { +class CommunalSceneRepositoryImplTest : SysuiTestCase() { + private val kosmos = testKosmos().useUnconfinedTestDispatcher() - private val kosmos = testKosmos() - private val testScope = kosmos.testScope - private val underTest by lazy { - CommunalSceneRepositoryImpl( - kosmos.applicationCoroutineScope, - kosmos.applicationCoroutineScope, - kosmos.sceneDataSource, - ) - } + private val delegator = mock<SceneDataSourceDelegator> {} + + private val Kosmos.underTest by + Kosmos.Fixture { + CommunalSceneRepositoryImpl( + applicationScope = applicationCoroutineScope, + backgroundScope = backgroundScope, + sceneDataSource = delegator, + delegator = delegator, + ) + } @Test fun transitionState_idleByDefault() = - testScope.runTest { + kosmos.runTest { val transitionState by collectLastValue(underTest.transitionState) assertThat(transitionState) .isEqualTo(ObservableTransitionState.Idle(CommunalScenes.Default)) @@ -56,7 +66,7 @@ class CommunalRepositoryImplTest : SysuiTestCase() { @Test fun transitionState_setTransitionState_returnsNewValue() = - testScope.runTest { + kosmos.runTest { val expectedSceneKey = CommunalScenes.Communal underTest.setTransitionState(flowOf(ObservableTransitionState.Idle(expectedSceneKey))) @@ -66,7 +76,7 @@ class CommunalRepositoryImplTest : SysuiTestCase() { @Test fun transitionState_setNullTransitionState_returnsDefaultValue() = - testScope.runTest { + kosmos.runTest { // Set a value for the transition state flow. underTest.setTransitionState( flowOf(ObservableTransitionState.Idle(CommunalScenes.Communal)) @@ -80,4 +90,18 @@ class CommunalRepositoryImplTest : SysuiTestCase() { assertThat(transitionState) .isEqualTo(ObservableTransitionState.Idle(CommunalScenes.Default)) } + + @Test + fun showHubFromPowerButton() = + kosmos.runTest { + fakeKeyguardRepository.setKeyguardShowing(false) + + underTest.showHubFromPowerButton() + + argumentCaptor<SceneDataSource>().apply { + verify(delegator).setDelegate(capture()) + + assertThat(firstValue.currentScene.value).isEqualTo(CommunalScenes.Communal) + } + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index c266a5b47cff..0b66a0ffb711 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -296,7 +296,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab private final Provider<JavaAdapter> mJavaAdapter; private final Provider<SceneInteractor> mSceneInteractor; private final Provider<AlternateBouncerInteractor> mAlternateBouncerInteractor; - private final CommunalSceneInteractor mCommunalSceneInteractor; + private final Provider<CommunalSceneInteractor> mCommunalSceneInteractor; private final AuthController mAuthController; private final UiEventLogger mUiEventLogger; private final Set<String> mAllowFingerprintOnOccludingActivitiesFromPackage; @@ -2210,7 +2210,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab Provider<AlternateBouncerInteractor> alternateBouncerInteractor, Provider<JavaAdapter> javaAdapter, Provider<SceneInteractor> sceneInteractor, - CommunalSceneInteractor communalSceneInteractor) { + Provider<CommunalSceneInteractor> communalSceneInteractor) { mContext = context; mSubscriptionManager = subscriptionManager; mUserTracker = userTracker; @@ -2543,7 +2543,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab if (glanceableHubV2()) { mJavaAdapter.get().alwaysCollectFlow( - mCommunalSceneInteractor.isCommunalVisible(), + mCommunalSceneInteractor.get().isCommunalVisible(), this::onCommunalShowingChanged ); } diff --git a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt index 643d185f1939..8b6322720118 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/data/repository/CommunalSceneRepository.kt @@ -16,7 +16,9 @@ package com.android.systemui.communal.data.repository +import com.android.app.tracing.coroutines.launchTraced as launch import com.android.compose.animation.scene.ObservableTransitionState +import com.android.compose.animation.scene.OverlayKey import com.android.compose.animation.scene.SceneKey import com.android.compose.animation.scene.TransitionKey import com.android.systemui.communal.dagger.Communal @@ -25,16 +27,17 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.scene.shared.model.SceneDataSource +import com.android.systemui.scene.shared.model.SceneDataSourceDelegator import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.stateIn -import com.android.app.tracing.coroutines.launchTraced as launch /** Encapsulates the state of communal mode. */ interface CommunalSceneRepository { @@ -52,6 +55,9 @@ interface CommunalSceneRepository { /** Immediately snaps to the desired scene. */ fun snapToScene(toScene: SceneKey) + /** Shows the hub from a power button press. */ + suspend fun showHubFromPowerButton() + /** * Updates the transition state of the hub [SceneTransitionLayout]. * @@ -67,6 +73,7 @@ constructor( @Application private val applicationScope: CoroutineScope, @Background backgroundScope: CoroutineScope, @Communal private val sceneDataSource: SceneDataSource, + @Communal private val delegator: SceneDataSourceDelegator, ) : CommunalSceneRepository { override val currentScene: StateFlow<SceneKey> = sceneDataSource.currentScene @@ -98,6 +105,18 @@ constructor( } } + override suspend fun showHubFromPowerButton() { + // If keyguard is not showing yet, the hub view is not ready and the + // [SceneDataSourceDelegator] will still be using the default [NoOpSceneDataSource] + // and initial key, which is Blank. This means that when the hub container loads, it + // will default to not showing the hub. Attempting to set the scene in this state + // is simply ignored by the [NoOpSceneDataSource]. Instead, we temporarily override + // it with a new one that defaults to Communal. This delegate will be overwritten + // once the [CommunalContainer] loads. + // TODO(b/392969914): show the hub first instead of forcing the scene. + delegator.setDelegate(NoOpSceneDataSource(CommunalScenes.Communal)) + } + /** * Updates the transition state of the hub [SceneTransitionLayout]. * @@ -106,4 +125,27 @@ constructor( override fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) { _transitionState.value = transitionState } + + /** Noop implementation of a scene data source that always returns the initial [SceneKey]. */ + private class NoOpSceneDataSource(initialSceneKey: SceneKey) : SceneDataSource { + override val currentScene: StateFlow<SceneKey> = + MutableStateFlow(initialSceneKey).asStateFlow() + + override val currentOverlays: StateFlow<Set<OverlayKey>> = + MutableStateFlow(emptySet<OverlayKey>()).asStateFlow() + + override fun changeScene(toScene: SceneKey, transitionKey: TransitionKey?) = Unit + + override fun snapToScene(toScene: SceneKey) = Unit + + override fun showOverlay(overlay: OverlayKey, transitionKey: TransitionKey?) = Unit + + override fun hideOverlay(overlay: OverlayKey, transitionKey: TransitionKey?) = Unit + + override fun replaceOverlay( + from: OverlayKey, + to: OverlayKey, + transitionKey: TransitionKey?, + ) = Unit + } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt index 476493225857..3d9e93036dbc 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneInteractor.kt @@ -148,6 +148,29 @@ constructor( } } + fun showHubFromPowerButton() { + val loggingReason = "showing hub from power button" + applicationScope.launch("$TAG#showHubFromPowerButton") { + if (SceneContainerFlag.isEnabled) { + sceneInteractor.changeScene( + toScene = CommunalScenes.Communal.toSceneContainerSceneKey(), + loggingReason = loggingReason, + ) + return@launch + } + + if (currentScene.value == CommunalScenes.Communal) return@launch + logger.logSceneChangeRequested( + from = currentScene.value, + to = CommunalScenes.Communal, + reason = loggingReason, + isInstant = true, + ) + notifyListeners(CommunalScenes.Communal, null) + repository.showHubFromPowerButton() + } + } + private fun notifyListeners(newScene: SceneKey, keyguardState: KeyguardState?) { onSceneAboutToChangeListener.forEach { it.onSceneAboutToChange(newScene, keyguardState) } } diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt index 099a85926020..49003a735fbd 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt @@ -45,7 +45,7 @@ abstract class BaseCommunalViewModel( val mediaHost: MediaHost, val mediaCarouselController: MediaCarouselController, ) { - val currentScene: Flow<SceneKey> = communalSceneInteractor.currentScene + val currentScene: StateFlow<SceneKey> = communalSceneInteractor.currentScene /** Used to animate showing or hiding the communal content. */ open val isCommunalContentVisible: Flow<Boolean> = MutableStateFlow(false) diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 312d2ffd74e4..4110a05170b3 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -18,7 +18,6 @@ package com.android.keyguard; import static android.app.StatusBarManager.SESSION_KEYGUARD; import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; -import static android.hardware.biometrics.BiometricAuthenticator.TYPE_ANY_BIOMETRIC; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE; import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT; import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT; @@ -2717,7 +2716,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { () -> mAlternateBouncerInteractor, () -> mJavaAdapter, () -> mSceneInteractor, - mCommunalSceneInteractor); + () -> mCommunalSceneInteractor); setAlternateBouncerVisibility(false); setPrimaryBouncerVisibility(false); setStrongAuthTracker(KeyguardUpdateMonitorTest.this.mStrongAuthTracker); diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt index b3c1411243c1..3f35bb9f3520 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/communal/data/repository/FakeCommunalSceneRepository.kt @@ -17,8 +17,7 @@ import kotlinx.coroutines.launch /** Fake implementation of [CommunalSceneRepository]. */ class FakeCommunalSceneRepository( private val applicationScope: CoroutineScope, - override val currentScene: MutableStateFlow<SceneKey> = - MutableStateFlow(CommunalScenes.Default), + override val currentScene: MutableStateFlow<SceneKey> = MutableStateFlow(CommunalScenes.Default), ) : CommunalSceneRepository { override fun changeScene(toScene: SceneKey, transitionKey: TransitionKey?) = @@ -31,6 +30,10 @@ class FakeCommunalSceneRepository( } } + override suspend fun showHubFromPowerButton() { + snapToScene(CommunalScenes.Communal) + } + private val defaultTransitionState = ObservableTransitionState.Idle(CommunalScenes.Default) private val _transitionState = MutableStateFlow<Flow<ObservableTransitionState>?>(null) override val transitionState: StateFlow<ObservableTransitionState> = |