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

Commit fa2e5e6e authored by Chandru S's avatar Chandru S
Browse files

Use the Touch to Unlock anytime settings toggle to control when we show the SFPS progress bar

Fixes: 305236201
Test: atest SideFpsSensorInteractorTest
Flag: LEGACY REST_TO_UNLOCK DEVELOPMENT
Change-Id: I4a0fdb54d3a2361536ce7ea47e8190fb843ee03e
parent 747174d5
Loading
Loading
Loading
Loading
+26 −9
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.biometrics.domain.interactor
import android.content.Context
import android.hardware.biometrics.SensorLocationInternal
import android.view.WindowManager
import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider
import com.android.systemui.biometrics.data.repository.FingerprintPropertyRepository
import com.android.systemui.biometrics.domain.model.SideFpsSensorLocation
import com.android.systemui.biometrics.shared.model.DisplayRotation
@@ -27,17 +28,16 @@ import com.android.systemui.biometrics.shared.model.isDefaultOrientation
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.flags.FeatureFlagsClassic
import com.android.systemui.flags.Flags
import com.android.systemui.log.SideFpsLogger
import com.android.systemui.res.R
import java.util.Optional
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map

@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class SideFpsSensorInteractor
@Inject
@@ -47,6 +47,8 @@ constructor(
    windowManager: WindowManager,
    displayStateInteractor: DisplayStateInteractor,
    featureFlags: FeatureFlagsClassic,
    fingerprintInteractiveToAuthProvider: Optional<FingerprintInteractiveToAuthProvider>,
    private val logger: SideFpsLogger,
) {

    private val sensorForCurrentDisplay =
@@ -65,12 +67,18 @@ constructor(
        flowOf(context.resources?.getInteger(R.integer.config_restToUnlockDuration)?.toLong() ?: 0L)

    val isProlongedTouchRequiredForAuthentication: Flow<Boolean> =
        isAvailable.flatMapLatest { sfpsAvailable ->
            if (sfpsAvailable) {
                // todo (b/305236201) also add the settings check here.
                flowOf(featureFlags.isEnabled(Flags.REST_TO_UNLOCK))
            } else {
        if (
            fingerprintInteractiveToAuthProvider.isEmpty ||
                !featureFlags.isEnabled(Flags.REST_TO_UNLOCK)
        ) {
            flowOf(false)
        } else {
            combine(
                isAvailable,
                fingerprintInteractiveToAuthProvider.get().enabledForCurrentUser
            ) { sfpsAvailable, isSettingEnabled ->
                logger.logStateChange(sfpsAvailable, isSettingEnabled)
                sfpsAvailable && isSettingEnabled
            }
        }

@@ -126,6 +134,15 @@ constructor(
                    }
                }

            logger.sensorLocationStateChanged(
                size,
                rotation,
                displayWidth,
                displayHeight,
                sensorWidth,
                isSensorVerticalInDefaultOrientation
            )

            SideFpsSensorLocation(
                left = sensorLeft,
                top = sensorTop,
+132 −0
Original line number Diff line number Diff line
/*
 * 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.log

import android.graphics.Point
import android.graphics.Rect
import com.android.systemui.biometrics.shared.model.DisplayRotation
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.log.core.LogLevel
import com.android.systemui.log.dagger.BouncerLog
import javax.inject.Inject

private const val TAG = "SideFpsLogger"

/**
 * Helper class for logging for SFPS related functionality
 *
 * To enable logcat echoing for an entire buffer:
 * ```
 *   adb shell settings put global systemui/buffer/BouncerLog <logLevel>
 *
 * ```
 */
@SysUISingleton
class SideFpsLogger @Inject constructor(@BouncerLog private val buffer: LogBuffer) {
    fun sfpsProgressBarStateChanged(
        visible: Boolean,
        location: Point,
        shouldRotate: Boolean,
        fpDetectRunning: Boolean,
        sensorWidth: Int
    ) {
        buffer.log(
            TAG,
            LogLevel.DEBUG,
            {
                bool1 = visible
                int1 = location.x
                int2 = location.y
                bool2 = shouldRotate
                bool3 = fpDetectRunning
                long1 = sensorWidth.toLong()
            },
            {
                "SFPS progress bar state changed: visible: $bool1, " +
                    "sensorLocation (x, y): ($int1, $int2), " +
                    "shouldRotate = $bool2, " +
                    "fpDetectRunning: $bool3, " +
                    "sensorWidth: $long1"
            }
        )
    }

    fun hidingSfpsIndicator() {
        buffer.log(TAG, LogLevel.DEBUG, "hiding SFPS indicator to show progress bar")
    }

    fun showingSfpsIndicator() {
        buffer.log(
            TAG,
            LogLevel.DEBUG,
            "Requesting show SFPS indicator because progress bar " +
                "is being hidden and FP detect is currently running"
        )
    }

    fun isProlongedTouchRequiredForAuthenticationChanged(enabled: Boolean) {
        buffer.log(
            TAG,
            LogLevel.DEBUG,
            { bool1 = enabled },
            { "isProlongedTouchRequiredForAuthentication: $bool1" }
        )
    }

    fun logStateChange(sfpsAvailable: Boolean, settingEnabled: Boolean) {
        buffer.log(
            TAG,
            LogLevel.DEBUG,
            {
                bool1 = sfpsAvailable
                bool2 = settingEnabled
            },
            { "SFPS rest to unlock state changed: sfpsAvailable: $bool1, settingEnabled: $bool2" }
        )
    }

    fun sensorLocationStateChanged(
        windowSize: Rect?,
        rotation: DisplayRotation,
        displayWidth: Int,
        displayHeight: Int,
        sensorWidth: Int,
        sensorVerticalInDefaultOrientation: Boolean
    ) {
        buffer.log(
            TAG,
            LogLevel.DEBUG,
            {
                str1 = "$windowSize"
                str2 = rotation.name
                int1 = displayWidth
                int2 = displayHeight
                long1 = sensorWidth.toLong()
                bool1 = sensorVerticalInDefaultOrientation
            },
            {
                "sensorLocation state changed: " +
                    "windowSize: $str1, " +
                    "rotation: $str2, " +
                    "widthInRotation0: $int1, " +
                    "heightInRotation0: $int2, " +
                    "sensorWidth: $long1, " +
                    "sensorVerticalInDefaultOrientation: $bool1"
            }
        )
    }
}
+32 −7
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.view.WindowManager
import android.view.WindowMetrics
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.shared.model.DisplayRotation
import com.android.systemui.biometrics.shared.model.DisplayRotation.ROTATION_0
@@ -35,11 +36,14 @@ import com.android.systemui.biometrics.shared.model.DisplayRotation.ROTATION_90
import com.android.systemui.biometrics.shared.model.FingerprintSensorType
import com.android.systemui.biometrics.shared.model.SensorStrength
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dump.logcatLogBuffer
import com.android.systemui.flags.FakeFeatureFlagsClassic
import com.android.systemui.flags.Flags.REST_TO_UNLOCK
import com.android.systemui.log.SideFpsLogger
import com.android.systemui.res.R
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import java.util.Optional
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.StandardTestDispatcher
@@ -62,7 +66,7 @@ import org.mockito.junit.MockitoJUnit
class SideFpsSensorInteractorTest : SysuiTestCase() {

    @JvmField @Rule var mockitoRule = MockitoJUnit.rule()
    private lateinit var testScope: TestScope
    private val testScope = TestScope(StandardTestDispatcher())

    private val fingerprintRepository = FakeFingerprintPropertyRepository()

@@ -70,32 +74,38 @@ class SideFpsSensorInteractorTest : SysuiTestCase() {

    @Mock private lateinit var windowManager: WindowManager
    @Mock private lateinit var displayStateInteractor: DisplayStateInteractor

    @Mock
    private lateinit var fingerprintInteractiveToAuthProvider: FingerprintInteractiveToAuthProvider
    private val isRestToUnlockEnabled = MutableStateFlow(false)
    private val contextDisplayInfo = DisplayInfo()
    private val displayChangeEvent = MutableStateFlow(0)
    private val currentRotation = MutableStateFlow(ROTATION_0)

    @Before
    fun setup() {
        testScope = TestScope(StandardTestDispatcher())
        mContext = spy(mContext)

        val displayManager = mock(DisplayManagerGlobal::class.java)
        val resources = mContext.resources
        whenever(mContext.display)
            .thenReturn(Display(displayManager, 1, contextDisplayInfo, resources))
            .thenReturn(
                Display(mock(DisplayManagerGlobal::class.java), 1, contextDisplayInfo, resources)
            )
        whenever(displayStateInteractor.displayChanges).thenReturn(displayChangeEvent)
        whenever(displayStateInteractor.currentRotation).thenReturn(currentRotation)

        contextDisplayInfo.uniqueId = "current-display"

        val featureFlags = FakeFeatureFlagsClassic().apply { set(REST_TO_UNLOCK, true) }
        whenever(fingerprintInteractiveToAuthProvider.enabledForCurrentUser)
            .thenReturn(isRestToUnlockEnabled)
        underTest =
            SideFpsSensorInteractor(
                mContext,
                fingerprintRepository,
                windowManager,
                displayStateInteractor,
                FakeFeatureFlagsClassic().apply { set(REST_TO_UNLOCK, true) }
                featureFlags,
                Optional.of(fingerprintInteractiveToAuthProvider),
                SideFpsLogger(logcatLogBuffer("SfpsLogger"))
            )
    }

@@ -348,6 +358,21 @@ class SideFpsSensorInteractorTest : SysuiTestCase() {
            assertThat(sensorLocation!!.width).isEqualTo(100)
        }

    @Test
    fun isProlongedTouchRequiredForAuthentication_dependsOnSettingsToggle() =
        testScope.runTest {
            val isEnabled by collectLastValue(underTest.isProlongedTouchRequiredForAuthentication)
            setupFingerprint(FingerprintSensorType.POWER_BUTTON)

            isRestToUnlockEnabled.value = true
            runCurrent()
            assertThat(isEnabled).isTrue()

            isRestToUnlockEnabled.value = false
            runCurrent()
            assertThat(isEnabled).isFalse()
        }

    private suspend fun TestScope.setupFPLocationAndDisplaySize(
        width: Int,
        height: Int,