diff options
3 files changed, 124 insertions, 9 deletions
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/DeviceInactiveConditionTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/DeviceInactiveConditionTest.kt new file mode 100644 index 000000000000..0c97750ba281 --- /dev/null +++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/DeviceInactiveConditionTest.kt @@ -0,0 +1,100 @@ +/* + * 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. + * 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.communal + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.keyguard.keyguardUpdateMonitor +import com.android.systemui.SysuiTestCase +import com.android.systemui.keyguard.WakefulnessLifecycle +import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP +import com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE +import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository +import com.android.systemui.keyguard.domain.interactor.keyguardInteractor +import com.android.systemui.keyguard.shared.model.DozeStateModel +import com.android.systemui.keyguard.shared.model.DozeTransitionModel +import com.android.systemui.keyguard.wakefulnessLifecycle +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.applicationCoroutineScope +import com.android.systemui.kosmos.runTest +import com.android.systemui.kosmos.useUnconfinedTestDispatcher +import com.android.systemui.statusbar.policy.keyguardStateController +import com.android.systemui.testKosmos +import com.android.systemui.util.kotlin.JavaAdapter +import com.google.common.truth.Truth.assertThat +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.argumentCaptor +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@SmallTest +@RunWith(AndroidJUnit4::class) +class DeviceInactiveConditionTest : SysuiTestCase() { + private val kosmos = + testKosmos().useUnconfinedTestDispatcher().also { + whenever(it.wakefulnessLifecycle.wakefulness) doReturn WAKEFULNESS_AWAKE + } + + private val Kosmos.underTest by + Kosmos.Fixture { + DeviceInactiveCondition( + applicationCoroutineScope, + keyguardStateController, + wakefulnessLifecycle, + keyguardUpdateMonitor, + keyguardInteractor, + JavaAdapter(applicationCoroutineScope), + ) + } + + @Test + fun asleep_conditionTrue() = + kosmos.runTest { + // Condition is false to start. + underTest.start() + assertThat(underTest.isConditionMet).isFalse() + + // Condition is true when device goes to sleep. + sleep() + assertThat(underTest.isConditionMet).isTrue() + } + + @Test + fun dozingAndAsleep_conditionFalse() = + kosmos.runTest { + // Condition is true when device is asleep. + underTest.start() + sleep() + assertThat(underTest.isConditionMet).isTrue() + + // Condition turns false after doze starts. + fakeKeyguardRepository.setDozeTransitionModel( + DozeTransitionModel(from = DozeStateModel.UNINITIALIZED, to = DozeStateModel.DOZE) + ) + assertThat(underTest.isConditionMet).isFalse() + } + + fun Kosmos.sleep() { + whenever(wakefulnessLifecycle.wakefulness) doReturn WAKEFULNESS_ASLEEP + argumentCaptor<WakefulnessLifecycle.Observer>().apply { + verify(wakefulnessLifecycle).addObserver(capture()) + firstValue.onStartedGoingToSleep() + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/communal/DeviceInactiveCondition.java b/packages/SystemUI/src/com/android/systemui/communal/DeviceInactiveCondition.java index 2e1b5ad177b5..e456310febfd 100644 --- a/packages/SystemUI/src/com/android/systemui/communal/DeviceInactiveCondition.java +++ b/packages/SystemUI/src/com/android/systemui/communal/DeviceInactiveCondition.java @@ -17,16 +17,19 @@ package com.android.systemui.communal; import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_ASLEEP; -import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; import com.android.systemui.dagger.qualifiers.Application; import com.android.systemui.keyguard.WakefulnessLifecycle; +import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; +import com.android.systemui.keyguard.shared.model.DozeStateModel; import com.android.systemui.shared.condition.Condition; import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.util.kotlin.JavaAdapter; import kotlinx.coroutines.CoroutineScope; +import kotlinx.coroutines.Job; import javax.inject.Inject; @@ -38,6 +41,10 @@ public class DeviceInactiveCondition extends Condition { private final KeyguardStateController mKeyguardStateController; private final WakefulnessLifecycle mWakefulnessLifecycle; private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final KeyguardInteractor mKeyguardInteractor; + private final JavaAdapter mJavaAdapter; + private Job mAnyDozeListenerJob; + private boolean mAnyDoze; private final KeyguardStateController.Callback mKeyguardStateCallback = new KeyguardStateController.Callback() { @Override @@ -63,12 +70,14 @@ public class DeviceInactiveCondition extends Condition { @Inject public DeviceInactiveCondition(@Application CoroutineScope scope, KeyguardStateController keyguardStateController, - WakefulnessLifecycle wakefulnessLifecycle, - KeyguardUpdateMonitor keyguardUpdateMonitor) { + WakefulnessLifecycle wakefulnessLifecycle, KeyguardUpdateMonitor keyguardUpdateMonitor, + KeyguardInteractor keyguardInteractor, JavaAdapter javaAdapter) { super(scope); mKeyguardStateController = keyguardStateController; mWakefulnessLifecycle = wakefulnessLifecycle; mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mKeyguardInteractor = keyguardInteractor; + mJavaAdapter = javaAdapter; } @Override @@ -77,6 +86,11 @@ public class DeviceInactiveCondition extends Condition { mKeyguardStateController.addCallback(mKeyguardStateCallback); mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateCallback); mWakefulnessLifecycle.addObserver(mWakefulnessObserver); + mAnyDozeListenerJob = mJavaAdapter.alwaysCollectFlow( + mKeyguardInteractor.getDozeTransitionModel(), dozeModel -> { + mAnyDoze = !DozeStateModel.Companion.isDozeOff(dozeModel.getTo()); + updateState(); + }); } @Override @@ -84,6 +98,7 @@ public class DeviceInactiveCondition extends Condition { mKeyguardStateController.removeCallback(mKeyguardStateCallback); mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateCallback); mWakefulnessLifecycle.removeObserver(mWakefulnessObserver); + mAnyDozeListenerJob.cancel(null); } @Override @@ -92,10 +107,10 @@ public class DeviceInactiveCondition extends Condition { } private void updateState() { - final boolean asleep = - mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP - || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_GOING_TO_SLEEP; - updateCondition(asleep || mKeyguardStateController.isShowing() - || mKeyguardUpdateMonitor.isDreaming()); + final boolean asleep = mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_ASLEEP; + // Doze/AoD is also a dream, but we should never override it with low light as to the user + // it's totally unrelated. + updateCondition(!mAnyDoze && (asleep || mKeyguardStateController.isShowing() + || mKeyguardUpdateMonitor.isDreaming())); } } diff --git a/packages/SystemUI/src/com/android/systemui/lowlightclock/dagger/LowLightModule.java b/packages/SystemUI/src/com/android/systemui/lowlightclock/dagger/LowLightModule.java index 8469cb4ab565..f8072f2f79b4 100644 --- a/packages/SystemUI/src/com/android/systemui/lowlightclock/dagger/LowLightModule.java +++ b/packages/SystemUI/src/com/android/systemui/lowlightclock/dagger/LowLightModule.java @@ -78,7 +78,7 @@ public abstract class LowLightModule { @Provides @IntoSet - @Named(com.android.systemui.lowlightclock.dagger.LowLightModule.LOW_LIGHT_PRECONDITIONS) + @Named(LOW_LIGHT_PRECONDITIONS) static Condition provideLowLightCondition(LowLightCondition lowLightCondition, DirectBootCondition directBootCondition) { // Start lowlight if we are either in lowlight or in direct boot. The ordering of the |