Loading packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +1 −1 Original line number Diff line number Diff line Loading @@ -1359,7 +1359,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:AOD_INTERRUPT_END"); } mAuthController.onCancelAodInterrupt(); mAuthController.onCancelUdfps(); mIsUdfpsRunningWhileDozing = false; } }; Loading packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +6 −8 Original line number Diff line number Diff line Loading @@ -309,18 +309,14 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } /** * Cancel a fingerprint scan. * * The sensor that triggers an AOD interrupt for fingerprint doesn't give * ACTION_UP/ACTION_CANCEL events, so the scan needs to be cancelled manually. This should be * called when authentication either succeeds or fails. Failing to cancel the scan will leave * the screen in high brightness mode. * Cancel a fingerprint scan manually. This will get rid of the white circle on the udfps * sensor area even if the user hasn't explicitly lifted their finger yet. */ public void onCancelAodInterrupt() { public void onCancelUdfps() { if (mUdfpsController == null) { return; } mUdfpsController.onCancelAodInterrupt(); mUdfpsController.onCancelUdfps(); } private void sendResultAndCleanUp(@DismissedReason int reason, Loading Loading @@ -499,6 +495,8 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, if (DEBUG) Log.d(TAG, "onBiometricError, hard error: " + errorMessage); mCurrentDialog.onError(errorMessage); } onCancelUdfps(); } @Override Loading packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +92 −9 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; Loading @@ -35,15 +36,23 @@ import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IUdfpsOverlayController; import android.hardware.fingerprint.IUdfpsOverlayControllerCallback; import android.media.AudioAttributes; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; import android.os.VibrationEffect; import android.os.Vibrator; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.Surface; import android.view.VelocityTracker; import android.view.View; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -94,7 +103,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback { @NonNull private final DumpManager mDumpManager; @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @NonNull private final KeyguardViewMediator mKeyguardViewMediator; @NonNull private FalsingManager mFalsingManager; @NonNull private final Vibrator mVibrator; @NonNull private final Handler mMainHandler; @NonNull private final 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; Loading @@ -118,6 +129,27 @@ public class UdfpsController implements DozeReceiver, HbmCallback { private boolean mIsAodInterruptActive; @Nullable private Runnable mCancelAodTimeoutAction; private static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) .build(); private final VibrationEffect mEffectTick = VibrationEffect.get(VibrationEffect.EFFECT_TICK); private final VibrationEffect mEffectTextureTick = VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK); private final VibrationEffect mEffectClick = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); private final VibrationEffect mEffectHeavy = VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK); private final Runnable mAcquiredVibration = new Runnable() { @Override public void run() { String effect = Settings.Global.getString(mContext.getContentResolver(), "udfps_acquired_type"); mVibrator.vibrate(getVibration(effect, mEffectTick), VIBRATION_SONIFICATION_ATTRIBUTES); } }; /** * Keeps track of state within a single FingerprintService request. Note that this state * persists across configuration changes, etc, since it is considered a single request. Loading Loading @@ -227,7 +259,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback { }; @SuppressLint("ClickableViewAccessibility") private final UdfpsView.OnTouchListener mOnTouchListener = (view, event) -> { private final UdfpsView.OnTouchListener mOnTouchListener = this::onTouch; private boolean onTouch(View view, MotionEvent event) { UdfpsView udfpsView = (UdfpsView) view; final boolean isFingerDown = udfpsView.isIlluminationRequested(); boolean handled = false; Loading @@ -251,6 +285,27 @@ public class UdfpsController implements DozeReceiver, HbmCallback { // data for many other pointers because of multi-touch support. mActivePointerId = event.getPointerId(0); mVelocityTracker.addMovement(event); // TODO: (b/185124905) these settings are for ux testing purposes and should // be removed (or cached) before going into production final ContentResolver contentResolver = mContext.getContentResolver(); int startEnabled = Settings.Global.getInt(contentResolver, "udfps_start", 0); if (startEnabled > 0) { String startEffectSetting = Settings.Global.getString(contentResolver, "udfps_start_type"); mVibrator.vibrate(getVibration(startEffectSetting, mEffectClick), VIBRATION_SONIFICATION_ATTRIBUTES); } int acquiredEnabled = Settings.Global.getInt(contentResolver, "udfps_acquired", 0); if (acquiredEnabled > 0) { int delay = Settings.Global.getInt(contentResolver, "udfps_acquired_delay", 500); mMainHandler.removeCallbacks(mAcquiredVibration); mMainHandler.postDelayed(mAcquiredVibration, delay); } handled = true; } break; Loading Loading @@ -307,7 +362,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback { // Do nothing. } return handled; }; } @Inject public UdfpsController(@NonNull Context context, Loading @@ -324,6 +379,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback { @NonNull KeyguardViewMediator keyguardViewMediator, @NonNull FalsingManager falsingManager) { mContext = context; // TODO (b/185124905): inject main handler and vibrator once done prototyping mMainHandler = new Handler(Looper.getMainLooper()); mVibrator = context.getSystemService(Vibrator.class); mInflater = inflater; // The fingerprint manager is queried for UDFPS before this class is constructed, so the // fingerprint manager should never be null. Loading Loading @@ -559,19 +617,25 @@ public class UdfpsController implements DozeReceiver, HbmCallback { // Since the sensor that triggers the AOD interrupt doesn't provide ACTION_UP/ACTION_CANCEL, // we need to be careful about not letting the screen accidentally remain in high brightness // mode. As a mitigation, queue a call to cancel the fingerprint scan. mCancelAodTimeoutAction = mFgExecutor.executeDelayed(this::onCancelAodInterrupt, mCancelAodTimeoutAction = mFgExecutor.executeDelayed(this::onCancelUdfps, AOD_INTERRUPT_TIMEOUT_MILLIS); // using a hard-coded value for major and minor until it is available from the sensor onFingerDown(screenX, screenY, minor, major); } /** * Cancel fingerprint scan. * Cancel updfs scan affordances - ability to hide the HbmSurfaceView (white circle) before * user explicitly lifts their finger. Generally, this should be called whenever udfps fails * or errors. * * This is intended to be called after the fingerprint scan triggered by the AOD interrupt * either succeeds or fails. * The sensor that triggers an AOD fingerprint interrupt (see onAodInterrupt) doesn't give * ACTION_UP/ACTION_CANCEL events, so and AOD interrupt scan needs to be cancelled manually. * This should be called when authentication either succeeds or fails. Failing to cancel the * scan will leave the screen in high brightness mode and will show the HbmSurfaceView until * the user lifts their finger. */ void onCancelAodInterrupt() { void onCancelUdfps() { onFingerUp(); if (!mIsAodInterruptActive) { return; } Loading @@ -580,7 +644,6 @@ public class UdfpsController implements DozeReceiver, HbmCallback { mCancelAodTimeoutAction = null; } mIsAodInterruptActive = false; onFingerUp(); } // This method can be called from the UI thread. Loading @@ -598,6 +661,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback { // This method can be called from the UI thread. private void onFingerUp() { mMainHandler.removeCallbacks(mAcquiredVibration); if (mView == null) { Log.w(TAG, "Null view in onFingerUp"); return; Loading @@ -617,4 +681,23 @@ public class UdfpsController implements DozeReceiver, HbmCallback { // Do nothing. This method can be implemented for devices that require the high-brightness // mode for fingerprint illumination. } private VibrationEffect getVibration(String effect, VibrationEffect defaultEffect) { if (TextUtils.isEmpty(effect)) { return defaultEffect; } switch (effect.toLowerCase()) { case "click": return mEffectClick; case "heavy": return mEffectHeavy; case "texture_tick": return mEffectTextureTick; case "tick": return mEffectTick; default: return defaultEffect; } } } packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +2 −2 Original line number Diff line number Diff line Loading @@ -537,7 +537,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { authCallback.onAuthenticationFailed(); // THEN aod interrupt is cancelled verify(mAuthController).onCancelAodInterrupt(); verify(mAuthController).onCancelUdfps(); } @Test Loading @@ -557,7 +557,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { authCallback.onAuthenticationError(0, ""); // THEN aod interrupt is cancelled verify(mAuthController).onCancelAodInterrupt(); verify(mAuthController).onCancelUdfps(); } @Test Loading packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -259,7 +259,7 @@ public class UdfpsControllerTest extends SysuiTestCase { mFgExecutor.runAllReady(); mUdfpsController.onAodInterrupt(0, 0, 0f, 0f); // WHEN it is cancelled mUdfpsController.onCancelAodInterrupt(); mUdfpsController.onCancelUdfps(); // THEN the illumination is hidden verify(mUdfpsView).stopIllumination(); } Loading Loading
packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +1 −1 Original line number Diff line number Diff line Loading @@ -1359,7 +1359,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:AOD_INTERRUPT_END"); } mAuthController.onCancelAodInterrupt(); mAuthController.onCancelUdfps(); mIsUdfpsRunningWhileDozing = false; } }; Loading
packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java +6 −8 Original line number Diff line number Diff line Loading @@ -309,18 +309,14 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, } /** * Cancel a fingerprint scan. * * The sensor that triggers an AOD interrupt for fingerprint doesn't give * ACTION_UP/ACTION_CANCEL events, so the scan needs to be cancelled manually. This should be * called when authentication either succeeds or fails. Failing to cancel the scan will leave * the screen in high brightness mode. * Cancel a fingerprint scan manually. This will get rid of the white circle on the udfps * sensor area even if the user hasn't explicitly lifted their finger yet. */ public void onCancelAodInterrupt() { public void onCancelUdfps() { if (mUdfpsController == null) { return; } mUdfpsController.onCancelAodInterrupt(); mUdfpsController.onCancelUdfps(); } private void sendResultAndCleanUp(@DismissedReason int reason, Loading Loading @@ -499,6 +495,8 @@ public class AuthController extends SystemUI implements CommandQueue.Callbacks, if (DEBUG) Log.d(TAG, "onBiometricError, hard error: " + errorMessage); mCurrentDialog.onError(errorMessage); } onCancelUdfps(); } @Override Loading
packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java +92 −9 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; Loading @@ -35,15 +36,23 @@ import android.hardware.fingerprint.FingerprintManager; import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IUdfpsOverlayController; import android.hardware.fingerprint.IUdfpsOverlayControllerCallback; import android.media.AudioAttributes; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; import android.os.VibrationEffect; import android.os.Vibrator; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.Surface; import android.view.VelocityTracker; import android.view.View; import android.view.WindowManager; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -94,7 +103,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback { @NonNull private final DumpManager mDumpManager; @NonNull private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; @NonNull private final KeyguardViewMediator mKeyguardViewMediator; @NonNull private FalsingManager mFalsingManager; @NonNull private final Vibrator mVibrator; @NonNull private final Handler mMainHandler; @NonNull private final 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; Loading @@ -118,6 +129,27 @@ public class UdfpsController implements DozeReceiver, HbmCallback { private boolean mIsAodInterruptActive; @Nullable private Runnable mCancelAodTimeoutAction; private static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION) .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) .build(); private final VibrationEffect mEffectTick = VibrationEffect.get(VibrationEffect.EFFECT_TICK); private final VibrationEffect mEffectTextureTick = VibrationEffect.get(VibrationEffect.EFFECT_TEXTURE_TICK); private final VibrationEffect mEffectClick = VibrationEffect.get(VibrationEffect.EFFECT_CLICK); private final VibrationEffect mEffectHeavy = VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK); private final Runnable mAcquiredVibration = new Runnable() { @Override public void run() { String effect = Settings.Global.getString(mContext.getContentResolver(), "udfps_acquired_type"); mVibrator.vibrate(getVibration(effect, mEffectTick), VIBRATION_SONIFICATION_ATTRIBUTES); } }; /** * Keeps track of state within a single FingerprintService request. Note that this state * persists across configuration changes, etc, since it is considered a single request. Loading Loading @@ -227,7 +259,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback { }; @SuppressLint("ClickableViewAccessibility") private final UdfpsView.OnTouchListener mOnTouchListener = (view, event) -> { private final UdfpsView.OnTouchListener mOnTouchListener = this::onTouch; private boolean onTouch(View view, MotionEvent event) { UdfpsView udfpsView = (UdfpsView) view; final boolean isFingerDown = udfpsView.isIlluminationRequested(); boolean handled = false; Loading @@ -251,6 +285,27 @@ public class UdfpsController implements DozeReceiver, HbmCallback { // data for many other pointers because of multi-touch support. mActivePointerId = event.getPointerId(0); mVelocityTracker.addMovement(event); // TODO: (b/185124905) these settings are for ux testing purposes and should // be removed (or cached) before going into production final ContentResolver contentResolver = mContext.getContentResolver(); int startEnabled = Settings.Global.getInt(contentResolver, "udfps_start", 0); if (startEnabled > 0) { String startEffectSetting = Settings.Global.getString(contentResolver, "udfps_start_type"); mVibrator.vibrate(getVibration(startEffectSetting, mEffectClick), VIBRATION_SONIFICATION_ATTRIBUTES); } int acquiredEnabled = Settings.Global.getInt(contentResolver, "udfps_acquired", 0); if (acquiredEnabled > 0) { int delay = Settings.Global.getInt(contentResolver, "udfps_acquired_delay", 500); mMainHandler.removeCallbacks(mAcquiredVibration); mMainHandler.postDelayed(mAcquiredVibration, delay); } handled = true; } break; Loading Loading @@ -307,7 +362,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback { // Do nothing. } return handled; }; } @Inject public UdfpsController(@NonNull Context context, Loading @@ -324,6 +379,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback { @NonNull KeyguardViewMediator keyguardViewMediator, @NonNull FalsingManager falsingManager) { mContext = context; // TODO (b/185124905): inject main handler and vibrator once done prototyping mMainHandler = new Handler(Looper.getMainLooper()); mVibrator = context.getSystemService(Vibrator.class); mInflater = inflater; // The fingerprint manager is queried for UDFPS before this class is constructed, so the // fingerprint manager should never be null. Loading Loading @@ -559,19 +617,25 @@ public class UdfpsController implements DozeReceiver, HbmCallback { // Since the sensor that triggers the AOD interrupt doesn't provide ACTION_UP/ACTION_CANCEL, // we need to be careful about not letting the screen accidentally remain in high brightness // mode. As a mitigation, queue a call to cancel the fingerprint scan. mCancelAodTimeoutAction = mFgExecutor.executeDelayed(this::onCancelAodInterrupt, mCancelAodTimeoutAction = mFgExecutor.executeDelayed(this::onCancelUdfps, AOD_INTERRUPT_TIMEOUT_MILLIS); // using a hard-coded value for major and minor until it is available from the sensor onFingerDown(screenX, screenY, minor, major); } /** * Cancel fingerprint scan. * Cancel updfs scan affordances - ability to hide the HbmSurfaceView (white circle) before * user explicitly lifts their finger. Generally, this should be called whenever udfps fails * or errors. * * This is intended to be called after the fingerprint scan triggered by the AOD interrupt * either succeeds or fails. * The sensor that triggers an AOD fingerprint interrupt (see onAodInterrupt) doesn't give * ACTION_UP/ACTION_CANCEL events, so and AOD interrupt scan needs to be cancelled manually. * This should be called when authentication either succeeds or fails. Failing to cancel the * scan will leave the screen in high brightness mode and will show the HbmSurfaceView until * the user lifts their finger. */ void onCancelAodInterrupt() { void onCancelUdfps() { onFingerUp(); if (!mIsAodInterruptActive) { return; } Loading @@ -580,7 +644,6 @@ public class UdfpsController implements DozeReceiver, HbmCallback { mCancelAodTimeoutAction = null; } mIsAodInterruptActive = false; onFingerUp(); } // This method can be called from the UI thread. Loading @@ -598,6 +661,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback { // This method can be called from the UI thread. private void onFingerUp() { mMainHandler.removeCallbacks(mAcquiredVibration); if (mView == null) { Log.w(TAG, "Null view in onFingerUp"); return; Loading @@ -617,4 +681,23 @@ public class UdfpsController implements DozeReceiver, HbmCallback { // Do nothing. This method can be implemented for devices that require the high-brightness // mode for fingerprint illumination. } private VibrationEffect getVibration(String effect, VibrationEffect defaultEffect) { if (TextUtils.isEmpty(effect)) { return defaultEffect; } switch (effect.toLowerCase()) { case "click": return mEffectClick; case "heavy": return mEffectHeavy; case "texture_tick": return mEffectTextureTick; case "tick": return mEffectTick; default: return defaultEffect; } } }
packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +2 −2 Original line number Diff line number Diff line Loading @@ -537,7 +537,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { authCallback.onAuthenticationFailed(); // THEN aod interrupt is cancelled verify(mAuthController).onCancelAodInterrupt(); verify(mAuthController).onCancelUdfps(); } @Test Loading @@ -557,7 +557,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { authCallback.onAuthenticationError(0, ""); // THEN aod interrupt is cancelled verify(mAuthController).onCancelAodInterrupt(); verify(mAuthController).onCancelUdfps(); } @Test Loading
packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -259,7 +259,7 @@ public class UdfpsControllerTest extends SysuiTestCase { mFgExecutor.runAllReady(); mUdfpsController.onAodInterrupt(0, 0, 0f, 0f); // WHEN it is cancelled mUdfpsController.onCancelAodInterrupt(); mUdfpsController.onCancelUdfps(); // THEN the illumination is hidden verify(mUdfpsView).stopIllumination(); } Loading