Merge "Add a setting to remove UDFPS overlay enrollment UI" into tm-qpr-dev

This commit is contained in:
Ilya Matyukhin
2022-10-21 16:51:19 +00:00
committed by Android (Google) Code Review
2 changed files with 145 additions and 53 deletions

View File

@@ -21,13 +21,18 @@ import android.annotation.UiThread
import android.content.Context
import android.graphics.PixelFormat
import android.graphics.Rect
import android.hardware.biometrics.BiometricOverlayConstants
import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_BP
import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_KEYGUARD
import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_OTHER
import android.hardware.biometrics.BiometricOverlayConstants.REASON_AUTH_SETTINGS
import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_ENROLLING
import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_SENSOR
import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
import android.hardware.fingerprint.FingerprintManager
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
import android.os.Build
import android.os.RemoteException
import android.provider.Settings
import android.util.Log
import android.util.RotationUtils
import android.view.LayoutInflater
@@ -38,6 +43,7 @@ import android.view.WindowManager
import android.view.accessibility.AccessibilityManager
import android.view.accessibility.AccessibilityManager.TouchExplorationStateChangeListener
import androidx.annotation.LayoutRes
import androidx.annotation.VisibleForTesting
import com.android.keyguard.KeyguardUpdateMonitor
import com.android.systemui.R
import com.android.systemui.animation.ActivityLaunchAnimator
@@ -54,13 +60,16 @@ import com.android.systemui.util.time.SystemClock
private const val TAG = "UdfpsControllerOverlay"
@VisibleForTesting
const val SETTING_REMOVE_ENROLLMENT_UI = "udfps_overlay_remove_enrollment_ui"
/**
* Keeps track of the overlay state and UI resources associated with a single FingerprintService
* request. This state can persist across configuration changes via the [show] and [hide]
* methods.
*/
@UiThread
class UdfpsControllerOverlay(
class UdfpsControllerOverlay @JvmOverloads constructor(
private val context: Context,
fingerprintManager: FingerprintManager,
private val inflater: LayoutInflater,
@@ -82,7 +91,8 @@ class UdfpsControllerOverlay(
@ShowReason val requestReason: Int,
private val controllerCallback: IUdfpsOverlayControllerCallback,
private val onTouch: (View, MotionEvent, Boolean) -> Boolean,
private val activityLaunchAnimator: ActivityLaunchAnimator
private val activityLaunchAnimator: ActivityLaunchAnimator,
private val isDebuggable: Boolean = Build.IS_DEBUGGABLE
) {
/** The view, when [isShowing], or null. */
var overlayView: UdfpsView? = null
@@ -102,18 +112,19 @@ class UdfpsControllerOverlay(
gravity = android.view.Gravity.TOP or android.view.Gravity.LEFT
layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
flags = (Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS or
WindowManager.LayoutParams.FLAG_SPLIT_TOUCH)
WindowManager.LayoutParams.FLAG_SPLIT_TOUCH)
privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
// Avoid announcing window title.
accessibilityTitle = " "
}
/** A helper if the [requestReason] was due to enrollment. */
val enrollHelper: UdfpsEnrollHelper? = if (requestReason.isEnrollmentReason()) {
UdfpsEnrollHelper(context, fingerprintManager, requestReason)
} else {
null
}
val enrollHelper: UdfpsEnrollHelper? =
if (requestReason.isEnrollmentReason() && !shouldRemoveEnrollmentUi()) {
UdfpsEnrollHelper(context, fingerprintManager, requestReason)
} else {
null
}
/** If the overlay is currently showing. */
val isShowing: Boolean
@@ -129,6 +140,17 @@ class UdfpsControllerOverlay(
private var touchExplorationEnabled = false
private fun shouldRemoveEnrollmentUi(): Boolean {
if (isDebuggable) {
return Settings.Global.getInt(
context.contentResolver,
SETTING_REMOVE_ENROLLMENT_UI,
0 /* def */
) != 0
}
return false
}
/** Show the overlay or return false and do nothing if it is already showing. */
@SuppressLint("ClickableViewAccessibility")
fun show(controller: UdfpsController, params: UdfpsOverlayParams): Boolean {
@@ -183,7 +205,18 @@ class UdfpsControllerOverlay(
view: UdfpsView,
controller: UdfpsController
): UdfpsAnimationViewController<*>? {
return when (requestReason) {
val isEnrollment = when (requestReason) {
REASON_ENROLL_FIND_SENSOR, REASON_ENROLL_ENROLLING -> true
else -> false
}
val filteredRequestReason = if (isEnrollment && shouldRemoveEnrollmentUi()) {
REASON_AUTH_OTHER
} else {
requestReason
}
return when (filteredRequestReason) {
REASON_ENROLL_FIND_SENSOR,
REASON_ENROLL_ENROLLING -> {
UdfpsEnrollViewController(
@@ -198,7 +231,7 @@ class UdfpsControllerOverlay(
overlayParams.scaleFactor
)
}
BiometricOverlayConstants.REASON_AUTH_KEYGUARD -> {
REASON_AUTH_KEYGUARD -> {
UdfpsKeyguardViewController(
view.addUdfpsView(R.layout.udfps_keyguard_view),
statusBarStateController,
@@ -216,7 +249,7 @@ class UdfpsControllerOverlay(
activityLaunchAnimator
)
}
BiometricOverlayConstants.REASON_AUTH_BP -> {
REASON_AUTH_BP -> {
// note: empty controller, currently shows no visual affordance
UdfpsBpViewController(
view.addUdfpsView(R.layout.udfps_bp_view),
@@ -226,8 +259,8 @@ class UdfpsControllerOverlay(
dumpManager
)
}
BiometricOverlayConstants.REASON_AUTH_OTHER,
BiometricOverlayConstants.REASON_AUTH_SETTINGS -> {
REASON_AUTH_OTHER,
REASON_AUTH_SETTINGS -> {
UdfpsFpmOtherViewController(
view.addUdfpsView(R.layout.udfps_fpm_other_view),
statusBarStateController,
@@ -440,4 +473,4 @@ private fun Int.isEnrollmentReason() =
private fun Int.isImportantForAccessibility() =
this == REASON_ENROLL_FIND_SENSOR ||
this == REASON_ENROLL_ENROLLING ||
this == BiometricOverlayConstants.REASON_AUTH_BP
this == REASON_AUTH_BP

View File

@@ -26,6 +26,7 @@ import android.hardware.biometrics.BiometricOverlayConstants.REASON_ENROLL_FIND_
import android.hardware.biometrics.BiometricOverlayConstants.ShowReason
import android.hardware.fingerprint.FingerprintManager
import android.hardware.fingerprint.IUdfpsOverlayControllerCallback
import android.provider.Settings
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import android.view.LayoutInflater
@@ -124,14 +125,18 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
whenever(udfpsEnrollView.context).thenReturn(context)
}
private fun withReason(@ShowReason reason: Int, block: () -> Unit) {
private fun withReason(
@ShowReason reason: Int,
isDebuggable: Boolean = false,
block: () -> Unit
) {
controllerOverlay = UdfpsControllerOverlay(
context, fingerprintManager, inflater, windowManager, accessibilityManager,
statusBarStateController, shadeExpansionStateManager, statusBarKeyguardViewManager,
keyguardUpdateMonitor, dialogManager, dumpManager, transitionController,
configurationController, systemClock, keyguardStateController,
unlockedScreenOffAnimationController, udfpsDisplayMode, REQUEST_ID, reason,
controllerCallback, onTouch, activityLaunchAnimator
controllerCallback, onTouch, activityLaunchAnimator, isDebuggable
)
block()
}
@@ -150,11 +155,29 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
showUdfpsOverlay(isEnrollUseCase = true)
}
@Test
fun showUdfpsOverlay_locate_withEnrollmentUiRemoved() {
Settings.Global.putInt(mContext.contentResolver, SETTING_REMOVE_ENROLLMENT_UI, 1)
withReason(REASON_ENROLL_FIND_SENSOR, isDebuggable = true) {
showUdfpsOverlay(isEnrollUseCase = false)
}
Settings.Global.putInt(mContext.contentResolver, SETTING_REMOVE_ENROLLMENT_UI, 0)
}
@Test
fun showUdfpsOverlay_enroll() = withReason(REASON_ENROLL_ENROLLING) {
showUdfpsOverlay(isEnrollUseCase = true)
}
@Test
fun showUdfpsOverlay_enroll_withEnrollmentUiRemoved() {
Settings.Global.putInt(mContext.contentResolver, SETTING_REMOVE_ENROLLMENT_UI, 1)
withReason(REASON_ENROLL_ENROLLING, isDebuggable = true) {
showUdfpsOverlay(isEnrollUseCase = false)
}
Settings.Global.putInt(mContext.contentResolver, SETTING_REMOVE_ENROLLMENT_UI, 0)
}
@Test
fun showUdfpsOverlay_other() = withReason(REASON_AUTH_OTHER) { showUdfpsOverlay() }
@@ -372,21 +395,33 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
context.resources.getStringArray(R.array.udfps_accessibility_touch_hints)
val rotation = Surface.ROTATION_0
// touch at 0 degrees
assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, 0.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
.isEqualTo(touchHints[0])
assertThat(
controllerOverlay.onTouchOutsideOfSensorAreaImpl(
0.0f /* x */, 0.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation
)
).isEqualTo(touchHints[0])
// touch at 90 degrees
assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, -1.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
.isEqualTo(touchHints[1])
assertThat(
controllerOverlay.onTouchOutsideOfSensorAreaImpl(
0.0f /* x */, -1.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation
)
).isEqualTo(touchHints[1])
// touch at 180 degrees
assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(-1.0f /* x */, 0.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
.isEqualTo(touchHints[2])
assertThat(
controllerOverlay.onTouchOutsideOfSensorAreaImpl(
-1.0f /* x */, 0.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation
)
).isEqualTo(touchHints[2])
// touch at 270 degrees
assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, 1.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
.isEqualTo(touchHints[3])
assertThat(
controllerOverlay.onTouchOutsideOfSensorAreaImpl(
0.0f /* x */, 1.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation
)
).isEqualTo(touchHints[3])
}
fun testTouchOutsideAreaNoRotation90Degrees() = withReason(REASON_ENROLL_ENROLLING) {
@@ -394,21 +429,33 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
context.resources.getStringArray(R.array.udfps_accessibility_touch_hints)
val rotation = Surface.ROTATION_90
// touch at 0 degrees -> 90 degrees
assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, 0.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
.isEqualTo(touchHints[1])
assertThat(
controllerOverlay.onTouchOutsideOfSensorAreaImpl(
0.0f /* x */, 0.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation
)
).isEqualTo(touchHints[1])
// touch at 90 degrees -> 180 degrees
assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, -1.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
.isEqualTo(touchHints[2])
assertThat(
controllerOverlay.onTouchOutsideOfSensorAreaImpl(
0.0f /* x */, -1.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation
)
).isEqualTo(touchHints[2])
// touch at 180 degrees -> 270 degrees
assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(-1.0f /* x */, 0.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
.isEqualTo(touchHints[3])
assertThat(
controllerOverlay.onTouchOutsideOfSensorAreaImpl(
-1.0f /* x */, 0.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation
)
).isEqualTo(touchHints[3])
// touch at 270 degrees -> 0 degrees
assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, 1.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
.isEqualTo(touchHints[0])
assertThat(
controllerOverlay.onTouchOutsideOfSensorAreaImpl(
0.0f /* x */, 1.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation
)
).isEqualTo(touchHints[0])
}
fun testTouchOutsideAreaNoRotation270Degrees() = withReason(REASON_ENROLL_ENROLLING) {
@@ -416,21 +463,33 @@ class UdfpsControllerOverlayTest : SysuiTestCase() {
context.resources.getStringArray(R.array.udfps_accessibility_touch_hints)
val rotation = Surface.ROTATION_270
// touch at 0 degrees -> 270 degrees
assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, 0.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
.isEqualTo(touchHints[3])
assertThat(
controllerOverlay.onTouchOutsideOfSensorAreaImpl(
0.0f /* x */, 0.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation
)
).isEqualTo(touchHints[3])
// touch at 90 degrees -> 0 degrees
assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, -1.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
.isEqualTo(touchHints[0])
assertThat(
controllerOverlay.onTouchOutsideOfSensorAreaImpl(
0.0f /* x */, -1.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation
)
).isEqualTo(touchHints[0])
// touch at 180 degrees -> 90 degrees
assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(-1.0f /* x */, 0.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
.isEqualTo(touchHints[1])
assertThat(
controllerOverlay.onTouchOutsideOfSensorAreaImpl(
-1.0f /* x */, 0.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation
)
).isEqualTo(touchHints[1])
// touch at 270 degrees -> 180 degrees
assertThat(controllerOverlay.onTouchOutsideOfSensorAreaImpl(0.0f /* x */, 1.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation))
.isEqualTo(touchHints[2])
assertThat(
controllerOverlay.onTouchOutsideOfSensorAreaImpl(
0.0f /* x */, 1.0f /* y */,
0.0f /* sensorX */, 0.0f /* sensorY */, rotation
)
).isEqualTo(touchHints[2])
}
}