Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d2c56525 authored by Sunny Goyal's avatar Sunny Goyal Committed by Android (Google) Code Review
Browse files

Merge "Using LeastSquaresVelocityTrackerStrategy for calculating velocity when...

Merge "Using LeastSquaresVelocityTrackerStrategy for calculating velocity when detecting motion pause events. This is the same logic used by the platform implementation VelocityTracker" into ub-launcher3-master
parents 7fa947cb a173193a
Loading
Loading
Loading
Loading
+137 −3
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
 */
package com.android.quickstep.util;

import static com.android.launcher3.config.FeatureFlags.ENABLE_LSQ_VELOCITY_PROVIDER;

import android.content.Context;
import android.content.res.Resources;
import android.view.MotionEvent;
@@ -85,7 +87,8 @@ public class MotionPauseDetector {
        mForcePauseTimeout = new Alarm();
        mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */));
        mMakePauseHarderToTrigger = makePauseHarderToTrigger;
        mVelocityProvider = new LinearVelocityProvider(axis);
        mVelocityProvider = ENABLE_LSQ_VELOCITY_PROVIDER.get()
                ? new LSqVelocityProvider(axis) : new LinearVelocityProvider(axis);
    }

    /**
@@ -106,8 +109,6 @@ public class MotionPauseDetector {
    /**
     * Computes velocity and acceleration to determine whether the motion is paused.
     * @param ev The motion being tracked.
     *
     * TODO: Use historical positions as well, e.g. {@link MotionEvent#getHistoricalY(int, int)}.
     */
    public void addPosition(MotionEvent ev) {
        addPosition(ev, 0);
@@ -248,4 +249,137 @@ public class MotionPauseDetector {
            mPreviousPosition = null;
        }
    }

    /**
     * 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 float[] mHistoricTimes = new float[HISTORY_SIZE];
        private final float[] mHistoricPos = new float[HISTORY_SIZE];
        private int mHistoryCount = 0;
        private int mHistoryStart = 0;

        private final int mAxis;

        LSqVelocityProvider(int axis) {
            mAxis = axis;
        }

        @Override
        public void clear() {
            mHistoryCount = mHistoryStart = 0;
        }

        private void addPositionAndTime(float eventTime, float eventPosition) {
            mHistoricTimes[mHistoryStart] = eventTime;
            mHistoricPos[mHistoryStart] = eventPosition;
            mHistoryStart++;
            if (mHistoryStart >= HISTORY_SIZE) {
                mHistoryStart = 0;
            }
            mHistoryCount = Math.min(HISTORY_SIZE, mHistoryCount + 1);
        }

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

                float time = mHistoricTimes[index];
                float 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
                if (count == 2) {
                    int endPos = pointPos - 1;
                    if (endPos < 0) {
                        endPos += HISTORY_SIZE;
                    }
                    float denominator = eventTime - mHistoricTimes[endPos];
                    if (denominator != 0) {
                        return (eventTime - mHistoricPos[endPos]) / denominator;

                    }
                }
                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;
        }
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -135,6 +135,10 @@ 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", false,
            "Use Least Square algorithm for motion pause detection.");

    public static void initialize(Context context) {
        synchronized (sDebugFlags) {
            for (DebugFlag flag : sDebugFlags) {