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

Commit 67c8fa68 authored by Yeabkal Wubshit's avatar Yeabkal Wubshit
Browse files

Conform to 1D VelocityTracker

The native VelocityTracker has been refactored to allow support of axes
beyond X and Y axes. To conform to this change, we are updating calls to
the native VelocityTracker. Furthermore, to support independent velocity
tracking for separate axes, we are updating the native/JNI methods
accordingly. With these changes, supporting new axes for velocity
tracking would only require changes at the native VelocityTracker level
only (besides creating a public API for our clients).

Bug: 32830165
Test: android.view.cts.VelocityTrackerTest unaffected; touch fling works

Change-Id: Ib0be0fc38c315ade2475cd53597a846e58016d14
parent 1fd7ea10
Loading
Loading
Loading
Loading
+21 −44
Original line number Diff line number Diff line
@@ -180,9 +180,9 @@ public final class VelocityTracker {
    private static native void nativeClear(long ptr);
    private static native void nativeAddMovement(long ptr, MotionEvent event);
    private static native void nativeComputeCurrentVelocity(long ptr, int units, float maxVelocity);
    private static native float nativeGetXVelocity(long ptr, int id);
    private static native float nativeGetYVelocity(long ptr, int id);
    private static native boolean nativeGetEstimator(long ptr, int id, Estimator outEstimator);
    private static native float nativeGetVelocity(long ptr, int axis, int id);
    private static native boolean nativeGetEstimator(
            long ptr, int axis, int id, Estimator outEstimator);

    static {
        // Strategy string and IDs mapping lookup.
@@ -361,7 +361,7 @@ public final class VelocityTracker {
     * @return The previously computed X velocity.
     */
    public float getXVelocity() {
        return nativeGetXVelocity(mPtr, ACTIVE_POINTER_ID);
        return getXVelocity(ACTIVE_POINTER_ID);
    }

    /**
@@ -371,7 +371,7 @@ public final class VelocityTracker {
     * @return The previously computed Y velocity.
     */
    public float getYVelocity() {
        return nativeGetYVelocity(mPtr, ACTIVE_POINTER_ID);
        return getYVelocity(ACTIVE_POINTER_ID);
    }

    /**
@@ -382,7 +382,7 @@ public final class VelocityTracker {
     * @return The previously computed X velocity.
     */
    public float getXVelocity(int id) {
        return nativeGetXVelocity(mPtr, id);
        return nativeGetVelocity(mPtr, MotionEvent.AXIS_X, id);
    }

    /**
@@ -393,7 +393,7 @@ public final class VelocityTracker {
     * @return The previously computed Y velocity.
     */
    public float getYVelocity(int id) {
        return nativeGetYVelocity(mPtr, id);
        return nativeGetVelocity(mPtr, MotionEvent.AXIS_Y, id);
    }

    /**
@@ -403,6 +403,8 @@ public final class VelocityTracker {
     * It is not necessary to call {@link #computeCurrentVelocity(int)} before calling
     * this method.
     *
     * @param axis Which axis's velocity to return.
     *             Should be one of the axes defined in {@link MotionEvent}.
     * @param id Which pointer's velocity to return.
     * @param outEstimator The estimator to populate.
     * @return True if an estimator was obtained, false if there is no information
@@ -410,11 +412,11 @@ public final class VelocityTracker {
     *
     * @hide For internal use only.  Not a final API.
     */
    public boolean getEstimator(int id, Estimator outEstimator) {
    public boolean getEstimator(int axis, int id, Estimator outEstimator) {
        if (outEstimator == null) {
            throw new IllegalArgumentException("outEstimator must not be null");
        }
        return nativeGetEstimator(mPtr, id, outEstimator);
        return nativeGetEstimator(mPtr, axis, id, outEstimator);
    }

    /**
@@ -434,16 +436,9 @@ public final class VelocityTracker {
        private static final int MAX_DEGREE = 4;

        /**
         * Polynomial coefficients describing motion in X.
         * Polynomial coefficients describing motion.
         */
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
        public final float[] xCoeff = new float[MAX_DEGREE + 1];

        /**
         * Polynomial coefficients describing motion in Y.
         */
        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
        public final float[] yCoeff = new float[MAX_DEGREE + 1];
        public final float[] coeff = new float[MAX_DEGREE + 1];

        /**
         * Polynomial degree, or zero if only position information is available.
@@ -458,39 +453,21 @@ public final class VelocityTracker {
        public float confidence;

        /**
         * Gets an estimate of the X position of the pointer at the specified time point.
         * Gets an estimate of the position of the pointer at the specified time point.
         * @param time The time point in seconds, 0 is the last recorded time.
         * @return The estimated X coordinate.
         */
        public float estimateX(float time) {
            return estimate(time, xCoeff);
        }

        /**
         * Gets an estimate of the Y position of the pointer at the specified time point.
         * @param time The time point in seconds, 0 is the last recorded time.
         * @return The estimated Y coordinate.
         */
        public float estimateY(float time) {
            return estimate(time, yCoeff);
        }

        /**
         * Gets the X coefficient with the specified index.
         * @param index The index of the coefficient to return.
         * @return The X coefficient, or 0 if the index is greater than the degree.
         * @return The estimated axis value.
         */
        public float getXCoeff(int index) {
            return index <= degree ? xCoeff[index] : 0;
        public float estimate(float time) {
            return estimate(time, coeff);
        }

        /**
         * Gets the Y coefficient with the specified index.
         * Gets the coefficient with the specified index.
         * @param index The index of the coefficient to return.
         * @return The Y coefficient, or 0 if the index is greater than the degree.
         * @return The coefficient, or 0 if the index is greater than the degree.
         */
        public float getYCoeff(int index) {
            return index <= degree ? yCoeff[index] : 0;
        public float getCoeff(int index) {
            return index <= degree ? coeff[index] : 0;
        }

        private float estimate(float time, float[] c) {
+8 −4
Original line number Diff line number Diff line
@@ -90,8 +90,10 @@ public class PointerLocationView extends View implements InputDeviceListener,
        private float mBoundingBottom;

        // Position estimator.
        private VelocityTracker.Estimator mEstimator = new VelocityTracker.Estimator();
        private VelocityTracker.Estimator mAltEstimator = new VelocityTracker.Estimator();
        private VelocityTracker.Estimator mEstimatorX = new VelocityTracker.Estimator();
        private VelocityTracker.Estimator mAltEstimatorX = new VelocityTracker.Estimator();
        private VelocityTracker.Estimator mEstimatorY = new VelocityTracker.Estimator();
        private VelocityTracker.Estimator mAltEstimatorY = new VelocityTracker.Estimator();

        @UnsupportedAppUsage
        public PointerState() {
@@ -679,11 +681,13 @@ public class PointerLocationView extends View implements InputDeviceListener,
                ps.addTrace(coords.x, coords.y, true);
                ps.mXVelocity = mVelocity.getXVelocity(id);
                ps.mYVelocity = mVelocity.getYVelocity(id);
                mVelocity.getEstimator(id, ps.mEstimator);
                mVelocity.getEstimator(MotionEvent.AXIS_X, id, ps.mEstimatorX);
                mVelocity.getEstimator(MotionEvent.AXIS_Y, id, ps.mEstimatorY);
                if (mAltVelocity != null) {
                    ps.mAltXVelocity = mAltVelocity.getXVelocity(id);
                    ps.mAltYVelocity = mAltVelocity.getYVelocity(id);
                    mAltVelocity.getEstimator(id, ps.mAltEstimator);
                    mAltVelocity.getEstimator(MotionEvent.AXIS_X, id, ps.mAltEstimatorX);
                    mAltVelocity.getEstimator(MotionEvent.AXIS_Y, id, ps.mAltEstimatorY);
                }
                ps.mToolType = event.getToolType(i);

+27 −89
Original line number Diff line number Diff line
@@ -32,8 +32,7 @@ namespace android {
static const int ACTIVE_POINTER_ID = -1;

static struct {
    jfieldID xCoeff;
    jfieldID yCoeff;
    jfieldID coeff;
    jfieldID degree;
    jfieldID confidence;
} gEstimatorClassInfo;
@@ -47,28 +46,22 @@ public:

    void clear();
    void addMovement(const MotionEvent* event);
    // TODO(b/32830165): consider supporting an overload that supports computing velocity only for
    // a subset of the supported axes.
    void computeCurrentVelocity(int32_t units, float maxVelocity);
    void getVelocity(int32_t id, float* outVx, float* outVy);
    bool getEstimator(int32_t id, VelocityTracker::Estimator* outEstimator);
    float getVelocity(int32_t axis, int32_t id);
    bool getEstimator(int32_t axis, int32_t id, VelocityTracker::Estimator* outEstimator);

private:
    struct Velocity {
        float vx, vy;
    };

    VelocityTracker mVelocityTracker;
    int32_t mActivePointerId;
    BitSet32 mCalculatedIdBits;
    Velocity mCalculatedVelocity[MAX_POINTERS];
    VelocityTracker::ComputedVelocity mComputedVelocity;
};

VelocityTrackerState::VelocityTrackerState(const VelocityTracker::Strategy strategy)
      : mVelocityTracker(strategy), mActivePointerId(-1) {}
      : mVelocityTracker(strategy) {}

void VelocityTrackerState::clear() {
    mVelocityTracker.clear();
    mActivePointerId = -1;
    mCalculatedIdBits.clear();
}

void VelocityTrackerState::addMovement(const MotionEvent* event) {
@@ -76,61 +69,20 @@ void VelocityTrackerState::addMovement(const MotionEvent* event) {
}

void VelocityTrackerState::computeCurrentVelocity(int32_t units, float maxVelocity) {
    BitSet32 idBits(mVelocityTracker.getCurrentPointerIdBits());
    mCalculatedIdBits = idBits;

    for (uint32_t index = 0; !idBits.isEmpty(); index++) {
        uint32_t id = idBits.clearFirstMarkedBit();

        float vx, vy;
        mVelocityTracker.getVelocity(id, &vx, &vy);

        vx = vx * units / 1000;
        vy = vy * units / 1000;

        if (vx > maxVelocity) {
            vx = maxVelocity;
        } else if (vx < -maxVelocity) {
            vx = -maxVelocity;
        }
        if (vy > maxVelocity) {
            vy = maxVelocity;
        } else if (vy < -maxVelocity) {
            vy = -maxVelocity;
        }

        Velocity& velocity = mCalculatedVelocity[index];
        velocity.vx = vx;
        velocity.vy = vy;
    }
    mVelocityTracker.populateComputedVelocity(mComputedVelocity, units, maxVelocity);
}

void VelocityTrackerState::getVelocity(int32_t id, float* outVx, float* outVy) {
float VelocityTrackerState::getVelocity(int32_t axis, int32_t id) {
    if (id == ACTIVE_POINTER_ID) {
        id = mVelocityTracker.getActivePointerId();
    }

    float vx, vy;
    if (id >= 0 && id <= MAX_POINTER_ID && mCalculatedIdBits.hasBit(id)) {
        uint32_t index = mCalculatedIdBits.getIndexOfBit(id);
        const Velocity& velocity = mCalculatedVelocity[index];
        vx = velocity.vx;
        vy = velocity.vy;
    } else {
        vx = 0;
        vy = 0;
    }

    if (outVx) {
        *outVx = vx;
    }
    if (outVy) {
        *outVy = vy;
    }
    return mComputedVelocity.getVelocity(axis, id).value_or(0);
}

bool VelocityTrackerState::getEstimator(int32_t id, VelocityTracker::Estimator* outEstimator) {
    return mVelocityTracker.getEstimator(id, outEstimator);
bool VelocityTrackerState::getEstimator(int32_t axis, int32_t id,
                                        VelocityTracker::Estimator* outEstimator) {
    return mVelocityTracker.getEstimator(axis, id, outEstimator);
}

// Return a strategy enum from integer value.
@@ -177,37 +129,25 @@ static void android_view_VelocityTracker_nativeComputeCurrentVelocity(JNIEnv* en
    state->computeCurrentVelocity(units, maxVelocity);
}

static jfloat android_view_VelocityTracker_nativeGetXVelocity(JNIEnv* env, jclass clazz,
        jlong ptr, jint id) {
static jfloat android_view_VelocityTracker_nativeGetVelocity(JNIEnv* env, jclass clazz, jlong ptr,
                                                             jint axis, jint id) {
    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
    float vx;
    state->getVelocity(id, &vx, NULL);
    return vx;
}

static jfloat android_view_VelocityTracker_nativeGetYVelocity(JNIEnv* env, jclass clazz,
        jlong ptr, jint id) {
    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
    float vy;
    state->getVelocity(id, NULL, &vy);
    return vy;
    return state->getVelocity(axis, id);
}

static jboolean android_view_VelocityTracker_nativeGetEstimator(JNIEnv* env, jclass clazz,
        jlong ptr, jint id, jobject outEstimatorObj) {
                                                                jlong ptr, jint axis, jint id,
                                                                jobject outEstimatorObj) {
    VelocityTrackerState* state = reinterpret_cast<VelocityTrackerState*>(ptr);
    VelocityTracker::Estimator estimator;
    bool result = state->getEstimator(id, &estimator);

    jfloatArray xCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj,
            gEstimatorClassInfo.xCoeff));
    jfloatArray yCoeffObj = jfloatArray(env->GetObjectField(outEstimatorObj,
            gEstimatorClassInfo.yCoeff));
    bool result = state->getEstimator(axis, id, &estimator);

    jfloatArray coeffObj =
            jfloatArray(env->GetObjectField(outEstimatorObj, gEstimatorClassInfo.coeff));

    env->SetFloatArrayRegion(xCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
            estimator.xCoeff);
    env->SetFloatArrayRegion(yCoeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
            estimator.yCoeff);
    env->SetFloatArrayRegion(coeffObj, 0, VelocityTracker::Estimator::MAX_DEGREE + 1,
                             estimator.coeff);
    env->SetIntField(outEstimatorObj, gEstimatorClassInfo.degree, estimator.degree);
    env->SetFloatField(outEstimatorObj, gEstimatorClassInfo.confidence, estimator.confidence);
    return result;
@@ -224,9 +164,8 @@ static const JNINativeMethod gVelocityTrackerMethods[] = {
         (void*)android_view_VelocityTracker_nativeAddMovement},
        {"nativeComputeCurrentVelocity", "(JIF)V",
         (void*)android_view_VelocityTracker_nativeComputeCurrentVelocity},
        {"nativeGetXVelocity", "(JI)F", (void*)android_view_VelocityTracker_nativeGetXVelocity},
        {"nativeGetYVelocity", "(JI)F", (void*)android_view_VelocityTracker_nativeGetYVelocity},
        {"nativeGetEstimator", "(JILandroid/view/VelocityTracker$Estimator;)Z",
        {"nativeGetVelocity", "(JII)F", (void*)android_view_VelocityTracker_nativeGetVelocity},
        {"nativeGetEstimator", "(JIILandroid/view/VelocityTracker$Estimator;)Z",
         (void*)android_view_VelocityTracker_nativeGetEstimator},
};

@@ -236,8 +175,7 @@ int register_android_view_VelocityTracker(JNIEnv* env) {

    jclass clazz = FindClassOrDie(env, "android/view/VelocityTracker$Estimator");

    gEstimatorClassInfo.xCoeff = GetFieldIDOrDie(env, clazz, "xCoeff", "[F");
    gEstimatorClassInfo.yCoeff = GetFieldIDOrDie(env, clazz, "yCoeff", "[F");
    gEstimatorClassInfo.coeff = GetFieldIDOrDie(env, clazz, "coeff", "[F");
    gEstimatorClassInfo.degree = GetFieldIDOrDie(env, clazz, "degree", "I");
    gEstimatorClassInfo.confidence = GetFieldIDOrDie(env, clazz, "confidence", "F");