Merge "Add ability to enable extra udfps vibrations" into sc-dev

This commit is contained in:
Beverly Tai
2021-04-14 21:28:03 +00:00
committed by Android (Google) Code Review
5 changed files with 102 additions and 21 deletions

View File

@@ -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;
}
};

View File

@@ -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,
@@ -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

View File

@@ -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;
@@ -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;
@@ -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;
@@ -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.
@@ -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;
@@ -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;
@@ -307,7 +362,7 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
// Do nothing.
}
return handled;
};
}
@Inject
public UdfpsController(@NonNull Context context,
@@ -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.
@@ -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;
}
@@ -580,7 +644,6 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
mCancelAodTimeoutAction = null;
}
mIsAodInterruptActive = false;
onFingerUp();
}
// This method can be called from the UI thread.
@@ -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;
@@ -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;
}
}
}

View File

@@ -537,7 +537,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
authCallback.onAuthenticationFailed();
// THEN aod interrupt is cancelled
verify(mAuthController).onCancelAodInterrupt();
verify(mAuthController).onCancelUdfps();
}
@Test
@@ -557,7 +557,7 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase {
authCallback.onAuthenticationError(0, "");
// THEN aod interrupt is cancelled
verify(mAuthController).onCancelAodInterrupt();
verify(mAuthController).onCancelUdfps();
}
@Test

View File

@@ -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();
}