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

Commit 510caf30 authored by Mindy Pereira's avatar Mindy Pereira Committed by Android (Google) Code Review
Browse files

Merge "Add doubletap swipe to scalegesturedetector" into klp-dev

parents 3f8da091 e8ce8ba2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -27175,6 +27175,7 @@ package android.view {
    method public long getTimeDelta();
    method public boolean isInProgress();
    method public boolean onTouchEvent(android.view.MotionEvent);
    method public void setQuickScaleEnabled(boolean);
  }
  public static abstract interface ScaleGestureDetector.OnScaleGestureListener {
+119 −13
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ package android.view;

import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
import android.os.Handler;
import android.os.SystemClock;
import android.util.FloatMath;

@@ -128,6 +130,8 @@ public class ScaleGestureDetector {
    private float mFocusX;
    private float mFocusY;

    private boolean mDoubleTapScales;

    private float mCurrSpan;
    private float mPrevSpan;
    private float mInitialSpan;
@@ -148,9 +152,14 @@ public class ScaleGestureDetector {
    private int mTouchHistoryDirection;
    private long mTouchHistoryLastAcceptedTime;
    private int mTouchMinMajor;
    private MotionEvent mDoubleTapEvent;
    private int mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
    private final Handler mHandler;

    private static final long TOUCH_STABILIZE_TIME = 128; // ms
    private static final int TOUCH_MIN_MAJOR = 48; // dp
    private static final int DOUBLE_TAP_MODE_NONE = 0;
    private static final int DOUBLE_TAP_MODE_IN_PROGRESS = 1;


    /**
     * Consistency verifier for debugging purposes.
@@ -158,8 +167,37 @@ public class ScaleGestureDetector {
    private final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
            InputEventConsistencyVerifier.isInstrumentationEnabled() ?
                    new InputEventConsistencyVerifier(this, 0) : null;
    private GestureDetector mGestureDetector;

    private boolean mEventBeforeOrAboveStartingGestureEvent;

    /**
     * Creates a ScaleGestureDetector with the supplied listener.
     * You may only use this constructor from a {@link android.os.Looper Looper} thread.
     *
     * @param context the application's context
     * @param listener the listener invoked for all the callbacks, this must
     * not be null.
     *
     * @throws NullPointerException if {@code listener} is null.
     */
    public ScaleGestureDetector(Context context, OnScaleGestureListener listener) {
        this(context, listener, null);
    }

    /**
     * Creates a ScaleGestureDetector with the supplied listener.
     * @see android.os.Handler#Handler()
     *
     * @param context the application's context
     * @param listener the listener invoked for all the callbacks, this must
     * not be null.
     * @param handler the handler to use for running deferred listener events.
     *
     * @throws NullPointerException if {@code listener} is null.
     */
    public ScaleGestureDetector(Context context, OnScaleGestureListener listener,
            Handler handler) {
        mContext = context;
        mListener = listener;
        mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
@@ -167,8 +205,12 @@ public class ScaleGestureDetector {
        final Resources res = context.getResources();
        mTouchMinMajor = res.getDimensionPixelSize(
                com.android.internal.R.dimen.config_minScalingTouchMajor);
        mMinSpan = res.getDimensionPixelSize(
                com.android.internal.R.dimen.config_minScalingSpan);
        mMinSpan = res.getDimensionPixelSize(com.android.internal.R.dimen.config_minScalingSpan);
        mHandler = handler;
        // Quick scale is enabled by default after JB_MR2
        if (context.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN_MR2) {
            setQuickScaleEnabled(true);
        }
    }

    /**
@@ -263,8 +305,14 @@ public class ScaleGestureDetector {

        final int action = event.getActionMasked();

        // Forward the event to check for double tap gesture
        if (mDoubleTapScales) {
            mGestureDetector.onTouchEvent(event);
        }

        final boolean streamComplete = action == MotionEvent.ACTION_UP ||
                action == MotionEvent.ACTION_CANCEL;

        if (action == MotionEvent.ACTION_DOWN || streamComplete) {
            // Reset any scale in progress with the listener.
            // If it's an ACTION_DOWN we're beginning a new event stream.
@@ -273,6 +321,7 @@ public class ScaleGestureDetector {
                mListener.onScaleEnd(this);
                mInProgress = false;
                mInitialSpan = 0;
                mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
            }

            if (streamComplete) {
@@ -284,21 +333,37 @@ public class ScaleGestureDetector {
        final boolean configChanged = action == MotionEvent.ACTION_DOWN ||
                action == MotionEvent.ACTION_POINTER_UP ||
                action == MotionEvent.ACTION_POINTER_DOWN;


        final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP;
        final int skipIndex = pointerUp ? event.getActionIndex() : -1;

        // Determine focal point
        float sumX = 0, sumY = 0;
        final int count = event.getPointerCount();
        final int div = pointerUp ? count - 1 : count;
        final float focusX;
        final float focusY;
        if (mDoubleTapMode == DOUBLE_TAP_MODE_IN_PROGRESS) {
            // In double tap mode, the focal pt is always where the double tap
            // gesture started
            focusX = mDoubleTapEvent.getX();
            focusY = mDoubleTapEvent.getY();
            if (event.getY() < focusY) {
                mEventBeforeOrAboveStartingGestureEvent = true;
            } else {
                mEventBeforeOrAboveStartingGestureEvent = false;
            }
        } else {
            for (int i = 0; i < count; i++) {
                if (skipIndex == i) continue;
                sumX += event.getX(i);
                sumY += event.getY(i);
            }
        final int div = pointerUp ? count - 1 : count;
        final float focusX = sumX / div;
        final float focusY = sumY / div;

            focusX = sumX / div;
            focusY = sumY / div;
        }

        addTouchHistory(event);

@@ -320,7 +385,12 @@ public class ScaleGestureDetector {
        // the focal point.
        final float spanX = devX * 2;
        final float spanY = devY * 2;
        final float span = FloatMath.sqrt(spanX * spanX + spanY * spanY);
        final float span;
        if (inDoubleTapMode()) {
            span = spanY;
        } else {
            span = FloatMath.sqrt(spanX * spanX + spanY * spanY);
        }

        // Dispatch begin/end events as needed.
        // If the configuration changes, notify the app to reset its current state by beginning
@@ -328,10 +398,11 @@ public class ScaleGestureDetector {
        final boolean wasInProgress = mInProgress;
        mFocusX = focusX;
        mFocusY = focusY;
        if (mInProgress && (span < mMinSpan || configChanged)) {
        if (!inDoubleTapMode() && mInProgress && (span < mMinSpan || configChanged)) {
            mListener.onScaleEnd(this);
            mInProgress = false;
            mInitialSpan = span;
            mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
        }
        if (configChanged) {
            mPrevSpanX = mCurrSpanX = spanX;
@@ -354,6 +425,7 @@ public class ScaleGestureDetector {
            mCurrSpan = span;

            boolean updatePrev = true;

            if (mInProgress) {
                updatePrev = mListener.onScale(this);
            }
@@ -369,6 +441,34 @@ public class ScaleGestureDetector {
        return true;
    }


    private boolean inDoubleTapMode() {
        return mDoubleTapMode == DOUBLE_TAP_MODE_IN_PROGRESS;
    }

    /**
     * Set whether the associated {@link OnScaleGestureListener} should receive onScale callbacks
     * when the user performs a doubleTap followed by a swipe. Note that this is enabled by default
     * if the app targets API 19 and newer.
     * @param scales true to enable quick scaling, false to disable
     */
    public void setQuickScaleEnabled(boolean scales) {
        mDoubleTapScales = scales;
        if (mDoubleTapScales && mGestureDetector == null) {
            GestureDetector.SimpleOnGestureListener gestureListener =
                    new GestureDetector.SimpleOnGestureListener() {
                        @Override
                        public boolean onDoubleTap(MotionEvent e) {
                            // Double tap: start watching for a swipe
                            mDoubleTapEvent = e;
                            mDoubleTapMode = DOUBLE_TAP_MODE_IN_PROGRESS;
                            return true;
                        }
            };
            mGestureDetector = new GestureDetector(mContext, gestureListener, mHandler);
        }
    }

    /**
     * Returns {@code true} if a scale gesture is in progress.
     */
@@ -472,6 +572,12 @@ public class ScaleGestureDetector {
     * @return The current scaling factor.
     */
    public float getScaleFactor() {
        if (inDoubleTapMode() && mEventBeforeOrAboveStartingGestureEvent) {
            // Drag is moving up; the further away from the gesture
            // start, the smaller the span should be, the closer,
            // the larger the span, and therefore the larger the scale
            return (1 / mCurrSpan) / (1 / mPrevSpan);
        }
        return mPrevSpan > 0 ? mCurrSpan / mPrevSpan : 1;
    }