• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.view;
18 
19 import android.annotation.FloatRange;
20 import android.annotation.NonNull;
21 import android.annotation.TestApi;
22 import android.annotation.UiContext;
23 import android.app.Activity;
24 import android.app.ActivityThread;
25 import android.app.AppGlobals;
26 import android.app.Application;
27 import android.compat.annotation.UnsupportedAppUsage;
28 import android.content.Context;
29 import android.content.res.Configuration;
30 import android.content.res.Resources;
31 import android.graphics.Rect;
32 import android.hardware.input.InputManager;
33 import android.hardware.input.InputManagerGlobal;
34 import android.os.Build;
35 import android.os.Bundle;
36 import android.os.RemoteException;
37 import android.os.StrictMode;
38 import android.provider.Settings;
39 import android.util.DisplayMetrics;
40 import android.util.SparseArray;
41 import android.util.TypedValue;
42 import android.view.flags.Flags;
43 
44 import com.android.internal.R;
45 import com.android.internal.annotations.VisibleForTesting;
46 
47 /**
48  * Contains methods to standard constants used in the UI for timeouts, sizes, and distances.
49  */
50 public class ViewConfiguration {
51     /**
52      * Defines the width of the horizontal scrollbar and the height of the vertical scrollbar in
53      * dips
54      */
55     private static final int SCROLL_BAR_SIZE = 4;
56 
57     /**
58      * Duration of the fade when scrollbars fade away in milliseconds
59      */
60     private static final int SCROLL_BAR_FADE_DURATION = 250;
61 
62     /**
63      * Default delay before the scrollbars fade in milliseconds
64      */
65     private static final int SCROLL_BAR_DEFAULT_DELAY = 300;
66 
67     /**
68      * Defines the length of the fading edges in dips
69      */
70     private static final int FADING_EDGE_LENGTH = 12;
71 
72     /**
73      * Defines the duration in milliseconds of the pressed state in child
74      * components.
75      */
76     private static final int PRESSED_STATE_DURATION = 64;
77 
78     /**
79      * Defines the default duration in milliseconds before a press turns into
80      * a long press
81      * @hide
82      */
83     public static final int DEFAULT_LONG_PRESS_TIMEOUT = 400;
84 
85     /**
86      * Defines the default duration in milliseconds between the first tap's up event and the second
87      * tap's down event for an interaction to be considered part of the same multi-press.
88      */
89     private static final int DEFAULT_MULTI_PRESS_TIMEOUT = 300;
90 
91     /**
92      * Defines the default duration in milliseconds between a key being pressed and its first key
93      * repeat event being generated. Historically, Android used the long press timeout as the
94      * key repeat timeout, so its default value is set to long press timeout's default.
95      */
96     private static final int DEFAULT_KEY_REPEAT_TIMEOUT_MS = DEFAULT_LONG_PRESS_TIMEOUT;
97 
98     /**
99      * Defines the default duration between successive key repeats in milliseconds.
100      */
101     private static final int DEFAULT_KEY_REPEAT_DELAY_MS = 50;
102 
103     /**
104      * Defines the duration in milliseconds a user needs to hold down the
105      * appropriate button to bring up the global actions dialog (power off,
106      * lock screen, etc).
107      */
108     private static final int GLOBAL_ACTIONS_KEY_TIMEOUT = 500;
109 
110     /**
111      * Defines the duration in milliseconds a user needs to hold down the
112      * appropriate buttons (power + volume down) to trigger the screenshot chord.
113      */
114     private static final int SCREENSHOT_CHORD_KEY_TIMEOUT = 0;
115 
116     /**
117      * Defines the duration in milliseconds a user needs to hold down the
118      * appropriate button to bring up the accessibility shortcut for the first time
119      */
120     private static final int A11Y_SHORTCUT_KEY_TIMEOUT = 3000;
121 
122     /**
123      * Defines the duration in milliseconds a user needs to hold down the
124      * appropriate button to enable the accessibility shortcut once it's configured.
125      */
126     private static final int A11Y_SHORTCUT_KEY_TIMEOUT_AFTER_CONFIRMATION = 1000;
127 
128     /**
129      * Defines the duration in milliseconds we will wait to see if a touch event
130      * is a tap or a scroll. If the user does not move within this interval, it is
131      * considered to be a tap.
132      */
133     private static final int TAP_TIMEOUT = 100;
134 
135     /**
136      * Defines the duration in milliseconds we will wait to see if a touch event
137      * is a jump tap. If the user does not complete the jump tap within this interval, it is
138      * considered to be a tap.
139      */
140     private static final int JUMP_TAP_TIMEOUT = 500;
141 
142     /**
143      * Defines the duration in milliseconds between the first tap's up event and
144      * the second tap's down event for an interaction to be considered a
145      * double-tap.
146      */
147     private static final int DOUBLE_TAP_TIMEOUT = 300;
148 
149     /**
150      * Defines the minimum duration in milliseconds between the first tap's up event and
151      * the second tap's down event for an interaction to be considered a
152      * double-tap.
153      */
154     private static final int DOUBLE_TAP_MIN_TIME = 40;
155 
156     /**
157      * Defines the maximum duration in milliseconds between a touch pad
158      * touch and release for a given touch to be considered a tap (click) as
159      * opposed to a hover movement gesture.
160      */
161     private static final int HOVER_TAP_TIMEOUT = 150;
162 
163     /**
164      * Defines the maximum distance in pixels that a touch pad touch can move
165      * before being released for it to be considered a tap (click) as opposed
166      * to a hover movement gesture.
167      */
168     private static final int HOVER_TAP_SLOP = 20;
169 
170     /**
171      * Defines the duration in milliseconds we want to display zoom controls in response
172      * to a user panning within an application.
173      */
174     private static final int ZOOM_CONTROLS_TIMEOUT = 3000;
175 
176     /**
177      * Inset in dips to look for touchable content when the user touches the edge of the screen
178      */
179     private static final int EDGE_SLOP = 12;
180 
181     /**
182      * Distance a touch can wander before we think the user is scrolling in dips.
183      * Note that this value defined here is only used as a fallback by legacy/misbehaving
184      * applications that do not provide a Context for determining density/configuration-dependent
185      * values.
186      *
187      * To alter this value, see the configuration resource config_viewConfigurationTouchSlop
188      * in frameworks/base/core/res/res/values/config.xml or the appropriate device resource overlay.
189      * It may be appropriate to tweak this on a device-specific basis in an overlay based on
190      * the characteristics of the touch panel and firmware.
191      */
192     private static final int TOUCH_SLOP = 8;
193 
194     /** Distance a stylus touch can wander before we think the user is handwriting in dips. */
195     private static final int HANDWRITING_SLOP = 2;
196 
197     /**
198      * Defines the minimum size of the touch target for a scrollbar in dips
199      */
200     private static final int MIN_SCROLLBAR_TOUCH_TARGET = 48;
201 
202     /**
203      * Distance the first touch can wander before we stop considering this event a double tap
204      * (in dips)
205      */
206     private static final int DOUBLE_TAP_TOUCH_SLOP = TOUCH_SLOP;
207 
208     /**
209      * Distance a touch can wander before we think the user is attempting a paged scroll
210      * (in dips)
211      *
212      * Note that this value defined here is only used as a fallback by legacy/misbehaving
213      * applications that do not provide a Context for determining density/configuration-dependent
214      * values.
215      *
216      * See the note above on {@link #TOUCH_SLOP} regarding the dimen resource
217      * config_viewConfigurationTouchSlop. ViewConfiguration will report a paging touch slop of
218      * config_viewConfigurationTouchSlop * 2 when provided with a Context.
219      */
220     private static final int PAGING_TOUCH_SLOP = TOUCH_SLOP * 2;
221 
222     /**
223      * Distance in dips between the first touch and second touch to still be considered a double tap
224      */
225     private static final int DOUBLE_TAP_SLOP = 100;
226 
227     /**
228      * Distance in dips a touch needs to be outside of a window's bounds for it to
229      * count as outside for purposes of dismissing the window.
230      */
231     private static final int WINDOW_TOUCH_SLOP = 16;
232 
233     /**
234      * Margin in dips around text line bounds where stylus handwriting gestures should be supported.
235      */
236     private static final int HANDWRITING_GESTURE_LINE_MARGIN = 16;
237 
238     /**
239      * Minimum velocity to initiate a fling, as measured in dips per second
240      */
241     private static final int MINIMUM_FLING_VELOCITY = 50;
242 
243     /**
244      * Maximum velocity to initiate a fling, as measured in dips per second
245      */
246     private static final int MAXIMUM_FLING_VELOCITY = 8000;
247 
248     /** Value used as a minimum fling velocity, when fling is not supported. */
249     private static final int NO_FLING_MIN_VELOCITY = Integer.MAX_VALUE;
250 
251     /** Value used as a maximum fling velocity, when fling is not supported. */
252     private static final int NO_FLING_MAX_VELOCITY = Integer.MIN_VALUE;
253 
254     /** @hide */
255     public static final int NO_HAPTIC_SCROLL_TICK_INTERVAL = Integer.MAX_VALUE;
256 
257     /**
258      * Delay before dispatching a recurring accessibility event in milliseconds.
259      * This delay guarantees that a recurring event will be send at most once
260      * during the {@link #SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS} time
261      * frame.
262      */
263     private static final long SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS = 100;
264 
265     /**
266      * The maximum size of View's drawing cache, expressed in bytes. This size
267      * should be at least equal to the size of the screen in ARGB888 format.
268      */
269     @Deprecated
270     private static final int MAXIMUM_DRAWING_CACHE_SIZE = 480 * 800 * 4; // ARGB8888
271 
272     /**
273      * The coefficient of friction applied to flings/scrolls.
274      */
275     @UnsupportedAppUsage
276     private static final float SCROLL_FRICTION = 0.015f;
277 
278     /**
279      * Max distance in dips to overscroll for edge effects
280      */
281     private static final int OVERSCROLL_DISTANCE = 0;
282 
283     /**
284      * Max distance in dips to overfling for edge effects
285      */
286     private static final int OVERFLING_DISTANCE = 6;
287 
288     /**
289      * Amount to scroll in response to a horizontal {@link MotionEvent#ACTION_SCROLL} event,
290      * in dips per axis value.
291      */
292     private static final float HORIZONTAL_SCROLL_FACTOR = 64;
293 
294     /**
295      * Amount to scroll in response to a vertical {@link MotionEvent#ACTION_SCROLL} event,
296      * in dips per axis value.
297      */
298     private static final float VERTICAL_SCROLL_FACTOR = 64;
299 
300     /**
301      * Default duration to hide an action mode for.
302      */
303     private static final long ACTION_MODE_HIDE_DURATION_DEFAULT = 2000;
304 
305     /**
306      * Defines the duration in milliseconds before an end of a long press causes a tooltip to be
307      * hidden.
308      */
309     private static final int LONG_PRESS_TOOLTIP_HIDE_TIMEOUT = 1500;
310 
311     /**
312      * Defines the duration in milliseconds before a hover event causes a tooltip to be shown.
313      */
314     private static final int HOVER_TOOLTIP_SHOW_TIMEOUT = 500;
315 
316     /**
317      * Defines the duration in milliseconds before mouse inactivity causes a tooltip to be hidden.
318      * (default variant to be used when {@link View#SYSTEM_UI_FLAG_LOW_PROFILE} is not set).
319      */
320     private static final int HOVER_TOOLTIP_HIDE_TIMEOUT = 15000;
321 
322     /**
323      * Defines the duration in milliseconds before mouse inactivity causes a tooltip to be hidden
324      * (short version to be used when {@link View#SYSTEM_UI_FLAG_LOW_PROFILE} is set).
325      */
326     private static final int HOVER_TOOLTIP_HIDE_SHORT_TIMEOUT = 3000;
327 
328     /**
329      * Configuration values for overriding {@link #hasPermanentMenuKey()} behavior.
330      * These constants must match the definition in res/values/config.xml.
331      */
332     private static final int HAS_PERMANENT_MENU_KEY_AUTODETECT = 0;
333     private static final int HAS_PERMANENT_MENU_KEY_TRUE = 1;
334     private static final int HAS_PERMANENT_MENU_KEY_FALSE = 2;
335 
336     /**
337      * The multiplication factor for inhibiting default gestures.
338      */
339     private static final float AMBIGUOUS_GESTURE_MULTIPLIER = 2f;
340 
341     /**
342      * The timeout value in milliseconds to adjust the selection span and actions for the selected
343      * text when TextClassifier has been initialized.
344      */
345     private static final int SMART_SELECTION_INITIALIZED_TIMEOUT_IN_MILLISECOND = 200;
346 
347     /**
348      * The timeout value in milliseconds to adjust the selection span and actions for the selected
349      * text when TextClassifier has not been initialized.
350      */
351     private static final int SMART_SELECTION_INITIALIZING_TIMEOUT_IN_MILLISECOND = 500;
352 
353     private static ResourceCache sResourceCache = new ResourceCache();
354 
355     private final boolean mConstructedWithContext;
356     private final int mEdgeSlop;
357     private final int mFadingEdgeLength;
358     private final int mMinimumFlingVelocity;
359     private final int mMaximumFlingVelocity;
360     private final int mMinimumRotaryEncoderFlingVelocity;
361     private final int mMaximumRotaryEncoderFlingVelocity;
362     private final int mRotaryEncoderHapticScrollFeedbackTickIntervalPixels;
363     private final boolean mRotaryEncoderHapticScrollFeedbackEnabled;
364     private final int mScrollbarSize;
365     private final int mTouchSlop;
366     private final int mHandwritingSlop;
367     private final int mMinScalingSpan;
368     private final int mHoverSlop;
369     private final int mMinScrollbarTouchTarget;
370     private final int mDoubleTapTouchSlop;
371     private final int mPagingTouchSlop;
372     private final int mDoubleTapSlop;
373     private final int mWindowTouchSlop;
374     private final int mHandwritingGestureLineMargin;
375     private final float mAmbiguousGestureMultiplier;
376     private final int mMaximumDrawingCacheSize;
377     private final int mOverscrollDistance;
378     private final int mOverflingDistance;
379     private final boolean mViewTouchScreenHapticScrollFeedbackEnabled;
380     private final boolean mFadingMarqueeEnabled;
381     private final long mGlobalActionsKeyTimeout;
382     private final float mVerticalScrollFactor;
383     private final float mHorizontalScrollFactor;
384     private final boolean mShowMenuShortcutsWhenKeyboardPresent;
385     private final long mScreenshotChordKeyTimeout;
386     private final int mSmartSelectionInitializedTimeout;
387     private final int mSmartSelectionInitializingTimeout;
388     private final boolean mPreferKeepClearForFocusEnabled;
389     private final boolean mViewBasedRotaryEncoderScrollHapticsEnabledConfig;
390 
391     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768915)
392     private boolean sHasPermanentMenuKey;
393     @UnsupportedAppUsage
394     private boolean sHasPermanentMenuKeySet;
395 
396     @UnsupportedAppUsage
397     static final SparseArray<ViewConfiguration> sConfigurations =
398             new SparseArray<ViewConfiguration>(2);
399 
400     /**
401      * @deprecated Use {@link android.view.ViewConfiguration#get(android.content.Context)} instead.
402      */
403     @Deprecated
ViewConfiguration()404     public ViewConfiguration() {
405         mConstructedWithContext = false;
406         mEdgeSlop = EDGE_SLOP;
407         mFadingEdgeLength = FADING_EDGE_LENGTH;
408         mMinimumFlingVelocity = MINIMUM_FLING_VELOCITY;
409         mMaximumFlingVelocity = MAXIMUM_FLING_VELOCITY;
410         mMinimumRotaryEncoderFlingVelocity = MINIMUM_FLING_VELOCITY;
411         mMaximumRotaryEncoderFlingVelocity = MAXIMUM_FLING_VELOCITY;
412         mRotaryEncoderHapticScrollFeedbackEnabled = false;
413         mRotaryEncoderHapticScrollFeedbackTickIntervalPixels = NO_HAPTIC_SCROLL_TICK_INTERVAL;
414         mViewBasedRotaryEncoderScrollHapticsEnabledConfig = false;
415         mScrollbarSize = SCROLL_BAR_SIZE;
416         mTouchSlop = TOUCH_SLOP;
417         mHandwritingSlop = HANDWRITING_SLOP;
418         mHoverSlop = TOUCH_SLOP / 2;
419         mMinScrollbarTouchTarget = MIN_SCROLLBAR_TOUCH_TARGET;
420         mDoubleTapTouchSlop = DOUBLE_TAP_TOUCH_SLOP;
421         mPagingTouchSlop = PAGING_TOUCH_SLOP;
422         mDoubleTapSlop = DOUBLE_TAP_SLOP;
423         mWindowTouchSlop = WINDOW_TOUCH_SLOP;
424         mHandwritingGestureLineMargin = HANDWRITING_GESTURE_LINE_MARGIN;
425         mAmbiguousGestureMultiplier = AMBIGUOUS_GESTURE_MULTIPLIER;
426         //noinspection deprecation
427         mMaximumDrawingCacheSize = MAXIMUM_DRAWING_CACHE_SIZE;
428         mOverscrollDistance = OVERSCROLL_DISTANCE;
429         mOverflingDistance = OVERFLING_DISTANCE;
430         mFadingMarqueeEnabled = true;
431         mGlobalActionsKeyTimeout = GLOBAL_ACTIONS_KEY_TIMEOUT;
432         mHorizontalScrollFactor = HORIZONTAL_SCROLL_FACTOR;
433         mVerticalScrollFactor = VERTICAL_SCROLL_FACTOR;
434         mShowMenuShortcutsWhenKeyboardPresent = false;
435         mScreenshotChordKeyTimeout = SCREENSHOT_CHORD_KEY_TIMEOUT;
436 
437         // Getter throws if mConstructedWithContext is false so doesn't matter what
438         // this value is.
439         mMinScalingSpan = 0;
440         mSmartSelectionInitializedTimeout = SMART_SELECTION_INITIALIZED_TIMEOUT_IN_MILLISECOND;
441         mSmartSelectionInitializingTimeout = SMART_SELECTION_INITIALIZING_TIMEOUT_IN_MILLISECOND;
442         mPreferKeepClearForFocusEnabled = false;
443         mViewTouchScreenHapticScrollFeedbackEnabled = false;
444     }
445 
446     /**
447      * Creates a new configuration for the specified visual {@link Context}. The configuration
448      * depends on various parameters of the {@link Context}, like the dimension of the display or
449      * the density of the display.
450      *
451      * @param context A visual {@link Context} used to initialize the view configuration. It must
452      *                be {@link Activity} or other {@link Context} created with
453      *                {@link Context#createWindowContext(int, Bundle)}.
454      *
455      * @see #get(android.content.Context)
456      * @see android.util.DisplayMetrics
457      */
ViewConfiguration(@onNull @iContext Context context)458     private ViewConfiguration(@NonNull @UiContext Context context) {
459         mConstructedWithContext = true;
460         final Resources res = context.getResources();
461         final DisplayMetrics metrics = res.getDisplayMetrics();
462         final Configuration config = res.getConfiguration();
463         final float density = metrics.density;
464         final float sizeAndDensity;
465         if (config.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_XLARGE)) {
466             sizeAndDensity = density * 1.5f;
467         } else {
468             sizeAndDensity = density;
469         }
470 
471         mEdgeSlop = (int) (sizeAndDensity * EDGE_SLOP + 0.5f);
472         mFadingEdgeLength = (int) (sizeAndDensity * FADING_EDGE_LENGTH + 0.5f);
473         mScrollbarSize = res.getDimensionPixelSize(R.dimen.config_scrollbarSize);
474         mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
475         mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
476 
477         final TypedValue multiplierValue = new TypedValue();
478         res.getValue(R.dimen.config_ambiguousGestureMultiplier,
479                 multiplierValue,
480                 true /*resolveRefs*/);
481         mAmbiguousGestureMultiplier = Math.max(1.0f, multiplierValue.getFloat());
482 
483         // Size of the screen in bytes, in ARGB_8888 format
484         final Rect maxBounds = config.windowConfiguration.getMaxBounds();
485         mMaximumDrawingCacheSize = 4 * maxBounds.width() * maxBounds.height();
486 
487         mOverscrollDistance = (int) (sizeAndDensity * OVERSCROLL_DISTANCE + 0.5f);
488         mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f);
489 
490         if (!sHasPermanentMenuKeySet) {
491             final int configVal = res.getInteger(R.integer.config_overrideHasPermanentMenuKey);
492 
493             switch (configVal) {
494                 default:
495                 case HAS_PERMANENT_MENU_KEY_AUTODETECT: {
496                     IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
497                     try {
498                         sHasPermanentMenuKey = !wm.hasNavigationBar(context.getDisplayId());
499                         sHasPermanentMenuKeySet = true;
500                     } catch (RemoteException ex) {
501                         sHasPermanentMenuKey = false;
502                     }
503                 }
504                 break;
505 
506                 case HAS_PERMANENT_MENU_KEY_TRUE:
507                     sHasPermanentMenuKey = true;
508                     sHasPermanentMenuKeySet = true;
509                     break;
510 
511                 case HAS_PERMANENT_MENU_KEY_FALSE:
512                     sHasPermanentMenuKey = false;
513                     sHasPermanentMenuKeySet = true;
514                     break;
515             }
516         }
517 
518         mFadingMarqueeEnabled = res.getBoolean(R.bool.config_ui_enableFadingMarquee);
519         mTouchSlop = res.getDimensionPixelSize(R.dimen.config_viewConfigurationTouchSlop);
520         mHandwritingSlop = res.getDimensionPixelSize(
521                 R.dimen.config_viewConfigurationHandwritingSlop);
522         mHoverSlop = res.getDimensionPixelSize(R.dimen.config_viewConfigurationHoverSlop);
523         mMinScrollbarTouchTarget = res.getDimensionPixelSize(
524                 R.dimen.config_minScrollbarTouchTarget);
525         mPagingTouchSlop = mTouchSlop * 2;
526 
527         mDoubleTapTouchSlop = mTouchSlop;
528 
529         mHandwritingGestureLineMargin = res.getDimensionPixelSize(
530                 R.dimen.config_viewConfigurationHandwritingGestureLineMargin);
531 
532         mMinimumFlingVelocity = res.getDimensionPixelSize(R.dimen.config_viewMinFlingVelocity);
533         mMaximumFlingVelocity = res.getDimensionPixelSize(R.dimen.config_viewMaxFlingVelocity);
534 
535         int configMinRotaryEncoderFlingVelocity = res.getDimensionPixelSize(
536                 R.dimen.config_viewMinRotaryEncoderFlingVelocity);
537         int configMaxRotaryEncoderFlingVelocity = res.getDimensionPixelSize(
538                 R.dimen.config_viewMaxRotaryEncoderFlingVelocity);
539         if (configMinRotaryEncoderFlingVelocity < 0 || configMaxRotaryEncoderFlingVelocity < 0) {
540             mMinimumRotaryEncoderFlingVelocity = NO_FLING_MIN_VELOCITY;
541             mMaximumRotaryEncoderFlingVelocity = NO_FLING_MAX_VELOCITY;
542         } else {
543             mMinimumRotaryEncoderFlingVelocity = configMinRotaryEncoderFlingVelocity;
544             mMaximumRotaryEncoderFlingVelocity = configMaxRotaryEncoderFlingVelocity;
545         }
546 
547         int configRotaryEncoderHapticScrollFeedbackTickIntervalPixels =
548                 res.getDimensionPixelSize(R.dimen
549                                 .config_rotaryEncoderAxisScrollTickInterval);
550         mRotaryEncoderHapticScrollFeedbackTickIntervalPixels =
551                 configRotaryEncoderHapticScrollFeedbackTickIntervalPixels > 0
552                         ? configRotaryEncoderHapticScrollFeedbackTickIntervalPixels
553                         : NO_HAPTIC_SCROLL_TICK_INTERVAL;
554 
555         mRotaryEncoderHapticScrollFeedbackEnabled =
556                 res.getBoolean(R.bool
557                                 .config_viewRotaryEncoderHapticScrollFedbackEnabled);
558 
559         mGlobalActionsKeyTimeout = res.getInteger(R.integer.config_globalActionsKeyTimeout);
560 
561         mHorizontalScrollFactor = res.getDimensionPixelSize(R.dimen.config_horizontalScrollFactor);
562         mVerticalScrollFactor = res.getDimensionPixelSize(R.dimen.config_verticalScrollFactor);
563 
564         mShowMenuShortcutsWhenKeyboardPresent = res.getBoolean(
565                 R.bool.config_showMenuShortcutsWhenKeyboardPresent);
566 
567         mMinScalingSpan = res.getDimensionPixelSize(R.dimen.config_minScalingSpan);
568 
569         mScreenshotChordKeyTimeout = res.getInteger(R.integer.config_screenshotChordKeyTimeout);
570 
571         mSmartSelectionInitializedTimeout = res.getInteger(
572                 R.integer.config_smartSelectionInitializedTimeoutMillis);
573         mSmartSelectionInitializingTimeout = res.getInteger(
574                 R.integer.config_smartSelectionInitializingTimeoutMillis);
575         mPreferKeepClearForFocusEnabled = res.getBoolean(R.bool.config_preferKeepClearForFocus);
576         mViewBasedRotaryEncoderScrollHapticsEnabledConfig =
577                 res.getBoolean(R.bool.config_viewBasedRotaryEncoderHapticsEnabled);
578         mViewTouchScreenHapticScrollFeedbackEnabled =
579                 Flags.enableScrollFeedbackForTouch()
580                         ? res.getBoolean(R.bool.config_viewTouchScreenHapticScrollFeedbackEnabled)
581                         : false;
582     }
583 
584     /**
585      * Returns a configuration for the specified visual {@link Context}. The configuration depends
586      * on various parameters of the {@link Context}, like the dimension of the display or the
587      * density of the display.
588      *
589      * @param context A visual {@link Context} used to initialize the view configuration. It must
590      *                be {@link Activity} or other {@link Context} created with
591      *                {@link Context#createWindowContext(int, Bundle)}.
592      */
593     // TODO(b/182007470): Use @ConfigurationContext instead
get(@onNull @iContext Context context)594     public static ViewConfiguration get(@NonNull @UiContext Context context) {
595         StrictMode.assertConfigurationContext(context, "ViewConfiguration");
596 
597         final int density = getDisplayDensity(context);
598 
599         ViewConfiguration configuration = sConfigurations.get(density);
600         if (configuration == null) {
601             configuration = new ViewConfiguration(context);
602             sConfigurations.put(density, configuration);
603         }
604 
605         return configuration;
606     }
607 
608     /**
609      * Removes cached ViewConfiguration instances, so that we can ensure `get` constructs a new
610      * ViewConfiguration instance. This is useful for testing the behavior and performance of
611      * creating ViewConfiguration the first time.
612      *
613      * @hide
614      */
615     @VisibleForTesting
resetCacheForTesting()616     public static void resetCacheForTesting() {
617         sConfigurations.clear();
618         sResourceCache = new ResourceCache();
619     }
620 
621     /**
622      * Sets the ViewConfiguration cached instanc for a given Context for testing.
623      *
624      * @hide
625      */
626     @VisibleForTesting
setInstanceForTesting(Context context, ViewConfiguration instance)627     public static void setInstanceForTesting(Context context, ViewConfiguration instance) {
628         sConfigurations.put(getDisplayDensity(context), instance);
629     }
630 
631     /**
632      * @return The width of the horizontal scrollbar and the height of the vertical
633      *         scrollbar in dips
634      *
635      * @deprecated Use {@link #getScaledScrollBarSize()} instead.
636      */
637     @Deprecated
getScrollBarSize()638     public static int getScrollBarSize() {
639         return SCROLL_BAR_SIZE;
640     }
641 
642     /**
643      * @return The width of the horizontal scrollbar and the height of the vertical
644      *         scrollbar in pixels
645      */
getScaledScrollBarSize()646     public int getScaledScrollBarSize() {
647         return mScrollbarSize;
648     }
649 
650     /**
651      * @return the minimum size of the scrollbar thumb's touch target in pixels
652      * @hide
653      */
getScaledMinScrollbarTouchTarget()654     public int getScaledMinScrollbarTouchTarget() {
655         return mMinScrollbarTouchTarget;
656     }
657 
658     /**
659      * @return Duration of the fade when scrollbars fade away in milliseconds
660      */
getScrollBarFadeDuration()661     public static int getScrollBarFadeDuration() {
662         return SCROLL_BAR_FADE_DURATION;
663     }
664 
665     /**
666      * @return Default delay before the scrollbars fade in milliseconds
667      */
getScrollDefaultDelay()668     public static int getScrollDefaultDelay() {
669         return SCROLL_BAR_DEFAULT_DELAY;
670     }
671 
672     /**
673      * @return the length of the fading edges in dips
674      *
675      * @deprecated Use {@link #getScaledFadingEdgeLength()} instead.
676      */
677     @Deprecated
getFadingEdgeLength()678     public static int getFadingEdgeLength() {
679         return FADING_EDGE_LENGTH;
680     }
681 
682     /**
683      * @return the length of the fading edges in pixels
684      */
getScaledFadingEdgeLength()685     public int getScaledFadingEdgeLength() {
686         return mFadingEdgeLength;
687     }
688 
689     /**
690      * @return the duration in milliseconds of the pressed state in child
691      * components.
692      */
getPressedStateDuration()693     public static int getPressedStateDuration() {
694         return sResourceCache.getPressedStateDuration();
695     }
696 
697     /**
698      * Used for both key and motion events.
699      *
700      * @return the duration in milliseconds before a press turns into
701      * a long press
702      */
getLongPressTimeout()703     public static int getLongPressTimeout() {
704         return AppGlobals.getIntCoreSetting(Settings.Secure.LONG_PRESS_TIMEOUT,
705                 DEFAULT_LONG_PRESS_TIMEOUT);
706     }
707 
708     /**
709      * @return the duration in milliseconds between the first tap's up event and the second tap's
710      * down event for an interaction to be considered part of the same multi-press.
711      */
getMultiPressTimeout()712     public static int getMultiPressTimeout() {
713         return AppGlobals.getIntCoreSetting(Settings.Secure.MULTI_PRESS_TIMEOUT,
714                 DEFAULT_MULTI_PRESS_TIMEOUT);
715     }
716 
717     /**
718      * @return the time before the first key repeat in milliseconds.
719      */
getKeyRepeatTimeout()720     public static int getKeyRepeatTimeout() {
721         return AppGlobals.getIntCoreSetting(Settings.Secure.KEY_REPEAT_TIMEOUT_MS,
722                 DEFAULT_KEY_REPEAT_TIMEOUT_MS);
723     }
724 
725     /**
726      * @return the time between successive key repeats in milliseconds.
727      */
getKeyRepeatDelay()728     public static int getKeyRepeatDelay() {
729         return AppGlobals.getIntCoreSetting(Settings.Secure.KEY_REPEAT_DELAY_MS,
730                 DEFAULT_KEY_REPEAT_DELAY_MS);
731     }
732 
733     /**
734      * @return the duration in milliseconds we will wait to see if a touch event
735      * is a tap or a scroll. If the user does not move within this interval, it is
736      * considered to be a tap.
737      */
getTapTimeout()738     public static int getTapTimeout() {
739         return sResourceCache.getTapTimeout();
740     }
741 
742     /**
743      * @return the duration in milliseconds we will wait to see if a touch event
744      * is a jump tap. If the user does not move within this interval, it is
745      * considered to be a tap.
746      */
getJumpTapTimeout()747     public static int getJumpTapTimeout() {
748         return sResourceCache.getJumpTapTimeout();
749     }
750 
751     /**
752      * @return the duration in milliseconds between the first tap's up event and
753      * the second tap's down event for an interaction to be considered a
754      * double-tap.
755      */
getDoubleTapTimeout()756     public static int getDoubleTapTimeout() {
757         return sResourceCache.getDoubleTapTimeout();
758     }
759 
760     /**
761      * @return the minimum duration in milliseconds between the first tap's
762      * up event and the second tap's down event for an interaction to be considered a
763      * double-tap.
764      *
765      * @hide
766      */
767     @UnsupportedAppUsage
getDoubleTapMinTime()768     public static int getDoubleTapMinTime() {
769         return sResourceCache.getDoubleTapMinTime();
770     }
771 
772     /**
773      * @return the maximum duration in milliseconds between a touch pad
774      * touch and release for a given touch to be considered a tap (click) as
775      * opposed to a hover movement gesture.
776      * @hide
777      */
getHoverTapTimeout()778     public static int getHoverTapTimeout() {
779         return sResourceCache.getHoverTapTimeout();
780     }
781 
782     /**
783      * @return the maximum distance in pixels that a touch pad touch can move
784      * before being released for it to be considered a tap (click) as opposed
785      * to a hover movement gesture.
786      * @hide
787      */
788     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getHoverTapSlop()789     public static int getHoverTapSlop() {
790         return sResourceCache.getHoverTapSlop();
791     }
792 
793     /**
794      * @return Inset in dips to look for touchable content when the user touches the edge of the
795      *         screen
796      *
797      * @deprecated Use {@link #getScaledEdgeSlop()} instead.
798      */
799     @Deprecated
getEdgeSlop()800     public static int getEdgeSlop() {
801         return EDGE_SLOP;
802     }
803 
804     /**
805      * @return Inset in pixels to look for touchable content when the user touches the edge of the
806      *         screen
807      */
getScaledEdgeSlop()808     public int getScaledEdgeSlop() {
809         return mEdgeSlop;
810     }
811 
812     /**
813      * @return Distance in dips a touch can wander before we think the user is scrolling
814      *
815      * @deprecated Use {@link #getScaledTouchSlop()} instead.
816      */
817     @Deprecated
getTouchSlop()818     public static int getTouchSlop() {
819         return TOUCH_SLOP;
820     }
821 
822     /**
823      * @return Distance in pixels a touch can wander before we think the user is scrolling
824      */
getScaledTouchSlop()825     public int getScaledTouchSlop() {
826         return mTouchSlop;
827     }
828 
829     /**
830      * @return Distance in pixels a stylus touch can wander before we think the user is
831      * handwriting.
832      */
getScaledHandwritingSlop()833     public int getScaledHandwritingSlop() {
834         return mHandwritingSlop;
835     }
836 
837     /**
838      * @return Distance in pixels a hover can wander while it is still considered "stationary".
839      *
840      */
getScaledHoverSlop()841     public int getScaledHoverSlop() {
842         return mHoverSlop;
843     }
844 
845     /**
846      * @return Distance in pixels the first touch can wander before we do not consider this a
847      * potential double tap event
848      * @hide
849      */
850     @UnsupportedAppUsage
getScaledDoubleTapTouchSlop()851     public int getScaledDoubleTapTouchSlop() {
852         return mDoubleTapTouchSlop;
853     }
854 
855     /**
856      * @return Distance in pixels a touch can wander before we think the user is scrolling a full
857      * page
858      */
getScaledPagingTouchSlop()859     public int getScaledPagingTouchSlop() {
860         return mPagingTouchSlop;
861     }
862 
863     /**
864      * @return Distance in dips between the first touch and second touch to still be
865      *         considered a double tap
866      * @deprecated Use {@link #getScaledDoubleTapSlop()} instead.
867      * @hide The only client of this should be GestureDetector, which needs this
868      *       for clients that still use its deprecated constructor.
869      */
870     @Deprecated
871     @UnsupportedAppUsage
getDoubleTapSlop()872     public static int getDoubleTapSlop() {
873         return DOUBLE_TAP_SLOP;
874     }
875 
876     /**
877      * @return Distance in pixels between the first touch and second touch to still be
878      *         considered a double tap
879      */
getScaledDoubleTapSlop()880     public int getScaledDoubleTapSlop() {
881         return mDoubleTapSlop;
882     }
883 
884     /**
885      * @return margin in pixels around text line bounds where stylus handwriting gestures should be
886      *     supported.
887      */
getScaledHandwritingGestureLineMargin()888     public int getScaledHandwritingGestureLineMargin() {
889         return mHandwritingGestureLineMargin;
890     }
891 
892     /**
893      * Interval for dispatching a recurring accessibility event in milliseconds.
894      * This interval guarantees that a recurring event will be send at most once
895      * during the {@link #getSendRecurringAccessibilityEventsInterval()} time frame.
896      *
897      * @return The delay in milliseconds.
898      *
899      * @hide
900      */
getSendRecurringAccessibilityEventsInterval()901     public static long getSendRecurringAccessibilityEventsInterval() {
902         return SEND_RECURRING_ACCESSIBILITY_EVENTS_INTERVAL_MILLIS;
903     }
904 
905     /**
906      * @return Distance in dips a touch must be outside the bounds of a window for it
907      * to be counted as outside the window for purposes of dismissing that
908      * window.
909      *
910      * @deprecated Use {@link #getScaledWindowTouchSlop()} instead.
911      */
912     @Deprecated
getWindowTouchSlop()913     public static int getWindowTouchSlop() {
914         return WINDOW_TOUCH_SLOP;
915     }
916 
917     /**
918      * @return Distance in pixels a touch must be outside the bounds of a window for it
919      * to be counted as outside the window for purposes of dismissing that window.
920      */
getScaledWindowTouchSlop()921     public int getScaledWindowTouchSlop() {
922         return mWindowTouchSlop;
923     }
924 
925     /**
926      * @return Minimum velocity to initiate a fling, as measured in dips per second.
927      *
928      * @deprecated Use {@link #getScaledMinimumFlingVelocity()} instead.
929      */
930     @Deprecated
getMinimumFlingVelocity()931     public static int getMinimumFlingVelocity() {
932         return MINIMUM_FLING_VELOCITY;
933     }
934 
935     /**
936      * @return Minimum velocity to initiate a fling, as measured in pixels per second.
937      */
getScaledMinimumFlingVelocity()938     public int getScaledMinimumFlingVelocity() {
939         return mMinimumFlingVelocity;
940     }
941 
942     /**
943      * @return Maximum velocity to initiate a fling, as measured in dips per second.
944      *
945      * @deprecated Use {@link #getScaledMaximumFlingVelocity()} instead.
946      */
947     @Deprecated
getMaximumFlingVelocity()948     public static int getMaximumFlingVelocity() {
949         return MAXIMUM_FLING_VELOCITY;
950     }
951 
952     /**
953      * @return Maximum velocity to initiate a fling, as measured in pixels per second.
954      */
getScaledMaximumFlingVelocity()955     public int getScaledMaximumFlingVelocity() {
956         return mMaximumFlingVelocity;
957     }
958 
959     /**
960      * @return Amount to scroll in response to a {@link MotionEvent#ACTION_SCROLL} event. Multiply
961      * this by the event's axis value to obtain the number of pixels to be scrolled.
962      *
963      * @removed
964      */
getScaledScrollFactor()965     public int getScaledScrollFactor() {
966         return (int) mVerticalScrollFactor;
967     }
968 
969     /**
970      * @return Amount to scroll in response to a horizontal {@link MotionEvent#ACTION_SCROLL} event.
971      * Multiply this by the event's axis value to obtain the number of pixels to be scrolled.
972      */
getScaledHorizontalScrollFactor()973     public float getScaledHorizontalScrollFactor() {
974         return mHorizontalScrollFactor;
975     }
976 
977     /**
978      * @return Amount to scroll in response to a vertical {@link MotionEvent#ACTION_SCROLL} event.
979      * Multiply this by the event's axis value to obtain the number of pixels to be scrolled.
980      */
getScaledVerticalScrollFactor()981     public float getScaledVerticalScrollFactor() {
982         return mVerticalScrollFactor;
983     }
984 
985     /**
986      * The maximum drawing cache size expressed in bytes.
987      *
988      * @return the maximum size of View's drawing cache expressed in bytes
989      *
990      * @deprecated Use {@link #getScaledMaximumDrawingCacheSize()} instead.
991      */
992     @Deprecated
getMaximumDrawingCacheSize()993     public static int getMaximumDrawingCacheSize() {
994         //noinspection deprecation
995         return MAXIMUM_DRAWING_CACHE_SIZE;
996     }
997 
998     /**
999      * The maximum drawing cache size expressed in bytes.
1000      *
1001      * @return the maximum size of View's drawing cache expressed in bytes
1002      */
getScaledMaximumDrawingCacheSize()1003     public int getScaledMaximumDrawingCacheSize() {
1004         return mMaximumDrawingCacheSize;
1005     }
1006 
1007     /**
1008      * @return The maximum distance a View should overscroll by when showing edge effects (in
1009      * pixels).
1010      */
getScaledOverscrollDistance()1011     public int getScaledOverscrollDistance() {
1012         return mOverscrollDistance;
1013     }
1014 
1015     /**
1016      * @return The maximum distance a View should overfling by when showing edge effects (in
1017      * pixels).
1018      */
getScaledOverflingDistance()1019     public int getScaledOverflingDistance() {
1020         return mOverflingDistance;
1021     }
1022 
1023     /**
1024      * The amount of time that the zoom controls should be
1025      * displayed on the screen expressed in milliseconds.
1026      *
1027      * @return the time the zoom controls should be visible expressed
1028      * in milliseconds.
1029      */
getZoomControlsTimeout()1030     public static long getZoomControlsTimeout() {
1031         return sResourceCache.getZoomControlsTimeout();
1032     }
1033 
1034     /**
1035      * The amount of time a user needs to press the relevant key to bring up
1036      * the global actions dialog.
1037      *
1038      * @return how long a user needs to press the relevant key to bring up
1039      *   the global actions dialog.
1040      * @deprecated This timeout should not be used by applications
1041      */
1042     @Deprecated
getGlobalActionKeyTimeout()1043     public static long getGlobalActionKeyTimeout() {
1044         return GLOBAL_ACTIONS_KEY_TIMEOUT;
1045     }
1046 
1047     /**
1048      * The amount of time a user needs to press the relevant key to bring up
1049      * the global actions dialog.
1050      *
1051      * @return how long a user needs to press the relevant key to bring up
1052      *   the global actions dialog.
1053      * @hide
1054      */
1055     @TestApi
getDeviceGlobalActionKeyTimeout()1056     public long getDeviceGlobalActionKeyTimeout() {
1057         return mGlobalActionsKeyTimeout;
1058     }
1059 
1060     /**
1061      * The amount of time a user needs to press the relevant keys to trigger
1062      * the screenshot chord.
1063      *
1064      * @return how long a user needs to press the relevant keys to trigger
1065      *   the screenshot chord.
1066      * @hide
1067      */
getScreenshotChordKeyTimeout()1068     public long getScreenshotChordKeyTimeout() {
1069         return mScreenshotChordKeyTimeout;
1070     }
1071 
1072     /**
1073      * The amount of time a user needs to press the relevant keys to activate the accessibility
1074      * shortcut.
1075      *
1076      * @return how long a user needs to press the relevant keys to activate the accessibility
1077      *   shortcut.
1078      * @hide
1079      */
getAccessibilityShortcutKeyTimeout()1080     public long getAccessibilityShortcutKeyTimeout() {
1081         return A11Y_SHORTCUT_KEY_TIMEOUT;
1082     }
1083 
1084     /**
1085      * @return The amount of time a user needs to press the relevant keys to activate the
1086      *   accessibility shortcut after it's confirmed that accessibility shortcut is used.
1087      * @hide
1088      */
getAccessibilityShortcutKeyTimeoutAfterConfirmation()1089     public long getAccessibilityShortcutKeyTimeoutAfterConfirmation() {
1090         return A11Y_SHORTCUT_KEY_TIMEOUT_AFTER_CONFIRMATION;
1091     }
1092 
1093     /**
1094      * The amount of friction applied to scrolls and flings.
1095      *
1096      * @return A scalar dimensionless value representing the coefficient of
1097      *         friction.
1098      */
getScrollFriction()1099     public static float getScrollFriction() {
1100         return sResourceCache.getScrollFriction();
1101     }
1102 
1103     /**
1104      * @return the default duration in milliseconds for {@link ActionMode#hide(long)}.
1105      */
getDefaultActionModeHideDuration()1106     public static long getDefaultActionModeHideDuration() {
1107         return sResourceCache.getDefaultActionModeHideDuration();
1108     }
1109 
1110     /**
1111      * The multiplication factor for inhibiting default gestures.
1112      *
1113      * If a MotionEvent has {@link android.view.MotionEvent#CLASSIFICATION_AMBIGUOUS_GESTURE} set,
1114      * then certain actions, such as scrolling, will be inhibited. However, to account for the
1115      * possibility of an incorrect classification, existing gesture thresholds (e.g. scrolling
1116      * touch slop and the long-press timeout) should be scaled by this factor and remain in effect.
1117      *
1118      * @deprecated Use {@link #getScaledAmbiguousGestureMultiplier()}.
1119      */
1120     @Deprecated
1121     @FloatRange(from = 1.0)
getAmbiguousGestureMultiplier()1122     public static float getAmbiguousGestureMultiplier() {
1123         return AMBIGUOUS_GESTURE_MULTIPLIER;
1124     }
1125 
1126     /**
1127      * The multiplication factor for inhibiting default gestures.
1128      *
1129      * If a MotionEvent has {@link android.view.MotionEvent#CLASSIFICATION_AMBIGUOUS_GESTURE} set,
1130      * then certain actions, such as scrolling, will be inhibited. However, to account for the
1131      * possibility of an incorrect classification, existing gesture thresholds (e.g. scrolling
1132      * touch slop and the long-press timeout) should be scaled by this factor and remain in effect.
1133      */
1134     @FloatRange(from = 1.0)
getScaledAmbiguousGestureMultiplier()1135     public float getScaledAmbiguousGestureMultiplier() {
1136         return mAmbiguousGestureMultiplier;
1137     }
1138 
1139     /**
1140      * Report if the device has a permanent menu key available to the user.
1141      *
1142      * <p>As of Android 3.0, devices may not have a permanent menu key available.
1143      * Apps should use the action bar to present menu options to users.
1144      * However, there are some apps where the action bar is inappropriate
1145      * or undesirable. This method may be used to detect if a menu key is present.
1146      * If not, applications should provide another on-screen affordance to access
1147      * functionality.
1148      *
1149      * @return true if a permanent menu key is present, false otherwise.
1150      */
hasPermanentMenuKey()1151     public boolean hasPermanentMenuKey() {
1152         return sHasPermanentMenuKey;
1153     }
1154 
1155     /**
1156      * Minimum absolute value of velocity to initiate a fling for a motion generated by an
1157      * {@link InputDevice} with an id of {@code inputDeviceId}, from an input {@code source} and on
1158      * a given motion event {@code axis}.
1159      *
1160      * <p>Before utilizing this method to get a minimum fling velocity for a motion generated by the
1161      * input device, scale the velocity of the motion events generated by the input device to pixels
1162      * per second.
1163      *
1164      * <p>For instance, if you tracked {@link MotionEvent#AXIS_SCROLL} vertical velocities generated
1165      * from a {@link InputDevice#SOURCE_ROTARY_ENCODER}, the velocity returned from
1166      * {@link VelocityTracker} will be in the units with which the axis values were reported in the
1167      * motion event. Before comparing that velocity against the minimum fling velocity specified
1168      * here, make sure that the {@link MotionEvent#AXIS_SCROLL} velocity from the tracker is
1169      * calculated in "units per second" (see {@link VelocityTracker#computeCurrentVelocity(int)},
1170      * {@link VelocityTracker#computeCurrentVelocity(int, float)} to adjust your velocity
1171      * computations to "per second"), and use {@link #getScaledVerticalScrollFactor} to change this
1172      * velocity value to "pixels/second".
1173      *
1174      * <p>If the provided {@code inputDeviceId} is not valid, or if the input device whose ID is
1175      * provided does not support the given motion event source and/or axis, this method will return
1176      * {@code Integer.MAX_VALUE}.
1177      *
1178      * <h3>Obtaining the correct arguments for this method call</h3>
1179      * <p><b>inputDeviceId</b>: if calling this method in response to a {@link MotionEvent}, use
1180      * the device ID that is reported by the event, which can be obtained using
1181      * {@link MotionEvent#getDeviceId()}. Otherwise, use a valid ID that is obtained from
1182      * {@link InputDevice#getId()}, or from an {@link InputManager} instance
1183      * ({@link InputManager#getInputDeviceIds()} gives all the valid input device IDs).
1184      *
1185      * <p><b>axis</b>: a {@link MotionEvent} may report data for multiple axes, and each axis may
1186      * have multiple data points for different pointers. Use the axis for which you obtained the
1187      * velocity for ({@link VelocityTracker} lets you calculate velocities for a specific axis. Use
1188      * the axis for which you calculated velocity). You can use
1189      * {@link InputDevice#getMotionRanges()} to get all the {@link InputDevice.MotionRange}s for the
1190      * {@link InputDevice}, from which you can derive all the valid axes for the device.
1191      *
1192      * <p><b>source</b>: use {@link MotionEvent#getSource()} if calling this method in response to a
1193      * {@link MotionEvent}. Otherwise, use a valid source for the {@link InputDevice}. You can use
1194      * {@link InputDevice#getMotionRanges()} to get all the {@link InputDevice.MotionRange}s for the
1195      * {@link InputDevice}, from which you can derive all the valid sources for the device.
1196      *
1197      *
1198      * <p>This method optimizes calls over multiple input device IDs, so caching the return value of
1199      * the method is not necessary if you are handling multiple input devices.
1200      *
1201      * @param inputDeviceId the ID of the {@link InputDevice} that generated the motion triggering
1202      *          fling.
1203      * @param axis the axis on which the motion triggering the fling happened. This axis should be
1204      *          a valid axis that can be reported by the provided input device from the provided
1205      *          input device source.
1206      * @param source the input source of the motion causing fling. This source should be a valid
1207      *          source for the {@link InputDevice} whose ID is {@code inputDeviceId}.
1208      *
1209      * @return the minimum velocity, in pixels/second, to trigger fling.
1210      *
1211      * @see InputDevice#getMotionRange(int, int)
1212      * @see InputDevice#getMotionRanges()
1213      * @see VelocityTracker#getAxisVelocity(int, int)
1214      * @see VelocityTracker#getAxisVelocity(int)
1215      */
getScaledMinimumFlingVelocity(int inputDeviceId, int axis, int source)1216     public int getScaledMinimumFlingVelocity(int inputDeviceId, int axis, int source) {
1217         if (!isInputDeviceInfoValid(inputDeviceId, axis, source)) return NO_FLING_MIN_VELOCITY;
1218 
1219         if (source == InputDevice.SOURCE_ROTARY_ENCODER) return mMinimumRotaryEncoderFlingVelocity;
1220 
1221         return mMinimumFlingVelocity;
1222     }
1223 
1224     /**
1225      * Maximum absolute value of velocity to initiate a fling for a motion generated by an
1226      * {@link InputDevice} with an id of {@code inputDeviceId}, from an input {@code source} and on
1227      * a given motion event {@code axis}.
1228      *
1229      * <p>Similar to {@link #getScaledMinimumFlingVelocity(int, int, int)}, but for maximum fling
1230      * velocity, instead of minimum. Also, unlike that method which returns
1231      * {@code Integer.MAX_VALUE} for bad input device ID, source and/or motion event axis inputs,
1232      * this method returns {@code Integer.MIN_VALUE} for such bad inputs.
1233      */
getScaledMaximumFlingVelocity(int inputDeviceId, int axis, int source)1234     public int getScaledMaximumFlingVelocity(int inputDeviceId, int axis, int source) {
1235         if (!isInputDeviceInfoValid(inputDeviceId, axis, source)) return NO_FLING_MAX_VELOCITY;
1236 
1237         if (source == InputDevice.SOURCE_ROTARY_ENCODER) return mMaximumRotaryEncoderFlingVelocity;
1238 
1239         return mMaximumFlingVelocity;
1240     }
1241 
1242     /**
1243      * Checks if any kind of scroll haptic feedback is enabled for a motion generated by a specific
1244      * input device configuration and motion axis.
1245      *
1246      * <p>See {@link ScrollFeedbackProvider} for details on the arguments that should be passed to
1247      * the methods in this class.
1248      *
1249      * <p>If the provided input device ID, source, and motion axis are not supported by this Android
1250      * device, this method returns {@code false}. In other words, if the {@link InputDevice}
1251      * represented by the provided {code inputDeviceId} does not have a
1252      * {@link InputDevice.MotionRange} with the provided {@code axis} and {@code source}, the method
1253      * returns {@code false}.
1254      *
1255      * <p>If the provided input device ID, source, and motion axis are supported by this Android
1256      * device, this method returns {@code true} only if the provided arguments are supported for
1257      * scroll haptics. Otherwise, this method returns {@code false}.
1258      *
1259      * @param inputDeviceId the ID of the {@link InputDevice} that generated the motion that may
1260      *      produce scroll haptics.
1261      * @param source the input source of the motion that may produce scroll haptics.
1262      * @param axis the axis of the motion that may produce scroll haptics.
1263      * @return {@code true} if motions generated by the provided input and motion configuration
1264      *      can produce scroll haptics. {@code false} otherwise.
1265      *
1266      * @see #getHapticScrollFeedbackTickInterval(int, int, int)
1267      * @see InputDevice#getMotionRanges()
1268      * @see InputDevice#getMotionRange(int)
1269      * @see InputDevice#getMotionRange(int, int)
1270      *
1271      * @hide
1272      */
isHapticScrollFeedbackEnabled(int inputDeviceId, int axis, int source)1273     public boolean isHapticScrollFeedbackEnabled(int inputDeviceId, int axis, int source) {
1274         if (!isInputDeviceInfoValid(inputDeviceId, axis, source)) return false;
1275 
1276         if (source == InputDevice.SOURCE_ROTARY_ENCODER && axis == MotionEvent.AXIS_SCROLL) {
1277             return mRotaryEncoderHapticScrollFeedbackEnabled;
1278         }
1279 
1280         if ((source & InputDevice.SOURCE_TOUCHSCREEN) != 0) {
1281             return mViewTouchScreenHapticScrollFeedbackEnabled;
1282         }
1283 
1284         return false;
1285     }
1286 
1287     /**
1288      * Provides the minimum scroll interval (in pixels) between consecutive scroll tick haptics for
1289      * motions generated by a specific input device configuration and motion axis.
1290      *
1291      * <p><b>Scroll tick</b> here refers to an interval-based, consistent scroll feedback provided
1292      * to the user as the user scrolls through a scrollable view.
1293      *
1294      * <p>If you are supporting scroll tick haptics, use this interval as the minimum pixel scroll
1295      * distance between consecutive scroll ticks. That is, once your view has scrolled for at least
1296      * this interval, play a haptic, and wait again until the view has further scrolled with this
1297      * interval in the same direction before playing the next scroll haptic.
1298      *
1299      * <p>Some devices may support other types of scroll haptics but not interval based tick
1300      * haptics. In those cases, this method will return {@code Integer.MAX_VALUE}. The same value
1301      * will be returned if the device does not support scroll haptics at all (which can be checked
1302      * via {@link #isHapticScrollFeedbackEnabled(int, int, int)}).
1303      *
1304      * <p>See {@link #isHapticScrollFeedbackEnabled(int, int, int)} for more details about obtaining
1305      * the correct arguments for this method.
1306      *
1307      * @param inputDeviceId the ID of the {@link InputDevice} that generated the motion that may
1308      *      produce scroll haptics.
1309      * @param source the input source of the motion that may produce scroll haptics.
1310      * @param axis the axis of the motion that may produce scroll haptics.
1311      * @return the absolute value of the minimum scroll interval, in pixels, between consecutive
1312      *      scroll feedback haptics for motions generated by the provided input and motion
1313      *      configuration. If scroll haptics is disabled for the given configuration, or if the
1314      *      device does not support scroll tick haptics for the given configuration, this method
1315      *      returns {@code Integer.MAX_VALUE}.
1316      *
1317      * @see #isHapticScrollFeedbackEnabled(int, int, int)
1318      *
1319      * @hide
1320      */
getHapticScrollFeedbackTickInterval(int inputDeviceId, int axis, int source)1321     public int getHapticScrollFeedbackTickInterval(int inputDeviceId, int axis, int source) {
1322         if (!mRotaryEncoderHapticScrollFeedbackEnabled) {
1323             return NO_HAPTIC_SCROLL_TICK_INTERVAL;
1324         }
1325 
1326         if (!isInputDeviceInfoValid(inputDeviceId, axis, source)) {
1327             return NO_HAPTIC_SCROLL_TICK_INTERVAL;
1328         }
1329 
1330         if (source == InputDevice.SOURCE_ROTARY_ENCODER && axis == MotionEvent.AXIS_SCROLL) {
1331             return mRotaryEncoderHapticScrollFeedbackTickIntervalPixels;
1332         }
1333 
1334         return NO_HAPTIC_SCROLL_TICK_INTERVAL;
1335     }
1336 
1337     /**
1338      * Checks if the View-based haptic scroll feedback implementation is enabled for
1339      * {@link InputDevice#SOURCE_ROTARY_ENCODER}s.
1340      *
1341      * @hide
1342      */
isViewBasedRotaryEncoderHapticScrollFeedbackEnabled()1343     public boolean isViewBasedRotaryEncoderHapticScrollFeedbackEnabled() {
1344         return mViewBasedRotaryEncoderScrollHapticsEnabledConfig
1345                 && Flags.useViewBasedRotaryEncoderScrollHaptics();
1346     }
1347 
isInputDeviceInfoValid(int id, int axis, int source)1348     private static boolean isInputDeviceInfoValid(int id, int axis, int source) {
1349         InputDevice device = InputManagerGlobal.getInstance().getInputDevice(id);
1350         return device != null && device.getMotionRange(axis, source) != null;
1351     }
1352 
1353     /**
1354      * Check if shortcuts should be displayed in menus.
1355      *
1356      * @return {@code True} if shortcuts should be displayed in menus.
1357      */
shouldShowMenuShortcutsWhenKeyboardPresent()1358     public boolean shouldShowMenuShortcutsWhenKeyboardPresent() {
1359         return mShowMenuShortcutsWhenKeyboardPresent;
1360     }
1361 
1362     /**
1363      * Retrieves the distance in pixels between touches that must be reached for a gesture to be
1364      * interpreted as scaling.
1365      *
1366      * In general, scaling shouldn't start until this distance has been met or surpassed, and
1367      * scaling should end when the distance in pixels between touches drops below this distance.
1368      *
1369      * @return The distance in pixels
1370      * @throws IllegalStateException if this method is called on a ViewConfiguration that was
1371      *         instantiated using a constructor with no Context parameter.
1372      */
getScaledMinimumScalingSpan()1373     public int getScaledMinimumScalingSpan() {
1374         if (!mConstructedWithContext) {
1375             throw new IllegalStateException("Min scaling span cannot be determined when this "
1376                     + "method is called on a ViewConfiguration that was instantiated using a "
1377                     + "constructor with no Context parameter");
1378         }
1379         return mMinScalingSpan;
1380     }
1381 
1382     /**
1383      * @hide
1384      * @return Whether or not marquee should use fading edges.
1385      */
1386     @UnsupportedAppUsage
isFadingMarqueeEnabled()1387     public boolean isFadingMarqueeEnabled() {
1388         return mFadingMarqueeEnabled;
1389     }
1390 
1391     /**
1392      * @return the timeout value in milliseconds to adjust the selection span and actions for the
1393      *         selected text when TextClassifier has been initialized.
1394      * @hide
1395      */
getSmartSelectionInitializedTimeout()1396     public int getSmartSelectionInitializedTimeout() {
1397         return mSmartSelectionInitializedTimeout;
1398     }
1399 
1400     /**
1401      * @return the timeout value in milliseconds to adjust the selection span and actions for the
1402      *         selected text when TextClassifier has not been initialized.
1403      * @hide
1404      */
getSmartSelectionInitializingTimeout()1405     public int getSmartSelectionInitializingTimeout() {
1406         return mSmartSelectionInitializingTimeout;
1407     }
1408 
1409     /**
1410      * @return {@code true} if Views should set themselves as preferred to keep clear when focused,
1411      * {@code false} otherwise.
1412      * @hide
1413      */
1414     @TestApi
isPreferKeepClearForFocusEnabled()1415     public boolean isPreferKeepClearForFocusEnabled() {
1416         return mPreferKeepClearForFocusEnabled;
1417     }
1418 
1419     /**
1420      * @return the duration in milliseconds before an end of a long press causes a tooltip to be
1421      * hidden
1422      * @hide
1423      */
1424     @TestApi
getLongPressTooltipHideTimeout()1425     public static int getLongPressTooltipHideTimeout() {
1426         return LONG_PRESS_TOOLTIP_HIDE_TIMEOUT;
1427     }
1428 
1429     /**
1430      * @return the duration in milliseconds before a hover event causes a tooltip to be shown
1431      * @hide
1432      */
1433     @TestApi
getHoverTooltipShowTimeout()1434     public static int getHoverTooltipShowTimeout() {
1435         return HOVER_TOOLTIP_SHOW_TIMEOUT;
1436     }
1437 
1438     /**
1439      * @return the duration in milliseconds before mouse inactivity causes a tooltip to be hidden
1440      * (default variant to be used when {@link View#SYSTEM_UI_FLAG_LOW_PROFILE} is not set).
1441      * @hide
1442      */
1443     @TestApi
getHoverTooltipHideTimeout()1444     public static int getHoverTooltipHideTimeout() {
1445         return HOVER_TOOLTIP_HIDE_TIMEOUT;
1446     }
1447 
1448     /**
1449      * @return the duration in milliseconds before mouse inactivity causes a tooltip to be hidden
1450      * (shorter variant to be used when {@link View#SYSTEM_UI_FLAG_LOW_PROFILE} is set).
1451      * @hide
1452      */
1453     @TestApi
getHoverTooltipHideShortTimeout()1454     public static int getHoverTooltipHideShortTimeout() {
1455         return HOVER_TOOLTIP_HIDE_SHORT_TIMEOUT;
1456     }
1457 
getDisplayDensity(Context context)1458     private static int getDisplayDensity(Context context) {
1459         final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
1460         return (int) (100.0f * metrics.density);
1461     }
1462 
1463     /**
1464      * Fetches resource values statically and caches them locally for fast lookup. Note that these
1465      * values will not be updated during the lifetime of a process, even if resource overlays are
1466      * applied.
1467      */
1468     private static final class ResourceCache {
1469 
1470         private int mPressedStateDuration = -1;
1471         private int mTapTimeout = -1;
1472         private int mJumpTapTimeout = -1;
1473         private int mDoubleTapTimeout = -1;
1474         private int mDoubleTapMinTime = -1;
1475         private int mHoverTapTimeout = -1;
1476         private int mHoverTapSlop = -1;
1477         private long mZoomControlsTimeout = -1L;
1478         private float mScrollFriction = -1f;
1479         private long mDefaultActionModeHideDuration = -1L;
1480 
getPressedStateDuration()1481         public int getPressedStateDuration() {
1482             if (mPressedStateDuration < 0) {
1483                 Resources resources = getCurrentResources();
1484                 mPressedStateDuration = resources != null
1485                         ? resources.getInteger(R.integer.config_pressedStateDurationMillis)
1486                         : PRESSED_STATE_DURATION;
1487             }
1488             return mPressedStateDuration;
1489         }
1490 
getTapTimeout()1491         public int getTapTimeout() {
1492             if (mTapTimeout < 0) {
1493                 Resources resources = getCurrentResources();
1494                 mTapTimeout = resources != null
1495                         ? resources.getInteger(R.integer.config_tapTimeoutMillis)
1496                         : TAP_TIMEOUT;
1497             }
1498             return mTapTimeout;
1499         }
1500 
getJumpTapTimeout()1501         public int getJumpTapTimeout() {
1502             if (mJumpTapTimeout < 0) {
1503                 Resources resources = getCurrentResources();
1504                 mJumpTapTimeout = resources != null
1505                         ? resources.getInteger(R.integer.config_jumpTapTimeoutMillis)
1506                         : JUMP_TAP_TIMEOUT;
1507             }
1508             return mJumpTapTimeout;
1509         }
1510 
getDoubleTapTimeout()1511         public int getDoubleTapTimeout() {
1512             if (mDoubleTapTimeout < 0) {
1513                 Resources resources = getCurrentResources();
1514                 mDoubleTapTimeout = resources != null
1515                         ? resources.getInteger(R.integer.config_doubleTapTimeoutMillis)
1516                         : DOUBLE_TAP_TIMEOUT;
1517             }
1518             return mDoubleTapTimeout;
1519         }
1520 
getDoubleTapMinTime()1521         public int getDoubleTapMinTime() {
1522             if (mDoubleTapMinTime < 0) {
1523                 Resources resources = getCurrentResources();
1524                 mDoubleTapMinTime = resources != null
1525                         ? resources.getInteger(R.integer.config_doubleTapMinTimeMillis)
1526                         : DOUBLE_TAP_MIN_TIME;
1527             }
1528             return mDoubleTapMinTime;
1529         }
1530 
getHoverTapTimeout()1531         public int getHoverTapTimeout() {
1532             if (mHoverTapTimeout < 0) {
1533                 Resources resources = getCurrentResources();
1534                 mHoverTapTimeout = resources != null
1535                         ? resources.getInteger(R.integer.config_hoverTapTimeoutMillis)
1536                         : HOVER_TAP_TIMEOUT;
1537             }
1538             return mHoverTapTimeout;
1539         }
1540 
getHoverTapSlop()1541         public int getHoverTapSlop() {
1542             if (mHoverTapSlop < 0) {
1543                 Resources resources = getCurrentResources();
1544                 mHoverTapSlop = resources != null
1545                         ? resources.getDimensionPixelSize(R.dimen.config_hoverTapSlop)
1546                         : HOVER_TAP_SLOP;
1547             }
1548             return mHoverTapSlop;
1549         }
1550 
getZoomControlsTimeout()1551         public long getZoomControlsTimeout() {
1552             if (mZoomControlsTimeout < 0) {
1553                 Resources resources = getCurrentResources();
1554                 mZoomControlsTimeout = resources != null
1555                         ? resources.getInteger(R.integer.config_zoomControlsTimeoutMillis)
1556                         : ZOOM_CONTROLS_TIMEOUT;
1557             }
1558             return mZoomControlsTimeout;
1559         }
1560 
getScrollFriction()1561         public float getScrollFriction() {
1562             if (mScrollFriction < 0) {
1563                 Resources resources = getCurrentResources();
1564                 mScrollFriction = resources != null
1565                         ? resources.getFloat(R.dimen.config_scrollFriction)
1566                         : SCROLL_FRICTION;
1567             }
1568             return mScrollFriction;
1569         }
1570 
getDefaultActionModeHideDuration()1571         public long getDefaultActionModeHideDuration() {
1572             if (mDefaultActionModeHideDuration < 0) {
1573                 Resources resources = getCurrentResources();
1574                 mDefaultActionModeHideDuration = resources != null
1575                         ? resources.getInteger(R.integer.config_defaultActionModeHideDurationMillis)
1576                         : ACTION_MODE_HIDE_DURATION_DEFAULT;
1577             }
1578             return mDefaultActionModeHideDuration;
1579         }
1580 
getCurrentResources()1581         private static Resources getCurrentResources() {
1582             if (!android.companion.virtualdevice.flags.Flags
1583                     .migrateViewconfigurationConstantsToResources()) {
1584                 return null;
1585             }
1586             Application application = ActivityThread.currentApplication();
1587             Context context = application != null ? application.getApplicationContext() : null;
1588             return context != null ? context.getResources() : null;
1589         }
1590     }
1591 }
1592