From 59d04e6ea69dc0c81fceab601194d8c0a6238fa0 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 12 Aug 2020 18:05:42 -0700 Subject: [PATCH] Use system VelocityTracker instead of forking least squares algorithm Change-Id: I8e03cdd0942b9037054cd1955bdb6809c89f3ea2 --- .../quickstep/util/MotionPauseDetector.java | 144 ++---------------- .../launcher3/config/FeatureFlags.java | 6 +- 2 files changed, 19 insertions(+), 131 deletions(-) diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java index f60f7ad6d8..b86293607e 100644 --- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java +++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java @@ -15,12 +15,13 @@ */ package com.android.quickstep.util; -import static com.android.launcher3.config.FeatureFlags.ENABLE_LSQ_VELOCITY_PROVIDER; +import static com.android.launcher3.config.FeatureFlags.ENABLE_SYSTEM_VELOCITY_PROVIDER; import android.content.Context; import android.content.res.Resources; import android.util.Log; import android.view.MotionEvent; +import android.view.VelocityTracker; import com.android.launcher3.Alarm; import com.android.launcher3.R; @@ -92,8 +93,8 @@ public class MotionPauseDetector { mForcePauseTimeout = new Alarm(); mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */)); mMakePauseHarderToTrigger = makePauseHarderToTrigger; - mVelocityProvider = ENABLE_LSQ_VELOCITY_PROVIDER.get() - ? new LSqVelocityProvider(axis) : new LinearVelocityProvider(axis); + mVelocityProvider = ENABLE_SYSTEM_VELOCITY_PROVIDER.get() + ? new SystemVelocityProvider(axis) : new LinearVelocityProvider(axis); } /** @@ -264,141 +265,28 @@ public class MotionPauseDetector { } } - /** - * Java implementation of {@link android.view.VelocityTracker} using the Least Square (deg 2) - * algorithm. - */ - private static class LSqVelocityProvider implements VelocityProvider { - - // Maximum age of a motion event to be considered when calculating the velocity. - private static final long HORIZON_MS = 100; - // Number of samples to keep. - private static final int HISTORY_SIZE = 20; - - // Position history are stored in a circular array - private final long[] mHistoricTimes = new long[HISTORY_SIZE]; - private final float[] mHistoricPos = new float[HISTORY_SIZE]; - private int mHistoryCount = 0; - private int mHistoryStart = 0; + private static class SystemVelocityProvider implements VelocityProvider { + private final VelocityTracker mVelocityTracker; private final int mAxis; - LSqVelocityProvider(int axis) { + SystemVelocityProvider(int axis) { + mVelocityTracker = VelocityTracker.obtain(); mAxis = axis; } @Override - public void clear() { - mHistoryCount = mHistoryStart = 0; - } - - private void addPositionAndTime(long eventTime, float eventPosition) { - mHistoricTimes[mHistoryStart] = eventTime; - mHistoricPos[mHistoryStart] = eventPosition; - mHistoryStart++; - if (mHistoryStart >= HISTORY_SIZE) { - mHistoryStart = 0; - } - mHistoryCount = Math.min(HISTORY_SIZE, mHistoryCount + 1); + public Float addMotionEvent(MotionEvent ev, int pointer) { + mVelocityTracker.addMovement(ev); + mVelocityTracker.computeCurrentVelocity(1); // px / ms + return mAxis == MotionEvent.AXIS_X + ? mVelocityTracker.getXVelocity(pointer) + : mVelocityTracker.getYVelocity(pointer); } @Override - public Float addMotionEvent(MotionEvent ev, int pointer) { - // Add all historic points - int historyCount = ev.getHistorySize(); - for (int i = 0; i < historyCount; i++) { - addPositionAndTime( - ev.getHistoricalEventTime(i), ev.getHistoricalAxisValue(mAxis, pointer, i)); - } - - // Start index for the last position (about to be added) - int eventStartIndex = mHistoryStart; - addPositionAndTime(ev.getEventTime(), ev.getAxisValue(mAxis, pointer)); - return solveUnweightedLeastSquaresDeg2(eventStartIndex); - } - - /** - * Solves the instantaneous velocity. - * Based on solveUnweightedLeastSquaresDeg2 in VelocityTracker.cpp - */ - private Float solveUnweightedLeastSquaresDeg2(final int pointPos) { - final long eventTime = mHistoricTimes[pointPos]; - - float sxi = 0, sxiyi = 0, syi = 0, sxi2 = 0, sxi3 = 0, sxi2yi = 0, sxi4 = 0; - int count = 0; - for (int i = 0; i < mHistoryCount; i++) { - int index = pointPos - i; - if (index < 0) { - index += HISTORY_SIZE; - } - - long time = mHistoricTimes[index]; - long age = eventTime - time; - if (age > HORIZON_MS) { - break; - } - count++; - float xi = -age; - - float yi = mHistoricPos[index]; - float xi2 = xi * xi; - float xi3 = xi2 * xi; - float xi4 = xi3 * xi; - float xiyi = xi * yi; - float xi2yi = xi2 * yi; - - sxi += xi; - sxi2 += xi2; - sxiyi += xiyi; - sxi2yi += xi2yi; - syi += yi; - sxi3 += xi3; - sxi4 += xi4; - } - - if (count < 3) { - // Too few samples - switch (count) { - case 2: { - int endPos = pointPos - 1; - if (endPos < 0) { - endPos += HISTORY_SIZE; - } - long denominator = eventTime - mHistoricTimes[endPos]; - if (denominator != 0) { - return (mHistoricPos[pointPos] - mHistoricPos[endPos]) / denominator; - } - } - // fall through - case 1: - return 0f; - default: - return null; - } - } - - float Sxx = sxi2 - sxi * sxi / count; - float Sxy = sxiyi - sxi * syi / count; - float Sxx2 = sxi3 - sxi * sxi2 / count; - float Sx2y = sxi2yi - sxi2 * syi / count; - float Sx2x2 = sxi4 - sxi2 * sxi2 / count; - - float denominator = Sxx * Sx2x2 - Sxx2 * Sxx2; - if (denominator == 0) { - // division by 0 when computing velocity - return null; - } - // Compute a - // float numerator = Sx2y*Sxx - Sxy*Sxx2; - - // Compute b - float numerator = Sxy * Sx2x2 - Sx2y * Sxx2; - float b = numerator / denominator; - - // Compute c - // float c = syi/count - b * sxi/count - a * sxi2/count; - - return b; + public void clear() { + mVelocityTracker.clear(); } } } diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index 0ab74afd87..74a3a272d2 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -161,9 +161,9 @@ public final class FeatureFlags { "ENABLE_UNIVERSAL_SMARTSPACE", false, "Replace Smartspace with a version rendered by System UI."); - public static final BooleanFlag ENABLE_LSQ_VELOCITY_PROVIDER = getDebugFlag( - "ENABLE_LSQ_VELOCITY_PROVIDER", true, - "Use Least Square algorithm for motion pause detection."); + public static final BooleanFlag ENABLE_SYSTEM_VELOCITY_PROVIDER = getDebugFlag( + "ENABLE_SYSTEM_VELOCITY_PROVIDER", true, + "Use system VelocityTracker's algorithm for motion pause detection."); public static final BooleanFlag ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS = getDebugFlag(