Merge changes from topics "face_auth_ripple", "udfps_falsing" into sc-dev
* changes: Add falsing checks to udfps affordance Support face auth ripple animation
This commit is contained in:
committed by
Android (Google) Code Review
commit
9a5967ffef
@@ -100,4 +100,12 @@
|
||||
android:ellipsize="marquee"
|
||||
android:focusable="true" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.android.systemui.biometrics.AuthRippleView
|
||||
android:id="@+id/auth_ripple"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:importantForAccessibility="no"
|
||||
sysui:ignoreRightInset="true"
|
||||
/>
|
||||
</com.android.systemui.statusbar.phone.NotificationShadeWindowView>
|
||||
|
||||
@@ -642,4 +642,11 @@
|
||||
|
||||
<!-- Whether to use window background blur for the volume dialog. -->
|
||||
<bool name="config_volumeDialogUseBackgroundBlur">false</bool>
|
||||
|
||||
<!-- The properties of the face auth camera in pixels -->
|
||||
<integer-array name="config_face_auth_props">
|
||||
<!-- sensorLocationX -->
|
||||
<!-- sensorLocationY -->
|
||||
<!--sensorRadius -->
|
||||
</integer-array>
|
||||
</resources>
|
||||
|
||||
@@ -18,11 +18,12 @@ package com.android.keyguard;
|
||||
|
||||
import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
|
||||
|
||||
import static com.android.systemui.classifier.Classifier.DISABLED_UDFPS_AFFORDANCE;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.InsetDrawable;
|
||||
import android.hardware.biometrics.BiometricSourceType;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
@@ -33,7 +34,9 @@ import com.android.systemui.Dumpable;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.biometrics.AuthController;
|
||||
import com.android.systemui.dagger.SysUISingleton;
|
||||
import com.android.systemui.plugins.FalsingManager;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.ViewController;
|
||||
|
||||
@@ -53,14 +56,16 @@ public class DisabledUdfpsController extends ViewController<DisabledUdfpsView> i
|
||||
@NonNull private final KeyguardViewController mKeyguardViewController;
|
||||
@NonNull private final StatusBarStateController mStatusBarStateController;
|
||||
@NonNull private final KeyguardStateController mKeyguardStateController;
|
||||
@NonNull private final FalsingManager mFalsingManager;
|
||||
@NonNull private final Drawable mButton;
|
||||
@NonNull private final Drawable mUnlockIcon;
|
||||
|
||||
private boolean mIsDozing;
|
||||
private boolean mIsBouncerShowing;
|
||||
private boolean mIsKeyguardShowing;
|
||||
private boolean mRunningFPS;
|
||||
private boolean mCanDismissLockScreen;
|
||||
private boolean mQsExpanded;
|
||||
private int mStatusBarState;
|
||||
|
||||
private boolean mShowButton;
|
||||
private boolean mShowUnlockIcon;
|
||||
@@ -71,16 +76,19 @@ public class DisabledUdfpsController extends ViewController<DisabledUdfpsView> i
|
||||
@NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
|
||||
@NonNull AuthController authController,
|
||||
@NonNull KeyguardViewController keyguardViewController,
|
||||
@NonNull KeyguardStateController keyguardStateController
|
||||
@NonNull KeyguardStateController keyguardStateController,
|
||||
@NonNull FalsingManager falsingManager
|
||||
) {
|
||||
super(view);
|
||||
mView.setOnTouchListener(mOnTouchListener);
|
||||
mView.setOnClickListener(v -> onAffordanceClick());
|
||||
mView.setOnLongClickListener(v -> onAffordanceClick());
|
||||
mView.setSensorProperties(authController.getUdfpsProps().get(0));
|
||||
|
||||
mStatusBarStateController = statusBarStateController;
|
||||
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
||||
mKeyguardViewController = keyguardViewController;
|
||||
mKeyguardStateController = keyguardStateController;
|
||||
mFalsingManager = falsingManager;
|
||||
|
||||
final Context context = view.getContext();
|
||||
mButton = context.getResources().getDrawable(
|
||||
@@ -94,10 +102,10 @@ public class DisabledUdfpsController extends ViewController<DisabledUdfpsView> i
|
||||
@Override
|
||||
protected void onViewAttached() {
|
||||
mIsBouncerShowing = mKeyguardViewController.isBouncerShowing();
|
||||
mIsKeyguardShowing = mKeyguardStateController.isShowing();
|
||||
mIsDozing = mStatusBarStateController.isDozing();
|
||||
mRunningFPS = mKeyguardUpdateMonitor.isFingerprintDetectionRunning();
|
||||
mCanDismissLockScreen = mKeyguardStateController.canDismissLockScreen();
|
||||
mStatusBarState = mStatusBarStateController.getState();
|
||||
mUnlockIcon.setTint(Utils.getColorAttrDefaultColor(mView.getContext(),
|
||||
R.attr.wallpaperTextColorAccent));
|
||||
updateVisibility();
|
||||
@@ -114,6 +122,15 @@ public class DisabledUdfpsController extends ViewController<DisabledUdfpsView> i
|
||||
mKeyguardStateController.removeCallback(mKeyguardStateCallback);
|
||||
}
|
||||
|
||||
private boolean onAffordanceClick() {
|
||||
if (mFalsingManager.isFalseTouch(DISABLED_UDFPS_AFFORDANCE)) {
|
||||
return false;
|
||||
}
|
||||
mView.setVisibility(View.INVISIBLE);
|
||||
mKeyguardViewController.showBouncer(/* scrim */ true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call when this controller is no longer needed. This will remove the view from its parent.
|
||||
*/
|
||||
@@ -123,6 +140,14 @@ public class DisabledUdfpsController extends ViewController<DisabledUdfpsView> i
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether qs is expanded. When QS is expanded, don't show a DisabledUdfps affordance.
|
||||
*/
|
||||
public void setQsExpanded(boolean expanded) {
|
||||
mQsExpanded = expanded;
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
private void updateVisibility() {
|
||||
mShowButton = !mCanDismissLockScreen && !mRunningFPS && isLockScreen();
|
||||
mShowUnlockIcon = mCanDismissLockScreen && isLockScreen();
|
||||
@@ -139,7 +164,10 @@ public class DisabledUdfpsController extends ViewController<DisabledUdfpsView> i
|
||||
}
|
||||
|
||||
private boolean isLockScreen() {
|
||||
return mIsKeyguardShowing && !mIsDozing && !mIsBouncerShowing;
|
||||
return !mIsDozing
|
||||
&& !mIsBouncerShowing
|
||||
&& !mQsExpanded
|
||||
&& mStatusBarState == StatusBarState.KEYGUARD;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -148,20 +176,13 @@ public class DisabledUdfpsController extends ViewController<DisabledUdfpsView> i
|
||||
pw.println(" mShowBouncerButton: " + mShowButton);
|
||||
pw.println(" mShowUnlockIcon: " + mShowUnlockIcon);
|
||||
pw.println(" mIsDozing: " + mIsDozing);
|
||||
pw.println(" mIsKeyguardShowing: " + mIsKeyguardShowing);
|
||||
pw.println(" mIsBouncerShowing: " + mIsBouncerShowing);
|
||||
pw.println(" mRunningFPS: " + mRunningFPS);
|
||||
pw.println(" mCanDismissLockScreen: " + mCanDismissLockScreen);
|
||||
pw.println(" mStatusBarState: " + StatusBarState.toShortString(mStatusBarState));
|
||||
pw.println(" mQsExpanded: " + mQsExpanded);
|
||||
}
|
||||
|
||||
private final View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
mKeyguardViewController.showBouncer(/* scrim */ true);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private StatusBarStateController.StateListener mStatusBarStateListener =
|
||||
new StatusBarStateController.StateListener() {
|
||||
@Override
|
||||
@@ -169,6 +190,12 @@ public class DisabledUdfpsController extends ViewController<DisabledUdfpsView> i
|
||||
mIsDozing = isDozing;
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStateChanged(int statusBarState) {
|
||||
mStatusBarState = statusBarState;
|
||||
updateVisibility();
|
||||
}
|
||||
};
|
||||
|
||||
private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
|
||||
@@ -192,22 +219,10 @@ public class DisabledUdfpsController extends ViewController<DisabledUdfpsView> i
|
||||
|
||||
private final KeyguardStateController.Callback mKeyguardStateCallback =
|
||||
new KeyguardStateController.Callback() {
|
||||
@Override
|
||||
public void onKeyguardShowingChanged() {
|
||||
updateIsKeyguardShowing();
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnlockedChanged() {
|
||||
updateIsKeyguardShowing();
|
||||
mCanDismissLockScreen = mKeyguardStateController.canDismissLockScreen();
|
||||
updateVisibility();
|
||||
}
|
||||
|
||||
private void updateIsKeyguardShowing() {
|
||||
mIsKeyguardShowing = mKeyguardStateController.isShowing()
|
||||
&& !mKeyguardStateController.isKeyguardGoingAway();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.RectF;
|
||||
import android.hardware.biometrics.BiometricConstants;
|
||||
import android.hardware.biometrics.BiometricPrompt;
|
||||
@@ -82,6 +83,7 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
|
||||
@Nullable private final List<FingerprintSensorPropertiesInternal> mFpProps;
|
||||
@Nullable private final List<FaceSensorPropertiesInternal> mFaceProps;
|
||||
@Nullable private final List<FingerprintSensorPropertiesInternal> mUdfpsProps;
|
||||
@Nullable private final PointF mFaceAuthSensorLocation;
|
||||
|
||||
// TODO: These should just be saved from onSaveState
|
||||
private SomeArgs mCurrentDialogArgs;
|
||||
@@ -261,10 +263,34 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
|
||||
}
|
||||
|
||||
/**
|
||||
* @return where the UDFPS exists on the screen in pixels.
|
||||
* @return where the UDFPS exists on the screen in pixels in portrait mode.
|
||||
*/
|
||||
public RectF getUdfpsRegion() {
|
||||
return mUdfpsController == null ? null : mUdfpsController.getSensorLocation();
|
||||
return mUdfpsController == null
|
||||
? null
|
||||
: mUdfpsController.getSensorLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return where the UDFPS exists on the screen in pixels in portrait mode.
|
||||
*/
|
||||
public PointF getUdfpsSensorLocation() {
|
||||
if (mUdfpsController == null) {
|
||||
return null;
|
||||
}
|
||||
return new PointF(mUdfpsController.getSensorLocation().centerX(),
|
||||
mUdfpsController.getSensorLocation().centerY());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return where the face authentication sensor exists relative to the screen in pixels in
|
||||
* portrait mode.
|
||||
*/
|
||||
public PointF getFaceAuthSensorLocation() {
|
||||
if (mFaceProps == null || mFaceAuthSensorLocation == null) {
|
||||
return null;
|
||||
}
|
||||
return new PointF(mFaceAuthSensorLocation.x, mFaceAuthSensorLocation.y);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,6 +365,15 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks,
|
||||
}
|
||||
}
|
||||
mUdfpsProps = !udfpsProps.isEmpty() ? udfpsProps : null;
|
||||
int[] faceAuthLocation = context.getResources().getIntArray(
|
||||
com.android.systemui.R.array.config_face_auth_props);
|
||||
if (faceAuthLocation == null || faceAuthLocation.length < 2) {
|
||||
mFaceAuthSensorLocation = null;
|
||||
} else {
|
||||
mFaceAuthSensorLocation = new PointF(
|
||||
(float) faceAuthLocation[0],
|
||||
(float) faceAuthLocation[1]);
|
||||
}
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
|
||||
|
||||
@@ -17,17 +17,19 @@
|
||||
package com.android.systemui.biometrics
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.PointF
|
||||
import android.hardware.biometrics.BiometricSourceType
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import com.android.internal.annotations.VisibleForTesting
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.keyguard.KeyguardUpdateMonitor
|
||||
import com.android.keyguard.KeyguardUpdateMonitorCallback
|
||||
import com.android.settingslib.Utils
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.statusbar.NotificationShadeWindowController
|
||||
import com.android.systemui.statusbar.commandline.Command
|
||||
import com.android.systemui.statusbar.commandline.CommandRegistry
|
||||
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController
|
||||
import com.android.systemui.util.ViewController
|
||||
import java.io.PrintWriter
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -35,30 +37,82 @@ import javax.inject.Inject
|
||||
* Controls the ripple effect that shows when authentication is successful.
|
||||
* The ripple uses the accent color of the current theme.
|
||||
*/
|
||||
@SysUISingleton
|
||||
@StatusBarScope
|
||||
class AuthRippleController @Inject constructor(
|
||||
commandRegistry: CommandRegistry,
|
||||
configurationController: ConfigurationController,
|
||||
private val context: Context,
|
||||
private val keyguardUpdateMonitor: KeyguardUpdateMonitor
|
||||
) {
|
||||
@VisibleForTesting
|
||||
var rippleView: AuthRippleView = AuthRippleView(context, attrs = null)
|
||||
private val sysuiContext: Context,
|
||||
private val authController: AuthController,
|
||||
private val configurationController: ConfigurationController,
|
||||
private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
|
||||
private val commandRegistry: CommandRegistry,
|
||||
private val notificationShadeWindowController: NotificationShadeWindowController,
|
||||
rippleView: AuthRippleView?
|
||||
) : ViewController<AuthRippleView>(rippleView) {
|
||||
private var fingerprintSensorLocation: PointF? = null
|
||||
private var faceSensorLocation: PointF? = null
|
||||
|
||||
val keyguardUpdateMonitorCallback = object : KeyguardUpdateMonitorCallback() {
|
||||
override fun onBiometricAuthenticated(
|
||||
userId: Int,
|
||||
biometricSourceType: BiometricSourceType?,
|
||||
isStrongBiometric: Boolean
|
||||
) {
|
||||
if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
|
||||
rippleView.startRipple()
|
||||
}
|
||||
@VisibleForTesting
|
||||
public override fun onViewAttached() {
|
||||
updateRippleColor()
|
||||
updateSensorLocation()
|
||||
configurationController.addCallback(configurationChangedListener)
|
||||
keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
|
||||
commandRegistry.registerCommand("auth-ripple") { AuthRippleCommand() }
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public override fun onViewDetached() {
|
||||
keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
|
||||
configurationController.removeCallback(configurationChangedListener)
|
||||
commandRegistry.unregisterCommand("auth-ripple")
|
||||
|
||||
notificationShadeWindowController.setForcePluginOpen(false, this)
|
||||
}
|
||||
|
||||
private fun showRipple(biometricSourceType: BiometricSourceType?) {
|
||||
if (biometricSourceType == BiometricSourceType.FINGERPRINT &&
|
||||
fingerprintSensorLocation != null) {
|
||||
mView.setSensorLocation(fingerprintSensorLocation!!)
|
||||
showRipple()
|
||||
} else if (biometricSourceType == BiometricSourceType.FACE &&
|
||||
faceSensorLocation != null) {
|
||||
mView.setSensorLocation(faceSensorLocation!!)
|
||||
showRipple()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
val configurationChangedListener = object : ConfigurationController.ConfigurationListener {
|
||||
private fun showRipple() {
|
||||
notificationShadeWindowController.setForcePluginOpen(true, this)
|
||||
mView.startRipple(Runnable {
|
||||
notificationShadeWindowController.setForcePluginOpen(false, this)
|
||||
})
|
||||
}
|
||||
|
||||
private fun updateSensorLocation() {
|
||||
fingerprintSensorLocation = authController.udfpsSensorLocation
|
||||
faceSensorLocation = authController.faceAuthSensorLocation
|
||||
}
|
||||
|
||||
private fun updateRippleColor() {
|
||||
mView.setColor(
|
||||
Utils.getColorAttr(sysuiContext, android.R.attr.colorAccent).defaultColor)
|
||||
}
|
||||
|
||||
val keyguardUpdateMonitorCallback =
|
||||
object : KeyguardUpdateMonitorCallback() {
|
||||
override fun onBiometricAuthenticated(
|
||||
userId: Int,
|
||||
biometricSourceType: BiometricSourceType?,
|
||||
isStrongBiometric: Boolean
|
||||
) {
|
||||
showRipple(biometricSourceType)
|
||||
}
|
||||
}
|
||||
|
||||
val configurationChangedListener =
|
||||
object : ConfigurationController.ConfigurationListener {
|
||||
override fun onConfigChanged(newConfig: Configuration?) {
|
||||
updateSensorLocation()
|
||||
}
|
||||
override fun onUiModeChanged() {
|
||||
updateRippleColor()
|
||||
}
|
||||
@@ -68,43 +122,50 @@ class AuthRippleController @Inject constructor(
|
||||
override fun onOverlayChanged() {
|
||||
updateRippleColor()
|
||||
}
|
||||
}
|
||||
configurationController.addCallback(configurationChangedListener)
|
||||
|
||||
commandRegistry.registerCommand("auth-ripple") { AuthRippleCommand() }
|
||||
}
|
||||
|
||||
fun setSensorLocation(x: Float, y: Float) {
|
||||
rippleView.setSensorLocation(x, y)
|
||||
}
|
||||
|
||||
fun setViewHost(viewHost: View) {
|
||||
// Add the ripple view to its host layout
|
||||
viewHost.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
|
||||
override fun onViewDetachedFromWindow(view: View?) {}
|
||||
|
||||
override fun onViewAttachedToWindow(view: View?) {
|
||||
(viewHost as ViewGroup).addView(rippleView)
|
||||
keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
|
||||
viewHost.removeOnAttachStateChangeListener(this)
|
||||
}
|
||||
})
|
||||
|
||||
updateRippleColor()
|
||||
}
|
||||
|
||||
private fun updateRippleColor() {
|
||||
rippleView.setColor(
|
||||
Utils.getColorAttr(context, android.R.attr.colorAccent).defaultColor)
|
||||
}
|
||||
|
||||
inner class AuthRippleCommand : Command {
|
||||
override fun execute(pw: PrintWriter, args: List<String>) {
|
||||
rippleView.startRipple()
|
||||
if (args.isEmpty()) {
|
||||
invalidCommand(pw)
|
||||
} else {
|
||||
when (args[0]) {
|
||||
"fingerprint" -> {
|
||||
pw.println("fingerprint ripple sensorLocation=$fingerprintSensorLocation")
|
||||
showRipple(BiometricSourceType.FINGERPRINT)
|
||||
}
|
||||
"face" -> {
|
||||
pw.println("face ripple sensorLocation=$faceSensorLocation")
|
||||
showRipple(BiometricSourceType.FACE)
|
||||
}
|
||||
"custom" -> {
|
||||
if (args.size != 3 ||
|
||||
args[1].toFloatOrNull() == null ||
|
||||
args[2].toFloatOrNull() == null) {
|
||||
invalidCommand(pw)
|
||||
return
|
||||
}
|
||||
pw.println("custom ripple sensorLocation=" + args[1].toFloat() + ", " +
|
||||
args[2].toFloat())
|
||||
mView.setSensorLocation(PointF(args[1].toFloat(), args[2].toFloat()))
|
||||
showRipple()
|
||||
}
|
||||
else -> invalidCommand(pw)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun help(pw: PrintWriter) {
|
||||
pw.println("Usage: adb shell cmd statusbar auth-ripple")
|
||||
pw.println("Usage: adb shell cmd statusbar auth-ripple <command>")
|
||||
pw.println("Available commands:")
|
||||
pw.println(" fingerprint")
|
||||
pw.println(" face")
|
||||
pw.println(" custom <x-location: int> <y-location: int>")
|
||||
}
|
||||
|
||||
fun invalidCommand(pw: PrintWriter) {
|
||||
pw.println("invalid command")
|
||||
help(pw)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package com.android.systemui.biometrics
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
@@ -24,9 +25,11 @@ import android.graphics.Paint
|
||||
import android.graphics.PointF
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.view.animation.PathInterpolator
|
||||
import com.android.internal.graphics.ColorUtils
|
||||
import com.android.systemui.statusbar.charging.RippleShader
|
||||
|
||||
private const val RIPPLE_ANIMATION_DURATION: Long = 950
|
||||
private const val RIPPLE_ANIMATION_DURATION: Long = 1533
|
||||
private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f
|
||||
|
||||
/**
|
||||
@@ -36,42 +39,64 @@ private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f
|
||||
class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
|
||||
private var rippleInProgress: Boolean = false
|
||||
private val rippleShader = RippleShader()
|
||||
private val defaultColor: Int = 0xffffffff.toInt()
|
||||
private val ripplePaint = Paint()
|
||||
|
||||
init {
|
||||
rippleShader.color = defaultColor
|
||||
rippleShader.color = 0xffffffff.toInt() // default color
|
||||
rippleShader.progress = 0f
|
||||
rippleShader.sparkleStrength = RIPPLE_SPARKLE_STRENGTH
|
||||
ripplePaint.shader = rippleShader
|
||||
visibility = View.GONE
|
||||
visibility = GONE
|
||||
}
|
||||
|
||||
fun setSensorLocation(x: Float, y: Float) {
|
||||
rippleShader.origin = PointF(x, y)
|
||||
rippleShader.radius = maxOf(x, y, width - x, height - y).toFloat()
|
||||
fun setSensorLocation(location: PointF) {
|
||||
rippleShader.origin = location
|
||||
rippleShader.radius = maxOf(location.x, location.y, width - location.x, height - location.y)
|
||||
.toFloat()
|
||||
}
|
||||
|
||||
fun startRipple() {
|
||||
fun startRipple(onAnimationEnd: Runnable?) {
|
||||
if (rippleInProgress) {
|
||||
return // Ignore if ripple effect is already playing
|
||||
}
|
||||
|
||||
val animator = ValueAnimator.ofFloat(0f, 1f)
|
||||
animator.interpolator = PathInterpolator(0.4f, 0f, 0f, 1f)
|
||||
animator.duration = RIPPLE_ANIMATION_DURATION
|
||||
animator.addUpdateListener { animator ->
|
||||
val now = animator.currentPlayTime
|
||||
rippleShader.progress = animator.animatedValue as Float
|
||||
rippleShader.time = now.toFloat()
|
||||
rippleShader.distortionStrength = 1 - rippleShader.progress
|
||||
invalidate()
|
||||
}
|
||||
animator.addListener(object : AnimatorListenerAdapter() {
|
||||
val alphaInAnimator = ValueAnimator.ofInt(0, 127)
|
||||
alphaInAnimator.duration = 167
|
||||
alphaInAnimator.addUpdateListener { alphaInAnimator ->
|
||||
rippleShader.color = ColorUtils.setAlphaComponent(rippleShader.color,
|
||||
alphaInAnimator.animatedValue as Int)
|
||||
invalidate()
|
||||
}
|
||||
val alphaOutAnimator = ValueAnimator.ofInt(127, 0)
|
||||
alphaOutAnimator.startDelay = 417
|
||||
alphaOutAnimator.duration = 1116
|
||||
alphaOutAnimator.addUpdateListener { alphaOutAnimator ->
|
||||
rippleShader.color = ColorUtils.setAlphaComponent(rippleShader.color,
|
||||
alphaOutAnimator.animatedValue as Int)
|
||||
invalidate()
|
||||
}
|
||||
|
||||
val animatorSet = AnimatorSet()
|
||||
animatorSet.playTogether(animator, alphaInAnimator, alphaOutAnimator)
|
||||
animatorSet.addListener(object : AnimatorListenerAdapter() {
|
||||
override fun onAnimationEnd(animation: Animator?) {
|
||||
onAnimationEnd?.run()
|
||||
rippleInProgress = false
|
||||
visibility = View.GONE
|
||||
visibility = GONE
|
||||
}
|
||||
})
|
||||
animator.start()
|
||||
visibility = View.VISIBLE
|
||||
animatorSet.start()
|
||||
visibility = VISIBLE
|
||||
rippleInProgress = true
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ import android.graphics.RectF;
|
||||
import com.android.systemui.Dumpable;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.systemui.util.ViewController;
|
||||
|
||||
@@ -47,7 +46,6 @@ abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
|
||||
@NonNull final DumpManager mDumpManger;
|
||||
|
||||
private boolean mNotificationShadeExpanded;
|
||||
private int mStatusBarState;
|
||||
|
||||
protected UdfpsAnimationViewController(
|
||||
T view,
|
||||
@@ -86,7 +84,6 @@ abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView>
|
||||
|
||||
@Override
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println("mStatusBarState=" + StatusBarState.toShortString(mStatusBarState));
|
||||
pw.println("mNotificationShadeExpanded=" + mNotificationShadeExpanded);
|
||||
pw.println("shouldPauseAuth()=" + shouldPauseAuth());
|
||||
pw.println("isPauseAuth=" + mView.isPauseAuth());
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.systemui.biometrics;
|
||||
|
||||
import static com.android.internal.util.Preconditions.checkArgument;
|
||||
import static com.android.internal.util.Preconditions.checkNotNull;
|
||||
import static com.android.systemui.classifier.Classifier.UDFPS_AUTHENTICATION;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
@@ -53,6 +54,7 @@ import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.doze.DozeReceiver;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||
import com.android.systemui.plugins.FalsingManager;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
|
||||
@@ -89,9 +91,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
|
||||
@NonNull private final StatusBarStateController mStatusBarStateController;
|
||||
@NonNull private final StatusBarKeyguardViewManager mKeyguardViewManager;
|
||||
@NonNull private final DumpManager mDumpManager;
|
||||
@NonNull private final AuthRippleController mAuthRippleController;
|
||||
@NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
@NonNull private final KeyguardViewMediator mKeyguardViewMediator;
|
||||
@NonNull private FalsingManager mFalsingManager;
|
||||
// Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
|
||||
// sensors, this, in addition to a lot of the code here, will be updated.
|
||||
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
|
||||
@@ -292,6 +294,8 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
|
||||
Log.v(TAG, "onTouch | finger up");
|
||||
onFingerUp();
|
||||
}
|
||||
mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -311,9 +315,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
|
||||
@NonNull StatusBar statusBar,
|
||||
@NonNull StatusBarKeyguardViewManager statusBarKeyguardViewManager,
|
||||
@NonNull DumpManager dumpManager,
|
||||
@NonNull AuthRippleController authRippleController,
|
||||
@NonNull KeyguardUpdateMonitor keyguardUpdateMonitor,
|
||||
@NonNull KeyguardViewMediator keyguardViewMediator) {
|
||||
@NonNull KeyguardViewMediator keyguardViewMediator,
|
||||
@NonNull FalsingManager falsingManager) {
|
||||
mContext = context;
|
||||
mInflater = inflater;
|
||||
// The fingerprint manager is queried for UDFPS before this class is constructed, so the
|
||||
@@ -325,9 +329,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
|
||||
mStatusBarStateController = statusBarStateController;
|
||||
mKeyguardViewManager = statusBarKeyguardViewManager;
|
||||
mDumpManager = dumpManager;
|
||||
mAuthRippleController = authRippleController;
|
||||
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
|
||||
mKeyguardViewMediator = keyguardViewMediator;
|
||||
mFalsingManager = falsingManager;
|
||||
|
||||
mSensorProps = findFirstUdfps();
|
||||
// At least one UDFPS sensor exists
|
||||
@@ -353,10 +357,6 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
|
||||
context.registerReceiver(mBroadcastReceiver, filter);
|
||||
|
||||
mAuthRippleController.setViewHost(mStatusBar.getNotificationShadeWindowView());
|
||||
mAuthRippleController.setSensorLocation(getSensorLocation().centerX(),
|
||||
getSensorLocation().centerY());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -91,6 +91,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
|
||||
mStatusBarStateController.addCallback(mStateListener);
|
||||
mStateListener.onDozeAmountChanged(dozeAmount, dozeAmount);
|
||||
mStateListener.onStateChanged(mStatusBarStateController.getState());
|
||||
mAlternateAuthInterceptor.setQsExpanded(mKeyguardViewManager.isQsExpanded());
|
||||
mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor);
|
||||
}
|
||||
|
||||
@@ -117,6 +118,8 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
|
||||
pw.println("mShowBouncer=" + mShowBouncer);
|
||||
pw.println("mFaceDetectRunning=" + mFaceDetectRunning);
|
||||
pw.println("mTransitioningFromHomeToKeyguard=" + mTransitioningFromHome);
|
||||
pw.println("mStatusBarState" + StatusBarState.toShortString(mStatusBarState));
|
||||
pw.println("mQsExpanded=" + mQsExpanded);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,6 +218,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
|
||||
public void onStateChanged(int statusBarState) {
|
||||
mStatusBarState = statusBarState;
|
||||
mView.setStatusBarState(statusBarState);
|
||||
updatePauseAuth();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -283,7 +287,7 @@ public class UdfpsKeyguardViewController extends UdfpsAnimationViewController<Ud
|
||||
|
||||
@Override
|
||||
public void dump(PrintWriter pw) {
|
||||
pw.print(getTag());
|
||||
pw.println(getTag());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ public abstract class Classifier {
|
||||
public static final int BOUNCER_UNLOCK = 8;
|
||||
public static final int PULSE_EXPAND = 9;
|
||||
public static final int BRIGHTNESS_SLIDER = 10;
|
||||
public static final int UDFPS_AUTHENTICATION = 11;
|
||||
public static final int DISABLED_UDFPS_AFFORDANCE = 12;
|
||||
|
||||
@IntDef({
|
||||
QUICK_SETTINGS,
|
||||
@@ -50,7 +52,9 @@ public abstract class Classifier {
|
||||
GENERIC,
|
||||
BOUNCER_UNLOCK,
|
||||
PULSE_EXPAND,
|
||||
BRIGHTNESS_SLIDER
|
||||
BRIGHTNESS_SLIDER,
|
||||
UDFPS_AUTHENTICATION,
|
||||
DISABLED_UDFPS_AFFORDANCE
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface InteractionType {}
|
||||
|
||||
@@ -148,7 +148,9 @@ class DistanceClassifier extends FalsingClassifier {
|
||||
Result calculateFalsingResult(
|
||||
@Classifier.InteractionType int interactionType,
|
||||
double historyBelief, double historyConfidence) {
|
||||
if (interactionType == Classifier.BRIGHTNESS_SLIDER) {
|
||||
if (interactionType == Classifier.BRIGHTNESS_SLIDER
|
||||
|| interactionType == Classifier.UDFPS_AUTHENTICATION
|
||||
|| interactionType == Classifier.DISABLED_UDFPS_AFFORDANCE) {
|
||||
return Result.passed(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,11 @@ public class TypeClassifier extends FalsingClassifier {
|
||||
Result calculateFalsingResult(
|
||||
@Classifier.InteractionType int interactionType,
|
||||
double historyBelief, double historyConfidence) {
|
||||
if (interactionType == Classifier.UDFPS_AUTHENTICATION
|
||||
|| interactionType == Classifier.DISABLED_UDFPS_AFFORDANCE) {
|
||||
return Result.passed(0);
|
||||
}
|
||||
|
||||
boolean vertical = isVertical();
|
||||
boolean up = isUp();
|
||||
boolean right = isRight();
|
||||
|
||||
@@ -142,7 +142,7 @@ public interface NotificationShadeWindowController extends RemoteInputController
|
||||
default void setDozing(boolean dozing) {}
|
||||
|
||||
/** Sets the state of whether plugin open is forced or not. */
|
||||
default void setForcePluginOpen(boolean forcePluginOpen) {}
|
||||
default void setForcePluginOpen(boolean forcePluginOpen, Object token) {}
|
||||
|
||||
/** Gets whether we are forcing plugin open or not. */
|
||||
default boolean getForcePluginOpen() {
|
||||
|
||||
@@ -1851,6 +1851,10 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
mPulseExpansionHandler.setQsExpanded(expanded);
|
||||
mKeyguardBypassController.setQSExpanded(expanded);
|
||||
mStatusBarKeyguardViewManager.setQsExpanded(expanded);
|
||||
|
||||
if (mDisabledUdfpsController != null) {
|
||||
mDisabledUdfpsController.setQsExpanded(expanded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3551,7 +3555,8 @@ public class NotificationPanelViewController extends PanelViewController {
|
||||
mUpdateMonitor,
|
||||
mAuthController,
|
||||
mStatusBarKeyguardViewManager,
|
||||
mKeyguardStateController);
|
||||
mKeyguardStateController,
|
||||
mFalsingManager);
|
||||
mDisabledUdfpsController.init();
|
||||
} else if (mDisabledUdfpsController != null && !udfpsEnrolled) {
|
||||
mDisabledUdfpsController.destroy();
|
||||
|
||||
@@ -611,12 +611,21 @@ public class NotificationShadeWindowControllerImpl implements NotificationShadeW
|
||||
apply(mCurrentState);
|
||||
}
|
||||
|
||||
private final Set<Object> mForceOpenTokens = new HashSet<>();
|
||||
@Override
|
||||
public void setForcePluginOpen(boolean forcePluginOpen) {
|
||||
mCurrentState.mForcePluginOpen = forcePluginOpen;
|
||||
apply(mCurrentState);
|
||||
if (mForcePluginOpenListener != null) {
|
||||
mForcePluginOpenListener.onChange(forcePluginOpen);
|
||||
public void setForcePluginOpen(boolean forceOpen, Object token) {
|
||||
if (forceOpen) {
|
||||
mForceOpenTokens.add(token);
|
||||
} else {
|
||||
mForceOpenTokens.remove(token);
|
||||
}
|
||||
final boolean previousForceOpenState = mCurrentState.mForcePluginOpen;
|
||||
mCurrentState.mForcePluginOpen = !mForceOpenTokens.isEmpty();
|
||||
if (previousForceOpenState != mCurrentState.mForcePluginOpen) {
|
||||
apply(mCurrentState);
|
||||
if (mForcePluginOpenListener != null) {
|
||||
mForcePluginOpenListener.onChange(mCurrentState.mForcePluginOpen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -207,7 +207,6 @@ import com.android.systemui.statusbar.StatusBarState;
|
||||
import com.android.systemui.statusbar.SuperStatusBarViewFactory;
|
||||
import com.android.systemui.statusbar.SysuiStatusBarStateController;
|
||||
import com.android.systemui.statusbar.VibratorHelper;
|
||||
import com.android.systemui.statusbar.charging.ChargingRippleView;
|
||||
import com.android.systemui.statusbar.charging.WiredChargingRippleController;
|
||||
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
|
||||
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
|
||||
@@ -386,7 +385,6 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
private boolean mWakeUpComingFromTouch;
|
||||
private PointF mWakeUpTouchLocation;
|
||||
private LightRevealScrim mLightRevealScrim;
|
||||
private ChargingRippleView mChargingRipple;
|
||||
private WiredChargingRippleController mChargingRippleAnimationController;
|
||||
private PowerButtonReveal mPowerButtonReveal;
|
||||
private CircleReveal mCircleReveal;
|
||||
@@ -1060,7 +1058,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
mMainThreadHandler.post(() -> {
|
||||
mOverlays.remove(plugin);
|
||||
mNotificationShadeWindowController
|
||||
.setForcePluginOpen(mOverlays.size() != 0);
|
||||
.setForcePluginOpen(mOverlays.size() != 0, this);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1083,7 +1081,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
.setStateListener(b -> mOverlays.forEach(
|
||||
o -> o.setCollapseDesired(b)));
|
||||
mNotificationShadeWindowController
|
||||
.setForcePluginOpen(mOverlays.size() != 0);
|
||||
.setForcePluginOpen(mOverlays.size() != 0, this);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1523,6 +1521,7 @@ public class StatusBar extends SystemUI implements DemoMode,
|
||||
mNotificationPanelViewController = statusBarComponent.getNotificationPanelViewController();
|
||||
mLockscreenLockIconController = statusBarComponent.getLockscreenLockIconController();
|
||||
mLockscreenLockIconController.init();
|
||||
statusBarComponent.getAuthRippleController().init();
|
||||
|
||||
mNotificationPanelViewController.setLaunchAffordanceListener(
|
||||
mLockscreenLockIconController::onShowingLaunchAffordanceChanged);
|
||||
|
||||
@@ -187,6 +187,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
private int mLastBiometricMode;
|
||||
private boolean mLastLockVisible;
|
||||
private boolean mLastLockOrientationIsPortrait;
|
||||
private boolean mQsExpanded;
|
||||
|
||||
private OnDismissAction mAfterKeyguardGoneAction;
|
||||
private Runnable mKeyguardGoneCancelAction;
|
||||
@@ -1127,10 +1128,17 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
|
||||
setDozing(isDozing);
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether qs is currently expanded.
|
||||
*/
|
||||
public boolean isQsExpanded() {
|
||||
return mQsExpanded;
|
||||
}
|
||||
/**
|
||||
* Set whether qs is currently expanded
|
||||
*/
|
||||
public void setQsExpanded(boolean expanded) {
|
||||
mQsExpanded = expanded;
|
||||
if (mAlternateAuthInterceptor != null) {
|
||||
mAlternateAuthInterceptor.setQsExpanded(expanded);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.phone.dagger;
|
||||
|
||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||
|
||||
import com.android.systemui.biometrics.AuthRippleController;
|
||||
import com.android.systemui.statusbar.phone.LockscreenLockIconController;
|
||||
import com.android.systemui.statusbar.phone.NotificationPanelViewController;
|
||||
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
|
||||
@@ -79,4 +80,10 @@ public interface StatusBarComponent {
|
||||
*/
|
||||
@StatusBarScope
|
||||
LockscreenLockIconController getLockscreenLockIconController();
|
||||
|
||||
/**
|
||||
* Creates an AuthRippleController
|
||||
*/
|
||||
@StatusBarScope
|
||||
AuthRippleController getAuthRippleController();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.phone.dagger;
|
||||
import android.annotation.Nullable;
|
||||
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.biometrics.AuthRippleView;
|
||||
import com.android.systemui.statusbar.phone.LockIcon;
|
||||
import com.android.systemui.statusbar.phone.NotificationPanelView;
|
||||
import com.android.systemui.statusbar.phone.NotificationShadeWindowView;
|
||||
@@ -44,4 +45,13 @@ public abstract class StatusBarViewModule {
|
||||
NotificationShadeWindowView notificationShadeWindowView) {
|
||||
return notificationShadeWindowView.findViewById(R.id.lock_icon);
|
||||
}
|
||||
|
||||
/** */
|
||||
@Provides
|
||||
@StatusBarComponent.StatusBarScope
|
||||
@Nullable
|
||||
public static AuthRippleView getAuthRippleView(
|
||||
NotificationShadeWindowView notificationShadeWindowView) {
|
||||
return notificationShadeWindowView.findViewById(R.id.auth_ripple);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
|
||||
package com.android.systemui.biometrics
|
||||
|
||||
import android.graphics.PointF
|
||||
import android.hardware.biometrics.BiometricSourceType
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.keyguard.KeyguardUpdateMonitor
|
||||
import com.android.keyguard.KeyguardUpdateMonitorCallback
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.statusbar.NotificationShadeWindowController
|
||||
import com.android.systemui.statusbar.commandline.CommandRegistry
|
||||
import com.android.systemui.statusbar.policy.ConfigurationController
|
||||
import org.junit.Before
|
||||
@@ -32,6 +32,8 @@ import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.ArgumentMatchers
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.`when`
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.reset
|
||||
import org.mockito.Mockito.verify
|
||||
@@ -41,38 +43,50 @@ import org.mockito.MockitoAnnotations
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
class AuthRippleControllerTest : SysuiTestCase() {
|
||||
private lateinit var controller: AuthRippleController
|
||||
@Mock private lateinit var rippleView: AuthRippleView
|
||||
@Mock private lateinit var commandRegistry: CommandRegistry
|
||||
@Mock private lateinit var configurationController: ConfigurationController
|
||||
@Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
|
||||
@Mock private lateinit var rippleView: AuthRippleView
|
||||
@Mock private lateinit var viewHost: ViewGroup
|
||||
@Mock private lateinit var authController: AuthController
|
||||
@Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
|
||||
|
||||
@Before
|
||||
|
||||
fun setUp() {
|
||||
MockitoAnnotations.initMocks(this)
|
||||
controller = AuthRippleController(
|
||||
commandRegistry, configurationController, context, keyguardUpdateMonitor)
|
||||
controller.rippleView = rippleView // Replace the real ripple view with a mock instance
|
||||
controller.setViewHost(viewHost)
|
||||
context,
|
||||
authController,
|
||||
configurationController,
|
||||
keyguardUpdateMonitor,
|
||||
commandRegistry,
|
||||
notificationShadeWindowController,
|
||||
rippleView
|
||||
)
|
||||
controller.init()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAddRippleView() {
|
||||
val listenerCaptor = ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java)
|
||||
verify(viewHost).addOnAttachStateChangeListener(listenerCaptor.capture())
|
||||
fun testFingerprintTriggerRipple() {
|
||||
val fpsLocation = PointF(5f, 5f)
|
||||
`when`(authController.udfpsSensorLocation).thenReturn(fpsLocation)
|
||||
controller.onViewAttached()
|
||||
|
||||
// Fake attach to window
|
||||
listenerCaptor.value.onViewAttachedToWindow(viewHost)
|
||||
verify(viewHost).addView(rippleView)
|
||||
val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
|
||||
verify(keyguardUpdateMonitor).registerCallback(captor.capture())
|
||||
|
||||
captor.value.onBiometricAuthenticated(
|
||||
0 /* userId */,
|
||||
BiometricSourceType.FINGERPRINT /* type */,
|
||||
false /* isStrongBiometric */)
|
||||
verify(rippleView).setSensorLocation(fpsLocation)
|
||||
verify(rippleView).startRipple(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTriggerRipple() {
|
||||
// Fake attach to window
|
||||
val listenerCaptor = ArgumentCaptor.forClass(View.OnAttachStateChangeListener::class.java)
|
||||
verify(viewHost).addOnAttachStateChangeListener(listenerCaptor.capture())
|
||||
listenerCaptor.value.onViewAttachedToWindow(viewHost)
|
||||
fun testFaceTriggerRipple() {
|
||||
val faceLocation = PointF(5f, 5f)
|
||||
`when`(authController.faceAuthSensorLocation).thenReturn(faceLocation)
|
||||
controller.onViewAttached()
|
||||
|
||||
val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
|
||||
verify(keyguardUpdateMonitor).registerCallback(captor.capture())
|
||||
@@ -81,17 +95,43 @@ class AuthRippleControllerTest : SysuiTestCase() {
|
||||
0 /* userId */,
|
||||
BiometricSourceType.FACE /* type */,
|
||||
false /* isStrongBiometric */)
|
||||
verify(rippleView, never()).startRipple()
|
||||
verify(rippleView).setSensorLocation(faceLocation)
|
||||
verify(rippleView).startRipple(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNullFaceSensorLocationDoesNothing() {
|
||||
`when`(authController.faceAuthSensorLocation).thenReturn(null)
|
||||
controller.onViewAttached()
|
||||
|
||||
val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
|
||||
verify(keyguardUpdateMonitor).registerCallback(captor.capture())
|
||||
|
||||
captor.value.onBiometricAuthenticated(
|
||||
0 /* userId */,
|
||||
BiometricSourceType.FACE /* type */,
|
||||
false /* isStrongBiometric */)
|
||||
verify(rippleView, never()).startRipple(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNullFingerprintSensorLocationDoesNothing() {
|
||||
`when`(authController.udfpsSensorLocation).thenReturn(null)
|
||||
controller.onViewAttached()
|
||||
|
||||
val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
|
||||
verify(keyguardUpdateMonitor).registerCallback(captor.capture())
|
||||
|
||||
captor.value.onBiometricAuthenticated(
|
||||
0 /* userId */,
|
||||
BiometricSourceType.FINGERPRINT /* type */,
|
||||
false /* isStrongBiometric */)
|
||||
verify(rippleView).startRipple()
|
||||
verify(rippleView, never()).startRipple(any())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testUpdateRippleColor() {
|
||||
controller.onViewAttached()
|
||||
val captor = ArgumentCaptor
|
||||
.forClass(ConfigurationController.ConfigurationListener::class.java)
|
||||
verify(configurationController).addCallback(captor.capture())
|
||||
@@ -104,10 +144,4 @@ class AuthRippleControllerTest : SysuiTestCase() {
|
||||
captor.value.onUiModeChanged()
|
||||
verify(rippleView).setColor(ArgumentMatchers.anyInt())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testForwardsSensorLocation() {
|
||||
controller.setSensorLocation(5f, 5f)
|
||||
verify(rippleView).setSensorLocation(5f, 5f)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
import com.android.systemui.keyguard.KeyguardViewMediator;
|
||||
import com.android.systemui.plugins.FalsingManager;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.statusbar.phone.StatusBar;
|
||||
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
|
||||
@@ -100,13 +101,13 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
@Mock
|
||||
private DumpManager mDumpManager;
|
||||
@Mock
|
||||
private AuthRippleController mAuthRippleController;
|
||||
@Mock
|
||||
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
|
||||
@Mock
|
||||
private KeyguardViewMediator mKeyguardViewMediator;
|
||||
@Mock
|
||||
private IUdfpsOverlayControllerCallback mUdfpsOverlayControllerCallback;
|
||||
@Mock
|
||||
private FalsingManager mFalsingManager;
|
||||
|
||||
private FakeExecutor mFgExecutor;
|
||||
|
||||
@@ -157,9 +158,9 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
||||
mStatusBar,
|
||||
mStatusBarKeyguardViewManager,
|
||||
mDumpManager,
|
||||
mAuthRippleController,
|
||||
mKeyguardUpdateMonitor,
|
||||
mKeyguardViewMediator);
|
||||
mKeyguardViewMediator,
|
||||
mFalsingManager);
|
||||
verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
|
||||
mOverlayController = mOverlayCaptor.getValue();
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
|
||||
|
||||
@Test
|
||||
public void testSetForcePluginOpen_beforeStatusBarInitialization() {
|
||||
mNotificationShadeWindowController.setForcePluginOpen(true);
|
||||
mNotificationShadeWindowController.setForcePluginOpen(true, this);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user