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