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