From b0c9e74c6ff8a772df9c754911c5f9d9e7e6c663 Mon Sep 17 00:00:00 2001 From: Yeabkal Wubshit Date: Tue, 1 Nov 2022 21:17:29 -0700 Subject: [PATCH] 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 --- core/api/current.txt | 2 + core/java/android/view/ViewConfiguration.java | 116 ++++++++++++++++++ core/res/res/values/config.xml | 8 ++ core/res/res/values/symbols.xml | 2 + 4 files changed, 128 insertions(+) diff --git a/core/api/current.txt b/core/api/current.txt index 205be59c0f955..6419f1311f358 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -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(); diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index f51d9bacc0a58..c96d298f9382b 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -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}. + * + *

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. + * + *

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". + * + *

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}. + * + *

Obtaining the correct arguments for this method call

+ *

inputDeviceId: 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). + * + *

axis: 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. + * + *

source: 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. + * + * + *

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}. + * + *

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. * diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 263d4315fdc32..328d068997f64 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2674,6 +2674,14 @@ 8000dp + + -1dp + + + -1dp + 500 diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index fbed371d86621..778ab699a5200 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -514,6 +514,8 @@ + +