diff options
3 files changed, 190 insertions, 16 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt index f85203ea2076..0567ea2ee465 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractor.kt @@ -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 { - flowOf(false) + 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, diff --git a/packages/SystemUI/src/com/android/systemui/log/SideFpsLogger.kt b/packages/SystemUI/src/com/android/systemui/log/SideFpsLogger.kt new file mode 100644 index 000000000000..74923eec4891 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/log/SideFpsLogger.kt @@ -0,0 +1,132 @@ +/* + * 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" + } + ) + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt index 99501c426e0c..1e7a3d3ef6ff 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/domain/interactor/SideFpsSensorInteractorTest.kt @@ -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, |