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

Commit 8b8cebe7 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Allow touches to go to lock icon in AOD" into main

parents e473c3f2 d6cd0ceb
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -1923,6 +1923,16 @@ flag {
   }
}

flag {
   name: "allow_doze_touches_for_lock_icon"
   namespace: "systemui"
   description: "Allow touches for device entry lock icon during aod deferment."
   bug: "433400058"
   metadata {
        purpose: PURPOSE_BUGFIX
   }
}

flag {
   name: "qs_compose_fragment_early_expansion"
   namespace: "systemui"
+116 −0
Original line number Diff line number Diff line
/*
 * 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.keyguard.domain.interactor

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.data.repository.fakeFingerprintPropertyRepository
import com.android.systemui.keyguard.data.repository.fakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.fakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.power.data.repository.fakePowerRepository
import com.android.systemui.power.shared.model.DozeScreenStateModel
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class DozeTouchInteractorTest : SysuiTestCase() {

    private val kosmos = testKosmos()
    private val Kosmos.underTest by Kosmos.Fixture { kosmos.dozeTouchInteractor }

    @Test
    fun shouldInterceptTouches_notDozing() =
        kosmos.runTest {
            val shouldInterceptTouches by collectLastValue(underTest.shouldInterceptTouches)
            kosmos.fakeKeyguardRepository.setDozeTransitionModel(
                DozeTransitionModel(
                    from = DozeStateModel.UNINITIALIZED,
                    to = DozeStateModel.UNINITIALIZED,
                )
            )
            assertThat(shouldInterceptTouches).isFalse()
        }

    @Test
    fun shouldInterceptTouches_pulsing() =
        kosmos.runTest {
            val shouldInterceptTouches by collectLastValue(underTest.shouldInterceptTouches)
            kosmos.fakeKeyguardRepository.setDozeTransitionModel(
                DozeTransitionModel(
                    from = DozeStateModel.DOZE_REQUEST_PULSE,
                    to = DozeStateModel.DOZE_PULSING,
                )
            )
            assertThat(shouldInterceptTouches).isFalse()
        }

    @Test
    fun shouldInterceptTouches_aod() =
        kosmos.runTest {
            val shouldInterceptTouches by collectLastValue(underTest.shouldInterceptTouches)
            kosmos.fakeKeyguardRepository.setDozeTransitionModel(
                DozeTransitionModel(from = DozeStateModel.INITIALIZED, to = DozeStateModel.DOZE_AOD)
            )
            assertThat(shouldInterceptTouches).isTrue()
        }

    @Test
    fun shouldInterceptTouches_docked() =
        kosmos.runTest {
            val shouldInterceptTouches by collectLastValue(underTest.shouldInterceptTouches)
            kosmos.fakeKeyguardRepository.setDozeTransitionModel(
                DozeTransitionModel(
                    from = DozeStateModel.DOZE_AOD,
                    to = DozeStateModel.DOZE_AOD_DOCKED,
                )
            )
            assertThat(shouldInterceptTouches).isFalse()
        }

    @Test
    fun shouldInterceptTouches_aodTransition_longpressEnabled() =
        kosmos.runTest {
            val shouldInterceptTouches by collectLastValue(underTest.shouldInterceptTouches)
            kosmos.fakeKeyguardRepository.setDozeTransitionModel(
                DozeTransitionModel(from = DozeStateModel.INITIALIZED, to = DozeStateModel.DOZE_AOD)
            )
            kosmos.fakePowerRepository.dozeScreenState.value = DozeScreenStateModel.ON
            deviceEntryIconLongPressEnabled()
            assertThat(shouldInterceptTouches).isFalse()
        }

    private fun deviceEntryIconLongPressEnabled() {
        kosmos.fakeBiometricSettingsRepository.setIsFingerprintAuthEnrolledAndEnabled(true)
        kosmos.fakeFingerprintPropertyRepository.supportsUdfps()
        kosmos.fakeDeviceEntryFingerprintAuthRepository.setIsRunning(false)
        if (!SceneContainerFlag.isEnabled) {
            kosmos.fakeKeyguardRepository.setHasTrust(false)
        }
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import com.android.systemui.flags.Flags
import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler
import com.android.systemui.keyguard.KeyguardUnlockAnimationController
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.domain.interactor.dozeTouchInteractor
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.LOCKSCREEN
@@ -73,6 +74,7 @@ import com.android.systemui.statusbar.window.StatusBarWindowStateController
import com.android.systemui.testKosmos
import com.android.systemui.unfold.SysUIUnfoldComponent
import com.android.systemui.unfold.UnfoldTransitionProgressProvider
import com.android.systemui.util.kotlin.javaAdapter
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.whenever
import com.android.systemui.util.time.FakeSystemClock
@@ -237,6 +239,8 @@ class NotificationShadeWindowViewTest : SysuiTestCase() {
                brightnessMirrorShowingInteractor,
                UnconfinedTestDispatcher(),
                kosmos.shadeStatusBarComponentsInteractor,
                kosmos.dozeTouchInteractor,
                kosmos.javaAdapter,
            )

        controller.setupExpandedStatusBar()
+90 −0
Original line number Diff line number Diff line
/*
 * 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.keyguard.domain.interactor

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.isDocked
import com.android.systemui.keyguard.shared.model.isDozing
import com.android.systemui.keyguard.shared.model.isPulsing
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.DozeScreenStateModel
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map

/**
 * Handles business logic for whether touches should be intercepted instead of going to child views
 * while entering/in doze.
 */
@SysUISingleton
class DozeTouchInteractor
@Inject
constructor(
    keyguardInteractor: KeyguardInteractor,
    powerInteractor: PowerInteractor,
    deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
    deviceEntryInteractor: DeviceEntryInteractor,
) {
    private val toDozeTransitionModel = keyguardInteractor.dozeTransitionModel.map { it.to }

    private val isUnlocked =
        if (SceneContainerFlag.isEnabled) {
            deviceEntryInteractor.isUnlocked
        } else {
            keyguardInteractor.hasTrust
        }

    // Long-press is enabled in AOD only if UDFPS is enrolled & UDFPS can't be used while locked
    private val deviceEntryIconLongPressEnabledInAod =
        deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest { udfpsEnrolled ->
            if (udfpsEnrolled) {
                combine(isUnlocked, deviceEntryUdfpsInteractor.isListeningForUdfps) {
                    isUnlocked,
                    udfpsRunning ->
                    !isUnlocked && !udfpsRunning
                }
            } else {
                flowOf(false)
            }
        }

    private val inAodDeferment: Flow<Boolean> =
        combine(toDozeTransitionModel, powerInteractor.dozeScreenState) {
            dozeTransitionModel,
            dozeScreenState ->
            dozeTransitionModel == DozeStateModel.DOZE_AOD &&
                dozeScreenState == DozeScreenStateModel.ON
        }

    val shouldInterceptTouches: Flow<Boolean> =
        combine(inAodDeferment, toDozeTransitionModel, deviceEntryIconLongPressEnabledInAod) {
            aodDeferment,
            dozeTransitionModel,
            deviceEntryIconLongPressEnabledInAod ->
            dozeTransitionModel.isDozing() &&
                !dozeTransitionModel.isPulsing() &&
                !dozeTransitionModel.isDocked() &&
                (!aodDeferment || !deviceEntryIconLongPressEnabledInAod)
        }
}
+47 −0
Original line number Diff line number Diff line
@@ -15,6 +15,24 @@
 */
package com.android.systemui.keyguard.shared.model

import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
import com.android.systemui.keyguard.shared.model.DozeStateModel.DOZE
import com.android.systemui.keyguard.shared.model.DozeStateModel.DOZE_AOD
import com.android.systemui.keyguard.shared.model.DozeStateModel.DOZE_AOD_DOCKED
import com.android.systemui.keyguard.shared.model.DozeStateModel.DOZE_AOD_MINMODE
import com.android.systemui.keyguard.shared.model.DozeStateModel.DOZE_AOD_PAUSED
import com.android.systemui.keyguard.shared.model.DozeStateModel.DOZE_AOD_PAUSING
import com.android.systemui.keyguard.shared.model.DozeStateModel.DOZE_PULSE_DONE
import com.android.systemui.keyguard.shared.model.DozeStateModel.DOZE_PULSING
import com.android.systemui.keyguard.shared.model.DozeStateModel.DOZE_PULSING_AUTH_UI
import com.android.systemui.keyguard.shared.model.DozeStateModel.DOZE_PULSING_BRIGHT
import com.android.systemui.keyguard.shared.model.DozeStateModel.DOZE_PULSING_WITHOUT_UI
import com.android.systemui.keyguard.shared.model.DozeStateModel.DOZE_REQUEST_PULSE
import com.android.systemui.keyguard.shared.model.DozeStateModel.DOZE_SUSPEND_TRIGGERS
import com.android.systemui.keyguard.shared.model.DozeStateModel.FINISH
import com.android.systemui.keyguard.shared.model.DozeStateModel.INITIALIZED
import com.android.systemui.keyguard.shared.model.DozeStateModel.UNINITIALIZED

/** Model device doze states. */
enum class DozeStateModel {
    /** Default state. Transition to INITIALIZED to get Doze going. */
@@ -58,3 +76,32 @@ enum class DozeStateModel {
        }
    }
}

fun DozeStateModel.isPulsing(): Boolean {
    return when (this) {
        UNINITIALIZED,
        INITIALIZED,
        DOZE,
        DOZE_SUSPEND_TRIGGERS,
        DOZE_PULSE_DONE,
        FINISH,
        DOZE_AOD_PAUSED,
        DOZE_AOD_PAUSING,
        DOZE_AOD_DOCKED,
        DOZE_AOD_MINMODE,
        DOZE_AOD,
        DOZE_REQUEST_PULSE -> false
        DOZE_PULSING,
        DOZE_PULSING_WITHOUT_UI,
        DOZE_PULSING_AUTH_UI,
        DOZE_PULSING_BRIGHT -> true
    }
}

fun DozeStateModel.isDocked(): Boolean {
    return this == DOZE_AOD_DOCKED
}

fun DozeStateModel.isDozing(): Boolean {
    return !isDozeOff(this)
}
Loading