summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Joe Bolinger <jbolinger@google.com> 2023-09-13 17:43:22 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-09-13 17:43:22 +0000
commitd9c84d54e761ac950d7e22e589a7aa02c5ae5ba8 (patch)
tree4ee55dca1f71f2d8924dc27e8a258aba3dedd076
parentc79159b4dace114dbac0051c3edacadf7080a901 (diff)
parent55e60b12a3e3fceb1490b32baca3d4072d23e274 (diff)
Merge "Remove released flag BIOMETRIC_BP_STRONG." into main
-rw-r--r--packages/SystemUI/Android.bp2
-rw-r--r--packages/SystemUI/res/layout/auth_biometric_contents.xml165
-rw-r--r--packages/SystemUI/res/layout/auth_biometric_face_view.xml26
-rw-r--r--packages/SystemUI/res/layout/auth_biometric_fingerprint_and_face_view.xml26
-rw-r--r--packages/SystemUI/res/layout/auth_biometric_fingerprint_view.xml26
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt36
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.kt80
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt58
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt45
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt113
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java984
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricViewAdapter.kt56
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java195
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java29
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java66
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthIconController.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt125
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt164
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconControllerTest.kt5
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt283
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt32
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest2.kt30
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java71
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt53
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt34
30 files changed, 236 insertions, 2534 deletions
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 000612b1fb6f..77925d6f03cd 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -296,8 +296,6 @@ filegroup {
/* Biometric converted tests */
"tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt",
- "tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt",
- "tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt",
"tests/src/com/android/systemui/biometrics/AuthControllerTest.java",
"tests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java",
"tests/src/com/android/systemui/biometrics/FaceHelpMessageDeferralTest.kt",
diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml
deleted file mode 100644
index 50b3bec93731..000000000000
--- a/packages/SystemUI/res/layout/auth_biometric_contents.xml
+++ /dev/null
@@ -1,165 +0,0 @@
-<!--
- ~ Copyright (C) 2019 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.
- -->
-<!-- TODO(b/251476085): inline in biometric_prompt_layout after Biometric*Views are un-flagged -->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-
- <TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="@integer/biometric_dialog_text_gravity"
- android:singleLine="true"
- android:marqueeRepeatLimit="1"
- android:ellipsize="marquee"
- android:importantForAccessibility="no"
- style="@style/TextAppearance.AuthCredential.Title"/>
-
- <TextView
- android:id="@+id/subtitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="@integer/biometric_dialog_text_gravity"
- android:singleLine="true"
- android:marqueeRepeatLimit="1"
- android:ellipsize="marquee"
- android:importantForAccessibility="no"
- style="@style/TextAppearance.AuthCredential.Subtitle"/>
-
- <TextView
- android:id="@+id/description"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:scrollbars ="vertical"
- style="@style/TextAppearance.AuthCredential.Description"/>
-
- <Space android:id="@+id/space_above_icon"
- android:layout_width="match_parent"
- android:layout_height="48dp" />
-
- <FrameLayout
- android:id="@+id/biometric_icon_frame"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center">
-
- <include layout="@layout/auth_biometric_icon"/>
-
- <com.android.systemui.biometrics.BiometricPromptLottieViewWrapper
- android:id="@+id/biometric_icon_overlay"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:contentDescription="@null"
- android:scaleType="fitXY" />
- </FrameLayout>
-
- <!-- For sensors such as UDFPS, this view is used during custom measurement/layout to add extra
- padding so that the biometric icon is always in the right physical position. -->
- <Space android:id="@+id/space_below_icon"
- android:layout_width="match_parent"
- android:layout_height="12dp" />
-
- <TextView
- android:id="@+id/indicator"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingHorizontal="24dp"
- android:textSize="12sp"
- android:gravity="center_horizontal"
- android:accessibilityLiveRegion="polite"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="marquee_forever"
- android:scrollHorizontally="true"
- android:fadingEdge="horizontal"
- android:textColor="@color/biometric_dialog_gray"/>
-
- <LinearLayout
- android:id="@+id/button_bar"
- android:layout_width="match_parent"
- android:layout_height="88dp"
- style="?android:attr/buttonBarStyle"
- android:orientation="horizontal"
- android:paddingTop="24dp">
-
- <Space android:id="@+id/leftSpacer"
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:visibility="visible" />
-
- <!-- Negative Button, reserved for app -->
- <Button android:id="@+id/button_negative"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_gravity="center_vertical"
- android:ellipsize="end"
- android:maxLines="2"
- android:maxWidth="@dimen/biometric_dialog_button_negative_max_width"/>
- <!-- Cancel Button, replaces negative button when biometric is accepted -->
- <Button android:id="@+id/button_cancel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_gravity="center_vertical"
- android:maxWidth="@dimen/biometric_dialog_button_negative_max_width"
- android:text="@string/cancel"
- android:visibility="gone"/>
- <!-- "Use Credential" Button, replaces if device credential is allowed -->
- <Button android:id="@+id/button_use_credential"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@*android:style/Widget.DeviceDefault.Button.Borderless.Colored"
- android:layout_gravity="center_vertical"
- android:maxWidth="@dimen/biometric_dialog_button_negative_max_width"
- android:visibility="gone"/>
-
- <Space android:id="@+id/middleSpacer"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_weight="1"
- android:visibility="visible"/>
-
- <!-- Positive Button -->
- <Button android:id="@+id/button_confirm"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@*android:style/Widget.DeviceDefault.Button.Colored"
- android:layout_gravity="center_vertical"
- android:ellipsize="end"
- android:maxLines="2"
- android:maxWidth="@dimen/biometric_dialog_button_positive_max_width"
- android:text="@string/biometric_dialog_confirm"
- android:visibility="gone"/>
- <!-- Try Again Button -->
- <Button android:id="@+id/button_try_again"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- style="@*android:style/Widget.DeviceDefault.Button.Colored"
- android:layout_gravity="center_vertical"
- android:ellipsize="end"
- android:maxLines="2"
- android:maxWidth="@dimen/biometric_dialog_button_positive_max_width"
- android:text="@string/biometric_dialog_try_again"
- android:visibility="gone"/>
-
- <Space android:id="@+id/rightSpacer"
- android:layout_width="8dp"
- android:layout_height="match_parent"
- android:visibility="visible" />
- </LinearLayout>
-
-</merge> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_biometric_face_view.xml b/packages/SystemUI/res/layout/auth_biometric_face_view.xml
deleted file mode 100644
index e3d073276369..000000000000
--- a/packages/SystemUI/res/layout/auth_biometric_face_view.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
- ~ Copyright (C) 2019 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.
- -->
-<!-- TODO(b/251476085): remove after BiometricFaceView is un-flagged -->
-<com.android.systemui.biometrics.AuthBiometricFaceView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/contents"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <include layout="@layout/auth_biometric_contents"/>
-
-</com.android.systemui.biometrics.AuthBiometricFaceView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_biometric_fingerprint_and_face_view.xml b/packages/SystemUI/res/layout/auth_biometric_fingerprint_and_face_view.xml
deleted file mode 100644
index 896d8362f5b9..000000000000
--- a/packages/SystemUI/res/layout/auth_biometric_fingerprint_and_face_view.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
- ~ Copyright (C) 2021 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.
- -->
-<!-- TODO(b/251476085): remove after BiometricFingerprintAndFaceView is un-flagged -->
-<com.android.systemui.biometrics.AuthBiometricFingerprintAndFaceView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/contents"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <include layout="@layout/auth_biometric_contents"/>
-
-</com.android.systemui.biometrics.AuthBiometricFingerprintAndFaceView> \ No newline at end of file
diff --git a/packages/SystemUI/res/layout/auth_biometric_fingerprint_view.xml b/packages/SystemUI/res/layout/auth_biometric_fingerprint_view.xml
deleted file mode 100644
index e36f9796be47..000000000000
--- a/packages/SystemUI/res/layout/auth_biometric_fingerprint_view.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
- ~ Copyright (C) 2019 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.
- -->
-<!-- TODO(b/251476085): remove after BiometricFingerprintView is un-flagged -->
-<com.android.systemui.biometrics.AuthBiometricFingerprintView
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/contents"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <include layout="@layout/auth_biometric_contents"/>
-
-</com.android.systemui.biometrics.AuthBiometricFingerprintView> \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt
index 0c7d56f46530..ea8f5d376ba7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceIconController.kt
@@ -20,14 +20,7 @@ import android.graphics.drawable.Drawable
import android.util.Log
import com.airbnb.lottie.LottieAnimationView
import com.android.systemui.R
-import com.android.systemui.biometrics.AuthBiometricView.BiometricState
-import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATED
-import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATING
-import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATING_ANIMATING_IN
-import com.android.systemui.biometrics.AuthBiometricView.STATE_ERROR
-import com.android.systemui.biometrics.AuthBiometricView.STATE_HELP
-import com.android.systemui.biometrics.AuthBiometricView.STATE_IDLE
-import com.android.systemui.biometrics.AuthBiometricView.STATE_PENDING_CONFIRMATION
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState
private const val TAG = "AuthBiometricFaceIconController"
@@ -40,8 +33,7 @@ class AuthBiometricFaceIconController(
// false = dark to light, true = light to dark
private var lastPulseLightToDark = false
- @BiometricState
- private var state = 0
+ private var state: BiometricState = BiometricState.STATE_IDLE
init {
val size = context.resources.getDimensionPixelSize(R.dimen.biometric_dialog_face_icon_size)
@@ -66,54 +58,54 @@ class AuthBiometricFaceIconController(
}
override fun handleAnimationEnd(drawable: Drawable) {
- if (state == STATE_AUTHENTICATING || state == STATE_HELP) {
+ if (state == BiometricState.STATE_AUTHENTICATING || state == BiometricState.STATE_HELP) {
pulseInNextDirection()
}
}
- override fun updateIcon(@BiometricState oldState: Int, @BiometricState newState: Int) {
- val lastStateIsErrorIcon = (oldState == STATE_ERROR || oldState == STATE_HELP)
- if (newState == STATE_AUTHENTICATING_ANIMATING_IN) {
+ override fun updateIcon(oldState: BiometricState, newState: BiometricState) {
+ val lastStateIsErrorIcon = (oldState == BiometricState.STATE_ERROR || oldState == BiometricState.STATE_HELP)
+ if (newState == BiometricState.STATE_AUTHENTICATING_ANIMATING_IN) {
showStaticDrawable(R.drawable.face_dialog_pulse_dark_to_light)
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_authenticating
)
- } else if (newState == STATE_AUTHENTICATING) {
+ } else if (newState == BiometricState.STATE_AUTHENTICATING) {
startPulsing()
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_authenticating
)
- } else if (oldState == STATE_PENDING_CONFIRMATION && newState == STATE_AUTHENTICATED) {
+ } else if (oldState == BiometricState.STATE_PENDING_CONFIRMATION && newState == BiometricState.STATE_AUTHENTICATED) {
animateIconOnce(R.drawable.face_dialog_dark_to_checkmark)
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_confirmed
)
- } else if (lastStateIsErrorIcon && newState == STATE_IDLE) {
+ } else if (lastStateIsErrorIcon && newState == BiometricState.STATE_IDLE) {
animateIconOnce(R.drawable.face_dialog_error_to_idle)
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_idle
)
- } else if (lastStateIsErrorIcon && newState == STATE_AUTHENTICATED) {
+ } else if (lastStateIsErrorIcon && newState == BiometricState.STATE_AUTHENTICATED) {
animateIconOnce(R.drawable.face_dialog_dark_to_checkmark)
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_authenticated
)
- } else if (newState == STATE_ERROR && oldState != STATE_ERROR) {
+ } else if (newState == BiometricState.STATE_ERROR && oldState != BiometricState.STATE_ERROR) {
animateIconOnce(R.drawable.face_dialog_dark_to_error)
iconView.contentDescription = context.getString(
R.string.keyguard_face_failed
)
- } else if (oldState == STATE_AUTHENTICATING && newState == STATE_AUTHENTICATED) {
+ } else if (oldState == BiometricState.STATE_AUTHENTICATING && newState == BiometricState.STATE_AUTHENTICATED) {
animateIconOnce(R.drawable.face_dialog_dark_to_checkmark)
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_authenticated
)
- } else if (newState == STATE_PENDING_CONFIRMATION) {
+ } else if (newState == BiometricState.STATE_PENDING_CONFIRMATION) {
animateIconOnce(R.drawable.face_dialog_wink_from_dark)
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_authenticated
)
- } else if (newState == STATE_IDLE) {
+ } else if (newState == BiometricState.STATE_IDLE) {
showStaticDrawable(R.drawable.face_dialog_idle_static)
iconView.contentDescription = context.getString(
R.string.biometric_dialog_face_icon_description_idle
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.kt
deleted file mode 100644
index be89d10393dd..000000000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFaceView.kt
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2019 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.biometrics
-
-import android.content.Context
-import android.hardware.biometrics.BiometricAuthenticator.Modality
-import android.util.AttributeSet
-
-/** Face only view for BiometricPrompt. */
-class AuthBiometricFaceView(
- context: Context,
- attrs: AttributeSet? = null
-) : AuthBiometricView(context, attrs) {
-
- override fun getDelayAfterAuthenticatedDurationMs() = HIDE_DELAY_MS
-
- override fun getStateForAfterError() = STATE_IDLE
-
- override fun handleResetAfterError() = resetErrorView()
-
- override fun handleResetAfterHelp() = resetErrorView()
-
- override fun supportsSmallDialog() = true
-
- override fun supportsManualRetry() = true
-
- override fun supportsRequireConfirmation() = true
-
- override fun createIconController(): AuthIconController =
- AuthBiometricFaceIconController(mContext, mIconView)
-
- override fun updateState(@BiometricState newState: Int) {
- if (newState == STATE_AUTHENTICATING_ANIMATING_IN ||
- newState == STATE_AUTHENTICATING && size == AuthDialog.SIZE_MEDIUM) {
- resetErrorView()
- }
-
- // Do this last since the state variable gets updated.
- super.updateState(newState)
- }
-
- override fun onAuthenticationFailed(
- @Modality modality: Int,
- failureReason: String?
- ) {
- if (size == AuthDialog.SIZE_MEDIUM) {
- if (supportsManualRetry()) {
- mTryAgainButton.visibility = VISIBLE
- mConfirmButton.visibility = GONE
- }
- }
-
- // Do this last since we want to know if the button is being animated (in the case of
- // small -> medium dialog)
- super.onAuthenticationFailed(modality, failureReason)
- }
-
- private fun resetErrorView() {
- mIndicatorView.setTextColor(mTextColorHint)
- mIndicatorView.visibility = INVISIBLE
- }
-
- companion object {
- /** Delay before dismissing after being authenticated/confirmed. */
- const val HIDE_DELAY_MS = 500
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
index 95610aec3562..fb22c6b07db4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
@@ -20,11 +20,11 @@ import android.annotation.RawRes
import android.content.Context
import com.airbnb.lottie.LottieAnimationView
import com.android.systemui.R
-import com.android.systemui.biometrics.AuthBiometricView.BiometricState
-import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATED
-import com.android.systemui.biometrics.AuthBiometricView.STATE_ERROR
-import com.android.systemui.biometrics.AuthBiometricView.STATE_HELP
-import com.android.systemui.biometrics.AuthBiometricView.STATE_PENDING_CONFIRMATION
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_AUTHENTICATED
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_ERROR
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_HELP
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_PENDING_CONFIRMATION
/** Face/Fingerprint combined icon animator for BiometricPrompt. */
open class AuthBiometricFingerprintAndFaceIconController(
@@ -36,8 +36,8 @@ open class AuthBiometricFingerprintAndFaceIconController(
override val actsAsConfirmButton: Boolean = true
override fun shouldAnimateIconViewForTransition(
- @BiometricState oldState: Int,
- @BiometricState newState: Int
+ oldState: BiometricState,
+ newState: BiometricState
): Boolean = when (newState) {
STATE_PENDING_CONFIRMATION -> true
else -> super.shouldAnimateIconViewForTransition(oldState, newState)
@@ -45,8 +45,8 @@ open class AuthBiometricFingerprintAndFaceIconController(
@RawRes
override fun getAnimationForTransition(
- @BiometricState oldState: Int,
- @BiometricState newState: Int
+ oldState: BiometricState,
+ newState: BiometricState
): Int? = when (newState) {
STATE_AUTHENTICATED -> {
if (oldState == STATE_PENDING_CONFIRMATION) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
deleted file mode 100644
index 7ce74dbe91b4..000000000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2022 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.biometrics
-
-import android.content.Context
-import android.hardware.biometrics.BiometricAuthenticator.Modality
-import android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE
-import android.hardware.biometrics.BiometricConstants
-import android.hardware.face.FaceManager
-import android.util.AttributeSet
-import com.android.systemui.R
-
-/** Face/Fingerprint combined view for BiometricPrompt. */
-class AuthBiometricFingerprintAndFaceView(
- context: Context,
- attrs: AttributeSet?
-) : AuthBiometricFingerprintView(context, attrs) {
- var isFaceClass3 = false
-
- constructor (context: Context) : this(context, null)
-
- override fun getConfirmationPrompt() = R.string.biometric_dialog_tap_confirm_with_face
-
- override fun forceRequireConfirmation(@Modality modality: Int) = modality == TYPE_FACE
-
- override fun ignoreUnsuccessfulEventsFrom(@Modality modality: Int, unsuccessfulReason: String) =
- modality == TYPE_FACE && !(isFaceClass3 && isLockoutErrorString(unsuccessfulReason))
-
- override fun createIconController(): AuthIconController =
- AuthBiometricFingerprintAndFaceIconController(mContext, mIconView, mIconViewOverlay)
-
- override fun isCoex() = true
-
- private fun isLockoutErrorString(unsuccessfulReason: String) =
- unsuccessfulReason == FaceManager.getErrorString(
- mContext,
- BiometricConstants.BIOMETRIC_ERROR_LOCKOUT,
- 0 /*vendorCode */
- ) || unsuccessfulReason == FaceManager.getErrorString(
- mContext,
- BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT,
- 0 /*vendorCode */
- )
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index d82f458cbde2..683541bd1b5b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -27,14 +27,15 @@ import androidx.annotation.VisibleForTesting
import com.airbnb.lottie.LottieAnimationView
import com.android.settingslib.widget.LottieColorUtils
import com.android.systemui.R
-import com.android.systemui.biometrics.AuthBiometricView.BiometricState
-import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATED
-import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATING
-import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATING_ANIMATING_IN
-import com.android.systemui.biometrics.AuthBiometricView.STATE_ERROR
-import com.android.systemui.biometrics.AuthBiometricView.STATE_HELP
-import com.android.systemui.biometrics.AuthBiometricView.STATE_IDLE
-import com.android.systemui.biometrics.AuthBiometricView.STATE_PENDING_CONFIRMATION
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_AUTHENTICATED
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_AUTHENTICATING
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_AUTHENTICATING_ANIMATING_IN
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_ERROR
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_HELP
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_IDLE
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState.STATE_PENDING_CONFIRMATION
+
/** Fingerprint only icon animator for BiometricPrompt. */
open class AuthBiometricFingerprintIconController(
@@ -76,7 +77,7 @@ open class AuthBiometricFingerprintIconController(
}
}
- private fun updateIconSideFps(@BiometricState lastState: Int, @BiometricState newState: Int) {
+ private fun updateIconSideFps(lastState: BiometricState, newState: BiometricState) {
val displayInfo = DisplayInfo()
context.display?.getDisplayInfo(displayInfo)
val rotation = getRotationFromDefault(displayInfo.rotation)
@@ -106,7 +107,7 @@ open class AuthBiometricFingerprintIconController(
LottieColorUtils.applyDynamicColors(context, iconViewOverlay)
}
- private fun updateIconNormal(@BiometricState lastState: Int, @BiometricState newState: Int) {
+ private fun updateIconNormal(lastState: BiometricState, newState: BiometricState) {
val icon = getAnimationForTransition(lastState, newState) ?: return
if (!(lastState == STATE_AUTHENTICATING_ANIMATING_IN && newState == STATE_AUTHENTICATING)) {
@@ -125,7 +126,7 @@ open class AuthBiometricFingerprintIconController(
LottieColorUtils.applyDynamicColors(context, iconView)
}
- override fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int) {
+ override fun updateIcon(lastState: BiometricState, newState: BiometricState) {
if (isSideFps) {
updateIconSideFps(lastState, newState)
} else {
@@ -135,7 +136,7 @@ open class AuthBiometricFingerprintIconController(
}
@VisibleForTesting
- fun getIconContentDescription(@BiometricState newState: Int): CharSequence? {
+ fun getIconContentDescription(newState: BiometricState): CharSequence? {
val id = when (newState) {
STATE_IDLE,
STATE_AUTHENTICATING_ANIMATING_IN,
@@ -160,8 +161,8 @@ open class AuthBiometricFingerprintIconController(
}
protected open fun shouldAnimateIconViewForTransition(
- @BiometricState oldState: Int,
- @BiometricState newState: Int
+ oldState: BiometricState,
+ newState: BiometricState
) = when (newState) {
STATE_HELP,
STATE_ERROR -> true
@@ -172,8 +173,8 @@ open class AuthBiometricFingerprintIconController(
}
private fun shouldAnimateSfpsIconViewForTransition(
- @BiometricState oldState: Int,
- @BiometricState newState: Int
+ oldState: BiometricState,
+ newState: BiometricState
) = when (newState) {
STATE_HELP,
STATE_ERROR -> true
@@ -185,8 +186,8 @@ open class AuthBiometricFingerprintIconController(
}
protected open fun shouldAnimateIconViewOverlayForTransition(
- @BiometricState oldState: Int,
- @BiometricState newState: Int
+ oldState: BiometricState,
+ newState: BiometricState
) = when (newState) {
STATE_HELP,
STATE_ERROR -> true
@@ -198,8 +199,8 @@ open class AuthBiometricFingerprintIconController(
@RawRes
protected open fun getAnimationForTransition(
- @BiometricState oldState: Int,
- @BiometricState newState: Int
+ oldState: BiometricState,
+ newState: BiometricState
): Int? {
val id = when (newState) {
STATE_HELP,
@@ -231,8 +232,8 @@ open class AuthBiometricFingerprintIconController(
@RawRes
private fun getSideFpsOverlayAnimationForTransition(
- @BiometricState oldState: Int,
- @BiometricState newState: Int,
+ oldState: BiometricState,
+ newState: BiometricState,
rotation: Int
): Int? = when (newState) {
STATE_HELP,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
deleted file mode 100644
index f2e47018bf4e..000000000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2019 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.biometrics
-
-import android.content.Context
-import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
-import android.util.AttributeSet
-import android.util.Log
-import android.widget.FrameLayout
-import android.widget.TextView
-import com.android.systemui.R
-import com.android.systemui.biometrics.AuthController.ScaleFactorProvider
-
-private const val TAG = "AuthBiometricFingerprintView"
-
-/** Fingerprint only view for BiometricPrompt. */
-open class AuthBiometricFingerprintView(
- context: Context,
- attrs: AttributeSet? = null
-) : AuthBiometricView(context, attrs) {
- /** If this view is for a SFPS sensor. */
- var isSfps = false
- private set
-
- /** If this view is for a UDFPS sensor. */
- var isUdfps = false
- private set
-
- private var udfpsAdapter: UdfpsDialogMeasureAdapter? = null
- private var scaleFactorProvider: ScaleFactorProvider? = null
-
- /** Set the [sensorProps] of this sensor so the view can be customized prior to layout. */
- fun setSensorProperties(sensorProps: FingerprintSensorPropertiesInternal) {
- isSfps = sensorProps.isAnySidefpsType
- isUdfps = sensorProps.isAnyUdfpsType
- udfpsAdapter = if (isUdfps) UdfpsDialogMeasureAdapter(this, sensorProps) else null
- }
-
- fun setScaleFactorProvider(scaleProvider: ScaleFactorProvider?) {
- scaleFactorProvider = scaleProvider
- }
-
- override fun onMeasureInternal(width: Int, height: Int): AuthDialog.LayoutParams {
- val layoutParams = super.onMeasureInternal(width, height)
- val scale = scaleFactorProvider?.provide() ?: 1.0f
- return udfpsAdapter?.onMeasureInternal(width, height, layoutParams,
- scale) ?: layoutParams
- }
-
- override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
- super.onLayout(changed, left, top, right, bottom)
-
- val adapter = udfpsAdapter
- if (adapter != null) {
- // Move the UDFPS icon and indicator text if necessary. This probably only needs to happen
- // for devices where the UDFPS sensor is too low.
- // TODO(b/201510778): Update this logic to support cases where the sensor or text overlap
- // the button bar area.
- val bottomSpacerHeight = adapter.bottomSpacerHeight
- Log.w(TAG, "bottomSpacerHeight: $bottomSpacerHeight")
- if (bottomSpacerHeight < 0) {
- val iconFrame = findViewById<FrameLayout>(R.id.biometric_icon_frame)!!
- iconFrame.translationY = -bottomSpacerHeight.toFloat()
- val indicator = findViewById<TextView>(R.id.indicator)!!
- indicator.translationY = -bottomSpacerHeight.toFloat()
- }
- }
- }
-
- override fun getDelayAfterAuthenticatedDurationMs() = 500
-
- override fun getStateForAfterError() = STATE_AUTHENTICATING
-
- override fun handleResetAfterError() = showTouchSensorString()
-
- override fun handleResetAfterHelp() = showTouchSensorString()
-
- override fun supportsSmallDialog() = false
-
- override fun createIconController(): AuthIconController =
- AuthBiometricFingerprintIconController(mContext, mIconView, mIconViewOverlay)
-
- fun updateOverrideIconLayoutParamsSize() {
- udfpsAdapter?.let {
- val sensorDiameter = it.getSensorDiameter(scaleFactorProvider?.provide() ?: 1.0f)
- (mIconController as? AuthBiometricFingerprintIconController)?.iconLayoutParamSize =
- Pair(sensorDiameter, sensorDiameter)
- }
- }
-
- override fun onAttachedToWindow() {
- super.onAttachedToWindow()
- showTouchSensorString()
- }
-
- private fun showTouchSensorString() {
- mIndicatorView.setText(R.string.fingerprint_dialog_touch_sensor)
- mIndicatorView.setTextColor(mTextColorHint)
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
deleted file mode 100644
index ed4b91c7c4e4..000000000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ /dev/null
@@ -1,984 +0,0 @@
-/*
- * Copyright (C) 2019 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.biometrics;
-
-import static android.hardware.biometrics.BiometricAuthenticator.TYPE_NONE;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ValueAnimator;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.StringRes;
-import android.content.Context;
-import android.content.res.Configuration;
-import android.graphics.Insets;
-import android.hardware.biometrics.BiometricAuthenticator.Modality;
-import android.hardware.biometrics.BiometricPrompt;
-import android.hardware.biometrics.PromptInfo;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.text.TextUtils;
-import android.text.method.ScrollingMovementMethod;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.accessibility.AccessibilityManager;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.widget.LockPatternUtils;
-import com.android.systemui.R;
-
-import com.airbnb.lottie.LottieAnimationView;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Contains the Biometric views (title, subtitle, icon, buttons, etc.) and its controllers.
- */
-public abstract class AuthBiometricView extends LinearLayout implements AuthBiometricViewAdapter {
-
- private static final String TAG = "AuthBiometricView";
-
- /**
- * Authentication hardware idle.
- */
- public static final int STATE_IDLE = 0;
- /**
- * UI animating in, authentication hardware active.
- */
- public static final int STATE_AUTHENTICATING_ANIMATING_IN = 1;
- /**
- * UI animated in, authentication hardware active.
- */
- public static final int STATE_AUTHENTICATING = 2;
- /**
- * UI animated in, authentication hardware active.
- */
- public static final int STATE_HELP = 3;
- /**
- * Hard error, e.g. ERROR_TIMEOUT. Authentication hardware idle.
- */
- public static final int STATE_ERROR = 4;
- /**
- * Authenticated, waiting for user confirmation. Authentication hardware idle.
- */
- public static final int STATE_PENDING_CONFIRMATION = 5;
- /**
- * Authenticated, dialog animating away soon.
- */
- public static final int STATE_AUTHENTICATED = 6;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({STATE_IDLE, STATE_AUTHENTICATING_ANIMATING_IN, STATE_AUTHENTICATING, STATE_HELP,
- STATE_ERROR, STATE_PENDING_CONFIRMATION, STATE_AUTHENTICATED})
- @interface BiometricState {}
-
- /**
- * Callback to the parent when a user action has occurred.
- */
- public interface Callback {
- int ACTION_AUTHENTICATED = 1;
- int ACTION_USER_CANCELED = 2;
- int ACTION_BUTTON_NEGATIVE = 3;
- int ACTION_BUTTON_TRY_AGAIN = 4;
- int ACTION_ERROR = 5;
- int ACTION_USE_DEVICE_CREDENTIAL = 6;
- int ACTION_START_DELAYED_FINGERPRINT_SENSOR = 7;
- int ACTION_AUTHENTICATED_AND_CONFIRMED = 8;
-
- /**
- * When an action has occurred. The caller will only invoke this when the callback should
- * be propagated. e.g. the caller will handle any necessary delay.
- * @param action
- */
- void onAction(int action);
- }
-
- private final Handler mHandler;
- private final AccessibilityManager mAccessibilityManager;
- private final LockPatternUtils mLockPatternUtils;
- protected final int mTextColorError;
- protected final int mTextColorHint;
-
- private AuthPanelController mPanelController;
-
- private PromptInfo mPromptInfo;
- private boolean mRequireConfirmation;
- private int mUserId;
- private int mEffectiveUserId;
- private @AuthDialog.DialogSize int mSize = AuthDialog.SIZE_UNKNOWN;
-
- private TextView mTitleView;
- private TextView mSubtitleView;
- private TextView mDescriptionView;
- private View mIconHolderView;
- protected LottieAnimationView mIconViewOverlay;
- protected LottieAnimationView mIconView;
- protected TextView mIndicatorView;
-
- @VisibleForTesting @NonNull AuthIconController mIconController;
- @VisibleForTesting int mAnimationDurationShort = AuthDialog.ANIMATE_SMALL_TO_MEDIUM_DURATION_MS;
- @VisibleForTesting int mAnimationDurationLong = AuthDialog.ANIMATE_MEDIUM_TO_LARGE_DURATION_MS;
- @VisibleForTesting int mAnimationDurationHideDialog = BiometricPrompt.HIDE_DIALOG_DELAY;
-
- // Negative button position, exclusively for the app-specified behavior
- @VisibleForTesting Button mNegativeButton;
- // Negative button position, exclusively for cancelling auth after passive auth success
- @VisibleForTesting Button mCancelButton;
- // Negative button position, shown if device credentials are allowed
- @VisibleForTesting Button mUseCredentialButton;
-
- // Positive button position,
- @VisibleForTesting Button mConfirmButton;
- @VisibleForTesting Button mTryAgainButton;
-
- // Measurements when biometric view is showing text, buttons, etc.
- @Nullable @VisibleForTesting AuthDialog.LayoutParams mLayoutParams;
-
- private Callback mCallback;
- @BiometricState private int mState;
-
- private float mIconOriginalY;
-
- protected boolean mDialogSizeAnimating;
- protected Bundle mSavedState;
-
- private final Runnable mResetErrorRunnable;
- private final Runnable mResetHelpRunnable;
-
- private Animator.AnimatorListener mJankListener;
-
- private final boolean mUseCustomBpSize;
- private final int mCustomBpWidth;
- private final int mCustomBpHeight;
-
- private final OnClickListener mBackgroundClickListener = (view) -> {
- if (mState == STATE_AUTHENTICATED) {
- Log.w(TAG, "Ignoring background click after authenticated");
- return;
- } else if (mSize == AuthDialog.SIZE_SMALL) {
- Log.w(TAG, "Ignoring background click during small dialog");
- return;
- } else if (mSize == AuthDialog.SIZE_LARGE) {
- Log.w(TAG, "Ignoring background click during large dialog");
- return;
- }
- mCallback.onAction(Callback.ACTION_USER_CANCELED);
- };
-
- public AuthBiometricView(Context context) {
- this(context, null);
- }
-
- public AuthBiometricView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mHandler = new Handler(Looper.getMainLooper());
- mTextColorError = getResources().getColor(
- R.color.biometric_dialog_error, context.getTheme());
- mTextColorHint = getResources().getColor(
- R.color.biometric_dialog_gray, context.getTheme());
-
- mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
- mLockPatternUtils = new LockPatternUtils(context);
-
- mResetErrorRunnable = () -> {
- updateState(getStateForAfterError());
- handleResetAfterError();
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
- };
-
- mResetHelpRunnable = () -> {
- updateState(STATE_AUTHENTICATING);
- handleResetAfterHelp();
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
- };
-
- mUseCustomBpSize = getResources().getBoolean(R.bool.use_custom_bp_size);
- mCustomBpWidth = getResources().getDimensionPixelSize(R.dimen.biometric_dialog_width);
- mCustomBpHeight = getResources().getDimensionPixelSize(R.dimen.biometric_dialog_height);
- }
-
- /** Delay after authentication is confirmed, before the dialog should be animated away. */
- protected int getDelayAfterAuthenticatedDurationMs() {
- return 0;
- }
-
- /** State that the dialog/icon should be in after showing a help message. */
- protected int getStateForAfterError() {
- return STATE_IDLE;
- }
-
- /** Invoked when the error message is being cleared. */
- protected void handleResetAfterError() {}
-
- /** Invoked when the help message is being cleared. */
- protected void handleResetAfterHelp() {}
-
- /** True if the dialog supports {@link AuthDialog.DialogSize#SIZE_SMALL}. */
- protected boolean supportsSmallDialog() {
- return false;
- }
-
- /** The string to show when the user must tap to confirm via the button or icon. */
- @StringRes
- protected int getConfirmationPrompt() {
- return R.string.biometric_dialog_tap_confirm;
- }
-
- /** True if require confirmation will be honored when set via the API. */
- protected boolean supportsRequireConfirmation() {
- return false;
- }
-
- /** True if confirmation will be required even if it was not supported/requested. */
- protected boolean forceRequireConfirmation(@Modality int modality) {
- return false;
- }
-
- /** Ignore all events from this (secondary) modality except successful authentication. */
- protected boolean ignoreUnsuccessfulEventsFrom(@Modality int modality,
- String unsuccessfulReason) {
- return false;
- }
-
- /** Create the controller for managing the icons transitions during the prompt.*/
- @NonNull
- protected abstract AuthIconController createIconController();
-
- @Override
- public AuthIconController getLegacyIconController() {
- return mIconController;
- }
-
- @Override
- public void cancelAnimation() {
- animate().cancel();
- }
-
- @Override
- public View asView() {
- return this;
- }
-
- @Override
- public boolean isCoex() {
- return false;
- }
-
- void setPanelController(AuthPanelController panelController) {
- mPanelController = panelController;
- }
- void setPromptInfo(PromptInfo promptInfo) {
- mPromptInfo = promptInfo;
- }
-
- void setCallback(Callback callback) {
- mCallback = callback;
- }
-
- void setBackgroundView(View backgroundView) {
- backgroundView.setOnClickListener(mBackgroundClickListener);
- }
-
- void setUserId(int userId) {
- mUserId = userId;
- }
-
- void setEffectiveUserId(int effectiveUserId) {
- mEffectiveUserId = effectiveUserId;
- }
-
- void setRequireConfirmation(boolean requireConfirmation) {
- mRequireConfirmation = requireConfirmation && supportsRequireConfirmation();
- }
-
- void setJankListener(Animator.AnimatorListener jankListener) {
- mJankListener = jankListener;
- }
-
- private void updatePaddings(int size) {
- final Insets navBarInsets = Utils.getNavbarInsets(mContext);
- if (size != AuthDialog.SIZE_LARGE) {
- if (mPanelController.getPosition() == AuthPanelController.POSITION_LEFT) {
- setPadding(navBarInsets.left, 0, 0, 0);
- } else if (mPanelController.getPosition() == AuthPanelController.POSITION_RIGHT) {
- setPadding(0, 0, navBarInsets.right, 0);
- } else {
- setPadding(0, 0, 0, navBarInsets.bottom);
- }
- } else {
- setPadding(0, 0, 0, 0);
- }
- }
-
- @VisibleForTesting
- final void updateSize(@AuthDialog.DialogSize int newSize) {
- Log.v(TAG, "Current size: " + mSize + " New size: " + newSize);
- updatePaddings(newSize);
- if (newSize == AuthDialog.SIZE_SMALL) {
- mTitleView.setVisibility(View.GONE);
- mSubtitleView.setVisibility(View.GONE);
- mDescriptionView.setVisibility(View.GONE);
- mIndicatorView.setVisibility(View.GONE);
- mNegativeButton.setVisibility(View.GONE);
- mUseCredentialButton.setVisibility(View.GONE);
-
- final float iconPadding = getResources()
- .getDimension(R.dimen.biometric_dialog_icon_padding);
- mIconHolderView.setY(getHeight() - mIconHolderView.getHeight() - iconPadding);
-
- // Subtract the vertical padding from the new height since it's only used to create
- // extra space between the other elements, and not part of the actual icon.
- final int newHeight = mIconHolderView.getHeight() + 2 * (int) iconPadding
- - mIconHolderView.getPaddingTop() - mIconHolderView.getPaddingBottom();
- mPanelController.updateForContentDimensions(mLayoutParams.mMediumWidth, newHeight,
- 0 /* animateDurationMs */);
-
- mSize = newSize;
- } else if (mSize == AuthDialog.SIZE_SMALL && newSize == AuthDialog.SIZE_MEDIUM) {
- if (mDialogSizeAnimating) {
- return;
- }
- mDialogSizeAnimating = true;
-
- // Animate the icon back to original position
- final ValueAnimator iconAnimator =
- ValueAnimator.ofFloat(mIconHolderView.getY(), mIconOriginalY);
- iconAnimator.addUpdateListener((animation) -> {
- mIconHolderView.setY((float) animation.getAnimatedValue());
- });
-
- // Animate the text
- final ValueAnimator opacityAnimator = ValueAnimator.ofFloat(0, 1);
- opacityAnimator.addUpdateListener((animation) -> {
- final float opacity = (float) animation.getAnimatedValue();
- mTitleView.setAlpha(opacity);
- mIndicatorView.setAlpha(opacity);
- mNegativeButton.setAlpha(opacity);
- mCancelButton.setAlpha(opacity);
- mTryAgainButton.setAlpha(opacity);
-
- if (!TextUtils.isEmpty(mSubtitleView.getText())) {
- mSubtitleView.setAlpha(opacity);
- }
- if (!TextUtils.isEmpty(mDescriptionView.getText())) {
- mDescriptionView.setAlpha(opacity);
- }
- });
-
- // Choreograph together
- final AnimatorSet as = new AnimatorSet();
- as.setDuration(mAnimationDurationShort);
- as.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- super.onAnimationStart(animation);
- mTitleView.setVisibility(View.VISIBLE);
- mIndicatorView.setVisibility(View.VISIBLE);
-
- if (isDeviceCredentialAllowed()) {
- mUseCredentialButton.setVisibility(View.VISIBLE);
- } else {
- mNegativeButton.setVisibility(View.VISIBLE);
- }
- if (supportsManualRetry()) {
- mTryAgainButton.setVisibility(View.VISIBLE);
- }
-
- if (!TextUtils.isEmpty(mSubtitleView.getText())) {
- mSubtitleView.setVisibility(View.VISIBLE);
- }
- if (!TextUtils.isEmpty(mDescriptionView.getText())) {
- mDescriptionView.setVisibility(View.VISIBLE);
- }
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- mSize = newSize;
- mDialogSizeAnimating = false;
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager,
- AuthBiometricView.this);
- }
- });
-
- if (mJankListener != null) {
- as.addListener(mJankListener);
- }
- as.play(iconAnimator).with(opacityAnimator);
- as.start();
- // Animate the panel
- mPanelController.updateForContentDimensions(mLayoutParams.mMediumWidth,
- mLayoutParams.mMediumHeight,
- AuthDialog.ANIMATE_SMALL_TO_MEDIUM_DURATION_MS);
- } else if (newSize == AuthDialog.SIZE_MEDIUM) {
- mPanelController.updateForContentDimensions(mLayoutParams.mMediumWidth,
- mLayoutParams.mMediumHeight,
- 0 /* animateDurationMs */);
- mSize = newSize;
- } else if (newSize == AuthDialog.SIZE_LARGE) {
- final float translationY = getResources().getDimension(
- R.dimen.biometric_dialog_medium_to_large_translation_offset);
- final AuthBiometricView biometricView = this;
-
- // Translate at full duration
- final ValueAnimator translationAnimator = ValueAnimator.ofFloat(
- biometricView.getY(), biometricView.getY() - translationY);
- translationAnimator.setDuration(mAnimationDurationLong);
- translationAnimator.addUpdateListener((animation) -> {
- final float translation = (float) animation.getAnimatedValue();
- biometricView.setTranslationY(translation);
- });
- translationAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- if (biometricView.getParent() instanceof ViewGroup) {
- ((ViewGroup) biometricView.getParent()).removeView(biometricView);
- }
- mSize = newSize;
- }
- });
-
- // Opacity to 0 in half duration
- final ValueAnimator opacityAnimator = ValueAnimator.ofFloat(1, 0);
- opacityAnimator.setDuration(mAnimationDurationLong / 2);
- opacityAnimator.addUpdateListener((animation) -> {
- final float opacity = (float) animation.getAnimatedValue();
- biometricView.setAlpha(opacity);
- });
-
- mPanelController.setUseFullScreen(true);
- mPanelController.updateForContentDimensions(
- mPanelController.getContainerWidth(),
- mPanelController.getContainerHeight(),
- mAnimationDurationLong);
-
- // Start the animations together
- AnimatorSet as = new AnimatorSet();
- List<Animator> animators = new ArrayList<>();
- animators.add(translationAnimator);
- animators.add(opacityAnimator);
-
- if (mJankListener != null) {
- as.addListener(mJankListener);
- }
- as.playTogether(animators);
- as.setDuration(mAnimationDurationLong * 2 / 3);
- as.start();
- } else {
- Log.e(TAG, "Unknown transition from: " + mSize + " to: " + newSize);
- }
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
- }
-
- protected boolean supportsManualRetry() {
- return false;
- }
-
- /**
- * Updates mIconView animation on updates to fold state, device rotation, or rear display mode
- * @param animation new asset to use for iconw
- */
- public void updateIconViewAnimation(int animation) {
- mIconView.setAnimation(animation);
- }
-
- public void updateState(@BiometricState int newState) {
- Log.d(TAG, "newState: " + newState);
-
- mIconController.updateState(mState, newState);
-
- switch (newState) {
- case STATE_AUTHENTICATING_ANIMATING_IN:
- case STATE_AUTHENTICATING:
- removePendingAnimations();
- if (mRequireConfirmation) {
- mConfirmButton.setEnabled(false);
- mConfirmButton.setVisibility(View.VISIBLE);
- }
- break;
-
- case STATE_AUTHENTICATED:
- removePendingAnimations();
- if (mSize != AuthDialog.SIZE_SMALL) {
- mConfirmButton.setVisibility(View.GONE);
- mNegativeButton.setVisibility(View.GONE);
- mUseCredentialButton.setVisibility(View.GONE);
- mCancelButton.setVisibility(View.GONE);
- mIndicatorView.setVisibility(View.INVISIBLE);
- }
- announceForAccessibility(getResources()
- .getString(R.string.biometric_dialog_authenticated));
- if (mState == STATE_PENDING_CONFIRMATION) {
- mHandler.postDelayed(() -> mCallback.onAction(
- Callback.ACTION_AUTHENTICATED_AND_CONFIRMED),
- getDelayAfterAuthenticatedDurationMs());
- } else {
- mHandler.postDelayed(() -> mCallback.onAction(Callback.ACTION_AUTHENTICATED),
- getDelayAfterAuthenticatedDurationMs());
- }
- break;
-
- case STATE_PENDING_CONFIRMATION:
- removePendingAnimations();
- mNegativeButton.setVisibility(View.GONE);
- mCancelButton.setVisibility(View.VISIBLE);
- mUseCredentialButton.setVisibility(View.GONE);
- // forced confirmations (multi-sensor) use the icon view as the confirm button
- mConfirmButton.setEnabled(mRequireConfirmation);
- mConfirmButton.setVisibility(mRequireConfirmation ? View.VISIBLE : View.GONE);
- mIndicatorView.setTextColor(mTextColorHint);
- mIndicatorView.setText(getConfirmationPrompt());
- mIndicatorView.setVisibility(View.VISIBLE);
- break;
-
- case STATE_ERROR:
- if (mSize == AuthDialog.SIZE_SMALL) {
- updateSize(AuthDialog.SIZE_MEDIUM);
- }
- break;
-
- default:
- Log.w(TAG, "Unhandled state: " + newState);
- break;
- }
-
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
- mState = newState;
- }
-
- public void onOrientationChanged() {
- // Update padding and AuthPanel outline by calling updateSize when the orientation changed.
- updateSize(mSize);
- }
-
- public void onDialogAnimatedIn(boolean fingerprintWasStarted) {
- updateState(STATE_AUTHENTICATING);
- }
-
- public void onAuthenticationSucceeded(@Modality int modality) {
- removePendingAnimations();
- if (mRequireConfirmation || forceRequireConfirmation(modality)) {
- updateState(STATE_PENDING_CONFIRMATION);
- } else {
- updateState(STATE_AUTHENTICATED);
- }
- }
-
- /**
- * Notify the view that auth has failed.
- *
- * @param modality sensor modality that failed
- * @param failureReason message
- */
- public void onAuthenticationFailed(
- @Modality int modality, @Nullable String failureReason) {
- if (ignoreUnsuccessfulEventsFrom(modality, failureReason)) {
- return;
- }
-
- showTemporaryMessage(failureReason, mResetErrorRunnable);
- updateState(STATE_ERROR);
- }
-
- /**
- * Notify the view that an error occurred.
- *
- * @param modality sensor modality that failed
- * @param error message
- */
- public void onError(@Modality int modality, String error) {
- if (ignoreUnsuccessfulEventsFrom(modality, error)) {
- return;
- }
-
- showTemporaryMessage(error, mResetErrorRunnable);
- updateState(STATE_ERROR);
-
- mHandler.postDelayed(() -> mCallback.onAction(Callback.ACTION_ERROR),
- mAnimationDurationHideDialog);
- }
-
- /**
- * Show a help message to the user.
- *
- * @param modality sensor modality
- * @param help message
- */
- public void onHelp(@Modality int modality, String help) {
- if (ignoreUnsuccessfulEventsFrom(modality, help)) {
- return;
- }
- if (mSize != AuthDialog.SIZE_MEDIUM) {
- Log.w(TAG, "Help received in size: " + mSize);
- return;
- }
- if (TextUtils.isEmpty(help)) {
- Log.w(TAG, "Ignoring blank help message");
- return;
- }
-
- showTemporaryMessage(help, mResetHelpRunnable);
- updateState(STATE_HELP);
- }
-
- public void onSaveState(@NonNull Bundle outState) {
- outState.putInt(AuthDialog.KEY_BIOMETRIC_CONFIRM_VISIBILITY,
- mConfirmButton.getVisibility());
- outState.putInt(AuthDialog.KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY,
- mTryAgainButton.getVisibility());
- outState.putInt(AuthDialog.KEY_BIOMETRIC_STATE, mState);
- outState.putString(AuthDialog.KEY_BIOMETRIC_INDICATOR_STRING,
- mIndicatorView.getText() != null ? mIndicatorView.getText().toString() : "");
- outState.putBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING,
- mHandler.hasCallbacks(mResetErrorRunnable));
- outState.putBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_HELP_SHOWING,
- mHandler.hasCallbacks(mResetHelpRunnable));
- outState.putInt(AuthDialog.KEY_BIOMETRIC_DIALOG_SIZE, mSize);
- }
-
- /**
- * Invoked after inflation but before being attached to window.
- * @param savedState
- */
- public void restoreState(@Nullable Bundle savedState) {
- mSavedState = savedState;
- }
- private void setTextOrHide(TextView view, CharSequence charSequence) {
- if (TextUtils.isEmpty(charSequence)) {
- view.setVisibility(View.GONE);
- } else {
- view.setText(charSequence);
- }
-
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
- }
-
- // Remove all pending icon and text animations
- private void removePendingAnimations() {
- mHandler.removeCallbacks(mResetHelpRunnable);
- mHandler.removeCallbacks(mResetErrorRunnable);
- }
-
- private void showTemporaryMessage(String message, Runnable resetMessageRunnable) {
- removePendingAnimations();
- mIndicatorView.setText(message);
- mIndicatorView.setTextColor(mTextColorError);
- mIndicatorView.setVisibility(View.VISIBLE);
- // select to enable marquee unless a screen reader is enabled
- mIndicatorView.setSelected(!mAccessibilityManager.isEnabled()
- || !mAccessibilityManager.isTouchExplorationEnabled());
- mHandler.postDelayed(resetMessageRunnable, mAnimationDurationHideDialog);
-
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
- }
-
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- if (mSavedState != null) {
- updateState(mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_STATE));
- }
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- mTitleView = findViewById(R.id.title);
- mSubtitleView = findViewById(R.id.subtitle);
- mDescriptionView = findViewById(R.id.description);
- mIconViewOverlay = findViewById(R.id.biometric_icon_overlay);
- mIconView = findViewById(R.id.biometric_icon);
- mIconHolderView = findViewById(R.id.biometric_icon_frame);
- mIndicatorView = findViewById(R.id.indicator);
-
- // Negative-side (left) buttons
- mNegativeButton = findViewById(R.id.button_negative);
- mCancelButton = findViewById(R.id.button_cancel);
- mUseCredentialButton = findViewById(R.id.button_use_credential);
-
- // Positive-side (right) buttons
- mConfirmButton = findViewById(R.id.button_confirm);
- mTryAgainButton = findViewById(R.id.button_try_again);
-
- mNegativeButton.setOnClickListener((view) -> {
- mCallback.onAction(Callback.ACTION_BUTTON_NEGATIVE);
- });
-
- mCancelButton.setOnClickListener((view) -> {
- mCallback.onAction(Callback.ACTION_USER_CANCELED);
- });
-
- mUseCredentialButton.setOnClickListener((view) -> {
- startTransitionToCredentialUI(false /* isError */);
- });
-
- mConfirmButton.setOnClickListener((view) -> {
- updateState(STATE_AUTHENTICATED);
- });
-
- mTryAgainButton.setOnClickListener((view) -> {
- updateState(STATE_AUTHENTICATING);
- mCallback.onAction(Callback.ACTION_BUTTON_TRY_AGAIN);
- mTryAgainButton.setVisibility(View.GONE);
- Utils.notifyAccessibilityContentChanged(mAccessibilityManager, this);
- });
-
- mIconController = createIconController();
- if (mIconController.getActsAsConfirmButton()) {
- mIconViewOverlay.setOnClickListener((view)->{
- if (mState == STATE_PENDING_CONFIRMATION) {
- updateState(STATE_AUTHENTICATED);
- }
- });
- mIconView.setOnClickListener((view) -> {
- if (mState == STATE_PENDING_CONFIRMATION) {
- updateState(STATE_AUTHENTICATED);
- }
- });
- }
- }
-
- /**
- * Kicks off the animation process and invokes the callback.
- *
- * @param isError if this was triggered due to an error and not a user action (unused,
- * previously for haptics).
- */
- @Override
- public void startTransitionToCredentialUI(boolean isError) {
- updateSize(AuthDialog.SIZE_LARGE);
- mCallback.onAction(Callback.ACTION_USE_DEVICE_CREDENTIAL);
- }
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
-
- mTitleView.setText(mPromptInfo.getTitle());
-
- // setSelected could make marquee work
- mTitleView.setSelected(true);
- mSubtitleView.setSelected(true);
- // make description view become scrollable
- mDescriptionView.setMovementMethod(new ScrollingMovementMethod());
-
- if (isDeviceCredentialAllowed()) {
- final CharSequence credentialButtonText;
- @Utils.CredentialType final int credentialType =
- Utils.getCredentialType(mLockPatternUtils, mEffectiveUserId);
- switch (credentialType) {
- case Utils.CREDENTIAL_PIN:
- credentialButtonText =
- getResources().getString(R.string.biometric_dialog_use_pin);
- break;
- case Utils.CREDENTIAL_PATTERN:
- credentialButtonText =
- getResources().getString(R.string.biometric_dialog_use_pattern);
- break;
- case Utils.CREDENTIAL_PASSWORD:
- default:
- credentialButtonText =
- getResources().getString(R.string.biometric_dialog_use_password);
- break;
- }
-
- mNegativeButton.setVisibility(View.GONE);
-
- mUseCredentialButton.setText(credentialButtonText);
- mUseCredentialButton.setVisibility(View.VISIBLE);
- } else {
- mNegativeButton.setText(mPromptInfo.getNegativeButtonText());
- }
-
- setTextOrHide(mSubtitleView, mPromptInfo.getSubtitle());
- setTextOrHide(mDescriptionView, mPromptInfo.getDescription());
-
- if (mSavedState == null) {
- updateState(STATE_AUTHENTICATING_ANIMATING_IN);
- } else {
- // Restore as much state as possible first
- updateState(mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_STATE));
-
- // Restore positive button(s) state
- mConfirmButton.setVisibility(
- mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_CONFIRM_VISIBILITY));
- if (mConfirmButton.getVisibility() == View.GONE) {
- setRequireConfirmation(false);
- }
- mTryAgainButton.setVisibility(
- mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY));
-
- }
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
-
- mIconController.setDeactivated(true);
-
- // Empty the handler, otherwise things like ACTION_AUTHENTICATED may be duplicated once
- // the new dialog is restored.
- mHandler.removeCallbacksAndMessages(null /* all */);
- }
-
- /**
- * Contains all of the testable logic that should be invoked when {@link #onMeasure(int, int)}
- * is invoked. In addition, this allows subclasses to implement custom measuring logic while
- * allowing the base class to have common code to apply the custom measurements.
- *
- * @param width Width to constrain the measurements to.
- * @param height Height to constrain the measurements to.
- * @return See {@link AuthDialog.LayoutParams}
- */
- @NonNull
- AuthDialog.LayoutParams onMeasureInternal(int width, int height) {
- int totalHeight = 0;
- final int numChildren = getChildCount();
- for (int i = 0; i < numChildren; i++) {
- final View child = getChildAt(i);
-
- if (child.getId() == R.id.space_above_icon
- || child.getId() == R.id.space_below_icon
- || child.getId() == R.id.button_bar) {
- child.measure(
- MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(child.getLayoutParams().height,
- MeasureSpec.EXACTLY));
- } else if (child.getId() == R.id.biometric_icon_frame) {
- final View iconView = findViewById(R.id.biometric_icon);
- child.measure(
- MeasureSpec.makeMeasureSpec(iconView.getLayoutParams().width,
- MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(iconView.getLayoutParams().height,
- MeasureSpec.EXACTLY));
- } else if (child.getId() == R.id.biometric_icon) {
- child.measure(
- MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
- } else {
- child.measure(
- MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));
- }
-
- if (child.getVisibility() != View.GONE) {
- totalHeight += child.getMeasuredHeight();
- }
- }
-
- return new AuthDialog.LayoutParams(width, totalHeight);
- }
-
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int width = MeasureSpec.getSize(widthMeasureSpec);
- int height = MeasureSpec.getSize(heightMeasureSpec);
-
- if (mUseCustomBpSize) {
- width = mCustomBpWidth;
- height = mCustomBpHeight;
- } else {
- width = Math.min(width, height);
- }
-
- mLayoutParams = onMeasureInternal(width, height);
-
- final Insets navBarInsets = Utils.getNavbarInsets(mContext);
- final int navBarHeight = navBarInsets.bottom;
- final int navBarWidth;
- if (mPanelController.getPosition() == AuthPanelController.POSITION_LEFT) {
- navBarWidth = navBarInsets.left;
- } else if (mPanelController.getPosition() == AuthPanelController.POSITION_RIGHT) {
- navBarWidth = navBarInsets.right;
- } else {
- navBarWidth = 0;
- }
-
- // The actual auth dialog w/h should include navigation bar size.
- if (navBarWidth != 0 || navBarHeight != 0) {
- mLayoutParams = new AuthDialog.LayoutParams(
- mLayoutParams.mMediumWidth + navBarWidth,
- mLayoutParams.mMediumHeight + navBarInsets.bottom);
- }
-
- setMeasuredDimension(mLayoutParams.mMediumWidth, mLayoutParams.mMediumHeight);
- }
-
- @Override
- public void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- // Start with initial size only once. Subsequent layout changes don't matter since we
- // only care about the initial icon position.
- if (mIconOriginalY == 0) {
- mIconOriginalY = mIconHolderView.getY();
- if (mSavedState == null) {
- updateSize(!mRequireConfirmation && supportsSmallDialog() ? AuthDialog.SIZE_SMALL
- : AuthDialog.SIZE_MEDIUM);
- } else {
- updateSize(mSavedState.getInt(AuthDialog.KEY_BIOMETRIC_DIALOG_SIZE));
-
- // Restore indicator text state only after size has been restored
- final String indicatorText =
- mSavedState.getString(AuthDialog.KEY_BIOMETRIC_INDICATOR_STRING);
- if (mSavedState.getBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_HELP_SHOWING)) {
- onHelp(TYPE_NONE, indicatorText);
- } else if (mSavedState.getBoolean(
- AuthDialog.KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING)) {
- onAuthenticationFailed(TYPE_NONE, indicatorText);
- }
- }
- }
- }
-
- private boolean isDeviceCredentialAllowed() {
- return Utils.isDeviceCredentialAllowed(mPromptInfo);
- }
-
- public LottieAnimationView getIconView() {
- return mIconView;
- }
-
- @AuthDialog.DialogSize int getSize() {
- return mSize;
- }
-
- /** If authentication has successfully occurred and the view is done. */
- boolean isAuthenticated() {
- return mState == STATE_AUTHENTICATED;
- }
-
- /** If authentication is currently in progress. */
- boolean isAuthenticating() {
- return mState == STATE_AUTHENTICATING;
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricViewAdapter.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricViewAdapter.kt
deleted file mode 100644
index 68db564606fd..000000000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricViewAdapter.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2022 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.biometrics
-
-import android.hardware.biometrics.BiometricAuthenticator
-import android.os.Bundle
-import android.view.View
-
-/** TODO(b/251476085): Temporary interface while legacy biometric prompt is around. */
-@Deprecated("temporary adapter while migrating biometric prompt - do not expand")
-interface AuthBiometricViewAdapter {
- val legacyIconController: AuthIconController?
-
- fun onDialogAnimatedIn(fingerprintWasStarted: Boolean)
-
- fun onAuthenticationSucceeded(@BiometricAuthenticator.Modality modality: Int)
-
- fun onAuthenticationFailed(
- @BiometricAuthenticator.Modality modality: Int,
- failureReason: String
- )
-
- fun onError(@BiometricAuthenticator.Modality modality: Int, error: String)
-
- fun onHelp(@BiometricAuthenticator.Modality modality: Int, help: String)
-
- fun startTransitionToCredentialUI(isError: Boolean)
-
- fun requestLayout()
-
- fun onSaveState(bundle: Bundle?)
-
- fun restoreState(bundle: Bundle?)
-
- fun onOrientationChanged()
-
- fun cancelAnimation()
-
- fun isCoex(): Boolean
-
- fun asView(): View
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 20b5f78bd70c..c7d7fe32be31 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -17,7 +17,6 @@
package com.android.systemui.biometrics;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE;
-import static android.hardware.biometrics.SensorProperties.STRENGTH_STRONG;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static com.android.internal.jank.InteractionJankMonitor.CUJ_BIOMETRIC_PROMPT_TRANSITION;
@@ -34,7 +33,6 @@ import android.hardware.biometrics.PromptInfo;
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Binder;
-import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -73,11 +71,12 @@ import com.android.systemui.biometrics.shared.model.BiometricModalities;
import com.android.systemui.biometrics.ui.BiometricPromptLayout;
import com.android.systemui.biometrics.ui.CredentialView;
import com.android.systemui.biometrics.ui.binder.BiometricViewBinder;
+import com.android.systemui.biometrics.ui.binder.BiometricViewSizeBinder;
+import com.android.systemui.biometrics.ui.binder.Spaghetti;
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.util.concurrency.DelayableExecutor;
@@ -95,7 +94,10 @@ import kotlinx.coroutines.CoroutineScope;
/**
* Top level container/controller for the BiometricPrompt UI.
+ *
+ * @deprecated TODO(b/287311775): remove and merge view/layouts into new prompt.
*/
+@Deprecated
public class AuthContainerView extends LinearLayout
implements AuthDialog, WakefulnessLifecycle.Observer, CredentialView.Host {
@@ -103,6 +105,7 @@ public class AuthContainerView extends LinearLayout
private static final int ANIMATION_DURATION_SHOW_MS = 250;
private static final int ANIMATION_DURATION_AWAY_MS = 350;
+ private static final int ANIMATE_CREDENTIAL_START_DELAY_MS = 300;
private static final int STATE_UNKNOWN = 0;
private static final int STATE_ANIMATING_IN = 1;
@@ -137,16 +140,16 @@ public class AuthContainerView extends LinearLayout
private final InteractionJankMonitor mInteractionJankMonitor;
private final CoroutineScope mApplicationCoroutineScope;
- // TODO: these should be migrated out once ready
+ // TODO(b/287311775): these should be migrated out once ready
private final Provider<PromptCredentialInteractor> mPromptCredentialInteractor;
private final @NonNull Provider<PromptSelectorInteractor> mPromptSelectorInteractorProvider;
- // TODO(b/251476085): these should be migrated out of the view
+ // TODO(b/287311775): these should be migrated out of the view
private final Provider<CredentialViewModel> mCredentialViewModelProvider;
private final PromptViewModel mPromptViewModel;
@VisibleForTesting final BiometricCallback mBiometricCallback;
- @Nullable private AuthBiometricViewAdapter mBiometricView;
+ @Nullable private Spaghetti mBiometricView;
@Nullable private View mCredentialView;
private final AuthPanelController mPanelController;
private final FrameLayout mFrameLayout;
@@ -165,7 +168,7 @@ public class AuthContainerView extends LinearLayout
// HAT received from LockSettingsService when credential is verified.
@Nullable private byte[] mCredentialAttestation;
- // TODO(b/251476085): remove when legacy prompt is replaced
+ // TODO(b/287311775): remove when legacy prompt is replaced
@Deprecated
static class Config {
Context mContext;
@@ -183,42 +186,50 @@ public class AuthContainerView extends LinearLayout
}
@VisibleForTesting
- final class BiometricCallback implements AuthBiometricView.Callback {
+ final class BiometricCallback implements Spaghetti.Callback {
@Override
- public void onAction(int action) {
- switch (action) {
- case AuthBiometricView.Callback.ACTION_AUTHENTICATED:
- animateAway(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED);
- break;
- case AuthBiometricView.Callback.ACTION_USER_CANCELED:
- sendEarlyUserCanceled();
- animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
- break;
- case AuthBiometricView.Callback.ACTION_BUTTON_NEGATIVE:
- animateAway(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE);
- break;
- case AuthBiometricView.Callback.ACTION_BUTTON_TRY_AGAIN:
- mFailedModalities.clear();
- mConfig.mCallback.onTryAgainPressed(getRequestId());
- break;
- case AuthBiometricView.Callback.ACTION_ERROR:
- animateAway(AuthDialogCallback.DISMISSED_ERROR);
- break;
- case AuthBiometricView.Callback.ACTION_USE_DEVICE_CREDENTIAL:
- mConfig.mCallback.onDeviceCredentialPressed(getRequestId());
- mHandler.postDelayed(() -> {
- addCredentialView(false /* animatePanel */, true /* animateContents */);
- }, mConfig.mSkipAnimation ? 0 : AuthDialog.ANIMATE_CREDENTIAL_START_DELAY_MS);
- break;
- case AuthBiometricView.Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR:
- mConfig.mCallback.onStartFingerprintNow(getRequestId());
- break;
- case AuthBiometricView.Callback.ACTION_AUTHENTICATED_AND_CONFIRMED:
- animateAway(AuthDialogCallback.DISMISSED_BUTTON_POSITIVE);
- break;
- default:
- Log.e(TAG, "Unhandled action: " + action);
- }
+ public void onAuthenticated() {
+ animateAway(AuthDialogCallback.DISMISSED_BIOMETRIC_AUTHENTICATED);
+ }
+
+ @Override
+ public void onUserCanceled() {
+ sendEarlyUserCanceled();
+ animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
+ }
+
+ @Override
+ public void onButtonNegative() {
+ animateAway(AuthDialogCallback.DISMISSED_BUTTON_NEGATIVE);
+ }
+
+ @Override
+ public void onButtonTryAgain() {
+ mFailedModalities.clear();
+ mConfig.mCallback.onTryAgainPressed(getRequestId());
+ }
+
+ @Override
+ public void onError() {
+ animateAway(AuthDialogCallback.DISMISSED_ERROR);
+ }
+
+ @Override
+ public void onUseDeviceCredential() {
+ mConfig.mCallback.onDeviceCredentialPressed(getRequestId());
+ mHandler.postDelayed(() -> {
+ addCredentialView(false /* animatePanel */, true /* animateContents */);
+ }, mConfig.mSkipAnimation ? 0 : ANIMATE_CREDENTIAL_START_DELAY_MS);
+ }
+
+ @Override
+ public void onStartDelayedFingerprintSensor() {
+ mConfig.mCallback.onStartFingerprintNow(getRequestId());
+ }
+
+ @Override
+ public void onAuthenticatedAndConfirmed() {
+ animateAway(AuthDialogCallback.DISMISSED_BUTTON_POSITIVE);
}
}
@@ -354,14 +365,10 @@ public class AuthContainerView extends LinearLayout
mCredentialViewModelProvider = credentialViewModelProvider;
mPromptViewModel = promptViewModel;
- if (featureFlags.isEnabled(Flags.BIOMETRIC_BP_STRONG)) {
- showPrompt(config, layoutInflater, promptViewModel,
- Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds),
- Utils.findFirstSensorProperties(faceProps, mConfig.mSensorIds),
- vibratorHelper, featureFlags);
- } else {
- showLegacyPrompt(config, layoutInflater, fpProps, faceProps);
- }
+ showPrompt(config, layoutInflater, promptViewModel,
+ Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds),
+ Utils.findFirstSensorProperties(faceProps, mConfig.mSensorIds),
+ vibratorHelper, featureFlags);
// TODO: De-dupe the logic with AuthCredentialPasswordView
setOnKeyListener((v, keyCode, event) -> {
@@ -397,7 +404,8 @@ public class AuthContainerView extends LinearLayout
R.layout.biometric_prompt_layout, null, false);
mBiometricView = BiometricViewBinder.bind(view, viewModel, mPanelController,
// TODO(b/201510778): This uses the wrong timeout in some cases
- getJankListener(view, TRANSIT, AuthDialog.ANIMATE_MEDIUM_TO_LARGE_DURATION_MS),
+ getJankListener(view, TRANSIT,
+ BiometricViewSizeBinder.ANIMATE_MEDIUM_TO_LARGE_DURATION_MS),
mBackgroundView, mBiometricCallback, mApplicationCoroutineScope,
vibratorHelper, featureFlags);
@@ -411,60 +419,6 @@ public class AuthContainerView extends LinearLayout
}
}
- // TODO(b/251476085): remove entirely
- private void showLegacyPrompt(@NonNull Config config, @NonNull LayoutInflater layoutInflater,
- @Nullable List<FingerprintSensorPropertiesInternal> fpProps,
- @Nullable List<FaceSensorPropertiesInternal> faceProps
- ) {
- // Inflate biometric view only if necessary.
- if (Utils.isBiometricAllowed(mConfig.mPromptInfo)) {
- final FingerprintSensorPropertiesInternal fpProperties =
- Utils.findFirstSensorProperties(fpProps, mConfig.mSensorIds);
- final FaceSensorPropertiesInternal faceProperties =
- Utils.findFirstSensorProperties(faceProps, mConfig.mSensorIds);
-
- if (fpProperties != null && faceProperties != null) {
- final AuthBiometricFingerprintAndFaceView fingerprintAndFaceView =
- (AuthBiometricFingerprintAndFaceView) layoutInflater.inflate(
- R.layout.auth_biometric_fingerprint_and_face_view, null, false);
- fingerprintAndFaceView.setSensorProperties(fpProperties);
- fingerprintAndFaceView.setScaleFactorProvider(config.mScaleProvider);
- fingerprintAndFaceView.updateOverrideIconLayoutParamsSize();
- fingerprintAndFaceView.setFaceClass3(
- faceProperties.sensorStrength == STRENGTH_STRONG);
- mBiometricView = fingerprintAndFaceView;
- } else if (fpProperties != null) {
- final AuthBiometricFingerprintView fpView =
- (AuthBiometricFingerprintView) layoutInflater.inflate(
- R.layout.auth_biometric_fingerprint_view, null, false);
- fpView.setSensorProperties(fpProperties);
- fpView.setScaleFactorProvider(config.mScaleProvider);
- fpView.updateOverrideIconLayoutParamsSize();
- mBiometricView = fpView;
- } else if (faceProperties != null) {
- mBiometricView = (AuthBiometricFaceView) layoutInflater.inflate(
- R.layout.auth_biometric_face_view, null, false);
- } else {
- Log.e(TAG, "No sensors found!");
- }
- }
-
- // init view before showing
- if (mBiometricView != null) {
- final AuthBiometricView view = (AuthBiometricView) mBiometricView;
- view.setRequireConfirmation(mConfig.mRequireConfirmation);
- view.setPanelController(mPanelController);
- view.setPromptInfo(mConfig.mPromptInfo);
- view.setCallback(mBiometricCallback);
- view.setBackgroundView(mBackgroundView);
- view.setUserId(mConfig.mUserId);
- view.setEffectiveUserId(mEffectiveUserId);
- // TODO(b/201510778): This uses the wrong timeout in some cases (remove w/ above)
- view.setJankListener(getJankListener(view, TRANSIT,
- AuthDialog.ANIMATE_MEDIUM_TO_LARGE_DURATION_MS));
- }
- }
-
private void onBackInvoked() {
sendEarlyUserCanceled();
animateAway(AuthDialogCallback.DISMISSED_USER_CANCELED);
@@ -532,9 +486,6 @@ public class AuthContainerView extends LinearLayout
@Override
public void onOrientationChanged() {
maybeUpdatePositionForUdfps(true /* invalidate */);
- if (mBiometricView != null) {
- mBiometricView.onOrientationChanged();
- }
}
@Override
@@ -620,10 +571,6 @@ public class AuthContainerView extends LinearLayout
}
private static boolean shouldUpdatePositionForUdfps(@NonNull View view) {
- // TODO(b/251476085): legacy view (delete when removed)
- if (view instanceof AuthBiometricFingerprintView) {
- return ((AuthBiometricFingerprintView) view).isUdfps();
- }
if (view instanceof BiometricPromptLayout) {
// this will force the prompt to align itself on the edge of the screen
// instead of centering (temporary workaround to prevent small implicit view
@@ -671,7 +618,6 @@ public class AuthContainerView extends LinearLayout
if (invalidate) {
mPanelView.invalidateOutline();
- mBiometricView.requestLayout();
}
return true;
@@ -701,11 +647,7 @@ public class AuthContainerView extends LinearLayout
}
@Override
- public void show(WindowManager wm, @Nullable Bundle savedState) {
- if (mBiometricView != null) {
- mBiometricView.restoreState(savedState);
- }
-
+ public void show(WindowManager wm) {
wm.addView(this, getLayoutParams(mWindowToken, mConfig.mPromptInfo.getTitle()));
}
@@ -780,7 +722,7 @@ public class AuthContainerView extends LinearLayout
if (mFailedModalities.contains(TYPE_FACE)) {
Log.d(TAG, "retrying failed modalities (pointer down)");
mFailedModalities.remove(TYPE_FACE);
- mBiometricCallback.onAction(AuthBiometricView.Callback.ACTION_BUTTON_TRY_AGAIN);
+ mBiometricCallback.onButtonTryAgain();
}
} else {
Log.e(TAG, "onPointerDown(): mBiometricView is null");
@@ -788,21 +730,6 @@ public class AuthContainerView extends LinearLayout
}
@Override
- public void onSaveState(@NonNull Bundle outState) {
- outState.putBoolean(AuthDialog.KEY_CONTAINER_GOING_AWAY,
- mContainerState == STATE_ANIMATING_OUT);
- // In the case where biometric and credential are both allowed, we can assume that
- // biometric isn't showing if credential is showing since biometric is shown first.
- outState.putBoolean(AuthDialog.KEY_BIOMETRIC_SHOWING,
- mBiometricView != null && mCredentialView == null);
- outState.putBoolean(AuthDialog.KEY_CREDENTIAL_SHOWING, mCredentialView != null);
-
- if (mBiometricView != null) {
- mBiometricView.onSaveState(outState);
- }
- }
-
- @Override
public String getOpPackageName() {
return mConfig.mOpPackageName;
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 5719fdd0b4de..b752c3b80cae 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -50,7 +50,6 @@ import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.IUdfpsRefreshRateRequestCallback;
-import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserManager;
@@ -966,7 +965,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
skipAnimation = true;
}
- showDialog(args, skipAnimation, null /* savedState */, mPromptViewModelProvider.get());
+ showDialog(args, skipAnimation, mPromptViewModelProvider.get());
}
/**
@@ -1198,7 +1197,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
return mFpEnrolledForUser.getOrDefault(userId, false);
}
- private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState,
+ private void showDialog(SomeArgs args, boolean skipAnimation,
@Nullable PromptViewModel viewModel) {
mCurrentDialogArgs = args;
@@ -1238,7 +1237,6 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
if (DEBUG) {
Log.d(TAG, "userId: " + userId
- + " savedState: " + savedState
+ " mCurrentDialog: " + mCurrentDialog
+ " newDialog: " + newDialog);
}
@@ -1260,7 +1258,7 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
if (!promptInfo.isAllowBackgroundAuthentication() && !isOwnerInForeground()) {
cancelIfOwnerIsNotInForeground();
} else {
- mCurrentDialog.show(mWindowManager, savedState);
+ mCurrentDialog.show(mWindowManager);
}
}
@@ -1282,29 +1280,12 @@ public class AuthController implements CoreStartable, CommandQueue.Callbacks,
public void onConfigurationChanged(Configuration newConfig) {
updateSensorLocations();
- // Save the state of the current dialog (buttons showing, etc)
+ // TODO(b/287311775): consider removing this to retain the UI cleanly vs re-creating
if (mCurrentDialog != null) {
final PromptViewModel viewModel = mCurrentDialog.getViewModel();
- final Bundle savedState = new Bundle();
- mCurrentDialog.onSaveState(savedState);
mCurrentDialog.dismissWithoutCallback(false /* animate */);
mCurrentDialog = null;
-
- // Only show the dialog if necessary. If it was animating out, the dialog is supposed
- // to send its pending callback immediately.
- if (!savedState.getBoolean(AuthDialog.KEY_CONTAINER_GOING_AWAY, false)) {
- final boolean credentialShowing =
- savedState.getBoolean(AuthDialog.KEY_CREDENTIAL_SHOWING);
- if (credentialShowing) {
- // There may be a cleaner way to do this, rather than altering the current
- // authentication's parameters. This gets the job done and should be clear
- // enough for now.
- PromptInfo promptInfo = (PromptInfo) mCurrentDialogArgs.arg1;
- promptInfo.setAuthenticators(Authenticators.DEVICE_CREDENTIAL);
- }
-
- showDialog(mCurrentDialogArgs, true /* skipAnimation */, savedState, viewModel);
- }
+ showDialog(mCurrentDialogArgs, true /* skipAnimation */, viewModel);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
index 3cfc6f280110..3fd488c34121 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthDialog.java
@@ -16,59 +16,20 @@
package com.android.systemui.biometrics;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.hardware.biometrics.BiometricAuthenticator.Modality;
-import android.os.Bundle;
import android.view.WindowManager;
import com.android.systemui.Dumpable;
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
/**
* Interface for the biometric dialog UI.
*
- * TODO(b/251476085): remove along with legacy controller once flag is removed
+ * TODO(b/287311775): remove along with legacy controller once flag is removed
*/
@Deprecated
public interface AuthDialog extends Dumpable {
- String KEY_CONTAINER_GOING_AWAY = "container_going_away";
- String KEY_BIOMETRIC_SHOWING = "biometric_showing";
- String KEY_CREDENTIAL_SHOWING = "credential_showing";
-
- String KEY_BIOMETRIC_CONFIRM_VISIBILITY = "confirm_visibility";
- String KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY = "try_agian_visibility";
- String KEY_BIOMETRIC_STATE = "state";
- String KEY_BIOMETRIC_INDICATOR_STRING = "indicator_string"; // error / help / hint
- String KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING = "error_is_temporary";
- String KEY_BIOMETRIC_INDICATOR_HELP_SHOWING = "hint_is_temporary";
- String KEY_BIOMETRIC_DIALOG_SIZE = "size";
-
- String KEY_BIOMETRIC_SENSOR_TYPE = "sensor_type";
- String KEY_BIOMETRIC_SENSOR_PROPS = "sensor_props";
-
- int SIZE_UNKNOWN = 0;
- /**
- * Minimal UI, showing only biometric icon.
- */
- int SIZE_SMALL = 1;
- /**
- * Normal-sized biometric UI, showing title, icon, buttons, etc.
- */
- int SIZE_MEDIUM = 2;
- /**
- * Full-screen credential UI.
- */
- int SIZE_LARGE = 3;
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({SIZE_UNKNOWN, SIZE_SMALL, SIZE_MEDIUM, SIZE_LARGE})
- @interface DialogSize {}
-
/**
* Parameters used when laying out {@link AuthBiometricView}, its subclasses, and
* {@link AuthPanelController}.
@@ -84,27 +45,10 @@ public interface AuthDialog extends Dumpable {
}
/**
- * Animation duration, from small to medium dialog, including back panel, icon translation, etc
- */
- int ANIMATE_SMALL_TO_MEDIUM_DURATION_MS = 150;
- /**
- * Animation duration from medium to large dialog, including biometric fade out, back panel, etc
- */
- int ANIMATE_MEDIUM_TO_LARGE_DURATION_MS = 450;
- /**
- * Delay before notifying {@link AuthCredentialView} to start animating in.
- */
- int ANIMATE_CREDENTIAL_START_DELAY_MS = ANIMATE_MEDIUM_TO_LARGE_DURATION_MS * 2 / 3;
- /**
- * Animation duration when sliding in credential UI
- */
- int ANIMATE_CREDENTIAL_INITIAL_DURATION_MS = 150;
-
- /**
* Show the dialog.
* @param wm
*/
- void show(WindowManager wm, @Nullable Bundle savedState);
+ void show(WindowManager wm);
/**
* Dismiss the dialog without sending a callback.
@@ -146,12 +90,6 @@ public interface AuthDialog extends Dumpable {
void onPointerDown();
/**
- * Save the current state.
- * @param outState
- */
- void onSaveState(@NonNull Bundle outState);
-
- /**
* Get the client's package name
*/
String getOpPackageName();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthIconController.kt
index f56bb881d8b7..958213afacdf 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthIconController.kt
@@ -24,7 +24,7 @@ import android.graphics.drawable.Drawable
import android.util.Log
import com.airbnb.lottie.LottieAnimationView
import com.airbnb.lottie.LottieCompositionFactory
-import com.android.systemui.biometrics.AuthBiometricView.BiometricState
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState
private const val TAG = "AuthIconController"
@@ -76,7 +76,7 @@ abstract class AuthIconController(
}
/** Update the icon to reflect the [newState]. */
- fun updateState(@BiometricState lastState: Int, @BiometricState newState: Int) {
+ fun updateState(lastState: BiometricState, newState: BiometricState) {
if (deactivated) {
Log.w(TAG, "Ignoring updateState when deactivated: $newState")
} else {
@@ -85,7 +85,7 @@ abstract class AuthIconController(
}
/** Call during [updateState] if the controller is not [deactivated]. */
- abstract fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int)
+ abstract fun updateIcon(lastState: BiometricState, newState: BiometricState)
/** Called during [onAnimationEnd] if the controller is not [deactivated]. */
open fun handleAnimationEnd(drawable: Drawable) {}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index 672f180c13b4..d616dcca338f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -23,7 +23,6 @@ import android.hardware.biometrics.BiometricAuthenticator
import android.hardware.biometrics.BiometricConstants
import android.hardware.biometrics.BiometricPrompt
import android.hardware.face.FaceManager
-import android.os.Bundle
import android.text.method.ScrollingMovementMethod
import android.util.Log
import android.view.HapticFeedbackConstants
@@ -43,9 +42,6 @@ import com.android.systemui.R
import com.android.systemui.biometrics.AuthBiometricFaceIconController
import com.android.systemui.biometrics.AuthBiometricFingerprintAndFaceIconController
import com.android.systemui.biometrics.AuthBiometricFingerprintIconController
-import com.android.systemui.biometrics.AuthBiometricView
-import com.android.systemui.biometrics.AuthBiometricView.Callback
-import com.android.systemui.biometrics.AuthBiometricViewAdapter
import com.android.systemui.biometrics.AuthIconController
import com.android.systemui.biometrics.AuthPanelController
import com.android.systemui.biometrics.shared.model.BiometricModalities
@@ -63,7 +59,6 @@ import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.statusbar.VibratorHelper
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
@@ -83,11 +78,11 @@ object BiometricViewBinder {
panelViewController: AuthPanelController,
jankListener: BiometricJankListener,
backgroundView: View,
- legacyCallback: Callback,
+ legacyCallback: Spaghetti.Callback,
applicationScope: CoroutineScope,
vibratorHelper: VibratorHelper,
featureFlags: FeatureFlags,
- ): AuthBiometricViewAdapter {
+ ): Spaghetti {
val accessibilityManager = view.context.getSystemService(AccessibilityManager::class.java)!!
val textColorError =
@@ -141,24 +136,20 @@ object BiometricViewBinder {
subtitleView.text = viewModel.subtitle.first()
// set button listeners
- negativeButton.setOnClickListener {
- legacyCallback.onAction(Callback.ACTION_BUTTON_NEGATIVE)
- }
- cancelButton.setOnClickListener {
- legacyCallback.onAction(Callback.ACTION_USER_CANCELED)
- }
+ negativeButton.setOnClickListener { legacyCallback.onButtonNegative() }
+ cancelButton.setOnClickListener { legacyCallback.onUserCanceled() }
credentialFallbackButton.setOnClickListener {
viewModel.onSwitchToCredential()
- legacyCallback.onAction(Callback.ACTION_USE_DEVICE_CREDENTIAL)
+ legacyCallback.onUseDeviceCredential()
}
confirmationButton.setOnClickListener { viewModel.confirmAuthenticated() }
retryButton.setOnClickListener {
viewModel.showAuthenticating(isRetry = true)
- legacyCallback.onAction(Callback.ACTION_BUTTON_TRY_AGAIN)
+ legacyCallback.onButtonTryAgain()
}
// TODO(b/251476085): migrate legacy icon controllers and remove
- var legacyState: Int = viewModel.legacyState.value
+ var legacyState = viewModel.legacyState.value
val iconController =
modalities.asIconController(
view.context,
@@ -219,7 +210,7 @@ object BiometricViewBinder {
oldMode == FingerprintStartMode.Pending &&
newMode == FingerprintStartMode.Delayed
) {
- legacyCallback.onAction(Callback.ACTION_START_DELAYED_FINGERPRINT_SENSOR)
+ legacyCallback.onStartDelayedFingerprintSensor()
}
if (newMode.isStarted) {
@@ -246,7 +237,7 @@ object BiometricViewBinder {
.collect { dismissOnClick ->
backgroundView.setOnClickListener {
if (dismissOnClick) {
- legacyCallback.onAction(Callback.ACTION_USER_CANCELED)
+ legacyCallback.onUserCanceled()
} else {
Log.w(TAG, "Ignoring background click")
}
@@ -360,13 +351,11 @@ object BiometricViewBinder {
launch {
delay(authState.delay)
- legacyCallback.onAction(
- if (authState.isAuthenticatedAndExplicitlyConfirmed) {
- Callback.ACTION_AUTHENTICATED_AND_CONFIRMED
- } else {
- Callback.ACTION_AUTHENTICATED
- }
- )
+ if (authState.isAuthenticatedAndExplicitlyConfirmed) {
+ legacyCallback.onAuthenticatedAndConfirmed()
+ } else {
+ legacyCallback.onAuthenticated()
+ }
}
}
}
@@ -428,21 +417,50 @@ object BiometricViewBinder {
* the view model (which will be retained) via the application scope.
*
* Do not reference the [view] for anything other than [asView].
- *
- * TODO(b/251476085): remove after replacing AuthContainerView
*/
-private class Spaghetti(
+@Deprecated("TODO(b/251476085): remove after replacing AuthContainerView")
+class Spaghetti(
private val view: View,
private val viewModel: PromptViewModel,
private val applicationContext: Context,
private val applicationScope: CoroutineScope,
-) : AuthBiometricViewAdapter {
+) {
+
+ @Deprecated("TODO(b/251476085): remove after replacing AuthContainerView")
+ interface Callback {
+ fun onAuthenticated()
+ fun onUserCanceled()
+ fun onButtonNegative()
+ fun onButtonTryAgain()
+ fun onError()
+ fun onUseDeviceCredential()
+ fun onStartDelayedFingerprintSensor()
+ fun onAuthenticatedAndConfirmed()
+ }
+
+ @Deprecated("TODO(b/251476085): remove after replacing AuthContainerView")
+ enum class BiometricState {
+ /** Authentication hardware idle. */
+ STATE_IDLE,
+ /** UI animating in, authentication hardware active. */
+ STATE_AUTHENTICATING_ANIMATING_IN,
+ /** UI animated in, authentication hardware active. */
+ STATE_AUTHENTICATING,
+ /** UI animated in, authentication hardware active. */
+ STATE_HELP,
+ /** Hard error, e.g. ERROR_TIMEOUT. Authentication hardware idle. */
+ STATE_ERROR,
+ /** Authenticated, waiting for user confirmation. Authentication hardware idle. */
+ STATE_PENDING_CONFIRMATION,
+ /** Authenticated, dialog animating away soon. */
+ STATE_AUTHENTICATED,
+ }
private var lifecycleScope: CoroutineScope? = null
private var modalities: BiometricModalities = BiometricModalities()
private var legacyCallback: Callback? = null
- override var legacyIconController: AuthIconController? = null
+ var legacyIconController: AuthIconController? = null
private set
// hacky way to suppress lockout errors
@@ -478,7 +496,7 @@ private class Spaghetti(
)
}
- override fun onDialogAnimatedIn(fingerprintWasStarted: Boolean) {
+ fun onDialogAnimatedIn(fingerprintWasStarted: Boolean) {
if (fingerprintWasStarted) {
viewModel.ensureFingerprintHasStarted(isDelayed = false)
viewModel.showAuthenticating(modalities.asDefaultHelpMessage(applicationContext))
@@ -487,7 +505,7 @@ private class Spaghetti(
}
}
- override fun onAuthenticationSucceeded(@BiometricAuthenticator.Modality modality: Int) {
+ fun onAuthenticationSucceeded(@BiometricAuthenticator.Modality modality: Int) {
applicationScope.launch {
val authenticatedModality = modality.asBiometricModality()
val msgId = getHelpForSuccessfulAuthentication(authenticatedModality)
@@ -511,7 +529,7 @@ private class Spaghetti(
else -> null
}
- override fun onAuthenticationFailed(
+ fun onAuthenticationFailed(
@BiometricAuthenticator.Modality modality: Int,
failureReason: String,
) {
@@ -533,7 +551,7 @@ private class Spaghetti(
}
}
- override fun onError(modality: Int, error: String) {
+ fun onError(modality: Int, error: String) {
val errorModality = modality.asBiometricModality()
if (ignoreUnsuccessfulEventsFrom(errorModality, error)) {
return
@@ -546,11 +564,11 @@ private class Spaghetti(
authenticateAfterError = modalities.hasFingerprint,
)
delay(BiometricPrompt.HIDE_DIALOG_DELAY.toLong())
- legacyCallback?.onAction(Callback.ACTION_ERROR)
+ legacyCallback?.onError()
}
}
- override fun onHelp(modality: Int, help: String) {
+ fun onHelp(modality: Int, help: String) {
if (ignoreUnsuccessfulEventsFrom(modality.asBiometricModality(), "")) {
return
}
@@ -574,36 +592,20 @@ private class Spaghetti(
else -> false
}
- override fun startTransitionToCredentialUI(isError: Boolean) {
+ fun startTransitionToCredentialUI(isError: Boolean) {
applicationScope.launch {
viewModel.onSwitchToCredential()
- legacyCallback?.onAction(Callback.ACTION_USE_DEVICE_CREDENTIAL)
+ legacyCallback?.onUseDeviceCredential()
}
}
- override fun requestLayout() {
- // nothing, for legacy view...
- }
-
- override fun restoreState(bundle: Bundle?) {
- // nothing, for legacy view...
- }
-
- override fun onSaveState(bundle: Bundle?) {
- // nothing, for legacy view...
- }
-
- override fun onOrientationChanged() {
- // nothing, for legacy view...
- }
-
- override fun cancelAnimation() {
+ fun cancelAnimation() {
view.animate()?.cancel()
}
- override fun isCoex() = modalities.hasFaceAndFingerprint
+ fun isCoex() = modalities.hasFaceAndFingerprint
- override fun asView() = view
+ fun asView() = view
}
private fun BiometricModalities.asDefaultHelpMessage(context: Context): String =
@@ -638,7 +640,7 @@ private class HackyCoexIconController(
iconViewOverlay: LottieAnimationView,
) : AuthBiometricFingerprintAndFaceIconController(context, iconView, iconViewOverlay) {
- private var state: Int? = null
+ private var state: Spaghetti.BiometricState? = null
private val faceController = AuthBiometricFaceIconController(context, iconView)
var faceMode: Boolean = true
@@ -649,11 +651,14 @@ private class HackyCoexIconController(
faceController.deactivated = !value
iconView.setImageIcon(null)
iconViewOverlay.setImageIcon(null)
- state?.let { updateIcon(AuthBiometricView.STATE_IDLE, it) }
+ state?.let { updateIcon(Spaghetti.BiometricState.STATE_IDLE, it) }
}
}
- override fun updateIcon(lastState: Int, newState: Int) {
+ override fun updateIcon(
+ lastState: Spaghetti.BiometricState,
+ newState: Spaghetti.BiometricState,
+ ) {
if (deactivated) {
return
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
index 370b36bcaec2..b9af03166fed 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
@@ -31,7 +31,6 @@ import androidx.core.view.doOnLayout
import androidx.core.view.isGone
import androidx.lifecycle.lifecycleScope
import com.android.systemui.R
-import com.android.systemui.biometrics.AuthDialog
import com.android.systemui.biometrics.AuthPanelController
import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.ui.BiometricPromptLayout
@@ -47,6 +46,10 @@ import kotlinx.coroutines.launch
/** Helper for [BiometricViewBinder] to handle resize transitions. */
object BiometricViewSizeBinder {
+ private const val ANIMATE_SMALL_TO_MEDIUM_DURATION_MS = 150
+ // TODO(b/201510778): make private when related misuse is fixed
+ const val ANIMATE_MEDIUM_TO_LARGE_DURATION_MS = 450
+
/** Resizes [BiometricPromptLayout] and the [panelViewController] via the [PromptViewModel]. */
fun bind(
view: BiometricPromptLayout,
@@ -134,7 +137,7 @@ object BiometricViewSizeBinder {
)
}
size.isMedium && currentSize.isSmall -> {
- val duration = AuthDialog.ANIMATE_SMALL_TO_MEDIUM_DURATION_MS
+ val duration = ANIMATE_SMALL_TO_MEDIUM_DURATION_MS
panelViewController.updateForContentDimensions(
width,
height,
@@ -165,7 +168,7 @@ object BiometricViewSizeBinder {
)
}
size.isLarge -> {
- val duration = AuthDialog.ANIMATE_MEDIUM_TO_LARGE_DURATION_MS
+ val duration = ANIMATE_MEDIUM_TO_LARGE_DURATION_MS
panelViewController.setUseFullScreen(true)
panelViewController.updateForContentDimensions(
panelViewController.containerWidth,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
index 25fe61916644..931946aaa382 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialViewBinder.kt
@@ -9,7 +9,6 @@ import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.app.animation.Interpolators
import com.android.systemui.R
-import com.android.systemui.biometrics.AuthDialog
import com.android.systemui.biometrics.AuthPanelController
import com.android.systemui.biometrics.ui.CredentialPasswordView
import com.android.systemui.biometrics.ui.CredentialPatternView
@@ -22,6 +21,8 @@ import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
+private const val ANIMATE_CREDENTIAL_INITIAL_DURATION_MS = 150
+
/**
* View binder for all credential variants of BiometricPrompt, including [CredentialPatternView] and
* [CredentialPasswordView].
@@ -147,7 +148,7 @@ private fun View.animateCredentialViewIn() {
postOnAnimation {
animate()
.translationY(0f)
- .setDuration(AuthDialog.ANIMATE_CREDENTIAL_INITIAL_DURATION_MS.toLong())
+ .setDuration(ANIMATE_CREDENTIAL_INITIAL_DURATION_MS.toLong())
.alpha(1f)
.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
.withLayer()
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index fbc88d43c48e..6269700d5419 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -19,12 +19,12 @@ import android.hardware.biometrics.BiometricPrompt
import android.util.Log
import android.view.HapticFeedbackConstants
import android.view.MotionEvent
-import com.android.systemui.biometrics.AuthBiometricView
import com.android.systemui.biometrics.domain.interactor.DisplayStateInteractor
import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteractor
import com.android.systemui.biometrics.shared.model.BiometricModalities
import com.android.systemui.biometrics.shared.model.BiometricModality
import com.android.systemui.biometrics.shared.model.PromptKind
+import com.android.systemui.biometrics.ui.binder.Spaghetti
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION
import com.android.systemui.statusbar.VibratorHelper
@@ -62,8 +62,8 @@ constructor(
.distinctUntilChanged()
// TODO(b/251476085): remove after icon controllers are migrated - do not keep this state
- private var _legacyState = MutableStateFlow(AuthBiometricView.STATE_IDLE)
- val legacyState: StateFlow<Int> = _legacyState.asStateFlow()
+ private var _legacyState = MutableStateFlow(Spaghetti.BiometricState.STATE_IDLE)
+ val legacyState: StateFlow<Spaghetti.BiometricState> = _legacyState.asStateFlow()
private val _isAuthenticating: MutableStateFlow<Boolean> = MutableStateFlow(false)
@@ -270,7 +270,7 @@ constructor(
_isAuthenticated.value = PromptAuthState(false)
_forceMediumSize.value = true
_message.value = PromptMessage.Error(message)
- _legacyState.value = AuthBiometricView.STATE_ERROR
+ _legacyState.value = Spaghetti.BiometricState.STATE_ERROR
if (hapticFeedback) {
vibrator.error(failedModality)
@@ -322,13 +322,13 @@ constructor(
_forceMediumSize.value = true
_legacyState.value =
if (alreadyAuthenticated && isConfirmationRequired.first()) {
- AuthBiometricView.STATE_PENDING_CONFIRMATION
+ Spaghetti.BiometricState.STATE_PENDING_CONFIRMATION
} else if (alreadyAuthenticated && !isConfirmationRequired.first()) {
- AuthBiometricView.STATE_AUTHENTICATED
+ Spaghetti.BiometricState.STATE_AUTHENTICATED
} else if (clearIconError) {
- AuthBiometricView.STATE_IDLE
+ Spaghetti.BiometricState.STATE_IDLE
} else {
- AuthBiometricView.STATE_HELP
+ Spaghetti.BiometricState.STATE_HELP
}
messageJob?.cancel()
@@ -353,7 +353,7 @@ constructor(
_message.value =
if (message.isNotBlank()) PromptMessage.Help(message) else PromptMessage.Empty
_forceMediumSize.value = true
- _legacyState.value = AuthBiometricView.STATE_HELP
+ _legacyState.value = Spaghetti.BiometricState.STATE_HELP
messageJob?.cancel()
messageJob = launch {
@@ -373,7 +373,7 @@ constructor(
_isAuthenticating.value = true
_isAuthenticated.value = PromptAuthState(false)
_message.value = if (message.isBlank()) PromptMessage.Empty else PromptMessage.Help(message)
- _legacyState.value = AuthBiometricView.STATE_AUTHENTICATING
+ _legacyState.value = Spaghetti.BiometricState.STATE_AUTHENTICATING
// reset the try again button(s) after the user attempts a retry
if (isRetry) {
@@ -406,9 +406,9 @@ constructor(
_message.value = PromptMessage.Empty
_legacyState.value =
if (needsUserConfirmation) {
- AuthBiometricView.STATE_PENDING_CONFIRMATION
+ Spaghetti.BiometricState.STATE_PENDING_CONFIRMATION
} else {
- AuthBiometricView.STATE_AUTHENTICATED
+ Spaghetti.BiometricState.STATE_AUTHENTICATED
}
if (!needsUserConfirmation) {
@@ -449,7 +449,7 @@ constructor(
_isAuthenticated.value = authState.asExplicitlyConfirmed()
_message.value = PromptMessage.Empty
- _legacyState.value = AuthBiometricView.STATE_AUTHENTICATED
+ _legacyState.value = Spaghetti.BiometricState.STATE_AUTHENTICATED
vibrator.success(authState.authenticatedModality)
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 595e0a300177..4cb9622ab4c9 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -659,8 +659,6 @@ object Flags {
// TODO(b/259264861): Tracking Bug
@JvmField val UDFPS_NEW_TOUCH_DETECTION = releasedFlag("udfps_new_touch_detection")
@JvmField val UDFPS_ELLIPSE_DETECTION = releasedFlag("udfps_ellipse_detection")
- // TODO(b/278622168): Tracking Bug
- @JvmField val BIOMETRIC_BP_STRONG = releasedFlag("biometric_bp_strong")
// 2300 - stylus
@JvmField val TRACK_STYLUS_EVER_USED = releasedFlag("track_stylus_ever_used")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt
deleted file mode 100644
index a93af7dd7450..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceViewTest.kt
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2022 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.biometrics
-
-import android.hardware.biometrics.BiometricAuthenticator.TYPE_FACE
-import android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT
-import android.hardware.biometrics.BiometricConstants
-import android.hardware.face.FaceManager
-import android.testing.TestableLooper
-import android.testing.TestableLooper.RunWithLooper
-import android.view.View
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.R
-import com.android.systemui.RoboPilotTest
-import com.android.systemui.SysuiTestCase
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.times
-import org.mockito.junit.MockitoJUnit
-
-
-@RunWith(AndroidJUnit4::class)
-@RunWithLooper(setAsMainLooper = true)
-@SmallTest
-@RoboPilotTest
-class AuthBiometricFingerprintAndFaceViewTest : SysuiTestCase() {
-
- @JvmField
- @Rule
- var mockitoRule = MockitoJUnit.rule()
-
- @Mock
- private lateinit var callback: AuthBiometricView.Callback
-
- @Mock
- private lateinit var panelController: AuthPanelController
-
- private lateinit var biometricView: AuthBiometricFingerprintAndFaceView
-
- @Before
- fun setup() {
- biometricView = R.layout.auth_biometric_fingerprint_and_face_view
- .asTestAuthBiometricView(mContext, callback, panelController)
- waitForIdleSync()
- }
-
- @After
- fun tearDown() {
- biometricView.destroyDialog()
- }
-
- @Test
- fun fingerprintSuccessDoesNotRequireExplicitConfirmation() {
- biometricView.onDialogAnimatedIn(fingerprintWasStarted = true)
- biometricView.onAuthenticationSucceeded(TYPE_FINGERPRINT)
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticated).isTrue()
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED)
- }
-
- @Test
- fun faceSuccessRequiresExplicitConfirmation() {
- biometricView.onDialogAnimatedIn(fingerprintWasStarted = true)
- biometricView.onAuthenticationSucceeded(TYPE_FACE)
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticated).isFalse()
- assertThat(biometricView.isAuthenticating).isFalse()
- assertThat(biometricView.mConfirmButton.visibility).isEqualTo(View.GONE)
- verify(callback, never()).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED)
-
- // icon acts as confirm button
- biometricView.mIconView.performClick()
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticated).isTrue()
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED_AND_CONFIRMED)
- }
-
- @Test
- fun ignoresFaceErrors_faceIsNotClass3_notLockoutError() {
- biometricView.onDialogAnimatedIn(fingerprintWasStarted = true)
- biometricView.onError(TYPE_FACE, "not a face")
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticating).isTrue()
- verify(callback, never()).onAction(AuthBiometricView.Callback.ACTION_ERROR)
-
- biometricView.onError(TYPE_FINGERPRINT, "that's a nope")
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)
- }
-
- @Test
- fun doNotIgnoresFaceErrors_faceIsClass3_notLockoutError() {
- biometricView.isFaceClass3 = true
- biometricView.onDialogAnimatedIn(fingerprintWasStarted = true)
- biometricView.onError(TYPE_FACE, "not a face")
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticating).isTrue()
- verify(callback, never()).onAction(AuthBiometricView.Callback.ACTION_ERROR)
-
- biometricView.onError(TYPE_FINGERPRINT, "that's a nope")
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)
- }
-
- @Test
- fun doNotIgnoresFaceErrors_faceIsClass3_lockoutError() {
- biometricView.isFaceClass3 = true
- biometricView.onDialogAnimatedIn(fingerprintWasStarted = true)
- biometricView.onError(
- TYPE_FACE,
- FaceManager.getErrorString(
- biometricView.context,
- BiometricConstants.BIOMETRIC_ERROR_LOCKOUT_PERMANENT,
- 0 /*vendorCode */
- )
- )
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticating).isTrue()
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_ERROR)
-
- biometricView.onError(TYPE_FINGERPRINT, "that's a nope")
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback, times(2)).onAction(AuthBiometricView.Callback.ACTION_ERROR)
- }
-
-
- override fun waitForIdleSync() = TestableLooper.get(this).processAllMessages()
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconControllerTest.kt
index cac618b21dc7..52bf350bfcc8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconControllerTest.kt
@@ -27,6 +27,7 @@ import androidx.test.filters.SmallTest
import com.airbnb.lottie.LottieAnimationView
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Rule
@@ -63,7 +64,7 @@ class AuthBiometricFingerprintIconControllerTest : SysuiTestCase() {
setupFingerprintSensorProperties(FingerprintSensorProperties.TYPE_POWER_BUTTON)
controller = AuthBiometricFingerprintIconController(context, iconView, iconViewOverlay)
- assertThat(controller.getIconContentDescription(AuthBiometricView.STATE_AUTHENTICATING))
+ assertThat(controller.getIconContentDescription(BiometricState.STATE_AUTHENTICATING))
.isEqualTo(
context.resources.getString(
R.string.security_settings_sfps_enroll_find_sensor_message
@@ -76,7 +77,7 @@ class AuthBiometricFingerprintIconControllerTest : SysuiTestCase() {
setupFingerprintSensorProperties(FingerprintSensorProperties.TYPE_UDFPS_OPTICAL)
controller = AuthBiometricFingerprintIconController(context, iconView, iconViewOverlay)
- assertThat(controller.getIconContentDescription(AuthBiometricView.STATE_AUTHENTICATING))
+ assertThat(controller.getIconContentDescription(BiometricState.STATE_AUTHENTICATING))
.isEqualTo(context.resources.getString(R.string.fingerprint_dialog_touch_sensor))
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt
deleted file mode 100644
index 8e5d96b0a2c6..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFingerprintViewTest.kt
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright (C) 2022 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.biometrics
-
-import android.hardware.biometrics.BiometricAuthenticator
-import android.os.Bundle
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import android.testing.TestableLooper
-import android.testing.TestableLooper.RunWithLooper
-import android.view.View
-import androidx.test.filters.SmallTest
-import com.android.systemui.R
-import com.android.systemui.RoboPilotTest
-import com.android.systemui.SysuiTestCase
-import com.google.common.truth.Truth.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mock
-import org.mockito.Mockito.never
-import org.mockito.Mockito.verify
-import org.mockito.junit.MockitoJUnit
-
-@RunWith(AndroidJUnit4::class)
-@RunWithLooper(setAsMainLooper = true)
-@SmallTest
-@RoboPilotTest
-class AuthBiometricFingerprintViewTest : SysuiTestCase() {
-
- @JvmField
- @Rule
- val mockitoRule = MockitoJUnit.rule()
-
- @Mock
- private lateinit var callback: AuthBiometricView.Callback
-
- @Mock
- private lateinit var panelController: AuthPanelController
-
- private lateinit var biometricView: AuthBiometricView
-
- private fun createView(allowDeviceCredential: Boolean = false): AuthBiometricFingerprintView {
- val view: AuthBiometricFingerprintView =
- R.layout.auth_biometric_fingerprint_view.asTestAuthBiometricView(
- mContext, callback, panelController, allowDeviceCredential = allowDeviceCredential
- )
- waitForIdleSync()
- return view
- }
-
- @Before
- fun setup() {
- biometricView = createView()
- }
-
- @After
- fun tearDown() {
- biometricView.destroyDialog()
- }
-
- @Test
- fun testOnAuthenticationSucceeded_noConfirmationRequired_sendsActionAuthenticated() {
- biometricView.onAuthenticationSucceeded(BiometricAuthenticator.TYPE_FINGERPRINT)
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticated).isTrue()
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED)
- }
-
- @Test
- fun testOnAuthenticationSucceeded_confirmationRequired_updatesDialogContents() {
- biometricView.setRequireConfirmation(true)
- biometricView.onAuthenticationSucceeded(BiometricAuthenticator.TYPE_FINGERPRINT)
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- // TODO: this should be tested in the subclasses
- if (biometricView.supportsRequireConfirmation()) {
- verify(callback, never()).onAction(ArgumentMatchers.anyInt())
- assertThat(biometricView.mNegativeButton.visibility).isEqualTo(View.GONE)
- assertThat(biometricView.mCancelButton.visibility).isEqualTo(View.VISIBLE)
- assertThat(biometricView.mCancelButton.isEnabled).isTrue()
- assertThat(biometricView.mConfirmButton.isEnabled).isTrue()
- assertThat(biometricView.mIndicatorView.text)
- .isEqualTo(mContext.getText(R.string.biometric_dialog_tap_confirm))
- assertThat(biometricView.mIndicatorView.visibility).isEqualTo(View.VISIBLE)
- } else {
- assertThat(biometricView.isAuthenticated).isTrue()
- verify(callback).onAction(eq(AuthBiometricView.Callback.ACTION_AUTHENTICATED))
- }
- }
-
- @Test
- fun testPositiveButton_sendsActionAuthenticated() {
- biometricView.mConfirmButton.performClick()
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_AUTHENTICATED)
- assertThat(biometricView.isAuthenticated).isTrue()
- }
-
- @Test
- fun testNegativeButton_beforeAuthentication_sendsActionButtonNegative() {
- biometricView.onDialogAnimatedIn(fingerprintWasStarted = true)
- biometricView.mNegativeButton.performClick()
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_BUTTON_NEGATIVE)
- }
-
- @Test
- fun testCancelButton_whenPendingConfirmation_sendsActionUserCanceled() {
- biometricView.setRequireConfirmation(true)
- biometricView.onAuthenticationSucceeded(BiometricAuthenticator.TYPE_FINGERPRINT)
-
- assertThat(biometricView.mNegativeButton.visibility).isEqualTo(View.GONE)
- biometricView.mCancelButton.performClick()
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_USER_CANCELED)
- }
-
- @Test
- fun testTryAgainButton_sendsActionTryAgain() {
- biometricView.mTryAgainButton.performClick()
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_BUTTON_TRY_AGAIN)
- assertThat(biometricView.mTryAgainButton.visibility).isEqualTo(View.GONE)
- assertThat(biometricView.isAuthenticating).isTrue()
- }
-
- @Test
- fun testOnErrorSendsActionError() {
- biometricView.onError(BiometricAuthenticator.TYPE_FACE, "testError")
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- verify(callback).onAction(eq(AuthBiometricView.Callback.ACTION_ERROR))
- }
-
- @Test
- fun testOnErrorShowsMessage() {
- // prevent error state from instantly returning to authenticating in the test
- biometricView.mAnimationDurationHideDialog = 10_000
-
- val message = "another error"
- biometricView.onError(BiometricAuthenticator.TYPE_FACE, message)
- TestableLooper.get(this).moveTimeForward(1000)
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticating).isFalse()
- assertThat(biometricView.isAuthenticated).isFalse()
- assertThat(biometricView.mIndicatorView.visibility).isEqualTo(View.VISIBLE)
- assertThat(biometricView.mIndicatorView.text).isEqualTo(message)
- }
-
- @Test
- fun testBackgroundClicked_sendsActionUserCanceled() {
- val view = View(mContext)
- biometricView.setBackgroundView(view)
- view.performClick()
-
- verify(callback).onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED))
- }
-
- @Test
- fun testBackgroundClicked_afterAuthenticated_neverSendsUserCanceled() {
- val view = View(mContext)
- biometricView.setBackgroundView(view)
- biometricView.onAuthenticationSucceeded(BiometricAuthenticator.TYPE_FINGERPRINT)
- waitForIdleSync()
- view.performClick()
-
- verify(callback, never())
- .onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED))
- }
-
- @Test
- fun testBackgroundClicked_whenSmallDialog_neverSendsUserCanceled() {
- biometricView.mLayoutParams = AuthDialog.LayoutParams(0, 0)
- biometricView.updateSize(AuthDialog.SIZE_SMALL)
- val view = View(mContext)
- biometricView.setBackgroundView(view)
- view.performClick()
-
- verify(callback, never()).onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED))
- }
-
- @Test
- fun testIgnoresUselessHelp() {
- biometricView.mAnimationDurationHideDialog = 10_000
- biometricView.onDialogAnimatedIn(fingerprintWasStarted = true)
- waitForIdleSync()
-
- assertThat(biometricView.isAuthenticating).isTrue()
-
- val helpText = biometricView.mIndicatorView.text
- biometricView.onHelp(BiometricAuthenticator.TYPE_FINGERPRINT, "")
- waitForIdleSync()
-
- // text should not change
- assertThat(biometricView.mIndicatorView.text).isEqualTo(helpText)
- verify(callback, never()).onAction(eq(AuthBiometricView.Callback.ACTION_ERROR))
- }
-
- @Test
- fun testRestoresState() {
- val requireConfirmation = true
- biometricView.mAnimationDurationHideDialog = 10_000
- val failureMessage = "testFailureMessage"
- biometricView.setRequireConfirmation(requireConfirmation)
- biometricView.onAuthenticationFailed(BiometricAuthenticator.TYPE_FACE, failureMessage)
- waitForIdleSync()
-
- val state = Bundle()
- biometricView.onSaveState(state)
- assertThat(biometricView.mTryAgainButton.visibility).isEqualTo(View.GONE)
- assertThat(state.getInt(AuthDialog.KEY_BIOMETRIC_TRY_AGAIN_VISIBILITY))
- .isEqualTo(View.GONE)
- assertThat(state.getInt(AuthDialog.KEY_BIOMETRIC_STATE))
- .isEqualTo(AuthBiometricView.STATE_ERROR)
- assertThat(biometricView.mIndicatorView.visibility).isEqualTo(View.VISIBLE)
- assertThat(state.getBoolean(AuthDialog.KEY_BIOMETRIC_INDICATOR_ERROR_SHOWING)).isTrue()
- assertThat(biometricView.mIndicatorView.text).isEqualTo(failureMessage)
- assertThat(state.getString(AuthDialog.KEY_BIOMETRIC_INDICATOR_STRING))
- .isEqualTo(failureMessage)
-
- // TODO: Test dialog size. Should move requireConfirmation to buildBiometricPromptBundle
-
- // Create new dialog and restore the previous state into it
- biometricView.destroyDialog()
- biometricView = createView()
- biometricView.restoreState(state)
- biometricView.mAnimationDurationHideDialog = 10_000
- biometricView.setRequireConfirmation(requireConfirmation)
- waitForIdleSync()
-
- assertThat(biometricView.mTryAgainButton.visibility).isEqualTo(View.GONE)
- assertThat(biometricView.mIndicatorView.visibility).isEqualTo(View.VISIBLE)
-
- // TODO: Test restored text. Currently cannot test this, since it gets restored only after
- // dialog size is known.
- }
-
- @Test
- fun testCredentialButton_whenDeviceCredentialAllowed() {
- biometricView.destroyDialog()
- biometricView = createView(allowDeviceCredential = true)
-
- assertThat(biometricView.mUseCredentialButton.visibility).isEqualTo(View.VISIBLE)
- assertThat(biometricView.mNegativeButton.visibility).isEqualTo(View.GONE)
-
- biometricView.mUseCredentialButton.performClick()
- waitForIdleSync()
-
- verify(callback).onAction(AuthBiometricView.Callback.ACTION_USE_DEVICE_CREDENTIAL)
- }
-
- override fun waitForIdleSync() = TestableLooper.get(this).processAllMessages()
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index d10b81c7b648..7775a05568e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -105,9 +105,6 @@ open class AuthContainerViewTest : SysuiTestCase() {
@Mock
lateinit var vibrator: VibratorHelper
- // TODO(b/278622168): remove with flag
- open val useNewBiometricPrompt = false
-
private val testScope = TestScope(StandardTestDispatcher())
private val fakeExecutor = FakeExecutor(FakeSystemClock())
private val biometricPromptRepository = FakePromptRepository()
@@ -137,7 +134,6 @@ open class AuthContainerViewTest : SysuiTestCase() {
@Before
fun setup() {
displayRepository = FakeDisplayRepository()
- featureFlags.set(Flags.BIOMETRIC_BP_STRONG, useNewBiometricPrompt)
featureFlags.set(Flags.ONE_WAY_HAPTICS_API_MIGRATION, false)
displayStateInteractor =
@@ -235,9 +231,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testActionCancel_panelInteractionDetectorDisable() {
val container = initializeFingerprintContainer()
- container.mBiometricCallback.onAction(
- AuthBiometricView.Callback.ACTION_USER_CANCELED
- )
+ container.mBiometricCallback.onUserCanceled()
waitForIdleSync()
verify(panelInteractionDetector).disable()
}
@@ -246,9 +240,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testActionAuthenticated_sendsDismissedAuthenticated() {
val container = initializeFingerprintContainer()
- container.mBiometricCallback.onAction(
- AuthBiometricView.Callback.ACTION_AUTHENTICATED
- )
+ container.mBiometricCallback.onAuthenticated()
waitForIdleSync()
verify(callback).onDismissed(
@@ -262,9 +254,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testActionUserCanceled_sendsDismissedUserCanceled() {
val container = initializeFingerprintContainer()
- container.mBiometricCallback.onAction(
- AuthBiometricView.Callback.ACTION_USER_CANCELED
- )
+ container.mBiometricCallback.onUserCanceled()
waitForIdleSync()
verify(callback).onSystemEvent(
@@ -282,9 +272,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testActionButtonNegative_sendsDismissedButtonNegative() {
val container = initializeFingerprintContainer()
- container.mBiometricCallback.onAction(
- AuthBiometricView.Callback.ACTION_BUTTON_NEGATIVE
- )
+ container.mBiometricCallback.onButtonNegative()
waitForIdleSync()
verify(callback).onDismissed(
@@ -300,9 +288,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
val container = initializeFingerprintContainer(
authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK
)
- container.mBiometricCallback.onAction(
- AuthBiometricView.Callback.ACTION_BUTTON_TRY_AGAIN
- )
+ container.mBiometricCallback.onButtonTryAgain()
waitForIdleSync()
verify(callback).onTryAgainPressed(authContainer?.requestId ?: 0L)
@@ -311,9 +297,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
@Test
fun testActionError_sendsDismissedError() {
val container = initializeFingerprintContainer()
- container.mBiometricCallback.onAction(
- AuthBiometricView.Callback.ACTION_ERROR
- )
+ container.mBiometricCallback.onError()
waitForIdleSync()
verify(callback).onDismissed(
@@ -331,9 +315,7 @@ open class AuthContainerViewTest : SysuiTestCase() {
authenticators = BiometricManager.Authenticators.BIOMETRIC_WEAK or
BiometricManager.Authenticators.DEVICE_CREDENTIAL
)
- container.mBiometricCallback.onAction(
- AuthBiometricView.Callback.ACTION_USE_DEVICE_CREDENTIAL
- )
+ container.mBiometricCallback.onUseDeviceCredential()
waitForIdleSync()
verify(callback).onDeviceCredentialPressed(authContainer?.requestId ?: 0L)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest2.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest2.kt
deleted file mode 100644
index b56d05537215..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest2.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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.biometrics
-
-import android.testing.TestableLooper
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import org.junit.runner.RunWith
-
-// TODO(b/278622168): remove with flag
-@RunWith(AndroidJUnit4::class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-@SmallTest
-class AuthContainerViewTest2 : AuthContainerViewTest() {
- override val useNewBiometricPrompt = true
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index f3ff669917ee..d0b3833a24a1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -17,7 +17,6 @@
package com.android.systemui.biometrics;
import static android.hardware.biometrics.BiometricAuthenticator.TYPE_FINGERPRINT;
-import static android.hardware.biometrics.BiometricManager.Authenticators;
import static com.google.common.truth.Truth.assertThat;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
@@ -29,7 +28,6 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -45,7 +43,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Point;
import android.hardware.biometrics.BiometricAuthenticator;
@@ -66,7 +63,6 @@ import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
-import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserManager;
@@ -91,7 +87,6 @@ import com.android.systemui.biometrics.domain.interactor.PromptSelectorInteracto
import com.android.systemui.biometrics.ui.viewmodel.CredentialViewModel;
import com.android.systemui.biometrics.ui.viewmodel.PromptViewModel;
import com.android.systemui.flags.FakeFeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.WakefulnessLifecycle;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.VibratorHelper;
@@ -203,10 +198,6 @@ public class AuthControllerTest extends SysuiTestCase {
@Before
public void setup() throws RemoteException {
- // TODO(b/278622168): remove with flag
- // AuthController simply passes this through to AuthContainerView (does not impact test)
- mFeatureFlags.set(Flags.BIOMETRIC_BP_STRONG, false);
-
mContextSpy = spy(mContext);
mExecution = new FakeExecution();
mTestableLooper = TestableLooper.get(this);
@@ -459,7 +450,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testShowInvoked_whenSystemRequested() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- verify(mDialog1).show(any(), any());
+ verify(mDialog1).show(any());
}
@Test
@@ -660,7 +651,7 @@ public class AuthControllerTest extends SysuiTestCase {
// 2) Client cancels authentication
showDialog(new int[0] /* sensorIds */, true /* credentialAllowed */);
- verify(mDialog1).show(any(), any());
+ verify(mDialog1).show(any());
final byte[] credentialAttestation = generateRandomHAT();
@@ -676,7 +667,7 @@ public class AuthControllerTest extends SysuiTestCase {
@Test
public void testShowNewDialog_beforeOldDialogDismissed_SkipsAnimations() {
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- verify(mDialog1).show(any(), any());
+ verify(mDialog1).show(any());
showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
@@ -684,59 +675,7 @@ public class AuthControllerTest extends SysuiTestCase {
verify(mDialog1).dismissWithoutCallback(eq(false) /* animate */);
// Second dialog should be shown without animation
- verify(mDialog2).show(any(), any());
- }
-
- @Test
- public void testConfigurationPersists_whenOnConfigurationChanged() {
- showDialog(new int[] {1} /* sensorIds */, false /* credentialAllowed */);
- verify(mDialog1).show(any(), any());
-
- // Return that the UI is in "showing" state
- doAnswer(invocation -> {
- Object[] args = invocation.getArguments();
- Bundle savedState = (Bundle) args[0];
- savedState.putBoolean(AuthDialog.KEY_CONTAINER_GOING_AWAY, false);
- return null; // onSaveState returns void
- }).when(mDialog1).onSaveState(any());
-
- mAuthController.onConfigurationChanged(new Configuration());
-
- ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class);
- verify(mDialog1).onSaveState(captor.capture());
-
- // Old dialog doesn't animate
- verify(mDialog1).dismissWithoutCallback(eq(false /* animate */));
-
- // Saved state is restored into new dialog
- ArgumentCaptor<Bundle> captor2 = ArgumentCaptor.forClass(Bundle.class);
- verify(mDialog2).show(any(), captor2.capture());
-
- // TODO: This should check all values we want to save/restore
- assertEquals(captor.getValue(), captor2.getValue());
- }
-
- @Test
- public void testConfigurationPersists_whenBiometricFallbackToCredential() {
- showDialog(new int[] {1} /* sensorIds */, true /* credentialAllowed */);
- verify(mDialog1).show(any(), any());
-
- // Pretend that the UI is now showing device credential UI.
- doAnswer(invocation -> {
- Object[] args = invocation.getArguments();
- Bundle savedState = (Bundle) args[0];
- savedState.putBoolean(AuthDialog.KEY_CONTAINER_GOING_AWAY, false);
- savedState.putBoolean(AuthDialog.KEY_CREDENTIAL_SHOWING, true);
- return null; // onSaveState returns void
- }).when(mDialog1).onSaveState(any());
-
- mAuthController.onConfigurationChanged(new Configuration());
-
- // Check that the new dialog was initialized to the credential UI.
- ArgumentCaptor<Bundle> captor = ArgumentCaptor.forClass(Bundle.class);
- verify(mDialog2).show(any(), captor.capture());
- assertEquals(Authenticators.DEVICE_CREDENTIAL,
- mAuthController.mLastBiometricPromptInfo.getAuthenticators());
+ verify(mDialog2).show(any());
}
@Test
@@ -1006,7 +945,7 @@ public class AuthControllerTest extends SysuiTestCase {
REQUEST_ID);
assertNull(mAuthController.mCurrentDialog);
- verify(mDialog1, never()).show(any(), any());
+ verify(mDialog1, never()).show(any());
}
private void showDialog(int[] sensorIds, boolean credentialAllowed) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
index 94244cdf271d..9f24a9f553a1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricTestExtensions.kt
@@ -16,8 +16,6 @@
package com.android.systemui.biometrics
-import android.annotation.IdRes
-import android.content.Context
import android.hardware.biometrics.BiometricManager.Authenticators
import android.hardware.biometrics.ComponentInfoInternal
import android.hardware.biometrics.PromptInfo
@@ -27,57 +25,6 @@ import android.hardware.face.FaceSensorProperties
import android.hardware.face.FaceSensorPropertiesInternal
import android.hardware.fingerprint.FingerprintSensorProperties
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal
-import android.os.Bundle
-import android.testing.ViewUtils
-import android.view.LayoutInflater
-
-/**
- * Inflate the given BiometricPrompt layout and initialize it with test parameters.
- *
- * This attaches the view so be sure to call [destroyDialog] at the end of the test.
- */
-@IdRes
-internal fun <T : AuthBiometricView> Int.asTestAuthBiometricView(
- context: Context,
- callback: AuthBiometricView.Callback,
- panelController: AuthPanelController,
- allowDeviceCredential: Boolean = false,
- savedState: Bundle? = null,
- hideDelay: Int = 0
-): T {
- val view = LayoutInflater.from(context).inflate(this, null, false) as T
- view.mAnimationDurationLong = 0
- view.mAnimationDurationShort = 0
- view.mAnimationDurationHideDialog = hideDelay
- view.setPromptInfo(buildPromptInfo(allowDeviceCredential))
- view.setCallback(callback)
- view.restoreState(savedState)
- view.setPanelController(panelController)
-
- ViewUtils.attachView(view)
-
- return view
-}
-
-private fun buildPromptInfo(allowDeviceCredential: Boolean): PromptInfo {
- val promptInfo = PromptInfo()
- promptInfo.title = "Title"
- var authenticators = Authenticators.BIOMETRIC_WEAK
- if (allowDeviceCredential) {
- authenticators = authenticators or Authenticators.DEVICE_CREDENTIAL
- } else {
- promptInfo.negativeButtonText = "Negative"
- }
- promptInfo.authenticators = authenticators
- return promptInfo
-}
-
-/** Detach the view, if needed. */
-internal fun AuthBiometricView?.destroyDialog() {
- if (this != null && isAttachedToWindow) {
- ViewUtils.detachView(this)
- }
-}
/** Create [FingerprintSensorPropertiesInternal] for a test. */
internal fun fingerprintSensorPropertiesInternal(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
index 3848aad695ab..5834e31cb591 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModelTest.kt
@@ -24,7 +24,6 @@ import android.view.MotionEvent
import androidx.test.filters.SmallTest
import com.android.internal.widget.LockPatternUtils
import com.android.systemui.SysuiTestCase
-import com.android.systemui.biometrics.AuthBiometricView
import com.android.systemui.biometrics.data.repository.FakeFingerprintPropertyRepository
import com.android.systemui.biometrics.data.repository.FakePromptRepository
import com.android.systemui.biometrics.data.repository.FakeRearDisplayStateRepository
@@ -37,6 +36,7 @@ import com.android.systemui.biometrics.faceSensorPropertiesInternal
import com.android.systemui.biometrics.fingerprintSensorPropertiesInternal
import com.android.systemui.biometrics.shared.model.BiometricModalities
import com.android.systemui.biometrics.shared.model.BiometricModality
+import com.android.systemui.biometrics.ui.binder.Spaghetti.BiometricState
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.coroutines.collectValues
import com.android.systemui.display.data.repository.FakeDisplayRepository
@@ -132,7 +132,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
}
assertThat(message).isEqualTo(PromptMessage.Empty)
assertThat(size).isEqualTo(expectedSize)
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_IDLE)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_IDLE)
val startMessage = "here we go"
viewModel.showAuthenticating(startMessage, isRetry = false)
@@ -142,7 +142,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
assertThat(authenticated?.isNotAuthenticated).isTrue()
assertThat(size).isEqualTo(expectedSize)
assertButtonsVisible(negative = expectedSize != PromptSize.SMALL)
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATING)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_AUTHENTICATING)
}
@Test
@@ -220,7 +220,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
assertThat(authenticating).isTrue()
assertThat(authenticated?.isNotAuthenticated).isTrue()
assertThat(size).isEqualTo(if (authWithSmallPrompt) PromptSize.SMALL else PromptSize.MEDIUM)
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATING)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_AUTHENTICATING)
assertButtonsVisible(negative = !authWithSmallPrompt)
val delay = 1000L
@@ -240,9 +240,9 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
assertThat(legacyState)
.isEqualTo(
if (expectConfirmation) {
- AuthBiometricView.STATE_PENDING_CONFIRMATION
+ BiometricState.STATE_PENDING_CONFIRMATION
} else {
- AuthBiometricView.STATE_AUTHENTICATED
+ BiometricState.STATE_AUTHENTICATED
}
)
assertButtonsVisible(
@@ -311,7 +311,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
assertThat(size).isEqualTo(PromptSize.MEDIUM)
assertThat(message).isEqualTo(PromptMessage.Error(errorMessage))
assertThat(messageVisible).isTrue()
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_ERROR)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_ERROR)
// temporary error should disappear after a delay
errorJob.join()
@@ -326,11 +326,11 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
assertThat(legacyState)
.isEqualTo(
if (restart) {
- AuthBiometricView.STATE_AUTHENTICATING
+ BiometricState.STATE_AUTHENTICATING
} else if (clearIconError) {
- AuthBiometricView.STATE_IDLE
+ BiometricState.STATE_IDLE
} else {
- AuthBiometricView.STATE_HELP
+ BiometricState.STATE_HELP
}
)
@@ -505,7 +505,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
assertThat(authenticating).isFalse()
assertThat(authenticated?.isAuthenticated).isTrue()
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATED)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_AUTHENTICATED)
assertThat(canTryAgain).isFalse()
}
@@ -531,7 +531,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
assertThat(authenticated?.isAuthenticated).isTrue()
if (testCase.isFaceOnly && expectConfirmation) {
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_PENDING_CONFIRMATION)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_PENDING_CONFIRMATION)
assertThat(size).isEqualTo(PromptSize.MEDIUM)
assertButtonsVisible(
@@ -543,7 +543,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
assertThat(message).isEqualTo(PromptMessage.Empty)
assertButtonsVisible()
} else {
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATED)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_AUTHENTICATED)
}
}
@@ -580,7 +580,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
assertThat(authenticating).isFalse()
assertThat(authenticated?.isAuthenticated).isTrue()
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATED)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_AUTHENTICATED)
assertThat(canTryAgain).isFalse()
}
@@ -614,7 +614,7 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
viewModel.showHelp(helpMessage)
assertThat(size).isEqualTo(PromptSize.MEDIUM)
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_HELP)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_HELP)
assertThat(message).isEqualTo(PromptMessage.Help(helpMessage))
assertThat(messageVisible).isTrue()
@@ -642,9 +642,9 @@ internal class PromptViewModelTest(private val testCase: TestCase) : SysuiTestCa
assertThat(size).isEqualTo(PromptSize.MEDIUM)
if (confirmationRequired == true) {
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_PENDING_CONFIRMATION)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_PENDING_CONFIRMATION)
} else {
- assertThat(legacyState).isEqualTo(AuthBiometricView.STATE_AUTHENTICATED)
+ assertThat(legacyState).isEqualTo(BiometricState.STATE_AUTHENTICATED)
}
assertThat(message).isEqualTo(PromptMessage.Help(helpMessage))
assertThat(messageVisible).isTrue()