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

Commit ba941516 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Use system VelocityTracker instead of forking least squares algorithm"...

Merge "Use system VelocityTracker instead of forking least squares algorithm" into ub-launcher3-master
parents 58a1689c 59d04e6e
Loading
Loading
Loading
Loading
+16 −128
Original line number Diff line number Diff line
@@ -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);
        }

        @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;
            mVelocityTracker.addMovement(ev);
            mVelocityTracker.computeCurrentVelocity(1); // px / ms
            return mAxis == MotionEvent.AXIS_X
                    ? mVelocityTracker.getXVelocity(pointer)
                    : mVelocityTracker.getYVelocity(pointer);
        }

                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;
        @Override
        public void clear() {
            mVelocityTracker.clear();
        }
    }
}
+3 −3
Original line number Diff line number Diff line
@@ -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(