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

Commit b0c9e74c authored by Yeabkal Wubshit's avatar Yeabkal Wubshit
Browse files

Add ViewConfiguration Fling Threshold APIs per InputDevice

The existing threshold APIs in ViewConfiguration were designed specific
for touch input. Without new min/max fling velocity APIs, devices that
are not touch screen will be using the existing min/max fling
thresholds. This prevents customizing fling behavior for different input
devices like rotary encoders, that wish to have fling behavior different
from touch screen devices.

The new API allows specifying min/max fling velocities per InputDevice.
This allows a more granular level of fling behavior control, allowing
each InputDevice to possibly define its own fling properties.

The presence of this API in ViewConfiguration (as opposed to in
InputDevice) allows setting global policies easily, where an OEM can
easily and globally configure fling for a set of devices (e.g. disable
fling for all rotary encoders).

Bug: 255845489
Test: CTS test
Change-Id: I6e08b2ed5e1959346530a1cc3cc3678480c5cdb7
parent e5fccdfb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -52430,7 +52430,9 @@ package android.view {
    method public int getScaledHoverSlop();
    method public int getScaledMaximumDrawingCacheSize();
    method public int getScaledMaximumFlingVelocity();
    method public int getScaledMaximumFlingVelocity(int, int, int);
    method public int getScaledMinimumFlingVelocity();
    method public int getScaledMinimumFlingVelocity(int, int, int);
    method public int getScaledMinimumScalingSpan();
    method public int getScaledOverflingDistance();
    method public int getScaledOverscrollDistance();
+116 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.hardware.input.InputManager;
import android.os.Build;
import android.os.Bundle;
import android.os.RemoteException;
@@ -232,6 +233,12 @@ public class ViewConfiguration {
     */
    private static final int MAXIMUM_FLING_VELOCITY = 8000;

    /** Value used as a minimum fling velocity, when fling is not supported. */
    private static final int NO_FLING_MIN_VELOCITY = Integer.MAX_VALUE;

    /** Value used as a maximum fling velocity, when fling is not supported. */
    private static final int NO_FLING_MAX_VELOCITY = Integer.MIN_VALUE;

    /**
     * Delay before dispatching a recurring accessibility event in milliseconds.
     * This delay guarantees that a recurring event will be send at most once
@@ -333,6 +340,8 @@ public class ViewConfiguration {
    private final int mFadingEdgeLength;
    private final int mMinimumFlingVelocity;
    private final int mMaximumFlingVelocity;
    private final int mMinimumRotaryEncoderFlingVelocity;
    private final int mMaximumRotaryEncoderFlingVelocity;
    private final int mScrollbarSize;
    private final int mTouchSlop;
    private final int mHandwritingSlop;
@@ -378,6 +387,8 @@ public class ViewConfiguration {
        mFadingEdgeLength = FADING_EDGE_LENGTH;
        mMinimumFlingVelocity = MINIMUM_FLING_VELOCITY;
        mMaximumFlingVelocity = MAXIMUM_FLING_VELOCITY;
        mMinimumRotaryEncoderFlingVelocity = MINIMUM_FLING_VELOCITY;
        mMaximumRotaryEncoderFlingVelocity = MAXIMUM_FLING_VELOCITY;
        mScrollbarSize = SCROLL_BAR_SIZE;
        mTouchSlop = TOUCH_SLOP;
        mHandwritingSlop = HANDWRITING_SLOP;
@@ -504,6 +515,19 @@ public class ViewConfiguration {
                com.android.internal.R.dimen.config_viewMinFlingVelocity);
        mMaximumFlingVelocity = res.getDimensionPixelSize(
                com.android.internal.R.dimen.config_viewMaxFlingVelocity);

        int configMinRotaryEncoderFlingVelocity = res.getDimensionPixelSize(
                com.android.internal.R.dimen.config_viewMinRotaryEncoderFlingVelocity);
        int configMaxRotaryEncoderFlingVelocity = res.getDimensionPixelSize(
                com.android.internal.R.dimen.config_viewMaxRotaryEncoderFlingVelocity);
        if (configMinRotaryEncoderFlingVelocity < 0 || configMaxRotaryEncoderFlingVelocity < 0) {
            mMinimumRotaryEncoderFlingVelocity = NO_FLING_MIN_VELOCITY;
            mMaximumRotaryEncoderFlingVelocity = NO_FLING_MAX_VELOCITY;
        } else {
            mMinimumRotaryEncoderFlingVelocity = configMinRotaryEncoderFlingVelocity;
            mMaximumRotaryEncoderFlingVelocity = configMaxRotaryEncoderFlingVelocity;
        }

        mGlobalActionsKeyTimeout = res.getInteger(
                com.android.internal.R.integer.config_globalActionsKeyTimeout);

@@ -1076,6 +1100,98 @@ public class ViewConfiguration {
        return sHasPermanentMenuKey;
    }

    /**
     * Minimum absolute value of velocity to initiate a fling for a motion generated by an
     * {@link InputDevice} with an id of {@code inputDeviceId}, from an input {@code source} and on
     * a given motion event {@code axis}.
     *
     * <p>Before utilizing this method to get a minimum fling velocity for a motion generated by the
     * input device, scale the velocity of the motion events generated by the input device to pixels
     * per second.
     *
     * <p>For instance, if you tracked {@link MotionEvent#AXIS_SCROLL} vertical velocities generated
     * from a {@link InputDevice#SOURCE_ROTARY_ENCODER}, the velocity returned from
     * {@link VelocityTracker} will be in the units with which the axis values were reported in the
     * motion event. Before comparing that velocity against the minimum fling velocity specified
     * here, make sure that the {@link MotionEvent#AXIS_SCROLL} velocity from the tracker is
     * calculated in "units per second" (see {@link VelocityTracker#computeCurrentVelocity(int)},
     * {@link VelocityTracker#computeCurrentVelocity(int, float)} to adjust your velocity
     * computations to "per second"), and use {@link #getScaledVerticalScrollFactor} to change this
     * velocity value to "pixels/second".
     *
     * <p>If the provided {@code inputDeviceId} is not valid, or if the input device whose ID is
     * provided does not support the given motion event source and/or axis, this method will return
     * {@code Integer.MAX_VALUE}.
     *
     * <h3>Obtaining the correct arguments for this method call</h3>
     * <p><b>inputDeviceId</b>: if calling this method in response to a {@link MotionEvent}, use
     * the device ID that is reported by the event, which can be obtained using
     * {@link MotionEvent#getDeviceId()}. Otherwise, use a valid ID that is obtained from
     * {@link InputDevice#getId()}, or from an {@link InputManager} instance
     * ({@link InputManager#getInputDeviceIds()} gives all the valid input device IDs).
     *
     * <p><b>axis</b>: a {@link MotionEvent} may report data for multiple axes, and each axis may
     * have multiple data points for different pointers. Use the axis for which you obtained the
     * velocity for ({@link VelocityTracker} lets you calculate velocities for a specific axis. Use
     * the axis for which you calculated velocity). You can use
     * {@link InputDevice#getMotionRanges()} to get all the {@link InputDevice.MotionRange}s for the
     * {@link InputDevice}, from which you can derive all the valid axes for the device.
     *
     * <p><b>source</b>: use {@link MotionEvent#getSource()} if calling this method in response to a
     * {@link MotionEvent}. Otherwise, use a valid source for the {@link InputDevice}. You can use
     * {@link InputDevice#getMotionRanges()} to get all the {@link InputDevice.MotionRange}s for the
     * {@link InputDevice}, from which you can derive all the valid sources for the device.
     *
     *
     * <p>This method optimizes calls over multiple input device IDs, so caching the return value of
     * the method is not necessary if you are handling multiple input devices.
     *
     * @param inputDeviceId the ID of the {@link InputDevice} that generated the motion triggering
     *          fling.
     * @param axis the axis on which the motion triggering the fling happened. This axis should be
     *          a valid axis that can be reported by the provided input device from the provided
     *          input device source.
     * @param source the input source of the motion causing fling. This source should be a valid
     *          source for the {@link InputDevice} whose ID is {@code inputDeviceId}.
     *
     * @return the minimum velocity, in pixels/second, to trigger fling.
     *
     * @see InputDevice#getMotionRange(int, int)
     * @see InputDevice#getMotionRanges()
     * @see VelocityTracker#getAxisVelocity(int, int)
     * @see VelocityTracker#getAxisVelocity(int)
     */
    public int getScaledMinimumFlingVelocity(int inputDeviceId, int axis, int source) {
        if (!isInputDeviceInfoValid(inputDeviceId, axis, source)) return NO_FLING_MIN_VELOCITY;

        if (source == InputDevice.SOURCE_ROTARY_ENCODER) return mMinimumRotaryEncoderFlingVelocity;

        return mMinimumFlingVelocity;
    }

    /**
     * Maximum absolute value of velocity to initiate a fling for a motion generated by an
     * {@link InputDevice} with an id of {@code inputDeviceId}, from an input {@code source} and on
     * a given motion event {@code axis}.
     *
     * <p>Similar to {@link #getScaledMinimumFlingVelocity(int, int, int)}, but for maximum fling
     * velocity, instead of minimum. Also, unlike that method which returns
     * {@code Integer.MAX_VALUE} for bad input device ID, source and/or motion event axis inputs,
     * this method returns {@code Integer.MIN_VALUE} for such bad inputs.
     */
    public int getScaledMaximumFlingVelocity(int inputDeviceId, int axis, int source) {
        if (!isInputDeviceInfoValid(inputDeviceId, axis, source)) return NO_FLING_MAX_VELOCITY;

        if (source == InputDevice.SOURCE_ROTARY_ENCODER) return mMaximumRotaryEncoderFlingVelocity;

        return mMaximumFlingVelocity;
    }

    private static boolean isInputDeviceInfoValid(int id, int axis, int source) {
        InputDevice device = InputManager.getInstance().getInputDevice(id);
        return device != null && device.getMotionRange(axis, source) != null;
    }

    /**
     * Check if shortcuts should be displayed in menus.
     *
+8 −0
Original line number Diff line number Diff line
@@ -2674,6 +2674,14 @@
    <!-- Maximum velocity to initiate a fling, as measured in dips per second. -->
    <dimen name="config_viewMaxFlingVelocity">8000dp</dimen>

    <!-- Minimum velocity (absolute value) to initiate a fling from a rotary encoder device, as
         measured in dips per second. Setting this to -1dp disables rotary encoder fling.  -->
    <dimen name="config_viewMinRotaryEncoderFlingVelocity">-1dp</dimen>

    <!-- Maximum velocity (absolute value) to initiate a fling from a rotary encoder device, as
         measured in dips per second. Setting this to -1dp disables rotary encoder fling.  -->
    <dimen name="config_viewMaxRotaryEncoderFlingVelocity">-1dp</dimen>

    <!-- Amount of time in ms the user needs to press the relevant key to bring up the
         global actions dialog -->
    <integer name="config_globalActionsKeyTimeout">500</integer>
+2 −0
Original line number Diff line number Diff line
@@ -514,6 +514,8 @@
  <java-symbol type="dimen" name="config_ambiguousGestureMultiplier" />
  <java-symbol type="dimen" name="config_viewMinFlingVelocity" />
  <java-symbol type="dimen" name="config_viewMaxFlingVelocity" />
  <java-symbol type="dimen" name="config_viewMinRotaryEncoderFlingVelocity" />
  <java-symbol type="dimen" name="config_viewMaxRotaryEncoderFlingVelocity" />
  <java-symbol type="dimen" name="config_scrollbarSize" />
  <java-symbol type="dimen" name="config_horizontalScrollFactor" />
  <java-symbol type="dimen" name="config_verticalScrollFactor" />