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

Commit 2091e8f3 authored by Biswarup Pal's avatar Biswarup Pal
Browse files

Fix fling to Dpad events conversion for VirtualNavigationTouchpad

SyntheticTouchNavigationHandler in ViewRootImpl uses GestureDetector
to convert touch navigation flings into Dpad events, based on fling
velocity direction. GestureDetector internally uses VelocityTracker,
which uses LSQ2 for x and y axes by default. Since LSQ2 velocity
calculation has a known issue of miscalculating velocity direction,
we use impulse strategy for fling velocity calculation during the
conversion of fling to Dpad events for VirtualNavigationTouchpad.

Flag: android.companion.virtual.flags.impulse_velocity_strategy_for_touch_navigation
Test: atest VirtualNavigationTouchpadTest
Fixes: 338426241
Change-Id: I14c5bcd7848ff8c5c989023e518f5b8936df3d15
parent 29a0a880
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -128,3 +128,14 @@ flag {
    purpose: PURPOSE_BUGFIX
  }
}

flag {
  name: "impulse_velocity_strategy_for_touch_navigation"
  is_exported: true
  namespace: "virtual_devices"
  description: "Use impulse velocity strategy during conversion of touch navigation flings into Dpad events"
  bug: "338426241"
  metadata {
    purpose: PURPOSE_BUGFIX
  }
}
 No newline at end of file
