Merge "Refine the onTouch logic and log touch speed" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
0a5bec679f
@@ -28,11 +28,13 @@ import android.graphics.RectF;
|
|||||||
import android.hardware.fingerprint.FingerprintManager;
|
import android.hardware.fingerprint.FingerprintManager;
|
||||||
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
||||||
import android.hardware.fingerprint.IUdfpsOverlayController;
|
import android.hardware.fingerprint.IUdfpsOverlayController;
|
||||||
|
import android.os.SystemClock;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
import android.view.VelocityTracker;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@@ -66,6 +68,9 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
|
|||||||
private static final String TAG = "UdfpsController";
|
private static final String TAG = "UdfpsController";
|
||||||
private static final long AOD_INTERRUPT_TIMEOUT_MILLIS = 1000;
|
private static final long AOD_INTERRUPT_TIMEOUT_MILLIS = 1000;
|
||||||
|
|
||||||
|
// Minimum required delay between consecutive touch logs in milliseconds.
|
||||||
|
private static final long MIN_TOUCH_LOG_INTERVAL = 50;
|
||||||
|
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final FingerprintManager mFingerprintManager;
|
private final FingerprintManager mFingerprintManager;
|
||||||
@NonNull private final LayoutInflater mInflater;
|
@NonNull private final LayoutInflater mInflater;
|
||||||
@@ -78,6 +83,13 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
|
|||||||
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
|
@VisibleForTesting final FingerprintSensorPropertiesInternal mSensorProps;
|
||||||
private final WindowManager.LayoutParams mCoreLayoutParams;
|
private final WindowManager.LayoutParams mCoreLayoutParams;
|
||||||
|
|
||||||
|
// Tracks the velocity of a touch to help filter out the touches that move too fast.
|
||||||
|
@Nullable private VelocityTracker mVelocityTracker;
|
||||||
|
// The ID of the pointer for which ACTION_DOWN has occurred. -1 means no pointer is active.
|
||||||
|
private int mActivePointerId;
|
||||||
|
// The timestamp of the most recent touch log.
|
||||||
|
private long mTouchLogTime;
|
||||||
|
|
||||||
@Nullable private UdfpsView mView;
|
@Nullable private UdfpsView mView;
|
||||||
// Indicates whether the overlay has been requested.
|
// Indicates whether the overlay has been requested.
|
||||||
private boolean mIsOverlayRequested;
|
private boolean mIsOverlayRequested;
|
||||||
@@ -136,12 +148,10 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting final StatusBar.ExpansionChangedListener mStatusBarExpansionListener =
|
||||||
final StatusBar.ExpansionChangedListener mStatusBarExpansionListener =
|
|
||||||
(expansion, expanded) -> mView.onExpansionChanged(expansion, expanded);
|
(expansion, expanded) -> mView.onExpansionChanged(expansion, expanded);
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting final StatusBarStateController.StateListener mStatusBarStateListener =
|
||||||
final StatusBarStateController.StateListener mStatusBarStateListener =
|
|
||||||
new StatusBarStateController.StateListener() {
|
new StatusBarStateController.StateListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onStateChanged(int newState) {
|
public void onStateChanged(int newState) {
|
||||||
@@ -149,33 +159,87 @@ public class UdfpsController implements DozeReceiver, HbmCallback {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static float computePointerSpeed(@NonNull VelocityTracker tracker, int pointerId) {
|
||||||
|
final float vx = tracker.getXVelocity(pointerId);
|
||||||
|
final float vy = tracker.getYVelocity(pointerId);
|
||||||
|
return (float) Math.sqrt(Math.pow(vx, 2.0) + Math.pow(vy, 2.0));
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
private final UdfpsView.OnTouchListener mOnTouchListener = (v, event) -> {
|
private final UdfpsView.OnTouchListener mOnTouchListener = (view, event) -> {
|
||||||
UdfpsView view = (UdfpsView) v;
|
UdfpsView udfpsView = (UdfpsView) view;
|
||||||
final boolean isFingerDown = view.isIlluminationRequested();
|
final boolean isFingerDown = udfpsView.isIlluminationRequested();
|
||||||
switch (event.getAction()) {
|
boolean handled = false;
|
||||||
|
switch (event.getActionMasked()) {
|
||||||
case MotionEvent.ACTION_DOWN:
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
// To simplify the lifecycle of the velocity tracker, make sure it's never null
|
||||||
|
// after ACTION_DOWN, and always null after ACTION_CANCEL or ACTION_UP.
|
||||||
|
if (mVelocityTracker == null) {
|
||||||
|
mVelocityTracker = VelocityTracker.obtain();
|
||||||
|
} else {
|
||||||
|
// ACTION_UP or ACTION_CANCEL is not guaranteed to be called before a new
|
||||||
|
// ACTION_DOWN, in that case we should just reuse the old instance.
|
||||||
|
mVelocityTracker.clear();
|
||||||
|
}
|
||||||
|
// TODO: move isWithinSensorArea to UdfpsController.
|
||||||
|
if (udfpsView.isWithinSensorArea(event.getX(), event.getY())) {
|
||||||
|
// The pointer that causes ACTION_DOWN is always at index 0.
|
||||||
|
// We need to persist its ID to track it during ACTION_MOVE that could include
|
||||||
|
// data for many other pointers because of multi-touch support.
|
||||||
|
mActivePointerId = event.getPointerId(0);
|
||||||
|
mVelocityTracker.addMovement(event);
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case MotionEvent.ACTION_MOVE:
|
case MotionEvent.ACTION_MOVE:
|
||||||
final boolean isValidTouch = view.isValidTouch(event.getX(), event.getY(),
|
final int idx = event.findPointerIndex(mActivePointerId);
|
||||||
event.getPressure());
|
if (idx == event.getActionIndex()) {
|
||||||
if (!isFingerDown && isValidTouch) {
|
final float x = event.getX(idx);
|
||||||
onFingerDown((int) event.getX(), (int) event.getY(), event.getTouchMinor(),
|
final float y = event.getY(idx);
|
||||||
event.getTouchMajor());
|
if (udfpsView.isWithinSensorArea(x, y)) {
|
||||||
} else if (isFingerDown && !isValidTouch) {
|
mVelocityTracker.addMovement(event);
|
||||||
|
// Compute pointer velocity in pixels per second.
|
||||||
|
mVelocityTracker.computeCurrentVelocity(1000);
|
||||||
|
// Compute pointer speed from X and Y velocities.
|
||||||
|
final float v = computePointerSpeed(mVelocityTracker, mActivePointerId);
|
||||||
|
final float minor = event.getTouchMinor(idx);
|
||||||
|
final float major = event.getTouchMajor(idx);
|
||||||
|
final String touchInfo = String.format("minor: %.1f, major: %.1f, v: %.1f",
|
||||||
|
minor, major, v);
|
||||||
|
final long sinceLastLog = SystemClock.elapsedRealtime() - mTouchLogTime;
|
||||||
|
if (!isFingerDown) {
|
||||||
|
onFingerDown((int) x, (int) y, minor, major);
|
||||||
|
Log.v(TAG, "onTouch | finger down: " + touchInfo);
|
||||||
|
mTouchLogTime = SystemClock.elapsedRealtime();
|
||||||
|
handled = true;
|
||||||
|
} else if (sinceLastLog >= MIN_TOUCH_LOG_INTERVAL) {
|
||||||
|
Log.v(TAG, "onTouch | finger move: " + touchInfo);
|
||||||
|
mTouchLogTime = SystemClock.elapsedRealtime();
|
||||||
|
}
|
||||||
|
} else if (isFingerDown) {
|
||||||
|
Log.v(TAG, "onTouch | finger outside");
|
||||||
onFingerUp();
|
onFingerUp();
|
||||||
}
|
}
|
||||||
return true;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case MotionEvent.ACTION_UP:
|
case MotionEvent.ACTION_UP:
|
||||||
case MotionEvent.ACTION_CANCEL:
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
if (mVelocityTracker != null) {
|
||||||
|
mVelocityTracker.recycle();
|
||||||
|
mVelocityTracker = null;
|
||||||
|
}
|
||||||
if (isFingerDown) {
|
if (isFingerDown) {
|
||||||
|
Log.v(TAG, "onTouch | finger up");
|
||||||
onFingerUp();
|
onFingerUp();
|
||||||
}
|
}
|
||||||
return true;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false;
|
// Do nothing.
|
||||||
}
|
}
|
||||||
|
return handled;
|
||||||
};
|
};
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
|
||||||
@@ -92,6 +93,12 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin
|
|||||||
mIlluminationRequested = false;
|
mIlluminationRequested = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't propagate any touch events to the child views.
|
||||||
|
@Override
|
||||||
|
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onFinishInflate() {
|
protected void onFinishInflate() {
|
||||||
mHbmSurfaceView = findViewById(R.id.hbm_view);
|
mHbmSurfaceView = findViewById(R.id.hbm_view);
|
||||||
@@ -179,7 +186,7 @@ public class UdfpsView extends FrameLayout implements DozeReceiver, UdfpsIllumin
|
|||||||
postInvalidate();
|
postInvalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isValidTouch(float x, float y, float pressure) {
|
boolean isWithinSensorArea(float x, float y) {
|
||||||
// The X and Y coordinates of the sensor's center.
|
// The X and Y coordinates of the sensor's center.
|
||||||
final PointF translation = mAnimationView.getTouchTranslation();
|
final PointF translation = mAnimationView.getTouchTranslation();
|
||||||
final float cx = mSensorRect.centerX() + translation.x;
|
final float cx = mSensorRect.centerX() + translation.x;
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
|||||||
public void fingerDown() throws RemoteException {
|
public void fingerDown() throws RemoteException {
|
||||||
// Configure UdfpsView to accept the ACTION_DOWN event
|
// Configure UdfpsView to accept the ACTION_DOWN event
|
||||||
when(mUdfpsView.isIlluminationRequested()).thenReturn(false);
|
when(mUdfpsView.isIlluminationRequested()).thenReturn(false);
|
||||||
when(mUdfpsView.isValidTouch(anyFloat(), anyFloat(), anyFloat())).thenReturn(true);
|
when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
|
||||||
|
|
||||||
// GIVEN that the overlay is showing
|
// GIVEN that the overlay is showing
|
||||||
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
|
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
|
||||||
@@ -187,9 +187,12 @@ public class UdfpsControllerTest extends SysuiTestCase {
|
|||||||
mFgExecutor.runAllReady();
|
mFgExecutor.runAllReady();
|
||||||
// WHEN ACTION_DOWN is received
|
// WHEN ACTION_DOWN is received
|
||||||
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
|
verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
|
||||||
MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
|
MotionEvent downEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_DOWN, 0, 0, 0);
|
||||||
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, event);
|
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
|
||||||
event.recycle();
|
downEvent.recycle();
|
||||||
|
MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
|
||||||
|
mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
|
||||||
|
moveEvent.recycle();
|
||||||
// THEN illumination begins
|
// THEN illumination begins
|
||||||
// AND onIlluminatedRunnable that notifies FingerprintManager is set
|
// AND onIlluminatedRunnable that notifies FingerprintManager is set
|
||||||
verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
|
verify(mUdfpsView).startIllumination(mOnIlluminatedRunnableCaptor.capture());
|
||||||
|
|||||||
Reference in New Issue
Block a user