diff options
8 files changed, 204 insertions, 0 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt index 42bee4a3bdcd..7475c4251211 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt @@ -31,11 +31,13 @@ import com.android.systemui.doze.DozeMachine import com.android.systemui.doze.DozeTransitionCallback import com.android.systemui.doze.DozeTransitionListener import com.android.systemui.dreams.DreamOverlayCallbackController +import com.android.systemui.keyguard.ScreenLifecycle import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.BiometricUnlockSource import com.android.systemui.keyguard.shared.model.DozeStateModel import com.android.systemui.keyguard.shared.model.DozeTransitionModel +import com.android.systemui.keyguard.shared.model.ScreenModel import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -49,9 +51,11 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.flowOn @@ -148,6 +152,9 @@ interface KeyguardRepository { /** Observable for device wake/sleep state */ val wakefulness: StateFlow<WakefulnessModel> + /** Observable for device screen state */ + val screenModel: StateFlow<ScreenModel> + /** Observable for biometric unlock modes */ val biometricUnlockState: Flow<BiometricUnlockModel> @@ -163,6 +170,9 @@ interface KeyguardRepository { /** Whether quick settings or quick-quick settings is visible. */ val isQuickSettingsVisible: Flow<Boolean> + /** Receive an event for doze time tick */ + val dozeTimeTick: Flow<Unit> + /** * Returns `true` if the keyguard is showing; `false` otherwise. * @@ -204,6 +214,8 @@ interface KeyguardRepository { fun setIsDozing(isDozing: Boolean) fun setIsActiveDreamLockscreenHosted(isLockscreenHosted: Boolean) + + fun dozeTimeTick() } /** Encapsulates application state for the keyguard. */ @@ -213,6 +225,7 @@ class KeyguardRepositoryImpl constructor( statusBarStateController: StatusBarStateController, wakefulnessLifecycle: WakefulnessLifecycle, + screenLifecycle: ScreenLifecycle, biometricUnlockController: BiometricUnlockController, private val keyguardStateController: KeyguardStateController, private val keyguardBypassController: KeyguardBypassController, @@ -370,6 +383,13 @@ constructor( _isDozing.value = isDozing } + private val _dozeTimeTick = MutableSharedFlow<Unit>() + override val dozeTimeTick = _dozeTimeTick.asSharedFlow() + + override fun dozeTimeTick() { + _dozeTimeTick.tryEmit(Unit) + } + private val _lastDozeTapToWakePosition = MutableStateFlow<Point?>(null) override val lastDozeTapToWakePosition = _lastDozeTapToWakePosition.asStateFlow() @@ -559,6 +579,42 @@ constructor( initialValue = WakefulnessModel.fromWakefulnessLifecycle(wakefulnessLifecycle), ) + override val screenModel: StateFlow<ScreenModel> = + conflatedCallbackFlow { + val observer = + object : ScreenLifecycle.Observer { + override fun onScreenTurningOn() { + dispatchNewState() + } + override fun onScreenTurnedOn() { + dispatchNewState() + } + override fun onScreenTurningOff() { + dispatchNewState() + } + override fun onScreenTurnedOff() { + dispatchNewState() + } + + private fun dispatchNewState() { + trySendWithFailureLogging( + ScreenModel.fromScreenLifecycle(screenLifecycle), + TAG, + "updated screen state", + ) + } + } + + screenLifecycle.addObserver(observer) + awaitClose { screenLifecycle.removeObserver(observer) } + } + .stateIn( + scope, + // Use Eagerly so that we're always listening and never miss an event. + SharingStarted.Eagerly, + initialValue = ScreenModel.fromScreenLifecycle(screenLifecycle), + ) + override val fingerprintSensorLocation: Flow<Point?> = conflatedCallbackFlow { fun sendFpLocation() { trySendWithFailureLogging( diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DozeInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DozeInteractor.kt index 2efcd0c1ffe7..0c898befe6a0 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DozeInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DozeInteractor.kt @@ -35,4 +35,8 @@ constructor( fun setLastTapToWakePosition(position: Point) { keyguardRepository.setLastDozeTapToWakePosition(position) } + + fun dozeTimeTick() { + keyguardRepository.dozeTimeTick() + } } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt index 7fae7522d981..1553525915d5 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt @@ -70,6 +70,8 @@ constructor( val dozeAmount: Flow<Float> = repository.linearDozeAmount /** Whether the system is in doze mode. */ val isDozing: Flow<Boolean> = repository.isDozing + /** Receive an event for doze time tick */ + val dozeTimeTick: Flow<Unit> = repository.dozeTimeTick /** Whether Always-on Display mode is available. */ val isAodAvailable: Flow<Boolean> = repository.isAodAvailable /** Doze transition information. */ diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScreenModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScreenModel.kt new file mode 100644 index 000000000000..80a1b75c4350 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScreenModel.kt @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2023 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ +package com.android.systemui.keyguard.shared.model + +import com.android.systemui.keyguard.ScreenLifecycle + +/** Model device screen lifecycle states. */ +data class ScreenModel( + val state: ScreenState, +) { + companion object { + fun fromScreenLifecycle(screenLifecycle: ScreenLifecycle): ScreenModel { + return ScreenModel(ScreenState.fromScreenLifecycleInt(screenLifecycle.getScreenState())) + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScreenState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScreenState.kt new file mode 100644 index 000000000000..fe5d9355a6fa --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/ScreenState.kt @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2022 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.keyguard.shared.model + +import com.android.systemui.keyguard.ScreenLifecycle + +enum class ScreenState { + /** Screen is fully off. */ + SCREEN_OFF, + /** Signal that the screen is turning on. */ + SCREEN_TURNING_ON, + /** Screen is fully on. */ + SCREEN_ON, + /** Signal that the screen is turning off. */ + SCREEN_TURNING_OFF; + + companion object { + fun fromScreenLifecycleInt(value: Int): ScreenState { + return when (value) { + ScreenLifecycle.SCREEN_OFF -> SCREEN_OFF + ScreenLifecycle.SCREEN_TURNING_ON -> SCREEN_TURNING_ON + ScreenLifecycle.SCREEN_ON -> SCREEN_ON + ScreenLifecycle.SCREEN_TURNING_OFF -> SCREEN_TURNING_OFF + else -> throw IllegalArgumentException("Invalid screen value: $value") + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java index 7312db6595e5..ed9722e04da0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java @@ -311,6 +311,7 @@ public final class DozeServiceHost implements DozeHost { @Override public void dozeTimeTick() { + mDozeInteractor.dozeTimeTick(); mNotificationPanel.dozeTimeTick(); mAuthController.dozeTimeTick(); if (mAmbientIndicationContainer instanceof DozeReceiver) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt index f541815d2711..ba7d3490e56d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt @@ -31,11 +31,14 @@ import com.android.systemui.doze.DozeMachine import com.android.systemui.doze.DozeTransitionCallback import com.android.systemui.doze.DozeTransitionListener import com.android.systemui.dreams.DreamOverlayCallbackController +import com.android.systemui.keyguard.ScreenLifecycle import com.android.systemui.keyguard.WakefulnessLifecycle import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.BiometricUnlockSource import com.android.systemui.keyguard.shared.model.DozeStateModel import com.android.systemui.keyguard.shared.model.DozeTransitionModel +import com.android.systemui.keyguard.shared.model.ScreenModel +import com.android.systemui.keyguard.shared.model.ScreenState import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessState import com.android.systemui.plugins.statusbar.StatusBarStateController @@ -71,6 +74,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() { @Mock private lateinit var statusBarStateController: StatusBarStateController @Mock private lateinit var keyguardStateController: KeyguardStateController @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle + @Mock private lateinit var screenLifecycle: ScreenLifecycle @Mock private lateinit var biometricUnlockController: BiometricUnlockController @Mock private lateinit var dozeTransitionListener: DozeTransitionListener @Mock private lateinit var authController: AuthController @@ -92,6 +96,7 @@ class KeyguardRepositoryImplTest : SysuiTestCase() { KeyguardRepositoryImpl( statusBarStateController, wakefulnessLifecycle, + screenLifecycle, biometricUnlockController, keyguardStateController, keyguardBypassController, @@ -160,6 +165,16 @@ class KeyguardRepositoryImplTest : SysuiTestCase() { } @Test + fun dozeTimeTick() = + testScope.runTest { + var dozeTimeTickValue = collectLastValue(underTest.dozeTimeTick) + underTest.dozeTimeTick() + runCurrent() + + assertThat(dozeTimeTickValue()).isNull() + } + + @Test fun isKeyguardShowing() = testScope.runTest { whenever(keyguardStateController.isShowing).thenReturn(false) @@ -371,6 +386,48 @@ class KeyguardRepositoryImplTest : SysuiTestCase() { } @Test + fun screenModel() = + testScope.runTest { + val values = mutableListOf<ScreenModel>() + val job = underTest.screenModel.onEach(values::add).launchIn(this) + + runCurrent() + val captor = argumentCaptor<ScreenLifecycle.Observer>() + verify(screenLifecycle).addObserver(captor.capture()) + + whenever(screenLifecycle.getScreenState()).thenReturn(ScreenLifecycle.SCREEN_TURNING_ON) + captor.value.onScreenTurningOn() + runCurrent() + + whenever(screenLifecycle.getScreenState()).thenReturn(ScreenLifecycle.SCREEN_ON) + captor.value.onScreenTurnedOn() + runCurrent() + + whenever(screenLifecycle.getScreenState()) + .thenReturn(ScreenLifecycle.SCREEN_TURNING_OFF) + captor.value.onScreenTurningOff() + runCurrent() + + whenever(screenLifecycle.getScreenState()).thenReturn(ScreenLifecycle.SCREEN_OFF) + captor.value.onScreenTurnedOff() + runCurrent() + + assertThat(values.map { it.state }) + .isEqualTo( + listOf( + // Initial value will be OFF + ScreenState.SCREEN_OFF, + ScreenState.SCREEN_TURNING_ON, + ScreenState.SCREEN_ON, + ScreenState.SCREEN_TURNING_OFF, + ScreenState.SCREEN_OFF, + ) + ) + + job.cancel() + } + + @Test fun isUdfpsSupported() = testScope.runTest { whenever(keyguardUpdateMonitor.isUdfpsSupported).thenReturn(true) diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt index b9d098fe2851..8428566270de 100644 --- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt +++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt @@ -22,11 +22,14 @@ import com.android.systemui.common.shared.model.Position import com.android.systemui.keyguard.shared.model.BiometricUnlockModel import com.android.systemui.keyguard.shared.model.BiometricUnlockSource import com.android.systemui.keyguard.shared.model.DozeTransitionModel +import com.android.systemui.keyguard.shared.model.ScreenModel +import com.android.systemui.keyguard.shared.model.ScreenState import com.android.systemui.keyguard.shared.model.StatusBarState import com.android.systemui.keyguard.shared.model.WakeSleepReason import com.android.systemui.keyguard.shared.model.WakefulnessModel import com.android.systemui.keyguard.shared.model.WakefulnessState import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow @@ -56,6 +59,9 @@ class FakeKeyguardRepository : KeyguardRepository { private val _isDozing = MutableStateFlow(false) override val isDozing: StateFlow<Boolean> = _isDozing + private val _dozeTimeTick = MutableSharedFlow<Unit>() + override val dozeTimeTick = _dozeTimeTick + private val _lastDozeTapToWakePosition = MutableStateFlow<Point?>(null) override val lastDozeTapToWakePosition = _lastDozeTapToWakePosition.asStateFlow() @@ -86,6 +92,9 @@ class FakeKeyguardRepository : KeyguardRepository { ) override val wakefulness = _wakefulnessModel + private val _screenModel = MutableStateFlow(ScreenModel(ScreenState.SCREEN_OFF)) + override val screenModel = _screenModel + private val _isUdfpsSupported = MutableStateFlow(false) private val _isKeyguardGoingAway = MutableStateFlow(false) @@ -147,6 +156,10 @@ class FakeKeyguardRepository : KeyguardRepository { _isDozing.value = isDozing } + override fun dozeTimeTick() { + _dozeTimeTick.tryEmit(Unit) + } + override fun setLastDozeTapToWakePosition(position: Point) { _lastDozeTapToWakePosition.value = position } |