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