Merge "Add FingerprintAuthenticationStatus" into udc-qpr-dev am: 7de73f27bb

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/24026553

Change-Id: I0da7cb7af5497e93a2dc98f0b08333a2b446db79
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Beverly Tai
2023-07-18 12:44:12 +00:00
committed by Automerger Merge Worker
19 changed files with 409 additions and 133 deletions

View File

@@ -164,13 +164,13 @@ import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.domain.interactor.FaceAuthenticationListener;
import com.android.systemui.keyguard.domain.interactor.KeyguardFaceAuthInteractor;
import com.android.systemui.keyguard.shared.constants.TrustAgentUiEvent;
import com.android.systemui.keyguard.shared.model.AcquiredAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.AuthenticationStatus;
import com.android.systemui.keyguard.shared.model.DetectionStatus;
import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.FailedAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.HelpAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.SuccessAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.AcquiredFaceAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.FaceDetectionStatus;
import com.android.systemui.keyguard.shared.model.FailedFaceAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.HelpFaceAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.SuccessFaceAuthenticationStatus;
import com.android.systemui.keyguard.shared.model.SysUiFaceAuthenticateOptions;
import com.android.systemui.log.SessionTracker;
import com.android.systemui.plugins.WeatherData;
@@ -1471,27 +1471,31 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab
private FaceAuthenticationListener mFaceAuthenticationListener =
new FaceAuthenticationListener() {
@Override
public void onAuthenticationStatusChanged(@NonNull AuthenticationStatus status) {
if (status instanceof AcquiredAuthenticationStatus) {
public void onAuthenticationStatusChanged(
@NonNull FaceAuthenticationStatus status
) {
if (status instanceof AcquiredFaceAuthenticationStatus) {
handleFaceAcquired(
((AcquiredAuthenticationStatus) status).getAcquiredInfo());
} else if (status instanceof ErrorAuthenticationStatus) {
ErrorAuthenticationStatus error = (ErrorAuthenticationStatus) status;
((AcquiredFaceAuthenticationStatus) status).getAcquiredInfo());
} else if (status instanceof ErrorFaceAuthenticationStatus) {
ErrorFaceAuthenticationStatus error =
(ErrorFaceAuthenticationStatus) status;
handleFaceError(error.getMsgId(), error.getMsg());
} else if (status instanceof FailedAuthenticationStatus) {
} else if (status instanceof FailedFaceAuthenticationStatus) {
handleFaceAuthFailed();
} else if (status instanceof HelpAuthenticationStatus) {
HelpAuthenticationStatus helpMsg = (HelpAuthenticationStatus) status;
} else if (status instanceof HelpFaceAuthenticationStatus) {
HelpFaceAuthenticationStatus helpMsg =
(HelpFaceAuthenticationStatus) status;
handleFaceHelp(helpMsg.getMsgId(), helpMsg.getMsg());
} else if (status instanceof SuccessAuthenticationStatus) {
} else if (status instanceof SuccessFaceAuthenticationStatus) {
FaceManager.AuthenticationResult result =
((SuccessAuthenticationStatus) status).getSuccessResult();
((SuccessFaceAuthenticationStatus) status).getSuccessResult();
handleFaceAuthenticated(result.getUserId(), result.isStrongBiometric());
}
}
@Override
public void onDetectionStatusChanged(@NonNull DetectionStatus status) {
public void onDetectionStatusChanged(@NonNull FaceDetectionStatus status) {
handleFaceAuthenticated(status.getUserId(), status.isStrongBiometric());
}
};

View File

@@ -16,10 +16,10 @@
package com.android.systemui.bouncer.domain.interactor
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.time.SystemClock
@@ -35,8 +35,8 @@ constructor(
private val keyguardStateController: KeyguardStateController,
private val bouncerRepository: KeyguardBouncerRepository,
private val biometricSettingsRepository: BiometricSettingsRepository,
private val deviceEntryFingerprintAuthRepository: DeviceEntryFingerprintAuthRepository,
private val systemClock: SystemClock,
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
) {
var receivedDownTouch = false
val isVisible: Flow<Boolean> = bouncerRepository.alternateBouncerVisible
@@ -78,7 +78,7 @@ constructor(
biometricSettingsRepository.isFingerprintEnrolled.value &&
biometricSettingsRepository.isStrongBiometricAllowed.value &&
biometricSettingsRepository.isFingerprintEnabledByDevicePolicy.value &&
!deviceEntryFingerprintAuthRepository.isLockedOut.value &&
!keyguardUpdateMonitor.isFingerprintLockedOut &&
!keyguardStateController.isUnlocked &&
!statusBarStateController.isDozing
}

View File

@@ -38,13 +38,13 @@ import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.AcquiredAuthenticationStatus
import com.android.systemui.keyguard.shared.model.AuthenticationStatus
import com.android.systemui.keyguard.shared.model.DetectionStatus
import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FailedAuthenticationStatus
import com.android.systemui.keyguard.shared.model.HelpAuthenticationStatus
import com.android.systemui.keyguard.shared.model.SuccessAuthenticationStatus
import com.android.systemui.keyguard.shared.model.AcquiredFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FaceDetectionStatus
import com.android.systemui.keyguard.shared.model.FailedFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.HelpFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.SuccessFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.log.FaceAuthenticationLogger
import com.android.systemui.log.SessionTracker
@@ -88,10 +88,10 @@ interface DeviceEntryFaceAuthRepository {
val canRunFaceAuth: StateFlow<Boolean>
/** Provide the current status of face authentication. */
val authenticationStatus: Flow<AuthenticationStatus>
val authenticationStatus: Flow<FaceAuthenticationStatus>
/** Provide the current status of face detection. */
val detectionStatus: Flow<DetectionStatus>
val detectionStatus: Flow<FaceDetectionStatus>
/** Current state of whether face authentication is locked out or not. */
val isLockedOut: StateFlow<Boolean>
@@ -151,13 +151,13 @@ constructor(
private var cancelNotReceivedHandlerJob: Job? = null
private var halErrorRetryJob: Job? = null
private val _authenticationStatus: MutableStateFlow<AuthenticationStatus?> =
private val _authenticationStatus: MutableStateFlow<FaceAuthenticationStatus?> =
MutableStateFlow(null)
override val authenticationStatus: Flow<AuthenticationStatus>
override val authenticationStatus: Flow<FaceAuthenticationStatus>
get() = _authenticationStatus.filterNotNull()
private val _detectionStatus = MutableStateFlow<DetectionStatus?>(null)
override val detectionStatus: Flow<DetectionStatus>
private val _detectionStatus = MutableStateFlow<FaceDetectionStatus?>(null)
override val detectionStatus: Flow<FaceDetectionStatus>
get() = _detectionStatus.filterNotNull()
private val _isLockedOut = MutableStateFlow(false)
@@ -396,18 +396,18 @@ constructor(
private val faceAuthCallback =
object : FaceManager.AuthenticationCallback() {
override fun onAuthenticationFailed() {
_authenticationStatus.value = FailedAuthenticationStatus
_authenticationStatus.value = FailedFaceAuthenticationStatus
_isAuthenticated.value = false
faceAuthLogger.authenticationFailed()
onFaceAuthRequestCompleted()
}
override fun onAuthenticationAcquired(acquireInfo: Int) {
_authenticationStatus.value = AcquiredAuthenticationStatus(acquireInfo)
_authenticationStatus.value = AcquiredFaceAuthenticationStatus(acquireInfo)
}
override fun onAuthenticationError(errorCode: Int, errString: CharSequence?) {
val errorStatus = ErrorAuthenticationStatus(errorCode, errString.toString())
val errorStatus = ErrorFaceAuthenticationStatus(errorCode, errString.toString())
if (errorStatus.isLockoutError()) {
_isLockedOut.value = true
}
@@ -433,11 +433,11 @@ constructor(
if (faceAcquiredInfoIgnoreList.contains(code)) {
return
}
_authenticationStatus.value = HelpAuthenticationStatus(code, helpStr.toString())
_authenticationStatus.value = HelpFaceAuthenticationStatus(code, helpStr.toString())
}
override fun onAuthenticationSucceeded(result: FaceManager.AuthenticationResult) {
_authenticationStatus.value = SuccessAuthenticationStatus(result)
_authenticationStatus.value = SuccessFaceAuthenticationStatus(result)
_isAuthenticated.value = true
faceAuthLogger.faceAuthSuccess(result)
onFaceAuthRequestCompleted()
@@ -482,7 +482,7 @@ constructor(
private val detectionCallback =
FaceManager.FaceDetectionCallback { sensorId, userId, isStrong ->
faceAuthLogger.faceDetected()
_detectionStatus.value = DetectionStatus(sensorId, userId, isStrong)
_detectionStatus.value = FaceDetectionStatus(sensorId, userId, isStrong)
}
private var cancellationInProgress = false

View File

@@ -21,27 +21,29 @@ import android.hardware.biometrics.BiometricAuthenticator.Modality
import android.hardware.biometrics.BiometricSourceType
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.keyguard.KeyguardUpdateMonitorCallback
import com.android.systemui.Dumpable
import com.android.systemui.biometrics.AuthController
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dump.DumpManager
import java.io.PrintWriter
import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FailedFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.HelpFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.stateIn
/** Encapsulates state about device entry fingerprint auth mechanism. */
interface DeviceEntryFingerprintAuthRepository {
/** Whether the device entry fingerprint auth is locked out. */
val isLockedOut: StateFlow<Boolean>
val isLockedOut: Flow<Boolean>
/**
* Whether the fingerprint sensor is currently listening, this doesn't mean that the user is
@@ -53,6 +55,9 @@ interface DeviceEntryFingerprintAuthRepository {
* Fingerprint sensor type present on the device, null if fingerprint sensor is not available.
*/
val availableFpSensorType: Flow<BiometricType?>
/** Provide the current status of fingerprint authentication. */
val authenticationStatus: Flow<FingerprintAuthenticationStatus>
}
/**
@@ -69,16 +74,7 @@ constructor(
val authController: AuthController,
val keyguardUpdateMonitor: KeyguardUpdateMonitor,
@Application scope: CoroutineScope,
dumpManager: DumpManager,
) : DeviceEntryFingerprintAuthRepository, Dumpable {
init {
dumpManager.registerDumpable(this)
}
override fun dump(pw: PrintWriter, args: Array<String?>) {
pw.println("isLockedOut=${isLockedOut.value}")
}
) : DeviceEntryFingerprintAuthRepository {
override val availableFpSensorType: Flow<BiometricType?>
get() {
@@ -114,7 +110,7 @@ constructor(
else if (authController.isRearFpsSupported) BiometricType.REAR_FINGERPRINT else null
}
override val isLockedOut: StateFlow<Boolean> =
override val isLockedOut: Flow<Boolean> =
conflatedCallbackFlow {
val sendLockoutUpdate =
fun() {
@@ -138,7 +134,7 @@ constructor(
sendLockoutUpdate()
awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
}
.stateIn(scope, started = SharingStarted.Eagerly, initialValue = false)
.stateIn(scope, started = SharingStarted.WhileSubscribed(), initialValue = false)
override val isRunning: Flow<Boolean>
get() = conflatedCallbackFlow {
@@ -166,6 +162,93 @@ constructor(
awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
}
override val authenticationStatus: Flow<FingerprintAuthenticationStatus>
get() = conflatedCallbackFlow {
val callback =
object : KeyguardUpdateMonitorCallback() {
override fun onBiometricAuthenticated(
userId: Int,
biometricSourceType: BiometricSourceType,
isStrongBiometric: Boolean,
) {
sendUpdateIfFingerprint(
biometricSourceType,
SuccessFingerprintAuthenticationStatus(
userId,
isStrongBiometric,
),
)
}
override fun onBiometricError(
msgId: Int,
errString: String?,
biometricSourceType: BiometricSourceType,
) {
sendUpdateIfFingerprint(
biometricSourceType,
ErrorFingerprintAuthenticationStatus(
msgId,
errString,
),
)
}
override fun onBiometricHelp(
msgId: Int,
helpString: String?,
biometricSourceType: BiometricSourceType,
) {
sendUpdateIfFingerprint(
biometricSourceType,
HelpFingerprintAuthenticationStatus(
msgId,
helpString,
),
)
}
override fun onBiometricAuthFailed(
biometricSourceType: BiometricSourceType,
) {
sendUpdateIfFingerprint(
biometricSourceType,
FailedFingerprintAuthenticationStatus,
)
}
override fun onBiometricAcquired(
biometricSourceType: BiometricSourceType,
acquireInfo: Int,
) {
sendUpdateIfFingerprint(
biometricSourceType,
AcquiredFingerprintAuthenticationStatus(
acquireInfo,
),
)
}
private fun sendUpdateIfFingerprint(
biometricSourceType: BiometricSourceType,
authenticationStatus: FingerprintAuthenticationStatus
) {
if (biometricSourceType != BiometricSourceType.FINGERPRINT) {
return
}
trySendWithFailureLogging(
authenticationStatus,
TAG,
"new fingerprint authentication status"
)
}
}
keyguardUpdateMonitor.registerCallback(callback)
awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
}
companion object {
const val TAG = "DeviceEntryFingerprintAuthRepositoryImpl"
}

View File

@@ -18,8 +18,8 @@ package com.android.systemui.keyguard.data.repository
import com.android.keyguard.FaceAuthUiEvent
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.AuthenticationStatus
import com.android.systemui.keyguard.shared.model.DetectionStatus
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FaceDetectionStatus
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -40,10 +40,10 @@ class NoopDeviceEntryFaceAuthRepository @Inject constructor() : DeviceEntryFaceA
private val _canRunFaceAuth = MutableStateFlow(false)
override val canRunFaceAuth: StateFlow<Boolean> = _canRunFaceAuth
override val authenticationStatus: Flow<AuthenticationStatus>
override val authenticationStatus: Flow<FaceAuthenticationStatus>
get() = emptyFlow()
override val detectionStatus: Flow<DetectionStatus>
override val detectionStatus: Flow<FaceDetectionStatus>
get() = emptyFlow()
private val _isLockedOut = MutableStateFlow(false)

View File

@@ -16,8 +16,8 @@
package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.keyguard.shared.model.AuthenticationStatus
import com.android.systemui.keyguard.shared.model.DetectionStatus
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FaceDetectionStatus
import kotlinx.coroutines.flow.Flow
/**
@@ -27,10 +27,10 @@ import kotlinx.coroutines.flow.Flow
interface KeyguardFaceAuthInteractor {
/** Current authentication status */
val authenticationStatus: Flow<AuthenticationStatus>
val authenticationStatus: Flow<FaceAuthenticationStatus>
/** Current detection status */
val detectionStatus: Flow<DetectionStatus>
val detectionStatus: Flow<FaceDetectionStatus>
/** Can face auth be run right now */
fun canFaceAuthRun(): Boolean
@@ -72,8 +72,8 @@ interface KeyguardFaceAuthInteractor {
*/
interface FaceAuthenticationListener {
/** Receive face authentication status updates */
fun onAuthenticationStatusChanged(status: AuthenticationStatus)
fun onAuthenticationStatusChanged(status: FaceAuthenticationStatus)
/** Receive status updates whenever face detection runs */
fun onDetectionStatusChanged(status: DetectionStatus)
fun onDetectionStatusChanged(status: FaceDetectionStatus)
}

View File

@@ -17,8 +17,8 @@
package com.android.systemui.keyguard.domain.interactor
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.AuthenticationStatus
import com.android.systemui.keyguard.shared.model.DetectionStatus
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FaceDetectionStatus
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow
@@ -31,9 +31,9 @@ import kotlinx.coroutines.flow.emptyFlow
*/
@SysUISingleton
class NoopKeyguardFaceAuthInteractor @Inject constructor() : KeyguardFaceAuthInteractor {
override val authenticationStatus: Flow<AuthenticationStatus>
override val authenticationStatus: Flow<FaceAuthenticationStatus>
get() = emptyFlow()
override val detectionStatus: Flow<DetectionStatus>
override val detectionStatus: Flow<FaceDetectionStatus>
get() = emptyFlow()
override fun canFaceAuthRun(): Boolean = false

View File

@@ -30,8 +30,8 @@ import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.shared.model.AuthenticationStatus
import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.log.FaceAuthenticationLogger
import com.android.systemui.util.kotlin.pairwise
@@ -165,10 +165,10 @@ constructor(
repository.cancel()
}
private val _authenticationStatusOverride = MutableStateFlow<AuthenticationStatus?>(null)
private val faceAuthenticationStatusOverride = MutableStateFlow<FaceAuthenticationStatus?>(null)
/** Provide the status of face authentication */
override val authenticationStatus =
merge(_authenticationStatusOverride.filterNotNull(), repository.authenticationStatus)
merge(faceAuthenticationStatusOverride.filterNotNull(), repository.authenticationStatus)
/** Provide the status of face detection */
override val detectionStatus = repository.detectionStatus
@@ -176,13 +176,13 @@ constructor(
private fun runFaceAuth(uiEvent: FaceAuthUiEvent, fallbackToDetect: Boolean) {
if (featureFlags.isEnabled(Flags.FACE_AUTH_REFACTOR)) {
if (repository.isLockedOut.value) {
_authenticationStatusOverride.value =
ErrorAuthenticationStatus(
faceAuthenticationStatusOverride.value =
ErrorFaceAuthenticationStatus(
BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT,
context.resources.getString(R.string.keyguard_face_unlock_unavailable)
)
} else {
_authenticationStatusOverride.value = null
faceAuthenticationStatusOverride.value = null
applicationScope.launch {
faceAuthenticationLogger.authRequested(uiEvent)
repository.authenticate(uiEvent, fallbackToDetection = fallbackToDetect)

View File

@@ -23,33 +23,35 @@ import android.os.SystemClock.elapsedRealtime
* Authentication status provided by
* [com.android.systemui.keyguard.data.repository.DeviceEntryFaceAuthRepository]
*/
sealed class AuthenticationStatus
sealed class FaceAuthenticationStatus
/** Success authentication status. */
data class SuccessAuthenticationStatus(val successResult: FaceManager.AuthenticationResult) :
AuthenticationStatus()
data class SuccessFaceAuthenticationStatus(val successResult: FaceManager.AuthenticationResult) :
FaceAuthenticationStatus()
/** Face authentication help message. */
data class HelpAuthenticationStatus(val msgId: Int, val msg: String?) : AuthenticationStatus()
data class HelpFaceAuthenticationStatus(val msgId: Int, val msg: String?) :
FaceAuthenticationStatus()
/** Face acquired message. */
data class AcquiredAuthenticationStatus(val acquiredInfo: Int) : AuthenticationStatus()
data class AcquiredFaceAuthenticationStatus(val acquiredInfo: Int) : FaceAuthenticationStatus()
/** Face authentication failed message. */
object FailedAuthenticationStatus : AuthenticationStatus()
object FailedFaceAuthenticationStatus : FaceAuthenticationStatus()
/** Face authentication error message */
data class ErrorAuthenticationStatus(
data class ErrorFaceAuthenticationStatus(
val msgId: Int,
val msg: String? = null,
// present to break equality check if the same error occurs repeatedly.
val createdAt: Long = elapsedRealtime()
) : AuthenticationStatus() {
) : FaceAuthenticationStatus() {
/**
* Method that checks if [msgId] is a lockout error. A lockout error means that face
* authentication is locked out.
*/
fun isLockoutError() = msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT
fun isLockoutError() =
msgId == FaceManager.FACE_ERROR_LOCKOUT_PERMANENT || msgId == FaceManager.FACE_ERROR_LOCKOUT
/**
* Method that checks if [msgId] is a cancellation error. This means that face authentication
@@ -64,4 +66,4 @@ data class ErrorAuthenticationStatus(
}
/** Face detection success message. */
data class DetectionStatus(val sensorId: Int, val userId: Int, val isStrongBiometric: Boolean)
data class FaceDetectionStatus(val sensorId: Int, val userId: Int, val isStrongBiometric: Boolean)

View File

@@ -0,0 +1,52 @@
/*
* 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.shared.model
import android.os.SystemClock.elapsedRealtime
/**
* Fingerprint authentication status provided by
* [com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository]
*/
sealed class FingerprintAuthenticationStatus
/** Fingerprint authentication success status. */
data class SuccessFingerprintAuthenticationStatus(
val userId: Int,
val isStrongBiometric: Boolean,
) : FingerprintAuthenticationStatus()
/** Fingerprint authentication help message. */
data class HelpFingerprintAuthenticationStatus(
val msgId: Int,
val msg: String?,
) : FingerprintAuthenticationStatus()
/** Fingerprint acquired message. */
data class AcquiredFingerprintAuthenticationStatus(val acquiredInfo: Int) :
FingerprintAuthenticationStatus()
/** Fingerprint authentication failed message. */
object FailedFingerprintAuthenticationStatus : FingerprintAuthenticationStatus()
/** Fingerprint authentication error message */
data class ErrorFingerprintAuthenticationStatus(
val msgId: Int,
val msg: String? = null,
// present to break equality check if the same error occurs repeatedly.
val createdAt: Long = elapsedRealtime(),
) : FingerprintAuthenticationStatus()

View File

@@ -4,7 +4,7 @@ import android.hardware.face.FaceManager
import android.hardware.face.FaceSensorPropertiesInternal
import com.android.keyguard.FaceAuthUiEvent
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.log.core.LogLevel.DEBUG
import com.android.systemui.log.dagger.FaceAuthLog
@@ -240,7 +240,7 @@ constructor(
)
}
fun hardwareError(errorStatus: ErrorAuthenticationStatus) {
fun hardwareError(errorStatus: ErrorFaceAuthenticationStatus) {
logBuffer.log(
TAG,
DEBUG,

View File

@@ -48,6 +48,7 @@ import android.view.WindowMetrics
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.airbnb.lottie.LottieAnimationView
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.R
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
@@ -64,7 +65,6 @@ import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepositor
import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.util.concurrency.FakeExecutor
@@ -153,8 +153,8 @@ class SideFpsControllerTest : SysuiTestCase() {
mock(KeyguardStateController::class.java),
keyguardBouncerRepository,
FakeBiometricSettingsRepository(),
FakeDeviceEntryFingerprintAuthRepository(),
FakeSystemClock(),
mock(KeyguardUpdateMonitor::class.java),
)
displayStateInteractor =
DisplayStateInteractorImpl(

View File

@@ -34,7 +34,6 @@ import com.android.systemui.flags.FakeFeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.DeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.plugins.statusbar.StatusBarStateController
@@ -106,8 +105,8 @@ class UdfpsKeyguardViewLegacyControllerWithCoroutinesTest :
mock(KeyguardStateController::class.java),
keyguardBouncerRepository,
mock(BiometricSettingsRepository::class.java),
mock(DeviceEntryFingerprintAuthRepository::class.java),
mock(SystemClock::class.java),
mKeyguardUpdateMonitor,
)
return createUdfpsKeyguardViewController(
/* useModernBouncer */ true, /* useExpandedOverlay */

View File

@@ -18,6 +18,7 @@ package com.android.systemui.bouncer.domain.interactor
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.KeyguardBouncerRepository
@@ -54,6 +55,7 @@ class AlternateBouncerInteractorTest : SysuiTestCase() {
@Mock private lateinit var keyguardStateController: KeyguardStateController
@Mock private lateinit var systemClock: SystemClock
@Mock private lateinit var bouncerLogger: TableLogBuffer
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Before
fun setup() {
@@ -72,8 +74,8 @@ class AlternateBouncerInteractorTest : SysuiTestCase() {
keyguardStateController,
bouncerRepository,
biometricSettingsRepository,
deviceEntryFingerprintAuthRepository,
systemClock,
keyguardUpdateMonitor,
)
}
@@ -118,7 +120,7 @@ class AlternateBouncerInteractorTest : SysuiTestCase() {
@Test
fun canShowAlternateBouncerForFingerprint_fingerprintLockedOut() {
givenCanShowAlternateBouncer()
deviceEntryFingerprintAuthRepository.setLockedOut(true)
whenever(keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(true)
assertFalse(underTest.canShowAlternateBouncerForFingerprint())
}
@@ -168,7 +170,7 @@ class AlternateBouncerInteractorTest : SysuiTestCase() {
biometricSettingsRepository.setFingerprintEnrolled(true)
biometricSettingsRepository.setStrongBiometricAllowed(true)
biometricSettingsRepository.setFingerprintEnabledByDevicePolicy(true)
deviceEntryFingerprintAuthRepository.setLockedOut(false)
whenever(keyguardUpdateMonitor.isFingerprintLockedOut).thenReturn(false)
whenever(keyguardStateController.isUnlocked).thenReturn(false)
}

View File

@@ -36,6 +36,7 @@ import com.android.internal.logging.UiEventLogger
import com.android.keyguard.FaceAuthUiEvent
import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_ALTERNATE_BIOMETRIC_BOUNCER_SHOWN
import com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_TRIGGERED_SWIPE_UP_ON_BOUNCER
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.R
import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
@@ -50,12 +51,12 @@ import com.android.systemui.flags.Flags.FACE_AUTH_REFACTOR
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
import com.android.systemui.keyguard.shared.model.AuthenticationStatus
import com.android.systemui.keyguard.shared.model.DetectionStatus
import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
import com.android.systemui.keyguard.shared.model.HelpAuthenticationStatus
import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FaceDetectionStatus
import com.android.systemui.keyguard.shared.model.HelpFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.SuccessAuthenticationStatus
import com.android.systemui.keyguard.shared.model.SuccessFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.shared.model.WakeSleepReason
@@ -113,6 +114,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
@Mock private lateinit var sessionTracker: SessionTracker
@Mock private lateinit var uiEventLogger: UiEventLogger
@Mock private lateinit var dumpManager: DumpManager
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Captor
private lateinit var authenticationCallback: ArgumentCaptor<FaceManager.AuthenticationCallback>
@@ -131,8 +133,8 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
private lateinit var testScope: TestScope
private lateinit var fakeUserRepository: FakeUserRepository
private lateinit var authStatus: FlowValue<AuthenticationStatus?>
private lateinit var detectStatus: FlowValue<DetectionStatus?>
private lateinit var authStatus: FlowValue<FaceAuthenticationStatus?>
private lateinit var detectStatus: FlowValue<FaceDetectionStatus?>
private lateinit var authRunning: FlowValue<Boolean?>
private lateinit var bypassEnabled: FlowValue<Boolean?>
private lateinit var lockedOut: FlowValue<Boolean?>
@@ -175,10 +177,10 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
AlternateBouncerInteractor(
bouncerRepository = bouncerRepository,
biometricSettingsRepository = biometricSettingsRepository,
deviceEntryFingerprintAuthRepository = deviceEntryFingerprintAuthRepository,
systemClock = mock(SystemClock::class.java),
keyguardStateController = FakeKeyguardStateController(),
statusBarStateController = mock(StatusBarStateController::class.java),
keyguardUpdateMonitor = keyguardUpdateMonitor,
)
bypassStateChangedListener =
@@ -262,7 +264,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
val successResult = successResult()
authenticationCallback.value.onAuthenticationSucceeded(successResult)
assertThat(authStatus()).isEqualTo(SuccessAuthenticationStatus(successResult))
assertThat(authStatus()).isEqualTo(SuccessFaceAuthenticationStatus(successResult))
assertThat(authenticated()).isTrue()
assertThat(authRunning()).isFalse()
assertThat(canFaceAuthRun()).isFalse()
@@ -383,7 +385,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
detectionCallback.value.onFaceDetected(1, 1, true)
assertThat(detectStatus()).isEqualTo(DetectionStatus(1, 1, true))
assertThat(detectStatus()).isEqualTo(FaceDetectionStatus(1, 1, true))
}
@Test
@@ -423,7 +425,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
FACE_ERROR_CANCELED,
"First auth attempt cancellation completed"
)
val value = authStatus() as ErrorAuthenticationStatus
val value = authStatus() as ErrorFaceAuthenticationStatus
assertThat(value.msgId).isEqualTo(FACE_ERROR_CANCELED)
assertThat(value.msg).isEqualTo("First auth attempt cancellation completed")
@@ -465,7 +467,7 @@ class DeviceEntryFaceAuthRepositoryTest : SysuiTestCase() {
authenticationCallback.value.onAuthenticationHelp(10, "Ignored help msg")
authenticationCallback.value.onAuthenticationHelp(11, "Ignored help msg")
assertThat(authStatus()).isEqualTo(HelpAuthenticationStatus(9, "help msg"))
assertThat(authStatus()).isEqualTo(HelpFaceAuthenticationStatus(9, "help msg"))
}
@Test

View File

@@ -26,7 +26,11 @@ import com.android.systemui.RoboPilotTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.biometrics.AuthController
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.shared.model.AcquiredFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.ErrorFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FailedFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.HelpFingerprintAuthenticationStatus
import com.android.systemui.keyguard.shared.model.SuccessFingerprintAuthenticationStatus
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -49,7 +53,6 @@ import org.mockito.MockitoAnnotations
@RunWith(AndroidJUnit4::class)
class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() {
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
@Mock private lateinit var dumpManager: DumpManager
@Mock private lateinit var authController: AuthController
@Captor
private lateinit var updateMonitorCallback: ArgumentCaptor<KeyguardUpdateMonitorCallback>
@@ -68,7 +71,6 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() {
authController,
keyguardUpdateMonitor,
testScope.backgroundScope,
dumpManager,
)
}
@@ -177,4 +179,129 @@ class DeviceEntryFingerprintAuthRepositoryTest : SysuiTestCase() {
callback.value.onAllAuthenticatorsRegistered(TYPE_FINGERPRINT)
assertThat(availableFpSensorType()).isEqualTo(BiometricType.UNDER_DISPLAY_FINGERPRINT)
}
@Test
fun onFingerprintSuccess_successAuthenticationStatus() =
testScope.runTest {
val authenticationStatus by collectLastValue(underTest.authenticationStatus)
runCurrent()
verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
updateMonitorCallback.value.onBiometricAuthenticated(
0,
BiometricSourceType.FINGERPRINT,
true,
)
val status = authenticationStatus as SuccessFingerprintAuthenticationStatus
assertThat(status.userId).isEqualTo(0)
assertThat(status.isStrongBiometric).isEqualTo(true)
}
@Test
fun onFingerprintFailed_failedAuthenticationStatus() =
testScope.runTest {
val authenticationStatus by collectLastValue(underTest.authenticationStatus)
runCurrent()
verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
updateMonitorCallback.value.onBiometricAuthFailed(
BiometricSourceType.FINGERPRINT,
)
assertThat(authenticationStatus)
.isInstanceOf(FailedFingerprintAuthenticationStatus::class.java)
}
@Test
fun onFingerprintError_errorAuthenticationStatus() =
testScope.runTest {
val authenticationStatus by collectLastValue(underTest.authenticationStatus)
runCurrent()
verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
updateMonitorCallback.value.onBiometricError(
1,
"test_string",
BiometricSourceType.FINGERPRINT,
)
val status = authenticationStatus as ErrorFingerprintAuthenticationStatus
assertThat(status.msgId).isEqualTo(1)
assertThat(status.msg).isEqualTo("test_string")
}
@Test
fun onFingerprintHelp_helpAuthenticationStatus() =
testScope.runTest {
val authenticationStatus by collectLastValue(underTest.authenticationStatus)
runCurrent()
verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
updateMonitorCallback.value.onBiometricHelp(
1,
"test_string",
BiometricSourceType.FINGERPRINT,
)
val status = authenticationStatus as HelpFingerprintAuthenticationStatus
assertThat(status.msgId).isEqualTo(1)
assertThat(status.msg).isEqualTo("test_string")
}
@Test
fun onFingerprintAcquired_acquiredAuthenticationStatus() =
testScope.runTest {
val authenticationStatus by collectLastValue(underTest.authenticationStatus)
runCurrent()
verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
updateMonitorCallback.value.onBiometricAcquired(
BiometricSourceType.FINGERPRINT,
5,
)
val status = authenticationStatus as AcquiredFingerprintAuthenticationStatus
assertThat(status.acquiredInfo).isEqualTo(5)
}
@Test
fun onFaceCallbacks_fingerprintAuthenticationStatusIsUnchanged() =
testScope.runTest {
val authenticationStatus by collectLastValue(underTest.authenticationStatus)
runCurrent()
verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
updateMonitorCallback.value.onBiometricAuthenticated(
0,
BiometricSourceType.FACE,
true,
)
assertThat(authenticationStatus).isNull()
updateMonitorCallback.value.onBiometricAuthFailed(
BiometricSourceType.FACE,
)
assertThat(authenticationStatus).isNull()
updateMonitorCallback.value.onBiometricHelp(
1,
"test_string",
BiometricSourceType.FACE,
)
assertThat(authenticationStatus).isNull()
updateMonitorCallback.value.onBiometricAcquired(
BiometricSourceType.FACE,
5,
)
assertThat(authenticationStatus).isNull()
updateMonitorCallback.value.onBiometricError(
1,
"test_string",
BiometricSourceType.FACE,
)
assertThat(authenticationStatus).isNull()
}
}

View File

@@ -38,10 +38,9 @@ import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.BiometricSettingsRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFaceAuthRepository
import com.android.systemui.keyguard.data.repository.FakeDeviceEntryFingerprintAuthRepository
import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.FakeTrustRepository
import com.android.systemui.keyguard.shared.model.ErrorAuthenticationStatus
import com.android.systemui.keyguard.shared.model.ErrorFaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -121,8 +120,8 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
mock(KeyguardStateController::class.java),
bouncerRepository,
mock(BiometricSettingsRepository::class.java),
FakeDeviceEntryFingerprintAuthRepository(),
FakeSystemClock(),
keyguardUpdateMonitor,
),
keyguardTransitionInteractor,
featureFlags,
@@ -160,7 +159,7 @@ class KeyguardFaceAuthInteractorTest : SysuiTestCase() {
underTest.onDeviceLifted()
val outputValue = authenticationStatus()!! as ErrorAuthenticationStatus
val outputValue = authenticationStatus()!! as ErrorFaceAuthenticationStatus
assertThat(outputValue.msgId)
.isEqualTo(BiometricFaceConstants.FACE_ERROR_LOCKOUT_PERMANENT)
assertThat(outputValue.msg).isEqualTo("Face Unlock unavailable")

View File

@@ -17,8 +17,8 @@
package com.android.systemui.keyguard.data.repository
import com.android.keyguard.FaceAuthUiEvent
import com.android.systemui.keyguard.shared.model.AuthenticationStatus
import com.android.systemui.keyguard.shared.model.DetectionStatus
import com.android.systemui.keyguard.shared.model.FaceAuthenticationStatus
import com.android.systemui.keyguard.shared.model.FaceDetectionStatus
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -29,16 +29,16 @@ class FakeDeviceEntryFaceAuthRepository : DeviceEntryFaceAuthRepository {
override val isAuthenticated = MutableStateFlow(false)
override val canRunFaceAuth = MutableStateFlow(false)
private val _authenticationStatus = MutableStateFlow<AuthenticationStatus?>(null)
override val authenticationStatus: Flow<AuthenticationStatus> =
private val _authenticationStatus = MutableStateFlow<FaceAuthenticationStatus?>(null)
override val authenticationStatus: Flow<FaceAuthenticationStatus> =
_authenticationStatus.filterNotNull()
fun setAuthenticationStatus(status: AuthenticationStatus) {
fun setAuthenticationStatus(status: FaceAuthenticationStatus) {
_authenticationStatus.value = status
}
private val _detectionStatus = MutableStateFlow<DetectionStatus?>(null)
override val detectionStatus: Flow<DetectionStatus>
private val _detectionStatus = MutableStateFlow<FaceDetectionStatus?>(null)
override val detectionStatus: Flow<FaceDetectionStatus>
get() = _detectionStatus.filterNotNull()
fun setDetectionStatus(status: DetectionStatus) {
fun setDetectionStatus(status: FaceDetectionStatus) {
_detectionStatus.value = status
}

View File

@@ -17,32 +17,38 @@
package com.android.systemui.keyguard.data.repository
import com.android.systemui.keyguard.shared.model.FingerprintAuthenticationStatus
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.filterNotNull
class FakeDeviceEntryFingerprintAuthRepository : DeviceEntryFingerprintAuthRepository {
private val _isLockedOut = MutableStateFlow(false)
override val isLockedOut: StateFlow<Boolean> = _isLockedOut.asStateFlow()
private val _isRunning = MutableStateFlow(false)
override val isRunning: Flow<Boolean>
get() = _isRunning
private var fpSensorType = MutableStateFlow<BiometricType?>(null)
override val availableFpSensorType: Flow<BiometricType?>
get() = fpSensorType
fun setLockedOut(lockedOut: Boolean) {
_isLockedOut.value = lockedOut
}
private val _isRunning = MutableStateFlow(false)
override val isRunning: Flow<Boolean>
get() = _isRunning
fun setIsRunning(value: Boolean) {
_isRunning.value = value
}
private var fpSensorType = MutableStateFlow<BiometricType?>(null)
override val availableFpSensorType: Flow<BiometricType?>
get() = fpSensorType
fun setAvailableFpSensorType(value: BiometricType?) {
fpSensorType.value = value
}
private var _authenticationStatus = MutableStateFlow<FingerprintAuthenticationStatus?>(null)
override val authenticationStatus: Flow<FingerprintAuthenticationStatus>
get() = _authenticationStatus.filterNotNull()
fun setAuthenticationStatus(status: FingerprintAuthenticationStatus) {
_authenticationStatus.value = status
}
}