Merge "Refine the onTouch logic and log touch speed" into sc-dev

This commit is contained in:
TreeHugger Robot
2021-03-06 13:17:56 +00:00
committed by Android (Google) Code Review
3 changed files with 100 additions and 26 deletions

View File

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

View File

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

View File

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