diff options
10 files changed, 475 insertions, 11 deletions
diff --git a/packages/SystemUI/res-keyguard/drawable/progress_bar.xml b/packages/SystemUI/res-keyguard/drawable/progress_bar.xml new file mode 100644 index 000000000000..910a74ad5faf --- /dev/null +++ b/packages/SystemUI/res-keyguard/drawable/progress_bar.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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. + --> + +<layer-list xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" + android:paddingMode="stack"> + <item + android:id="@android:id/background" + android:gravity="center_vertical|fill_horizontal"> + <shape + android:layout_width="match_parent" + android:layout_height="match_parent" + android:shape="rectangle"> + <corners android:radius="30dp" /> + <solid android:color="?androidprv:attr/materialColorSurfaceContainerHighest" /> + </shape> + </item> + <item + android:id="@android:id/progress" + android:gravity="center_vertical|fill_horizontal"> + <clip> + <shape + android:layout_width="match_parent" + android:layout_height="match_parent" + android:shape="rectangle"> + <corners android:radius="30dp" /> + <solid android:color="?androidprv:attr/textColorPrimary" /> + </shape> + </clip> + </item> +</layer-list>
\ No newline at end of file diff --git a/packages/SystemUI/res-keyguard/layout/sidefps_progress_bar.xml b/packages/SystemUI/res-keyguard/layout/sidefps_progress_bar.xml new file mode 100644 index 000000000000..183f0e591c91 --- /dev/null +++ b/packages/SystemUI/res-keyguard/layout/sidefps_progress_bar.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ 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. + ~ + --> + +<LinearLayout android:layout_height="match_parent" + android:layout_width="match_parent" + android:orientation="vertical" + android:layoutDirection="ltr" + android:gravity="center" + xmlns:android="http://schemas.android.com/apk/res/android"> + <ProgressBar + android:id="@+id/side_fps_progress_bar" + android:layout_width="55dp" + android:layout_height="10dp" + android:indeterminateOnly="false" + android:min="0" + android:max="100" + android:progressDrawable="@drawable/progress_bar" /> +</LinearLayout> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index b7bb35eb6783..84e06e221b01 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -153,7 +153,6 @@ import com.android.settingslib.Utils; import com.android.settingslib.WirelessUtils; import com.android.settingslib.fuelgauge.BatteryStatus; import com.android.systemui.Dumpable; -import com.android.systemui.res.R; import com.android.systemui.biometrics.AuthController; import com.android.systemui.biometrics.FingerprintInteractiveToAuthProvider; import com.android.systemui.broadcast.BroadcastDispatcher; @@ -177,6 +176,7 @@ import com.android.systemui.keyguard.shared.model.SysUiFaceAuthenticateOptions; import com.android.systemui.log.SessionTracker; import com.android.systemui.plugins.WeatherData; import com.android.systemui.plugins.statusbar.StatusBarStateController; +import com.android.systemui.res.R; import com.android.systemui.settings.DisplayTracker; import com.android.systemui.settings.UserTracker; import com.android.systemui.shared.system.TaskStackChangeListener; @@ -1984,6 +1984,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab @Override public void onAuthenticationAcquired(int acquireInfo) { Trace.beginSection("KeyguardUpdateMonitor#onAuthenticationAcquired"); + mLogger.logFingerprintAcquired(acquireInfo); handleFingerprintAcquired(acquireInfo); Trace.endSection(); } diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt index fe19616cef1d..fa07072b7fe1 100644 --- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt +++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt @@ -44,6 +44,7 @@ import com.google.errorprone.annotations.CompileTimeConstant import javax.inject.Inject private const val TAG = "KeyguardUpdateMonitorLog" +private const val FP_LOG_TAG = "KeyguardFingerprintLog" /** Helper class for logging for [com.android.keyguard.KeyguardUpdateMonitor] */ class KeyguardUpdateMonitorLogger @@ -157,7 +158,7 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { fun logFingerprintAuthForWrongUser(authUserId: Int) { logBuffer.log( - TAG, + FP_LOG_TAG, DEBUG, { int1 = authUserId }, { "Fingerprint authenticated for wrong user: $int1" } @@ -166,7 +167,7 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { fun logFingerprintDisabledForUser(userId: Int) { logBuffer.log( - TAG, + FP_LOG_TAG, DEBUG, { int1 = userId }, { "Fingerprint disabled by DPM for userId: $int1" } @@ -174,12 +175,17 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { } fun logFingerprintLockoutReset(@LockoutMode mode: Int) { - logBuffer.log(TAG, DEBUG, { int1 = mode }, { "handleFingerprintLockoutReset: $int1" }) + logBuffer.log( + FP_LOG_TAG, + DEBUG, + { int1 = mode }, + { "handleFingerprintLockoutReset: $int1" } + ) } fun logFingerprintRunningState(fingerprintRunningState: Int) { logBuffer.log( - TAG, + FP_LOG_TAG, DEBUG, { int1 = fingerprintRunningState }, { "fingerprintRunningState: $int1" } @@ -188,7 +194,7 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { fun logFingerprintSuccess(userId: Int, isStrongBiometric: Boolean) { logBuffer.log( - TAG, + FP_LOG_TAG, DEBUG, { int1 = userId @@ -212,7 +218,7 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { fun logFingerprintDetected(userId: Int, isStrongBiometric: Boolean) { logBuffer.log( - TAG, + FP_LOG_TAG, DEBUG, { int1 = userId @@ -224,7 +230,7 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { fun logFingerprintError(msgId: Int, originalErrMsg: String) { logBuffer.log( - TAG, + FP_LOG_TAG, DEBUG, { str1 = originalErrMsg @@ -751,4 +757,25 @@ constructor(@KeyguardUpdateMonitorLog private val logBuffer: LogBuffer) { { "userSwitchComplete: $str1, userId: $int1" } ) } + + fun logFingerprintHelp(helpMsgId: Int, helpString: CharSequence) { + logBuffer.log( + FP_LOG_TAG, + DEBUG, + { + int1 = helpMsgId + str1 = "$helpString" + }, + { "fingerprint help message: $int1, $str1" } + ) + } + + fun logFingerprintAcquired(acquireInfo: Int) { + logBuffer.log( + FP_LOG_TAG, + DEBUG, + { int1 = acquireInfo }, + { "fingerprint acquire message: $int1" } + ) + } } diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt index c1f6259d94f7..40f229b7004a 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt +++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt @@ -41,6 +41,8 @@ import android.view.LayoutInflater import android.view.Surface import android.view.View import android.view.View.AccessibilityDelegate +import android.view.View.INVISIBLE +import android.view.View.VISIBLE import android.view.ViewPropertyAnimator import android.view.WindowManager import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION @@ -54,13 +56,13 @@ import com.android.app.animation.Interpolators import com.android.internal.annotations.VisibleForTesting import com.android.keyguard.KeyguardPINView import com.android.systemui.Dumpable -import com.android.systemui.res.R import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.dump.DumpManager +import com.android.systemui.res.R import com.android.systemui.util.boundsOnScreen import com.android.systemui.util.concurrency.DelayableExecutor import com.android.systemui.util.traceSection @@ -229,6 +231,20 @@ constructor( } } + /** Hide the arrow indicator. */ + fun hideIndicator() { + val lottieAnimationView = + overlayView?.findViewById(R.id.sidefps_animation) as LottieAnimationView? + lottieAnimationView?.visibility = INVISIBLE + } + + /** Show the arrow indicator. */ + fun showIndicator() { + val lottieAnimationView = + overlayView?.findViewById(R.id.sidefps_animation) as LottieAnimationView? + lottieAnimationView?.visibility = VISIBLE + } + override fun dump(pw: PrintWriter, args: Array<out String>) { pw.println("requests:") for (requestSource in requests) { @@ -247,6 +263,10 @@ constructor( pw.println(" displayId=${displayInfo.uniqueId}") pw.println(" sensorType=${sensorProps?.sensorType}") pw.println(" location=${sensorProps?.getLocation(displayInfo.uniqueId)}") + pw.println("lottieAnimationView:") + pw.println( + " visibility=${overlayView?.findViewById<View>(R.id.sidefps_animation)?.visibility}" + ) pw.println("overlayOffsets=$overlayOffsets") pw.println("isReverseDefaultRotation=$isReverseDefaultRotation") @@ -498,5 +518,5 @@ enum class SideFpsUiRequestSource { AUTO_SHOW, /** Pin, pattern or password bouncer */ PRIMARY_BOUNCER, - ALTERNATE_BOUNCER + ALTERNATE_BOUNCER, } diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt index 2f8010620e5e..565962394db1 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt @@ -22,6 +22,7 @@ import com.android.systemui.bouncer.data.repository.BouncerMessageRepositoryImpl import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepositoryImpl import com.android.systemui.bouncer.domain.interactor.BouncerMessageAuditLogger +import com.android.systemui.keyguard.ui.binder.SideFpsProgressBarViewBinder import dagger.Binds import dagger.Module import dagger.multibindings.ClassKey @@ -32,6 +33,11 @@ interface KeyguardRepositoryModule { @Binds fun keyguardRepository(impl: KeyguardRepositoryImpl): KeyguardRepository @Binds + @IntoMap + @ClassKey(SideFpsProgressBarViewBinder::class) + fun bindSideFpsProgressBarViewBinder(viewBinder: SideFpsProgressBarViewBinder): CoreStartable + + @Binds fun keyguardSurfaceBehindRepository( impl: KeyguardSurfaceBehindRepositoryImpl ): KeyguardSurfaceBehindRepository diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FingerprintAuthenticationModels.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FingerprintAuthenticationModels.kt index ae18681a5b92..3c143fe1a68a 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FingerprintAuthenticationModels.kt +++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/FingerprintAuthenticationModels.kt @@ -16,6 +16,8 @@ package com.android.systemui.keyguard.shared.model +import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD +import android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START import android.hardware.fingerprint.FingerprintManager import android.os.SystemClock.elapsedRealtime @@ -39,7 +41,12 @@ data class HelpFingerprintAuthenticationStatus( /** Fingerprint acquired message. */ data class AcquiredFingerprintAuthenticationStatus(val acquiredInfo: Int) : - FingerprintAuthenticationStatus() + FingerprintAuthenticationStatus() { + + val fingerprintCaptureStarted: Boolean = acquiredInfo == FINGERPRINT_ACQUIRED_START + + val fingerprintCaptureCompleted: Boolean = acquiredInfo == FINGERPRINT_ACQUIRED_GOOD +} /** Fingerprint authentication failed message. */ object FailFingerprintAuthenticationStatus : FingerprintAuthenticationStatus() diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt new file mode 100644 index 000000000000..1acea5cfc579 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/SideFpsProgressBarViewBinder.kt @@ -0,0 +1,74 @@ +/* + * 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.ui.binder + +import com.android.systemui.CoreStartable +import com.android.systemui.biometrics.SideFpsController +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.keyguard.ui.view.SideFpsProgressBar +import com.android.systemui.keyguard.ui.viewmodel.SideFpsProgressBarViewModel +import com.android.systemui.util.kotlin.Quint +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.launch + +@SysUISingleton +class SideFpsProgressBarViewBinder +@Inject +constructor( + private val viewModel: SideFpsProgressBarViewModel, + private val view: SideFpsProgressBar, + @Application private val applicationScope: CoroutineScope, + private val sfpsController: dagger.Lazy<SideFpsController>, +) : CoreStartable { + + override fun start() { + applicationScope.launch { + viewModel.isProlongedTouchRequiredForAuthentication.collectLatest { enabled -> + if (enabled) { + launch { + combine( + viewModel.isVisible, + viewModel.sensorLocation, + viewModel.shouldRotate90Degrees, + viewModel.isFingerprintAuthRunning, + viewModel.sensorWidth, + ::Quint + ) + .collectLatest { + (visible, location, shouldRotate, fpDetectRunning, sensorWidth) -> + view.updateView(visible, location, shouldRotate, sensorWidth) + // We have to hide the SFPS indicator as the progress bar will + // be shown at the same location + if (visible) { + sfpsController.get().hideIndicator() + } else if (fpDetectRunning) { + sfpsController.get().showIndicator() + } + } + } + launch { viewModel.progress.collectLatest { view.setProgress(it) } } + } else { + view.hideOverlay() + } + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/SideFpsProgressBar.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/SideFpsProgressBar.kt new file mode 100644 index 000000000000..f7ab1ee77582 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/SideFpsProgressBar.kt @@ -0,0 +1,114 @@ +/* + * 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.ui.view + +import android.graphics.PixelFormat +import android.graphics.Point +import android.view.Gravity +import android.view.LayoutInflater +import android.view.View +import android.view.WindowManager +import android.widget.ProgressBar +import com.android.systemui.biometrics.Utils +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.res.R +import javax.inject.Inject + +private const val TAG = "SideFpsProgressBar" + +const val progressBarHeight = 100 + +@SysUISingleton +class SideFpsProgressBar +@Inject +constructor( + private val layoutInflater: LayoutInflater, + private val windowManager: WindowManager, +) { + private var progressBarWidth = 200 + fun updateView( + visible: Boolean, + location: Point, + shouldRotate90Degrees: Boolean, + progressBarWidth: Int + ) { + if (visible) { + this.progressBarWidth = progressBarWidth + createAndShowOverlay(location, shouldRotate90Degrees) + } else { + hideOverlay() + } + } + + fun hideOverlay() { + overlayView = null + } + + private val overlayViewParams = + WindowManager.LayoutParams( + progressBarHeight, + progressBarWidth, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL, + Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS, + PixelFormat.TRANSPARENT + ) + .apply { + title = TAG + fitInsetsTypes = 0 // overrides default, avoiding status bars during layout + gravity = Gravity.TOP or Gravity.LEFT + layoutInDisplayCutoutMode = + WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS + privateFlags = + WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY or + WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION + } + + private var overlayView: View? = null + set(value) { + field?.let { oldView -> windowManager.removeView(oldView) } + field = value + field?.let { newView -> windowManager.addView(newView, overlayViewParams) } + } + + private fun createAndShowOverlay( + fingerprintSensorLocation: Point, + shouldRotate90Degrees: Boolean + ) { + if (overlayView == null) { + overlayView = layoutInflater.inflate(R.layout.sidefps_progress_bar, null, false) + } + overlayViewParams.x = fingerprintSensorLocation.x + overlayViewParams.y = fingerprintSensorLocation.y + if (shouldRotate90Degrees) { + overlayView?.rotation = 270.0f + overlayViewParams.width = progressBarHeight + overlayViewParams.height = progressBarWidth + } else { + overlayView?.rotation = 0.0f + overlayViewParams.width = progressBarWidth + overlayViewParams.height = progressBarHeight + } + windowManager.updateViewLayout(overlayView, overlayViewParams) + } + + fun setProgress(value: Float) { + overlayView + ?.findViewById<ProgressBar?>(R.id.side_fps_progress_bar) + ?.setProgress((value * 100).toInt(), false) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt new file mode 100644 index 000000000000..2c3b431715a9 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/SideFpsProgressBarViewModel.kt @@ -0,0 +1,138 @@ +/* + * 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.ui.viewmodel + +import android.animation.ValueAnimator +import android.graphics.Point +import androidx.core.animation.doOnEnd +import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor +import com.android.systemui.biometrics.domain.interactor.SideFpsSensorInteractor +import com.android.systemui.biometrics.shared.model.isDefaultOrientation +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.dagger.qualifiers.Application +import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository +import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.FailFingerprintAuthenticationStatus +import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus +import javax.inject.Inject +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.launch + +@SysUISingleton +class SideFpsProgressBarViewModel +@Inject +constructor( + private val fpAuthRepository: DeviceEntryFingerprintAuthRepository, + private val sfpsSensorInteractor: SideFpsSensorInteractor, + displayStateInteractor: DisplayStateInteractor, + @Application private val applicationScope: CoroutineScope, +) { + private val _progress = MutableStateFlow(0.0f) + private val _visible = MutableStateFlow(false) + private var _animator: ValueAnimator? = null + + private fun onFingerprintCaptureCompleted() { + _visible.value = false + _progress.value = 0.0f + } + + val isVisible: Flow<Boolean> = _visible.asStateFlow() + + val progress: Flow<Float> = _progress.asStateFlow() + + val sensorWidth: Flow<Int> = sfpsSensorInteractor.sensorLocation.map { it.width } + + val sensorLocation: Flow<Point> = + sfpsSensorInteractor.sensorLocation.map { Point(it.left, it.top) } + + val isFingerprintAuthRunning: Flow<Boolean> = fpAuthRepository.isRunning + + val shouldRotate90Degrees: Flow<Boolean> = + combine(displayStateInteractor.currentRotation, sfpsSensorInteractor.sensorLocation, ::Pair) + .map { (rotation, sensorLocation) -> + if (rotation.isDefaultOrientation()) { + sensorLocation.isSensorVerticalInDefaultOrientation + } else { + !sensorLocation.isSensorVerticalInDefaultOrientation + } + } + + val isProlongedTouchRequiredForAuthentication: Flow<Boolean> = + sfpsSensorInteractor.isProlongedTouchRequiredForAuthentication + + init { + applicationScope.launch { + combine( + sfpsSensorInteractor.isProlongedTouchRequiredForAuthentication, + sfpsSensorInteractor.authenticationDuration, + ::Pair + ) + .collectLatest { (enabled, authDuration) -> + if (!enabled) return@collectLatest + + launch { + fpAuthRepository.authenticationStatus.collectLatest { authStatus -> + when (authStatus) { + is AcquiredFingerprintAuthenticationStatus -> { + if (authStatus.fingerprintCaptureStarted) { + + _visible.value = true + _animator?.cancel() + _animator = + ValueAnimator.ofFloat(0.0f, 1.0f) + .setDuration(authDuration) + .apply { + addUpdateListener { + _progress.value = it.animatedValue as Float + } + addListener( + doOnEnd { + if (_progress.value == 0.0f) { + _visible.value = false + } + } + ) + } + _animator?.start() + } else if (authStatus.fingerprintCaptureCompleted) { + onFingerprintCaptureCompleted() + } else { + // Abandoned FP Auth attempt + _animator?.reverse() + } + } + is ErrorFingerprintAuthenticationStatus -> + onFingerprintCaptureCompleted() + is FailFingerprintAuthenticationStatus -> + onFingerprintCaptureCompleted() + is SuccessFingerprintAuthenticationStatus -> + onFingerprintCaptureCompleted() + else -> Unit + } + } + } + } + } + } +} |