+52 −20
Original line number Diff line number Diff line
@@ -26,11 +26,13 @@ import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFI
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UiContext;
import android.app.Activity;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.StrictMode;
import android.os.SystemClock;
@@ -298,6 +300,11 @@ public class GestureDetector {
     */
    private VelocityTracker mVelocityTracker;

    /**
     * Determines strategy for velocity calculation
     */
    private @VelocityTracker.VelocityTrackerStrategy int mVelocityTrackerStrategy;

    /**
     * Consistency verifier for debugging purposes.
     */
@@ -356,8 +363,8 @@ public class GestureDetector {
     *
     * @throws NullPointerException if {@code listener} is null.
     *
     * @deprecated Use {@link #GestureDetector(android.content.Context,
     *      android.view.GestureDetector.OnGestureListener, android.os.Handler)} instead.
     * @deprecated Use {@link #GestureDetector(Context, GestureDetector.OnGestureListener, Handler)}
     * instead.
     */
    @Deprecated
    public GestureDetector(@NonNull OnGestureListener listener, @Nullable Handler handler) {
@@ -367,15 +374,14 @@ public class GestureDetector {
    /**
     * Creates a GestureDetector with the supplied listener.
     * You may only use this constructor from a UI thread (this is the usual situation).
     * @see android.os.Handler#Handler()
     * @see Handler#Handler()
     *
     * @param listener the listener invoked for all the callbacks, this must
     * not be null.
     *
     * @throws NullPointerException if {@code listener} is null.
     *
     * @deprecated Use {@link #GestureDetector(android.content.Context,
     *      android.view.GestureDetector.OnGestureListener)} instead.
     * @deprecated Use {@link #GestureDetector(Context, GestureDetector.OnGestureListener)} instead.
     */
    @Deprecated
    public GestureDetector(@NonNull OnGestureListener listener) {
@@ -384,10 +390,10 @@ public class GestureDetector {

    /**
     * Creates a GestureDetector with the supplied listener.
     * You may only use this constructor from a {@link android.os.Looper} thread.
     * @see android.os.Handler#Handler()
     * You may only use this constructor from a {@link Looper} thread.
     * @see Handler#Handler()
     *
     * @param context An {@link android.app.Activity} or a {@link Context} created from
     * @param context An {@link Activity} or a {@link Context} created from
     * {@link Context#createWindowContext(int, Bundle)}
     * @param listener the listener invoked for all the callbacks, this must
     * not be null. If the listener implements the {@link OnDoubleTapListener} or
@@ -404,10 +410,10 @@ public class GestureDetector {

    /**
     * Creates a GestureDetector with the supplied listener that runs deferred events on the
     * thread associated with the supplied {@link android.os.Handler}.
     * @see android.os.Handler#Handler()
     * thread associated with the supplied {@link Handler}.
     * @see Handler#Handler()
     *
     * @param context An {@link android.app.Activity} or a {@link Context} created from
     * @param context An {@link Activity} or a {@link Context} created from
     * {@link Context#createWindowContext(int, Bundle)}
     * @param listener the listener invoked for all the callbacks, this must
     * not be null. If the listener implements the {@link OnDoubleTapListener} or
@@ -419,6 +425,31 @@ public class GestureDetector {
     */
    public GestureDetector(@Nullable @UiContext Context context,
            @NonNull OnGestureListener listener, @Nullable Handler handler) {
        this(context, listener, handler, VelocityTracker.VELOCITY_TRACKER_STRATEGY_DEFAULT);
    }

    /**
     * Creates a GestureDetector with the supplied listener that runs deferred events on the
     * thread associated with the supplied {@link Handler}.
     * @see Handler#Handler()
     *
     * @param context An {@link Activity} or a {@link Context} created from
     * {@link Context#createWindowContext(int, Bundle)}
     * @param listener the listener invoked for all the callbacks, this must
     * not be null. If the listener implements the {@link OnDoubleTapListener} or
     * {@link OnContextClickListener} then it will also be set as the listener for
     * these callbacks (for example when using the {@link SimpleOnGestureListener}).
     * @param handler the handler to use for running deferred listener events.
     * @param velocityTrackerStrategy strategy to use for velocity calculation of scroll/fling
     *                                events.
     *
     * @throws NullPointerException if {@code listener} is null.
     *
     * @hide
     */
    public GestureDetector(@Nullable @UiContext Context context,
            @NonNull OnGestureListener listener, @Nullable Handler handler,
            @VelocityTracker.VelocityTrackerStrategy int velocityTrackerStrategy) {
        if (handler != null) {
            mHandler = new GestureHandler(handler);
        } else {
@@ -431,15 +462,16 @@ public class GestureDetector {
        if (listener instanceof OnContextClickListener) {
            setContextClickListener((OnContextClickListener) listener);
        }
        mVelocityTrackerStrategy = velocityTrackerStrategy;
        init(context);
    }

    /**
     * Creates a GestureDetector with the supplied listener that runs deferred events on the
     * thread associated with the supplied {@link android.os.Handler}.
     * @see android.os.Handler#Handler()
     * thread associated with the supplied {@link Handler}.
     * @see Handler#Handler()
     *
     * @param context An {@link android.app.Activity} or a {@link Context} created from
     * @param context An {@link Activity} or a {@link Context} created from
     * {@link Context#createWindowContext(int, Bundle)}
     * @param listener the listener invoked for all the callbacks, this must
     * not be null.
@@ -547,7 +579,7 @@ public class GestureDetector {
        mCurrentMotionEvent = MotionEvent.obtain(ev);

        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
            mVelocityTracker = VelocityTracker.obtain(mVelocityTrackerStrategy);
        }
        mVelocityTracker.addMovement(ev);

+3 −1
Original line number Diff line number Diff line
@@ -264,7 +264,6 @@ public final class VelocityTracker {

    /**
     * Obtains a velocity tracker with the specified strategy.
     * For testing and comparison purposes only.
     *
     * @param strategy The strategy Id, VELOCITY_TRACKER_STRATEGY_DEFAULT to use the default.
     * @return The velocity tracker.
@@ -272,6 +271,9 @@ public final class VelocityTracker {
     * @hide
     */
    public static VelocityTracker obtain(int strategy) {
        if (strategy == VELOCITY_TRACKER_STRATEGY_DEFAULT) {
            return obtain();
        }
        return new VelocityTracker(strategy);
    }

+43 −36
Original line number Diff line number Diff line
@@ -8609,7 +8609,16 @@ public final class ViewRootImpl implements ViewParent,
        private int mPendingKeyMetaState;
        private final GestureDetector mGestureDetector = new GestureDetector(mContext,
        private final GestureDetector mGestureDetector;
        SyntheticTouchNavigationHandler() {
            super(true);
            int gestureDetectorVelocityStrategy =
                    android.companion.virtual.flags.Flags
                            .impulseVelocityStrategyForTouchNavigation()
                    ? VelocityTracker.VELOCITY_TRACKER_STRATEGY_IMPULSE
                    : VelocityTracker.VELOCITY_TRACKER_STRATEGY_DEFAULT;
            mGestureDetector = new GestureDetector(mContext,
                    new GestureDetector.OnGestureListener() {
                        @Override
                        public boolean onDown(@NonNull MotionEvent e) {
@@ -8620,7 +8629,6 @@ public final class ViewRootImpl implements ViewParent,
                        @Override
                        public void onShowPress(@NonNull MotionEvent e) {
                        }
                        @Override
@@ -8647,10 +8655,9 @@ public final class ViewRootImpl implements ViewParent,
                            dispatchFling(velocityX, velocityY, e2.getEventTime());
                            return true;
                        }
                });
        SyntheticTouchNavigationHandler() {
            super(true);
                    },
                    /* handler= */ null,
                    gestureDetectorVelocityStrategy);
        }
        public void process(MotionEvent event) {