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 static android.content.res.Resources.ID_NULL; 20 import static android.os.Trace.TRACE_TAG_APP; 21 import static android.os.Trace.TRACE_TAG_VIEW; 22 import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION; 23 import static android.view.ContentInfo.SOURCE_DRAG_AND_DROP; 24 import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH; 25 import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH_HINT; 26 import static android.view.Surface.FRAME_RATE_CATEGORY_LOW; 27 import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL; 28 import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE; 29 import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; 30 import static android.view.Surface.FRAME_RATE_COMPATIBILITY_AT_LEAST; 31 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; 32 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; 33 import static android.view.accessibility.Flags.FLAG_DEPRECATE_ACCESSIBILITY_ANNOUNCEMENT_APIS; 34 import static android.view.accessibility.Flags.FLAG_SUPPLEMENTAL_DESCRIPTION; 35 import static android.view.accessibility.Flags.removeChildHoverCheckForTouchExploration; 36 import static android.view.accessibility.Flags.supplementalDescription; 37 import static android.view.accessibility.Flags.supportMultipleLabeledby; 38 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS; 39 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW; 40 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN; 41 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_UNKNOWN; 42 import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH; 43 import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE; 44 import static android.view.flags.Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API; 45 import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY; 46 import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API; 47 import static android.view.flags.Flags.calculateBoundsInParentFromBoundsInScreen; 48 import static android.view.flags.Flags.enableUseMeasureCacheDuringForceLayout; 49 import static android.view.flags.Flags.sensitiveContentAppProtection; 50 import static android.view.flags.Flags.toolkitFrameRateAnimationBugfix25q1; 51 import static android.view.flags.Flags.toolkitFrameRateBySizeReadOnly; 52 import static android.view.flags.Flags.toolkitFrameRateDefaultNormalReadOnly; 53 import static android.view.flags.Flags.toolkitFrameRateSmallUsesPercentReadOnly; 54 import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly; 55 import static android.view.flags.Flags.toolkitFrameRateViewEnablingReadOnly; 56 import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision; 57 import static android.view.flags.Flags.toolkitSetFrameRateReadOnly; 58 import static android.view.flags.Flags.toolkitViewgroupSetRequestedFrameRateApi; 59 import static android.view.flags.Flags.viewVelocityApi; 60 import static android.view.inputmethod.Flags.FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR; 61 import static android.view.inputmethod.Flags.initiationWithoutInputConnection; 62 63 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS; 64 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS; 65 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP; 66 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; 67 import static com.android.window.flags.Flags.FLAG_DELEGATE_UNHANDLED_DRAGS; 68 import static com.android.window.flags.Flags.FLAG_SUPPORTS_DRAG_ASSISTANT_TO_MULTIWINDOW; 69 import static com.android.window.flags.Flags.reduceChangedExclusionRectsMsgs; 70 71 import static java.lang.Math.max; 72 73 import android.animation.AnimatorInflater; 74 import android.animation.StateListAnimator; 75 import android.annotation.AttrRes; 76 import android.annotation.CallSuper; 77 import android.annotation.ColorInt; 78 import android.annotation.DrawableRes; 79 import android.annotation.FlaggedApi; 80 import android.annotation.FloatRange; 81 import android.annotation.IdRes; 82 import android.annotation.IntDef; 83 import android.annotation.IntRange; 84 import android.annotation.LayoutRes; 85 import android.annotation.NonNull; 86 import android.annotation.Nullable; 87 import android.annotation.RequiresPermission; 88 import android.annotation.Size; 89 import android.annotation.StyleRes; 90 import android.annotation.SuppressLint; 91 import android.annotation.SystemApi; 92 import android.annotation.TestApi; 93 import android.annotation.UiContext; 94 import android.annotation.UiThread; 95 import android.app.PendingIntent; 96 import android.app.jank.AppJankStats; 97 import android.app.jank.JankTracker; 98 import android.compat.annotation.UnsupportedAppUsage; 99 import android.content.AutofillOptions; 100 import android.content.ClipData; 101 import android.content.ClipDescription; 102 import android.content.Context; 103 import android.content.ContextWrapper; 104 import android.content.Intent; 105 import android.content.IntentSender; 106 import android.content.res.ColorStateList; 107 import android.content.res.CompatibilityInfo; 108 import android.content.res.Configuration; 109 import android.content.res.Resources; 110 import android.content.res.TypedArray; 111 import android.credentials.CredentialManager; 112 import android.credentials.CredentialOption; 113 import android.credentials.GetCredentialException; 114 import android.credentials.GetCredentialRequest; 115 import android.credentials.GetCredentialResponse; 116 import android.graphics.Bitmap; 117 import android.graphics.BlendMode; 118 import android.graphics.Canvas; 119 import android.graphics.Color; 120 import android.graphics.Insets; 121 import android.graphics.Interpolator; 122 import android.graphics.LinearGradient; 123 import android.graphics.Matrix; 124 import android.graphics.Outline; 125 import android.graphics.Paint; 126 import android.graphics.PixelFormat; 127 import android.graphics.Point; 128 import android.graphics.PorterDuff; 129 import android.graphics.PorterDuffXfermode; 130 import android.graphics.RecordingCanvas; 131 import android.graphics.Rect; 132 import android.graphics.RectF; 133 import android.graphics.Region; 134 import android.graphics.RenderEffect; 135 import android.graphics.RenderNode; 136 import android.graphics.Shader; 137 import android.graphics.drawable.ColorDrawable; 138 import android.graphics.drawable.Drawable; 139 import android.graphics.drawable.GradientDrawable; 140 import android.hardware.display.DisplayManagerGlobal; 141 import android.hardware.input.InputManager; 142 import android.net.Uri; 143 import android.os.Build; 144 import android.os.Bundle; 145 import android.os.Handler; 146 import android.os.IBinder; 147 import android.os.Message; 148 import android.os.OutcomeReceiver; 149 import android.os.Parcel; 150 import android.os.Parcelable; 151 import android.os.RemoteCallback; 152 import android.os.RemoteException; 153 import android.os.SystemClock; 154 import android.os.Trace; 155 import android.service.credentials.CredentialProviderService; 156 import android.sysprop.DisplayProperties; 157 import android.text.InputType; 158 import android.text.TextUtils; 159 import android.util.ArraySet; 160 import android.util.AttributeSet; 161 import android.util.DisplayMetrics; 162 import android.util.FloatProperty; 163 import android.util.LayoutDirection; 164 import android.util.Log; 165 import android.util.LongSparseArray; 166 import android.util.LongSparseLongArray; 167 import android.util.Pair; 168 import android.util.Pools.SynchronizedPool; 169 import android.util.Property; 170 import android.util.SparseArray; 171 import android.util.SparseIntArray; 172 import android.util.StateSet; 173 import android.util.SuperNotCalledException; 174 import android.util.TimeUtils; 175 import android.util.TypedValue; 176 import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 177 import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 178 import android.view.AccessibilityIterators.TextSegmentIterator; 179 import android.view.AccessibilityIterators.WordTextSegmentIterator; 180 import android.view.ContextMenu.ContextMenuInfo; 181 import android.view.InputDevice.InputSourceClass; 182 import android.view.Window.OnContentApplyWindowInsetsListener; 183 import android.view.WindowInsets.Type; 184 import android.view.WindowInsetsAnimation.Bounds; 185 import android.view.WindowManager.LayoutParams; 186 import android.view.accessibility.AccessibilityEvent; 187 import android.view.accessibility.AccessibilityEventSource; 188 import android.view.accessibility.AccessibilityManager; 189 import android.view.accessibility.AccessibilityNodeIdManager; 190 import android.view.accessibility.AccessibilityNodeInfo; 191 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 192 import android.view.accessibility.AccessibilityNodeProvider; 193 import android.view.accessibility.AccessibilityWindowInfo; 194 import android.view.animation.Animation; 195 import android.view.animation.AnimationUtils; 196 import android.view.animation.Transformation; 197 import android.view.autofill.AutofillId; 198 import android.view.autofill.AutofillManager; 199 import android.view.autofill.AutofillValue; 200 import android.view.contentcapture.ContentCaptureContext; 201 import android.view.contentcapture.ContentCaptureManager; 202 import android.view.contentcapture.ContentCaptureSession; 203 import android.view.displayhash.DisplayHash; 204 import android.view.displayhash.DisplayHashManager; 205 import android.view.displayhash.DisplayHashResultCallback; 206 import android.view.inputmethod.EditorInfo; 207 import android.view.inputmethod.InputConnection; 208 import android.view.inputmethod.InputMethodManager; 209 import android.view.inspector.InspectableProperty; 210 import android.view.inspector.InspectableProperty.EnumEntry; 211 import android.view.inspector.InspectableProperty.FlagEntry; 212 import android.view.translation.TranslationCapability; 213 import android.view.translation.TranslationSpec.DataFormat; 214 import android.view.translation.ViewTranslationCallback; 215 import android.view.translation.ViewTranslationRequest; 216 import android.view.translation.ViewTranslationResponse; 217 import android.widget.Checkable; 218 import android.widget.ScrollBarDrawable; 219 import android.window.OnBackInvokedDispatcher; 220 221 import com.android.internal.R; 222 import com.android.internal.util.ArrayUtils; 223 import com.android.internal.util.FrameworkStatsLog; 224 import com.android.internal.util.Preconditions; 225 import com.android.internal.view.ScrollCaptureInternal; 226 import com.android.internal.view.TooltipPopup; 227 import com.android.internal.view.menu.MenuBuilder; 228 import com.android.internal.widget.ScrollBarUtils; 229 230 import com.google.android.collect.Lists; 231 import com.google.android.collect.Maps; 232 233 import java.io.PrintWriter; 234 import java.lang.annotation.Retention; 235 import java.lang.annotation.RetentionPolicy; 236 import java.lang.ref.WeakReference; 237 import java.lang.reflect.Field; 238 import java.lang.reflect.InvocationTargetException; 239 import java.lang.reflect.Method; 240 import java.lang.reflect.Modifier; 241 import java.time.Duration; 242 import java.util.ArrayList; 243 import java.util.Arrays; 244 import java.util.Calendar; 245 import java.util.Collection; 246 import java.util.Collections; 247 import java.util.HashMap; 248 import java.util.List; 249 import java.util.Locale; 250 import java.util.Map; 251 import java.util.Objects; 252 import java.util.concurrent.CopyOnWriteArrayList; 253 import java.util.concurrent.Executor; 254 import java.util.concurrent.atomic.AtomicInteger; 255 import java.util.function.Consumer; 256 import java.util.function.Predicate; 257 258 /** 259 * <p> 260 * This class represents the basic building block for user interface components. A View 261 * occupies a rectangular area on the screen and is responsible for drawing and 262 * event handling. View is the base class for <em>widgets</em>, which are 263 * used to create interactive UI components (buttons, text fields, etc.). The 264 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 265 * are invisible containers that hold other Views (or other ViewGroups) and define 266 * their layout properties. 267 * </p> 268 * 269 * <div class="special reference"> 270 * <h3>Developer Guides</h3> 271 * <p>For information about using this class to develop your application's user interface, 272 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 273 * </div> 274 * 275 * <a name="Using"></a> 276 * <h3>Using Views</h3> 277 * <p> 278 * All of the views in a window are arranged in a single tree. You can add views 279 * either from code or by specifying a tree of views in one or more XML layout 280 * files. There are many specialized subclasses of views that act as controls or 281 * are capable of displaying text, images, or other content. 282 * </p> 283 * <p> 284 * Once you have created a tree of views, there are typically a few types of 285 * common operations you may wish to perform: 286 * <ul> 287 * <li><strong>Set properties:</strong> for example setting the text of a 288 * {@link android.widget.TextView}. The available properties and the methods 289 * that set them will vary among the different subclasses of views. Note that 290 * properties that are known at build time can be set in the XML layout 291 * files.</li> 292 * <li><strong>Set focus:</strong> The framework will handle moving focus in 293 * response to user input. To force focus to a specific view, call 294 * {@link #requestFocus}.</li> 295 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 296 * that will be notified when something interesting happens to the view. For 297 * example, all views will let you set a listener to be notified when the view 298 * gains or loses focus. You can register such a listener using 299 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 300 * Other view subclasses offer more specialized listeners. For example, a Button 301 * exposes a listener to notify clients when the button is clicked.</li> 302 * <li><strong>Set visibility:</strong> You can hide or show views using 303 * {@link #setVisibility(int)}.</li> 304 * </ul> 305 * </p> 306 * <p><em> 307 * Note: The Android framework is responsible for measuring, laying out and 308 * drawing views. You should not call methods that perform these actions on 309 * views yourself unless you are actually implementing a 310 * {@link android.view.ViewGroup}. 311 * </em></p> 312 * 313 * <a name="Lifecycle"></a> 314 * <h3>Implementing a Custom View</h3> 315 * 316 * <p> 317 * To implement a custom view, you will usually begin by providing overrides for 318 * some of the standard methods that the framework calls on all views. You do 319 * not need to override all of these methods. In fact, you can start by just 320 * overriding {@link #onDraw(android.graphics.Canvas)}. 321 * <table border="2" width="85%" align="center" cellpadding="5"> 322 * <thead> 323 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 324 * </thead> 325 * 326 * <tbody> 327 * <tr> 328 * <td rowspan="2">Creation</td> 329 * <td>Constructors</td> 330 * <td>There is a form of the constructor that are called when the view 331 * is created from code and a form that is called when the view is 332 * inflated from a layout file. The second form should parse and apply 333 * any attributes defined in the layout file. 334 * </td> 335 * </tr> 336 * <tr> 337 * <td><code>{@link #onFinishInflate()}</code></td> 338 * <td>Called after a view and all of its children has been inflated 339 * from XML.</td> 340 * </tr> 341 * 342 * <tr> 343 * <td rowspan="3">Layout</td> 344 * <td><code>{@link #onMeasure(int, int)}</code></td> 345 * <td>Called to determine the size requirements for this view and all 346 * of its children. 347 * </td> 348 * </tr> 349 * <tr> 350 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 351 * <td>Called when this view should assign a size and position to all 352 * of its children. 353 * </td> 354 * </tr> 355 * <tr> 356 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 357 * <td>Called when the size of this view has changed. 358 * </td> 359 * </tr> 360 * 361 * <tr> 362 * <td>Drawing</td> 363 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 364 * <td>Called when the view should render its content. 365 * </td> 366 * </tr> 367 * 368 * <tr> 369 * <td rowspan="6">Event processing</td> 370 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 371 * <td>Called when a new hardware key event occurs. 372 * </td> 373 * </tr> 374 * <tr> 375 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 376 * <td>Called when a hardware key up event occurs. 377 * </td> 378 * </tr> 379 * <tr> 380 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 381 * <td>Called when a trackball motion event occurs. 382 * </td> 383 * </tr> 384 * <tr> 385 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 386 * <td>Called when a motion event occurs with pointers down on the view. 387 * </td> 388 * </tr> 389 * <tr> 390 * <td><code>{@link #onGenericMotionEvent(MotionEvent)}</code></td> 391 * <td>Called when a generic motion event occurs. 392 * </td> 393 * </tr> 394 * <tr> 395 * <td><code>{@link #onHoverEvent(MotionEvent)}</code></td> 396 * <td>Called when a hover motion event occurs. 397 * </td> 398 * </tr> 399 * 400 * <tr> 401 * <td rowspan="2">Focus</td> 402 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 403 * <td>Called when the view gains or loses focus. 404 * </td> 405 * </tr> 406 * 407 * <tr> 408 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 409 * <td>Called when the window containing the view gains or loses focus. 410 * </td> 411 * </tr> 412 * 413 * <tr> 414 * <td rowspan="3">Attaching</td> 415 * <td><code>{@link #onAttachedToWindow()}</code></td> 416 * <td>Called when the view is attached to a window. 417 * </td> 418 * </tr> 419 * 420 * <tr> 421 * <td><code>{@link #onDetachedFromWindow}</code></td> 422 * <td>Called when the view is detached from its window. 423 * </td> 424 * </tr> 425 * 426 * <tr> 427 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 428 * <td>Called when the visibility of the window containing the view 429 * has changed. 430 * </td> 431 * </tr> 432 * </tbody> 433 * 434 * </table> 435 * </p> 436 * 437 * <a name="IDs"></a> 438 * <h3>IDs</h3> 439 * Views may have an integer id associated with them. These ids are typically 440 * assigned in the layout XML files, and are used to find specific views within 441 * the view tree. A common pattern is to: 442 * <ul> 443 * <li>Define a Button in the layout file and assign it a unique ID. 444 * <pre> 445 * <Button 446 * android:id="@+id/my_button" 447 * android:layout_width="wrap_content" 448 * android:layout_height="wrap_content" 449 * android:text="@string/my_button_text"/> 450 * </pre></li> 451 * <li>From the onCreate method of an Activity, find the Button 452 * <pre class="prettyprint"> 453 * Button myButton = findViewById(R.id.my_button); 454 * </pre></li> 455 * </ul> 456 * <p> 457 * View IDs need not be unique throughout the tree, but it is good practice to 458 * ensure that they are at least unique within the part of the tree you are 459 * searching. 460 * </p> 461 * 462 * <a name="Position"></a> 463 * <h3>Position</h3> 464 * <p> 465 * The geometry of a view is that of a rectangle. A view has a location, 466 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 467 * two dimensions, expressed as a width and a height. The unit for location 468 * and dimensions is the pixel. 469 * </p> 470 * 471 * <p> 472 * It is possible to retrieve the location of a view by invoking the methods 473 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 474 * coordinate of the rectangle representing the view. The latter returns the 475 * top, or Y, coordinate of the rectangle representing the view. These methods 476 * both return the location of the view relative to its parent. For instance, 477 * when getLeft() returns 20, that means the view is located 20 pixels to the 478 * right of the left edge of its direct parent. 479 * </p> 480 * 481 * <p> 482 * In addition, several convenience methods are offered to avoid unnecessary 483 * computations, namely {@link #getRight()} and {@link #getBottom()}. 484 * These methods return the coordinates of the right and bottom edges of the 485 * rectangle representing the view. For instance, calling {@link #getRight()} 486 * is similar to the following computation: <code>getLeft() + getWidth()</code> 487 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 488 * </p> 489 * 490 * <a name="SizePaddingMargins"></a> 491 * <h3>Size, padding and margins</h3> 492 * <p> 493 * The size of a view is expressed with a width and a height. A view actually 494 * possess two pairs of width and height values. 495 * </p> 496 * 497 * <p> 498 * The first pair is known as <em>measured width</em> and 499 * <em>measured height</em>. These dimensions define how big a view wants to be 500 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 501 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 502 * and {@link #getMeasuredHeight()}. 503 * </p> 504 * 505 * <p> 506 * The second pair is simply known as <em>width</em> and <em>height</em>, or 507 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 508 * dimensions define the actual size of the view on screen, at drawing time and 509 * after layout. These values may, but do not have to, be different from the 510 * measured width and height. The width and height can be obtained by calling 511 * {@link #getWidth()} and {@link #getHeight()}. 512 * </p> 513 * 514 * <p> 515 * To measure its dimensions, a view takes into account its padding. The padding 516 * is expressed in pixels for the left, top, right and bottom parts of the view. 517 * Padding can be used to offset the content of the view by a specific amount of 518 * pixels. For instance, a left padding of 2 will push the view's content by 519 * 2 pixels to the right of the left edge. Padding can be set using the 520 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 521 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 522 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 523 * {@link #getPaddingEnd()}. 524 * </p> 525 * 526 * <p> 527 * Even though a view can define a padding, it does not provide any support for 528 * margins. However, view groups provide such a support. Refer to 529 * {@link android.view.ViewGroup} and 530 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 531 * </p> 532 * 533 * <a name="Layout"></a> 534 * <h3>Layout</h3> 535 * <p> 536 * Layout is a two pass process: a measure pass and a layout pass. The measuring 537 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 538 * of the view tree. Each view pushes dimension specifications down the tree 539 * during the recursion. At the end of the measure pass, every view has stored 540 * its measurements. The second pass happens in 541 * {@link #layout(int,int,int,int)} and is also top-down. During 542 * this pass each parent is responsible for positioning all of its children 543 * using the sizes computed in the measure pass. 544 * </p> 545 * 546 * <p> 547 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 548 * {@link #getMeasuredHeight()} values must be set, along with those for all of 549 * that view's descendants. A view's measured width and measured height values 550 * must respect the constraints imposed by the view's parents. This guarantees 551 * that at the end of the measure pass, all parents accept all of their 552 * children's measurements. A parent view may call measure() more than once on 553 * its children. For example, the parent may measure each child once with 554 * unspecified dimensions to find out how big they want to be, then call 555 * measure() on them again with actual numbers if the sum of all the children's 556 * unconstrained sizes is too big or too small. 557 * </p> 558 * 559 * <p> 560 * The measure pass uses two classes to communicate dimensions. The 561 * {@link MeasureSpec} class is used by views to tell their parents how they 562 * want to be measured and positioned. The base LayoutParams class just 563 * describes how big the view wants to be for both width and height. For each 564 * dimension, it can specify one of: 565 * <ul> 566 * <li> an exact number 567 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 568 * (minus padding) 569 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 570 * enclose its content (plus padding). 571 * </ul> 572 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 573 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 574 * an X and Y value. 575 * </p> 576 * 577 * <p> 578 * MeasureSpecs are used to push requirements down the tree from parent to 579 * child. A MeasureSpec can be in one of three modes: 580 * <ul> 581 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 582 * of a child view. For example, a LinearLayout may call measure() on its child 583 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 584 * tall the child view wants to be given a width of 240 pixels. 585 * <li>EXACTLY: This is used by the parent to impose an exact size on the 586 * child. The child must use this size, and guarantee that all of its 587 * descendants will fit within this size. 588 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 589 * child. The child must guarantee that it and all of its descendants will fit 590 * within this size. 591 * </ul> 592 * </p> 593 * 594 * <p> 595 * To initiate a layout, call {@link #requestLayout}. This method is typically 596 * called by a view on itself when it believes that it can no longer fit within 597 * its current bounds. 598 * </p> 599 * 600 * <a name="Drawing"></a> 601 * <h3>Drawing</h3> 602 * <p> 603 * Drawing is handled by walking the tree and recording the drawing commands of 604 * any View that needs to update. After this, the drawing commands of the 605 * entire tree are issued to screen, clipped to the newly damaged area. 606 * </p> 607 * 608 * <p> 609 * The tree is largely recorded and drawn in order, with parents drawn before 610 * (i.e., behind) their children, with siblings drawn in the order they appear 611 * in the tree. If you set a background drawable for a View, then the View will 612 * draw it before calling back to its <code>onDraw()</code> method. The child 613 * drawing order can be overridden with 614 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 615 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 616 * </p> 617 * 618 * <p> 619 * To force a view to draw, call {@link #invalidate()}. 620 * </p> 621 * 622 * <a name="EventHandlingThreading"></a> 623 * <h3>Event Handling and Threading</h3> 624 * <p> 625 * The basic cycle of a view is as follows: 626 * <ol> 627 * <li>An event comes in and is dispatched to the appropriate view. The view 628 * handles the event and notifies any listeners.</li> 629 * <li>If in the course of processing the event, the view's bounds may need 630 * to be changed, the view will call {@link #requestLayout()}.</li> 631 * <li>Similarly, if in the course of processing the event the view's appearance 632 * may need to be changed, the view will call {@link #invalidate()}.</li> 633 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 634 * the framework will take care of measuring, laying out, and drawing the tree 635 * as appropriate.</li> 636 * </ol> 637 * </p> 638 * 639 * <p><em>Note: The entire view tree is single threaded. You must always be on 640 * the UI thread when calling any method on any view.</em> 641 * If you are doing work on other threads and want to update the state of a view 642 * from that thread, you should use a {@link Handler}. 643 * </p> 644 * 645 * <a name="FocusHandling"></a> 646 * <h3>Focus Handling</h3> 647 * <p> 648 * The framework will handle routine focus movement in response to user input. 649 * This includes changing the focus as views are removed or hidden, or as new 650 * views become available. Views indicate their willingness to take focus 651 * through the {@link #isFocusable} method. To change whether a view can take 652 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 653 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 654 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 655 * </p> 656 * <p> 657 * Focus movement is based on an algorithm which finds the nearest neighbor in a 658 * given direction. In rare cases, the default algorithm may not match the 659 * intended behavior of the developer. In these situations, you can provide 660 * explicit overrides by using these XML attributes in the layout file: 661 * <pre> 662 * nextFocusDown 663 * nextFocusLeft 664 * nextFocusRight 665 * nextFocusUp 666 * </pre> 667 * </p> 668 * 669 * 670 * <p> 671 * To get a particular view to take focus, call {@link #requestFocus()}. 672 * </p> 673 * 674 * <a name="TouchMode"></a> 675 * <h3>Touch Mode</h3> 676 * <p> 677 * When a user is navigating a user interface via directional keys such as a D-pad, it is 678 * necessary to give focus to actionable items such as buttons so the user can see 679 * what will take input. If the device has touch capabilities, however, and the user 680 * begins interacting with the interface by touching it, it is no longer necessary to 681 * always highlight, or give focus to, a particular view. This motivates a mode 682 * for interaction named 'touch mode'. 683 * </p> 684 * <p> 685 * For a touch capable device, once the user touches the screen, the device 686 * will enter touch mode. From this point onward, only views for which 687 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 688 * Other views that are touchable, like buttons, will not take focus when touched; they will 689 * only fire the on click listeners. 690 * </p> 691 * <p> 692 * Any time a user hits a directional key, such as a D-pad direction, the view device will 693 * exit touch mode, and find a view to take focus, so that the user may resume interacting 694 * with the user interface without touching the screen again. 695 * </p> 696 * <p> 697 * The touch mode state is maintained across {@link android.app.Activity}s. Call 698 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 699 * </p> 700 * 701 * <a name="Scrolling"></a> 702 * <h3>Scrolling</h3> 703 * <p> 704 * The framework provides basic support for views that wish to internally 705 * scroll their content. This includes keeping track of the X and Y scroll 706 * offset as well as mechanisms for drawing scrollbars. See 707 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 708 * {@link #awakenScrollBars()} for more details. 709 * </p> 710 * 711 * <a name="Tags"></a> 712 * <h3>Tags</h3> 713 * <p> 714 * Unlike IDs, tags are not used to identify views. Tags are essentially an 715 * extra piece of information that can be associated with a view. They are most 716 * often used as a convenience to store data related to views in the views 717 * themselves rather than by putting them in a separate structure. 718 * </p> 719 * <p> 720 * Tags may be specified with character sequence values in layout XML as either 721 * a single tag using the {@link android.R.styleable#View_tag android:tag} 722 * attribute or multiple tags using the {@code <tag>} child element: 723 * <pre> 724 * <View ... 725 * android:tag="@string/mytag_value" /> 726 * <View ...> 727 * <tag android:id="@+id/mytag" 728 * android:value="@string/mytag_value" /> 729 * </View> 730 * </pre> 731 * </p> 732 * <p> 733 * Tags may also be specified with arbitrary objects from code using 734 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 735 * </p> 736 * 737 * <a name="Themes"></a> 738 * <h3>Themes</h3> 739 * <p> 740 * By default, Views are created using the theme of the Context object supplied 741 * to their constructor; however, a different theme may be specified by using 742 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 743 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 744 * code. 745 * </p> 746 * <p> 747 * When the {@link android.R.styleable#View_theme android:theme} attribute is 748 * used in XML, the specified theme is applied on top of the inflation 749 * context's theme (see {@link LayoutInflater}) and used for the view itself as 750 * well as any child elements. 751 * </p> 752 * <p> 753 * In the following example, both views will be created using the Material dark 754 * color scheme; however, because an overlay theme is used which only defines a 755 * subset of attributes, the value of 756 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 757 * the inflation context's theme (e.g. the Activity theme) will be preserved. 758 * <pre> 759 * <LinearLayout 760 * ... 761 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 762 * <View ...> 763 * </LinearLayout> 764 * </pre> 765 * </p> 766 * 767 * <a name="Properties"></a> 768 * <h3>Properties</h3> 769 * <p> 770 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 771 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 772 * available both in the {@link Property} form as well as in similarly-named setter/getter 773 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 774 * be used to set persistent state associated with these rendering-related properties on the view. 775 * The properties and methods can also be used in conjunction with 776 * {@link android.animation.Animator Animator}-based animations, described more in the 777 * <a href="#Animation">Animation</a> section. 778 * </p> 779 * 780 * <a name="Animation"></a> 781 * <h3>Animation</h3> 782 * <p> 783 * Starting with Android 3.0, the preferred way of animating views is to use the 784 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 785 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 786 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 787 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 788 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 789 * makes animating these View properties particularly easy and efficient. 790 * </p> 791 * <p> 792 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 793 * You can attach an {@link Animation} object to a view using 794 * {@link #setAnimation(Animation)} or 795 * {@link #startAnimation(Animation)}. The animation can alter the scale, 796 * rotation, translation and alpha of a view over time. If the animation is 797 * attached to a view that has children, the animation will affect the entire 798 * subtree rooted by that node. When an animation is started, the framework will 799 * take care of redrawing the appropriate views until the animation completes. 800 * </p> 801 * 802 * <a name="Security"></a> 803 * <h3>Security</h3> 804 * <p> 805 * Sometimes it is essential that an application be able to verify that an action 806 * is being performed with the full knowledge and consent of the user, such as 807 * granting a permission request, making a purchase or clicking on an advertisement. 808 * Unfortunately, a malicious application could try to spoof the user into 809 * performing these actions, unaware, by concealing the intended purpose of the view. 810 * As a remedy, the framework offers a touch filtering mechanism that can be used to 811 * improve the security of views that provide access to sensitive functionality. 812 * </p><p> 813 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 814 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 815 * will discard touches that are received whenever the view's window is obscured by 816 * another visible window at the touched location. As a result, the view will not receive touches 817 * whenever the touch passed through a toast, dialog or other window that appears above the view's 818 * window. 819 * </p><p> 820 * For more fine-grained control over security, consider overriding the 821 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 822 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 823 * </p> 824 * 825 * @attr ref android.R.styleable#View_accessibilityHeading 826 * @attr ref android.R.styleable#View_allowClickWhenDisabled 827 * @attr ref android.R.styleable#View_alpha 828 * @attr ref android.R.styleable#View_background 829 * @attr ref android.R.styleable#View_clickable 830 * @attr ref android.R.styleable#View_clipToOutline 831 * @attr ref android.R.styleable#View_contentDescription 832 * @attr ref android.R.styleable#View_drawingCacheQuality 833 * @attr ref android.R.styleable#View_duplicateParentState 834 * @attr ref android.R.styleable#View_id 835 * @attr ref android.R.styleable#View_requiresFadingEdge 836 * @attr ref android.R.styleable#View_fadeScrollbars 837 * @attr ref android.R.styleable#View_fadingEdgeLength 838 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 839 * @attr ref android.R.styleable#View_fitsSystemWindows 840 * @attr ref android.R.styleable#View_isScrollContainer 841 * @attr ref android.R.styleable#View_focusable 842 * @attr ref android.R.styleable#View_focusableInTouchMode 843 * @attr ref android.R.styleable#View_focusedByDefault 844 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 845 * @attr ref android.R.styleable#View_keepScreenOn 846 * @attr ref android.R.styleable#View_keyboardNavigationCluster 847 * @attr ref android.R.styleable#View_layerType 848 * @attr ref android.R.styleable#View_layoutDirection 849 * @attr ref android.R.styleable#View_longClickable 850 * @attr ref android.R.styleable#View_minHeight 851 * @attr ref android.R.styleable#View_minWidth 852 * @attr ref android.R.styleable#View_nextClusterForward 853 * @attr ref android.R.styleable#View_nextFocusDown 854 * @attr ref android.R.styleable#View_nextFocusLeft 855 * @attr ref android.R.styleable#View_nextFocusRight 856 * @attr ref android.R.styleable#View_nextFocusUp 857 * @attr ref android.R.styleable#View_onClick 858 * @attr ref android.R.styleable#View_outlineSpotShadowColor 859 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 860 * @attr ref android.R.styleable#View_padding 861 * @attr ref android.R.styleable#View_paddingHorizontal 862 * @attr ref android.R.styleable#View_paddingVertical 863 * @attr ref android.R.styleable#View_paddingBottom 864 * @attr ref android.R.styleable#View_paddingLeft 865 * @attr ref android.R.styleable#View_paddingRight 866 * @attr ref android.R.styleable#View_paddingTop 867 * @attr ref android.R.styleable#View_paddingStart 868 * @attr ref android.R.styleable#View_paddingEnd 869 * @attr ref android.R.styleable#View_saveEnabled 870 * @attr ref android.R.styleable#View_rotation 871 * @attr ref android.R.styleable#View_rotationX 872 * @attr ref android.R.styleable#View_rotationY 873 * @attr ref android.R.styleable#View_scaleX 874 * @attr ref android.R.styleable#View_scaleY 875 * @attr ref android.R.styleable#View_scrollX 876 * @attr ref android.R.styleable#View_scrollY 877 * @attr ref android.R.styleable#View_scrollbarSize 878 * @attr ref android.R.styleable#View_scrollbarStyle 879 * @attr ref android.R.styleable#View_scrollbars 880 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 881 * @attr ref android.R.styleable#View_scrollbarFadeDuration 882 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 883 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 884 * @attr ref android.R.styleable#View_scrollbarThumbVertical 885 * @attr ref android.R.styleable#View_scrollbarTrackVertical 886 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 887 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 888 * @attr ref android.R.styleable#View_stateListAnimator 889 * @attr ref android.R.styleable#View_transitionName 890 * @attr ref android.R.styleable#View_soundEffectsEnabled 891 * @attr ref android.R.styleable#View_tag 892 * @attr ref android.R.styleable#View_textAlignment 893 * @attr ref android.R.styleable#View_textDirection 894 * @attr ref android.R.styleable#View_transformPivotX 895 * @attr ref android.R.styleable#View_transformPivotY 896 * @attr ref android.R.styleable#View_translationX 897 * @attr ref android.R.styleable#View_translationY 898 * @attr ref android.R.styleable#View_translationZ 899 * @attr ref android.R.styleable#View_visibility 900 * @attr ref android.R.styleable#View_theme 901 * 902 * @see android.view.ViewGroup 903 */ 904 @UiThread 905 public class View implements Drawable.Callback, KeyEvent.Callback, 906 AccessibilityEventSource { 907 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 908 private static final boolean DBG = false; 909 910 /** @hide */ 911 public static boolean DEBUG_DRAW = false; 912 913 /** 914 * The logging tag used by this class with android.util.Log. 915 */ 916 protected static final String VIEW_LOG_TAG = "View"; 917 918 /** 919 * The logging tag used by this class when logging verbose, autofill-related messages. 920 */ 921 // NOTE: We cannot use android.view.autofill.Helper.sVerbose because that variable is not 922 // set if a session is not started. 923 private static final String AUTOFILL_LOG_TAG = "View.Autofill"; 924 925 /** 926 * The logging tag used by this class when logging content capture-related messages. 927 */ 928 private static final String CONTENT_CAPTURE_LOG_TAG = "View.ContentCapture"; 929 930 private static final boolean DEBUG_CONTENT_CAPTURE = false; 931 932 /** 933 * When set to true, this view will save its attribute data. 934 * 935 * @hide 936 */ 937 public static boolean sDebugViewAttributes = false; 938 939 /** 940 * When set to this application package view will save its attribute data. 941 * 942 * @hide 943 */ 944 public static String sDebugViewAttributesApplicationPackage; 945 946 /** 947 * Used to mark a View that has no ID. 948 */ 949 public static final int NO_ID = -1; 950 951 /** 952 * Last ID that is given to Views that are no part of activities. 953 * 954 * {@hide} 955 */ 956 public static final int LAST_APP_AUTOFILL_ID = Integer.MAX_VALUE / 2; 957 958 /** 959 * Attribute to find the autofilled highlight 960 * 961 * @see #getAutofilledDrawable() 962 */ 963 private static final int[] AUTOFILL_HIGHLIGHT_ATTR = 964 new int[]{android.R.attr.autofilledHighlight}; 965 966 /** 967 * Signals that compatibility booleans have been initialized according to 968 * target SDK versions. 969 */ 970 private static boolean sCompatibilityDone = false; 971 972 /** @hide */ 973 public HapticScrollFeedbackProvider mScrollFeedbackProvider = null; 974 975 /** 976 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 977 */ 978 private static boolean sAlwaysRemeasureExactly = false; 979 980 /** 981 * When true calculates the bounds in parent from bounds in screen relative to its parents. 982 * This addresses the deprecated API (setBoundsInParent) in Compose, which causes empty 983 * getBoundsInParent call for Compose apps. 984 */ 985 private static boolean sCalculateBoundsInParentFromBoundsInScreenFlagValue = false; 986 987 /** 988 * When true makes it possible to use onMeasure caches also when the force layout flag is 989 * enabled. This helps avoiding multiple measures in the same frame with the same dimensions. 990 */ 991 private static boolean sUseMeasureCacheDuringForceLayoutFlagValue; 992 993 /** 994 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 995 * without throwing 996 */ 997 static boolean sTextureViewIgnoresDrawableSetters = false; 998 999 /** 1000 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 1001 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 1002 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 1003 * check is implemented for backwards compatibility. 1004 * 1005 * {@hide} 1006 */ 1007 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 1008 1009 /** 1010 * Prior to N, when drag enters into child of a view that has already received an 1011 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 1012 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 1013 * false from its event handler for these events. 1014 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 1015 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 1016 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 1017 */ 1018 static boolean sCascadedDragDrop; 1019 1020 /** 1021 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 1022 * to determine things like whether or not to permit item click events. We can't break 1023 * apps that do this just because more things (clickable things) are now auto-focusable 1024 * and they would get different results, so give old behavior to old apps. 1025 */ 1026 static boolean sHasFocusableExcludeAutoFocusable; 1027 1028 /** 1029 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 1030 * made focusable by default. As a result, apps could (incorrectly) change the clickable 1031 * setting of views off the UI thread. Now that clickable can effect the focusable state, 1032 * changing the clickable attribute off the UI thread will cause an exception (since changing 1033 * the focusable state checks). In order to prevent apps from crashing, we will handle this 1034 * specific case and just not notify parents on new focusables resulting from marking views 1035 * clickable from outside the UI thread. 1036 */ 1037 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 1038 1039 /** 1040 * Prior to P things like setScaleX() allowed passing float values that were bogus such as 1041 * Float.NaN. If the app is targetting P or later then passing these values will result in an 1042 * exception being thrown. If the app is targetting an earlier SDK version, then we will 1043 * silently clamp these values to avoid crashes elsewhere when the rendering code hits 1044 * these bogus values. 1045 */ 1046 private static boolean sThrowOnInvalidFloatProperties; 1047 1048 /** 1049 * Prior to P, {@code #startDragAndDrop} accepts a builder which produces an empty drag shadow. 1050 * Currently zero size SurfaceControl cannot be created thus we create a 1x1 surface instead. 1051 */ 1052 private static boolean sAcceptZeroSizeDragShadow; 1053 1054 /** 1055 * When true, measure and layout passes of all the newly attached views will be logged with 1056 * {@link Trace}, so we can better debug jank due to complex view hierarchies. 1057 */ 1058 private static boolean sTraceLayoutSteps; 1059 1060 /** 1061 * When not null, emits a {@link Trace} instant event and the stacktrace every time a relayout 1062 * of a class having this name happens. 1063 */ 1064 private static String sTraceRequestLayoutClass; 1065 1066 @Nullable 1067 private ViewCredentialHandler mViewCredentialHandler; 1068 1069 /** Used to avoid computing the full strings each time when layout tracing is enabled. */ 1070 @Nullable 1071 private ViewTraversalTracingStrings mTracingStrings; 1072 1073 /** 1074 * Prior to R, {@link #dispatchApplyWindowInsets} had an issue: 1075 * <p>The modified insets changed by {@link #onApplyWindowInsets} were passed to the 1076 * entire view hierarchy in prefix order, including siblings as well as siblings of parents 1077 * further down the hierarchy. This violates the basic concepts of the view hierarchy, and 1078 * thus, the hierarchical dispatching mechanism was hard to use for apps. 1079 * <p> 1080 * In order to make window inset dispatching work properly, we dispatch window insets 1081 * in the view hierarchy in a proper hierarchical manner if this flag is set to {@code false}. 1082 */ 1083 static boolean sBrokenInsetsDispatch; 1084 1085 /** 1086 * Prior to Q, calling 1087 * {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} 1088 * did not call update the window format so the opacity of the background was not correctly 1089 * applied to the window. Some applications rely on this misbehavior to work properly. 1090 * <p> 1091 * From Q, {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} is 1092 * the same as {@link com.android.internal.policy.DecorView#setWindowBackground(Drawable)} 1093 * which updates the window format. 1094 * @hide 1095 */ 1096 protected static boolean sBrokenWindowBackground; 1097 1098 /** 1099 * Prior to R, we were always forcing a layout of the entire hierarchy when insets changed from 1100 * the server. This is inefficient and not all apps use it. Instead, we want to rely on apps 1101 * calling {@link #requestLayout} when they need to relayout based on an insets change. 1102 */ 1103 static boolean sForceLayoutWhenInsetsChanged; 1104 1105 /** @hide */ 1106 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 1107 @Retention(RetentionPolicy.SOURCE) 1108 public @interface Focusable {} 1109 1110 /** 1111 * This view does not want keystrokes. 1112 * <p> 1113 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1114 * android:focusable}. 1115 */ 1116 public static final int NOT_FOCUSABLE = 0x00000000; 1117 1118 /** 1119 * This view wants keystrokes. 1120 * <p> 1121 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1122 * android:focusable}. 1123 */ 1124 public static final int FOCUSABLE = 0x00000001; 1125 1126 /** 1127 * This view determines focusability automatically. This is the default. 1128 * <p> 1129 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1130 * android:focusable}. 1131 */ 1132 public static final int FOCUSABLE_AUTO = 0x00000010; 1133 1134 /** 1135 * Mask for use with setFlags indicating bits used for focus. 1136 */ 1137 private static final int FOCUSABLE_MASK = 0x00000011; 1138 1139 /** 1140 * This view will adjust its padding to fit system windows (e.g. status bar) 1141 */ 1142 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 1143 1144 /** @hide */ 1145 @IntDef({VISIBLE, INVISIBLE, GONE}) 1146 @Retention(RetentionPolicy.SOURCE) 1147 public @interface Visibility {} 1148 1149 /** 1150 * This view is visible. 1151 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1152 * android:visibility}. 1153 */ 1154 public static final int VISIBLE = 0x00000000; 1155 1156 /** 1157 * This view is invisible, but it still takes up space for layout purposes. 1158 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1159 * android:visibility}. 1160 */ 1161 public static final int INVISIBLE = 0x00000004; 1162 1163 /** 1164 * This view is invisible, and it doesn't take any space for layout 1165 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1166 * android:visibility}. 1167 */ 1168 public static final int GONE = 0x00000008; 1169 1170 /** 1171 * Mask for use with setFlags indicating bits used for visibility. 1172 * {@hide} 1173 */ 1174 static final int VISIBILITY_MASK = 0x0000000C; 1175 1176 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 1177 1178 /** 1179 * Hint indicating that this view can be autofilled with an email address. 1180 * 1181 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1182 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1183 * value should be <code>{@value #AUTOFILL_HINT_EMAIL_ADDRESS}</code>). 1184 * 1185 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1186 */ 1187 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 1188 1189 /** 1190 * Hint indicating that this view can be autofilled with a user's real name. 1191 * 1192 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1193 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1194 * value should be <code>{@value #AUTOFILL_HINT_NAME}</code>). 1195 * 1196 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1197 */ 1198 public static final String AUTOFILL_HINT_NAME = "name"; 1199 1200 /** 1201 * Hint indicating that this view can be autofilled with a username. 1202 * 1203 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1204 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1205 * value should be <code>{@value #AUTOFILL_HINT_USERNAME}</code>). 1206 * 1207 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1208 */ 1209 public static final String AUTOFILL_HINT_USERNAME = "username"; 1210 1211 /** 1212 * Hint indicating that this view can be autofilled with a password. 1213 * 1214 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1215 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1216 * value should be <code>{@value #AUTOFILL_HINT_PASSWORD}</code>). 1217 * 1218 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1219 */ 1220 public static final String AUTOFILL_HINT_PASSWORD = "password"; 1221 1222 /** 1223 * Hint indicating that this view can be autofilled with a phone number. 1224 * 1225 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1226 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1227 * value should be <code>{@value #AUTOFILL_HINT_PHONE}</code>). 1228 * 1229 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1230 */ 1231 public static final String AUTOFILL_HINT_PHONE = "phone"; 1232 1233 /** 1234 * Hint indicating that this view can be autofilled with a postal address. 1235 * 1236 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1237 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1238 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_ADDRESS}</code>). 1239 * 1240 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1241 */ 1242 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1243 1244 /** 1245 * Hint indicating that this view can be autofilled with a postal code. 1246 * 1247 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1248 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1249 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_CODE}</code>). 1250 * 1251 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1252 */ 1253 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1254 1255 /** 1256 * Hint indicating that this view can be autofilled with a credit card number. 1257 * 1258 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1259 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1260 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_NUMBER}</code>). 1261 * 1262 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1263 */ 1264 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1265 1266 /** 1267 * Hint indicating that this view can be autofilled with a credit card security code. 1268 * 1269 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1270 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1271 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}</code>). 1272 * 1273 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1274 */ 1275 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1276 1277 /** 1278 * Hint indicating that this view can be autofilled with a credit card expiration date. 1279 * 1280 * <p>It should be used when the credit card expiration date is represented by just one view; 1281 * if it is represented by more than one (for example, one view for the month and another view 1282 * for the year), then each of these views should use the hint specific for the unit 1283 * ({@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 1284 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 1285 * or {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}). 1286 * 1287 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1288 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1289 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}</code>). 1290 * 1291 * <p>When annotating a view with this hint, it's recommended to use a date autofill value to 1292 * avoid ambiguity when the autofill service provides a value for it. To understand why a 1293 * value can be ambiguous, consider "April of 2020", which could be represented as either of 1294 * the following options: 1295 * 1296 * <ul> 1297 * <li>{@code "04/2020"} 1298 * <li>{@code "4/2020"} 1299 * <li>{@code "2020/04"} 1300 * <li>{@code "2020/4"} 1301 * <li>{@code "April/2020"} 1302 * <li>{@code "Apr/2020"} 1303 * </ul> 1304 * 1305 * <p>You define a date autofill value for the view by overriding the following methods: 1306 * 1307 * <ol> 1308 * <li>{@link #getAutofillType()} to return {@link #AUTOFILL_TYPE_DATE}. 1309 * <li>{@link #getAutofillValue()} to return a 1310 * {@link AutofillValue#forDate(long) date autofillvalue}. 1311 * <li>{@link #autofill(AutofillValue)} to expect a data autofillvalue. 1312 * </ol> 1313 * 1314 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1315 */ 1316 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1317 "creditCardExpirationDate"; 1318 1319 /** 1320 * Hint indicating that this view can be autofilled with a credit card expiration month. 1321 * 1322 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1323 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1324 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}</code>). 1325 * 1326 * <p>When annotating a view with this hint, it's recommended to use a text autofill value 1327 * whose value is the numerical representation of the month, starting on {@code 1} to avoid 1328 * ambiguity when the autofill service provides a value for it. To understand why a 1329 * value can be ambiguous, consider "January", which could be represented as either of 1330 * 1331 * <ul> 1332 * <li>{@code "1"}: recommended way. 1333 * <li>{@code "0"}: if following the {@link Calendar#MONTH} convention. 1334 * <li>{@code "January"}: full name, in English. 1335 * <li>{@code "jan"}: abbreviated name, in English. 1336 * <li>{@code "Janeiro"}: full name, in another language. 1337 * </ul> 1338 * 1339 * <p>Another recommended approach is to use a date autofill value - see 1340 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE} for more details. 1341 * 1342 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1343 */ 1344 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1345 "creditCardExpirationMonth"; 1346 1347 /** 1348 * Hint indicating that this view can be autofilled with a credit card expiration year. 1349 * 1350 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1351 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1352 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}</code>). 1353 * 1354 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1355 */ 1356 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1357 "creditCardExpirationYear"; 1358 1359 /** 1360 * Hint indicating that this view can be autofilled with a credit card expiration day. 1361 * 1362 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1363 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1364 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}</code>). 1365 * 1366 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1367 */ 1368 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1369 1370 /** 1371 * A hint indicating that this view can be autofilled with a password. 1372 * 1373 * This is a heuristic-based hint that is meant to be used by UI Toolkit developers when a 1374 * view is a password field but doesn't specify a 1375 * <code>{@value View#AUTOFILL_HINT_PASSWORD}</code>. 1376 * @hide 1377 */ 1378 // TODO(229765029): unhide this for UI toolkit 1379 public static final String AUTOFILL_HINT_PASSWORD_AUTO = "passwordAuto"; 1380 1381 /** 1382 * Hint indicating that the developer intends to fill this view with output from 1383 * CredentialManager. 1384 * 1385 * @hide 1386 */ 1387 public static final String AUTOFILL_HINT_CREDENTIAL_MANAGER = "credential"; 1388 1389 /** 1390 * Hints for the autofill services that describes the content of the view. 1391 */ 1392 private @Nullable String[] mAutofillHints; 1393 1394 /** 1395 * Autofill id, lazily created on calls to {@link #getAutofillId()}. 1396 */ 1397 private AutofillId mAutofillId; 1398 1399 /** @hide */ 1400 @IntDef(prefix = { "AUTOFILL_TYPE_" }, value = { 1401 AUTOFILL_TYPE_NONE, 1402 AUTOFILL_TYPE_TEXT, 1403 AUTOFILL_TYPE_TOGGLE, 1404 AUTOFILL_TYPE_LIST, 1405 AUTOFILL_TYPE_DATE, 1406 }) 1407 @Retention(RetentionPolicy.SOURCE) 1408 public @interface AutofillType {} 1409 1410 /** 1411 * Autofill type for views that cannot be autofilled. 1412 * 1413 * <p>Typically used when the view is read-only; for example, a text label. 1414 * 1415 * @see #getAutofillType() 1416 */ 1417 public static final int AUTOFILL_TYPE_NONE = 0; 1418 1419 /** 1420 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1421 * 1422 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1423 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1424 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1425 * 1426 * @see #getAutofillType() 1427 */ 1428 public static final int AUTOFILL_TYPE_TEXT = 1; 1429 1430 /** 1431 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1432 * 1433 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1434 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1435 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1436 * 1437 * @see #getAutofillType() 1438 */ 1439 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1440 1441 /** 1442 * Autofill type for a selection list field, which is filled by an {@code int} 1443 * representing the element index inside the list (starting at {@code 0}). 1444 * 1445 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1446 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1447 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1448 * 1449 * <p>The available options in the selection list are typically provided by 1450 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1451 * 1452 * @see #getAutofillType() 1453 */ 1454 public static final int AUTOFILL_TYPE_LIST = 3; 1455 1456 /** 1457 * Autofill type for a field that contains a date, which is represented by a long representing 1458 * the number of milliseconds since the standard base time known as "the epoch", namely 1459 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1460 * 1461 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1462 * {@link AutofillValue#forDate(long)}, and the values passed to 1463 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1464 * 1465 * @see #getAutofillType() 1466 */ 1467 public static final int AUTOFILL_TYPE_DATE = 4; 1468 1469 1470 /** @hide */ 1471 @IntDef(prefix = { "IMPORTANT_FOR_AUTOFILL_" }, value = { 1472 IMPORTANT_FOR_AUTOFILL_AUTO, 1473 IMPORTANT_FOR_AUTOFILL_YES, 1474 IMPORTANT_FOR_AUTOFILL_NO, 1475 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 1476 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 1477 }) 1478 @Retention(RetentionPolicy.SOURCE) 1479 public @interface AutofillImportance {} 1480 1481 /** 1482 * Automatically determine whether a view is important for autofill. 1483 * 1484 * @see #isImportantForAutofill() 1485 * @see #setImportantForAutofill(int) 1486 */ 1487 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1488 1489 /** 1490 * The view is important for autofill, and its children (if any) will be traversed. 1491 * 1492 * @see #isImportantForAutofill() 1493 * @see #setImportantForAutofill(int) 1494 */ 1495 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1496 1497 /** 1498 * The view is not important for autofill, but its children (if any) will be traversed. 1499 * 1500 * @see #isImportantForAutofill() 1501 * @see #setImportantForAutofill(int) 1502 */ 1503 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1504 1505 /** 1506 * The view is important for autofill, but its children (if any) will not be traversed. 1507 * 1508 * @see #isImportantForAutofill() 1509 * @see #setImportantForAutofill(int) 1510 */ 1511 public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; 1512 1513 /** 1514 * The view is not important for autofill, and its children (if any) will not be traversed. 1515 * 1516 * @see #isImportantForAutofill() 1517 * @see #setImportantForAutofill(int) 1518 */ 1519 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; 1520 1521 /** @hide */ 1522 @IntDef(flag = true, prefix = { "AUTOFILL_FLAG_" }, value = { 1523 AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 1524 }) 1525 @Retention(RetentionPolicy.SOURCE) 1526 public @interface AutofillFlags {} 1527 1528 /** 1529 * Flag requesting you to add views that are marked as not important for autofill 1530 * (see {@link #setImportantForAutofill(int)}) to a {@link ViewStructure}. 1531 */ 1532 public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; 1533 1534 /** @hide */ 1535 @IntDef(prefix = { "IMPORTANT_FOR_CONTENT_CAPTURE_" }, value = { 1536 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, 1537 IMPORTANT_FOR_CONTENT_CAPTURE_YES, 1538 IMPORTANT_FOR_CONTENT_CAPTURE_NO, 1539 IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 1540 IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 1541 }) 1542 @Retention(RetentionPolicy.SOURCE) 1543 public @interface ContentCaptureImportance {} 1544 1545 /** 1546 * Automatically determine whether a view is important for content capture. 1547 * 1548 * @see #isImportantForContentCapture() 1549 * @see #setImportantForContentCapture(int) 1550 */ 1551 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0x0; 1552 1553 /** 1554 * The view is important for content capture, and its children (if any) will be traversed. 1555 * 1556 * @see #isImportantForContentCapture() 1557 * @see #setImportantForContentCapture(int) 1558 */ 1559 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 0x1; 1560 1561 /** 1562 * The view is not important for content capture, but its children (if any) will be traversed. 1563 * 1564 * @see #isImportantForContentCapture() 1565 * @see #setImportantForContentCapture(int) 1566 */ 1567 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 0x2; 1568 1569 /** 1570 * The view is important for content capture, but its children (if any) will not be traversed. 1571 * 1572 * @see #isImportantForContentCapture() 1573 * @see #setImportantForContentCapture(int) 1574 */ 1575 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 0x4; 1576 1577 /** 1578 * The view is not important for content capture, and its children (if any) will not be 1579 * traversed. 1580 * 1581 * @see #isImportantForContentCapture() 1582 * @see #setImportantForContentCapture(int) 1583 */ 1584 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 0x8; 1585 1586 /** {@hide} */ 1587 @IntDef(flag = true, prefix = {"SCROLL_CAPTURE_HINT_"}, 1588 value = { 1589 SCROLL_CAPTURE_HINT_AUTO, 1590 SCROLL_CAPTURE_HINT_EXCLUDE, 1591 SCROLL_CAPTURE_HINT_INCLUDE, 1592 SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS 1593 }) 1594 @Retention(RetentionPolicy.SOURCE) 1595 public @interface ScrollCaptureHint {} 1596 1597 /** 1598 * The content of this view will be considered for scroll capture if scrolling is possible. 1599 * 1600 * @see #getScrollCaptureHint() 1601 * @see #setScrollCaptureHint(int) 1602 */ 1603 public static final int SCROLL_CAPTURE_HINT_AUTO = 0; 1604 1605 /** 1606 * Explicitly exclude this view as a potential scroll capture target. The system will not 1607 * consider it. Mutually exclusive with {@link #SCROLL_CAPTURE_HINT_INCLUDE}, which this flag 1608 * takes precedence over. 1609 * 1610 * @see #getScrollCaptureHint() 1611 * @see #setScrollCaptureHint(int) 1612 */ 1613 public static final int SCROLL_CAPTURE_HINT_EXCLUDE = 0x1; 1614 1615 /** 1616 * Explicitly include this view as a potential scroll capture target. When locating a scroll 1617 * capture target, this view will be prioritized before others without this flag. Mutually 1618 * exclusive with {@link #SCROLL_CAPTURE_HINT_EXCLUDE}, which takes precedence. 1619 * 1620 * @see #getScrollCaptureHint() 1621 * @see #setScrollCaptureHint(int) 1622 */ 1623 public static final int SCROLL_CAPTURE_HINT_INCLUDE = 0x2; 1624 1625 /** 1626 * Explicitly exclude all children of this view as potential scroll capture targets. This view 1627 * is unaffected. Note: Excluded children are not considered, regardless of {@link 1628 * #SCROLL_CAPTURE_HINT_INCLUDE}. 1629 * 1630 * @see #getScrollCaptureHint() 1631 * @see #setScrollCaptureHint(int) 1632 */ 1633 public static final int SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS = 0x4; 1634 1635 /** 1636 * This view is enabled. Interpretation varies by subclass. 1637 * Use with ENABLED_MASK when calling setFlags. 1638 * {@hide} 1639 */ 1640 static final int ENABLED = 0x00000000; 1641 1642 /** 1643 * This view is disabled. Interpretation varies by subclass. 1644 * Use with ENABLED_MASK when calling setFlags. 1645 * {@hide} 1646 */ 1647 static final int DISABLED = 0x00000020; 1648 1649 /** 1650 * Mask for use with setFlags indicating bits used for indicating whether 1651 * this view is enabled 1652 * {@hide} 1653 */ 1654 static final int ENABLED_MASK = 0x00000020; 1655 1656 /** 1657 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1658 * called and further optimizations will be performed. It is okay to have 1659 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1660 * {@hide} 1661 */ 1662 static final int WILL_NOT_DRAW = 0x00000080; 1663 1664 /** 1665 * Mask for use with setFlags indicating bits used for indicating whether 1666 * this view is will draw 1667 * {@hide} 1668 */ 1669 static final int DRAW_MASK = 0x00000080; 1670 1671 /** 1672 * <p>This view doesn't show scrollbars.</p> 1673 * {@hide} 1674 */ 1675 static final int SCROLLBARS_NONE = 0x00000000; 1676 1677 /** 1678 * <p>This view shows horizontal scrollbars.</p> 1679 * {@hide} 1680 */ 1681 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1682 1683 /** 1684 * <p>This view shows vertical scrollbars.</p> 1685 * {@hide} 1686 */ 1687 static final int SCROLLBARS_VERTICAL = 0x00000200; 1688 1689 /** 1690 * <p>Mask for use with setFlags indicating bits used for indicating which 1691 * scrollbars are enabled.</p> 1692 * {@hide} 1693 */ 1694 static final int SCROLLBARS_MASK = 0x00000300; 1695 1696 /** 1697 * Indicates that the view should filter touches when its window is obscured. 1698 * Refer to the class comments for more information about this security feature. 1699 * {@hide} 1700 */ 1701 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1702 1703 /** 1704 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1705 * that they are optional and should be skipped if the window has 1706 * requested system UI flags that ignore those insets for layout. 1707 * <p> 1708 * This is only used for support library as of Android R. The framework now uses 1709 * {@link #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS} such that it can skip the legacy 1710 * insets path that loses insets information. 1711 */ 1712 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1713 1714 /** 1715 * <p>This view doesn't show fading edges.</p> 1716 * {@hide} 1717 */ 1718 static final int FADING_EDGE_NONE = 0x00000000; 1719 1720 /** 1721 * <p>This view shows horizontal fading edges.</p> 1722 * {@hide} 1723 */ 1724 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1725 1726 /** 1727 * <p>This view shows vertical fading edges.</p> 1728 * {@hide} 1729 */ 1730 static final int FADING_EDGE_VERTICAL = 0x00002000; 1731 1732 /** 1733 * <p>Mask for use with setFlags indicating bits used for indicating which 1734 * fading edges are enabled.</p> 1735 * {@hide} 1736 */ 1737 static final int FADING_EDGE_MASK = 0x00003000; 1738 1739 /** 1740 * <p>Indicates this view can be clicked. When clickable, a View reacts 1741 * to clicks by notifying the OnClickListener.<p> 1742 * {@hide} 1743 */ 1744 static final int CLICKABLE = 0x00004000; 1745 1746 /** 1747 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1748 * {@hide} 1749 */ 1750 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1751 1752 /** 1753 * <p>Indicates that no icicle should be saved for this view.<p> 1754 * {@hide} 1755 */ 1756 static final int SAVE_DISABLED = 0x000010000; 1757 1758 /** 1759 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1760 * property.</p> 1761 * {@hide} 1762 */ 1763 static final int SAVE_DISABLED_MASK = 0x000010000; 1764 1765 /** 1766 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1767 * {@hide} 1768 */ 1769 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1770 1771 /** 1772 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1773 * {@hide} 1774 */ 1775 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1776 1777 /** @hide */ 1778 @Retention(RetentionPolicy.SOURCE) 1779 @IntDef(prefix = { "DRAWING_CACHE_QUALITY_" }, value = { 1780 DRAWING_CACHE_QUALITY_LOW, 1781 DRAWING_CACHE_QUALITY_HIGH, 1782 DRAWING_CACHE_QUALITY_AUTO 1783 }) 1784 public @interface DrawingCacheQuality {} 1785 1786 /** 1787 * <p>Enables low quality mode for the drawing cache.</p> 1788 * 1789 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1790 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1791 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1792 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1793 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1794 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1795 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1796 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1797 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1798 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1799 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1800 * reports or unit testing the {@link PixelCopy} API is recommended. 1801 */ 1802 @Deprecated 1803 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1804 1805 /** 1806 * <p>Enables high quality mode for the drawing cache.</p> 1807 * 1808 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1809 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1810 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1811 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1812 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1813 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1814 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1815 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1816 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1817 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1818 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1819 * reports or unit testing the {@link PixelCopy} API is recommended. 1820 */ 1821 @Deprecated 1822 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1823 1824 /** 1825 * <p>Enables automatic quality mode for the drawing cache.</p> 1826 * 1827 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1828 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1829 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1830 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1831 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1832 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1833 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1834 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1835 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1836 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1837 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1838 * reports or unit testing the {@link PixelCopy} API is recommended. 1839 */ 1840 @Deprecated 1841 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1842 1843 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1844 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1845 }; 1846 1847 /** 1848 * <p>Mask for use with setFlags indicating bits used for the cache 1849 * quality property.</p> 1850 * {@hide} 1851 */ 1852 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1853 1854 /** 1855 * <p> 1856 * Indicates this view can be long clicked. When long clickable, a View 1857 * reacts to long clicks by notifying the OnLongClickListener or showing a 1858 * context menu. 1859 * </p> 1860 * {@hide} 1861 */ 1862 static final int LONG_CLICKABLE = 0x00200000; 1863 1864 /** 1865 * <p>Indicates that this view gets its drawable states from its direct parent 1866 * and ignores its original internal states.</p> 1867 * 1868 * @hide 1869 */ 1870 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1871 1872 /** 1873 * <p> 1874 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1875 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1876 * OnContextClickListener. 1877 * </p> 1878 * {@hide} 1879 */ 1880 static final int CONTEXT_CLICKABLE = 0x00800000; 1881 1882 /** @hide */ 1883 @IntDef(prefix = { "SCROLLBARS_" }, value = { 1884 SCROLLBARS_INSIDE_OVERLAY, 1885 SCROLLBARS_INSIDE_INSET, 1886 SCROLLBARS_OUTSIDE_OVERLAY, 1887 SCROLLBARS_OUTSIDE_INSET 1888 }) 1889 @Retention(RetentionPolicy.SOURCE) 1890 public @interface ScrollBarStyle {} 1891 1892 /** 1893 * The scrollbar style to display the scrollbars inside the content area, 1894 * without increasing the padding. The scrollbars will be overlaid with 1895 * translucency on the view's content. 1896 */ 1897 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1898 1899 /** 1900 * The scrollbar style to display the scrollbars inside the padded area, 1901 * increasing the padding of the view. The scrollbars will not overlap the 1902 * content area of the view. 1903 */ 1904 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1905 1906 /** 1907 * The scrollbar style to display the scrollbars at the edge of the view, 1908 * without increasing the padding. The scrollbars will be overlaid with 1909 * translucency. 1910 */ 1911 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1912 1913 /** 1914 * The scrollbar style to display the scrollbars at the edge of the view, 1915 * increasing the padding of the view. The scrollbars will only overlap the 1916 * background, if any. 1917 */ 1918 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1919 1920 /** 1921 * Mask to check if the scrollbar style is overlay or inset. 1922 * {@hide} 1923 */ 1924 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1925 1926 /** 1927 * Mask to check if the scrollbar style is inside or outside. 1928 * {@hide} 1929 */ 1930 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1931 1932 /** 1933 * Mask for scrollbar style. 1934 * {@hide} 1935 */ 1936 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1937 1938 /** 1939 * View flag indicating that the screen should remain on while the 1940 * window containing this view is visible to the user. This effectively 1941 * takes care of automatically setting the WindowManager's 1942 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1943 */ 1944 public static final int KEEP_SCREEN_ON = 0x04000000; 1945 1946 /** 1947 * View flag indicating whether this view should have sound effects enabled 1948 * for events such as clicking and touching. 1949 */ 1950 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1951 1952 /** 1953 * View flag indicating whether this view should have haptic feedback 1954 * enabled for events such as long presses. 1955 */ 1956 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1957 1958 /** 1959 * <p>Indicates that the view hierarchy should stop saving state when 1960 * it reaches this view. If state saving is initiated immediately at 1961 * the view, it will be allowed. 1962 * {@hide} 1963 */ 1964 static final int PARENT_SAVE_DISABLED = 0x20000000; 1965 1966 /** 1967 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1968 * {@hide} 1969 */ 1970 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1971 1972 private static Paint sDebugPaint; 1973 1974 /** 1975 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1976 * {@hide} 1977 */ 1978 static final int TOOLTIP = 0x40000000; 1979 1980 /** @hide */ 1981 @IntDef(prefix = { "CONTENT_SENSITIVITY_" }, value = { 1982 CONTENT_SENSITIVITY_AUTO, 1983 CONTENT_SENSITIVITY_SENSITIVE, 1984 CONTENT_SENSITIVITY_NOT_SENSITIVE 1985 }) 1986 @Retention(RetentionPolicy.SOURCE) 1987 public @interface ContentSensitivity {} 1988 1989 /** 1990 * Content sensitivity is determined by the framework. The framework uses a heuristic to 1991 * determine if this view displays sensitive content. 1992 * Autofill hints i.e. {@link #getAutofillHints()} are used in the heuristic 1993 * to determine if this view should be considered as a sensitive view. 1994 * <p> 1995 * {@link #AUTOFILL_HINT_USERNAME}, 1996 * {@link #AUTOFILL_HINT_PASSWORD}, 1997 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, 1998 * {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 1999 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 2000 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 2001 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 2002 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR} 2003 * are considered sensitive hints by the framework, and the list may include more hints 2004 * in the future. 2005 * 2006 * <p> The window hosting a sensitive view will be marked as secure during an active media 2007 * projection session. This would be equivalent to applying 2008 * {@link android.view.WindowManager.LayoutParams#FLAG_SECURE} to the window. 2009 * 2010 * @see #getContentSensitivity() 2011 */ 2012 @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) 2013 public static final int CONTENT_SENSITIVITY_AUTO = 0x0; 2014 2015 /** 2016 * The view displays sensitive content. 2017 * 2018 * <p> The window hosting a sensitive view will be marked as secure during an active media 2019 * projection session. This would be equivalent to applying 2020 * {@link android.view.WindowManager.LayoutParams#FLAG_SECURE} to the window. 2021 * 2022 * @see #getContentSensitivity() 2023 */ 2024 @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) 2025 public static final int CONTENT_SENSITIVITY_SENSITIVE = 0x1; 2026 2027 /** 2028 * The view doesn't display sensitive content. 2029 * 2030 * @see #getContentSensitivity() 2031 */ 2032 @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) 2033 public static final int CONTENT_SENSITIVITY_NOT_SENSITIVE = 0x2; 2034 2035 /** @hide */ 2036 @IntDef(flag = true, prefix = { "FOCUSABLES_" }, value = { 2037 FOCUSABLES_ALL, 2038 FOCUSABLES_TOUCH_MODE 2039 }) 2040 @Retention(RetentionPolicy.SOURCE) 2041 public @interface FocusableMode {} 2042 2043 /** 2044 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 2045 * should add all focusable Views regardless if they are focusable in touch mode. 2046 */ 2047 public static final int FOCUSABLES_ALL = 0x00000000; 2048 2049 /** 2050 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 2051 * should add only Views focusable in touch mode. 2052 */ 2053 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 2054 2055 /** @hide */ 2056 @IntDef(prefix = { "FOCUS_" }, value = { 2057 FOCUS_BACKWARD, 2058 FOCUS_FORWARD, 2059 FOCUS_LEFT, 2060 FOCUS_UP, 2061 FOCUS_RIGHT, 2062 FOCUS_DOWN 2063 }) 2064 @Retention(RetentionPolicy.SOURCE) 2065 public @interface FocusDirection {} 2066 2067 /** @hide */ 2068 @IntDef(prefix = { "FOCUS_" }, value = { 2069 FOCUS_LEFT, 2070 FOCUS_UP, 2071 FOCUS_RIGHT, 2072 FOCUS_DOWN 2073 }) 2074 @Retention(RetentionPolicy.SOURCE) 2075 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 2076 2077 /** 2078 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 2079 * item. 2080 */ 2081 public static final int FOCUS_BACKWARD = 0x00000001; 2082 2083 /** 2084 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 2085 * item. 2086 */ 2087 public static final int FOCUS_FORWARD = 0x00000002; 2088 2089 /** 2090 * Use with {@link #focusSearch(int)}. Move focus to the left. 2091 */ 2092 public static final int FOCUS_LEFT = 0x00000011; 2093 2094 /** 2095 * Use with {@link #focusSearch(int)}. Move focus up. 2096 */ 2097 public static final int FOCUS_UP = 0x00000021; 2098 2099 /** 2100 * Use with {@link #focusSearch(int)}. Move focus to the right. 2101 */ 2102 public static final int FOCUS_RIGHT = 0x00000042; 2103 2104 /** 2105 * Use with {@link #focusSearch(int)}. Move focus down. 2106 */ 2107 public static final int FOCUS_DOWN = 0x00000082; 2108 2109 /** 2110 * Bits of {@link #getMeasuredWidthAndState()} and 2111 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 2112 */ 2113 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 2114 2115 /** 2116 * Bits of {@link #getMeasuredWidthAndState()} and 2117 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 2118 */ 2119 public static final int MEASURED_STATE_MASK = 0xff000000; 2120 2121 /** 2122 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 2123 * for functions that combine both width and height into a single int, 2124 * such as {@link #getMeasuredState()} and the childState argument of 2125 * {@link #resolveSizeAndState(int, int, int)}. 2126 */ 2127 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 2128 2129 /** 2130 * Bit of {@link #getMeasuredWidthAndState()} and 2131 * {@link #getMeasuredWidthAndState()} that indicates the measured size 2132 * is smaller that the space the view would like to have. 2133 */ 2134 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 2135 2136 /** 2137 * Base View state sets 2138 */ 2139 // Singles 2140 /** 2141 * Indicates the view has no states set. States are used with 2142 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2143 * view depending on its state. 2144 * 2145 * @see android.graphics.drawable.Drawable 2146 * @see #getDrawableState() 2147 */ 2148 protected static final int[] EMPTY_STATE_SET; 2149 /** 2150 * Indicates the view is enabled. States are used with 2151 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2152 * view depending on its state. 2153 * 2154 * @see android.graphics.drawable.Drawable 2155 * @see #getDrawableState() 2156 */ 2157 protected static final int[] ENABLED_STATE_SET; 2158 /** 2159 * Indicates the view is focused. States are used with 2160 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2161 * view depending on its state. 2162 * 2163 * @see android.graphics.drawable.Drawable 2164 * @see #getDrawableState() 2165 */ 2166 protected static final int[] FOCUSED_STATE_SET; 2167 /** 2168 * Indicates the view is selected. States are used with 2169 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2170 * view depending on its state. 2171 * 2172 * @see android.graphics.drawable.Drawable 2173 * @see #getDrawableState() 2174 */ 2175 protected static final int[] SELECTED_STATE_SET; 2176 /** 2177 * Indicates the view is pressed. States are used with 2178 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2179 * view depending on its state. 2180 * 2181 * @see android.graphics.drawable.Drawable 2182 * @see #getDrawableState() 2183 */ 2184 protected static final int[] PRESSED_STATE_SET; 2185 /** 2186 * Indicates the view's window has focus. States are used with 2187 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2188 * view depending on its state. 2189 * 2190 * @see android.graphics.drawable.Drawable 2191 * @see #getDrawableState() 2192 */ 2193 protected static final int[] WINDOW_FOCUSED_STATE_SET; 2194 // Doubles 2195 /** 2196 * Indicates the view is enabled and has the focus. 2197 * 2198 * @see #ENABLED_STATE_SET 2199 * @see #FOCUSED_STATE_SET 2200 */ 2201 protected static final int[] ENABLED_FOCUSED_STATE_SET; 2202 /** 2203 * Indicates the view is enabled and selected. 2204 * 2205 * @see #ENABLED_STATE_SET 2206 * @see #SELECTED_STATE_SET 2207 */ 2208 protected static final int[] ENABLED_SELECTED_STATE_SET; 2209 /** 2210 * Indicates the view is enabled and that its window has focus. 2211 * 2212 * @see #ENABLED_STATE_SET 2213 * @see #WINDOW_FOCUSED_STATE_SET 2214 */ 2215 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 2216 /** 2217 * Indicates the view is focused and selected. 2218 * 2219 * @see #FOCUSED_STATE_SET 2220 * @see #SELECTED_STATE_SET 2221 */ 2222 protected static final int[] FOCUSED_SELECTED_STATE_SET; 2223 /** 2224 * Indicates the view has the focus and that its window has the focus. 2225 * 2226 * @see #FOCUSED_STATE_SET 2227 * @see #WINDOW_FOCUSED_STATE_SET 2228 */ 2229 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 2230 /** 2231 * Indicates the view is selected and that its window has the focus. 2232 * 2233 * @see #SELECTED_STATE_SET 2234 * @see #WINDOW_FOCUSED_STATE_SET 2235 */ 2236 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 2237 // Triples 2238 /** 2239 * Indicates the view is enabled, focused and selected. 2240 * 2241 * @see #ENABLED_STATE_SET 2242 * @see #FOCUSED_STATE_SET 2243 * @see #SELECTED_STATE_SET 2244 */ 2245 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 2246 /** 2247 * Indicates the view is enabled, focused and its window has the focus. 2248 * 2249 * @see #ENABLED_STATE_SET 2250 * @see #FOCUSED_STATE_SET 2251 * @see #WINDOW_FOCUSED_STATE_SET 2252 */ 2253 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2254 /** 2255 * Indicates the view is enabled, selected and its window has the focus. 2256 * 2257 * @see #ENABLED_STATE_SET 2258 * @see #SELECTED_STATE_SET 2259 * @see #WINDOW_FOCUSED_STATE_SET 2260 */ 2261 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2262 /** 2263 * Indicates the view is focused, selected and its window has the focus. 2264 * 2265 * @see #FOCUSED_STATE_SET 2266 * @see #SELECTED_STATE_SET 2267 * @see #WINDOW_FOCUSED_STATE_SET 2268 */ 2269 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2270 /** 2271 * Indicates the view is enabled, focused, selected and its window 2272 * has the focus. 2273 * 2274 * @see #ENABLED_STATE_SET 2275 * @see #FOCUSED_STATE_SET 2276 * @see #SELECTED_STATE_SET 2277 * @see #WINDOW_FOCUSED_STATE_SET 2278 */ 2279 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2280 /** 2281 * Indicates the view is pressed and its window has the focus. 2282 * 2283 * @see #PRESSED_STATE_SET 2284 * @see #WINDOW_FOCUSED_STATE_SET 2285 */ 2286 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 2287 /** 2288 * Indicates the view is pressed and selected. 2289 * 2290 * @see #PRESSED_STATE_SET 2291 * @see #SELECTED_STATE_SET 2292 */ 2293 protected static final int[] PRESSED_SELECTED_STATE_SET; 2294 /** 2295 * Indicates the view is pressed, selected and its window has the focus. 2296 * 2297 * @see #PRESSED_STATE_SET 2298 * @see #SELECTED_STATE_SET 2299 * @see #WINDOW_FOCUSED_STATE_SET 2300 */ 2301 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2302 /** 2303 * Indicates the view is pressed and focused. 2304 * 2305 * @see #PRESSED_STATE_SET 2306 * @see #FOCUSED_STATE_SET 2307 */ 2308 protected static final int[] PRESSED_FOCUSED_STATE_SET; 2309 /** 2310 * Indicates the view is pressed, focused and its window has the focus. 2311 * 2312 * @see #PRESSED_STATE_SET 2313 * @see #FOCUSED_STATE_SET 2314 * @see #WINDOW_FOCUSED_STATE_SET 2315 */ 2316 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2317 /** 2318 * Indicates the view is pressed, focused and selected. 2319 * 2320 * @see #PRESSED_STATE_SET 2321 * @see #SELECTED_STATE_SET 2322 * @see #FOCUSED_STATE_SET 2323 */ 2324 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 2325 /** 2326 * Indicates the view is pressed, focused, selected and its window has the focus. 2327 * 2328 * @see #PRESSED_STATE_SET 2329 * @see #FOCUSED_STATE_SET 2330 * @see #SELECTED_STATE_SET 2331 * @see #WINDOW_FOCUSED_STATE_SET 2332 */ 2333 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2334 /** 2335 * Indicates the view is pressed and enabled. 2336 * 2337 * @see #PRESSED_STATE_SET 2338 * @see #ENABLED_STATE_SET 2339 */ 2340 protected static final int[] PRESSED_ENABLED_STATE_SET; 2341 /** 2342 * Indicates the view is pressed, enabled and its window has the focus. 2343 * 2344 * @see #PRESSED_STATE_SET 2345 * @see #ENABLED_STATE_SET 2346 * @see #WINDOW_FOCUSED_STATE_SET 2347 */ 2348 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 2349 /** 2350 * Indicates the view is pressed, enabled and selected. 2351 * 2352 * @see #PRESSED_STATE_SET 2353 * @see #ENABLED_STATE_SET 2354 * @see #SELECTED_STATE_SET 2355 */ 2356 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 2357 /** 2358 * Indicates the view is pressed, enabled, selected and its window has the 2359 * focus. 2360 * 2361 * @see #PRESSED_STATE_SET 2362 * @see #ENABLED_STATE_SET 2363 * @see #SELECTED_STATE_SET 2364 * @see #WINDOW_FOCUSED_STATE_SET 2365 */ 2366 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2367 /** 2368 * Indicates the view is pressed, enabled and focused. 2369 * 2370 * @see #PRESSED_STATE_SET 2371 * @see #ENABLED_STATE_SET 2372 * @see #FOCUSED_STATE_SET 2373 */ 2374 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 2375 /** 2376 * Indicates the view is pressed, enabled, focused and its window has the 2377 * focus. 2378 * 2379 * @see #PRESSED_STATE_SET 2380 * @see #ENABLED_STATE_SET 2381 * @see #FOCUSED_STATE_SET 2382 * @see #WINDOW_FOCUSED_STATE_SET 2383 */ 2384 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2385 /** 2386 * Indicates the view is pressed, enabled, focused and selected. 2387 * 2388 * @see #PRESSED_STATE_SET 2389 * @see #ENABLED_STATE_SET 2390 * @see #SELECTED_STATE_SET 2391 * @see #FOCUSED_STATE_SET 2392 */ 2393 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 2394 /** 2395 * Indicates the view is pressed, enabled, focused, selected and its window 2396 * has the focus. 2397 * 2398 * @see #PRESSED_STATE_SET 2399 * @see #ENABLED_STATE_SET 2400 * @see #SELECTED_STATE_SET 2401 * @see #FOCUSED_STATE_SET 2402 * @see #WINDOW_FOCUSED_STATE_SET 2403 */ 2404 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2405 2406 /** 2407 * This indicates that the frame rate category was chosen for an unknown reason. 2408 * @hide 2409 */ 2410 public static final int FRAME_RATE_CATEGORY_REASON_UNKNOWN = 0x0000_0000; 2411 2412 /** 2413 * This indicates that the frame rate category was chosen because it was a small area update. 2414 * @hide 2415 */ 2416 public static final int FRAME_RATE_CATEGORY_REASON_SMALL = 0x0100_0000; 2417 2418 /** 2419 * This indicates that the frame rate category was chosen because it was an intermittent update. 2420 * @hide 2421 */ 2422 public static final int FRAME_RATE_CATEGORY_REASON_INTERMITTENT = 0x0200_0000; 2423 2424 /** 2425 * This indicates that the frame rate category was chosen because it was a large View. 2426 * @hide 2427 */ 2428 public static final int FRAME_RATE_CATEGORY_REASON_LARGE = 0x03000000; 2429 2430 /** 2431 * This indicates that the frame rate category was chosen because it was requested. 2432 * @hide 2433 */ 2434 public static final int FRAME_RATE_CATEGORY_REASON_REQUESTED = 0x0400_0000; 2435 2436 /** 2437 * This indicates that the frame rate category was chosen because an invalid frame rate was 2438 * requested. 2439 * @hide 2440 */ 2441 public static final int FRAME_RATE_CATEGORY_REASON_INVALID = 0x0500_0000; 2442 2443 /** 2444 * This indicates that the frame rate category was chosen because the view has a velocity 2445 * @hide 2446 */ 2447 public static final int FRAME_RATE_CATEGORY_REASON_VELOCITY = 0x0600_0000; 2448 2449 /** 2450 * This indicates that the frame rate category was chosen because it is currently boosting. 2451 * @hide 2452 */ 2453 public static final int FRAME_RATE_CATEGORY_REASON_BOOST = 0x0800_0000; 2454 2455 /** 2456 * This indicates that the frame rate category was chosen because it is currently having 2457 * touch boost. 2458 * @hide 2459 */ 2460 public static final int FRAME_RATE_CATEGORY_REASON_TOUCH = 0x0900_0000; 2461 2462 /** 2463 * This indicates that the frame rate category was chosen because it is currently having 2464 * touch boost. 2465 * @hide 2466 */ 2467 public static final int FRAME_RATE_CATEGORY_REASON_CONFLICTED = 0x0A00_0000; 2468 2469 private static final int FRAME_RATE_CATEGORY_REASON_MASK = 0xFFFF_0000; 2470 2471 /** 2472 * @hide 2473 */ 2474 protected static boolean sToolkitSetFrameRateReadOnlyFlagValue; 2475 private static boolean sToolkitMetricsForFrameRateDecisionFlagValue; 2476 private static final boolean sToolkitFrameRateDefaultNormalReadOnlyFlagValue = 2477 toolkitFrameRateDefaultNormalReadOnly(); 2478 private static final boolean sToolkitFrameRateBySizeReadOnlyFlagValue = 2479 toolkitFrameRateBySizeReadOnly(); 2480 private static final boolean sToolkitFrameRateSmallUsesPercentReadOnlyFlagValue = 2481 toolkitFrameRateSmallUsesPercentReadOnly(); 2482 private static final boolean sToolkitFrameRateViewEnablingReadOnlyFlagValue = 2483 toolkitFrameRateViewEnablingReadOnly(); 2484 private static boolean sToolkitFrameRateVelocityMappingReadOnlyFlagValue = 2485 toolkitFrameRateVelocityMappingReadOnly(); 2486 private static boolean sToolkitFrameRateAnimationBugfix25q1FlagValue = 2487 toolkitFrameRateAnimationBugfix25q1(); 2488 private static boolean sToolkitViewGroupFrameRateApiFlagValue = 2489 toolkitViewgroupSetRequestedFrameRateApi(); 2490 2491 // Used to set frame rate compatibility. 2492 @Surface.FrameRateCompatibility int mFrameRateCompatibility = 2493 FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; 2494 2495 static { 2496 EMPTY_STATE_SET = StateSet.get(0); 2497 2498 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 2499 2500 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 2501 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2502 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 2503 2504 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 2505 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2506 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 2507 FOCUSED_SELECTED_STATE_SET = StateSet.get( 2508 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 2509 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2510 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2511 | StateSet.VIEW_STATE_FOCUSED); 2512 2513 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 2514 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2515 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2516 ENABLED_SELECTED_STATE_SET = StateSet.get( 2517 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 2518 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2519 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2520 | StateSet.VIEW_STATE_ENABLED); 2521 ENABLED_FOCUSED_STATE_SET = StateSet.get( 2522 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2523 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2524 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2525 | StateSet.VIEW_STATE_ENABLED); 2526 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2527 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2528 | StateSet.VIEW_STATE_ENABLED); 2529 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2530 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2531 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 2532 2533 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 2534 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2535 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2536 PRESSED_SELECTED_STATE_SET = StateSet.get( 2537 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 2538 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2539 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2540 | StateSet.VIEW_STATE_PRESSED); 2541 PRESSED_FOCUSED_STATE_SET = StateSet.get( 2542 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2543 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2544 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2545 | StateSet.VIEW_STATE_PRESSED); 2546 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2547 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2548 | StateSet.VIEW_STATE_PRESSED); 2549 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2550 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2551 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2552 PRESSED_ENABLED_STATE_SET = StateSet.get( 2553 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2554 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2555 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 2556 | StateSet.VIEW_STATE_PRESSED); 2557 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 2558 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 2559 | StateSet.VIEW_STATE_PRESSED); 2560 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2561 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2562 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2563 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 2564 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 2565 | StateSet.VIEW_STATE_PRESSED); 2566 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2567 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2568 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2569 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2570 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2571 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2572 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2573 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2574 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 2575 | StateSet.VIEW_STATE_PRESSED); 2576 2577 sToolkitSetFrameRateReadOnlyFlagValue = toolkitSetFrameRateReadOnly(); 2578 sToolkitMetricsForFrameRateDecisionFlagValue = toolkitMetricsForFrameRateDecision(); 2579 sCalculateBoundsInParentFromBoundsInScreenFlagValue = 2580 calculateBoundsInParentFromBoundsInScreen(); 2581 sUseMeasureCacheDuringForceLayoutFlagValue = enableUseMeasureCacheDuringForceLayout(); 2582 } 2583 2584 /** 2585 * Accessibility event types that are dispatched for text population. 2586 */ 2587 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 2588 AccessibilityEvent.TYPE_VIEW_CLICKED 2589 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 2590 | AccessibilityEvent.TYPE_VIEW_SELECTED 2591 | AccessibilityEvent.TYPE_VIEW_FOCUSED 2592 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 2593 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 2594 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 2595 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 2596 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 2597 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 2598 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 2599 2600 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 2601 2602 static final int DEBUG_CORNERS_SIZE_DIP = 8; 2603 2604 /** 2605 * Temporary Rect currently for use in setBackground(). This will probably 2606 * be extended in the future to hold our own class with more than just 2607 * a Rect. :) 2608 */ 2609 static final ThreadLocal<Rect> sThreadLocal = ThreadLocal.withInitial(Rect::new); 2610 2611 /** 2612 * Map used to store views' tags. 2613 */ 2614 @UnsupportedAppUsage 2615 private SparseArray<Object> mKeyedTags; 2616 2617 /** 2618 * The next available accessibility id. 2619 */ 2620 private static int sNextAccessibilityViewId; 2621 2622 /** 2623 * The animation currently associated with this view. 2624 * @hide 2625 */ 2626 protected Animation mCurrentAnimation = null; 2627 2628 /** 2629 * Width as measured during measure pass. 2630 * {@hide} 2631 */ 2632 @ViewDebug.ExportedProperty(category = "measurement") 2633 @UnsupportedAppUsage 2634 int mMeasuredWidth; 2635 2636 /** 2637 * Height as measured during measure pass. 2638 * {@hide} 2639 */ 2640 @ViewDebug.ExportedProperty(category = "measurement") 2641 @UnsupportedAppUsage 2642 int mMeasuredHeight; 2643 2644 /** 2645 * Flag to indicate that this view was marked INVALIDATED, or had its display list 2646 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 2647 * its display list. This flag, used only when hw accelerated, allows us to clear the 2648 * flag while retaining this information until it's needed (at getDisplayList() time and 2649 * in drawChild(), when we decide to draw a view's children's display lists into our own). 2650 * 2651 * {@hide} 2652 */ 2653 @UnsupportedAppUsage 2654 boolean mRecreateDisplayList = false; 2655 2656 /** 2657 * The view's identifier. 2658 * {@hide} 2659 * 2660 * @see #setId(int) 2661 * @see #getId() 2662 */ 2663 @IdRes 2664 @ViewDebug.ExportedProperty(resolveId = true) 2665 int mID = NO_ID; 2666 2667 /** The ID of this view for autofill purposes. 2668 * <ul> 2669 * <li>== {@link #NO_ID}: ID has not been assigned yet 2670 * <li>≤ {@link #LAST_APP_AUTOFILL_ID}: View is not part of a activity. The ID is 2671 * unique in the process. This might change 2672 * over activity lifecycle events. 2673 * <li>> {@link #LAST_APP_AUTOFILL_ID}: View is part of a activity. The ID is 2674 * unique in the activity. This stays the same 2675 * over activity lifecycle events. 2676 */ 2677 private int mAutofillViewId = NO_ID; 2678 2679 // ID for accessibility purposes. This ID must be unique for every window 2680 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2681 private int mAccessibilityViewId = NO_ID; 2682 2683 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2684 2685 /** 2686 * The view's tag. 2687 * {@hide} 2688 * 2689 * @see #setTag(Object) 2690 * @see #getTag() 2691 */ 2692 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2693 protected Object mTag = null; 2694 2695 /* 2696 * Masks for mPrivateFlags, as generated by dumpFlags(): 2697 * 2698 * |-------|-------|-------|-------| 2699 * 1 PFLAG_WANTS_FOCUS 2700 * 1 PFLAG_FOCUSED 2701 * 1 PFLAG_SELECTED 2702 * 1 PFLAG_IS_ROOT_NAMESPACE 2703 * 1 PFLAG_HAS_BOUNDS 2704 * 1 PFLAG_DRAWN 2705 * 1 PFLAG_DRAW_ANIMATION 2706 * 1 PFLAG_SKIP_DRAW 2707 * 1 PFLAG_REQUEST_TRANSPARENT_REGIONS 2708 * 1 PFLAG_DRAWABLE_STATE_DIRTY 2709 * 1 PFLAG_MEASURED_DIMENSION_SET 2710 * 1 PFLAG_FORCE_LAYOUT 2711 * 1 PFLAG_LAYOUT_REQUIRED 2712 * 1 PFLAG_PRESSED 2713 * 1 PFLAG_DRAWING_CACHE_VALID 2714 * 1 PFLAG_ANIMATION_STARTED 2715 * 1 PFLAG_SAVE_STATE_CALLED 2716 * 1 PFLAG_ALPHA_SET 2717 * 1 PFLAG_SCROLL_CONTAINER 2718 * 1 PFLAG_SCROLL_CONTAINER_ADDED 2719 * 1 PFLAG_DIRTY 2720 * 1 PFLAG_DIRTY_MASK 2721 * 1 PFLAG_OPAQUE_BACKGROUND 2722 * 1 PFLAG_OPAQUE_SCROLLBARS 2723 * 11 PFLAG_OPAQUE_MASK 2724 * 1 PFLAG_PREPRESSED 2725 * 1 PFLAG_CANCEL_NEXT_UP_EVENT 2726 * 1 PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH 2727 * 1 PFLAG_HOVERED 2728 * 1 PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK 2729 * 1 PFLAG_ACTIVATED 2730 * 1 PFLAG_INVALIDATED 2731 * |-------|-------|-------|-------| 2732 */ 2733 /** {@hide} */ 2734 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2735 /** {@hide} */ 2736 static final int PFLAG_FOCUSED = 0x00000002; 2737 /** {@hide} */ 2738 static final int PFLAG_SELECTED = 0x00000004; 2739 /** {@hide} */ 2740 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2741 /** {@hide} */ 2742 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2743 /** {@hide} */ 2744 static final int PFLAG_DRAWN = 0x00000020; 2745 /** 2746 * When this flag is set, this view is running an animation on behalf of its 2747 * children and should therefore not cancel invalidate requests, even if they 2748 * lie outside of this view's bounds. 2749 * 2750 * {@hide} 2751 */ 2752 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2753 /** {@hide} */ 2754 static final int PFLAG_SKIP_DRAW = 0x00000080; 2755 /** {@hide} */ 2756 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2757 /** {@hide} */ 2758 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2759 /** {@hide} */ 2760 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2761 /** {@hide} */ 2762 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2763 /** {@hide} */ 2764 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2765 2766 private static final int PFLAG_PRESSED = 0x00004000; 2767 2768 /** {@hide} */ 2769 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2770 /** 2771 * Flag used to indicate that this view should be drawn once more (and only once 2772 * more) after its animation has completed. 2773 * {@hide} 2774 */ 2775 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2776 2777 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2778 2779 /** 2780 * Indicates that the View returned true when onSetAlpha() was called and that 2781 * the alpha must be restored. 2782 * {@hide} 2783 */ 2784 static final int PFLAG_ALPHA_SET = 0x00040000; 2785 2786 /** 2787 * Set by {@link #setScrollContainer(boolean)}. 2788 */ 2789 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2790 2791 /** 2792 * Set by {@link #setScrollContainer(boolean)}. 2793 */ 2794 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2795 2796 /** 2797 * View flag indicating whether this view was invalidated (fully or partially.) 2798 * 2799 * @hide 2800 */ 2801 static final int PFLAG_DIRTY = 0x00200000; 2802 2803 /** 2804 * Mask for {@link #PFLAG_DIRTY}. 2805 * 2806 * @hide 2807 */ 2808 static final int PFLAG_DIRTY_MASK = 0x00200000; 2809 2810 /** 2811 * Indicates whether the background is opaque. 2812 * 2813 * @hide 2814 */ 2815 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2816 2817 /** 2818 * Indicates whether the scrollbars are opaque. 2819 * 2820 * @hide 2821 */ 2822 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2823 2824 /** 2825 * Indicates whether the view is opaque. 2826 * 2827 * @hide 2828 */ 2829 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2830 2831 /** 2832 * Indicates a prepressed state; 2833 * the short time between ACTION_DOWN and recognizing 2834 * a 'real' press. Prepressed is used to recognize quick taps 2835 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2836 * 2837 * @hide 2838 */ 2839 private static final int PFLAG_PREPRESSED = 0x02000000; 2840 2841 /** 2842 * Indicates whether the view is temporarily detached. 2843 * 2844 * @hide 2845 */ 2846 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2847 2848 /** 2849 * Indicates that we should awaken scroll bars once attached 2850 * 2851 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2852 * during window attachment and it is no longer needed. Feel free to repurpose it. 2853 * 2854 * @hide 2855 */ 2856 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2857 2858 /** 2859 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2860 * @hide 2861 */ 2862 private static final int PFLAG_HOVERED = 0x10000000; 2863 2864 /** 2865 * Flag set by {@link AutofillManager} if it needs to be notified when this view is clicked. 2866 */ 2867 private static final int PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK = 0x20000000; 2868 2869 /** {@hide} */ 2870 static final int PFLAG_ACTIVATED = 0x40000000; 2871 2872 /** 2873 * Indicates that this view was specifically invalidated, not just dirtied because some 2874 * child view was invalidated. The flag is used to determine when we need to recreate 2875 * a view's display list (as opposed to just returning a reference to its existing 2876 * display list). 2877 * 2878 * @hide 2879 */ 2880 static final int PFLAG_INVALIDATED = 0x80000000; 2881 2882 /* End of masks for mPrivateFlags */ 2883 2884 /* 2885 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2886 * 2887 * |-------|-------|-------|-------| 2888 * 1 PFLAG2_DRAG_CAN_ACCEPT 2889 * 1 PFLAG2_DRAG_HOVERED 2890 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2891 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2892 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2893 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2894 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2895 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2896 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2897 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2898 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2899 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2900 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2901 * 111 PFLAG2_TEXT_DIRECTION_MASK 2902 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2903 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2904 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2905 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2906 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2907 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2908 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2909 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2910 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2911 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2912 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2913 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2914 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2915 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2916 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2917 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2918 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2919 * 1 PFLAG2_VIEW_QUICK_REJECTED 2920 * 1 PFLAG2_PADDING_RESOLVED 2921 * 1 PFLAG2_DRAWABLE_RESOLVED 2922 * 1 PFLAG2_HAS_TRANSIENT_STATE 2923 * |-------|-------|-------|-------| 2924 */ 2925 2926 /** 2927 * Indicates that this view has reported that it can accept the current drag's content. 2928 * Cleared when the drag operation concludes. 2929 * @hide 2930 */ 2931 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2932 2933 /** 2934 * Indicates that this view is currently directly under the drag location in a 2935 * drag-and-drop operation involving content that it can accept. Cleared when 2936 * the drag exits the view, or when the drag operation concludes. 2937 * @hide 2938 */ 2939 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2940 2941 /** @hide */ 2942 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2943 LAYOUT_DIRECTION_LTR, 2944 LAYOUT_DIRECTION_RTL, 2945 LAYOUT_DIRECTION_INHERIT, 2946 LAYOUT_DIRECTION_LOCALE 2947 }) 2948 @Retention(RetentionPolicy.SOURCE) 2949 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2950 public @interface LayoutDir {} 2951 2952 /** @hide */ 2953 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2954 LAYOUT_DIRECTION_LTR, 2955 LAYOUT_DIRECTION_RTL 2956 }) 2957 @Retention(RetentionPolicy.SOURCE) 2958 public @interface ResolvedLayoutDir {} 2959 2960 /** 2961 * A flag to indicate that the layout direction of this view has not been defined yet. 2962 * @hide 2963 */ 2964 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2965 2966 /** 2967 * Horizontal layout direction of this view is from Left to Right. 2968 * Use with {@link #setLayoutDirection}. 2969 */ 2970 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2971 2972 /** 2973 * Horizontal layout direction of this view is from Right to Left. 2974 * Use with {@link #setLayoutDirection}. 2975 */ 2976 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2977 2978 /** 2979 * Horizontal layout direction of this view is inherited from its parent. 2980 * Use with {@link #setLayoutDirection}. 2981 */ 2982 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2983 2984 /** 2985 * Horizontal layout direction of this view is from deduced from the default language 2986 * script for the locale. Use with {@link #setLayoutDirection}. 2987 */ 2988 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2989 2990 /** 2991 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2992 * @hide 2993 */ 2994 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2995 2996 /** 2997 * Mask for use with private flags indicating bits used for horizontal layout direction. 2998 * @hide 2999 */ 3000 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 3001 3002 /** 3003 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 3004 * right-to-left direction. 3005 * @hide 3006 */ 3007 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 3008 3009 /** 3010 * Indicates whether the view horizontal layout direction has been resolved. 3011 * @hide 3012 */ 3013 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 3014 3015 /** 3016 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 3017 * @hide 3018 */ 3019 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 3020 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 3021 3022 /* 3023 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 3024 * flag value. 3025 * @hide 3026 */ 3027 private static final int[] LAYOUT_DIRECTION_FLAGS = { 3028 LAYOUT_DIRECTION_LTR, 3029 LAYOUT_DIRECTION_RTL, 3030 LAYOUT_DIRECTION_INHERIT, 3031 LAYOUT_DIRECTION_LOCALE 3032 }; 3033 3034 /** 3035 * Default horizontal layout direction. 3036 */ 3037 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 3038 3039 /** 3040 * Default horizontal layout direction. 3041 * @hide 3042 */ 3043 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 3044 3045 /** 3046 * Text direction is inherited through {@link ViewGroup} 3047 */ 3048 public static final int TEXT_DIRECTION_INHERIT = 0; 3049 3050 /** 3051 * Text direction is using "first strong algorithm". The first strong directional character 3052 * determines the paragraph direction. If there is no strong directional character, the 3053 * paragraph direction is the view's resolved layout direction. 3054 */ 3055 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 3056 3057 /** 3058 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 3059 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 3060 * If there are neither, the paragraph direction is the view's resolved layout direction. 3061 */ 3062 public static final int TEXT_DIRECTION_ANY_RTL = 2; 3063 3064 /** 3065 * Text direction is forced to LTR. 3066 */ 3067 public static final int TEXT_DIRECTION_LTR = 3; 3068 3069 /** 3070 * Text direction is forced to RTL. 3071 */ 3072 public static final int TEXT_DIRECTION_RTL = 4; 3073 3074 /** 3075 * Text direction is coming from the system Locale. 3076 */ 3077 public static final int TEXT_DIRECTION_LOCALE = 5; 3078 3079 /** 3080 * Text direction is using "first strong algorithm". The first strong directional character 3081 * determines the paragraph direction. If there is no strong directional character, the 3082 * paragraph direction is LTR. 3083 */ 3084 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 3085 3086 /** 3087 * Text direction is using "first strong algorithm". The first strong directional character 3088 * determines the paragraph direction. If there is no strong directional character, the 3089 * paragraph direction is RTL. 3090 */ 3091 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 3092 3093 /** 3094 * Default text direction is inherited 3095 */ 3096 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 3097 3098 /** 3099 * Default resolved text direction 3100 * @hide 3101 */ 3102 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 3103 3104 /** 3105 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 3106 * @hide 3107 */ 3108 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 3109 3110 /** 3111 * Mask for use with private flags indicating bits used for text direction. 3112 * @hide 3113 */ 3114 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 3115 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 3116 3117 /** 3118 * Array of text direction flags for mapping attribute "textDirection" to correct 3119 * flag value. 3120 * @hide 3121 */ 3122 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 3123 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 3124 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 3125 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 3126 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 3127 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 3128 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 3129 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 3130 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 3131 }; 3132 3133 /** 3134 * Indicates whether the view text direction has been resolved. 3135 * @hide 3136 */ 3137 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 3138 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 3139 3140 /** 3141 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 3142 * @hide 3143 */ 3144 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 3145 3146 /** 3147 * Mask for use with private flags indicating bits used for resolved text direction. 3148 * @hide 3149 */ 3150 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 3151 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 3152 3153 /** 3154 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 3155 * @hide 3156 */ 3157 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 3158 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 3159 3160 /** @hide */ 3161 @IntDef(prefix = { "TEXT_ALIGNMENT_" }, value = { 3162 TEXT_ALIGNMENT_INHERIT, 3163 TEXT_ALIGNMENT_GRAVITY, 3164 TEXT_ALIGNMENT_CENTER, 3165 TEXT_ALIGNMENT_TEXT_START, 3166 TEXT_ALIGNMENT_TEXT_END, 3167 TEXT_ALIGNMENT_VIEW_START, 3168 TEXT_ALIGNMENT_VIEW_END 3169 }) 3170 @Retention(RetentionPolicy.SOURCE) 3171 public @interface TextAlignment {} 3172 3173 /** 3174 * Default text alignment. The text alignment of this View is inherited from its parent. 3175 * Use with {@link #setTextAlignment(int)} 3176 */ 3177 public static final int TEXT_ALIGNMENT_INHERIT = 0; 3178 3179 /** 3180 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 3181 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph's text direction. 3182 * 3183 * Use with {@link #setTextAlignment(int)} 3184 */ 3185 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 3186 3187 /** 3188 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 3189 * 3190 * Use with {@link #setTextAlignment(int)} 3191 */ 3192 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 3193 3194 /** 3195 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 3196 * 3197 * Use with {@link #setTextAlignment(int)} 3198 */ 3199 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 3200 3201 /** 3202 * Center the paragraph, e.g. ALIGN_CENTER. 3203 * 3204 * Use with {@link #setTextAlignment(int)} 3205 */ 3206 public static final int TEXT_ALIGNMENT_CENTER = 4; 3207 3208 /** 3209 * Align to the start of the view, which is ALIGN_LEFT if the view's resolved 3210 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 3211 * 3212 * Use with {@link #setTextAlignment(int)} 3213 */ 3214 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 3215 3216 /** 3217 * Align to the end of the view, which is ALIGN_RIGHT if the view's resolved 3218 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 3219 * 3220 * Use with {@link #setTextAlignment(int)} 3221 */ 3222 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 3223 3224 /** 3225 * Default text alignment is inherited 3226 */ 3227 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 3228 3229 /** 3230 * Default resolved text alignment 3231 * @hide 3232 */ 3233 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 3234 3235 /** 3236 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 3237 * @hide 3238 */ 3239 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 3240 3241 /** 3242 * Mask for use with private flags indicating bits used for text alignment. 3243 * @hide 3244 */ 3245 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 3246 3247 /** 3248 * Array of text direction flags for mapping attribute "textAlignment" to correct 3249 * flag value. 3250 * @hide 3251 */ 3252 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 3253 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3254 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3255 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3256 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3257 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3258 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3259 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 3260 }; 3261 3262 /** 3263 * Indicates whether the view text alignment has been resolved. 3264 * @hide 3265 */ 3266 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 3267 3268 /** 3269 * Bit shift to get the resolved text alignment. 3270 * @hide 3271 */ 3272 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 3273 3274 /** 3275 * Mask for use with private flags indicating bits used for text alignment. 3276 * @hide 3277 */ 3278 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 3279 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 3280 3281 /** 3282 * Indicates whether if the view text alignment has been resolved to gravity 3283 */ 3284 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 3285 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 3286 3287 // Accessiblity constants for mPrivateFlags2 3288 3289 /** 3290 * Shift for the bits in {@link #mPrivateFlags2} related to the 3291 * "importantForAccessibility" attribute. 3292 */ 3293 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 3294 3295 /** 3296 * Automatically determine whether a view is important for accessibility. 3297 */ 3298 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 3299 3300 /** 3301 * The view is important for accessibility. 3302 */ 3303 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 3304 3305 /** 3306 * The view is not important for accessibility. 3307 */ 3308 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 3309 3310 /** 3311 * The view is not important for accessibility, nor are any of its 3312 * descendant views. 3313 */ 3314 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 3315 3316 /** 3317 * The default whether the view is important for accessibility. 3318 */ 3319 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 3320 3321 /** 3322 * Automatically determine whether the view should only allow interactions from 3323 * {@link android.accessibilityservice.AccessibilityService}s with the 3324 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property 3325 * set to true. 3326 * 3327 * <p> 3328 * Accessibility interactions from services without {@code isAccessibilityTool} set to true are 3329 * disallowed for any of the following conditions: 3330 * <li>this view sets {@link #getFilterTouchesWhenObscured()}.</li> 3331 * <li>any parent of this view returns true from {@link #isAccessibilityDataSensitive()}.</li> 3332 * </p> 3333 */ 3334 public static final int ACCESSIBILITY_DATA_SENSITIVE_AUTO = 0x00000000; 3335 3336 /** 3337 * Only allow interactions from {@link android.accessibilityservice.AccessibilityService}s 3338 * with the {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} 3339 * property set to true. 3340 */ 3341 public static final int ACCESSIBILITY_DATA_SENSITIVE_YES = 0x00000001; 3342 3343 /** 3344 * Allow interactions from all {@link android.accessibilityservice.AccessibilityService}s, 3345 * regardless of their 3346 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property. 3347 */ 3348 public static final int ACCESSIBILITY_DATA_SENSITIVE_NO = 0x00000002; 3349 3350 /** @hide */ 3351 @IntDef(prefix = { "ACCESSIBILITY_DATA_SENSITIVE_" }, value = { 3352 ACCESSIBILITY_DATA_SENSITIVE_AUTO, 3353 ACCESSIBILITY_DATA_SENSITIVE_YES, 3354 ACCESSIBILITY_DATA_SENSITIVE_NO, 3355 }) 3356 @Retention(RetentionPolicy.SOURCE) 3357 public @interface AccessibilityDataSensitive {} 3358 3359 /** 3360 * Mask for obtaining the bits which specify how to determine 3361 * whether a view is important for accessibility. 3362 */ 3363 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 3364 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 3365 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 3366 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 3367 3368 /** 3369 * Shift for the bits in {@link #mPrivateFlags2} related to the 3370 * "accessibilityLiveRegion" attribute. 3371 */ 3372 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 3373 3374 /** 3375 * Live region mode specifying that accessibility services should not 3376 * automatically announce changes to this view. This is the default live 3377 * region mode for most views. 3378 * <p> 3379 * Use with {@link #setAccessibilityLiveRegion(int)}. 3380 */ 3381 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 3382 3383 /** 3384 * Live region mode specifying that accessibility services should notify users of changes to 3385 * this view. 3386 * <p> 3387 * Use with {@link #setAccessibilityLiveRegion(int)}. 3388 */ 3389 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 3390 3391 /** 3392 * Live region mode specifying that accessibility services should immediately notify users of 3393 * changes to this view. For example, a screen reader may interrupt ongoing speech to 3394 * immediately announce these changes. 3395 * <p> 3396 * Use with {@link #setAccessibilityLiveRegion(int)}. 3397 */ 3398 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 3399 3400 /** 3401 * The default whether the view is important for accessibility. 3402 */ 3403 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 3404 3405 /** 3406 * Mask for obtaining the bits which specify a view's accessibility live 3407 * region mode. 3408 */ 3409 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 3410 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 3411 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 3412 3413 /** 3414 * Flag indicating whether a view has accessibility focus. 3415 */ 3416 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 3417 3418 /** 3419 * Flag whether the accessibility state of the subtree rooted at this view changed. 3420 */ 3421 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 3422 3423 /** 3424 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 3425 * is used to check whether later changes to the view's transform should invalidate the 3426 * view to force the quickReject test to run again. 3427 */ 3428 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 3429 3430 /** 3431 * Flag indicating that start/end padding has been resolved into left/right padding 3432 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 3433 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 3434 * during measurement. In some special cases this is required such as when an adapter-based 3435 * view measures prospective children without attaching them to a window. 3436 */ 3437 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 3438 3439 /** 3440 * Flag indicating that the start/end drawables has been resolved into left/right ones. 3441 */ 3442 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 3443 3444 /** 3445 * Indicates that the view is tracking some sort of transient state 3446 * that the app should not need to be aware of, but that the framework 3447 * should take special care to preserve. 3448 */ 3449 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 3450 3451 /** 3452 * Group of bits indicating that RTL properties resolution is done. 3453 */ 3454 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 3455 PFLAG2_TEXT_DIRECTION_RESOLVED | 3456 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 3457 PFLAG2_PADDING_RESOLVED | 3458 PFLAG2_DRAWABLE_RESOLVED; 3459 3460 // There are a couple of flags left in mPrivateFlags2 3461 3462 /* End of masks for mPrivateFlags2 */ 3463 3464 /* 3465 * Masks for mPrivateFlags3, as generated by dumpFlags(): 3466 * 3467 * |-------|-------|-------|-------| 3468 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 3469 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 3470 * 1 PFLAG3_IS_LAID_OUT 3471 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 3472 * 1 PFLAG3_CALLED_SUPER 3473 * 1 PFLAG3_APPLYING_INSETS 3474 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 3475 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 3476 * 1 PFLAG3_SCROLL_INDICATOR_TOP 3477 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 3478 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 3479 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 3480 * 1 PFLAG3_SCROLL_INDICATOR_START 3481 * 1 PFLAG3_SCROLL_INDICATOR_END 3482 * 1 PFLAG3_ASSIST_BLOCKED 3483 * 1 PFLAG3_CLUSTER 3484 * 1 PFLAG3_IS_AUTOFILLED 3485 * 1 PFLAG3_FINGER_DOWN 3486 * 1 PFLAG3_FOCUSED_BY_DEFAULT 3487 * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL 3488 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 3489 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 3490 * 1 PFLAG3_TEMPORARY_DETACH 3491 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 3492 * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT 3493 * 1 PFLAG3_SCREEN_READER_FOCUSABLE 3494 * 1 PFLAG3_AGGREGATED_VISIBLE 3495 * 1 PFLAG3_AUTOFILLID_EXPLICITLY_SET 3496 * 1 PFLAG3_ACCESSIBILITY_HEADING 3497 * |-------|-------|-------|-------| 3498 */ 3499 3500 /** 3501 * Flag indicating that view has a transform animation set on it. This is used to track whether 3502 * an animation is cleared between successive frames, in order to tell the associated 3503 * DisplayList to clear its animation matrix. 3504 */ 3505 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 3506 3507 /** 3508 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 3509 * animation is cleared between successive frames, in order to tell the associated 3510 * DisplayList to restore its alpha value. 3511 */ 3512 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 3513 3514 /** 3515 * Flag indicating that the view has been through at least one layout since it 3516 * was last attached to a window. 3517 */ 3518 static final int PFLAG3_IS_LAID_OUT = 0x4; 3519 3520 /** 3521 * Flag indicating that a call to measure() was skipped and should be done 3522 * instead when layout() is invoked. 3523 */ 3524 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 3525 3526 /** 3527 * Flag indicating that an overridden method correctly called down to 3528 * the superclass implementation as required by the API spec. 3529 */ 3530 static final int PFLAG3_CALLED_SUPER = 0x10; 3531 3532 /** 3533 * Flag indicating that we're in the process of applying window insets. 3534 */ 3535 static final int PFLAG3_APPLYING_INSETS = 0x20; 3536 3537 /** 3538 * Flag indicating that we're in the process of fitting system windows using the old method. 3539 */ 3540 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 3541 3542 /** 3543 * Flag indicating that nested scrolling is enabled for this view. 3544 * The view will optionally cooperate with views up its parent chain to allow for 3545 * integrated nested scrolling along the same axis. 3546 */ 3547 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 3548 3549 /** 3550 * Flag indicating that the bottom scroll indicator should be displayed 3551 * when this view can scroll up. 3552 */ 3553 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 3554 3555 /** 3556 * Flag indicating that the bottom scroll indicator should be displayed 3557 * when this view can scroll down. 3558 */ 3559 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 3560 3561 /** 3562 * Flag indicating that the left scroll indicator should be displayed 3563 * when this view can scroll left. 3564 */ 3565 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 3566 3567 /** 3568 * Flag indicating that the right scroll indicator should be displayed 3569 * when this view can scroll right. 3570 */ 3571 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 3572 3573 /** 3574 * Flag indicating that the start scroll indicator should be displayed 3575 * when this view can scroll in the start direction. 3576 */ 3577 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 3578 3579 /** 3580 * Flag indicating that the end scroll indicator should be displayed 3581 * when this view can scroll in the end direction. 3582 */ 3583 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 3584 3585 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 3586 3587 static final int SCROLL_INDICATORS_NONE = 0x0000; 3588 3589 /** 3590 * Mask for use with setFlags indicating bits used for indicating which 3591 * scroll indicators are enabled. 3592 */ 3593 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 3594 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 3595 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 3596 | PFLAG3_SCROLL_INDICATOR_END; 3597 3598 /** 3599 * Left-shift required to translate between public scroll indicator flags 3600 * and internal PFLAGS3 flags. When used as a right-shift, translates 3601 * PFLAGS3 flags to public flags. 3602 */ 3603 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 3604 3605 /** @hide */ 3606 @Retention(RetentionPolicy.SOURCE) 3607 @IntDef(flag = true, prefix = { "SCROLL_INDICATOR_" }, value = { 3608 SCROLL_INDICATOR_TOP, 3609 SCROLL_INDICATOR_BOTTOM, 3610 SCROLL_INDICATOR_LEFT, 3611 SCROLL_INDICATOR_RIGHT, 3612 SCROLL_INDICATOR_START, 3613 SCROLL_INDICATOR_END, 3614 }) 3615 public @interface ScrollIndicators {} 3616 3617 /** 3618 * Scroll indicator direction for the top edge of the view. 3619 * 3620 * @see #setScrollIndicators(int) 3621 * @see #setScrollIndicators(int, int) 3622 * @see #getScrollIndicators() 3623 */ 3624 public static final int SCROLL_INDICATOR_TOP = 3625 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3626 3627 /** 3628 * Scroll indicator direction for the bottom edge of the view. 3629 * 3630 * @see #setScrollIndicators(int) 3631 * @see #setScrollIndicators(int, int) 3632 * @see #getScrollIndicators() 3633 */ 3634 public static final int SCROLL_INDICATOR_BOTTOM = 3635 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3636 3637 /** 3638 * Scroll indicator direction for the left edge of the view. 3639 * 3640 * @see #setScrollIndicators(int) 3641 * @see #setScrollIndicators(int, int) 3642 * @see #getScrollIndicators() 3643 */ 3644 public static final int SCROLL_INDICATOR_LEFT = 3645 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3646 3647 /** 3648 * Scroll indicator direction for the right edge of the view. 3649 * 3650 * @see #setScrollIndicators(int) 3651 * @see #setScrollIndicators(int, int) 3652 * @see #getScrollIndicators() 3653 */ 3654 public static final int SCROLL_INDICATOR_RIGHT = 3655 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3656 3657 /** 3658 * Scroll indicator direction for the starting edge of the view. 3659 * <p> 3660 * Resolved according to the view's layout direction, see 3661 * {@link #getLayoutDirection()} for more information. 3662 * 3663 * @see #setScrollIndicators(int) 3664 * @see #setScrollIndicators(int, int) 3665 * @see #getScrollIndicators() 3666 */ 3667 public static final int SCROLL_INDICATOR_START = 3668 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3669 3670 /** 3671 * Scroll indicator direction for the ending edge of the view. 3672 * <p> 3673 * Resolved according to the view's layout direction, see 3674 * {@link #getLayoutDirection()} for more information. 3675 * 3676 * @see #setScrollIndicators(int) 3677 * @see #setScrollIndicators(int, int) 3678 * @see #getScrollIndicators() 3679 */ 3680 public static final int SCROLL_INDICATOR_END = 3681 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3682 3683 /** 3684 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 3685 * into this view.<p> 3686 */ 3687 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 3688 3689 /** 3690 * Flag indicating that the view is a root of a keyboard navigation cluster. 3691 * 3692 * @see #isKeyboardNavigationCluster() 3693 * @see #setKeyboardNavigationCluster(boolean) 3694 */ 3695 private static final int PFLAG3_CLUSTER = 0x8000; 3696 3697 /** 3698 * Flag indicating that the view is autofilled 3699 * 3700 * @see #isAutofilled() 3701 * @see #setAutofilled(boolean, boolean) 3702 */ 3703 private static final int PFLAG3_IS_AUTOFILLED = 0x10000; 3704 3705 /** 3706 * Indicates that the user is currently touching the screen. 3707 * Currently used for the tooltip positioning only. 3708 */ 3709 private static final int PFLAG3_FINGER_DOWN = 0x20000; 3710 3711 /** 3712 * Flag indicating that this view is the default-focus view. 3713 * 3714 * @see #isFocusedByDefault() 3715 * @see #setFocusedByDefault(boolean) 3716 */ 3717 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 3718 3719 /** 3720 * Shift for the bits in {@link #mPrivateFlags3} related to the 3721 * "importantForAutofill" attribute. 3722 */ 3723 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19; 3724 3725 /** 3726 * Mask for obtaining the bits which specify how to determine 3727 * whether a view is important for autofill. 3728 */ 3729 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 3730 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO 3731 | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 3732 | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS) 3733 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 3734 3735 /** 3736 * Whether this view has rendered elements that overlap (see {@link 3737 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 3738 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 3739 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 3740 * determined by whatever {@link #hasOverlappingRendering()} returns. 3741 */ 3742 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 3743 3744 /** 3745 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 3746 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 3747 */ 3748 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 3749 3750 /** 3751 * Flag indicating that the view is temporarily detached from the parent view. 3752 * 3753 * @see #onStartTemporaryDetach() 3754 * @see #onFinishTemporaryDetach() 3755 */ 3756 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3757 3758 /** 3759 * Flag indicating that the view does not wish to be revealed within its parent 3760 * hierarchy when it gains focus. Expressed in the negative since the historical 3761 * default behavior is to reveal on focus; this flag suppresses that behavior. 3762 * 3763 * @see #setRevealOnFocusHint(boolean) 3764 * @see #getRevealOnFocusHint() 3765 */ 3766 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3767 3768 /** 3769 * Flag indicating that when layout is completed we should notify 3770 * that the view was entered for autofill purposes. To minimize 3771 * showing autofill for views not visible to the user we evaluate 3772 * user visibility which cannot be done until the view is laid out. 3773 */ 3774 static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000; 3775 3776 /** 3777 * Works like focusable for screen readers, but without the side effects on input focus. 3778 * @see #setScreenReaderFocusable(boolean) 3779 */ 3780 private static final int PFLAG3_SCREEN_READER_FOCUSABLE = 0x10000000; 3781 3782 /** 3783 * The last aggregated visibility. Used to detect when it truly changes. 3784 */ 3785 private static final int PFLAG3_AGGREGATED_VISIBLE = 0x20000000; 3786 3787 /** 3788 * Used to indicate that {@link #mAutofillId} was explicitly set through 3789 * {@link #setAutofillId(AutofillId)}. 3790 */ 3791 private static final int PFLAG3_AUTOFILLID_EXPLICITLY_SET = 0x40000000; 3792 3793 /** 3794 * Indicates if the View is a heading for accessibility purposes 3795 */ 3796 private static final int PFLAG3_ACCESSIBILITY_HEADING = 0x80000000; 3797 3798 /* End of masks for mPrivateFlags3 */ 3799 3800 /* 3801 * Masks for mPrivateFlags4, as generated by dumpFlags(): 3802 * 3803 * |-------|-------|-------|-------| 3804 * 1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK 3805 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED 3806 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED 3807 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3808 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE 3809 * 11 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK 3810 * 1 PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS 3811 * 1 PFLAG4_AUTOFILL_HIDE_HIGHLIGHT 3812 * 11 PFLAG4_SCROLL_CAPTURE_HINT_MASK 3813 * 1 PFLAG4_ALLOW_CLICK_WHEN_DISABLED 3814 * 1 PFLAG4_DETACHED 3815 * 1 PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE 3816 * 1 PFLAG4_DRAG_A11Y_STARTED 3817 * 1 PFLAG4_AUTO_HANDWRITING_INITIATION_ENABLED 3818 * 1 PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER 3819 * 1 PFLAG4_TRAVERSAL_TRACING_ENABLED 3820 * 1 PFLAG4_RELAYOUT_TRACING_ENABLED 3821 * 1 PFLAG4_ROTARY_HAPTICS_DETERMINED 3822 * 1 PFLAG4_ROTARY_HAPTICS_ENABLED 3823 * 1 PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT 3824 * 1 PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT 3825 * 11 PFLAG4_CONTENT_SENSITIVITY_MASK 3826 * 1 PFLAG4_IS_COUNTED_AS_SENSITIVE 3827 * 1 PFLAG4_HAS_DRAWN 3828 * 1 PFLAG4_HAS_MOVED 3829 * 1 PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION 3830 * 1 PFLAG4_FORCED_OVERRIDE_FRAME_RATE 3831 * 1 PFLAG4_SELF_REQUESTED_FRAME_RATE 3832 * |-------|-------|-------|-------| 3833 */ 3834 3835 /** 3836 * Mask for obtaining the bits which specify how to determine 3837 * whether a view is important for autofill. 3838 * 3839 * <p>NOTE: the important for content capture values were the first flags added and are set in 3840 * the rightmost position, so we don't need to shift them 3841 */ 3842 private static final int PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK = 3843 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO | IMPORTANT_FOR_CONTENT_CAPTURE_YES 3844 | IMPORTANT_FOR_CONTENT_CAPTURE_NO 3845 | IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 3846 | IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS; 3847 3848 /* 3849 * Variables used to control when the IntelligenceManager.notifyNodeAdded()/removed() methods 3850 * should be called. 3851 * 3852 * The idea is to call notifyAppeared() after the view is layout and visible, then call 3853 * notifyDisappeared() when it's gone (without known when it was removed from the parent). 3854 */ 3855 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10; 3856 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20; 3857 3858 /* 3859 * Flags used to cache the value returned by isImportantForContentCapture while the view 3860 * hierarchy is being traversed. 3861 */ 3862 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED = 0x40; 3863 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE = 0x80; 3864 3865 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK = 3866 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3867 | PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 3868 3869 /** 3870 * @see #OPTIONAL_FITS_SYSTEM_WINDOWS 3871 */ 3872 static final int PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS = 0x000000100; 3873 3874 /** 3875 * Flag indicating the field should not have yellow highlight when autofilled. 3876 */ 3877 private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x200; 3878 3879 /** 3880 * Shift for the bits in {@link #mPrivateFlags4} related to scroll capture. 3881 */ 3882 static final int PFLAG4_SCROLL_CAPTURE_HINT_SHIFT = 10; 3883 3884 static final int PFLAG4_SCROLL_CAPTURE_HINT_MASK = (SCROLL_CAPTURE_HINT_INCLUDE 3885 | SCROLL_CAPTURE_HINT_EXCLUDE | SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS) 3886 << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; 3887 3888 /** 3889 * Indicates if the view can receive click events when disabled. 3890 */ 3891 private static final int PFLAG4_ALLOW_CLICK_WHEN_DISABLED = 0x000001000; 3892 3893 /** 3894 * Indicates if the view is just detached. 3895 */ 3896 private static final int PFLAG4_DETACHED = 0x000002000; 3897 3898 /** 3899 * Indicates that the view has transient state because the system is translating it. 3900 */ 3901 private static final int PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE = 0x000004000; 3902 3903 /** 3904 * Indicates that the view has started a drag with {@link AccessibilityAction#ACTION_DRAG_START} 3905 */ 3906 private static final int PFLAG4_DRAG_A11Y_STARTED = 0x000008000; 3907 3908 /** 3909 * Indicates that the view enables auto handwriting initiation. 3910 */ 3911 private static final int PFLAG4_AUTO_HANDWRITING_ENABLED = 0x000010000; 3912 3913 /** 3914 * Indicates that the view is important for Credential Manager. 3915 */ 3916 private static final int PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER = 0x000020000; 3917 3918 /** 3919 * When set, measure and layout passes of this view will be logged with {@link Trace}, so we 3920 * can better debug jank due to complex view hierarchies. 3921 */ 3922 private static final int PFLAG4_TRAVERSAL_TRACING_ENABLED = 0x000040000; 3923 3924 /** 3925 * When set, emits a {@link Trace} instant event and stacktrace every time a requestLayout of 3926 * this class happens. 3927 */ 3928 private static final int PFLAG4_RELAYOUT_TRACING_ENABLED = 0x000080000; 3929 3930 /** Indicates if rotary scroll haptics support for the view has been determined. */ 3931 private static final int PFLAG4_ROTARY_HAPTICS_DETERMINED = 0x100000; 3932 3933 /** 3934 * Indicates if rotary scroll haptics is enabled for this view. 3935 * The source of truth for this info is a ViewConfiguration API; this bit only caches the value. 3936 */ 3937 private static final int PFLAG4_ROTARY_HAPTICS_ENABLED = 0x200000; 3938 3939 /** Indicates if there has been a scroll event since the last rotary input. */ 3940 private static final int PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT = 0x400000; 3941 3942 /** 3943 * Indicates if there has been a rotary input that may generate a scroll event. 3944 * This flag is important so that a scroll event can be properly attributed to a rotary input. 3945 */ 3946 private static final int PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT = 0x800000; 3947 3948 private static final int PFLAG4_CONTENT_SENSITIVITY_SHIFT = 24; 3949 3950 /** 3951 * Mask for obtaining the bits which specify how to determine whether a view 3952 * displays sensitive content or not. 3953 */ 3954 private static final int PFLAG4_CONTENT_SENSITIVITY_MASK = 3955 (CONTENT_SENSITIVITY_AUTO | CONTENT_SENSITIVITY_SENSITIVE 3956 | CONTENT_SENSITIVITY_NOT_SENSITIVE) << PFLAG4_CONTENT_SENSITIVITY_SHIFT; 3957 3958 /** 3959 * Whether this view has been counted as a sensitive view or not. 3960 * 3961 * @see AttachInfo#mSensitiveViewsCount 3962 */ 3963 private static final int PFLAG4_IS_COUNTED_AS_SENSITIVE = 0x4000000; 3964 3965 /** 3966 * Whether this view has been drawn once with updateDisplayListIfDirty() or not. 3967 * Used by VRR to for quick detection of scrolling. 3968 */ 3969 private static final int PFLAG4_HAS_DRAWN = 0x8000000; 3970 3971 /** 3972 * Whether this view has been moved with either setTranslationX/Y or setLeft/Top. 3973 * Used by VRR to for quick detection of scrolling. 3974 */ 3975 private static final int PFLAG4_HAS_MOVED = 0x10000000; 3976 3977 /** 3978 * Whether the invalidateViewProperty is involked at current frame. 3979 */ 3980 private static final int PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION = 0x20000000; 3981 3982 /** 3983 * When set, this indicates whether the frame rate of the children should be 3984 * forcibly overridden, even if it has been explicitly configured by a user request. 3985 */ 3986 private static final int PFLAG4_FORCED_OVERRIDE_FRAME_RATE = 0x40000000; 3987 3988 /** 3989 * When set, this indicates that the frame rate is configured based on a user request. 3990 */ 3991 private static final int PFLAG4_SELF_REQUESTED_FRAME_RATE = 0x80000000; 3992 3993 /* End of masks for mPrivateFlags4 */ 3994 3995 /** @hide */ 3996 protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0; 3997 /** @hide */ 3998 protected static final int VIEW_STRUCTURE_FOR_AUTOFILL = 1; 3999 /** @hide */ 4000 protected static final int VIEW_STRUCTURE_FOR_CONTENT_CAPTURE = 2; 4001 4002 /** @hide */ 4003 @IntDef(flag = true, prefix = { "VIEW_STRUCTURE_FOR" }, value = { 4004 VIEW_STRUCTURE_FOR_ASSIST, 4005 VIEW_STRUCTURE_FOR_AUTOFILL, 4006 VIEW_STRUCTURE_FOR_CONTENT_CAPTURE 4007 }) 4008 @Retention(RetentionPolicy.SOURCE) 4009 public @interface ViewStructureType {} 4010 4011 /** 4012 * Always allow a user to over-scroll this view, provided it is a 4013 * view that can scroll. 4014 * 4015 * @see #getOverScrollMode() 4016 * @see #setOverScrollMode(int) 4017 */ 4018 public static final int OVER_SCROLL_ALWAYS = 0; 4019 4020 /** 4021 * Allow a user to over-scroll this view only if the content is large 4022 * enough to meaningfully scroll, provided it is a view that can scroll. 4023 * 4024 * @see #getOverScrollMode() 4025 * @see #setOverScrollMode(int) 4026 */ 4027 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 4028 4029 /** 4030 * Never allow a user to over-scroll this view. 4031 * 4032 * @see #getOverScrollMode() 4033 * @see #setOverScrollMode(int) 4034 */ 4035 public static final int OVER_SCROLL_NEVER = 2; 4036 4037 /** 4038 * Special constant for {@link #setSystemUiVisibility(int)}: View has 4039 * requested the system UI (status bar) to be visible (the default). 4040 * 4041 * @see #setSystemUiVisibility(int) 4042 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 4043 * instead. 4044 */ 4045 @Deprecated 4046 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 4047 4048 /** 4049 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 4050 * system UI to enter an unobtrusive "low profile" mode. 4051 * 4052 * <p>This is for use in games, book readers, video players, or any other 4053 * "immersive" application where the usual system chrome is deemed too distracting. 4054 * 4055 * <p>In low profile mode, the status bar and/or navigation icons may dim. 4056 * 4057 * @see #setSystemUiVisibility(int) 4058 * @deprecated Low profile mode is deprecated. Hide the system bars instead if the application 4059 * needs to be in a unobtrusive mode. Use {@link WindowInsetsController#hide(int)} with 4060 * {@link Type#systemBars()}. 4061 */ 4062 @Deprecated 4063 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 4064 4065 /** 4066 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 4067 * system navigation be temporarily hidden. 4068 * 4069 * <p>This is an even less obtrusive state than that called for by 4070 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 4071 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 4072 * those to disappear. This is useful (in conjunction with the 4073 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 4074 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 4075 * window flags) for displaying content using every last pixel on the display. 4076 * 4077 * <p>There is a limitation: because navigation controls are so important, the least user 4078 * interaction will cause them to reappear immediately. When this happens, both 4079 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 4080 * so that both elements reappear at the same time. 4081 * 4082 * @see #setSystemUiVisibility(int) 4083 * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#navigationBars()} 4084 * instead. 4085 */ 4086 @Deprecated 4087 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 4088 4089 /** 4090 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 4091 * into the normal fullscreen mode so that its content can take over the screen 4092 * while still allowing the user to interact with the application. 4093 * 4094 * <p>This has the same visual effect as 4095 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 4096 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 4097 * meaning that non-critical screen decorations (such as the status bar) will be 4098 * hidden while the user is in the View's window, focusing the experience on 4099 * that content. Unlike the window flag, if you are using ActionBar in 4100 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 4101 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 4102 * hide the action bar. 4103 * 4104 * <p>This approach to going fullscreen is best used over the window flag when 4105 * it is a transient state -- that is, the application does this at certain 4106 * points in its user interaction where it wants to allow the user to focus 4107 * on content, but not as a continuous state. For situations where the application 4108 * would like to simply stay full screen the entire time (such as a game that 4109 * wants to take over the screen), the 4110 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 4111 * is usually a better approach. The state set here will be removed by the system 4112 * in various situations (such as the user moving to another application) like 4113 * the other system UI states. 4114 * 4115 * <p>When using this flag, the application should provide some easy facility 4116 * for the user to go out of it. A common example would be in an e-book 4117 * reader, where tapping on the screen brings back whatever screen and UI 4118 * decorations that had been hidden while the user was immersed in reading 4119 * the book. 4120 * 4121 * @see #setSystemUiVisibility(int) 4122 * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#statusBars()} 4123 * instead. 4124 */ 4125 @Deprecated 4126 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 4127 4128 /** 4129 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 4130 * flags, we would like a stable view of the content insets given to 4131 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 4132 * will always represent the worst case that the application can expect 4133 * as a continuous state. In the stock Android UI this is the space for 4134 * the system bar, nav bar, and status bar, but not more transient elements 4135 * such as an input method. 4136 * 4137 * The stable layout your UI sees is based on the system UI modes you can 4138 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 4139 * then you will get a stable layout for changes of the 4140 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 4141 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 4142 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 4143 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 4144 * with a stable layout. (Note that you should avoid using 4145 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 4146 * 4147 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 4148 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 4149 * then a hidden status bar will be considered a "stable" state for purposes 4150 * here. This allows your UI to continually hide the status bar, while still 4151 * using the system UI flags to hide the action bar while still retaining 4152 * a stable layout. Note that changing the window fullscreen flag will never 4153 * provide a stable layout for a clean transition. 4154 * 4155 * <p>If you are using ActionBar in 4156 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 4157 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 4158 * insets it adds to those given to the application. 4159 * 4160 * @deprecated Use {@link WindowInsets#getInsetsIgnoringVisibility(int)} instead to retrieve 4161 * insets that don't change when system bars change visibility state. 4162 */ 4163 @Deprecated 4164 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 4165 4166 /** 4167 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 4168 * to be laid out as if it has requested 4169 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 4170 * allows it to avoid artifacts when switching in and out of that mode, at 4171 * the expense that some of its user interface may be covered by screen 4172 * decorations when they are shown. You can perform layout of your inner 4173 * UI elements to account for the navigation system UI through the 4174 * {@link #fitSystemWindows(Rect)} method. 4175 * 4176 * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with 4177 * {@link Type#navigationBars()}. For non-floating windows that fill the screen, call 4178 * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. 4179 */ 4180 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 4181 4182 /** 4183 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 4184 * to be laid out as if it has requested 4185 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 4186 * allows it to avoid artifacts when switching in and out of that mode, at 4187 * the expense that some of its user interface may be covered by screen 4188 * decorations when they are shown. You can perform layout of your inner 4189 * UI elements to account for non-fullscreen system UI through the 4190 * {@link #fitSystemWindows(Rect)} method. 4191 * 4192 * <p>Note: on displays that have a {@link DisplayCutout}, the window may still be placed 4193 * differently than if {@link #SYSTEM_UI_FLAG_FULLSCREEN} was set, if the 4194 * window's {@link WindowManager.LayoutParams#layoutInDisplayCutoutMode 4195 * layoutInDisplayCutoutMode} is 4196 * {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 4197 * LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT}. To avoid this, use either of the other modes. 4198 * 4199 * @see WindowManager.LayoutParams#layoutInDisplayCutoutMode 4200 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 4201 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 4202 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 4203 * 4204 * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with 4205 * {@link Type#statusBars()} ()}. For non-floating windows that fill the screen, call 4206 * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. 4207 */ 4208 @Deprecated 4209 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 4210 4211 /** 4212 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 4213 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 4214 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 4215 * user interaction. 4216 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 4217 * has an effect when used in combination with that flag.</p> 4218 * 4219 * @deprecated Use {@link WindowInsetsController#BEHAVIOR_DEFAULT} instead. 4220 */ 4221 @Deprecated 4222 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 4223 4224 /** 4225 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 4226 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 4227 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 4228 * experience while also hiding the system bars. If this flag is not set, 4229 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 4230 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 4231 * if the user swipes from the top of the screen. 4232 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 4233 * system gestures, such as swiping from the top of the screen. These transient system bars 4234 * will overlay app's content, may have some degree of transparency, and will automatically 4235 * hide after a short timeout. 4236 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 4237 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 4238 * with one or both of those flags.</p> 4239 * 4240 * @deprecated Use {@link WindowInsetsController#BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE} instead. 4241 */ 4242 @Deprecated 4243 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 4244 4245 /** 4246 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 4247 * is compatible with light status bar backgrounds. 4248 * 4249 * <p>For this to take effect, the window must request 4250 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 4251 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 4252 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 4253 * FLAG_TRANSLUCENT_STATUS}. 4254 * 4255 * @see android.R.attr#windowLightStatusBar 4256 * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_STATUS_BARS} instead. 4257 */ 4258 @Deprecated 4259 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 4260 4261 /** 4262 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 4263 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 4264 */ 4265 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 4266 4267 /** 4268 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 4269 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 4270 */ 4271 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 4272 4273 /** 4274 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 4275 * that is compatible with light navigation bar backgrounds. 4276 * 4277 * <p>For this to take effect, the window must request 4278 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 4279 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 4280 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 4281 * FLAG_TRANSLUCENT_NAVIGATION}. 4282 * 4283 * @see android.R.attr#windowLightNavigationBar 4284 * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_NAVIGATION_BARS} instead. 4285 */ 4286 @Deprecated 4287 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 4288 4289 /** 4290 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 4291 */ 4292 @Deprecated 4293 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 4294 4295 /** 4296 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 4297 */ 4298 @Deprecated 4299 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 4300 4301 /** 4302 * @hide 4303 * 4304 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4305 * out of the public fields to keep the undefined bits out of the developer's way. 4306 * 4307 * Flag to make the status bar not expandable. Unless you also 4308 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 4309 */ 4310 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4311 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 4312 4313 /** 4314 * @hide 4315 * 4316 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4317 * out of the public fields to keep the undefined bits out of the developer's way. 4318 * 4319 * Flag to hide notification icons and scrolling ticker text. 4320 */ 4321 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 4322 4323 /** 4324 * @hide 4325 * 4326 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4327 * out of the public fields to keep the undefined bits out of the developer's way. 4328 * 4329 * Flag to disable incoming notification alerts. This will not block 4330 * icons, but it will block sound, vibrating and other visual or aural notifications. 4331 */ 4332 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 4333 4334 /** 4335 * @hide 4336 * 4337 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4338 * out of the public fields to keep the undefined bits out of the developer's way. 4339 * 4340 * Flag to hide only the scrolling ticker. Note that 4341 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 4342 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 4343 */ 4344 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 4345 4346 /** 4347 * @hide 4348 * 4349 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4350 * out of the public fields to keep the undefined bits out of the developer's way. 4351 * 4352 * Flag to hide the center system info area. 4353 */ 4354 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 4355 4356 /** 4357 * @hide 4358 * 4359 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4360 * out of the public fields to keep the undefined bits out of the developer's way. 4361 * 4362 * Flag to hide only the home button. Don't use this 4363 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4364 */ 4365 @UnsupportedAppUsage 4366 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 4367 4368 /** 4369 * @hide 4370 * 4371 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4372 * out of the public fields to keep the undefined bits out of the developer's way. 4373 * 4374 * Flag to hide only the back button. Don't use this 4375 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4376 */ 4377 @UnsupportedAppUsage 4378 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 4379 4380 /** 4381 * @hide 4382 * 4383 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4384 * out of the public fields to keep the undefined bits out of the developer's way. 4385 * 4386 * Flag to hide only the clock. You might use this if your activity has 4387 * its own clock making the status bar's clock redundant. 4388 */ 4389 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 4390 4391 /** 4392 * @hide 4393 * 4394 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4395 * out of the public fields to keep the undefined bits out of the developer's way. 4396 * 4397 * Flag to hide only the recent apps button. Don't use this 4398 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4399 */ 4400 @UnsupportedAppUsage 4401 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 4402 4403 /** 4404 * @hide 4405 * 4406 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4407 * out of the public fields to keep the undefined bits out of the developer's way. 4408 * 4409 * Flag to disable the global search gesture. Don't use this 4410 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4411 */ 4412 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 4413 4414 /** 4415 * @hide 4416 * 4417 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4418 * out of the public fields to keep the undefined bits out of the developer's way. 4419 * 4420 * Flag to disable the ongoing call chip. 4421 */ 4422 public static final int STATUS_BAR_DISABLE_ONGOING_CALL_CHIP = 0x04000000; 4423 4424 /** 4425 * @hide 4426 */ 4427 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 4428 4429 /** 4430 * These are the system UI flags that can be cleared by events outside 4431 * of an application. Currently this is just the ability to tap on the 4432 * screen while hiding the navigation bar to have it return. 4433 * @hide 4434 */ 4435 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 4436 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 4437 | SYSTEM_UI_FLAG_FULLSCREEN; 4438 4439 /** 4440 * Flags that can impact the layout in relation to system UI. 4441 * 4442 * @deprecated System UI layout flags are deprecated. 4443 */ 4444 @Deprecated 4445 public static final int SYSTEM_UI_LAYOUT_FLAGS = 4446 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 4447 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 4448 4449 /** @hide */ 4450 @IntDef(flag = true, prefix = { "FIND_VIEWS_" }, value = { 4451 FIND_VIEWS_WITH_TEXT, 4452 FIND_VIEWS_WITH_CONTENT_DESCRIPTION 4453 }) 4454 @Retention(RetentionPolicy.SOURCE) 4455 public @interface FindViewFlags {} 4456 4457 /** 4458 * Find views that render the specified text. 4459 * 4460 * @see #findViewsWithText(ArrayList, CharSequence, int) 4461 */ 4462 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 4463 4464 /** 4465 * Find find views that contain the specified content description. 4466 * 4467 * @see #findViewsWithText(ArrayList, CharSequence, int) 4468 */ 4469 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 4470 4471 /** 4472 * Find views that contain {@link AccessibilityNodeProvider}. Such 4473 * a View is a root of virtual view hierarchy and may contain the searched 4474 * text. If this flag is set Views with providers are automatically 4475 * added and it is a responsibility of the client to call the APIs of 4476 * the provider to determine whether the virtual tree rooted at this View 4477 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 4478 * representing the virtual views with this text. 4479 * 4480 * @see #findViewsWithText(ArrayList, CharSequence, int) 4481 * 4482 * @hide 4483 */ 4484 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 4485 4486 /** 4487 * The undefined cursor position. 4488 * 4489 * @hide 4490 */ 4491 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 4492 4493 /** 4494 * Indicates that the screen has changed state and is now off. 4495 * 4496 * @see #onScreenStateChanged(int) 4497 */ 4498 public static final int SCREEN_STATE_OFF = 0x0; 4499 4500 /** 4501 * Indicates that the screen has changed state and is now on. 4502 * 4503 * @see #onScreenStateChanged(int) 4504 */ 4505 public static final int SCREEN_STATE_ON = 0x1; 4506 4507 /** 4508 * Indicates no axis of view scrolling. 4509 */ 4510 public static final int SCROLL_AXIS_NONE = 0; 4511 4512 /** 4513 * Indicates scrolling along the horizontal axis. 4514 */ 4515 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 4516 4517 /** 4518 * Indicates scrolling along the vertical axis. 4519 */ 4520 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 4521 4522 /** 4523 * Controls the over-scroll mode for this view. 4524 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 4525 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 4526 * and {@link #OVER_SCROLL_NEVER}. 4527 */ 4528 private int mOverScrollMode; 4529 4530 /** 4531 * The parent this view is attached to. 4532 * {@hide} 4533 * 4534 * @see #getParent() 4535 */ 4536 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4537 protected ViewParent mParent; 4538 4539 /** 4540 * {@hide} 4541 * 4542 * Not available for general use. If you need help, hang up and then dial one of the following 4543 * public APIs: 4544 * 4545 * @see #isAttachedToWindow() for current attach state 4546 * @see #onAttachedToWindow() for subclasses performing work when becoming attached 4547 * @see #onDetachedFromWindow() for subclasses performing work when becoming detached 4548 * @see OnAttachStateChangeListener for other code performing work on attach/detach 4549 * @see #getHandler() for posting messages to this view's UI thread/looper 4550 * @see #getParent() for interacting with the parent chain 4551 * @see #getWindowToken() for the current window token 4552 * @see #getRootView() for the view at the root of the attached hierarchy 4553 * @see #getDisplay() for the Display this view is presented on 4554 * @see #getRootWindowInsets() for the current insets applied to the whole attached window 4555 * @see #hasWindowFocus() for whether the attached window is currently focused 4556 * @see #getWindowVisibility() for checking the visibility of the attached window 4557 */ 4558 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4559 AttachInfo mAttachInfo; 4560 4561 /** 4562 * {@hide} 4563 */ 4564 @ViewDebug.ExportedProperty(flagMapping = { 4565 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 4566 name = "FORCE_LAYOUT"), 4567 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 4568 name = "LAYOUT_REQUIRED"), 4569 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 4570 name = "DRAWING_CACHE_INVALID", outputIf = false), 4571 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 4572 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 4573 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 4574 }, formatToHexString = true) 4575 4576 /* @hide */ 4577 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769414) 4578 public int mPrivateFlags; 4579 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768943) 4580 int mPrivateFlags2; 4581 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 129147060) 4582 int mPrivateFlags3; 4583 4584 private int mPrivateFlags4; 4585 4586 /** 4587 * This view's request for the visibility of the status bar. 4588 * @hide 4589 */ 4590 @ViewDebug.ExportedProperty(flagMapping = { 4591 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 4592 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 4593 name = "LOW_PROFILE"), 4594 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4595 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4596 name = "HIDE_NAVIGATION"), 4597 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_FULLSCREEN, 4598 equals = SYSTEM_UI_FLAG_FULLSCREEN, 4599 name = "FULLSCREEN"), 4600 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4601 equals = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4602 name = "LAYOUT_STABLE"), 4603 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4604 equals = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4605 name = "LAYOUT_HIDE_NAVIGATION"), 4606 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4607 equals = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4608 name = "LAYOUT_FULLSCREEN"), 4609 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE, 4610 equals = SYSTEM_UI_FLAG_IMMERSIVE, 4611 name = "IMMERSIVE"), 4612 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4613 equals = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4614 name = "IMMERSIVE_STICKY"), 4615 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4616 equals = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4617 name = "LIGHT_STATUS_BAR"), 4618 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4619 equals = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4620 name = "LIGHT_NAVIGATION_BAR"), 4621 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_EXPAND, 4622 equals = STATUS_BAR_DISABLE_EXPAND, 4623 name = "STATUS_BAR_DISABLE_EXPAND"), 4624 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4625 equals = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4626 name = "STATUS_BAR_DISABLE_NOTIFICATION_ICONS"), 4627 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4628 equals = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4629 name = "STATUS_BAR_DISABLE_NOTIFICATION_ALERTS"), 4630 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4631 equals = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4632 name = "STATUS_BAR_DISABLE_NOTIFICATION_TICKER"), 4633 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SYSTEM_INFO, 4634 equals = STATUS_BAR_DISABLE_SYSTEM_INFO, 4635 name = "STATUS_BAR_DISABLE_SYSTEM_INFO"), 4636 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_HOME, 4637 equals = STATUS_BAR_DISABLE_HOME, 4638 name = "STATUS_BAR_DISABLE_HOME"), 4639 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_BACK, 4640 equals = STATUS_BAR_DISABLE_BACK, 4641 name = "STATUS_BAR_DISABLE_BACK"), 4642 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_CLOCK, 4643 equals = STATUS_BAR_DISABLE_CLOCK, 4644 name = "STATUS_BAR_DISABLE_CLOCK"), 4645 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_RECENT, 4646 equals = STATUS_BAR_DISABLE_RECENT, 4647 name = "STATUS_BAR_DISABLE_RECENT"), 4648 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH, 4649 equals = STATUS_BAR_DISABLE_SEARCH, 4650 name = "STATUS_BAR_DISABLE_SEARCH"), 4651 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4652 equals = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4653 name = "STATUS_BAR_DISABLE_ONGOING_CALL_CHIP") 4654 }, formatToHexString = true) 4655 @SystemUiVisibility 4656 int mSystemUiVisibility; 4657 4658 /** 4659 * @hide 4660 */ 4661 @IntDef(flag = true, prefix = "", value = { 4662 SYSTEM_UI_FLAG_LOW_PROFILE, 4663 SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4664 SYSTEM_UI_FLAG_FULLSCREEN, 4665 SYSTEM_UI_FLAG_LAYOUT_STABLE, 4666 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4667 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4668 SYSTEM_UI_FLAG_IMMERSIVE, 4669 SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4670 SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4671 SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4672 STATUS_BAR_DISABLE_EXPAND, 4673 STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4674 STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4675 STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4676 STATUS_BAR_DISABLE_SYSTEM_INFO, 4677 STATUS_BAR_DISABLE_HOME, 4678 STATUS_BAR_DISABLE_BACK, 4679 STATUS_BAR_DISABLE_CLOCK, 4680 STATUS_BAR_DISABLE_RECENT, 4681 STATUS_BAR_DISABLE_SEARCH, 4682 STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4683 }) 4684 @Retention(RetentionPolicy.SOURCE) 4685 public @interface SystemUiVisibility {} 4686 4687 /** 4688 * Reference count for transient state. 4689 * @see #setHasTransientState(boolean) 4690 */ 4691 int mTransientStateCount = 0; 4692 4693 /** 4694 * Count of how many windows this view has been attached to. 4695 */ 4696 int mWindowAttachCount; 4697 4698 /** 4699 * The layout parameters associated with this view and used by the parent 4700 * {@link android.view.ViewGroup} to determine how this view should be 4701 * laid out. 4702 * 4703 * The field should not be used directly. Instead {@link #getLayoutParams()} and {@link 4704 * #setLayoutParams(ViewGroup.LayoutParams)} should be used. The setter guarantees internal 4705 * state correctness of the class. 4706 * {@hide} 4707 */ 4708 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4709 protected ViewGroup.LayoutParams mLayoutParams; 4710 4711 /** 4712 * The view flags hold various views states. 4713 * 4714 * Use {@link #setTransitionVisibility(int)} to change the visibility of this view without 4715 * triggering updates. 4716 * {@hide} 4717 */ 4718 @ViewDebug.ExportedProperty(formatToHexString = true) 4719 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4720 int mViewFlags; 4721 4722 static class TransformationInfo { 4723 /** 4724 * The transform matrix for the View. This transform is calculated internally 4725 * based on the translation, rotation, and scale properties. 4726 * 4727 * Do *not* use this variable directly; instead call getMatrix(), which will 4728 * load the value from the View's RenderNode. 4729 */ 4730 private final Matrix mMatrix = new Matrix(); 4731 4732 /** 4733 * The inverse transform matrix for the View. This transform is calculated 4734 * internally based on the translation, rotation, and scale properties. 4735 * 4736 * Do *not* use this variable directly; instead call getInverseMatrix(), 4737 * which will load the value from the View's RenderNode. 4738 */ 4739 private Matrix mInverseMatrix; 4740 4741 /** 4742 * The opacity of the View. This is a value from 0 to 1, where 0 means 4743 * completely transparent and 1 means completely opaque. 4744 */ 4745 @ViewDebug.ExportedProperty 4746 private float mAlpha = 1f; 4747 4748 /** 4749 * The opacity of the view as manipulated by the Fade transition. This is a 4750 * property only used by transitions, which is composited with the other alpha 4751 * values to calculate the final visual alpha value. 4752 */ 4753 float mTransitionAlpha = 1f; 4754 } 4755 4756 /** @hide */ 4757 @UnsupportedAppUsage 4758 public TransformationInfo mTransformationInfo; 4759 4760 /** 4761 * Current clip bounds. to which all drawing of this view are constrained. 4762 */ 4763 @ViewDebug.ExportedProperty(category = "drawing") 4764 Rect mClipBounds = null; 4765 4766 private boolean mLastIsOpaque; 4767 4768 /** 4769 * The distance in pixels from the left edge of this view's parent 4770 * to the left edge of this view. 4771 * {@hide} 4772 */ 4773 @ViewDebug.ExportedProperty(category = "layout") 4774 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4775 protected int mLeft; 4776 /** 4777 * The mLeft from the previous frame. Used for detecting movement for purposes of variable 4778 * refresh rate. 4779 */ 4780 private int mLastFrameLeft; 4781 /** 4782 * The distance in pixels from the left edge of this view's parent 4783 * to the right edge of this view. 4784 * {@hide} 4785 */ 4786 @ViewDebug.ExportedProperty(category = "layout") 4787 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4788 protected int mRight; 4789 /** 4790 * The distance in pixels from the top edge of this view's parent 4791 * to the top edge of this view. 4792 * {@hide} 4793 */ 4794 @ViewDebug.ExportedProperty(category = "layout") 4795 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4796 protected int mTop; 4797 /** 4798 * The mTop from the previous frame. Used for detecting movement for purposes of variable 4799 * refresh rate. 4800 */ 4801 private int mLastFrameTop; 4802 /** 4803 * The distance in pixels from the top edge of this view's parent 4804 * to the bottom edge of this view. 4805 * {@hide} 4806 */ 4807 @ViewDebug.ExportedProperty(category = "layout") 4808 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4809 protected int mBottom; 4810 4811 /** 4812 * The offset, in pixels, by which the content of this view is scrolled 4813 * horizontally. 4814 * Please use {@link View#getScrollX()} and {@link View#setScrollX(int)} instead of 4815 * accessing these directly. 4816 * {@hide} 4817 */ 4818 @ViewDebug.ExportedProperty(category = "scrolling") 4819 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4820 protected int mScrollX; 4821 /** 4822 * The offset, in pixels, by which the content of this view is scrolled 4823 * vertically. 4824 * Please use {@link View#getScrollY()} and {@link View#setScrollY(int)} instead of 4825 * accessing these directly. 4826 * {@hide} 4827 */ 4828 @ViewDebug.ExportedProperty(category = "scrolling") 4829 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4830 protected int mScrollY; 4831 4832 /** 4833 * The final computed left padding in pixels that is used for drawing. This is the distance in 4834 * pixels between the left edge of this view and the left edge of its content. 4835 * {@hide} 4836 */ 4837 @ViewDebug.ExportedProperty(category = "padding") 4838 @UnsupportedAppUsage 4839 protected int mPaddingLeft = 0; 4840 /** 4841 * The final computed right padding in pixels that is used for drawing. This is the distance in 4842 * pixels between the right edge of this view and the right edge of its content. 4843 * {@hide} 4844 */ 4845 @ViewDebug.ExportedProperty(category = "padding") 4846 @UnsupportedAppUsage 4847 protected int mPaddingRight = 0; 4848 /** 4849 * The final computed top padding in pixels that is used for drawing. This is the distance in 4850 * pixels between the top edge of this view and the top edge of its content. 4851 * {@hide} 4852 */ 4853 @ViewDebug.ExportedProperty(category = "padding") 4854 @UnsupportedAppUsage 4855 protected int mPaddingTop; 4856 /** 4857 * The final computed bottom padding in pixels that is used for drawing. This is the distance in 4858 * pixels between the bottom edge of this view and the bottom edge of its content. 4859 * {@hide} 4860 */ 4861 @ViewDebug.ExportedProperty(category = "padding") 4862 @UnsupportedAppUsage 4863 protected int mPaddingBottom; 4864 4865 /** 4866 * The amount of pixel offset applied to the left edge of this view's handwriting bounds. 4867 */ 4868 private float mHandwritingBoundsOffsetLeft; 4869 4870 /** 4871 * The amount of pixel offset applied to the top edge of this view's handwriting bounds. 4872 */ 4873 private float mHandwritingBoundsOffsetTop; 4874 4875 /** 4876 * The amount of pixel offset applied to the right edge of this view's handwriting bounds. 4877 */ 4878 private float mHandwritingBoundsOffsetRight; 4879 4880 /** 4881 * The amount of pixel offset applied to the bottom edge of this view's handwriting bounds. 4882 */ 4883 private float mHandwritingBoundsOffsetBottom; 4884 4885 /** 4886 * The layout insets in pixels, that is the distance in pixels between the 4887 * visible edges of this view its bounds. 4888 */ 4889 private Insets mLayoutInsets; 4890 4891 /** 4892 * Briefly describes the state of the view and is primarily used for accessibility support. 4893 */ 4894 private CharSequence mStateDescription; 4895 4896 /** 4897 * Briefly describes the view and is primarily used for accessibility support. 4898 */ 4899 private CharSequence mContentDescription; 4900 4901 /** 4902 * Brief supplemental information for view and is primarily used for accessibility support. 4903 */ 4904 private CharSequence mSupplementalDescription; 4905 4906 /** 4907 * If this view represents a distinct part of the window, it can have a title that labels the 4908 * area. 4909 */ 4910 private CharSequence mAccessibilityPaneTitle; 4911 4912 /** 4913 * Describes whether this view should only allow interactions from 4914 * {@link android.accessibilityservice.AccessibilityService}s with the 4915 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property 4916 * set to true. 4917 */ 4918 private int mExplicitAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_AUTO; 4919 /** Used to calculate and cache {@link #isAccessibilityDataSensitive()}. */ 4920 private int mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_AUTO; 4921 4922 /** 4923 * Specifies the id of a view for which this view serves as a label for 4924 * accessibility purposes. 4925 */ 4926 private int mLabelForId = View.NO_ID; 4927 4928 /** 4929 * Predicate for matching labeled view id with its label for 4930 * accessibility purposes. 4931 */ 4932 private MatchLabelForPredicate mMatchLabelForPredicate; 4933 4934 /** 4935 * Specifies a view before which this one is visited in accessibility traversal. 4936 */ 4937 private int mAccessibilityTraversalBeforeId = NO_ID; 4938 4939 /** 4940 * Specifies a view after which this one is visited in accessibility traversal. 4941 */ 4942 private int mAccessibilityTraversalAfterId = NO_ID; 4943 4944 /** 4945 * Predicate for matching a view by its id. 4946 */ 4947 private MatchIdPredicate mMatchIdPredicate; 4948 4949 /** 4950 * The right padding after RTL resolution, but before taking account of scroll bars. 4951 * 4952 * @hide 4953 */ 4954 @ViewDebug.ExportedProperty(category = "padding") 4955 protected int mUserPaddingRight; 4956 4957 /** 4958 * The resolved bottom padding before taking account of scroll bars. 4959 * 4960 * @hide 4961 */ 4962 @ViewDebug.ExportedProperty(category = "padding") 4963 protected int mUserPaddingBottom; 4964 4965 /** 4966 * The left padding after RTL resolution, but before taking account of scroll bars. 4967 * 4968 * @hide 4969 */ 4970 @ViewDebug.ExportedProperty(category = "padding") 4971 protected int mUserPaddingLeft; 4972 4973 /** 4974 * Cache the paddingStart set by the user to append to the scrollbar's size. 4975 * 4976 */ 4977 @ViewDebug.ExportedProperty(category = "padding") 4978 int mUserPaddingStart; 4979 4980 /** 4981 * Cache the paddingEnd set by the user to append to the scrollbar's size. 4982 * 4983 */ 4984 @ViewDebug.ExportedProperty(category = "padding") 4985 int mUserPaddingEnd; 4986 4987 /** 4988 * The left padding as set by a setter method, a background's padding, or via XML property 4989 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4990 * 4991 * @hide 4992 */ 4993 int mUserPaddingLeftInitial; 4994 4995 /** 4996 * The right padding as set by a setter method, a background's padding, or via XML property 4997 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4998 * 4999 * @hide 5000 */ 5001 int mUserPaddingRightInitial; 5002 5003 /** 5004 * Default undefined padding 5005 */ 5006 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 5007 5008 /** 5009 * Cache if a left padding has been defined explicitly via padding, horizontal padding, 5010 * or leftPadding in XML, or by setPadding(...) or setRelativePadding(...) 5011 */ 5012 private boolean mLeftPaddingDefined = false; 5013 5014 /** 5015 * Cache if a right padding has been defined explicitly via padding, horizontal padding, 5016 * or rightPadding in XML, or by setPadding(...) or setRelativePadding(...) 5017 */ 5018 private boolean mRightPaddingDefined = false; 5019 5020 /** 5021 * @hide 5022 */ 5023 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 5024 /** 5025 * @hide 5026 */ 5027 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 5028 5029 private LongSparseLongArray mMeasureCache; 5030 5031 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 5032 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 5033 private Drawable mBackground; 5034 private TintInfo mBackgroundTint; 5035 5036 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 5037 private ForegroundInfo mForegroundInfo; 5038 5039 private Drawable mScrollIndicatorDrawable; 5040 5041 /** 5042 * RenderNode used for backgrounds. 5043 * <p> 5044 * When non-null and valid, this is expected to contain an up-to-date copy 5045 * of the background drawable. It is cleared on temporary detach, and reset 5046 * on cleanup. 5047 * @hide 5048 */ 5049 RenderNode mBackgroundRenderNode; 5050 5051 @UnsupportedAppUsage 5052 private int mBackgroundResource; 5053 private boolean mBackgroundSizeChanged; 5054 5055 /** The default focus highlight. 5056 * @see #mDefaultFocusHighlightEnabled 5057 * @see Drawable#hasFocusStateSpecified() 5058 */ 5059 private Drawable mDefaultFocusHighlight; 5060 private Drawable mDefaultFocusHighlightCache; 5061 private boolean mDefaultFocusHighlightSizeChanged; 5062 /** 5063 * True if the default focus highlight is needed on the target device. 5064 */ 5065 private static boolean sUseDefaultFocusHighlight; 5066 5067 /** 5068 * True if zero-sized views can be focused. 5069 */ 5070 private static boolean sCanFocusZeroSized; 5071 5072 /** 5073 * Always assign focus if a focusable View is available. 5074 */ 5075 private static boolean sAlwaysAssignFocus; 5076 5077 private String mTransitionName; 5078 5079 static class TintInfo { 5080 ColorStateList mTintList; 5081 BlendMode mBlendMode; 5082 boolean mHasTintMode; 5083 boolean mHasTintList; 5084 } 5085 5086 private static class ForegroundInfo { 5087 private Drawable mDrawable; 5088 private TintInfo mTintInfo; 5089 private int mGravity = Gravity.FILL; 5090 private boolean mInsidePadding = true; 5091 private boolean mBoundsChanged = true; 5092 private final Rect mSelfBounds = new Rect(); 5093 private final Rect mOverlayBounds = new Rect(); 5094 } 5095 5096 static class ListenerInfo { 5097 5098 @UnsupportedAppUsage ListenerInfo()5099 ListenerInfo() { 5100 } 5101 5102 /** 5103 * Listener used to dispatch focus change events. 5104 * This field should be made private, so it is hidden from the SDK. 5105 * {@hide} 5106 */ 5107 @UnsupportedAppUsage 5108 protected OnFocusChangeListener mOnFocusChangeListener; 5109 5110 /** 5111 * Listeners for layout change events. 5112 */ 5113 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 5114 5115 protected OnScrollChangeListener mOnScrollChangeListener; 5116 5117 /** 5118 * Listeners for attach events. 5119 */ 5120 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 5121 5122 /** 5123 * Listener used to dispatch click events. 5124 * This field should be made private, so it is hidden from the SDK. 5125 * {@hide} 5126 */ 5127 @UnsupportedAppUsage 5128 public OnClickListener mOnClickListener; 5129 5130 /** 5131 * Listener used to dispatch long click events. 5132 * This field should be made private, so it is hidden from the SDK. 5133 * {@hide} 5134 */ 5135 @UnsupportedAppUsage 5136 protected OnLongClickListener mOnLongClickListener; 5137 5138 /** 5139 * Listener used to dispatch context click events. This field should be made private, so it 5140 * is hidden from the SDK. 5141 * {@hide} 5142 */ 5143 protected OnContextClickListener mOnContextClickListener; 5144 5145 /** 5146 * Listener used to build the context menu. 5147 * This field should be made private, so it is hidden from the SDK. 5148 * {@hide} 5149 */ 5150 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 5151 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 5152 5153 @UnsupportedAppUsage 5154 private OnKeyListener mOnKeyListener; 5155 5156 @UnsupportedAppUsage 5157 private OnTouchListener mOnTouchListener; 5158 5159 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 5160 private OnHoverListener mOnHoverListener; 5161 5162 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 5163 private OnGenericMotionListener mOnGenericMotionListener; 5164 5165 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 5166 private OnDragListener mOnDragListener; 5167 5168 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 5169 5170 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 5171 5172 OnCapturedPointerListener mOnCapturedPointerListener; 5173 5174 private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners; 5175 5176 WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback; 5177 5178 /** 5179 * This lives here since it's only valid for interactive views. This list is null 5180 * until its first use. 5181 */ 5182 private ArrayList<Rect> mSystemGestureExclusionRects = null; 5183 private ArrayList<Rect> mKeepClearRects = null; 5184 private ArrayList<Rect> mUnrestrictedKeepClearRects = null; 5185 private boolean mPreferKeepClear = false; 5186 private Rect mHandwritingArea = null; 5187 5188 /** 5189 * Used to track {@link #mSystemGestureExclusionRects}, {@link #mKeepClearRects} and 5190 * {@link #mHandwritingArea}. 5191 */ 5192 public RenderNode.PositionUpdateListener mPositionUpdateListener; 5193 private Runnable mPositionChangedUpdate; 5194 5195 /** 5196 * Allows the application to implement custom scroll capture support. 5197 */ 5198 ScrollCaptureCallback mScrollCaptureCallback; 5199 5200 @Nullable 5201 private OnReceiveContentListener mOnReceiveContentListener; 5202 } 5203 5204 @UnsupportedAppUsage 5205 ListenerInfo mListenerInfo; 5206 5207 private static class TooltipInfo { 5208 /** 5209 * Text to be displayed in a tooltip popup. 5210 */ 5211 @Nullable 5212 CharSequence mTooltipText; 5213 5214 /** 5215 * View-relative position of the tooltip anchor point. 5216 */ 5217 int mAnchorX; 5218 int mAnchorY; 5219 5220 /** 5221 * The tooltip popup. 5222 */ 5223 @Nullable 5224 TooltipPopup mTooltipPopup; 5225 5226 /** 5227 * Set to true if the tooltip was shown as a result of a long click. 5228 */ 5229 boolean mTooltipFromLongClick; 5230 5231 /** 5232 * Keep these Runnables so that they can be used to reschedule. 5233 */ 5234 Runnable mShowTooltipRunnable; 5235 Runnable mHideTooltipRunnable; 5236 5237 /** 5238 * Hover move is ignored if it is within this distance in pixels from the previous one. 5239 */ 5240 int mHoverSlop; 5241 5242 /** 5243 * Update the anchor position if it significantly (that is by at least mHoverSlop) 5244 * different from the previously stored position. Ignoring insignificant changes 5245 * filters out the jitter which is typical for such input sources as stylus. 5246 * 5247 * @return True if the position has been updated. 5248 */ updateAnchorPos(MotionEvent event)5249 private boolean updateAnchorPos(MotionEvent event) { 5250 final int newAnchorX = (int) event.getX(); 5251 final int newAnchorY = (int) event.getY(); 5252 if (Math.abs(newAnchorX - mAnchorX) <= mHoverSlop 5253 && Math.abs(newAnchorY - mAnchorY) <= mHoverSlop) { 5254 return false; 5255 } 5256 mAnchorX = newAnchorX; 5257 mAnchorY = newAnchorY; 5258 return true; 5259 } 5260 5261 /** 5262 * Clear the anchor position to ensure that the next change is considered significant. 5263 */ clearAnchorPos()5264 private void clearAnchorPos() { 5265 mAnchorX = Integer.MAX_VALUE; 5266 mAnchorY = Integer.MAX_VALUE; 5267 } 5268 } 5269 5270 TooltipInfo mTooltipInfo; 5271 5272 // Temporary values used to hold (x,y) coordinates when delegating from the 5273 // two-arg performLongClick() method to the legacy no-arg version. 5274 private float mLongClickX = Float.NaN; 5275 private float mLongClickY = Float.NaN; 5276 5277 /** 5278 * The application environment this view lives in. 5279 * This field should be made private, so it is hidden from the SDK. 5280 * {@hide} 5281 */ 5282 @ViewDebug.ExportedProperty(deepExport = true) 5283 @UnsupportedAppUsage 5284 @UiContext 5285 protected Context mContext; 5286 5287 @UnsupportedAppUsage 5288 private final Resources mResources; 5289 5290 @UnsupportedAppUsage 5291 private ScrollabilityCache mScrollCache; 5292 5293 private int[] mDrawableState = null; 5294 5295 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 5296 5297 /** 5298 * Animator that automatically runs based on state changes. 5299 */ 5300 private StateListAnimator mStateListAnimator; 5301 5302 /** 5303 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 5304 * the user may specify which view to go to next. 5305 */ 5306 private int mNextFocusLeftId = View.NO_ID; 5307 5308 /** 5309 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 5310 * the user may specify which view to go to next. 5311 */ 5312 private int mNextFocusRightId = View.NO_ID; 5313 5314 /** 5315 * When this view has focus and the next focus is {@link #FOCUS_UP}, 5316 * the user may specify which view to go to next. 5317 */ 5318 private int mNextFocusUpId = View.NO_ID; 5319 5320 /** 5321 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 5322 * the user may specify which view to go to next. 5323 */ 5324 private int mNextFocusDownId = View.NO_ID; 5325 5326 /** 5327 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 5328 * the user may specify which view to go to next. 5329 */ 5330 int mNextFocusForwardId = View.NO_ID; 5331 5332 /** 5333 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction. 5334 * 5335 * @see #findUserSetNextKeyboardNavigationCluster(View, int) 5336 */ 5337 int mNextClusterForwardId = View.NO_ID; 5338 5339 /** 5340 * Whether this View should use a default focus highlight when it gets focused but doesn't 5341 * have {@link android.R.attr#state_focused} defined in its background. 5342 */ 5343 boolean mDefaultFocusHighlightEnabled = true; 5344 5345 private CheckForLongPress mPendingCheckForLongPress; 5346 @UnsupportedAppUsage 5347 private CheckForTap mPendingCheckForTap = null; 5348 private PerformClick mPerformClick; 5349 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 5350 private SendAccessibilityEventThrottle mSendStateChangedAccessibilityEvent; 5351 private UnsetPressedState mUnsetPressedState; 5352 5353 /** 5354 * Whether the long press's action has been invoked. The tap's action is invoked on the 5355 * up event while a long press is invoked as soon as the long press duration is reached, so 5356 * a long press could be performed before the tap is checked, in which case the tap's action 5357 * should not be invoked. 5358 */ 5359 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 5360 private boolean mHasPerformedLongPress; 5361 5362 /** 5363 * Whether a context click button is currently pressed down. This is true when the stylus is 5364 * touching the screen and the primary button has been pressed, or if a mouse's right button is 5365 * pressed. This is false once the button is released or if the stylus has been lifted. 5366 */ 5367 private boolean mInContextButtonPress; 5368 5369 /** 5370 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 5371 * true after a stylus button press has occured, when the next up event should not be recognized 5372 * as a tap. 5373 */ 5374 private boolean mIgnoreNextUpEvent; 5375 5376 /** 5377 * The minimum height of the view. We'll try our best to have the height 5378 * of this view to at least this amount. 5379 */ 5380 @ViewDebug.ExportedProperty(category = "measurement") 5381 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 5382 private int mMinHeight; 5383 5384 /** 5385 * The minimum width of the view. We'll try our best to have the width 5386 * of this view to at least this amount. 5387 */ 5388 @ViewDebug.ExportedProperty(category = "measurement") 5389 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 5390 private int mMinWidth; 5391 5392 /** 5393 * The delegate to handle touch events that are physically in this view 5394 * but should be handled by another view. 5395 */ 5396 private TouchDelegate mTouchDelegate = null; 5397 5398 /** 5399 * While touch exploration is in use, set to true when hovering across boundaries and 5400 * inside the touch area of the delegate at receiving {@link MotionEvent#ACTION_HOVER_ENTER} 5401 * or {@link MotionEvent#ACTION_HOVER_MOVE}. False when leaving boundaries or receiving a 5402 * {@link MotionEvent#ACTION_HOVER_EXIT}. 5403 * Note that children of view group are excluded in the touch area. 5404 * @see #dispatchTouchExplorationHoverEvent 5405 */ 5406 private boolean mHoveringTouchDelegate = false; 5407 5408 // These two fields are set if the view is a handwriting delegator. 5409 private Runnable mHandwritingDelegatorCallback; 5410 private String mAllowedHandwritingDelegatePackageName; 5411 5412 // These three fields are set if the view is a handwriting delegate. 5413 private boolean mIsHandwritingDelegate; 5414 private String mAllowedHandwritingDelegatorPackageName; 5415 private @InputMethodManager.HandwritingDelegateFlags int mHandwritingDelegateFlags; 5416 5417 /** 5418 * Solid color to use as a background when creating the drawing cache. Enables 5419 * the cache to use 16 bit bitmaps instead of 32 bit. 5420 */ 5421 private int mDrawingCacheBackgroundColor = 0; 5422 5423 /** 5424 * Special tree observer used when mAttachInfo is null. 5425 */ 5426 private ViewTreeObserver mFloatingTreeObserver; 5427 5428 /** 5429 * Cache the touch slop from the context that created the view. 5430 */ 5431 private int mTouchSlop; 5432 5433 /** 5434 * Cache the ambiguous gesture multiplier from the context that created the view. 5435 */ 5436 private float mAmbiguousGestureMultiplier; 5437 5438 /** 5439 * Object that handles automatic animation of view properties. 5440 */ 5441 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 5442 private ViewPropertyAnimator mAnimator = null; 5443 5444 /** 5445 * List of registered FrameMetricsObservers. 5446 */ 5447 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 5448 5449 /** 5450 * Flag indicating that a drag can cross window boundaries. When 5451 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 5452 * with this flag set, all visible applications with targetSdkVersion >= 5453 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 5454 * in the drag operation and receive the dragged content. 5455 * 5456 * <p>If this is the only flag set, then the drag recipient will only have access to text data 5457 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 5458 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 5459 */ 5460 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 5461 5462 /** 5463 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 5464 * request read access to the content URI(s) contained in the {@link ClipData} object. 5465 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION 5466 */ 5467 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 5468 5469 /** 5470 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 5471 * request write access to the content URI(s) contained in the {@link ClipData} object. 5472 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION 5473 */ 5474 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 5475 5476 /** 5477 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 5478 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 5479 * reboots until explicitly revoked with 5480 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}. 5481 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION 5482 */ 5483 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 5484 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 5485 5486 /** 5487 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 5488 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 5489 * match against the original granted URI. 5490 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION 5491 */ 5492 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 5493 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 5494 5495 /** 5496 * Flag indicating that the drag shadow will be opaque. When 5497 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 5498 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 5499 */ 5500 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 5501 5502 /** 5503 * Flag indicating that the drag was initiated with 5504 * {@link AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_START}. When 5505 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called, this 5506 * is used by the system to perform a drag without animations. 5507 */ 5508 public static final int DRAG_FLAG_ACCESSIBILITY_ACTION = 1 << 10; 5509 5510 /** 5511 * Flag indicating that the caller desires to take ownership of the drag surface for handling 5512 * the animation associated with an unhandled drag. It is mainly useful if the view starting 5513 * a global drag changes visibility during the gesture and the default animation of animating 5514 * the surface back to the origin is not sufficient. 5515 * 5516 * The calling app must hold the {@link android.Manifest.permission#START_TASKS_FROM_RECENTS} 5517 * permission and will receive the drag surface as a part of 5518 * {@link action.view.DragEvent#ACTION_DRAG_ENDED} only if the drag event's 5519 * {@link action.view.DragEvent#getDragResult()} is {@code false}. The caller is responsible 5520 * for removing the surface after its animation. 5521 * 5522 * This flag has no effect if the system decides that a cancel-drag animation does not need to 5523 * occur. 5524 * @hide 5525 */ 5526 public static final int DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION = 1 << 11; 5527 5528 /** 5529 * Flag indicating that a drag can cross window boundaries (within the same application). When 5530 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 5531 * with this flag set, only visible windows belonging to the same application (ie. share the 5532 * same UID) with targetSdkVersion >= {@link android.os.Build.VERSION_CODES#N API 24} will be 5533 * able to participate in the drag operation and receive the dragged content. 5534 * 5535 * If both DRAG_FLAG_GLOBAL_SAME_APPLICATION and DRAG_FLAG_GLOBAL are set, then 5536 * DRAG_FLAG_GLOBAL_SAME_APPLICATION takes precedence and the drag will only go to visible 5537 * windows from the same application. 5538 */ 5539 @FlaggedApi(FLAG_DELEGATE_UNHANDLED_DRAGS) 5540 public static final int DRAG_FLAG_GLOBAL_SAME_APPLICATION = 1 << 12; 5541 5542 /** 5543 * Flag indicating that an unhandled drag should be delegated to the system to be started if no 5544 * visible window wishes to handle the drop. When using this flag, the caller must provide 5545 * ClipData with an Item that contains an immutable IntentSender to an activity to be launched 5546 * (not a broadcast, service, etc). See 5547 * {@link ClipData.Item.Builder#setIntentSender(IntentSender)}. 5548 * 5549 * The system can decide to launch the intent or not based on factors like the current screen 5550 * size or windowing mode. If the system does not launch the intent, it will be canceled via the 5551 * normal drag and drop flow. 5552 */ 5553 @FlaggedApi(FLAG_DELEGATE_UNHANDLED_DRAGS) 5554 public static final int DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG = 1 << 13; 5555 5556 /** 5557 * Flag indicating that this drag will result in the caller activity's task to be hidden for the 5558 * duration of the drag, which means that the source activity will not receive drag events for 5559 * the current drag gesture. Only the current 5560 * {@link android.service.voice.VoiceInteractionService} may use this flag. 5561 */ 5562 @FlaggedApi(FLAG_SUPPORTS_DRAG_ASSISTANT_TO_MULTIWINDOW) 5563 public static final int DRAG_FLAG_HIDE_CALLING_TASK_ON_DRAG_START = 1 << 14; 5564 5565 /** 5566 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 5567 */ 5568 private float mVerticalScrollFactor; 5569 5570 /** 5571 * Position of the vertical scroll bar. 5572 */ 5573 @UnsupportedAppUsage 5574 private int mVerticalScrollbarPosition; 5575 5576 /** 5577 * Position the scroll bar at the default position as determined by the system. 5578 */ 5579 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 5580 5581 /** 5582 * Position the scroll bar along the left edge. 5583 */ 5584 public static final int SCROLLBAR_POSITION_LEFT = 1; 5585 5586 /** 5587 * Position the scroll bar along the right edge. 5588 */ 5589 public static final int SCROLLBAR_POSITION_RIGHT = 2; 5590 5591 /** 5592 * Indicates that the view does not have a layer. 5593 * 5594 * @see #getLayerType() 5595 * @see #setLayerType(int, android.graphics.Paint) 5596 * @see #LAYER_TYPE_SOFTWARE 5597 * @see #LAYER_TYPE_HARDWARE 5598 */ 5599 public static final int LAYER_TYPE_NONE = 0; 5600 5601 /** 5602 * <p>Indicates that the view has a software layer. A software layer is backed 5603 * by a bitmap and causes the view to be rendered using Android's software 5604 * rendering pipeline, even if hardware acceleration is enabled.</p> 5605 * 5606 * <p>Software layers have various usages:</p> 5607 * <p>When the application is not using hardware acceleration, a software layer 5608 * is useful to apply a specific color filter and/or blending mode and/or 5609 * translucency to a view and all its children.</p> 5610 * <p>When the application is using hardware acceleration, a software layer 5611 * is useful to render drawing primitives not supported by the hardware 5612 * accelerated pipeline. It can also be used to cache a complex view tree 5613 * into a texture and reduce the complexity of drawing operations. For instance, 5614 * when animating a complex view tree with a translation, a software layer can 5615 * be used to render the view tree only once.</p> 5616 * <p>Software layers should be avoided when the affected view tree updates 5617 * often. Every update will require to re-render the software layer, which can 5618 * potentially be slow (particularly when hardware acceleration is turned on 5619 * since the layer will have to be uploaded into a hardware texture after every 5620 * update.)</p> 5621 * 5622 * @see #getLayerType() 5623 * @see #setLayerType(int, android.graphics.Paint) 5624 * @see #LAYER_TYPE_NONE 5625 * @see #LAYER_TYPE_HARDWARE 5626 */ 5627 public static final int LAYER_TYPE_SOFTWARE = 1; 5628 5629 /** 5630 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 5631 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 5632 * OpenGL hardware) and causes the view to be rendered using Android's hardware 5633 * rendering pipeline, but only if hardware acceleration is turned on for the 5634 * view hierarchy. When hardware acceleration is turned off, hardware layers 5635 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 5636 * 5637 * <p>A hardware layer is useful to apply a specific color filter and/or 5638 * blending mode and/or translucency to a view and all its children.</p> 5639 * <p>A hardware layer can be used to cache a complex view tree into a 5640 * texture and reduce the complexity of drawing operations. For instance, 5641 * when animating a complex view tree with a translation, a hardware layer can 5642 * be used to render the view tree only once.</p> 5643 * <p>A hardware layer can also be used to increase the rendering quality when 5644 * rotation transformations are applied on a view. It can also be used to 5645 * prevent potential clipping issues when applying 3D transforms on a view.</p> 5646 * 5647 * @see #getLayerType() 5648 * @see #setLayerType(int, android.graphics.Paint) 5649 * @see #LAYER_TYPE_NONE 5650 * @see #LAYER_TYPE_SOFTWARE 5651 */ 5652 public static final int LAYER_TYPE_HARDWARE = 2; 5653 5654 /** @hide */ 5655 @IntDef(prefix = { "LAYER_TYPE_" }, value = { 5656 LAYER_TYPE_NONE, 5657 LAYER_TYPE_SOFTWARE, 5658 LAYER_TYPE_HARDWARE 5659 }) 5660 @Retention(RetentionPolicy.SOURCE) 5661 public @interface LayerType {} 5662 5663 int mLayerType = LAYER_TYPE_NONE; 5664 Paint mLayerPaint; 5665 5666 /** 5667 * Set to true when drawing cache is enabled and cannot be created. 5668 * 5669 * @hide 5670 */ 5671 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 5672 public boolean mCachingFailed; 5673 @UnsupportedAppUsage 5674 private Bitmap mDrawingCache; 5675 @UnsupportedAppUsage 5676 private Bitmap mUnscaledDrawingCache; 5677 5678 /** 5679 * RenderNode holding View properties, potentially holding a DisplayList of View content. 5680 * <p> 5681 * When non-null and valid, this is expected to contain an up-to-date copy 5682 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 5683 * cleanup. 5684 */ 5685 @UnsupportedAppUsage 5686 final RenderNode mRenderNode; 5687 5688 /** 5689 * Set to true when the view is sending hover accessibility events because it 5690 * is the innermost hovered view. 5691 */ 5692 private boolean mSendingHoverAccessibilityEvents; 5693 5694 /** 5695 * Delegate for injecting accessibility functionality. 5696 */ 5697 @UnsupportedAppUsage 5698 AccessibilityDelegate mAccessibilityDelegate; 5699 5700 /** 5701 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 5702 * and add/remove objects to/from the overlay directly through the Overlay methods. 5703 */ 5704 ViewOverlay mOverlay; 5705 5706 /** 5707 * The currently active parent view for receiving delegated nested scrolling events. 5708 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 5709 * by {@link #stopNestedScroll()} at the same point where we clear 5710 * requestDisallowInterceptTouchEvent. 5711 */ 5712 private ViewParent mNestedScrollingParent; 5713 5714 /** 5715 * Consistency verifier for debugging purposes. 5716 * @hide 5717 */ 5718 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 5719 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 5720 new InputEventConsistencyVerifier(this, 0) : null; 5721 5722 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 5723 5724 private int[] mTempNestedScrollConsumed; 5725 5726 /** 5727 * An overlay is going to draw this View instead of being drawn as part of this 5728 * View's parent. mGhostView is the View in the Overlay that must be invalidated 5729 * when this view is invalidated. 5730 */ 5731 GhostView mGhostView; 5732 5733 /** 5734 * Holds pairs of adjacent attribute data: attribute name followed by its value. 5735 * @hide 5736 */ 5737 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 5738 public String[] mAttributes; 5739 5740 /** 5741 * Maps a Resource id to its name. 5742 */ 5743 private static SparseArray<String> mAttributeMap; 5744 5745 /** 5746 * Queue of pending runnables. Used to postpone calls to post() until this 5747 * view is attached and has a handler. 5748 */ 5749 private HandlerActionQueue mRunQueue; 5750 5751 /** 5752 * The pointer icon when the mouse hovers on this view. The default is null. 5753 */ 5754 private PointerIcon mMousePointerIcon; 5755 5756 /** 5757 * @hide 5758 */ 5759 @UnsupportedAppUsage 5760 String mStartActivityRequestWho; 5761 5762 @Nullable 5763 private RoundScrollbarRenderer mRoundScrollbarRenderer; 5764 5765 /** Used to delay visibility updates sent to the autofill manager */ 5766 private Handler mVisibilityChangeForAutofillHandler; 5767 5768 /** 5769 * Used when app developers explicitly set the {@link ContentCaptureSession} associated with the 5770 * view (through {@link #setContentCaptureSession(ContentCaptureSession)}. 5771 */ 5772 @Nullable 5773 private ContentCaptureSession mContentCaptureSession; 5774 5775 /** 5776 * Whether {@link ContentCaptureSession} is cached, resets on {@link #invalidate()}. 5777 */ 5778 private boolean mContentCaptureSessionCached; 5779 5780 @LayoutRes 5781 private int mSourceLayoutId = ID_NULL; 5782 5783 @Nullable 5784 private SparseIntArray mAttributeSourceResId; 5785 5786 @Nullable 5787 private SparseArray<int[]> mAttributeResolutionStacks; 5788 5789 @StyleRes 5790 private int mExplicitStyle; 5791 5792 /** 5793 * Specifies which input source classes should provide unbuffered input events to this view 5794 * 5795 * @see View#requestUnbufferedDispatch(int) 5796 */ 5797 @InputSourceClass 5798 int mUnbufferedInputSource = InputDevice.SOURCE_CLASS_NONE; 5799 5800 @Nullable 5801 private String[] mReceiveContentMimeTypes; 5802 5803 @Nullable 5804 private ViewTranslationCallback mViewTranslationCallback; 5805 5806 private float mFrameContentVelocity = -1; 5807 5808 @Nullable 5809 5810 private ViewTranslationResponse mViewTranslationResponse; 5811 5812 /** 5813 * The size in DP that is considered small for VRR purposes, if square. 5814 */ 5815 private static final float FRAME_RATE_SQUARE_SMALL_SIZE_DP = 40f; 5816 5817 /** 5818 * The size in DP that is considered small for VRR purposes in the narrow dimension. Used for 5819 * narrow Views like a progress bar. 5820 */ 5821 private static final float FRAME_RATE_NARROW_SIZE_DP = 10f; 5822 5823 /** 5824 * A threshold value to determine the frame rate category of the View based on the size. 5825 */ 5826 private static final float FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD = 0.07f; 5827 5828 static final float MAX_FRAME_RATE = 120; 5829 5830 // The preferred frame rate of the view that is mainly used for 5831 // touch boosting, view velocity handling, and TextureView. 5832 private float mPreferredFrameRate = REQUESTED_FRAME_RATE_CATEGORY_DEFAULT; 5833 5834 private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE; 5835 5836 @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) 5837 public static final float REQUESTED_FRAME_RATE_CATEGORY_DEFAULT = Float.NaN; 5838 @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) 5839 public static final float REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE = -1; 5840 @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) 5841 public static final float REQUESTED_FRAME_RATE_CATEGORY_LOW = -2; 5842 @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) 5843 public static final float REQUESTED_FRAME_RATE_CATEGORY_NORMAL = -3; 5844 @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) 5845 public static final float REQUESTED_FRAME_RATE_CATEGORY_HIGH = -4; 5846 5847 private int mSizeBasedFrameRateCategoryAndReason; 5848 5849 /** 5850 * Simple constructor to use when creating a view from code. 5851 * 5852 * @param context The Context the view is running in, through which it can 5853 * access the current theme, resources, etc. 5854 */ View(Context context)5855 public View(Context context) { 5856 mContext = context; 5857 mResources = context != null ? context.getResources() : null; 5858 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 5859 // Set some flags defaults 5860 mPrivateFlags2 = 5861 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 5862 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 5863 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 5864 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 5865 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 5866 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 5867 5868 final ViewConfiguration configuration = ViewConfiguration.get(context); 5869 mTouchSlop = configuration.getScaledTouchSlop(); 5870 mAmbiguousGestureMultiplier = configuration.getScaledAmbiguousGestureMultiplier(); 5871 5872 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 5873 mUserPaddingStart = UNDEFINED_PADDING; 5874 mUserPaddingEnd = UNDEFINED_PADDING; 5875 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 5876 5877 if (!sCompatibilityDone && context != null) { 5878 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5879 5880 // Old versions of the platform would give different results from 5881 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 5882 // modes, so we always need to run an additional EXACTLY pass. 5883 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 5884 5885 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 5886 // On N+, we throw, but that breaks compatibility with apps that use these methods. 5887 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 5888 5889 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 5890 // in apps so we target check it to avoid breaking existing apps. 5891 sPreserveMarginParamsInLayoutParamConversion = 5892 targetSdkVersion >= Build.VERSION_CODES.N; 5893 5894 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 5895 5896 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 5897 5898 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 5899 5900 sUseDefaultFocusHighlight = context.getResources().getBoolean( 5901 com.android.internal.R.bool.config_useDefaultFocusHighlight); 5902 5903 sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P; 5904 5905 sCanFocusZeroSized = targetSdkVersion < Build.VERSION_CODES.P; 5906 5907 sAlwaysAssignFocus = targetSdkVersion < Build.VERSION_CODES.P; 5908 5909 sAcceptZeroSizeDragShadow = targetSdkVersion < Build.VERSION_CODES.P; 5910 5911 sBrokenInsetsDispatch = targetSdkVersion < Build.VERSION_CODES.R; 5912 5913 sBrokenWindowBackground = targetSdkVersion < Build.VERSION_CODES.Q; 5914 5915 GradientDrawable.sWrapNegativeAngleMeasurements = 5916 targetSdkVersion >= Build.VERSION_CODES.Q; 5917 5918 sForceLayoutWhenInsetsChanged = targetSdkVersion < Build.VERSION_CODES.R; 5919 5920 sCompatibilityDone = true; 5921 } 5922 } 5923 5924 /** 5925 * Constructor that is called when inflating a view from XML. This is called 5926 * when a view is being constructed from an XML file, supplying attributes 5927 * that were specified in the XML file. This version uses a default style of 5928 * 0, so the only attribute values applied are those in the Context's Theme 5929 * and the given AttributeSet. 5930 * 5931 * <p> 5932 * The method onFinishInflate() will be called after all children have been 5933 * added. 5934 * 5935 * @param context The Context the view is running in, through which it can 5936 * access the current theme, resources, etc. 5937 * @param attrs The attributes of the XML tag that is inflating the view. 5938 * @see #View(Context, AttributeSet, int) 5939 */ 5940 public View(Context context, @Nullable AttributeSet attrs) { 5941 this(context, attrs, 0); 5942 } 5943 5944 /** 5945 * Perform inflation from XML and apply a class-specific base style from a 5946 * theme attribute. This constructor of View allows subclasses to use their 5947 * own base style when they are inflating. For example, a Button class's 5948 * constructor would call this version of the super class constructor and 5949 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 5950 * allows the theme's button style to modify all of the base view attributes 5951 * (in particular its background) as well as the Button class's attributes. 5952 * 5953 * @param context The Context the view is running in, through which it can 5954 * access the current theme, resources, etc. 5955 * @param attrs The attributes of the XML tag that is inflating the view. 5956 * @param defStyleAttr An attribute in the current theme that contains a 5957 * reference to a style resource that supplies default values for 5958 * the view. Can be 0 to not look for defaults. 5959 * @see #View(Context, AttributeSet) 5960 */ 5961 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 5962 this(context, attrs, defStyleAttr, 0); 5963 } 5964 5965 /** 5966 * Perform inflation from XML and apply a class-specific base style from a 5967 * theme attribute or style resource. This constructor of View allows 5968 * subclasses to use their own base style when they are inflating. 5969 * <p> 5970 * When determining the final value of a particular attribute, there are 5971 * four inputs that come into play: 5972 * <ol> 5973 * <li>Any attribute values in the given AttributeSet. 5974 * <li>The style resource specified in the AttributeSet (named "style"). 5975 * <li>The default style specified by <var>defStyleAttr</var>. 5976 * <li>The default style specified by <var>defStyleRes</var>. 5977 * <li>The base values in this theme. 5978 * </ol> 5979 * <p> 5980 * Each of these inputs is considered in-order, with the first listed taking 5981 * precedence over the following ones. In other words, if in the 5982 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 5983 * , then the button's text will <em>always</em> be black, regardless of 5984 * what is specified in any of the styles. 5985 * 5986 * @param context The Context the view is running in, through which it can 5987 * access the current theme, resources, etc. 5988 * @param attrs The attributes of the XML tag that is inflating the view. 5989 * @param defStyleAttr An attribute in the current theme that contains a 5990 * reference to a style resource that supplies default values for 5991 * the view. Can be 0 to not look for defaults. 5992 * @param defStyleRes A resource identifier of a style resource that 5993 * supplies default values for the view, used only if 5994 * defStyleAttr is 0 or can not be found in the theme. Can be 0 5995 * to not look for defaults. 5996 * @see #View(Context, AttributeSet, int) 5997 */ 5998 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 5999 this(context); 6000 6001 mSourceLayoutId = Resources.getAttributeSetSourceResId(attrs); 6002 6003 final TypedArray a = context.obtainStyledAttributes( 6004 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 6005 6006 retrieveExplicitStyle(context.getTheme(), attrs); 6007 saveAttributeDataForStyleable(context, com.android.internal.R.styleable.View, attrs, a, 6008 defStyleAttr, defStyleRes); 6009 6010 if (sDebugViewAttributes) { 6011 saveAttributeData(attrs, a); 6012 } 6013 6014 Drawable background = null; 6015 6016 int leftPadding = -1; 6017 int topPadding = -1; 6018 int rightPadding = -1; 6019 int bottomPadding = -1; 6020 int startPadding = UNDEFINED_PADDING; 6021 int endPadding = UNDEFINED_PADDING; 6022 6023 int padding = -1; 6024 int paddingHorizontal = -1; 6025 int paddingVertical = -1; 6026 6027 int viewFlagValues = 0; 6028 int viewFlagMasks = 0; 6029 6030 boolean setScrollContainer = false; 6031 6032 int x = 0; 6033 int y = 0; 6034 6035 float tx = 0; 6036 float ty = 0; 6037 float tz = 0; 6038 float elevation = 0; 6039 float rotation = 0; 6040 float rotationX = 0; 6041 float rotationY = 0; 6042 float sx = 1f; 6043 float sy = 1f; 6044 boolean transformSet = false; 6045 6046 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 6047 int overScrollMode = mOverScrollMode; 6048 boolean initializeScrollbars = false; 6049 boolean initializeScrollIndicators = false; 6050 6051 boolean startPaddingDefined = false; 6052 boolean endPaddingDefined = false; 6053 boolean leftPaddingDefined = false; 6054 boolean rightPaddingDefined = false; 6055 6056 // Set default values. 6057 viewFlagValues |= FOCUSABLE_AUTO; 6058 viewFlagMasks |= FOCUSABLE_AUTO; 6059 6060 final int N = a.getIndexCount(); 6061 for (int i = 0; i < N; i++) { 6062 int attr = a.getIndex(i); 6063 switch (attr) { 6064 case com.android.internal.R.styleable.View_background: 6065 background = a.getDrawable(attr); 6066 break; 6067 case com.android.internal.R.styleable.View_padding: 6068 padding = a.getDimensionPixelSize(attr, -1); 6069 mUserPaddingLeftInitial = padding; 6070 mUserPaddingRightInitial = padding; 6071 leftPaddingDefined = true; 6072 rightPaddingDefined = true; 6073 break; 6074 case com.android.internal.R.styleable.View_paddingHorizontal: 6075 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 6076 mUserPaddingLeftInitial = paddingHorizontal; 6077 mUserPaddingRightInitial = paddingHorizontal; 6078 leftPaddingDefined = true; 6079 rightPaddingDefined = true; 6080 break; 6081 case com.android.internal.R.styleable.View_paddingVertical: 6082 paddingVertical = a.getDimensionPixelSize(attr, -1); 6083 break; 6084 case com.android.internal.R.styleable.View_paddingLeft: 6085 leftPadding = a.getDimensionPixelSize(attr, -1); 6086 mUserPaddingLeftInitial = leftPadding; 6087 leftPaddingDefined = true; 6088 break; 6089 case com.android.internal.R.styleable.View_paddingTop: 6090 topPadding = a.getDimensionPixelSize(attr, -1); 6091 break; 6092 case com.android.internal.R.styleable.View_paddingRight: 6093 rightPadding = a.getDimensionPixelSize(attr, -1); 6094 mUserPaddingRightInitial = rightPadding; 6095 rightPaddingDefined = true; 6096 break; 6097 case com.android.internal.R.styleable.View_paddingBottom: 6098 bottomPadding = a.getDimensionPixelSize(attr, -1); 6099 break; 6100 case com.android.internal.R.styleable.View_paddingStart: 6101 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 6102 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 6103 break; 6104 case com.android.internal.R.styleable.View_paddingEnd: 6105 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 6106 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 6107 break; 6108 case com.android.internal.R.styleable.View_scrollX: 6109 x = a.getDimensionPixelOffset(attr, 0); 6110 break; 6111 case com.android.internal.R.styleable.View_scrollY: 6112 y = a.getDimensionPixelOffset(attr, 0); 6113 break; 6114 case com.android.internal.R.styleable.View_alpha: 6115 setAlpha(a.getFloat(attr, 1f)); 6116 break; 6117 case com.android.internal.R.styleable.View_transformPivotX: 6118 setPivotX(a.getDimension(attr, 0)); 6119 break; 6120 case com.android.internal.R.styleable.View_transformPivotY: 6121 setPivotY(a.getDimension(attr, 0)); 6122 break; 6123 case com.android.internal.R.styleable.View_translationX: 6124 tx = a.getDimension(attr, 0); 6125 transformSet = true; 6126 break; 6127 case com.android.internal.R.styleable.View_translationY: 6128 ty = a.getDimension(attr, 0); 6129 transformSet = true; 6130 break; 6131 case com.android.internal.R.styleable.View_translationZ: 6132 tz = a.getDimension(attr, 0); 6133 transformSet = true; 6134 break; 6135 case com.android.internal.R.styleable.View_elevation: 6136 elevation = a.getDimension(attr, 0); 6137 transformSet = true; 6138 break; 6139 case com.android.internal.R.styleable.View_rotation: 6140 rotation = a.getFloat(attr, 0); 6141 transformSet = true; 6142 break; 6143 case com.android.internal.R.styleable.View_rotationX: 6144 rotationX = a.getFloat(attr, 0); 6145 transformSet = true; 6146 break; 6147 case com.android.internal.R.styleable.View_rotationY: 6148 rotationY = a.getFloat(attr, 0); 6149 transformSet = true; 6150 break; 6151 case com.android.internal.R.styleable.View_scaleX: 6152 sx = a.getFloat(attr, 1f); 6153 transformSet = true; 6154 break; 6155 case com.android.internal.R.styleable.View_scaleY: 6156 sy = a.getFloat(attr, 1f); 6157 transformSet = true; 6158 break; 6159 case com.android.internal.R.styleable.View_id: 6160 mID = a.getResourceId(attr, NO_ID); 6161 break; 6162 case com.android.internal.R.styleable.View_tag: 6163 mTag = a.getText(attr); 6164 break; 6165 case com.android.internal.R.styleable.View_fitsSystemWindows: 6166 if (a.getBoolean(attr, false)) { 6167 viewFlagValues |= FITS_SYSTEM_WINDOWS; 6168 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 6169 } 6170 break; 6171 case com.android.internal.R.styleable.View_focusable: 6172 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 6173 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 6174 viewFlagMasks |= FOCUSABLE_MASK; 6175 } 6176 break; 6177 case com.android.internal.R.styleable.View_focusableInTouchMode: 6178 if (a.getBoolean(attr, false)) { 6179 // unset auto focus since focusableInTouchMode implies explicit focusable 6180 viewFlagValues &= ~FOCUSABLE_AUTO; 6181 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 6182 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 6183 } 6184 break; 6185 case com.android.internal.R.styleable.View_clickable: 6186 if (a.getBoolean(attr, false)) { 6187 viewFlagValues |= CLICKABLE; 6188 viewFlagMasks |= CLICKABLE; 6189 } 6190 break; 6191 case com.android.internal.R.styleable.View_allowClickWhenDisabled: 6192 setAllowClickWhenDisabled(a.getBoolean(attr, false)); 6193 break; 6194 case com.android.internal.R.styleable.View_longClickable: 6195 if (a.getBoolean(attr, false)) { 6196 viewFlagValues |= LONG_CLICKABLE; 6197 viewFlagMasks |= LONG_CLICKABLE; 6198 } 6199 break; 6200 case com.android.internal.R.styleable.View_contextClickable: 6201 if (a.getBoolean(attr, false)) { 6202 viewFlagValues |= CONTEXT_CLICKABLE; 6203 viewFlagMasks |= CONTEXT_CLICKABLE; 6204 } 6205 break; 6206 case com.android.internal.R.styleable.View_saveEnabled: 6207 if (!a.getBoolean(attr, true)) { 6208 viewFlagValues |= SAVE_DISABLED; 6209 viewFlagMasks |= SAVE_DISABLED_MASK; 6210 } 6211 break; 6212 case com.android.internal.R.styleable.View_duplicateParentState: 6213 if (a.getBoolean(attr, false)) { 6214 viewFlagValues |= DUPLICATE_PARENT_STATE; 6215 viewFlagMasks |= DUPLICATE_PARENT_STATE; 6216 } 6217 break; 6218 case com.android.internal.R.styleable.View_visibility: 6219 final int visibility = a.getInt(attr, 0); 6220 if (visibility != 0) { 6221 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 6222 viewFlagMasks |= VISIBILITY_MASK; 6223 } 6224 break; 6225 case com.android.internal.R.styleable.View_layoutDirection: 6226 // Clear any layout direction flags (included resolved bits) already set 6227 mPrivateFlags2 &= 6228 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 6229 // Set the layout direction flags depending on the value of the attribute 6230 final int layoutDirection = a.getInt(attr, -1); 6231 final int value = (layoutDirection != -1) ? 6232 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 6233 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 6234 break; 6235 case com.android.internal.R.styleable.View_drawingCacheQuality: 6236 final int cacheQuality = a.getInt(attr, 0); 6237 if (cacheQuality != 0) { 6238 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 6239 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 6240 } 6241 break; 6242 case com.android.internal.R.styleable.View_contentDescription: 6243 setContentDescription(a.getString(attr)); 6244 break; 6245 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 6246 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 6247 break; 6248 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 6249 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 6250 break; 6251 case com.android.internal.R.styleable.View_labelFor: 6252 setLabelFor(a.getResourceId(attr, NO_ID)); 6253 break; 6254 case com.android.internal.R.styleable.View_soundEffectsEnabled: 6255 if (!a.getBoolean(attr, true)) { 6256 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 6257 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 6258 } 6259 break; 6260 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 6261 if (!a.getBoolean(attr, true)) { 6262 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 6263 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 6264 } 6265 break; 6266 case R.styleable.View_scrollbars: 6267 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 6268 if (scrollbars != SCROLLBARS_NONE) { 6269 viewFlagValues |= scrollbars; 6270 viewFlagMasks |= SCROLLBARS_MASK; 6271 initializeScrollbars = true; 6272 } 6273 break; 6274 //noinspection deprecation 6275 case R.styleable.View_fadingEdge: 6276 break; 6277 case R.styleable.View_requiresFadingEdge: 6278 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 6279 if (fadingEdge != FADING_EDGE_NONE) { 6280 viewFlagValues |= fadingEdge; 6281 viewFlagMasks |= FADING_EDGE_MASK; 6282 initializeFadingEdgeInternal(a); 6283 } 6284 break; 6285 case R.styleable.View_scrollbarStyle: 6286 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 6287 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 6288 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 6289 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 6290 } 6291 break; 6292 case R.styleable.View_isScrollContainer: 6293 setScrollContainer = true; 6294 if (a.getBoolean(attr, false)) { 6295 setScrollContainer(true); 6296 } 6297 break; 6298 case com.android.internal.R.styleable.View_keepScreenOn: 6299 if (a.getBoolean(attr, false)) { 6300 viewFlagValues |= KEEP_SCREEN_ON; 6301 viewFlagMasks |= KEEP_SCREEN_ON; 6302 } 6303 break; 6304 case R.styleable.View_filterTouchesWhenObscured: 6305 if (a.getBoolean(attr, false)) { 6306 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 6307 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 6308 } 6309 break; 6310 case R.styleable.View_nextFocusLeft: 6311 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 6312 break; 6313 case R.styleable.View_nextFocusRight: 6314 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 6315 break; 6316 case R.styleable.View_nextFocusUp: 6317 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 6318 break; 6319 case R.styleable.View_nextFocusDown: 6320 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 6321 break; 6322 case R.styleable.View_nextFocusForward: 6323 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 6324 break; 6325 case R.styleable.View_nextClusterForward: 6326 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 6327 break; 6328 case R.styleable.View_minWidth: 6329 mMinWidth = a.getDimensionPixelSize(attr, 0); 6330 break; 6331 case R.styleable.View_minHeight: 6332 mMinHeight = a.getDimensionPixelSize(attr, 0); 6333 break; 6334 case R.styleable.View_onClick: 6335 if (context.isRestricted()) { 6336 throw new IllegalStateException("The android:onClick attribute cannot " 6337 + "be used within a restricted context"); 6338 } 6339 6340 final String handlerName = a.getString(attr); 6341 if (handlerName != null) { 6342 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 6343 } 6344 break; 6345 case R.styleable.View_overScrollMode: 6346 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 6347 break; 6348 case R.styleable.View_verticalScrollbarPosition: 6349 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 6350 break; 6351 case R.styleable.View_layerType: 6352 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 6353 break; 6354 case R.styleable.View_textDirection: 6355 // Clear any text direction flag already set 6356 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 6357 // Set the text direction flags depending on the value of the attribute 6358 final int textDirection = a.getInt(attr, -1); 6359 if (textDirection != -1) { 6360 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 6361 } 6362 break; 6363 case R.styleable.View_textAlignment: 6364 // Clear any text alignment flag already set 6365 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 6366 // Set the text alignment flag depending on the value of the attribute 6367 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 6368 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 6369 break; 6370 case R.styleable.View_importantForAccessibility: 6371 setImportantForAccessibility(a.getInt(attr, 6372 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 6373 break; 6374 case R.styleable.View_accessibilityDataSensitive: 6375 setAccessibilityDataSensitive(a.getInt(attr, 6376 ACCESSIBILITY_DATA_SENSITIVE_AUTO)); 6377 break; 6378 case R.styleable.View_accessibilityLiveRegion: 6379 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 6380 break; 6381 case R.styleable.View_transitionName: 6382 setTransitionName(a.getString(attr)); 6383 break; 6384 case R.styleable.View_nestedScrollingEnabled: 6385 setNestedScrollingEnabled(a.getBoolean(attr, false)); 6386 break; 6387 case R.styleable.View_stateListAnimator: 6388 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 6389 a.getResourceId(attr, 0))); 6390 break; 6391 case R.styleable.View_backgroundTint: 6392 // This will get applied later during setBackground(). 6393 if (mBackgroundTint == null) { 6394 mBackgroundTint = new TintInfo(); 6395 } 6396 mBackgroundTint.mTintList = a.getColorStateList( 6397 R.styleable.View_backgroundTint); 6398 mBackgroundTint.mHasTintList = true; 6399 break; 6400 case R.styleable.View_backgroundTintMode: 6401 // This will get applied later during setBackground(). 6402 if (mBackgroundTint == null) { 6403 mBackgroundTint = new TintInfo(); 6404 } 6405 mBackgroundTint.mBlendMode = Drawable.parseBlendMode(a.getInt( 6406 R.styleable.View_backgroundTintMode, -1), null); 6407 mBackgroundTint.mHasTintMode = true; 6408 break; 6409 case R.styleable.View_outlineProvider: 6410 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 6411 PROVIDER_BACKGROUND)); 6412 break; 6413 case R.styleable.View_foreground: 6414 setForeground(a.getDrawable(attr)); 6415 break; 6416 case R.styleable.View_foregroundGravity: 6417 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 6418 break; 6419 case R.styleable.View_foregroundTintMode: 6420 setForegroundTintBlendMode( 6421 Drawable.parseBlendMode(a.getInt(attr, -1), 6422 null)); 6423 break; 6424 case R.styleable.View_foregroundTint: 6425 setForegroundTintList(a.getColorStateList(attr)); 6426 break; 6427 case R.styleable.View_foregroundInsidePadding: 6428 if (mForegroundInfo == null) { 6429 mForegroundInfo = new ForegroundInfo(); 6430 } 6431 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 6432 mForegroundInfo.mInsidePadding); 6433 break; 6434 case R.styleable.View_scrollIndicators: 6435 final int scrollIndicators = 6436 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 6437 & SCROLL_INDICATORS_PFLAG3_MASK; 6438 if (scrollIndicators != 0) { 6439 mPrivateFlags3 |= scrollIndicators; 6440 initializeScrollIndicators = true; 6441 } 6442 break; 6443 case R.styleable.View_pointerIcon: 6444 final int resourceId = a.getResourceId(attr, 0); 6445 if (resourceId != 0) { 6446 setPointerIcon(PointerIcon.load( 6447 context.getResources(), resourceId)); 6448 } else { 6449 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 6450 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 6451 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 6452 } 6453 } 6454 break; 6455 case R.styleable.View_forceHasOverlappingRendering: 6456 if (a.peekValue(attr) != null) { 6457 forceHasOverlappingRendering(a.getBoolean(attr, true)); 6458 } 6459 break; 6460 case R.styleable.View_tooltipText: 6461 setTooltipText(a.getText(attr)); 6462 break; 6463 case R.styleable.View_keyboardNavigationCluster: 6464 if (a.peekValue(attr) != null) { 6465 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 6466 } 6467 break; 6468 case R.styleable.View_focusedByDefault: 6469 if (a.peekValue(attr) != null) { 6470 setFocusedByDefault(a.getBoolean(attr, true)); 6471 } 6472 break; 6473 case R.styleable.View_autofillHints: 6474 if (a.peekValue(attr) != null) { 6475 CharSequence[] rawHints = null; 6476 String rawString = null; 6477 6478 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 6479 int resId = a.getResourceId(attr, 0); 6480 6481 try { 6482 rawHints = a.getTextArray(attr); 6483 } catch (Resources.NotFoundException e) { 6484 rawString = getResources().getString(resId); 6485 } 6486 } else { 6487 rawString = a.getString(attr); 6488 } 6489 6490 if (rawHints == null) { 6491 if (rawString == null) { 6492 throw new IllegalArgumentException( 6493 "Could not resolve autofillHints"); 6494 } else { 6495 rawHints = rawString.split(","); 6496 } 6497 } 6498 6499 String[] hints = new String[rawHints.length]; 6500 6501 int numHints = rawHints.length; 6502 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 6503 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 6504 } 6505 setAutofillHints(hints); 6506 } 6507 break; 6508 case R.styleable.View_importantForAutofill: 6509 if (a.peekValue(attr) != null) { 6510 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 6511 } 6512 break; 6513 case R.styleable.View_importantForContentCapture: 6514 if (a.peekValue(attr) != null) { 6515 setImportantForContentCapture(a.getInt(attr, 6516 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO)); 6517 } 6518 break; 6519 case R.styleable.View_isCredential: 6520 if (a.peekValue(attr) != null) { 6521 setIsCredential(a.getBoolean(attr, false)); 6522 } 6523 break; 6524 case R.styleable.View_defaultFocusHighlightEnabled: 6525 if (a.peekValue(attr) != null) { 6526 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); 6527 } 6528 break; 6529 case R.styleable.View_screenReaderFocusable: 6530 if (a.peekValue(attr) != null) { 6531 setScreenReaderFocusable(a.getBoolean(attr, false)); 6532 } 6533 break; 6534 case R.styleable.View_accessibilityPaneTitle: 6535 if (a.peekValue(attr) != null) { 6536 setAccessibilityPaneTitle(a.getString(attr)); 6537 } 6538 break; 6539 case R.styleable.View_outlineSpotShadowColor: 6540 setOutlineSpotShadowColor(a.getColor(attr, Color.BLACK)); 6541 break; 6542 case R.styleable.View_outlineAmbientShadowColor: 6543 setOutlineAmbientShadowColor(a.getColor(attr, Color.BLACK)); 6544 break; 6545 case com.android.internal.R.styleable.View_accessibilityHeading: 6546 setAccessibilityHeading(a.getBoolean(attr, false)); 6547 break; 6548 case R.styleable.View_forceDarkAllowed: 6549 mRenderNode.setForceDarkAllowed(a.getBoolean(attr, true)); 6550 break; 6551 case R.styleable.View_scrollCaptureHint: 6552 setScrollCaptureHint((a.getInt(attr, SCROLL_CAPTURE_HINT_AUTO))); 6553 break; 6554 case R.styleable.View_clipToOutline: 6555 setClipToOutline(a.getBoolean(attr, false)); 6556 break; 6557 case R.styleable.View_preferKeepClear: 6558 setPreferKeepClear(a.getBoolean(attr, false)); 6559 break; 6560 case R.styleable.View_autoHandwritingEnabled: 6561 setAutoHandwritingEnabled(a.getBoolean(attr, false)); 6562 break; 6563 case R.styleable.View_handwritingBoundsOffsetLeft: 6564 mHandwritingBoundsOffsetLeft = a.getDimension(attr, 0); 6565 break; 6566 case R.styleable.View_handwritingBoundsOffsetTop: 6567 mHandwritingBoundsOffsetTop = a.getDimension(attr, 0); 6568 break; 6569 case R.styleable.View_handwritingBoundsOffsetRight: 6570 mHandwritingBoundsOffsetRight = a.getDimension(attr, 0); 6571 break; 6572 case R.styleable.View_handwritingBoundsOffsetBottom: 6573 mHandwritingBoundsOffsetBottom = a.getDimension(attr, 0); 6574 break; 6575 case R.styleable.View_contentSensitivity: 6576 setContentSensitivity(a.getInt(attr, CONTENT_SENSITIVITY_AUTO)); 6577 break; 6578 default: { 6579 if (supplementalDescription()) { 6580 if (attr == com.android.internal.R.styleable.View_supplementalDescription) { 6581 setSupplementalDescription(a.getString(attr)); 6582 } 6583 } 6584 } 6585 } 6586 } 6587 6588 setOverScrollMode(overScrollMode); 6589 6590 // Cache start/end user padding as we cannot fully resolve padding here (we don't have yet 6591 // the resolved layout direction). Those cached values will be used later during padding 6592 // resolution. 6593 mUserPaddingStart = startPadding; 6594 mUserPaddingEnd = endPadding; 6595 6596 if (background != null) { 6597 setBackground(background); 6598 } 6599 6600 // setBackground above will record that padding is currently provided by the background. 6601 // If we have padding specified via xml, record that here instead and use it. 6602 mLeftPaddingDefined = leftPaddingDefined; 6603 mRightPaddingDefined = rightPaddingDefined; 6604 6605 // Valid paddingHorizontal/paddingVertical beats leftPadding, rightPadding, topPadding, 6606 // bottomPadding, and padding set by background. Valid padding beats everything. 6607 if (padding >= 0) { 6608 leftPadding = padding; 6609 topPadding = padding; 6610 rightPadding = padding; 6611 bottomPadding = padding; 6612 mUserPaddingLeftInitial = padding; 6613 mUserPaddingRightInitial = padding; 6614 } else { 6615 if (paddingHorizontal >= 0) { 6616 leftPadding = paddingHorizontal; 6617 rightPadding = paddingHorizontal; 6618 mUserPaddingLeftInitial = paddingHorizontal; 6619 mUserPaddingRightInitial = paddingHorizontal; 6620 } 6621 if (paddingVertical >= 0) { 6622 topPadding = paddingVertical; 6623 bottomPadding = paddingVertical; 6624 } 6625 } 6626 6627 if (isRtlCompatibilityMode()) { 6628 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 6629 // left / right padding are used if defined (meaning here nothing to do). If they are not 6630 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 6631 // start / end and resolve them as left / right (layout direction is not taken into account). 6632 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 6633 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 6634 // defined. 6635 if (!mLeftPaddingDefined && startPaddingDefined) { 6636 leftPadding = startPadding; 6637 } 6638 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 6639 if (!mRightPaddingDefined && endPaddingDefined) { 6640 rightPadding = endPadding; 6641 } 6642 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 6643 } else { 6644 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 6645 // values defined. Otherwise, left /right values are used. 6646 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 6647 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 6648 // defined. 6649 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 6650 6651 if (mLeftPaddingDefined && !hasRelativePadding) { 6652 mUserPaddingLeftInitial = leftPadding; 6653 } 6654 if (mRightPaddingDefined && !hasRelativePadding) { 6655 mUserPaddingRightInitial = rightPadding; 6656 } 6657 } 6658 6659 // mPaddingTop and mPaddingBottom may have been set by setBackground(Drawable) so must pass 6660 // them on if topPadding or bottomPadding are not valid. 6661 internalSetPadding( 6662 mUserPaddingLeftInitial, 6663 topPadding >= 0 ? topPadding : mPaddingTop, 6664 mUserPaddingRightInitial, 6665 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 6666 6667 if (viewFlagMasks != 0) { 6668 setFlags(viewFlagValues, viewFlagMasks); 6669 } 6670 6671 if (initializeScrollbars) { 6672 initializeScrollbarsInternal(a); 6673 } 6674 6675 if (initializeScrollIndicators) { 6676 initializeScrollIndicatorsInternal(); 6677 } 6678 6679 a.recycle(); 6680 6681 // Needs to be called after mViewFlags is set 6682 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 6683 recomputePadding(); 6684 } 6685 6686 if (x != 0 || y != 0) { 6687 scrollTo(x, y); 6688 } 6689 6690 if (transformSet) { 6691 setTranslationX(tx); 6692 setTranslationY(ty); 6693 setTranslationZ(tz); 6694 setElevation(elevation); 6695 setRotation(rotation); 6696 setRotationX(rotationX); 6697 setRotationY(rotationY); 6698 setScaleX(sx); 6699 setScaleY(sy); 6700 } 6701 6702 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 6703 setScrollContainer(true); 6704 } 6705 6706 computeOpaqueFlags(); 6707 } 6708 6709 /** 6710 * Returns the ordered list of resource ID that are considered when resolving attribute values 6711 * for this {@link View}. The list will include layout resource ID if the View is inflated from 6712 * XML. It will also include a set of explicit styles if specified in XML using 6713 * {@code style="..."}. Finally, it will include the default styles resolved from the theme. 6714 * 6715 * <p> 6716 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6717 * is enabled in Android developer options. 6718 * 6719 * @param attribute Attribute resource ID for which the resolution stack should be returned. 6720 * @return ordered list of resource ID that are considered when resolving attribute values for 6721 * this {@link View}. 6722 */ 6723 @NonNull 6724 public int[] getAttributeResolutionStack(@AttrRes int attribute) { 6725 if (!sDebugViewAttributes 6726 || mAttributeResolutionStacks == null 6727 || mAttributeResolutionStacks.get(attribute) == null) { 6728 return new int[0]; 6729 } 6730 int[] attributeResolutionStack = mAttributeResolutionStacks.get(attribute); 6731 int stackSize = attributeResolutionStack.length; 6732 if (mSourceLayoutId != ID_NULL) { 6733 stackSize++; 6734 } 6735 6736 int currentIndex = 0; 6737 int[] stack = new int[stackSize]; 6738 6739 if (mSourceLayoutId != ID_NULL) { 6740 stack[currentIndex] = mSourceLayoutId; 6741 currentIndex++; 6742 } 6743 for (int i = 0; i < attributeResolutionStack.length; i++) { 6744 stack[currentIndex] = attributeResolutionStack[i]; 6745 currentIndex++; 6746 } 6747 return stack; 6748 } 6749 6750 /** 6751 * Returns the mapping of attribute resource ID to source resource ID where the attribute value 6752 * was set. Source resource ID can either be a layout resource ID, if the value was set in XML 6753 * within the View tag, or a style resource ID, if the attribute was set in a style. The source 6754 * resource value will be one of the resource IDs from {@link #getAttributeSourceResourceMap()}. 6755 * 6756 * <p> 6757 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6758 * is enabled in Android developer options. 6759 * 6760 * @return mapping of attribute resource ID to source resource ID where the attribute value 6761 * was set. 6762 */ 6763 @NonNull 6764 @SuppressWarnings("AndroidFrameworkEfficientCollections") 6765 public Map<Integer, Integer> getAttributeSourceResourceMap() { 6766 HashMap<Integer, Integer> map = new HashMap<>(); 6767 if (!sDebugViewAttributes || mAttributeSourceResId == null) { 6768 return map; 6769 } 6770 for (int i = 0; i < mAttributeSourceResId.size(); i++) { 6771 map.put(mAttributeSourceResId.keyAt(i), mAttributeSourceResId.valueAt(i)); 6772 } 6773 return map; 6774 } 6775 6776 /** 6777 * Returns the resource ID for the style specified using {@code style="..."} in the 6778 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise if not 6779 * specified or otherwise not applicable. 6780 * <p> 6781 * Each {@link View} can have an explicit style specified in the layout file. 6782 * This style is used first during the {@link View} attribute resolution, then if an attribute 6783 * is not defined there the resource system looks at default style and theme as fallbacks. 6784 * 6785 * <p> 6786 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6787 * is enabled in Android developer options. 6788 * 6789 * @return The resource ID for the style specified using {@code style="..."} in the 6790 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise 6791 * if not specified or otherwise not applicable. 6792 */ 6793 @StyleRes 6794 public int getExplicitStyle() { 6795 if (!sDebugViewAttributes) { 6796 return ID_NULL; 6797 } 6798 return mExplicitStyle; 6799 } 6800 6801 /** 6802 * An implementation of OnClickListener that attempts to lazily load a 6803 * named click handling method from a parent or ancestor context. 6804 */ 6805 private static class DeclaredOnClickListener implements OnClickListener { 6806 private final View mHostView; 6807 private final String mMethodName; 6808 6809 private Method mResolvedMethod; 6810 private Context mResolvedContext; 6811 6812 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 6813 mHostView = hostView; 6814 mMethodName = methodName; 6815 } 6816 6817 @Override 6818 public void onClick(@NonNull View v) { 6819 if (mResolvedMethod == null) { 6820 resolveMethod(mHostView.getContext(), mMethodName); 6821 } 6822 6823 try { 6824 mResolvedMethod.invoke(mResolvedContext, v); 6825 } catch (IllegalAccessException e) { 6826 throw new IllegalStateException( 6827 "Could not execute non-public method for android:onClick", e); 6828 } catch (InvocationTargetException e) { 6829 throw new IllegalStateException( 6830 "Could not execute method for android:onClick", e); 6831 } 6832 } 6833 6834 @NonNull 6835 private void resolveMethod(@Nullable Context context, @NonNull String name) { 6836 while (context != null) { 6837 try { 6838 if (!context.isRestricted()) { 6839 final Method method = context.getClass().getMethod(mMethodName, View.class); 6840 if (method != null) { 6841 mResolvedMethod = method; 6842 mResolvedContext = context; 6843 return; 6844 } 6845 } 6846 } catch (NoSuchMethodException e) { 6847 // Failed to find method, keep searching up the hierarchy. 6848 } 6849 6850 if (context instanceof ContextWrapper) { 6851 context = ((ContextWrapper) context).getBaseContext(); 6852 } else { 6853 // Can't search up the hierarchy, null out and fail. 6854 context = null; 6855 } 6856 } 6857 6858 final int id = mHostView.getId(); 6859 final String idText = id == NO_ID ? "" : " with id '" 6860 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 6861 throw new IllegalStateException("Could not find method " + mMethodName 6862 + "(View) in a parent or ancestor Context for android:onClick " 6863 + "attribute defined on view " + mHostView.getClass() + idText); 6864 } 6865 } 6866 6867 /** 6868 * Non-public constructor for use in testing 6869 */ 6870 @UnsupportedAppUsage 6871 View() { 6872 mResources = null; 6873 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 6874 } 6875 6876 /** 6877 * Returns {@code true} when the View is attached and the system developer setting to show 6878 * the layout bounds is enabled or {@code false} otherwise. 6879 */ 6880 public final boolean isShowingLayoutBounds() { 6881 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 6882 } 6883 6884 /** 6885 * Used to test isShowingLayoutBounds(). This sets the local value used 6886 * by that function. This method does nothing if the layout isn't attached. 6887 * 6888 * @hide 6889 */ 6890 @TestApi 6891 public final void setShowingLayoutBounds(boolean debugLayout) { 6892 if (mAttachInfo != null) { 6893 mAttachInfo.mDebugLayout = debugLayout; 6894 } 6895 } 6896 6897 private static SparseArray<String> getAttributeMap() { 6898 if (mAttributeMap == null) { 6899 mAttributeMap = new SparseArray<>(); 6900 } 6901 return mAttributeMap; 6902 } 6903 6904 private void retrieveExplicitStyle(@NonNull Resources.Theme theme, 6905 @Nullable AttributeSet attrs) { 6906 if (!sDebugViewAttributes) { 6907 return; 6908 } 6909 mExplicitStyle = theme.getExplicitStyle(attrs); 6910 } 6911 6912 /** 6913 * Stores debugging information about attributes. This should be called in a constructor by 6914 * every custom {@link View} that uses a custom styleable. If the custom view does not call it, 6915 * then the custom attributes used by this view will not be visible in layout inspection tools. 6916 * 6917 * @param context Context under which this view is created. 6918 * @param styleable A reference to styleable array R.styleable.Foo 6919 * @param attrs AttributeSet used to construct this view. 6920 * @param t Resolved {@link TypedArray} returned by a call to 6921 * {@link Resources#obtainAttributes(AttributeSet, int[])}. 6922 * @param defStyleAttr Default style attribute passed into the view constructor. 6923 * @param defStyleRes Default style resource passed into the view constructor. 6924 */ 6925 public final void saveAttributeDataForStyleable(@NonNull Context context, 6926 @NonNull int[] styleable, @Nullable AttributeSet attrs, @NonNull TypedArray t, 6927 int defStyleAttr, int defStyleRes) { 6928 if (!sDebugViewAttributes) { 6929 return; 6930 } 6931 6932 int[] attributeResolutionStack = context.getTheme().getAttributeResolutionStack( 6933 defStyleAttr, defStyleRes, mExplicitStyle); 6934 6935 if (mAttributeResolutionStacks == null) { 6936 mAttributeResolutionStacks = new SparseArray<>(); 6937 } 6938 6939 if (mAttributeSourceResId == null) { 6940 mAttributeSourceResId = new SparseIntArray(); 6941 } 6942 6943 final int indexCount = t.getIndexCount(); 6944 for (int j = 0; j < indexCount; ++j) { 6945 final int index = t.getIndex(j); 6946 mAttributeSourceResId.append(styleable[index], t.getSourceResourceId(index, 0)); 6947 mAttributeResolutionStacks.append(styleable[index], attributeResolutionStack); 6948 } 6949 } 6950 6951 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 6952 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 6953 final int indexCount = t.getIndexCount(); 6954 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 6955 6956 int i = 0; 6957 6958 // Store raw XML attributes. 6959 for (int j = 0; j < attrsCount; ++j) { 6960 attributes[i] = attrs.getAttributeName(j); 6961 attributes[i + 1] = attrs.getAttributeValue(j); 6962 i += 2; 6963 } 6964 6965 // Store resolved styleable attributes. 6966 final Resources res = t.getResources(); 6967 final SparseArray<String> attributeMap = getAttributeMap(); 6968 for (int j = 0; j < indexCount; ++j) { 6969 final int index = t.getIndex(j); 6970 if (!t.hasValueOrEmpty(index)) { 6971 // Value is undefined. Skip it. 6972 continue; 6973 } 6974 6975 final int resourceId = t.getResourceId(index, 0); 6976 if (resourceId == 0) { 6977 // Value is not a reference. Skip it. 6978 continue; 6979 } 6980 6981 String resourceName = attributeMap.get(resourceId); 6982 if (resourceName == null) { 6983 try { 6984 resourceName = res.getResourceName(resourceId); 6985 } catch (Resources.NotFoundException e) { 6986 resourceName = "0x" + Integer.toHexString(resourceId); 6987 } 6988 attributeMap.put(resourceId, resourceName); 6989 } 6990 6991 attributes[i] = resourceName; 6992 attributes[i + 1] = t.getString(index); 6993 i += 2; 6994 } 6995 6996 // Trim to fit contents. 6997 final String[] trimmed = new String[i]; 6998 System.arraycopy(attributes, 0, trimmed, 0, i); 6999 mAttributes = trimmed; 7000 } 7001 7002 @Override 7003 public String toString() { 7004 StringBuilder out = new StringBuilder(256); 7005 out.append(getClass().getName()); 7006 out.append('{'); 7007 out.append(Integer.toHexString(System.identityHashCode(this))); 7008 out.append(' '); 7009 switch (mViewFlags&VISIBILITY_MASK) { 7010 case VISIBLE: out.append('V'); break; 7011 case INVISIBLE: out.append('I'); break; 7012 case GONE: out.append('G'); break; 7013 default: out.append('.'); break; 7014 } 7015 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 7016 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 7017 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 7018 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 7019 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 7020 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 7021 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 7022 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 7023 out.append(' '); 7024 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 7025 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 7026 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 7027 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 7028 out.append('p'); 7029 } else { 7030 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 7031 } 7032 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 7033 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 7034 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 7035 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 7036 out.append(' '); 7037 out.append(mLeft); 7038 out.append(','); 7039 out.append(mTop); 7040 out.append('-'); 7041 out.append(mRight); 7042 out.append(','); 7043 out.append(mBottom); 7044 appendId(out); 7045 if (mAutofillId != null) { 7046 out.append(" aid="); out.append(mAutofillId); 7047 } 7048 out.append("}"); 7049 return out.toString(); 7050 } 7051 7052 void appendId(StringBuilder out) { 7053 final int id = getId(); 7054 if (id != NO_ID) { 7055 out.append(" #"); 7056 out.append(Integer.toHexString(id)); 7057 final Resources r = mResources; 7058 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 7059 try { 7060 String pkgname; 7061 switch (id&0xff000000) { 7062 case 0x7f000000: 7063 pkgname="app"; 7064 break; 7065 case 0x01000000: 7066 pkgname="android"; 7067 break; 7068 default: 7069 pkgname = r.getResourcePackageName(id); 7070 break; 7071 } 7072 String typename = r.getResourceTypeName(id); 7073 String entryname = r.getResourceEntryName(id); 7074 out.append(" "); 7075 out.append(pkgname); 7076 out.append(":"); 7077 out.append(typename); 7078 out.append("/"); 7079 out.append(entryname); 7080 } catch (Resources.NotFoundException e) { 7081 } 7082 } 7083 } 7084 } 7085 7086 /** 7087 * <p> 7088 * Initializes the fading edges from a given set of styled attributes. This 7089 * method should be called by subclasses that need fading edges and when an 7090 * instance of these subclasses is created programmatically rather than 7091 * being inflated from XML. This method is automatically called when the XML 7092 * is inflated. 7093 * </p> 7094 * 7095 * @param a the styled attributes set to initialize the fading edges from 7096 * 7097 * @removed 7098 */ 7099 protected void initializeFadingEdge(TypedArray a) { 7100 // This method probably shouldn't have been included in the SDK to begin with. 7101 // It relies on 'a' having been initialized using an attribute filter array that is 7102 // not publicly available to the SDK. The old method has been renamed 7103 // to initializeFadingEdgeInternal and hidden for framework use only; 7104 // this one initializes using defaults to make it safe to call for apps. 7105 7106 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 7107 7108 initializeFadingEdgeInternal(arr); 7109 7110 arr.recycle(); 7111 } 7112 7113 /** 7114 * <p> 7115 * Initializes the fading edges from a given set of styled attributes. This 7116 * method should be called by subclasses that need fading edges and when an 7117 * instance of these subclasses is created programmatically rather than 7118 * being inflated from XML. This method is automatically called when the XML 7119 * is inflated. 7120 * </p> 7121 * 7122 * @param a the styled attributes set to initialize the fading edges from 7123 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 7124 */ 7125 protected void initializeFadingEdgeInternal(TypedArray a) { 7126 initScrollCache(); 7127 7128 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 7129 R.styleable.View_fadingEdgeLength, 7130 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 7131 } 7132 7133 /** 7134 * Returns the size of the vertical faded edges used to indicate that more 7135 * content in this view is visible. 7136 * 7137 * @return The size in pixels of the vertical faded edge or 0 if vertical 7138 * faded edges are not enabled for this view. 7139 * @attr ref android.R.styleable#View_fadingEdgeLength 7140 */ 7141 public int getVerticalFadingEdgeLength() { 7142 if (isVerticalFadingEdgeEnabled()) { 7143 ScrollabilityCache cache = mScrollCache; 7144 if (cache != null) { 7145 return cache.fadingEdgeLength; 7146 } 7147 } 7148 return 0; 7149 } 7150 7151 /** 7152 * Set the size of the faded edge used to indicate that more content in this 7153 * view is available. Will not change whether the fading edge is enabled; use 7154 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 7155 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 7156 * for the vertical or horizontal fading edges. 7157 * 7158 * @param length The size in pixels of the faded edge used to indicate that more 7159 * content in this view is visible. 7160 */ 7161 public void setFadingEdgeLength(int length) { 7162 initScrollCache(); 7163 mScrollCache.fadingEdgeLength = length; 7164 } 7165 7166 /** 7167 * Clears the request and callback previously set 7168 * through {@link View#setPendingCredentialRequest}. 7169 * Once this API is invoked, there will be no request fired to {@link CredentialManager} 7170 * on future view focus events. 7171 * 7172 * @see #setPendingCredentialRequest 7173 */ 7174 @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) 7175 public void clearPendingCredentialRequest() { 7176 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 7177 Log.v(AUTOFILL_LOG_TAG, "clearPendingCredentialRequest called"); 7178 } 7179 mViewCredentialHandler = null; 7180 } 7181 7182 /** 7183 * Sets a {@link CredentialManager} request to retrieve credentials, when the user focuses 7184 * on this given view. 7185 * 7186 * When this view is focused, the given {@code request} will be fired to 7187 * {@link CredentialManager}, which will fetch content from all 7188 * {@link android.service.credentials.CredentialProviderService} services on the 7189 * device, and then display credential options to the user on a relevant UI 7190 * (dropdown, keyboard suggestions etc.). 7191 * 7192 * When the user selects a credential, the final {@link GetCredentialResponse} will be 7193 * propagated to the given {@code callback}. Developers are expected to handle the response 7194 * programmatically and perform a relevant action, e.g. signing in the user. 7195 * 7196 * <p> For details on how to build a Credential Manager request, please see 7197 * {@link GetCredentialRequest}. 7198 * 7199 * <p> This API should be called at any point before the user focuses on the view, e.g. during 7200 * {@code onCreate} of an Activity. 7201 * 7202 * @param request the request to be fired when this view is entered 7203 * @param callback to be invoked when either a response or an exception needs to be 7204 * propagated for the given view 7205 */ 7206 @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) 7207 public void setPendingCredentialRequest(@NonNull GetCredentialRequest request, 7208 @NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) { 7209 Preconditions.checkNotNull(request, "request must not be null"); 7210 Preconditions.checkNotNull(callback, "callback must not be null"); 7211 7212 for (CredentialOption option : request.getCredentialOptions()) { 7213 ArrayList<AutofillId> ids = option.getCandidateQueryData() 7214 .getParcelableArrayList( 7215 CredentialProviderService.EXTRA_AUTOFILL_ID, AutofillId.class); 7216 ids = ids != null ? ids : new ArrayList<>(); 7217 if (!ids.contains(getAutofillId())) { 7218 ids.add(getAutofillId()); 7219 } 7220 option.getCandidateQueryData() 7221 .putParcelableArrayList(CredentialProviderService.EXTRA_AUTOFILL_ID, ids); 7222 } 7223 mViewCredentialHandler = new ViewCredentialHandler(request, callback); 7224 } 7225 7226 /** 7227 * 7228 * @hide 7229 */ 7230 @Nullable 7231 public ViewCredentialHandler getViewCredentialHandler() { 7232 return mViewCredentialHandler; 7233 } 7234 7235 /** 7236 * Returns the size of the horizontal faded edges used to indicate that more 7237 * content in this view is visible. 7238 * 7239 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 7240 * faded edges are not enabled for this view. 7241 * @attr ref android.R.styleable#View_fadingEdgeLength 7242 */ 7243 public int getHorizontalFadingEdgeLength() { 7244 if (isHorizontalFadingEdgeEnabled()) { 7245 ScrollabilityCache cache = mScrollCache; 7246 if (cache != null) { 7247 return cache.fadingEdgeLength; 7248 } 7249 } 7250 return 0; 7251 } 7252 7253 /** 7254 * Returns the width of the vertical scrollbar. 7255 * 7256 * @return The width in pixels of the vertical scrollbar or 0 if there 7257 * is no vertical scrollbar. 7258 */ 7259 public int getVerticalScrollbarWidth() { 7260 ScrollabilityCache cache = mScrollCache; 7261 if (cache != null) { 7262 ScrollBarDrawable scrollBar = cache.scrollBar; 7263 if (scrollBar != null) { 7264 int size = scrollBar.getSize(true); 7265 if (size <= 0) { 7266 size = cache.scrollBarSize; 7267 } 7268 return size; 7269 } 7270 return 0; 7271 } 7272 return 0; 7273 } 7274 7275 /** 7276 * Returns the height of the horizontal scrollbar. 7277 * 7278 * @return The height in pixels of the horizontal scrollbar or 0 if 7279 * there is no horizontal scrollbar. 7280 */ 7281 protected int getHorizontalScrollbarHeight() { 7282 ScrollabilityCache cache = mScrollCache; 7283 if (cache != null) { 7284 ScrollBarDrawable scrollBar = cache.scrollBar; 7285 if (scrollBar != null) { 7286 int size = scrollBar.getSize(false); 7287 if (size <= 0) { 7288 size = cache.scrollBarSize; 7289 } 7290 return size; 7291 } 7292 return 0; 7293 } 7294 return 0; 7295 } 7296 7297 /** 7298 * <p> 7299 * Initializes the scrollbars from a given set of styled attributes. This 7300 * method should be called by subclasses that need scrollbars and when an 7301 * instance of these subclasses is created programmatically rather than 7302 * being inflated from XML. This method is automatically called when the XML 7303 * is inflated. 7304 * </p> 7305 * 7306 * @param a the styled attributes set to initialize the scrollbars from 7307 * 7308 * @removed 7309 */ 7310 protected void initializeScrollbars(TypedArray a) { 7311 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 7312 // using the View filter array which is not available to the SDK. As such, internal 7313 // framework usage now uses initializeScrollbarsInternal and we grab a default 7314 // TypedArray with the right filter instead here. 7315 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 7316 7317 initializeScrollbarsInternal(arr); 7318 7319 // We ignored the method parameter. Recycle the one we actually did use. 7320 arr.recycle(); 7321 } 7322 7323 private void initializeScrollBarDrawable() { 7324 initScrollCache(); 7325 7326 if (mScrollCache.scrollBar == null) { 7327 mScrollCache.scrollBar = new ScrollBarDrawable(); 7328 mScrollCache.scrollBar.setState(getDrawableState()); 7329 mScrollCache.scrollBar.setCallback(this); 7330 } 7331 } 7332 7333 /** 7334 * <p> 7335 * Initializes the scrollbars from a given set of styled attributes. This 7336 * method should be called by subclasses that need scrollbars and when an 7337 * instance of these subclasses is created programmatically rather than 7338 * being inflated from XML. This method is automatically called when the XML 7339 * is inflated. 7340 * </p> 7341 * 7342 * @param a the styled attributes set to initialize the scrollbars from 7343 * @hide 7344 */ 7345 @UnsupportedAppUsage 7346 protected void initializeScrollbarsInternal(TypedArray a) { 7347 initScrollCache(); 7348 7349 final ScrollabilityCache scrollabilityCache = mScrollCache; 7350 7351 if (scrollabilityCache.scrollBar == null) { 7352 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 7353 scrollabilityCache.scrollBar.setState(getDrawableState()); 7354 scrollabilityCache.scrollBar.setCallback(this); 7355 } 7356 7357 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 7358 7359 if (!fadeScrollbars) { 7360 scrollabilityCache.state = ScrollabilityCache.ON; 7361 } 7362 scrollabilityCache.fadeScrollBars = fadeScrollbars; 7363 7364 7365 scrollabilityCache.scrollBarFadeDuration = a.getInt( 7366 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 7367 .getScrollBarFadeDuration()); 7368 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 7369 R.styleable.View_scrollbarDefaultDelayBeforeFade, 7370 ViewConfiguration.getScrollDefaultDelay()); 7371 7372 7373 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 7374 com.android.internal.R.styleable.View_scrollbarSize, 7375 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 7376 7377 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 7378 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 7379 7380 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 7381 if (thumb != null) { 7382 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 7383 } 7384 7385 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 7386 false); 7387 if (alwaysDraw) { 7388 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 7389 } 7390 7391 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 7392 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 7393 7394 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 7395 if (thumb != null) { 7396 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 7397 } 7398 7399 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 7400 false); 7401 if (alwaysDraw) { 7402 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 7403 } 7404 7405 // Apply layout direction to the new Drawables if needed 7406 final int layoutDirection = getLayoutDirection(); 7407 if (track != null) { 7408 track.setLayoutDirection(layoutDirection); 7409 } 7410 if (thumb != null) { 7411 thumb.setLayoutDirection(layoutDirection); 7412 } 7413 7414 // Re-apply user/background padding so that scrollbar(s) get added 7415 resolvePadding(); 7416 } 7417 7418 /** 7419 * Defines the vertical scrollbar thumb drawable 7420 * @attr ref android.R.styleable#View_scrollbarThumbVertical 7421 * 7422 * @see #awakenScrollBars(int) 7423 * @see #isVerticalScrollBarEnabled() 7424 * @see #setVerticalScrollBarEnabled(boolean) 7425 */ 7426 public void setVerticalScrollbarThumbDrawable(@Nullable Drawable drawable) { 7427 initializeScrollBarDrawable(); 7428 mScrollCache.scrollBar.setVerticalThumbDrawable(drawable); 7429 } 7430 7431 /** 7432 * Defines the vertical scrollbar track drawable 7433 * @attr ref android.R.styleable#View_scrollbarTrackVertical 7434 * 7435 * @see #awakenScrollBars(int) 7436 * @see #isVerticalScrollBarEnabled() 7437 * @see #setVerticalScrollBarEnabled(boolean) 7438 */ 7439 public void setVerticalScrollbarTrackDrawable(@Nullable Drawable drawable) { 7440 initializeScrollBarDrawable(); 7441 mScrollCache.scrollBar.setVerticalTrackDrawable(drawable); 7442 } 7443 7444 /** 7445 * Defines the horizontal thumb drawable 7446 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 7447 * 7448 * @see #awakenScrollBars(int) 7449 * @see #isHorizontalScrollBarEnabled() 7450 * @see #setHorizontalScrollBarEnabled(boolean) 7451 */ 7452 public void setHorizontalScrollbarThumbDrawable(@Nullable Drawable drawable) { 7453 initializeScrollBarDrawable(); 7454 mScrollCache.scrollBar.setHorizontalThumbDrawable(drawable); 7455 } 7456 7457 /** 7458 * Defines the horizontal track drawable 7459 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 7460 * 7461 * @see #awakenScrollBars(int) 7462 * @see #isHorizontalScrollBarEnabled() 7463 * @see #setHorizontalScrollBarEnabled(boolean) 7464 */ 7465 public void setHorizontalScrollbarTrackDrawable(@Nullable Drawable drawable) { 7466 initializeScrollBarDrawable(); 7467 mScrollCache.scrollBar.setHorizontalTrackDrawable(drawable); 7468 } 7469 7470 /** 7471 * Returns the currently configured Drawable for the thumb of the vertical scroll bar if it 7472 * exists, null otherwise. 7473 * 7474 * @see #awakenScrollBars(int) 7475 * @see #isVerticalScrollBarEnabled() 7476 * @see #setVerticalScrollBarEnabled(boolean) 7477 */ 7478 public @Nullable Drawable getVerticalScrollbarThumbDrawable() { 7479 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalThumbDrawable() : null; 7480 } 7481 7482 /** 7483 * Returns the currently configured Drawable for the track of the vertical scroll bar if it 7484 * exists, null otherwise. 7485 * 7486 * @see #awakenScrollBars(int) 7487 * @see #isVerticalScrollBarEnabled() 7488 * @see #setVerticalScrollBarEnabled(boolean) 7489 */ 7490 public @Nullable Drawable getVerticalScrollbarTrackDrawable() { 7491 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalTrackDrawable() : null; 7492 } 7493 7494 /** 7495 * Returns the currently configured Drawable for the thumb of the horizontal scroll bar if it 7496 * exists, null otherwise. 7497 * 7498 * @see #awakenScrollBars(int) 7499 * @see #isHorizontalScrollBarEnabled() 7500 * @see #setHorizontalScrollBarEnabled(boolean) 7501 */ 7502 public @Nullable Drawable getHorizontalScrollbarThumbDrawable() { 7503 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalThumbDrawable() : null; 7504 } 7505 7506 /** 7507 * Returns the currently configured Drawable for the track of the horizontal scroll bar if it 7508 * exists, null otherwise. 7509 * 7510 * @see #awakenScrollBars(int) 7511 * @see #isHorizontalScrollBarEnabled() 7512 * @see #setHorizontalScrollBarEnabled(boolean) 7513 */ 7514 public @Nullable Drawable getHorizontalScrollbarTrackDrawable() { 7515 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalTrackDrawable() : null; 7516 } 7517 7518 private void initializeScrollIndicatorsInternal() { 7519 // Some day maybe we'll break this into top/left/start/etc. and let the 7520 // client control it. Until then, you can have any scroll indicator you 7521 // want as long as it's a 1dp foreground-colored rectangle. 7522 if (mScrollIndicatorDrawable == null) { 7523 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 7524 } 7525 } 7526 7527 /** 7528 * <p> 7529 * Initalizes the scrollability cache if necessary. 7530 * </p> 7531 */ 7532 private void initScrollCache() { 7533 if (mScrollCache == null) { 7534 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 7535 } 7536 } 7537 7538 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 7539 private ScrollabilityCache getScrollCache() { 7540 initScrollCache(); 7541 return mScrollCache; 7542 } 7543 7544 /** 7545 * Set the position of the vertical scroll bar. Should be one of 7546 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 7547 * {@link #SCROLLBAR_POSITION_RIGHT}. 7548 * 7549 * @param position Where the vertical scroll bar should be positioned. 7550 */ 7551 public void setVerticalScrollbarPosition(int position) { 7552 if (mVerticalScrollbarPosition != position) { 7553 mVerticalScrollbarPosition = position; 7554 computeOpaqueFlags(); 7555 resolvePadding(); 7556 } 7557 } 7558 7559 /** 7560 * @return The position where the vertical scroll bar will show, if applicable. 7561 * @see #setVerticalScrollbarPosition(int) 7562 */ 7563 public int getVerticalScrollbarPosition() { 7564 return mVerticalScrollbarPosition; 7565 } 7566 7567 boolean isOnScrollbar(float x, float y) { 7568 if (mScrollCache == null) { 7569 return false; 7570 } 7571 x += getScrollX(); 7572 y += getScrollY(); 7573 final boolean canScrollVertically = 7574 computeVerticalScrollRange() > computeVerticalScrollExtent(); 7575 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden() && canScrollVertically) { 7576 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7577 getVerticalScrollBarBounds(null, touchBounds); 7578 if (touchBounds.contains((int) x, (int) y)) { 7579 return true; 7580 } 7581 } 7582 final boolean canScrollHorizontally = 7583 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 7584 if (isHorizontalScrollBarEnabled() && canScrollHorizontally) { 7585 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7586 getHorizontalScrollBarBounds(null, touchBounds); 7587 if (touchBounds.contains((int) x, (int) y)) { 7588 return true; 7589 } 7590 } 7591 return false; 7592 } 7593 7594 @UnsupportedAppUsage 7595 boolean isOnScrollbarThumb(float x, float y) { 7596 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 7597 } 7598 7599 private boolean isOnVerticalScrollbarThumb(float x, float y) { 7600 if (mScrollCache == null || !isVerticalScrollBarEnabled() || isVerticalScrollBarHidden()) { 7601 return false; 7602 } 7603 final int range = computeVerticalScrollRange(); 7604 final int extent = computeVerticalScrollExtent(); 7605 if (range > extent) { 7606 x += getScrollX(); 7607 y += getScrollY(); 7608 final Rect bounds = mScrollCache.mScrollBarBounds; 7609 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7610 getVerticalScrollBarBounds(bounds, touchBounds); 7611 final int offset = computeVerticalScrollOffset(); 7612 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 7613 extent, range); 7614 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 7615 extent, range, offset); 7616 final int thumbTop = bounds.top + thumbOffset; 7617 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 7618 if (x >= touchBounds.left && x <= touchBounds.right 7619 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 7620 return true; 7621 } 7622 } 7623 return false; 7624 } 7625 7626 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 7627 if (mScrollCache == null || !isHorizontalScrollBarEnabled()) { 7628 return false; 7629 } 7630 final int range = computeHorizontalScrollRange(); 7631 final int extent = computeHorizontalScrollExtent(); 7632 if (range > extent) { 7633 x += getScrollX(); 7634 y += getScrollY(); 7635 final Rect bounds = mScrollCache.mScrollBarBounds; 7636 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7637 getHorizontalScrollBarBounds(bounds, touchBounds); 7638 final int offset = computeHorizontalScrollOffset(); 7639 7640 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 7641 extent, range); 7642 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 7643 extent, range, offset); 7644 final int thumbLeft = bounds.left + thumbOffset; 7645 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 7646 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 7647 && y >= touchBounds.top && y <= touchBounds.bottom) { 7648 return true; 7649 } 7650 } 7651 return false; 7652 } 7653 7654 @UnsupportedAppUsage 7655 boolean isDraggingScrollBar() { 7656 return mScrollCache != null 7657 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 7658 } 7659 7660 /** 7661 * Sets the state of all scroll indicators. 7662 * <p> 7663 * See {@link #setScrollIndicators(int, int)} for usage information. 7664 * 7665 * @param indicators a bitmask of indicators that should be enabled, or 7666 * {@code 0} to disable all indicators 7667 * @see #setScrollIndicators(int, int) 7668 * @see #getScrollIndicators() 7669 * @attr ref android.R.styleable#View_scrollIndicators 7670 */ 7671 @RemotableViewMethod 7672 public void setScrollIndicators(@ScrollIndicators int indicators) { 7673 setScrollIndicators(indicators, 7674 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 7675 } 7676 7677 /** 7678 * Sets the state of the scroll indicators specified by the mask. To change 7679 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 7680 * <p> 7681 * When a scroll indicator is enabled, it will be displayed if the view 7682 * can scroll in the direction of the indicator. 7683 * <p> 7684 * Multiple indicator types may be enabled or disabled by passing the 7685 * logical OR of the desired types. If multiple types are specified, they 7686 * will all be set to the same enabled state. 7687 * <p> 7688 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 7689 * 7690 * @param indicators the indicator direction, or the logical OR of multiple 7691 * indicator directions. One or more of: 7692 * <ul> 7693 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 7694 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 7695 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 7696 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 7697 * <li>{@link #SCROLL_INDICATOR_START}</li> 7698 * <li>{@link #SCROLL_INDICATOR_END}</li> 7699 * </ul> 7700 * @see #setScrollIndicators(int) 7701 * @see #getScrollIndicators() 7702 * @attr ref android.R.styleable#View_scrollIndicators 7703 */ 7704 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 7705 // Shift and sanitize mask. 7706 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7707 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 7708 7709 // Shift and mask indicators. 7710 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7711 indicators &= mask; 7712 7713 // Merge with non-masked flags. 7714 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 7715 7716 if (mPrivateFlags3 != updatedFlags) { 7717 mPrivateFlags3 = updatedFlags; 7718 7719 if (indicators != 0) { 7720 initializeScrollIndicatorsInternal(); 7721 } 7722 invalidate(); 7723 } 7724 } 7725 7726 /** 7727 * Returns a bitmask representing the enabled scroll indicators. 7728 * <p> 7729 * For example, if the top and left scroll indicators are enabled and all 7730 * other indicators are disabled, the return value will be 7731 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 7732 * <p> 7733 * To check whether the bottom scroll indicator is enabled, use the value 7734 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 7735 * 7736 * @return a bitmask representing the enabled scroll indicators 7737 */ 7738 @InspectableProperty(flagMapping = { 7739 @FlagEntry(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"), 7740 @FlagEntry(target = SCROLL_INDICATOR_TOP, name = "top"), 7741 @FlagEntry(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"), 7742 @FlagEntry(target = SCROLL_INDICATOR_LEFT, name = "left"), 7743 @FlagEntry(target = SCROLL_INDICATOR_RIGHT, name = "right"), 7744 @FlagEntry(target = SCROLL_INDICATOR_START, name = "start"), 7745 @FlagEntry(target = SCROLL_INDICATOR_END, name = "end") 7746 }) 7747 @ScrollIndicators 7748 public int getScrollIndicators() { 7749 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 7750 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7751 } 7752 7753 @UnsupportedAppUsage 7754 ListenerInfo getListenerInfo() { 7755 if (mListenerInfo != null) { 7756 return mListenerInfo; 7757 } 7758 mListenerInfo = new ListenerInfo(); 7759 return mListenerInfo; 7760 } 7761 7762 /** 7763 * Register a callback to be invoked when the scroll X or Y positions of 7764 * this view change. 7765 * <p> 7766 * <b>Note:</b> Some views handle scrolling independently from View and may 7767 * have their own separate listeners for scroll-type events. For example, 7768 * {@link android.widget.ListView ListView} allows clients to register an 7769 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 7770 * to listen for changes in list scroll position. 7771 * 7772 * @param l The listener to notify when the scroll X or Y position changes. 7773 * @see android.view.View#getScrollX() 7774 * @see android.view.View#getScrollY() 7775 */ 7776 public void setOnScrollChangeListener(OnScrollChangeListener l) { 7777 getListenerInfo().mOnScrollChangeListener = l; 7778 } 7779 7780 /** 7781 * Register a callback to be invoked when focus of this view changed. 7782 * 7783 * @param l The callback that will run. 7784 */ 7785 public void setOnFocusChangeListener(OnFocusChangeListener l) { 7786 getListenerInfo().mOnFocusChangeListener = l; 7787 } 7788 7789 /** 7790 * Add a listener that will be called when the bounds of the view change due to 7791 * layout processing. 7792 * 7793 * @param listener The listener that will be called when layout bounds change. 7794 */ 7795 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 7796 ListenerInfo li = getListenerInfo(); 7797 if (li.mOnLayoutChangeListeners == null) { 7798 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 7799 } 7800 if (!li.mOnLayoutChangeListeners.contains(listener)) { 7801 li.mOnLayoutChangeListeners.add(listener); 7802 } 7803 } 7804 7805 /** 7806 * Remove a listener for layout changes. 7807 * 7808 * @param listener The listener for layout bounds change. 7809 */ 7810 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 7811 ListenerInfo li = mListenerInfo; 7812 if (li == null || li.mOnLayoutChangeListeners == null) { 7813 return; 7814 } 7815 li.mOnLayoutChangeListeners.remove(listener); 7816 } 7817 7818 /** 7819 * Add a listener for attach state changes. 7820 * 7821 * This listener will be called whenever this view is attached or detached 7822 * from a window. Remove the listener using 7823 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 7824 * 7825 * @param listener Listener to attach 7826 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 7827 */ 7828 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7829 ListenerInfo li = getListenerInfo(); 7830 if (li.mOnAttachStateChangeListeners == null) { 7831 li.mOnAttachStateChangeListeners 7832 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 7833 } 7834 li.mOnAttachStateChangeListeners.add(listener); 7835 } 7836 7837 /** 7838 * Remove a listener for attach state changes. The listener will receive no further 7839 * notification of window attach/detach events. 7840 * 7841 * @param listener Listener to remove 7842 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 7843 */ 7844 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7845 ListenerInfo li = mListenerInfo; 7846 if (li == null || li.mOnAttachStateChangeListeners == null) { 7847 return; 7848 } 7849 li.mOnAttachStateChangeListeners.remove(listener); 7850 } 7851 7852 /** 7853 * Returns the focus-change callback registered for this view. 7854 * 7855 * @return The callback, or null if one is not registered. 7856 */ 7857 public OnFocusChangeListener getOnFocusChangeListener() { 7858 ListenerInfo li = mListenerInfo; 7859 return li != null ? li.mOnFocusChangeListener : null; 7860 } 7861 7862 /** 7863 * Register a callback to be invoked when this view is clicked. If this view is not 7864 * clickable, it becomes clickable. 7865 * 7866 * @param l The callback that will run 7867 * 7868 * @see #setClickable(boolean) 7869 */ 7870 public void setOnClickListener(@Nullable OnClickListener l) { 7871 if (!isClickable()) { 7872 setClickable(true); 7873 } 7874 getListenerInfo().mOnClickListener = l; 7875 } 7876 7877 /** 7878 * Return whether this view has an attached OnClickListener. Returns 7879 * true if there is a listener, false if there is none. 7880 */ 7881 public boolean hasOnClickListeners() { 7882 ListenerInfo li = mListenerInfo; 7883 return (li != null && li.mOnClickListener != null); 7884 } 7885 7886 /** 7887 * Register a callback to be invoked when this view is clicked and held. If this view is not 7888 * long clickable, it becomes long clickable. 7889 * 7890 * @param l The callback that will run 7891 * 7892 * @see #setLongClickable(boolean) 7893 */ 7894 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 7895 if (!isLongClickable()) { 7896 setLongClickable(true); 7897 } 7898 getListenerInfo().mOnLongClickListener = l; 7899 } 7900 7901 /** 7902 * Return whether this view has an attached OnLongClickListener. Returns 7903 * true if there is a listener, false if there is none. 7904 */ 7905 public boolean hasOnLongClickListeners() { 7906 ListenerInfo li = mListenerInfo; 7907 return (li != null && li.mOnLongClickListener != null); 7908 } 7909 7910 /** 7911 * @return the registered {@link OnLongClickListener} if there is one, {@code null} otherwise. 7912 * @hide 7913 */ 7914 @Nullable 7915 public OnLongClickListener getOnLongClickListener() { 7916 ListenerInfo li = mListenerInfo; 7917 return (li != null) ? li.mOnLongClickListener : null; 7918 } 7919 7920 /** 7921 * Register a callback to be invoked when this view is context clicked. If the view is not 7922 * context clickable, it becomes context clickable. 7923 * 7924 * @param l The callback that will run 7925 * @see #setContextClickable(boolean) 7926 */ 7927 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 7928 if (!isContextClickable()) { 7929 setContextClickable(true); 7930 } 7931 getListenerInfo().mOnContextClickListener = l; 7932 } 7933 7934 /** 7935 * Register a callback to be invoked when the context menu for this view is 7936 * being built. If this view is not long clickable, it becomes long clickable. 7937 * 7938 * @param l The callback that will run 7939 * 7940 */ 7941 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 7942 if (!isLongClickable()) { 7943 setLongClickable(true); 7944 } 7945 getListenerInfo().mOnCreateContextMenuListener = l; 7946 } 7947 7948 /** 7949 * Set an observer to collect stats for each frame rendered for this view. 7950 * 7951 * @hide 7952 */ 7953 public void addFrameMetricsListener(Window window, 7954 Window.OnFrameMetricsAvailableListener listener, 7955 Handler handler) { 7956 if (mAttachInfo != null) { 7957 if (mAttachInfo.mThreadedRenderer != null) { 7958 if (mFrameMetricsObservers == null) { 7959 mFrameMetricsObservers = new ArrayList<>(); 7960 } 7961 7962 FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); 7963 mFrameMetricsObservers.add(fmo); 7964 mAttachInfo.mThreadedRenderer.addObserver(fmo.getRendererObserver()); 7965 } else { 7966 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7967 } 7968 } else { 7969 if (mFrameMetricsObservers == null) { 7970 mFrameMetricsObservers = new ArrayList<>(); 7971 } 7972 7973 FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); 7974 mFrameMetricsObservers.add(fmo); 7975 } 7976 } 7977 7978 /** 7979 * Remove observer configured to collect frame stats for this view. 7980 * 7981 * @hide 7982 */ 7983 public void removeFrameMetricsListener( 7984 Window.OnFrameMetricsAvailableListener listener) { 7985 ThreadedRenderer renderer = getThreadedRenderer(); 7986 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 7987 if (fmo == null) { 7988 throw new IllegalArgumentException( 7989 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 7990 } 7991 7992 if (mFrameMetricsObservers != null) { 7993 mFrameMetricsObservers.remove(fmo); 7994 if (renderer != null) { 7995 renderer.removeObserver(fmo.getRendererObserver()); 7996 } 7997 } 7998 } 7999 8000 private void registerPendingFrameMetricsObservers() { 8001 if (mFrameMetricsObservers != null) { 8002 ThreadedRenderer renderer = getThreadedRenderer(); 8003 if (renderer != null) { 8004 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 8005 renderer.addObserver(fmo.getRendererObserver()); 8006 } 8007 } else { 8008 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 8009 } 8010 } 8011 } 8012 8013 private FrameMetricsObserver findFrameMetricsObserver( 8014 Window.OnFrameMetricsAvailableListener listener) { 8015 if (mFrameMetricsObservers != null) { 8016 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 8017 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 8018 if (observer.mListener == listener) { 8019 return observer; 8020 } 8021 } 8022 } 8023 8024 return null; 8025 } 8026 8027 /** @hide */ 8028 public void setNotifyAutofillManagerOnClick(boolean notify) { 8029 if (notify) { 8030 mPrivateFlags |= PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 8031 } else { 8032 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 8033 } 8034 } 8035 8036 private void notifyAutofillManagerOnClick() { 8037 if ((mPrivateFlags & PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK) != 0) { 8038 try { 8039 getAutofillManager().notifyViewClicked(this); 8040 } finally { 8041 // Set it to already called so it's not called twice when called by 8042 // performClickInternal() 8043 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 8044 } 8045 } 8046 } 8047 8048 /** 8049 * Entry point for {@link #performClick()} - other methods on View should call it instead of 8050 * {@code performClick()} directly to make sure the autofill manager is notified when 8051 * necessary (as subclasses could extend {@code performClick()} without calling the parent's 8052 * method). 8053 */ 8054 private boolean performClickInternal() { 8055 // Must notify autofill manager before performing the click actions to avoid scenarios where 8056 // the app has a click listener that changes the state of views the autofill service might 8057 // be interested on. 8058 notifyAutofillManagerOnClick(); 8059 8060 return performClick(); 8061 } 8062 8063 /** 8064 * Call this view's OnClickListener, if it is defined. Performs all normal 8065 * actions associated with clicking: reporting accessibility event, playing 8066 * a sound, etc. 8067 * 8068 * @return True there was an assigned OnClickListener that was called, false 8069 * otherwise is returned. 8070 */ 8071 // NOTE: other methods on View should not call this method directly, but performClickInternal() 8072 // instead, to guarantee that the autofill manager is notified when necessary (as subclasses 8073 // could extend this method without calling super.performClick()). 8074 public boolean performClick() { 8075 // We still need to call this method to handle the cases where performClick() was called 8076 // externally, instead of through performClickInternal() 8077 notifyAutofillManagerOnClick(); 8078 8079 final boolean result; 8080 final ListenerInfo li = mListenerInfo; 8081 if (li != null && li.mOnClickListener != null) { 8082 playSoundEffect(SoundEffectConstants.CLICK); 8083 li.mOnClickListener.onClick(this); 8084 result = true; 8085 } else { 8086 result = false; 8087 } 8088 8089 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 8090 8091 notifyEnterOrExitForAutoFillIfNeeded(true); 8092 8093 return result; 8094 } 8095 8096 /** 8097 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 8098 * this only calls the listener, and does not do any associated clicking 8099 * actions like reporting an accessibility event. 8100 * 8101 * @return True there was an assigned OnClickListener that was called, false 8102 * otherwise is returned. 8103 */ 8104 public boolean callOnClick() { 8105 ListenerInfo li = mListenerInfo; 8106 if (li != null && li.mOnClickListener != null) { 8107 li.mOnClickListener.onClick(this); 8108 return true; 8109 } 8110 return false; 8111 } 8112 8113 /** 8114 * Calls this view's OnLongClickListener, if it is defined. Invokes the 8115 * context menu if the OnLongClickListener did not consume the event. 8116 * 8117 * @return {@code true} if one of the above receivers consumed the event, 8118 * {@code false} otherwise 8119 */ 8120 public boolean performLongClick() { 8121 return performLongClickInternal(mLongClickX, mLongClickY); 8122 } 8123 8124 /** 8125 * Calls this view's OnLongClickListener, if it is defined. Invokes the 8126 * context menu if the OnLongClickListener did not consume the event, 8127 * anchoring it to an (x,y) coordinate. 8128 * 8129 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 8130 * to disable anchoring 8131 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 8132 * to disable anchoring 8133 * @return {@code true} if one of the above receivers consumed the event, 8134 * {@code false} otherwise 8135 */ 8136 public boolean performLongClick(float x, float y) { 8137 mLongClickX = x; 8138 mLongClickY = y; 8139 final boolean handled = performLongClick(); 8140 mLongClickX = Float.NaN; 8141 mLongClickY = Float.NaN; 8142 return handled; 8143 } 8144 8145 /** 8146 * Calls this view's OnLongClickListener, if it is defined. Invokes the 8147 * context menu if the OnLongClickListener did not consume the event, 8148 * optionally anchoring it to an (x,y) coordinate. 8149 * 8150 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 8151 * to disable anchoring 8152 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 8153 * to disable anchoring 8154 * @return {@code true} if one of the above receivers consumed the event, 8155 * {@code false} otherwise 8156 */ 8157 private boolean performLongClickInternal(float x, float y) { 8158 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 8159 8160 boolean handled = false; 8161 final OnLongClickListener listener = 8162 mListenerInfo == null ? null : mListenerInfo.mOnLongClickListener; 8163 boolean shouldPerformHapticFeedback = true; 8164 if (listener != null) { 8165 handled = listener.onLongClick(View.this); 8166 if (handled) { 8167 shouldPerformHapticFeedback = listener.onLongClickUseDefaultHapticFeedback( 8168 View.this); 8169 } 8170 } 8171 if (!handled) { 8172 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 8173 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 8174 } 8175 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 8176 if (!handled) { 8177 handled = showLongClickTooltip((int) x, (int) y); 8178 } 8179 } 8180 if (handled && shouldPerformHapticFeedback) { 8181 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 8182 } 8183 return handled; 8184 } 8185 8186 /** 8187 * Call this view's OnContextClickListener, if it is defined. 8188 * 8189 * @param x the x coordinate of the context click 8190 * @param y the y coordinate of the context click 8191 * @return True if there was an assigned OnContextClickListener that consumed the event, false 8192 * otherwise. 8193 */ 8194 public boolean performContextClick(float x, float y) { 8195 return performContextClick(); 8196 } 8197 8198 /** 8199 * Call this view's OnContextClickListener, if it is defined. 8200 * 8201 * @return True if there was an assigned OnContextClickListener that consumed the event, false 8202 * otherwise. 8203 */ 8204 public boolean performContextClick() { 8205 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 8206 8207 boolean handled = false; 8208 ListenerInfo li = mListenerInfo; 8209 if (li != null && li.mOnContextClickListener != null) { 8210 handled = li.mOnContextClickListener.onContextClick(View.this); 8211 } 8212 if (handled) { 8213 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 8214 } 8215 return handled; 8216 } 8217 8218 /** 8219 * Performs button-related actions during a touch down event. 8220 * 8221 * @param event The event. 8222 * @return True if the down was consumed. 8223 * 8224 * @hide 8225 */ 8226 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 8227 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 8228 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 8229 showContextMenu(event.getX(), event.getY()); 8230 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 8231 return true; 8232 } 8233 return false; 8234 } 8235 8236 /** 8237 * Shows the context menu for this view. 8238 * 8239 * @return {@code true} if the context menu was shown, {@code false} 8240 * otherwise 8241 * @see #showContextMenu(float, float) 8242 */ 8243 public boolean showContextMenu() { 8244 return getParent().showContextMenuForChild(this); 8245 } 8246 8247 /** 8248 * Shows the context menu for this view anchored to the specified 8249 * view-relative coordinate. 8250 * 8251 * @param x the X coordinate in pixels relative to the view to which the 8252 * menu should be anchored, or {@link Float#NaN} to disable anchoring 8253 * @param y the Y coordinate in pixels relative to the view to which the 8254 * menu should be anchored, or {@link Float#NaN} to disable anchoring 8255 * @return {@code true} if the context menu was shown, {@code false} 8256 * otherwise 8257 */ 8258 public boolean showContextMenu(float x, float y) { 8259 return getParent().showContextMenuForChild(this, x, y); 8260 } 8261 8262 /** 8263 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 8264 * 8265 * @param callback Callback that will control the lifecycle of the action mode 8266 * @return The new action mode if it is started, null otherwise 8267 * 8268 * @see ActionMode 8269 * @see #startActionMode(android.view.ActionMode.Callback, int) 8270 */ 8271 public ActionMode startActionMode(ActionMode.Callback callback) { 8272 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 8273 } 8274 8275 /** 8276 * Start an action mode with the given type. 8277 * 8278 * @param callback Callback that will control the lifecycle of the action mode 8279 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 8280 * @return The new action mode if it is started, null otherwise 8281 * 8282 * @see ActionMode 8283 */ 8284 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 8285 ViewParent parent = getParent(); 8286 if (parent == null) return null; 8287 try { 8288 return parent.startActionModeForChild(this, callback, type); 8289 } catch (AbstractMethodError ame) { 8290 // Older implementations of custom views might not implement this. 8291 return parent.startActionModeForChild(this, callback); 8292 } 8293 } 8294 8295 /** 8296 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 8297 * Context, creating a unique View identifier to retrieve the result. 8298 * 8299 * @param intent The Intent to be started. 8300 * @param requestCode The request code to use. 8301 * @hide 8302 */ 8303 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 8304 public void startActivityForResult(Intent intent, int requestCode) { 8305 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 8306 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 8307 } 8308 8309 /** 8310 * If this View corresponds to the calling who, dispatches the activity result. 8311 * @param who The identifier for the targeted View to receive the result. 8312 * @param requestCode The integer request code originally supplied to 8313 * startActivityForResult(), allowing you to identify who this 8314 * result came from. 8315 * @param resultCode The integer result code returned by the child activity 8316 * through its setResult(). 8317 * @param data An Intent, which can return result data to the caller 8318 * (various data can be attached to Intent "extras"). 8319 * @return {@code true} if the activity result was dispatched. 8320 * @hide 8321 */ 8322 public boolean dispatchActivityResult( 8323 String who, int requestCode, int resultCode, Intent data) { 8324 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 8325 onActivityResult(requestCode, resultCode, data); 8326 mStartActivityRequestWho = null; 8327 return true; 8328 } 8329 return false; 8330 } 8331 8332 /** 8333 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 8334 * 8335 * @param requestCode The integer request code originally supplied to 8336 * startActivityForResult(), allowing you to identify who this 8337 * result came from. 8338 * @param resultCode The integer result code returned by the child activity 8339 * through its setResult(). 8340 * @param data An Intent, which can return result data to the caller 8341 * (various data can be attached to Intent "extras"). 8342 * @hide 8343 */ 8344 public void onActivityResult(int requestCode, int resultCode, Intent data) { 8345 // Do nothing. 8346 } 8347 8348 /** 8349 * Register a callback to be invoked when a hardware key is pressed in this view. 8350 * Key presses in software input methods will generally not trigger the methods of 8351 * this listener. 8352 * @param l the key listener to attach to this view 8353 */ 8354 public void setOnKeyListener(OnKeyListener l) { 8355 getListenerInfo().mOnKeyListener = l; 8356 } 8357 8358 /** 8359 * Register a callback to be invoked when a touch event is sent to this view. 8360 * @param l the touch listener to attach to this view 8361 */ 8362 public void setOnTouchListener(OnTouchListener l) { 8363 getListenerInfo().mOnTouchListener = l; 8364 } 8365 8366 /** 8367 * Register a callback to be invoked when a generic motion event is sent to this view. 8368 * @param l the generic motion listener to attach to this view 8369 */ 8370 public void setOnGenericMotionListener(OnGenericMotionListener l) { 8371 getListenerInfo().mOnGenericMotionListener = l; 8372 } 8373 8374 /** 8375 * Register a callback to be invoked when a hover event is sent to this view. 8376 * @param l the hover listener to attach to this view 8377 */ 8378 public void setOnHoverListener(OnHoverListener l) { 8379 getListenerInfo().mOnHoverListener = l; 8380 } 8381 8382 /** 8383 * Register a drag event listener callback object for this View. The parameter is 8384 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 8385 * View, the system calls the 8386 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 8387 * @param l An implementation of {@link android.view.View.OnDragListener}. 8388 */ 8389 public void setOnDragListener(OnDragListener l) { 8390 getListenerInfo().mOnDragListener = l; 8391 } 8392 8393 /** 8394 * Give this view focus. This will cause 8395 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 8396 * 8397 * Note: this does not check whether this {@link View} should get focus, it just 8398 * gives it focus no matter what. It should only be called internally by framework 8399 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 8400 * 8401 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 8402 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 8403 * focus moved when requestFocus() is called. It may not always 8404 * apply, in which case use the default View.FOCUS_DOWN. 8405 * @param previouslyFocusedRect The rectangle of the view that had focus 8406 * prior in this View's coordinate system. 8407 */ 8408 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 8409 if (DBG) { 8410 System.out.println(this + " requestFocus()"); 8411 } 8412 8413 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 8414 mPrivateFlags |= PFLAG_FOCUSED; 8415 8416 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 8417 8418 if (mParent != null) { 8419 mParent.requestChildFocus(this, this); 8420 updateFocusedInCluster(oldFocus, direction); 8421 } 8422 8423 if (mAttachInfo != null) { 8424 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 8425 } 8426 8427 onFocusChanged(true, direction, previouslyFocusedRect); 8428 refreshDrawableState(); 8429 } 8430 } 8431 8432 /** 8433 * Sets this view's preference for reveal behavior when it gains focus. 8434 * 8435 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 8436 * this view would prefer to be brought fully into view when it gains focus. 8437 * For example, a text field that a user is meant to type into. Other views such 8438 * as scrolling containers may prefer to opt-out of this behavior.</p> 8439 * 8440 * <p>The default value for views is true, though subclasses may change this 8441 * based on their preferred behavior.</p> 8442 * 8443 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 8444 * 8445 * @see #getRevealOnFocusHint() 8446 */ 8447 public final void setRevealOnFocusHint(boolean revealOnFocus) { 8448 if (revealOnFocus) { 8449 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 8450 } else { 8451 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 8452 } 8453 } 8454 8455 /** 8456 * Returns this view's preference for reveal behavior when it gains focus. 8457 * 8458 * <p>When this method returns true for a child view requesting focus, ancestor 8459 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 8460 * should make a best effort to make the newly focused child fully visible to the user. 8461 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 8462 * other properties affecting visibility to the user as part of the focus change.</p> 8463 * 8464 * @return true if this view would prefer to become fully visible when it gains focus, 8465 * false if it would prefer not to disrupt scroll positioning 8466 * 8467 * @see #setRevealOnFocusHint(boolean) 8468 */ 8469 public final boolean getRevealOnFocusHint() { 8470 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 8471 } 8472 8473 /** 8474 * Populates <code>outRect</code> with the hotspot bounds. By default, 8475 * the hotspot bounds are identical to the screen bounds. 8476 * 8477 * @param outRect rect to populate with hotspot bounds 8478 * @hide Only for internal use by views and widgets. 8479 */ 8480 public void getHotspotBounds(Rect outRect) { 8481 final Drawable background = getBackground(); 8482 if (background != null) { 8483 background.getHotspotBounds(outRect); 8484 } else { 8485 getBoundsOnScreen(outRect); 8486 } 8487 } 8488 8489 /** 8490 * Request that a rectangle of this view be visible on the screen, 8491 * scrolling if necessary just enough. 8492 * 8493 * <p>A View should call this if it maintains some notion of which part 8494 * of its content is interesting. For example, a text editing view 8495 * should call this when its cursor moves. 8496 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 8497 * It should not be affected by which part of the View is currently visible or its scroll 8498 * position. 8499 * 8500 * @param rectangle The rectangle in the View's content coordinate space 8501 * @return Whether any parent scrolled. 8502 * @see AccessibilityAction#ACTION_SHOW_ON_SCREEN 8503 */ 8504 public boolean requestRectangleOnScreen(Rect rectangle) { 8505 return requestRectangleOnScreen(rectangle, false); 8506 } 8507 8508 /** 8509 * Request that a rectangle of this view be visible on the screen, 8510 * scrolling if necessary just enough. 8511 * 8512 * <p>A View should call this if it maintains some notion of which part 8513 * of its content is interesting. For example, a text editing view 8514 * should call this when its cursor moves. 8515 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 8516 * It should not be affected by which part of the View is currently visible or its scroll 8517 * position. 8518 * <p>When <code>immediate</code> is set to true, scrolling will not be 8519 * animated. 8520 * 8521 * @param rectangle The rectangle in the View's content coordinate space 8522 * @param immediate True to forbid animated scrolling, false otherwise 8523 * @return Whether any parent scrolled. 8524 */ 8525 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 8526 if (mParent == null) { 8527 return false; 8528 } 8529 8530 View child = this; 8531 8532 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 8533 position.set(rectangle); 8534 8535 ViewParent parent = mParent; 8536 boolean scrolled = false; 8537 while (parent != null) { 8538 rectangle.set((int) position.left, (int) position.top, 8539 (int) position.right, (int) position.bottom); 8540 8541 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 8542 8543 if (!(parent instanceof View)) { 8544 break; 8545 } 8546 8547 // move it from child's content coordinate space to parent's content coordinate space 8548 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 8549 8550 child = (View) parent; 8551 parent = child.getParent(); 8552 } 8553 8554 return scrolled; 8555 } 8556 8557 /** 8558 * Called when this view wants to give up focus. If focus is cleared 8559 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 8560 * <p> 8561 * <strong>Note:</strong> When not in touch-mode, the framework will try to give focus 8562 * to the first focusable View from the top after focus is cleared. Hence, if this 8563 * View is the first from the top that can take focus, then all callbacks 8564 * related to clearing focus will be invoked after which the framework will 8565 * give focus to this view. 8566 * </p> 8567 */ 8568 public void clearFocus() { 8569 if (DBG) { 8570 System.out.println(this + " clearFocus()"); 8571 } 8572 8573 final boolean refocus = sAlwaysAssignFocus || !isInTouchMode(); 8574 clearFocusInternal(null, true, refocus); 8575 } 8576 8577 /** 8578 * Clears focus from the view, optionally propagating the change up through 8579 * the parent hierarchy and requesting that the root view place new focus. 8580 * 8581 * @param propagate whether to propagate the change up through the parent 8582 * hierarchy 8583 * @param refocus when propagate is true, specifies whether to request the 8584 * root view place new focus 8585 * @hide 8586 */ 8587 public void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 8588 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 8589 mPrivateFlags &= ~PFLAG_FOCUSED; 8590 clearParentsWantFocus(); 8591 8592 if (propagate && mParent != null) { 8593 mParent.clearChildFocus(this); 8594 } 8595 8596 onFocusChanged(false, 0, null); 8597 refreshDrawableState(); 8598 8599 if (propagate && (!refocus || !rootViewRequestFocus())) { 8600 notifyGlobalFocusCleared(this); 8601 } 8602 } 8603 } 8604 8605 void notifyGlobalFocusCleared(View oldFocus) { 8606 if (oldFocus != null && mAttachInfo != null) { 8607 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 8608 } 8609 } 8610 8611 boolean rootViewRequestFocus() { 8612 final View root = getRootView(); 8613 return root != null && root.requestFocus(); 8614 } 8615 8616 /** 8617 * Called internally by the view system when a new view is getting focus. 8618 * This is what clears the old focus. 8619 * <p> 8620 * <b>NOTE:</b> The parent view's focused child must be updated manually 8621 * after calling this method. Otherwise, the view hierarchy may be left in 8622 * an inconstent state. 8623 */ 8624 void unFocus(View focused) { 8625 if (DBG) { 8626 System.out.println(this + " unFocus()"); 8627 } 8628 8629 clearFocusInternal(focused, false, false); 8630 } 8631 8632 /** 8633 * Returns true if this view has focus itself, or is the ancestor of the 8634 * view that has focus. 8635 * 8636 * @return True if this view has or contains focus, false otherwise. 8637 */ 8638 @ViewDebug.ExportedProperty(category = "focus") 8639 public boolean hasFocus() { 8640 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 8641 } 8642 8643 /** 8644 * Returns true if this view is focusable or if it contains a reachable View 8645 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 8646 * is a view whose parents do not block descendants focus. 8647 * Only {@link #VISIBLE} views are considered focusable. 8648 * 8649 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 8650 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 8651 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 8652 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 8653 * {@code false} for views not explicitly marked as focusable. 8654 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 8655 * behavior.</p> 8656 * 8657 * @return {@code true} if the view is focusable or if the view contains a focusable 8658 * view, {@code false} otherwise 8659 * 8660 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 8661 * @see ViewGroup#getTouchscreenBlocksFocus() 8662 * @see #hasExplicitFocusable() 8663 */ 8664 public boolean hasFocusable() { 8665 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 8666 } 8667 8668 /** 8669 * Returns true if this view is focusable or if it contains a reachable View 8670 * for which {@link #hasExplicitFocusable()} returns {@code true}. 8671 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 8672 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 8673 * {@link #FOCUSABLE} are considered focusable. 8674 * 8675 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 8676 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 8677 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 8678 * to focusable will not.</p> 8679 * 8680 * @return {@code true} if the view is focusable or if the view contains a focusable 8681 * view, {@code false} otherwise 8682 * 8683 * @see #hasFocusable() 8684 */ 8685 public boolean hasExplicitFocusable() { 8686 return hasFocusable(false, true); 8687 } 8688 8689 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 8690 if (!isFocusableInTouchMode()) { 8691 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 8692 final ViewGroup g = (ViewGroup) p; 8693 if (g.shouldBlockFocusForTouchscreen()) { 8694 return false; 8695 } 8696 } 8697 } 8698 8699 // Invisible, gone, or disabled views are never focusable. 8700 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE 8701 || (mViewFlags & ENABLED_MASK) != ENABLED) { 8702 return false; 8703 } 8704 8705 // Only use effective focusable value when allowed. 8706 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 8707 return true; 8708 } 8709 8710 return false; 8711 } 8712 8713 /** 8714 * Called by the view system when the focus state of this view changes. 8715 * When the focus change event is caused by directional navigation, direction 8716 * and previouslyFocusedRect provide insight into where the focus is coming from. 8717 * When overriding, be sure to call up through to the super class so that 8718 * the standard focus handling will occur. 8719 * 8720 * @param gainFocus True if the View has focus; false otherwise. 8721 * @param direction The direction focus has moved when requestFocus() 8722 * is called to give this view focus. Values are 8723 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 8724 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 8725 * It may not always apply, in which case use the default. 8726 * @param previouslyFocusedRect The rectangle, in this view's coordinate 8727 * system, of the previously focused view. If applicable, this will be 8728 * passed in as finer grained information about where the focus is coming 8729 * from (in addition to direction). Will be <code>null</code> otherwise. 8730 */ 8731 @CallSuper 8732 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 8733 @Nullable Rect previouslyFocusedRect) { 8734 if (DBG) { 8735 Log.d(VIEW_LOG_TAG, "onFocusChanged() entered. gainFocus: " 8736 + gainFocus); 8737 } 8738 if (gainFocus) { 8739 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 8740 } else { 8741 notifyViewAccessibilityStateChangedIfNeeded( 8742 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8743 } 8744 8745 // Here we check whether we still need the default focus highlight, and switch it on/off. 8746 switchDefaultFocusHighlight(); 8747 8748 if (!gainFocus) { 8749 if (isPressed()) { 8750 setPressed(false); 8751 } 8752 if (hasWindowFocus()) { 8753 notifyFocusChangeToImeFocusController(false /* hasFocus */); 8754 } 8755 onFocusLost(); 8756 } else if (hasWindowFocus()) { 8757 notifyFocusChangeToImeFocusController(true /* hasFocus */); 8758 ViewRootImpl viewRoot = getViewRootImpl(); 8759 if (viewRoot != null) { 8760 if (mIsHandwritingDelegate) { 8761 viewRoot.getHandwritingInitiator().onDelegateViewFocused(this); 8762 } else if (initiationWithoutInputConnection() && onCheckIsTextEditor()) { 8763 viewRoot.getHandwritingInitiator().onEditorFocused(this); 8764 } 8765 } 8766 } 8767 8768 invalidate(true); 8769 ListenerInfo li = mListenerInfo; 8770 if (li != null && li.mOnFocusChangeListener != null) { 8771 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 8772 } 8773 8774 if (mAttachInfo != null) { 8775 mAttachInfo.mKeyDispatchState.reset(this); 8776 } 8777 8778 if (mParent != null) { 8779 mParent.onDescendantUnbufferedRequested(); 8780 } 8781 8782 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 8783 updatePreferKeepClearForFocus(); 8784 } 8785 8786 /** 8787 * Notify {@link ImeFocusController} about the focus change of the {@link View}. 8788 * 8789 * @param hasFocus {@code true} when the {@link View} is being focused. 8790 */ 8791 private void notifyFocusChangeToImeFocusController(boolean hasFocus) { 8792 if (mAttachInfo == null) { 8793 return; 8794 } 8795 mAttachInfo.mViewRootImpl.getImeFocusController().onViewFocusChanged(this, hasFocus); 8796 } 8797 8798 /** @hide */ 8799 public void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 8800 if (canNotifyAutofillEnterExitEvent()) { 8801 AutofillManager afm = getAutofillManager(); 8802 if (afm != null) { 8803 if (DBG) { 8804 Log.d(VIEW_LOG_TAG, this + " afm is not null"); 8805 } 8806 if (enter) { 8807 // We have not been laid out yet, hence cannot evaluate 8808 // whether this view is visible to the user, we will do 8809 // the evaluation once layout is complete. 8810 // Sometimes, views are already laid out, but it's still 8811 // not visible to the user, we also do the evaluation once 8812 // the view is visible. ex: There is a fade-in animation 8813 // for the activity, the view will be laid out when the 8814 // animation beginning. On the time, the view is not visible 8815 // to the user. And then as the animation progresses, the view 8816 // becomes visible to the user. 8817 if (DBG) { 8818 Log.d(VIEW_LOG_TAG, 8819 "notifyEnterOrExitForAutoFillIfNeeded:" 8820 + " isLaidOut(): " + isLaidOut() 8821 + " isVisibleToUser(): " + isVisibleToUser() 8822 + " isFocused(): " + isFocused()); 8823 } 8824 if (!isLaidOut() || !isVisibleToUser()) { 8825 mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 8826 } else if (isVisibleToUser()) { 8827 if (isFocused()) { 8828 // TODO This is a potential problem that View gets focus before it's 8829 // visible to User. Ideally View should handle the event when 8830 // isVisibleToUser() becomes true where it should issue 8831 // notifyViewEntered(). 8832 afm.notifyViewEntered(this); 8833 } else { 8834 afm.notifyViewEnteredForFillDialog(this); 8835 } 8836 } 8837 } else if (!isFocused()) { 8838 afm.notifyViewExited(this); 8839 } 8840 } 8841 } 8842 } 8843 8844 /** 8845 * Visually distinct portion of a window with window-like semantics are considered panes for 8846 * accessibility purposes. One example is the content view of a large fragment that is replaced. 8847 * In order for accessibility services to understand a pane's window-like behavior, panes 8848 * should have descriptive titles. Views with pane titles produce 8849 * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}s when they appear, disappear, or change 8850 * title. 8851 * 8852 * <p> 8853 * When transitioning from one Activity to another, instead of using 8854 * {@code setAccessibilityPaneTitle()}, set a descriptive title for its window by using 8855 * {@code android:label} 8856 * for the matching Activity entry in your application's manifest or updating the title at 8857 * runtime with {@link android.app.Activity#setTitle(CharSequence)}. 8858 * 8859 * <p> 8860 * <aside> 8861 * <b>Note:</b> Use 8862 * {@link androidx.core.view.ViewCompat#setAccessibilityPaneTitle(View, CharSequence)} 8863 * for backwards-compatibility. 8864 * </aside> 8865 * @param accessibilityPaneTitle The pane's title. Setting to {@code null} indicates that this 8866 * View is not a pane. 8867 * 8868 * {@see AccessibilityNodeInfo#setPaneTitle(CharSequence)} 8869 * 8870 * @attr ref android.R.styleable#View_accessibilityPaneTitle 8871 */ 8872 public void setAccessibilityPaneTitle(@Nullable CharSequence accessibilityPaneTitle) { 8873 if (!TextUtils.equals(accessibilityPaneTitle, mAccessibilityPaneTitle)) { 8874 boolean currentPaneTitleEmpty = mAccessibilityPaneTitle == null; 8875 boolean newPaneTitleEmpty = accessibilityPaneTitle == null; 8876 mAccessibilityPaneTitle = accessibilityPaneTitle; 8877 // Make explicitly important as nulled titles need to be important for DISAPPEARED 8878 // events. 8879 if (mAccessibilityPaneTitle != null 8880 && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 8881 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 8882 } 8883 if (currentPaneTitleEmpty) { 8884 notifyViewAccessibilityStateChangedIfNeeded( 8885 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED); 8886 } else if (newPaneTitleEmpty) { 8887 notifyViewAccessibilityStateChangedIfNeeded( 8888 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); 8889 } else { 8890 notifyViewAccessibilityStateChangedIfNeeded( 8891 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE); 8892 } 8893 } 8894 } 8895 8896 /** 8897 * Get the title of the pane for purposes of accessibility. 8898 * 8899 * @return The current pane title. 8900 * 8901 * {@see #setAccessibilityPaneTitle}. 8902 * 8903 * @attr ref android.R.styleable#View_accessibilityPaneTitle 8904 */ 8905 @InspectableProperty 8906 @Nullable 8907 public CharSequence getAccessibilityPaneTitle() { 8908 return mAccessibilityPaneTitle; 8909 } 8910 8911 private boolean isAccessibilityPane() { 8912 return mAccessibilityPaneTitle != null; 8913 } 8914 8915 /** 8916 * Sends an accessibility event of the given type. If accessibility is 8917 * not enabled this method has no effect. The default implementation calls 8918 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 8919 * to populate information about the event source (this View), then calls 8920 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 8921 * populate the text content of the event source including its descendants, 8922 * then for events type {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} 8923 * and {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} with 8924 * subtype {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_STATE_DESCRIPTION}, 8925 * throttle the events, and last calls 8926 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 8927 * on its parent to request sending of the event to interested parties. 8928 * <p> 8929 * If an {@link AccessibilityDelegate} has been specified via calling 8930 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8931 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 8932 * responsible for handling this call. 8933 * </p> 8934 * <p> 8935 * If this view uses {@link AccessibilityNodeProvider} to provide virtual view hierarchy rooted 8936 * at this view, this method should not be called to send events from virtual children because 8937 * it will populate the events with wrong information and the events should be throttled per 8938 * child instead at the virtual root level. To send events from virtual children, call 8939 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} on the view's 8940 * parent to request sending of the event to interested parties. 8941 * </p> 8942 * 8943 * @param eventType The type of the event to send, as defined by several types from 8944 * {@link AccessibilityEvent}, such as 8945 * {@link AccessibilityEvent#TYPE_VIEW_CLICKED} or 8946 * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 8947 * 8948 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 8949 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8950 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 8951 * @see AccessibilityDelegate 8952 */ 8953 public void sendAccessibilityEvent(int eventType) { 8954 if (mAccessibilityDelegate != null) { 8955 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 8956 } else { 8957 sendAccessibilityEventInternal(eventType); 8958 } 8959 } 8960 8961 /** 8962 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} {@link 8963 * AccessibilityEvent} to suggest that an accessibility service announce the specified text to 8964 * its users. 8965 * 8966 * <p>Note: The event generated with this API carries no semantic meaning, and accessibility 8967 * services may choose to ignore it. Apps that accurately supply accessibility with the 8968 * semantics of their UI should not need to specify what exactly is announced. 8969 * 8970 * <p>In general, do not attempt to generate announcements as confirmation message for simple 8971 * actions like a button press. Label your controls concisely and precisely instead. 8972 * 8973 * <p>To convey significant UI changes like window changes, use {@link 8974 * android.app.Activity#setTitle(CharSequence)} and {@link 8975 * #setAccessibilityPaneTitle(CharSequence)}. 8976 * 8977 * <p>Use {@link #setAccessibilityLiveRegion(int)} to inform the user of changes to critical 8978 * views within the user interface. These should still be used sparingly as they may generate 8979 * announcements every time a View is updated. 8980 * 8981 * <p>Use {@link #setStateDescription(CharSequence)} to convey state changes to views within the 8982 * user interface. While a live region may send different types of events generated by the view, 8983 * state description will send {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events of 8984 * type {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_STATE_DESCRIPTION}. 8985 * 8986 * <p>For notifying users about errors, such as in a login screen with text that displays an 8987 * "incorrect password" notification, set {@link AccessibilityNodeInfo#setError(CharSequence)} 8988 * and dispatch an {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} event with a change 8989 * type of {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_ERROR}, instead. Some widgets may 8990 * expose methods that convey error states to accessibility automatically, such as {@link 8991 * android.widget.TextView#setError(CharSequence)}, which manages these accessibility semantics 8992 * and event dispatch for callers. 8993 * 8994 * @deprecated Use one of the methods described in the documentation above to semantically 8995 * describe UI instead of using an announcement, as accessibility services may choose to 8996 * ignore events dispatched with this method. 8997 * @param text The announcement text. 8998 */ 8999 @FlaggedApi(FLAG_DEPRECATE_ACCESSIBILITY_ANNOUNCEMENT_APIS) 9000 @Deprecated 9001 public void announceForAccessibility(CharSequence text) { 9002 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 9003 AccessibilityEvent event = AccessibilityEvent.obtain( 9004 AccessibilityEvent.TYPE_ANNOUNCEMENT); 9005 onInitializeAccessibilityEvent(event); 9006 event.getText().add(text); 9007 event.setContentDescription(null); 9008 mParent.requestSendAccessibilityEvent(this, event); 9009 } 9010 } 9011 9012 /** 9013 * @see #sendAccessibilityEvent(int) 9014 * 9015 * Note: Called from the default {@link AccessibilityDelegate}. 9016 * 9017 * @hide 9018 */ 9019 public void sendAccessibilityEventInternal(int eventType) { 9020 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 9021 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 9022 } 9023 } 9024 9025 /** 9026 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 9027 * takes as an argument an empty {@link AccessibilityEvent} and does not 9028 * perform a check whether accessibility is enabled. 9029 * <p> 9030 * If an {@link AccessibilityDelegate} has been specified via calling 9031 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 9032 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 9033 * is responsible for handling this call. 9034 * </p> 9035 * 9036 * @param event The event to send. 9037 * 9038 * @see #sendAccessibilityEvent(int) 9039 */ 9040 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 9041 if (mAccessibilityDelegate != null) { 9042 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 9043 } else { 9044 sendAccessibilityEventUncheckedInternal(event); 9045 } 9046 } 9047 9048 /** 9049 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 9050 * 9051 * Note: Called from the default {@link AccessibilityDelegate}. 9052 * 9053 * @hide 9054 */ 9055 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 9056 // Panes disappearing are relevant even if though the view is no longer visible. 9057 boolean isWindowStateChanged = 9058 (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 9059 boolean isWindowDisappearedEvent = isWindowStateChanged && ((event.getContentChangeTypes() 9060 & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) != 0); 9061 boolean detached = detached(); 9062 if (!isShown() && !isWindowDisappearedEvent && !detached) { 9063 return; 9064 } 9065 onInitializeAccessibilityEvent(event); 9066 // Only a subset of accessibility events populates text content. 9067 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 9068 dispatchPopulateAccessibilityEvent(event); 9069 } 9070 SendAccessibilityEventThrottle throttle = getThrottleForAccessibilityEvent(event); 9071 if (throttle != null) { 9072 throttle.post(event); 9073 } else if (!isWindowDisappearedEvent && detached) { 9074 // Views could be attached soon later. Accessibility events during this temporarily 9075 // detached period should be sent too. 9076 postDelayed(() -> { 9077 if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) { 9078 requestParentSendAccessibilityEvent(event); 9079 } 9080 }, ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 9081 } else { 9082 requestParentSendAccessibilityEvent(event); 9083 } 9084 } 9085 9086 private void requestParentSendAccessibilityEvent(AccessibilityEvent event) { 9087 ViewParent parent = getParent(); 9088 if (parent != null) { 9089 getParent().requestSendAccessibilityEvent(this, event); 9090 } 9091 } 9092 9093 private SendAccessibilityEventThrottle getThrottleForAccessibilityEvent( 9094 AccessibilityEvent event) { 9095 if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { 9096 if (mSendViewScrolledAccessibilityEvent == null) { 9097 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 9098 } 9099 return mSendViewScrolledAccessibilityEvent; 9100 } 9101 boolean isStateContentChanged = (event.getContentChangeTypes() 9102 & AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION) != 0; 9103 if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 9104 && isStateContentChanged) { 9105 if (mSendStateChangedAccessibilityEvent == null) { 9106 mSendStateChangedAccessibilityEvent = new SendAccessibilityEventThrottle(); 9107 } 9108 return mSendStateChangedAccessibilityEvent; 9109 } 9110 return null; 9111 } 9112 9113 private void clearAccessibilityThrottles() { 9114 cancel(mSendViewScrolledAccessibilityEvent); 9115 cancel(mSendStateChangedAccessibilityEvent); 9116 } 9117 9118 /** 9119 * Dispatches an {@link AccessibilityEvent} to the {@link View} to add the text content of the 9120 * view and its children. 9121 * <p> 9122 * <b>Note:</b> This method should only be used with event.setText(). 9123 * Avoid mutating other event state in this method. In general, put UI metadata in the node for 9124 * services to easily query. 9125 * <ul> 9126 * <li> If you are modifying other event properties, you may be eliminating semantics 9127 * accessibility services may want. Instead, send a separate event using 9128 * {@link #sendAccessibilityEvent(int)} and override 9129 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 9130 * </li> 9131 * <li>If you are checking for type {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED} 9132 * to generate window/title announcements, you may be causing disruptive announcements 9133 * (or making no announcements at all). Instead, follow the practices described in 9134 * {@link View#announceForAccessibility(CharSequence)}. <b>Note:</b> this does not suggest 9135 * calling announceForAccessibility(), but using the suggestions listed in its 9136 * documentation. 9137 * </li> 9138 * <li>If you are making changes based on the state of accessibility, such as checking for 9139 * an event type to trigger a UI update, while well-intentioned, you are creating brittle, 9140 * less well-maintained code that works for some users but not others. Instead, leverage 9141 * existing code for equitable experiences and less technical debt. See 9142 * {@link AccessibilityManager#isEnabled()} for an example. 9143 * </li> 9144 * </ul> 9145 * <p> 9146 * Note that the event text is populated in a separate dispatch path 9147 * ({@link #onPopulateAccessibilityEvent(AccessibilityEvent)}) since we add to the 9148 * event not only the text of the source but also the text of all its descendants. 9149 * <p> 9150 * A typical implementation will call 9151 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on this view 9152 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 9153 * on each child or the first child that is visible. Override this method if custom population 9154 * of the event text content is required. 9155 * 9156 * <p> 9157 * If an {@link AccessibilityDelegate} has been specified via calling 9158 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 9159 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 9160 * is responsible for handling this call. 9161 * </p> 9162 * <p> 9163 * If this view sets {@link #isAccessibilityDataSensitive()} then this view should only append 9164 * sensitive information to an event that also sets 9165 * {@link AccessibilityEvent#isAccessibilityDataSensitive()}. 9166 * </p> 9167 * <p> 9168 * <em>Note:</em> Accessibility events of certain types are not dispatched for 9169 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 9170 * </p> 9171 * 9172 * @param event The event. 9173 * 9174 * @return True if the event population was completed. 9175 */ 9176 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 9177 if (mAccessibilityDelegate != null) { 9178 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 9179 } else { 9180 return dispatchPopulateAccessibilityEventInternal(event); 9181 } 9182 } 9183 9184 /** 9185 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 9186 * 9187 * Note: Called from the default {@link AccessibilityDelegate}. 9188 * 9189 * @hide 9190 */ 9191 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 9192 onPopulateAccessibilityEvent(event); 9193 return false; 9194 } 9195 9196 /** 9197 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 9198 * giving a chance to this View to populate the accessibility event with its 9199 * text content. 9200 * <p> 9201 * <b>Note:</b> This method should only be used with event.setText(). 9202 * Avoid mutating other event state in this method. Instead, follow the practices described in 9203 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)}. In general, put UI 9204 * metadata in the node for services to easily query, than in transient events. 9205 * <p> 9206 * Example: Adding formatted date string to an accessibility event in addition 9207 * to the text added by the super implementation: 9208 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 9209 * super.onPopulateAccessibilityEvent(event); 9210 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 9211 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 9212 * mCurrentDate.getTimeInMillis(), flags); 9213 * event.getText().add(selectedDateUtterance); 9214 * }</pre> 9215 * <p> 9216 * If an {@link AccessibilityDelegate} has been specified via calling 9217 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 9218 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 9219 * is responsible for handling this call. 9220 * </p> 9221 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 9222 * information to the event, in case the default implementation has basic information to add. 9223 * </p> 9224 * 9225 * @param event The accessibility event which to populate. 9226 * 9227 * @see #sendAccessibilityEvent(int) 9228 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 9229 */ 9230 @CallSuper 9231 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 9232 if (mAccessibilityDelegate != null) { 9233 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 9234 } else { 9235 onPopulateAccessibilityEventInternal(event); 9236 } 9237 } 9238 9239 /** 9240 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 9241 * 9242 * Note: Called from the default {@link AccessibilityDelegate}. 9243 * 9244 * @hide 9245 */ 9246 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 9247 if ((event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) 9248 && isAccessibilityPane()) { 9249 event.getText().add(getAccessibilityPaneTitle()); 9250 } 9251 } 9252 9253 /** 9254 * Initializes an {@link AccessibilityEvent} with information about 9255 * this View which is the event source. In other words, the source of 9256 * an accessibility event is the view whose state change triggered firing 9257 * the event. 9258 * <p> 9259 * Example: Setting the password property of an event in addition 9260 * to properties set by the super implementation: 9261 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 9262 * super.onInitializeAccessibilityEvent(event); 9263 * event.setPassword(true); 9264 * }</pre> 9265 * <p> 9266 * If an {@link AccessibilityDelegate} has been specified via calling 9267 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 9268 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 9269 * is responsible for handling this call. 9270 * </p> 9271 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 9272 * information to the event, in case the default implementation has basic information to add. 9273 * </p> 9274 * @param event The event to initialize. 9275 * 9276 * @see #sendAccessibilityEvent(int) 9277 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 9278 */ 9279 @CallSuper 9280 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 9281 if (mAccessibilityDelegate != null) { 9282 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 9283 } else { 9284 onInitializeAccessibilityEventInternal(event); 9285 } 9286 } 9287 9288 /** 9289 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 9290 * 9291 * Note: Called from the default {@link AccessibilityDelegate}. 9292 * 9293 * @hide 9294 */ 9295 @UnsupportedAppUsage 9296 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 9297 event.setSource(this); 9298 event.setClassName(getAccessibilityClassName()); 9299 event.setPackageName(getContext().getPackageName()); 9300 event.setEnabled(isEnabled()); 9301 event.setContentDescription(mContentDescription); 9302 event.setScrollX(getScrollX()); 9303 event.setScrollY(getScrollY()); 9304 9305 switch (event.getEventType()) { 9306 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 9307 ArrayList<View> focusablesTempList = (mAttachInfo != null) 9308 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 9309 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 9310 event.setItemCount(focusablesTempList.size()); 9311 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 9312 if (mAttachInfo != null) { 9313 focusablesTempList.clear(); 9314 } 9315 } break; 9316 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 9317 CharSequence text = getIterableTextForAccessibility(); 9318 if (text != null && text.length() > 0) { 9319 event.setFromIndex(getAccessibilitySelectionStart()); 9320 event.setToIndex(getAccessibilitySelectionEnd()); 9321 event.setItemCount(text.length()); 9322 } 9323 } break; 9324 } 9325 } 9326 9327 /** 9328 * Returns an {@link AccessibilityNodeInfo} representing this view from the 9329 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 9330 * This method is responsible for obtaining an accessibility node info from a 9331 * pool of reusable instances and calling 9332 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 9333 * initialize the former. 9334 * <p> 9335 * Note: The client is responsible for recycling the obtained instance by calling 9336 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 9337 * </p> 9338 * 9339 * @return A populated {@link AccessibilityNodeInfo}. 9340 * 9341 * @see AccessibilityNodeInfo 9342 */ 9343 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 9344 if (mAccessibilityDelegate != null) { 9345 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 9346 } else { 9347 return createAccessibilityNodeInfoInternal(); 9348 } 9349 } 9350 9351 /** 9352 * @see #createAccessibilityNodeInfo() 9353 * 9354 * @hide 9355 */ 9356 public @Nullable AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 9357 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 9358 if (provider != null) { 9359 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 9360 } else { 9361 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 9362 onInitializeAccessibilityNodeInfo(info); 9363 return info; 9364 } 9365 } 9366 9367 /** 9368 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 9369 * The base implementation sets: 9370 * <ul> 9371 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 9372 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 9373 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 9374 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 9375 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 9376 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 9377 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 9378 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 9379 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 9380 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 9381 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 9382 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 9383 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 9384 * </ul> 9385 * <p> 9386 * Subclasses should override this method, call the super implementation, 9387 * and set additional attributes. 9388 * </p> 9389 * <p> 9390 * If an {@link AccessibilityDelegate} has been specified via calling 9391 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 9392 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 9393 * is responsible for handling this call. 9394 * </p> 9395 * 9396 * @param info The instance to initialize. 9397 */ 9398 @CallSuper 9399 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 9400 if (mAccessibilityDelegate != null) { 9401 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 9402 } else { 9403 onInitializeAccessibilityNodeInfoInternal(info); 9404 } 9405 } 9406 9407 /** 9408 * Gets the location of this view in screen coordinates. 9409 * 9410 * @param outRect The output location 9411 * @hide 9412 */ 9413 @UnsupportedAppUsage 9414 public void getBoundsOnScreen(Rect outRect) { 9415 getBoundsOnScreen(outRect, false); 9416 } 9417 9418 /** 9419 * Gets the location of this view in screen coordinates. 9420 * 9421 * @param outRect The output location 9422 * @param clipToParent Whether to clip child bounds to the parent ones. 9423 * @hide 9424 */ 9425 @UnsupportedAppUsage 9426 @TestApi 9427 public void getBoundsOnScreen(@NonNull Rect outRect, boolean clipToParent) { 9428 if (mAttachInfo == null) { 9429 return; 9430 } 9431 RectF position = mAttachInfo.mTmpTransformRect; 9432 getBoundsToScreenInternal(position, clipToParent); 9433 outRect.set(Math.round(position.left), Math.round(position.top), 9434 Math.round(position.right), Math.round(position.bottom)); 9435 // If "Sandboxing View Bounds APIs" override is enabled, applyViewBoundsSandboxingIfNeeded 9436 // will sandbox outRect within window bounds. 9437 mAttachInfo.mViewRootImpl.applyViewBoundsSandboxingIfNeeded(outRect); 9438 } 9439 9440 /** 9441 * Gets the location of this view in screen coordinates. 9442 * 9443 * @param outRect The output location 9444 * @param clipToParent Whether to clip child bounds to the parent ones. 9445 * @hide 9446 */ 9447 public void getBoundsOnScreen(RectF outRect, boolean clipToParent) { 9448 if (mAttachInfo == null) { 9449 return; 9450 } 9451 RectF position = mAttachInfo.mTmpTransformRect; 9452 getBoundsToScreenInternal(position, clipToParent); 9453 outRect.set(position.left, position.top, position.right, position.bottom); 9454 } 9455 9456 /** 9457 * Gets the location of this view in window coordinates. 9458 * 9459 * @param outRect The output location 9460 * @param clipToParent Whether to clip child bounds to the parent ones. 9461 * @hide 9462 */ 9463 public void getBoundsInWindow(Rect outRect, boolean clipToParent) { 9464 if (mAttachInfo == null) { 9465 return; 9466 } 9467 RectF position = mAttachInfo.mTmpTransformRect; 9468 getBoundsToWindowInternal(position, clipToParent); 9469 outRect.set(Math.round(position.left), Math.round(position.top), 9470 Math.round(position.right), Math.round(position.bottom)); 9471 } 9472 9473 private void getBoundsToScreenInternal(RectF position, boolean clipToParent) { 9474 position.set(0, 0, mRight - mLeft, mBottom - mTop); 9475 mapRectFromViewToScreenCoords(position, clipToParent); 9476 } 9477 9478 private void getBoundsToWindowInternal(RectF position, boolean clipToParent) { 9479 position.set(0, 0, mRight - mLeft, mBottom - mTop); 9480 mapRectFromViewToWindowCoords(position, clipToParent); 9481 } 9482 9483 /** 9484 * Map a rectangle from view-relative coordinates to screen-relative coordinates 9485 * 9486 * @param rect The rectangle to be mapped 9487 * @param clipToParent Whether to clip child bounds to the parent ones. 9488 * @hide 9489 */ 9490 public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { 9491 mapRectFromViewToWindowCoords(rect, clipToParent); 9492 rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 9493 } 9494 9495 /** 9496 * Map a rectangle from view-relative coordinates to window-relative coordinates 9497 * 9498 * @param rect The rectangle to be mapped 9499 * @param clipToParent Whether to clip child bounds to the parent ones. 9500 * @hide 9501 */ 9502 public void mapRectFromViewToWindowCoords(RectF rect, boolean clipToParent) { 9503 if (!hasIdentityMatrix()) { 9504 getMatrix().mapRect(rect); 9505 } 9506 9507 rect.offset(mLeft, mTop); 9508 9509 ViewParent parent = mParent; 9510 while (parent instanceof View) { 9511 View parentView = (View) parent; 9512 9513 rect.offset(-parentView.mScrollX, -parentView.mScrollY); 9514 9515 if (clipToParent) { 9516 rect.left = Math.max(rect.left, 0); 9517 rect.top = Math.max(rect.top, 0); 9518 rect.right = Math.min(rect.right, parentView.getWidth()); 9519 rect.bottom = Math.min(rect.bottom, parentView.getHeight()); 9520 } 9521 9522 if (!parentView.hasIdentityMatrix()) { 9523 parentView.getMatrix().mapRect(rect); 9524 } 9525 9526 rect.offset(parentView.mLeft, parentView.mTop); 9527 9528 parent = parentView.mParent; 9529 } 9530 9531 if (parent instanceof ViewRootImpl) { 9532 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 9533 rect.offset(0, -viewRootImpl.mCurScrollY); 9534 } 9535 } 9536 9537 /** 9538 * Return the class name of this object to be used for accessibility purposes. 9539 * Subclasses should only override this if they are implementing something that 9540 * should be seen as a completely new class of view when used by accessibility, 9541 * unrelated to the class it is deriving from. This is used to fill in 9542 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 9543 */ 9544 public CharSequence getAccessibilityClassName() { 9545 return View.class.getName(); 9546 } 9547 9548 /** 9549 * Called when assist structure is being retrieved from a view as part of 9550 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 9551 * @param structure Fill in with structured view data. The default implementation 9552 * fills in all data that can be inferred from the view itself. 9553 */ 9554 public void onProvideStructure(ViewStructure structure) { 9555 onProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 9556 } 9557 9558 /** 9559 * Populates a {@link ViewStructure} to fullfil an autofill request. 9560 * 9561 * <p>The structure should contain at least the following properties: 9562 * <ul> 9563 * <li>Autofill id ({@link ViewStructure#setAutofillId(AutofillId, int)}). 9564 * <li>Autofill type ({@link ViewStructure#setAutofillType(int)}). 9565 * <li>Autofill value ({@link ViewStructure#setAutofillValue(AutofillValue)}). 9566 * <li>Whether the data is sensitive ({@link ViewStructure#setDataIsSensitive(boolean)}). 9567 * </ul> 9568 * 9569 * <p>It's also recommended to set the following properties - the more properties the structure 9570 * has, the higher the chances of an {@link android.service.autofill.AutofillService} properly 9571 * using the structure: 9572 * 9573 * <ul> 9574 * <li>Autofill hints ({@link ViewStructure#setAutofillHints(String[])}). 9575 * <li>Autofill options ({@link ViewStructure#setAutofillOptions(CharSequence[])}) when the 9576 * view can only be filled with predefined values (typically used when the autofill type 9577 * is {@link #AUTOFILL_TYPE_LIST}). 9578 * <li>Resource id ({@link ViewStructure#setId(int, String, String, String)}). 9579 * <li>Class name ({@link ViewStructure#setClassName(String)}). 9580 * <li>Content description ({@link ViewStructure#setContentDescription(CharSequence)}). 9581 * <li>Visual properties such as visibility ({@link ViewStructure#setVisibility(int)}), 9582 * dimensions ({@link ViewStructure#setDimens(int, int, int, int, int, int)}), and 9583 * opacity ({@link ViewStructure#setOpaque(boolean)}). 9584 * <li>For views representing text fields, text properties such as the text itself 9585 * ({@link ViewStructure#setText(CharSequence)}), text hints 9586 * ({@link ViewStructure#setHint(CharSequence)}, input type 9587 * ({@link ViewStructure#setInputType(int)}), 9588 * <li>For views representing HTML nodes, its web domain 9589 * ({@link ViewStructure#setWebDomain(String)}) and HTML properties 9590 * (({@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}). 9591 * </ul> 9592 * 9593 * <p>The default implementation of this method already sets most of these properties based on 9594 * related {@link View} methods (for example, the autofill id is set using 9595 * {@link #getAutofillId()}, the autofill type set using {@link #getAutofillType()}, etc.), 9596 * and views in the standard Android widgets library also override it to set their 9597 * relevant properties (for example, {@link android.widget.TextView} already sets the text 9598 * properties), so it's recommended to only override this method 9599 * (and call {@code super.onProvideAutofillStructure()}) when: 9600 * 9601 * <ul> 9602 * <li>The view contents does not include PII (Personally Identifiable Information), so it 9603 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 9604 * <li>The view can only be autofilled with predefined options, so it can call 9605 * {@link ViewStructure#setAutofillOptions(CharSequence[])}. 9606 * </ul> 9607 * 9608 * <p><b>Note:</b> The {@code left} and {@code top} values set in 9609 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the next 9610 * {@link ViewGroup#isImportantForAutofill()} predecessor view included in the structure. 9611 * 9612 * <p>Views support the Autofill Framework mainly by: 9613 * <ul> 9614 * <li>Providing the metadata defining what the view means and how it can be autofilled. 9615 * <li>Notifying the Android System when the view value changed by calling 9616 * {@link AutofillManager#notifyValueChanged(View)}. 9617 * <li>Implementing the methods that autofill the view. 9618 * </ul> 9619 * <p>This method is responsible for the former; {@link #autofill(AutofillValue)} is responsible 9620 * for the latter. 9621 * 9622 * @param structure fill in with structured view data for autofill purposes. 9623 * @param flags optional flags. 9624 * 9625 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 9626 */ 9627 public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) { 9628 onProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 9629 } 9630 9631 /** 9632 * Populates a {@link ViewStructure} for content capture. 9633 * 9634 * <p>This method is called after a view that is eligible for content capture 9635 * (for example, if it {@link #isImportantForContentCapture()}, an intelligence service is 9636 * enabled for the user, and the activity rendering the view is enabled for content capture) 9637 * is laid out and is visible. The populated structure is then passed to the service through 9638 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}. 9639 * 9640 * <p>The default implementation of this method sets the most relevant properties based on 9641 * related {@link View} methods, and views in the standard Android widgets library also 9642 * override it to set their relevant properties. Therefore, if overriding this method, it 9643 * is recommended to call {@code super.onProvideContentCaptureStructure()}. 9644 * 9645 * <p><b>Note: </b>views that manage a virtual structure under this view must populate just 9646 * the node representing this view and return right away, then asynchronously report (not 9647 * necessarily in the UI thread) when the children nodes appear, disappear or have their text 9648 * changed by calling 9649 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}, 9650 * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and 9651 * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence)} 9652 * respectively. The structure for a child must be created using 9653 * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, long)}, and the 9654 * {@code autofillId} for a child can be obtained either through 9655 * {@code childStructure.getAutofillId()} or 9656 * {@link ContentCaptureSession#newAutofillId(AutofillId, long)}. 9657 * 9658 * <p>When the virtual view hierarchy represents a web page, you should also: 9659 * 9660 * <ul> 9661 * <li>Call {@link ContentCaptureManager#getContentCaptureConditions()} to infer content 9662 * capture events should be generate for that URL. 9663 * <li>Create a new {@link ContentCaptureSession} child for every HTML element that 9664 * renders a new URL (like an {@code IFRAME}) and use that session to notify events from 9665 * that subtree. 9666 * </ul> 9667 * 9668 * <p><b>Note: </b>the following methods of the {@code structure} will be ignored: 9669 * <ul> 9670 * <li>{@link ViewStructure#setChildCount(int)} 9671 * <li>{@link ViewStructure#addChildCount(int)} 9672 * <li>{@link ViewStructure#getChildCount()} 9673 * <li>{@link ViewStructure#newChild(int)} 9674 * <li>{@link ViewStructure#asyncNewChild(int)} 9675 * <li>{@link ViewStructure#asyncCommit()} 9676 * <li>{@link ViewStructure#setWebDomain(String)} 9677 * <li>{@link ViewStructure#newHtmlInfoBuilder(String)} 9678 * <li>{@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)} 9679 * <li>{@link ViewStructure#setDataIsSensitive(boolean)} 9680 * <li>{@link ViewStructure#setAlpha(float)} 9681 * <li>{@link ViewStructure#setElevation(float)} 9682 * <li>{@link ViewStructure#setTransformation(Matrix)} 9683 * 9684 * </ul> 9685 */ 9686 public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) { 9687 onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags); 9688 } 9689 9690 /** @hide */ 9691 protected void onProvideStructure(@NonNull ViewStructure structure, 9692 @ViewStructureType int viewFor, int flags) { 9693 final int id = mID; 9694 if (id != NO_ID && !isViewIdGenerated(id)) { 9695 String pkg, type, entry; 9696 try { 9697 final Resources res = getResources(); 9698 entry = res.getResourceEntryName(id); 9699 type = res.getResourceTypeName(id); 9700 pkg = res.getResourcePackageName(id); 9701 } catch (Resources.NotFoundException e) { 9702 entry = type = pkg = null; 9703 } 9704 structure.setId(id, pkg, type, entry); 9705 } else { 9706 structure.setId(id, null, null, null); 9707 } 9708 9709 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 9710 || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { 9711 final @AutofillType int autofillType = getAutofillType(); 9712 // Don't need to fill autofill info if view does not support it. 9713 // For example, only TextViews that are editable support autofill 9714 if (autofillType != AUTOFILL_TYPE_NONE) { 9715 structure.setAutofillType(autofillType); 9716 structure.setAutofillHints(getAutofillHints()); 9717 structure.setAutofillValue(getAutofillValue()); 9718 structure.setIsCredential(isCredential()); 9719 } 9720 if (getViewCredentialHandler() != null) { 9721 structure.setPendingCredentialRequest( 9722 getViewCredentialHandler().getRequest(), 9723 getViewCredentialHandler().getCallback()); 9724 } 9725 structure.setImportantForAutofill(getImportantForAutofill()); 9726 structure.setReceiveContentMimeTypes(getReceiveContentMimeTypes()); 9727 } 9728 9729 int ignoredParentLeft = 0; 9730 int ignoredParentTop = 0; 9731 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 9732 && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 9733 View parentGroup = null; 9734 9735 ViewParent viewParent = getParent(); 9736 if (viewParent instanceof View) { 9737 parentGroup = (View) viewParent; 9738 } 9739 9740 while (parentGroup != null && !parentGroup.isImportantForAutofill()) { 9741 ignoredParentLeft += parentGroup.mLeft - parentGroup.mScrollX; 9742 ignoredParentTop += parentGroup.mTop - parentGroup.mScrollY; 9743 9744 viewParent = parentGroup.getParent(); 9745 if (viewParent instanceof View) { 9746 parentGroup = (View) viewParent; 9747 } else { 9748 break; 9749 } 9750 } 9751 } 9752 9753 structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY, 9754 mRight - mLeft, mBottom - mTop); 9755 if (viewFor == VIEW_STRUCTURE_FOR_ASSIST) { 9756 if (!hasIdentityMatrix()) { 9757 structure.setTransformation(getMatrix()); 9758 } 9759 structure.setElevation(getZ()); 9760 } 9761 structure.setVisibility(getVisibility()); 9762 structure.setEnabled(isEnabled()); 9763 if (isClickable()) { 9764 structure.setClickable(true); 9765 } 9766 if (isFocusable()) { 9767 structure.setFocusable(true); 9768 } 9769 if (isFocused()) { 9770 structure.setFocused(true); 9771 } 9772 if (isAccessibilityFocused()) { 9773 structure.setAccessibilityFocused(true); 9774 } 9775 if (isSelected()) { 9776 structure.setSelected(true); 9777 } 9778 if (isActivated()) { 9779 structure.setActivated(true); 9780 } 9781 if (isLongClickable()) { 9782 structure.setLongClickable(true); 9783 } 9784 if (this instanceof Checkable) { 9785 structure.setCheckable(true); 9786 if (((Checkable)this).isChecked()) { 9787 structure.setChecked(true); 9788 } 9789 } 9790 if (isOpaque()) { 9791 structure.setOpaque(true); 9792 } 9793 if (isContextClickable()) { 9794 structure.setContextClickable(true); 9795 } 9796 structure.setClassName(getAccessibilityClassName().toString()); 9797 structure.setContentDescription(getContentDescription()); 9798 } 9799 9800 /** 9801 * Called when assist structure is being retrieved from a view as part of 9802 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 9803 * generate additional virtual structure under this view. The default implementation 9804 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 9805 * view's virtual accessibility nodes, if any. You can override this for a more 9806 * optimal implementation providing this data. 9807 */ 9808 public void onProvideVirtualStructure(ViewStructure structure) { 9809 onProvideVirtualStructureCompat(structure, false); 9810 } 9811 9812 /** 9813 * Fallback implementation to populate a ViewStructure from accessibility state. 9814 * 9815 * @param structure The structure to populate. 9816 * @param forAutofill Whether the structure is needed for autofill. 9817 */ 9818 private void onProvideVirtualStructureCompat(ViewStructure structure, boolean forAutofill) { 9819 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 9820 if (provider != null) { 9821 if (forAutofill && Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9822 Log.v(AUTOFILL_LOG_TAG, "onProvideVirtualStructureCompat() for " + this); 9823 } 9824 final AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 9825 structure.setChildCount(1); 9826 final ViewStructure root = structure.newChild(0); 9827 if (info != null) { 9828 populateVirtualStructure(root, provider, info, null, forAutofill); 9829 info.recycle(); 9830 } else { 9831 Log.w(AUTOFILL_LOG_TAG, "AccessibilityNodeInfo is null."); 9832 } 9833 } 9834 } 9835 9836 /** 9837 * Populates a {@link ViewStructure} containing virtual children to fullfil an autofill 9838 * request. 9839 * 9840 * <p>This method should be used when the view manages a virtual structure under this view. For 9841 * example, a view that draws input fields using {@link #draw(Canvas)}. 9842 * 9843 * <p>When implementing this method, subclasses must follow the rules below: 9844 * 9845 * <ul> 9846 * <li>Add virtual children by calling the {@link ViewStructure#newChild(int)} or 9847 * {@link ViewStructure#asyncNewChild(int)} methods, where the {@code id} is an unique id 9848 * identifying the children in the virtual structure. 9849 * <li>The children hierarchy can have multiple levels if necessary, but ideally it should 9850 * exclude intermediate levels that are irrelevant for autofill; that would improve the 9851 * autofill performance. 9852 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual 9853 * children. 9854 * <li>Set the autofill properties of the child structure as defined by 9855 * {@link #onProvideAutofillStructure(ViewStructure, int)}, using 9856 * {@link ViewStructure#setAutofillId(AutofillId, int)} to set its autofill id. 9857 * <li>Call {@link android.view.autofill.AutofillManager#notifyViewEntered(View, int, Rect)} 9858 * and/or {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} 9859 * when the focused virtual child changed. 9860 * <li>Override {@link #isVisibleToUserForAutofill(int)} to allow the platform to query 9861 * whether a given virtual view is visible to the user in order to support triggering 9862 * save when all views of interest go away. 9863 * <li>Call 9864 * {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, AutofillValue)} 9865 * when the value of a virtual child changed. 9866 * <li>Call {@link 9867 * android.view.autofill.AutofillManager#notifyViewVisibilityChanged(View, int, boolean)} 9868 * when the visibility of a virtual child changed. 9869 * <li>Call 9870 * {@link android.view.autofill.AutofillManager#notifyViewClicked(View, int)} when a virtual 9871 * child is clicked. 9872 * <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure 9873 * changed and the current context should be committed (for example, when the user tapped 9874 * a {@code SUBMIT} button in an HTML page). 9875 * <li>Call {@link AutofillManager#cancel()} when the autofill context of the view structure 9876 * changed and the current context should be canceled (for example, when the user tapped 9877 * a {@code CANCEL} button in an HTML page). 9878 * <li>Provide ways for users to manually request autofill by calling 9879 * {@link AutofillManager#requestAutofill(View, int, Rect)}. 9880 * <li>The {@code left} and {@code top} values set in 9881 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the 9882 * next {@link ViewGroup#isImportantForAutofill()} predecessor view included in the 9883 * structure. 9884 * </ul> 9885 * 9886 * <p>Views with virtual children support the Autofill Framework mainly by: 9887 * <ul> 9888 * <li>Providing the metadata defining what the virtual children mean and how they can be 9889 * autofilled. 9890 * <li>Implementing the methods that autofill the virtual children. 9891 * </ul> 9892 * <p>This method is responsible for the former; {@link #autofill(SparseArray)} is responsible 9893 * for the latter. 9894 * 9895 * @param structure fill in with virtual children data for autofill purposes. 9896 * @param flags optional flags. 9897 * 9898 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 9899 */ 9900 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 9901 if (mContext.isAutofillCompatibilityEnabled()) { 9902 onProvideVirtualStructureCompat(structure, true); 9903 } 9904 } 9905 9906 /** 9907 * Sets the listener to be {@link #performReceiveContent used} to handle insertion of 9908 * content into this view. 9909 * 9910 * <p>Depending on the type of view, this listener may be invoked for different scenarios. For 9911 * example, for an editable {@link android.widget.TextView}, this listener will be invoked for 9912 * the following scenarios: 9913 * <ol> 9914 * <li>Paste from the clipboard (e.g. "Paste" or "Paste as plain text" action in the 9915 * insertion/selection menu) 9916 * <li>Content insertion from the keyboard (from {@link InputConnection#commitContent}) 9917 * <li>Drag and drop (drop events from {@link #onDragEvent}) 9918 * <li>Autofill 9919 * <li>Selection replacement via {@link Intent#ACTION_PROCESS_TEXT} 9920 * </ol> 9921 * 9922 * <p>When setting a listener, clients must also declare the accepted MIME types. 9923 * The listener will still be invoked even if the MIME type of the content is not one of the 9924 * declared MIME types (e.g. if the user pastes content whose type is not one of the declared 9925 * MIME types). 9926 * In that case, the listener may reject the content (defer to the default platform behavior) 9927 * or execute some other fallback logic (e.g. show an appropriate message to the user). 9928 * The declared MIME types serve as a hint to allow different features to optionally alter 9929 * their behavior. For example, a soft keyboard may optionally choose to hide its UI for 9930 * inserting GIFs for a particular input field if the MIME types set here for that field 9931 * don't include "image/gif" or "image/*". 9932 * 9933 * <p>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC 9934 * MIME types. As a result, you should always write your MIME types with lowercase letters, 9935 * or use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to 9936 * lowercase. 9937 * 9938 * @param mimeTypes The MIME types accepted by the given listener. These may use patterns 9939 * such as "image/*", but may not start with a wildcard. This argument must 9940 * not be null or empty if a non-null listener is passed in. 9941 * @param listener The listener to use. This can be null to reset to the default behavior. 9942 */ 9943 public void setOnReceiveContentListener( 9944 @SuppressLint("NullableCollection") @Nullable String[] mimeTypes, 9945 @Nullable OnReceiveContentListener listener) { 9946 if (listener != null) { 9947 Preconditions.checkArgument(mimeTypes != null && mimeTypes.length > 0, 9948 "When the listener is set, MIME types must also be set"); 9949 } 9950 if (mimeTypes != null) { 9951 Preconditions.checkArgument(Arrays.stream(mimeTypes).noneMatch(t -> t.startsWith("*")), 9952 "A MIME type set here must not start with *: " + Arrays.toString(mimeTypes)); 9953 } 9954 mReceiveContentMimeTypes = ArrayUtils.isEmpty(mimeTypes) ? null : mimeTypes; 9955 getListenerInfo().mOnReceiveContentListener = listener; 9956 } 9957 9958 /** 9959 * Receives the given content. If no listener is set, invokes {@link #onReceiveContent}. If a 9960 * listener is {@link #setOnReceiveContentListener set}, invokes the listener instead; if the 9961 * listener returns a non-null result, invokes {@link #onReceiveContent} to handle it. 9962 * 9963 * @param payload The content to insert and related metadata. 9964 * 9965 * @return The portion of the passed-in content that was not accepted (may be all, some, or none 9966 * of the passed-in content). 9967 */ 9968 @Nullable 9969 public ContentInfo performReceiveContent(@NonNull ContentInfo payload) { 9970 final OnReceiveContentListener listener = (mListenerInfo == null) ? null 9971 : getListenerInfo().mOnReceiveContentListener; 9972 if (listener != null) { 9973 final ContentInfo remaining = listener.onReceiveContent(this, payload); 9974 return (remaining == null) ? null : onReceiveContent(remaining); 9975 } 9976 return onReceiveContent(payload); 9977 } 9978 9979 /** 9980 * Implements the default behavior for receiving content for this type of view. The default 9981 * view implementation is a no-op (returns the passed-in content without acting on it). 9982 * 9983 * <p>Widgets should override this method to define their default behavior for receiving 9984 * content. Apps should {@link #setOnReceiveContentListener set a listener} to provide 9985 * app-specific handling for receiving content. 9986 * 9987 * <p>See {@link #setOnReceiveContentListener} and {@link #performReceiveContent} for more info. 9988 * 9989 * @param payload The content to insert and related metadata. 9990 * 9991 * @return The portion of the passed-in content that was not handled (may be all, some, or none 9992 * of the passed-in content). 9993 */ 9994 @Nullable 9995 public ContentInfo onReceiveContent(@NonNull ContentInfo payload) { 9996 return payload; 9997 } 9998 9999 /** 10000 * Returns the MIME types accepted by {@link #performReceiveContent} for this view, as 10001 * configured via {@link #setOnReceiveContentListener}. By default returns null. 10002 * 10003 * <p>Different features (e.g. pasting from the clipboard, inserting stickers from the soft 10004 * keyboard, etc) may optionally use this metadata to conditionally alter their behavior. For 10005 * example, a soft keyboard may choose to hide its UI for inserting GIFs for a particular 10006 * input field if the MIME types returned here for that field don't include "image/gif" or 10007 * "image/*". 10008 * 10009 * <p>Note: Comparisons of MIME types should be performed using utilities such as 10010 * {@link ClipDescription#compareMimeTypes} rather than simple string equality, in order to 10011 * correctly handle patterns such as "text/*", "image/*", etc. Note that MIME type matching 10012 * in the Android framework is case-sensitive, unlike formal RFC MIME types. As a result, 10013 * you should always write your MIME types with lowercase letters, or use 10014 * {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to 10015 * lowercase. 10016 * 10017 * @return The MIME types accepted by {@link #performReceiveContent} for this view (may 10018 * include patterns such as "image/*"). 10019 */ 10020 @SuppressLint("NullableCollection") 10021 @Nullable 10022 public String[] getReceiveContentMimeTypes() { 10023 return mReceiveContentMimeTypes; 10024 } 10025 10026 /** 10027 * Automatically fills the content of this view with the {@code value}. 10028 * 10029 * <p>Views support the Autofill Framework mainly by: 10030 * <ul> 10031 * <li>Providing the metadata defining what the view means and how it can be autofilled. 10032 * <li>Implementing the methods that autofill the view. 10033 * </ul> 10034 * <p>{@link #onProvideAutofillStructure(ViewStructure, int)} is responsible for the former, 10035 * this method is responsible for latter. 10036 * 10037 * <p>This method does nothing by default, but when overridden it typically: 10038 * <ol> 10039 * <li>Checks if the provided value matches the expected type (which is defined by 10040 * {@link #getAutofillType()}). 10041 * <li>Checks if the view is editable - if it isn't, it should return right away. 10042 * <li>Call the proper getter method on {@link AutofillValue} to fetch the actual value. 10043 * <li>Pass the actual value to the equivalent setter in the view. 10044 * </ol> 10045 * 10046 * <p>For example, a text-field view could implement the method this way: 10047 * 10048 * <pre class="prettyprint"> 10049 * @Override 10050 * public void autofill(AutofillValue value) { 10051 * if (!value.isText() || !this.isEditable()) { 10052 * return; 10053 * } 10054 * CharSequence text = value.getTextValue(); 10055 * if (text != null) { 10056 * this.setText(text); 10057 * } 10058 * } 10059 * </pre> 10060 * 10061 * <p>If the value is updated asynchronously, the next call to 10062 * {@link AutofillManager#notifyValueChanged(View)} must happen <b>after</b> the value was 10063 * changed to the autofilled value. If not, the view will not be considered autofilled. 10064 * 10065 * <p><b>Note:</b> After this method is called, the value returned by 10066 * {@link #getAutofillValue()} must be equal to the {@code value} passed to it, otherwise the 10067 * view will not be highlighted as autofilled. 10068 * 10069 * @param value value to be autofilled. 10070 */ 10071 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 10072 } 10073 10074 /** 10075 * Automatically fills the content of the virtual children within this view. 10076 * 10077 * <p>Views with virtual children support the Autofill Framework mainly by: 10078 * <ul> 10079 * <li>Providing the metadata defining what the virtual children mean and how they can be 10080 * autofilled. 10081 * <li>Implementing the methods that autofill the virtual children. 10082 * </ul> 10083 * <p>{@link #onProvideAutofillVirtualStructure(ViewStructure, int)} is responsible for the 10084 * former, this method is responsible for the latter - see {@link #autofill(AutofillValue)} and 10085 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info about autofill. 10086 * 10087 * <p>If a child value is updated asynchronously, the next call to 10088 * {@link AutofillManager#notifyValueChanged(View, int, AutofillValue)} must happen 10089 * <b>after</b> the value was changed to the autofilled value. If not, the child will not be 10090 * considered autofilled. 10091 * 10092 * <p><b>Note:</b> To indicate that a virtual view was autofilled, 10093 * <code>?android:attr/autofilledHighlight</code> should be drawn over it until the data 10094 * changes. 10095 * 10096 * @param values map of values to be autofilled, keyed by virtual child id. 10097 * 10098 * @attr ref android.R.styleable#Theme_autofilledHighlight 10099 */ 10100 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { 10101 if (!mContext.isAutofillCompatibilityEnabled()) { 10102 return; 10103 } 10104 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 10105 if (provider == null) { 10106 return; 10107 } 10108 final int valueCount = values.size(); 10109 for (int i = 0; i < valueCount; i++) { 10110 final AutofillValue value = values.valueAt(i); 10111 if (value.isText()) { 10112 final int virtualId = values.keyAt(i); 10113 final CharSequence text = value.getTextValue(); 10114 final Bundle arguments = new Bundle(); 10115 arguments.putCharSequence( 10116 AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text); 10117 provider.performAction(virtualId, AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); 10118 } 10119 } 10120 } 10121 10122 /** 10123 * @hide 10124 */ 10125 public void onGetCredentialResponse(GetCredentialResponse response) { 10126 if (getPendingCredentialCallback() == null) { 10127 Log.w(AUTOFILL_LOG_TAG, "onGetCredentialResponse called but no callback found"); 10128 return; 10129 } 10130 getPendingCredentialCallback().onResult(response); 10131 } 10132 10133 /** 10134 * @hide 10135 */ 10136 public void onGetCredentialException(String errorType, String errorMsg) { 10137 if (getPendingCredentialCallback() == null) { 10138 Log.w(AUTOFILL_LOG_TAG, "onGetCredentialException called but no callback found"); 10139 return; 10140 } 10141 getPendingCredentialCallback().onError(new GetCredentialException(errorType, errorMsg)); 10142 } 10143 10144 /** 10145 * Gets the unique, logical identifier of this view in the activity, for autofill purposes. 10146 * 10147 * <p>The autofill id is created on demand, unless it is explicitly set by 10148 * {@link #setAutofillId(AutofillId)}. 10149 * 10150 * <p>See {@link #setAutofillId(AutofillId)} for more info. 10151 * 10152 * @return The View's autofill id. 10153 */ 10154 public final AutofillId getAutofillId() { 10155 if (mAutofillId == null) { 10156 // The autofill id needs to be unique, but its value doesn't matter, 10157 // so it's better to reuse the accessibility id to save space. 10158 mAutofillId = new AutofillId(getAutofillViewId()); 10159 } 10160 return mAutofillId; 10161 } 10162 10163 /** 10164 * Returns the {@link GetCredentialRequest} associated with the view. 10165 * If the return value is null, that means no request has been set 10166 * on the view and no {@link CredentialManager} flow will be invoked 10167 * when this view is focused. Traditioanl autofill flows will still 10168 * work, autofilling content if applicable, from 10169 * the active {@link android.service.autofill.AutofillService} on 10170 * the device. 10171 * 10172 * <p>See {@link #setPendingCredentialRequest} for more info. 10173 * 10174 * @return The credential request associated with this View. 10175 */ 10176 @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) 10177 @Nullable 10178 public final GetCredentialRequest getPendingCredentialRequest() { 10179 if (mViewCredentialHandler == null) { 10180 return null; 10181 } 10182 return mViewCredentialHandler.getRequest(); 10183 } 10184 10185 10186 /** 10187 * Returns the callback that has previously been set up on this view through 10188 * the {@link #setPendingCredentialRequest} API. 10189 * If the return value is null, that means no callback, or request, has been set 10190 * on the view and no {@link CredentialManager} flow will be invoked 10191 * when this view is focused. Traditioanl autofill flows will still 10192 * work, and autofillable content will still be returned through the 10193 * {@link #autofill(AutofillValue)} )} API. 10194 * 10195 * <p>See {@link #setPendingCredentialRequest} for more info. 10196 * 10197 * @return The callback associated with this view that will be invoked on a response from 10198 * {@link CredentialManager} . 10199 */ 10200 @FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION) 10201 @Nullable 10202 public final OutcomeReceiver<GetCredentialResponse, 10203 GetCredentialException> getPendingCredentialCallback() { 10204 if (mViewCredentialHandler == null) { 10205 return null; 10206 } 10207 return mViewCredentialHandler.getCallback(); 10208 } 10209 10210 /** 10211 * Sets the unique, logical identifier of this view in the activity, for autofill purposes. 10212 * 10213 * <p>The autofill id is created on demand, and this method should only be called when a view is 10214 * reused after {@link #dispatchProvideAutofillStructure(ViewStructure, int)} is called, as 10215 * that method creates a snapshot of the view that is passed along to the autofill service. 10216 * 10217 * <p>This method is typically used when view subtrees are recycled to represent different 10218 * content* —in this case, the autofill id can be saved before the view content is swapped 10219 * out, and restored later when it's swapped back in. For example: 10220 * 10221 * <pre> 10222 * EditText reusableView = ...; 10223 * ViewGroup parentView = ...; 10224 * AutofillManager afm = ...; 10225 * 10226 * // Swap out the view and change its contents 10227 * AutofillId oldId = reusableView.getAutofillId(); 10228 * CharSequence oldText = reusableView.getText(); 10229 * parentView.removeView(reusableView); 10230 * AutofillId newId = afm.getNextAutofillId(); 10231 * reusableView.setText("New I am"); 10232 * reusableView.setAutofillId(newId); 10233 * parentView.addView(reusableView); 10234 * 10235 * // Later, swap the old content back in 10236 * parentView.removeView(reusableView); 10237 * reusableView.setAutofillId(oldId); 10238 * reusableView.setText(oldText); 10239 * parentView.addView(reusableView); 10240 * </pre> 10241 * 10242 * <p>NOTE: If this view is a descendant of an {@link android.widget.AdapterView}, the system 10243 * may reset its autofill id when this view is recycled. If the autofill ids need to be stable, 10244 * they should be set again in 10245 * {@link android.widget.Adapter#getView(int, android.view.View, android.view.ViewGroup)}. 10246 * 10247 * @param id an autofill ID that is unique in the {@link android.app.Activity} hosting the view, 10248 * or {@code null} to reset it. Usually it's an id previously allocated to another view (and 10249 * obtained through {@link #getAutofillId()}), or a new value obtained through 10250 * {@link AutofillManager#getNextAutofillId()}. 10251 * 10252 * @throws IllegalStateException if the view is already {@link #isAttachedToWindow() attached to 10253 * a window}. 10254 * 10255 * @throws IllegalArgumentException if the id is an autofill id associated with a virtual view. 10256 */ 10257 public void setAutofillId(@Nullable AutofillId id) { 10258 // TODO(b/37566627): add unit / CTS test for all possible combinations below 10259 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 10260 Log.v(AUTOFILL_LOG_TAG, "setAutofill(): from " + mAutofillId + " to " + id); 10261 } 10262 if (isAttachedToWindow()) { 10263 throw new IllegalStateException("Cannot set autofill id when view is attached"); 10264 } 10265 if (id != null && !id.isNonVirtual()) { 10266 throw new IllegalStateException("Cannot set autofill id assigned to virtual views"); 10267 } 10268 if (id == null && (mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) == 0) { 10269 // Ignore reset because it was never explicitly set before. 10270 return; 10271 } 10272 mAutofillId = id; 10273 if (id != null) { 10274 mAutofillViewId = id.getViewId(); 10275 mPrivateFlags3 |= PFLAG3_AUTOFILLID_EXPLICITLY_SET; 10276 } else { 10277 mAutofillViewId = NO_ID; 10278 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 10279 } 10280 } 10281 10282 /** 10283 * Forces a reset of the autofill ids of the subtree rooted at this view. Like calling 10284 * {@link #setAutofillId(AutofillId) setAutofillId(null)} for each view, but works even if the 10285 * views are attached to a window. 10286 * 10287 * <p>This is useful if the views are being recycled, since an autofill id should uniquely 10288 * identify a particular piece of content. 10289 * 10290 * @hide 10291 */ 10292 public void resetSubtreeAutofillIds() { 10293 if (mAutofillViewId == NO_ID) { 10294 return; 10295 } 10296 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 10297 Log.v(CONTENT_CAPTURE_LOG_TAG, "resetAutofillId() for " + mAutofillViewId); 10298 } else if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 10299 Log.v(AUTOFILL_LOG_TAG, "resetAutofillId() for " + mAutofillViewId); 10300 } 10301 mAutofillId = null; 10302 mAutofillViewId = NO_ID; 10303 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 10304 } 10305 10306 /** 10307 * Describes the autofill type of this view, so an 10308 * {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue} 10309 * when autofilling the view. 10310 * 10311 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it to properly 10312 * support the Autofill Framework. 10313 * 10314 * @return either {@link #AUTOFILL_TYPE_NONE}, {@link #AUTOFILL_TYPE_TEXT}, 10315 * {@link #AUTOFILL_TYPE_LIST}, {@link #AUTOFILL_TYPE_DATE}, or {@link #AUTOFILL_TYPE_TOGGLE}. 10316 * 10317 * @see #onProvideAutofillStructure(ViewStructure, int) 10318 * @see #autofill(AutofillValue) 10319 */ 10320 public @AutofillType int getAutofillType() { 10321 return AUTOFILL_TYPE_NONE; 10322 } 10323 10324 /** 10325 * Gets the hints that help an {@link android.service.autofill.AutofillService} determine how 10326 * to autofill the view with the user's data. 10327 * 10328 * <p>See {@link #setAutofillHints(String...)} for more info about these hints. 10329 * 10330 * @return The hints set via the attribute or {@link #setAutofillHints(String...)}, or 10331 * {@code null} if no hints were set. 10332 * 10333 * @attr ref android.R.styleable#View_autofillHints 10334 */ 10335 @ViewDebug.ExportedProperty() 10336 @InspectableProperty 10337 @Nullable public String[] getAutofillHints() { 10338 return mAutofillHints; 10339 } 10340 10341 /** 10342 * @hide 10343 */ 10344 @TestApi 10345 public boolean isAutofilled() { 10346 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; 10347 } 10348 10349 /** 10350 * @hide 10351 */ 10352 public boolean hideAutofillHighlight() { 10353 return (mPrivateFlags4 & PFLAG4_AUTOFILL_HIDE_HIGHLIGHT) != 0; 10354 } 10355 10356 /** 10357 * Gets the {@link View}'s current autofill value. 10358 * 10359 * <p>By default returns {@code null}, but subclasses should override it and return an 10360 * appropriate value to properly support the Autofill Framework. 10361 * 10362 * @see #onProvideAutofillStructure(ViewStructure, int) 10363 * @see #autofill(AutofillValue) 10364 */ 10365 @Nullable 10366 public AutofillValue getAutofillValue() { 10367 return null; 10368 } 10369 10370 /** 10371 * Gets the mode for determining whether this view is important for autofill. 10372 * 10373 * <p>See {@link #setImportantForAutofill(int)} and {@link #isImportantForAutofill()} for more 10374 * info about this mode. 10375 * 10376 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 10377 * {@link #setImportantForAutofill(int)}. 10378 * 10379 * @attr ref android.R.styleable#View_importantForAutofill 10380 */ 10381 @ViewDebug.ExportedProperty(mapping = { 10382 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 10383 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 10384 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), 10385 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 10386 to = "yesExcludeDescendants"), 10387 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 10388 to = "noExcludeDescendants")}) 10389 @InspectableProperty(enumMapping = { 10390 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"), 10391 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"), 10392 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"), 10393 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 10394 name = "yesExcludeDescendants"), 10395 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 10396 name = "noExcludeDescendants"), 10397 }) 10398 public @AutofillImportance int getImportantForAutofill() { 10399 return (mPrivateFlags3 10400 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 10401 } 10402 10403 /** 10404 * Sets the mode for determining whether this view is considered important for autofill. 10405 * 10406 * <p>The platform determines the importance for autofill automatically but you 10407 * can use this method to customize the behavior. For example: 10408 * 10409 * <ol> 10410 * <li>When the view contents is irrelevant for autofill (for example, a text field used in a 10411 * "Captcha" challenge), it should be {@link #IMPORTANT_FOR_AUTOFILL_NO}. 10412 * <li>When both the view and its children are irrelevant for autofill (for example, the root 10413 * view of an activity containing a spreadhseet editor), it should be 10414 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 10415 * <li>When the view content is relevant for autofill but its children aren't (for example, 10416 * a credit card expiration date represented by a custom view that overrides the proper 10417 * autofill methods and has 2 children representing the month and year), it should 10418 * be {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}. 10419 * </ol> 10420 * 10421 * <p><b>Note:</b> Setting the mode as {@link #IMPORTANT_FOR_AUTOFILL_NO} or 10422 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and its 10423 * children) will not be used for autofill purpose; for example, when the user explicitly 10424 * makes an autofill request, all views are included in the ViewStructure, and starting in 10425 * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} the system uses other factors along 10426 * with importance to determine the autofill behavior. See {@link #isImportantForAutofill()} 10427 * for more details about how the View's importance for autofill is used. 10428 * 10429 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 10430 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, 10431 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 10432 * 10433 * @attr ref android.R.styleable#View_importantForAutofill 10434 */ 10435 public void setImportantForAutofill(@AutofillImportance int mode) { 10436 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 10437 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 10438 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 10439 } 10440 10441 /** 10442 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 10443 * associated with this view is considered important for autofill purposes. 10444 * 10445 * <p>Generally speaking, a view is important for autofill if: 10446 * <ol> 10447 * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}. 10448 * <li>The view contents can help an {@link android.service.autofill.AutofillService} 10449 * determine how other views can be autofilled. 10450 * <ol> 10451 * 10452 * <p>For example, view containers should typically return {@code false} for performance reasons 10453 * (since the important info is provided by their children), but if its properties have relevant 10454 * information (for example, a resource id called {@code credentials}, it should return 10455 * {@code true}. On the other hand, views representing labels or editable fields should 10456 * typically return {@code true}, but in some cases they could return {@code false} 10457 * (for example, if they're part of a "Captcha" mechanism). 10458 * 10459 * <p>The value returned by this method depends on the value returned by 10460 * {@link #getImportantForAutofill()}: 10461 * 10462 * <ol> 10463 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_YES} or 10464 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, then it returns {@code true} 10465 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_NO} or 10466 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}, then it returns {@code false} 10467 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, then it uses some simple heuristics 10468 * that can return {@code true} in some cases (like a container with a resource id), 10469 * but {@code false} in most. 10470 * <li>otherwise, it returns {@code false}. 10471 * </ol> 10472 * 10473 * <p> The behavior of importances depends on Android version: 10474 * <ol> 10475 * <li>For {@link android.os.Build.VERSION_CODES#TIRAMISU} and below: 10476 * <ol> 10477 * <li>When a view is considered important for autofill: 10478 * <ol> 10479 * <li>The view might automatically trigger an autofill request when focused on. 10480 * <li>The contents of the view are included in the {@link ViewStructure} used in an 10481 * autofill request. 10482 * </ol> 10483 * <li>On the other hand, when a view is considered not important for autofill: 10484 * <ol> 10485 * <li>The view never automatically triggers autofill requests, but it can trigger a 10486 * manual request through {@link AutofillManager#requestAutofill(View)}. 10487 * <li>The contents of the view are not included in the {@link ViewStructure} used in 10488 * an autofill request, unless the request has the 10489 * {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag. 10490 * </ol> 10491 * </ol> 10492 * <li>For {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above: 10493 * <ol> 10494 * <li>The system uses importance, along with other view properties and other optimization 10495 * factors, to determine if a view should trigger autofill on focus. 10496 * <li>The contents of {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, 10497 * {@link #IMPORTANT_FOR_AUTOFILL_YES}, {@link #IMPORTANT_FOR_AUTOFILL_NO}, 10498 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, and 10499 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} views will be included in the 10500 * {@link ViewStructure} used in an autofill request. 10501 * </ol> 10502 * </ol> 10503 * 10504 * @return whether the view is considered important for autofill. 10505 * 10506 * @see #setImportantForAutofill(int) 10507 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 10508 * @see #IMPORTANT_FOR_AUTOFILL_YES 10509 * @see #IMPORTANT_FOR_AUTOFILL_NO 10510 * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 10511 * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 10512 * @see AutofillManager#requestAutofill(View) 10513 */ 10514 public final boolean isImportantForAutofill() { 10515 // Check parent mode to ensure we're not hidden. 10516 ViewParent parent = mParent; 10517 while (parent instanceof View) { 10518 final int parentImportance = ((View) parent).getImportantForAutofill(); 10519 if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 10520 || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) { 10521 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 10522 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 10523 + "because parent " + parent + "'s importance is " + parentImportance); 10524 } 10525 return false; 10526 } 10527 parent = parent.getParent(); 10528 } 10529 10530 final int importance = getImportantForAutofill(); 10531 10532 // First, check the explicit states. 10533 if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 10534 || importance == IMPORTANT_FOR_AUTOFILL_YES) { 10535 return true; 10536 } 10537 if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 10538 || importance == IMPORTANT_FOR_AUTOFILL_NO) { 10539 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 10540 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 10541 + "because its importance is " + importance); 10542 } 10543 return false; 10544 } 10545 10546 // Then use some heuristics to handle AUTO. 10547 if (importance != IMPORTANT_FOR_AUTOFILL_AUTO) { 10548 Log.w(AUTOFILL_LOG_TAG, "invalid autofill importance (" + importance + " on view " 10549 + this); 10550 return false; 10551 } 10552 10553 // Always include views that have an explicit resource id. 10554 final int id = mID; 10555 if (id != NO_ID && !isViewIdGenerated(id)) { 10556 final Resources res = getResources(); 10557 String entry = null; 10558 String pkg = null; 10559 try { 10560 entry = res.getResourceEntryName(id); 10561 pkg = res.getResourcePackageName(id); 10562 } catch (Resources.NotFoundException e) { 10563 // ignore 10564 } 10565 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 10566 return true; 10567 } 10568 } 10569 10570 // If the app developer explicitly set hints for it, it's important. 10571 if (getAutofillHints() != null) { 10572 return true; 10573 } 10574 10575 // Otherwise, assume it's not important... 10576 return false; 10577 } 10578 10579 /** 10580 * Sets content sensitivity mode to determine whether this view displays sensitive content 10581 * (e.g. username, password etc.). The system will improve user privacy i.e. hide content 10582 * drawn by a sensitive view from screen sharing and recording. 10583 * 10584 * <p> The window hosting a sensitive view will be marked as secure during an active media 10585 * projection session. This would be equivalent to applying 10586 * {@link android.view.WindowManager.LayoutParams#FLAG_SECURE} to the window. 10587 * 10588 * @param mode {@link #CONTENT_SENSITIVITY_AUTO}, {@link #CONTENT_SENSITIVITY_NOT_SENSITIVE} 10589 * or {@link #CONTENT_SENSITIVITY_SENSITIVE} 10590 */ 10591 @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) 10592 public final void setContentSensitivity(@ContentSensitivity int mode) { 10593 mPrivateFlags4 &= ~PFLAG4_CONTENT_SENSITIVITY_MASK; 10594 mPrivateFlags4 |= ((mode << PFLAG4_CONTENT_SENSITIVITY_SHIFT) 10595 & PFLAG4_CONTENT_SENSITIVITY_MASK); 10596 if (sensitiveContentAppProtection()) { 10597 updateSensitiveViewsCountIfNeeded(isAggregatedVisible()); 10598 } 10599 } 10600 10601 /** 10602 * Gets content sensitivity mode to determine whether this view displays sensitive content. 10603 * 10604 * <p>See {@link #setContentSensitivity(int)} and 10605 * {@link #isContentSensitive()} for more info about this mode. 10606 * 10607 * @return {@link #CONTENT_SENSITIVITY_AUTO} by default, or value passed to 10608 * {@link #setContentSensitivity(int)}. 10609 */ 10610 @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) 10611 public @ContentSensitivity final int getContentSensitivity() { 10612 return (mPrivateFlags4 & PFLAG4_CONTENT_SENSITIVITY_MASK) 10613 >> PFLAG4_CONTENT_SENSITIVITY_SHIFT; 10614 } 10615 10616 /** 10617 * Returns whether this view displays sensitive content, based 10618 * on the value explicitly set by {@link #setContentSensitivity(int)}. 10619 * 10620 * @return whether the view displays sensitive content. 10621 * 10622 * @see #setContentSensitivity(int) 10623 * @see #CONTENT_SENSITIVITY_AUTO 10624 * @see #CONTENT_SENSITIVITY_SENSITIVE 10625 * @see #CONTENT_SENSITIVITY_NOT_SENSITIVE 10626 */ 10627 @FlaggedApi(FLAG_SENSITIVE_CONTENT_APP_PROTECTION_API) 10628 public final boolean isContentSensitive() { 10629 final int contentSensitivity = getContentSensitivity(); 10630 if (contentSensitivity == CONTENT_SENSITIVITY_SENSITIVE) { 10631 return true; 10632 } else if (contentSensitivity == CONTENT_SENSITIVITY_NOT_SENSITIVE) { 10633 return false; 10634 } else if (sensitiveContentAppProtection()) { 10635 return SensitiveAutofillHintsHelper 10636 .containsSensitiveAutofillHint(getAutofillHints()); 10637 } 10638 return false; 10639 } 10640 10641 /** 10642 * Helper used to track sensitive views when they are added or removed from the window 10643 * based on whether it's laid out and visible. 10644 * 10645 * <p>This method is called from many places (visibility changed, view laid out, view attached 10646 * or detached to/from window, etc...) 10647 */ 10648 private void updateSensitiveViewsCountIfNeeded(boolean appeared) { 10649 if (!sensitiveContentAppProtection() || mAttachInfo == null) { 10650 return; 10651 } 10652 10653 if (appeared && isContentSensitive()) { 10654 if ((mPrivateFlags4 & PFLAG4_IS_COUNTED_AS_SENSITIVE) == 0) { 10655 mPrivateFlags4 |= PFLAG4_IS_COUNTED_AS_SENSITIVE; 10656 mAttachInfo.increaseSensitiveViewsCount(); 10657 } 10658 } else { 10659 if ((mPrivateFlags4 & PFLAG4_IS_COUNTED_AS_SENSITIVE) != 0) { 10660 mPrivateFlags4 &= ~PFLAG4_IS_COUNTED_AS_SENSITIVE; 10661 mAttachInfo.decreaseSensitiveViewsCount(); 10662 } 10663 } 10664 } 10665 10666 /** 10667 * Gets the mode for determining whether this view is important for content capture. 10668 * 10669 * <p>See {@link #setImportantForContentCapture(int)} and 10670 * {@link #isImportantForContentCapture()} for more info about this mode. 10671 * 10672 * @return {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO} by default, or value passed to 10673 * {@link #setImportantForContentCapture(int)}. 10674 * 10675 * @attr ref android.R.styleable#View_importantForContentCapture 10676 */ 10677 @ViewDebug.ExportedProperty(mapping = { 10678 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to = "auto"), 10679 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES, to = "yes"), 10680 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO, to = "no"), 10681 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 10682 to = "yesExcludeDescendants"), 10683 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 10684 to = "noExcludeDescendants")}) 10685 @InspectableProperty(enumMapping = { 10686 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"), 10687 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"), 10688 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"), 10689 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 10690 name = "yesExcludeDescendants"), 10691 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 10692 name = "noExcludeDescendants"), 10693 }) 10694 public @ContentCaptureImportance int getImportantForContentCapture() { 10695 // NOTE: the important for content capture values were the first flags added and are set in 10696 // the rightmost position, so we don't need to shift them 10697 return mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 10698 } 10699 10700 /** 10701 * Sets the mode for determining whether this view is considered important for content capture. 10702 * 10703 * <p>The platform determines the importance for autofill automatically but you 10704 * can use this method to customize the behavior. Typically, a view that provides text should 10705 * be marked as {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}. 10706 * 10707 * @param mode {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}, 10708 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}, {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO}, 10709 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS}, 10710 * or {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS}. 10711 * 10712 * @attr ref android.R.styleable#View_importantForContentCapture 10713 */ 10714 public void setImportantForContentCapture(@ContentCaptureImportance int mode) { 10715 // Reset first 10716 mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 10717 // Then set again 10718 // NOTE: the important for content capture values were the first flags added and are set in 10719 // the rightmost position, so we don't need to shift them 10720 mPrivateFlags4 |= (mode & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK); 10721 } 10722 10723 /** 10724 * Hints the Android System whether this view is considered important for content capture, based 10725 * on the value explicitly set by {@link #setImportantForContentCapture(int)} and heuristics 10726 * when it's {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}. 10727 * 10728 * <p>See {@link ContentCaptureManager} for more info about content capture. 10729 * 10730 * @return whether the view is considered important for content capture. 10731 * 10732 * @see #setImportantForContentCapture(int) 10733 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO 10734 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES 10735 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO 10736 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 10737 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 10738 */ 10739 public final boolean isImportantForContentCapture() { 10740 boolean isImportant; 10741 if ((mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED) != 0) { 10742 isImportant = (mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE) != 0; 10743 return isImportant; 10744 } 10745 10746 isImportant = calculateIsImportantForContentCapture(); 10747 10748 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 10749 if (isImportant) { 10750 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 10751 } 10752 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED; 10753 return isImportant; 10754 } 10755 10756 /** 10757 * Calculates whether the flag is important for content capture so it can be used by 10758 * {@link #isImportantForContentCapture()} while the tree is traversed. 10759 */ 10760 private boolean calculateIsImportantForContentCapture() { 10761 // Check parent mode to ensure we're important 10762 ViewParent parent = mParent; 10763 while (parent instanceof View) { 10764 final int parentImportance = ((View) parent).getImportantForContentCapture(); 10765 if (parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 10766 || parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS) { 10767 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 10768 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for " 10769 + "content capture because parent " + parent + "'s importance is " 10770 + parentImportance); 10771 } 10772 return false; 10773 } 10774 parent = parent.getParent(); 10775 } 10776 10777 final int importance = getImportantForContentCapture(); 10778 10779 // First, check the explicit states. 10780 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 10781 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES) { 10782 return true; 10783 } 10784 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 10785 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO) { 10786 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 10787 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for content " 10788 + "capture because its importance is " + importance); 10789 } 10790 return false; 10791 } 10792 10793 // Then use some heuristics to handle AUTO. 10794 if (importance != IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { 10795 Log.w(CONTENT_CAPTURE_LOG_TAG, "invalid content capture importance (" + importance 10796 + " on view " + this); 10797 return false; 10798 } 10799 10800 // View group is important if at least one children also is 10801 if (this instanceof ViewGroup) { 10802 final ViewGroup group = (ViewGroup) this; 10803 for (int i = 0; i < group.getChildCount(); i++) { 10804 final View child = group.getChildAt(i); 10805 if (child.isImportantForContentCapture()) { 10806 return true; 10807 } 10808 } 10809 } 10810 10811 // If the app developer explicitly set hints or autofill hintsfor it, it's important. 10812 if (getAutofillHints() != null) { 10813 return true; 10814 } 10815 10816 // Otherwise, assume it's not important... 10817 return false; 10818 } 10819 10820 /** 10821 * Helper used to notify the {@link ContentCaptureManager} when the view is removed or 10822 * added, based on whether it's laid out and visible, and without knowing if the parent removed 10823 * it from the view hierarchy. 10824 * 10825 * <p>This method is called from many places (visibility changed, view laid out, view attached 10826 * or detached to/from window, etc...) and hence must contain the logic to call the manager, as 10827 * described below: 10828 * 10829 * <ol> 10830 * <li>It should only be called when content capture is enabled for the view. 10831 * <li>It must call viewAppeared() before viewDisappeared() 10832 * <li>viewAppeared() can only be called when the view is visible and laid out 10833 * <li>It should not call the same event twice. 10834 * </ol> 10835 */ 10836 private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) { 10837 AttachInfo ai = mAttachInfo; 10838 // Skip it while the view is being laid out for the first time 10839 if (ai != null && !ai.mReadyForContentCaptureUpdates) return; 10840 10841 // First check if context has client, so it saves a service lookup when it doesn't 10842 if (mContext.getContentCaptureOptions() == null) return; 10843 10844 if (appeared) { 10845 // The appeared event stops sending to AiAi. 10846 // 1. The view is hidden. 10847 // 2. The same event was sent. 10848 // 3. The view is not laid out, and it will be laid out in the future. 10849 // Some recycled views cached its layout and a relayout is unnecessary. In this case, 10850 // system still needs to notify content capture the view appeared. When a view is 10851 // recycled, it will set the flag PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED. 10852 final boolean isRecycledWithoutRelayout = getNotifiedContentCaptureDisappeared() 10853 && getVisibility() == VISIBLE 10854 && !isLayoutRequested(); 10855 if (getVisibility() != VISIBLE || getNotifiedContentCaptureAppeared() 10856 || !(isLaidOut() || isRecycledWithoutRelayout)) { 10857 if (DEBUG_CONTENT_CAPTURE) { 10858 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid=" 10859 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 10860 + ", visible=" + (getVisibility() == VISIBLE) 10861 + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared() 10862 + ", alreadyNotifiedDisappeared=" 10863 + getNotifiedContentCaptureDisappeared()); 10864 } 10865 return; 10866 } 10867 } else { 10868 if (!getNotifiedContentCaptureAppeared() || getNotifiedContentCaptureDisappeared()) { 10869 if (DEBUG_CONTENT_CAPTURE) { 10870 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": laid=" 10871 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 10872 + ", visible=" + (getVisibility() == VISIBLE) 10873 + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared() 10874 + ", alreadyNotifiedDisappeared=" 10875 + getNotifiedContentCaptureDisappeared()); 10876 } 10877 return; 10878 } 10879 } 10880 10881 ContentCaptureSession session = getContentCaptureSession(); 10882 if (session == null) return; 10883 10884 // ... and finally at the view level 10885 // NOTE: isImportantForContentCapture() is more expensive than cm.isContentCaptureEnabled() 10886 if (!isImportantForContentCapture()) return; 10887 10888 if (appeared) { 10889 setNotifiedContentCaptureAppeared(); 10890 10891 if (ai != null) { 10892 makeParentImportantAndNotifyAppearedEventIfNeed(); 10893 ai.delayNotifyContentCaptureEvent(session, this, appeared); 10894 } else { 10895 if (DEBUG_CONTENT_CAPTURE) { 10896 Log.w(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on appeared for " + this); 10897 } 10898 } 10899 } else { 10900 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 10901 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 10902 10903 if (ai != null) { 10904 ai.delayNotifyContentCaptureEvent(session, this, appeared); 10905 } else { 10906 if (DEBUG_CONTENT_CAPTURE) { 10907 Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on disappeared for " + this); 10908 } 10909 } 10910 10911 // We reset any translation state as views may be re-used (e.g., as in ListView and 10912 // RecyclerView). We only need to do this for views important for content capture since 10913 // views unimportant for content capture won't be translated anyway. 10914 if (!isTemporarilyDetached()) { 10915 clearTranslationState(); 10916 } 10917 } 10918 } 10919 10920 private void makeParentImportantAndNotifyAppearedEventIfNeed() { 10921 // If view sent the appeared event to Content Capture, Content Capture also 10922 // would like to receive its parents' appeared events. So checks its parents 10923 // whether the appeared event is sent or not. If not, send the appeared event. 10924 final ViewParent parent = getParent(); 10925 if (parent instanceof View) { 10926 View p = ((View) parent); 10927 if (p.getNotifiedContentCaptureAppeared()) { 10928 return; 10929 } 10930 // Set important for content capture in the cache. 10931 p.mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; 10932 p.notifyAppearedOrDisappearedForContentCaptureIfNeeded(/* appeared */ true); 10933 } 10934 } 10935 10936 private void setNotifiedContentCaptureAppeared() { 10937 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 10938 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 10939 } 10940 10941 /** @hide */ 10942 protected boolean getNotifiedContentCaptureAppeared() { 10943 return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0; 10944 } 10945 10946 10947 private boolean getNotifiedContentCaptureDisappeared() { 10948 return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0; 10949 } 10950 10951 /** 10952 * Sets the (optional) {@link ContentCaptureSession} associated with this view. 10953 * 10954 * <p>This method should be called when you need to associate a {@link ContentCaptureContext} to 10955 * the content capture events associated with this view or its view hierarchy (if it's a 10956 * {@link ViewGroup}). 10957 * 10958 * <p>For example, if your activity is associated with a web domain, first you would need to 10959 * set the context for the main DOM: 10960 * 10961 * <pre> 10962 * ContentCaptureSession mainSession = rootView.getContentCaptureSession(); 10963 * mainSession.setContentCaptureContext(ContentCaptureContext.forLocusId(Uri.parse(myUrl)); 10964 * </pre> 10965 * 10966 * <p>Then if the page had an {@code IFRAME}, you would create a new session for it: 10967 * 10968 * <pre> 10969 * ContentCaptureSession iframeSession = mainSession.createContentCaptureSession( 10970 * ContentCaptureContext.forLocusId(Uri.parse(iframeUrl))); 10971 * iframeView.setContentCaptureSession(iframeSession); 10972 * </pre> 10973 * 10974 * @param contentCaptureSession a session created by 10975 * {@link ContentCaptureSession#createContentCaptureSession( 10976 * android.view.contentcapture.ContentCaptureContext)}. 10977 */ 10978 public void setContentCaptureSession(@Nullable ContentCaptureSession contentCaptureSession) { 10979 mContentCaptureSession = contentCaptureSession; 10980 } 10981 10982 /** 10983 * Gets the session used to notify content capture events. 10984 * 10985 * @return session explicitly set by {@link #setContentCaptureSession(ContentCaptureSession)}, 10986 * inherited by ancestors, default session or {@code null} if content capture is disabled for 10987 * this view. 10988 */ 10989 @Nullable 10990 public final ContentCaptureSession getContentCaptureSession() { 10991 if (mContentCaptureSessionCached) { 10992 return mContentCaptureSession; 10993 } 10994 10995 mContentCaptureSession = getAndCacheContentCaptureSession(); 10996 mContentCaptureSessionCached = true; 10997 return mContentCaptureSession; 10998 } 10999 11000 @Nullable 11001 private ContentCaptureSession getAndCacheContentCaptureSession() { 11002 // First try the session explicitly set by setContentCaptureSession() 11003 if (mContentCaptureSession != null) { 11004 return mContentCaptureSession; 11005 } 11006 11007 // Then the session explicitly set in an ancestor 11008 ContentCaptureSession session = null; 11009 if (mParent instanceof View) { 11010 session = ((View) mParent).getContentCaptureSession(); 11011 } 11012 11013 // Finally, if no session was explicitly set, use the context's default session. 11014 if (session == null) { 11015 final ContentCaptureManager ccm = mContext 11016 .getSystemService(ContentCaptureManager.class); 11017 return ccm == null ? null : ccm.getMainContentCaptureSession(); 11018 } 11019 return session; 11020 } 11021 11022 @Nullable 11023 private AutofillManager getAutofillManager() { 11024 return mContext.getSystemService(AutofillManager.class); 11025 } 11026 11027 /** 11028 * Check whether current activity / package is in autofill denylist. 11029 * 11030 * Called by viewGroup#populateChildrenForAutofill() to determine whether to include view in 11031 * assist structure 11032 */ 11033 final boolean isActivityDeniedForAutofillForUnimportantView() { 11034 final AutofillManager afm = getAutofillManager(); 11035 if (afm == null) return false; 11036 return afm.isActivityDeniedForAutofill(); 11037 } 11038 11039 /** 11040 * Check whether current view matches autofillable heuristics 11041 * 11042 * Called by viewGroup#populateChildrenForAutofill() to determine whether to include view in 11043 * assist structure 11044 */ 11045 final boolean isMatchingAutofillableHeuristics() { 11046 final AutofillManager afm = getAutofillManager(); 11047 if (afm == null) return false; 11048 // check the flag to see if trigger fill request on not important views is enabled 11049 return afm.isTriggerFillRequestOnUnimportantViewEnabled() 11050 ? afm.isAutofillable(this) : false; 11051 } 11052 11053 /** 11054 * Returns whether the view is autofillable. 11055 * 11056 * @return whether the view is autofillable, and should send out autofill request to provider. 11057 */ 11058 private boolean isAutofillable() { 11059 if (DBG) { 11060 Log.d(VIEW_LOG_TAG, "isAutofillable() entered."); 11061 } 11062 if (getAutofillType() == AUTOFILL_TYPE_NONE) { 11063 if (DBG) { 11064 Log.d(VIEW_LOG_TAG, "getAutofillType() returns AUTOFILL_TYPE_NONE"); 11065 } 11066 return false; 11067 } 11068 11069 final AutofillManager afm = getAutofillManager(); 11070 if (afm == null) { 11071 if (DBG) { 11072 Log.d(VIEW_LOG_TAG, "AutofillManager is null"); 11073 } 11074 return false; 11075 } 11076 11077 // Check whether view is not part of an activity. If it's not, return false. 11078 if (getAutofillViewId() <= LAST_APP_AUTOFILL_ID) { 11079 if (DBG) { 11080 Log.d(VIEW_LOG_TAG, "getAutofillViewId()<=LAST_APP_AUTOFILL_ID"); 11081 } 11082 return false; 11083 } 11084 11085 // If view is important and filter important view flag is turned on, or view is not 11086 // important and trigger fill request on not important view flag is turned on, then use 11087 // AutofillManager.isAutofillable() to decide whether view is autofillable instead. 11088 if ((isImportantForAutofill() && afm.isTriggerFillRequestOnFilteredImportantViewsEnabled()) 11089 || (!isImportantForAutofill() 11090 && afm.isTriggerFillRequestOnUnimportantViewEnabled())) { 11091 if (DBG) { 11092 Log.d(VIEW_LOG_TAG, "isImportantForAutofill(): " + isImportantForAutofill() 11093 + "afm.isAutofillable(): " + afm.isAutofillable(this)); 11094 } 11095 return afm.isAutofillable(this) ? true : notifyAugmentedAutofillIfNeeded(afm); 11096 } 11097 11098 // If the previous condition is not met, fall back to the previous way to trigger fill 11099 // request based on autofill importance instead. 11100 if (DBG) { 11101 Log.d(VIEW_LOG_TAG, "isImportantForAutofill(): " + isImportantForAutofill()); 11102 } 11103 return isImportantForAutofill() ? true : notifyAugmentedAutofillIfNeeded(afm); 11104 } 11105 11106 private boolean notifyAugmentedAutofillIfNeeded(AutofillManager afm) { 11107 final AutofillOptions options = mContext.getAutofillOptions(); 11108 if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { 11109 return false; 11110 } 11111 afm.notifyViewEnteredForAugmentedAutofill(this); 11112 return true; 11113 } 11114 11115 /** @hide */ 11116 public boolean canNotifyAutofillEnterExitEvent() { 11117 if (DBG) { 11118 Log.d(VIEW_LOG_TAG, "canNotifyAutofillEnterExitEvent() entered. " 11119 + " isAutofillable(): " + isAutofillable() 11120 + " isAttachedToWindow(): " + isAttachedToWindow()); 11121 } 11122 return isAutofillable() && isAttachedToWindow(); 11123 } 11124 11125 private void populateVirtualStructure(ViewStructure structure, 11126 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, 11127 @Nullable AccessibilityNodeInfo parentInfo, boolean forAutofill) { 11128 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 11129 null, null, info.getViewIdResourceName()); 11130 Rect rect = structure.getTempRect(); 11131 // The bounds in parent for Jetpack Compose views aren't set as setBoundsInParent is 11132 // deprecated, and only setBoundsInScreen is called. 11133 // The bounds in parent can be calculated by diff'ing the child view's bounds in screen with 11134 // the parent's. 11135 if (sCalculateBoundsInParentFromBoundsInScreenFlagValue) { 11136 getBoundsInParent(info, parentInfo, rect); 11137 } else { 11138 info.getBoundsInParent(rect); 11139 } 11140 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 11141 structure.setVisibility(VISIBLE); 11142 structure.setEnabled(info.isEnabled()); 11143 if (info.isClickable()) { 11144 structure.setClickable(true); 11145 } 11146 if (info.isFocusable()) { 11147 structure.setFocusable(true); 11148 } 11149 if (info.isFocused()) { 11150 structure.setFocused(true); 11151 } 11152 if (info.isAccessibilityFocused()) { 11153 structure.setAccessibilityFocused(true); 11154 } 11155 if (info.isSelected()) { 11156 structure.setSelected(true); 11157 } 11158 if (info.isLongClickable()) { 11159 structure.setLongClickable(true); 11160 } 11161 if (info.isCheckable()) { 11162 structure.setCheckable(true); 11163 if (info.isChecked()) { 11164 structure.setChecked(true); 11165 } 11166 } 11167 if (info.isContextClickable()) { 11168 structure.setContextClickable(true); 11169 } 11170 if (forAutofill) { 11171 structure.setAutofillId(new AutofillId(getAutofillId(), 11172 AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()))); 11173 } 11174 if (getViewCredentialHandler() != null) { 11175 structure.setPendingCredentialRequest( 11176 getViewCredentialHandler().getRequest(), 11177 getViewCredentialHandler().getCallback()); 11178 } 11179 CharSequence cname = info.getClassName(); 11180 structure.setClassName(cname != null ? cname.toString() : null); 11181 structure.setContentDescription(info.getContentDescription()); 11182 if (forAutofill) { 11183 final int maxTextLength = info.getMaxTextLength(); 11184 if (maxTextLength != -1) { 11185 structure.setMaxTextLength(maxTextLength); 11186 } 11187 structure.setHint(info.getHintText()); 11188 } 11189 CharSequence text = info.getText(); 11190 boolean hasText = text != null || info.getError() != null; 11191 if (hasText) { 11192 structure.setText(text, info.getTextSelectionStart(), info.getTextSelectionEnd()); 11193 } 11194 if (forAutofill) { 11195 if (info.isEditable()) { 11196 structure.setDataIsSensitive(true); 11197 if (hasText) { 11198 structure.setAutofillType(AUTOFILL_TYPE_TEXT); 11199 structure.setAutofillValue(AutofillValue.forText(text)); 11200 } 11201 int inputType = info.getInputType(); 11202 if (inputType == 0 && info.isPassword()) { 11203 inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD; 11204 } 11205 structure.setInputType(inputType); 11206 } else { 11207 structure.setDataIsSensitive(false); 11208 } 11209 } 11210 final int NCHILDREN = info.getChildCount(); 11211 if (NCHILDREN > 0) { 11212 structure.setChildCount(NCHILDREN); 11213 for (int i=0; i<NCHILDREN; i++) { 11214 if (AccessibilityNodeInfo.getVirtualDescendantId(info.getChildNodeIds().get(i)) 11215 == AccessibilityNodeProvider.HOST_VIEW_ID) { 11216 Log.e(VIEW_LOG_TAG, "Virtual view pointing to its host. Ignoring"); 11217 continue; 11218 } 11219 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 11220 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 11221 if (cinfo != null) { 11222 ViewStructure child = structure.newChild(i); 11223 populateVirtualStructure(child, provider, cinfo, info, forAutofill); 11224 cinfo.recycle(); 11225 } 11226 } 11227 } 11228 } 11229 11230 private void getBoundsInParent(@NonNull AccessibilityNodeInfo info, 11231 @Nullable AccessibilityNodeInfo parentInfo, @NonNull Rect rect) { 11232 info.getBoundsInParent(rect); 11233 // Fallback to calculate bounds in parent by diffing the bounds in 11234 // screen if it's all 0. 11235 if ((rect.left | rect.top | rect.right | rect.bottom) == 0) { 11236 if (parentInfo != null) { 11237 Rect parentBoundsInScreen = parentInfo.getBoundsInScreen(); 11238 Rect boundsInScreen = info.getBoundsInScreen(); 11239 rect.set(boundsInScreen.left - parentBoundsInScreen.left, 11240 boundsInScreen.top - parentBoundsInScreen.top, 11241 boundsInScreen.right - parentBoundsInScreen.left, 11242 boundsInScreen.bottom - parentBoundsInScreen.top); 11243 } else { 11244 info.getBoundsInScreen(rect); 11245 } 11246 } 11247 } 11248 11249 /** 11250 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 11251 * implementation calls {@link #onProvideStructure} and 11252 * {@link #onProvideVirtualStructure}. 11253 */ 11254 public void dispatchProvideStructure(ViewStructure structure) { 11255 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 11256 } 11257 11258 /** 11259 * Dispatches creation of a {@link ViewStructure}s for autofill purposes down the hierarchy, 11260 * when an Assist structure is being created as part of an autofill request. 11261 * 11262 * <p>The default implementation does the following: 11263 * <ul> 11264 * <li>Sets the {@link AutofillId} in the structure. 11265 * <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}. 11266 * <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 11267 * </ul> 11268 * 11269 * <p>Typically, this method should only be overridden by subclasses that provide a view 11270 * hierarchy (such as {@link ViewGroup}) - other classes should override 11271 * {@link #onProvideAutofillStructure(ViewStructure, int)} or 11272 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} instead. 11273 * 11274 * <p>When overridden, it must: 11275 * 11276 * <ul> 11277 * <li>Either call 11278 * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly 11279 * set the {@link AutofillId} in the structure (for example, by calling 11280 * {@code structure.setAutofillId(getAutofillId())}). 11281 * <li>Decide how to handle the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag - when 11282 * set, all views in the structure should be considered important for autofill, 11283 * regardless of what {@link #isImportantForAutofill()} returns. We encourage you to 11284 * respect this flag to provide a better user experience - this flag is typically used 11285 * when an user explicitly requested autofill. If the flag is not set, 11286 * then only views marked as important for autofill should be included in the 11287 * structure - skipping non-important views optimizes the overall autofill performance. 11288 * </ul> 11289 * 11290 * @param structure fill in with structured view data for autofill purposes. 11291 * @param flags optional flags. 11292 * 11293 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 11294 */ 11295 public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, 11296 @AutofillFlags int flags) { 11297 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 11298 } 11299 11300 private void dispatchProvideStructure(@NonNull ViewStructure structure, 11301 @ViewStructureType int viewFor, @AutofillFlags int flags) { 11302 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { 11303 structure.setAutofillId(getAutofillId()); 11304 onProvideAutofillStructure(structure, flags); 11305 onProvideAutofillVirtualStructure(structure, flags); 11306 } else if (!isAssistBlocked()) { 11307 onProvideStructure(structure); 11308 onProvideVirtualStructure(structure); 11309 } else { 11310 structure.setClassName(getAccessibilityClassName().toString()); 11311 structure.setAssistBlocked(true); 11312 } 11313 } 11314 11315 /** 11316 * Dispatches the initial content capture events for a view structure. 11317 * 11318 * @hide 11319 */ 11320 public void dispatchInitialProvideContentCaptureStructure() { 11321 AttachInfo ai = mAttachInfo; 11322 if (ai == null) { 11323 Log.w(CONTENT_CAPTURE_LOG_TAG, 11324 "dispatchProvideContentCaptureStructure(): no AttachInfo for " + this); 11325 return; 11326 } 11327 ContentCaptureManager ccm = ai.mContentCaptureManager; 11328 if (ccm == null) { 11329 Log.w(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): " 11330 + "no ContentCaptureManager for " + this); 11331 return; 11332 } 11333 11334 // We must set it before checkign if the view itself is important, because it might 11335 // initially not be (for example, if it's empty), although that might change later (for 11336 // example, if important views are added) 11337 ai.mReadyForContentCaptureUpdates = true; 11338 11339 if (!isImportantForContentCapture()) { 11340 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 11341 Log.d(CONTENT_CAPTURE_LOG_TAG, 11342 "dispatchProvideContentCaptureStructure(): decorView is not important"); 11343 } 11344 return; 11345 } 11346 11347 ai.mContentCaptureManager = ccm; 11348 11349 ContentCaptureSession session = getContentCaptureSession(); 11350 if (session == null) { 11351 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 11352 Log.d(CONTENT_CAPTURE_LOG_TAG, 11353 "dispatchProvideContentCaptureStructure(): no session for " + this); 11354 } 11355 return; 11356 } 11357 11358 session.notifyViewTreeEvent(/* started= */ true); 11359 try { 11360 dispatchProvideContentCaptureStructure(); 11361 } finally { 11362 session.notifyViewTreeEvent(/* started= */ false); 11363 } 11364 } 11365 11366 /** @hide */ 11367 void dispatchProvideContentCaptureStructure() { 11368 ContentCaptureSession session = getContentCaptureSession(); 11369 if (session != null) { 11370 ViewStructure structure = session.newViewStructure(this); 11371 onProvideContentCaptureStructure(structure, /* flags= */ 0); 11372 setNotifiedContentCaptureAppeared(); 11373 session.notifyViewAppeared(structure); 11374 } 11375 } 11376 11377 /** 11378 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 11379 * 11380 * Note: Called from the default {@link AccessibilityDelegate}. 11381 * 11382 * @hide 11383 */ 11384 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 11385 if (mAttachInfo == null) { 11386 return; 11387 } 11388 11389 Rect bounds = mAttachInfo.mTmpInvalRect; 11390 11391 getDrawingRect(bounds); 11392 info.setBoundsInParent(bounds); 11393 11394 getBoundsOnScreen(bounds, true); 11395 info.setBoundsInScreen(bounds); 11396 getBoundsInWindow(bounds, true); 11397 info.setBoundsInWindow(bounds); 11398 11399 ViewParent parent = getParentForAccessibility(); 11400 if (parent instanceof View) { 11401 info.setParent((View) parent); 11402 } 11403 11404 if (mID != View.NO_ID) { 11405 View rootView = getRootView(); 11406 if (rootView == null) { 11407 rootView = this; 11408 } 11409 11410 View label = rootView.findLabelForView(this, mID); 11411 if (label != null) { 11412 if (supportMultipleLabeledby()) { 11413 info.addLabeledBy(label); 11414 } else { 11415 info.setLabeledBy(label); 11416 } 11417 } 11418 11419 if ((mAttachInfo.mAccessibilityFetchFlags 11420 & AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS) != 0 11421 && Resources.resourceHasPackage(mID)) { 11422 try { 11423 String viewId = getResources().getResourceName(mID); 11424 info.setViewIdResourceName(viewId); 11425 } catch (Resources.NotFoundException nfe) { 11426 /* ignore */ 11427 } 11428 } 11429 } 11430 11431 if (mLabelForId != View.NO_ID) { 11432 View rootView = getRootView(); 11433 if (rootView == null) { 11434 rootView = this; 11435 } 11436 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 11437 if (labeled != null) { 11438 info.setLabelFor(labeled); 11439 } 11440 } 11441 11442 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 11443 View rootView = getRootView(); 11444 if (rootView == null) { 11445 rootView = this; 11446 } 11447 View next = rootView.findViewInsideOutShouldExist(this, 11448 mAccessibilityTraversalBeforeId); 11449 if (next != null && next.includeForAccessibility()) { 11450 info.setTraversalBefore(next); 11451 } 11452 } 11453 11454 if (mAccessibilityTraversalAfterId != View.NO_ID) { 11455 View rootView = getRootView(); 11456 if (rootView == null) { 11457 rootView = this; 11458 } 11459 View next = rootView.findViewInsideOutShouldExist(this, 11460 mAccessibilityTraversalAfterId); 11461 if (next != null && next.includeForAccessibility()) { 11462 info.setTraversalAfter(next); 11463 } 11464 } 11465 11466 info.setVisibleToUser(isVisibleToUser()); 11467 11468 info.setImportantForAccessibility(isImportantForAccessibility()); 11469 info.setAccessibilityDataSensitive(isAccessibilityDataSensitive()); 11470 info.setPackageName(mContext.getPackageName()); 11471 info.setClassName(getAccessibilityClassName()); 11472 info.setStateDescription(getStateDescription()); 11473 info.setContentDescription(getContentDescription()); 11474 11475 info.setEnabled(isEnabled()); 11476 info.setClickable(isClickable()); 11477 info.setFocusable(isFocusable()); 11478 info.setScreenReaderFocusable(isScreenReaderFocusable()); 11479 info.setFocused(isFocused()); 11480 info.setAccessibilityFocused(isAccessibilityFocused()); 11481 info.setSelected(isSelected()); 11482 info.setLongClickable(isLongClickable()); 11483 info.setContextClickable(isContextClickable()); 11484 info.setLiveRegion(getAccessibilityLiveRegion()); 11485 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipText != null)) { 11486 info.setTooltipText(mTooltipInfo.mTooltipText); 11487 info.addAction((mTooltipInfo.mTooltipPopup == null) 11488 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP 11489 : AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP); 11490 } 11491 11492 // TODO: These make sense only if we are in an AdapterView but all 11493 // views can be selected. Maybe from accessibility perspective 11494 // we should report as selectable view in an AdapterView. 11495 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 11496 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 11497 11498 if (isFocusable()) { 11499 if (isFocused()) { 11500 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 11501 } else { 11502 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 11503 } 11504 } 11505 11506 if (!isAccessibilityFocused()) { 11507 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 11508 } else { 11509 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 11510 } 11511 11512 if (isClickable() && isEnabled()) { 11513 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 11514 } 11515 11516 if (isLongClickable() && isEnabled()) { 11517 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 11518 } 11519 11520 if (isContextClickable() && isEnabled()) { 11521 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 11522 } 11523 11524 CharSequence text = getIterableTextForAccessibility(); 11525 if (text != null && text.length() > 0) { 11526 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 11527 11528 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 11529 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 11530 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 11531 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 11532 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 11533 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 11534 } 11535 11536 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 11537 populateAccessibilityNodeInfoDrawingOrderInParent(info); 11538 info.setPaneTitle(mAccessibilityPaneTitle); 11539 info.setHeading(isAccessibilityHeading()); 11540 11541 if (mTouchDelegate != null) { 11542 info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo()); 11543 } 11544 11545 if (startedSystemDragForAccessibility()) { 11546 info.addAction(AccessibilityAction.ACTION_DRAG_CANCEL); 11547 } 11548 11549 if (canAcceptAccessibilityDrop()) { 11550 info.addAction(AccessibilityAction.ACTION_DRAG_DROP); 11551 } 11552 } 11553 11554 11555 /** 11556 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 11557 * additional data. 11558 * <p> 11559 * This method only needs overloading if the node is marked as having extra data available. 11560 * </p> 11561 * 11562 * @param info The info to which to add the extra data. Never {@code null}. 11563 * @param extraDataKey A key specifying the type of extra data to add to the info. The 11564 * extra data should be added to the {@link Bundle} returned by 11565 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 11566 * {@code null}. 11567 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 11568 * {@code null} if the service provided no arguments. 11569 * 11570 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 11571 */ 11572 public void addExtraDataToAccessibilityNodeInfo( 11573 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 11574 @Nullable Bundle arguments) { 11575 } 11576 11577 /** 11578 * Determine the order in which this view will be drawn relative to its siblings for a11y 11579 * 11580 * @param info The info whose drawing order should be populated 11581 */ 11582 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 11583 /* 11584 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 11585 * drawing order may not be well-defined, and some Views with custom drawing order may 11586 * not be initialized sufficiently to respond properly getChildDrawingOrder. 11587 */ 11588 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 11589 info.setDrawingOrder(0); 11590 return; 11591 } 11592 int drawingOrderInParent = 1; 11593 // Iterate up the hierarchy if parents are not important for a11y 11594 View viewAtDrawingLevel = this; 11595 final ViewParent parent = getParentForAccessibility(); 11596 while (viewAtDrawingLevel != parent) { 11597 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 11598 if (!(currentParent instanceof ViewGroup)) { 11599 // Should only happen for the Decor 11600 drawingOrderInParent = 0; 11601 break; 11602 } else { 11603 final ViewGroup parentGroup = (ViewGroup) currentParent; 11604 final int childCount = parentGroup.getChildCount(); 11605 if (childCount > 1) { 11606 List<View> preorderedList = parentGroup.buildOrderedChildList(); 11607 if (preorderedList != null) { 11608 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 11609 for (int i = 0; i < childDrawIndex; i++) { 11610 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 11611 } 11612 preorderedList.clear(); 11613 } else { 11614 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 11615 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 11616 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 11617 .getChildDrawingOrder(childCount, childIndex) : childIndex; 11618 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 11619 if (childDrawIndex != 0) { 11620 for (int i = 0; i < numChildrenToIterate; i++) { 11621 final int otherDrawIndex = (customOrder ? 11622 parentGroup.getChildDrawingOrder(childCount, i) : i); 11623 if (otherDrawIndex < childDrawIndex) { 11624 drawingOrderInParent += 11625 numViewsForAccessibility(parentGroup.getChildAt(i)); 11626 } 11627 } 11628 } 11629 } 11630 } 11631 } 11632 viewAtDrawingLevel = (View) currentParent; 11633 } 11634 info.setDrawingOrder(drawingOrderInParent); 11635 } 11636 11637 private static int numViewsForAccessibility(View view) { 11638 if (view != null) { 11639 if (view.includeForAccessibility()) { 11640 return 1; 11641 } else if (view instanceof ViewGroup) { 11642 return ((ViewGroup) view).getNumChildrenForAccessibility(); 11643 } 11644 } 11645 return 0; 11646 } 11647 11648 private View findLabelForView(View view, int labeledId) { 11649 if (mMatchLabelForPredicate == null) { 11650 mMatchLabelForPredicate = new MatchLabelForPredicate(); 11651 } 11652 mMatchLabelForPredicate.mLabeledId = labeledId; 11653 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 11654 } 11655 11656 /** 11657 * Computes whether this virtual autofill view is visible to the user. 11658 * 11659 * <p><b>Note: </b>By default it returns {@code true}, but views providing a virtual hierarchy 11660 * view must override it. 11661 * 11662 * @return Whether the view is visible on the screen. 11663 */ 11664 public boolean isVisibleToUserForAutofill(int virtualId) { 11665 if (mContext.isAutofillCompatibilityEnabled()) { 11666 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 11667 if (provider != null) { 11668 final AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(virtualId); 11669 if (node != null) { 11670 return node.isVisibleToUser(); 11671 } 11672 // if node is null, assume it's not visible anymore 11673 } else { 11674 Log.w(VIEW_LOG_TAG, "isVisibleToUserForAutofill(" + virtualId + "): no provider"); 11675 } 11676 return false; 11677 } 11678 return true; 11679 } 11680 11681 /** 11682 * Computes whether this view is visible to the user. Such a view is 11683 * attached, visible, all its predecessors are visible, it is not clipped 11684 * entirely by its predecessors, and has an alpha greater than zero. 11685 * 11686 * @return Whether the view is visible on the screen. 11687 * 11688 * @hide 11689 */ 11690 @UnsupportedAppUsage 11691 public boolean isVisibleToUser() { 11692 return isVisibleToUser(null); 11693 } 11694 11695 /** 11696 * Computes whether the given portion of this view is visible to the user. 11697 * Such a view is attached, visible, all its predecessors are visible, 11698 * has an alpha greater than zero, and the specified portion is not 11699 * clipped entirely by its predecessors. 11700 * 11701 * @param boundInView the portion of the view to test; coordinates should be relative; may be 11702 * <code>null</code>, and the entire view will be tested in this case. 11703 * When <code>true</code> is returned by the function, the actual visible 11704 * region will be stored in this parameter; that is, if boundInView is fully 11705 * contained within the view, no modification will be made, otherwise regions 11706 * outside of the visible area of the view will be clipped. 11707 * 11708 * @return Whether the specified portion of the view is visible on the screen. 11709 * 11710 * @hide 11711 */ 11712 @UnsupportedAppUsage(trackingBug = 171933273) 11713 protected boolean isVisibleToUser(Rect boundInView) { 11714 if (mAttachInfo != null) { 11715 // Attached to invisible window means this view is not visible. 11716 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 11717 return false; 11718 } 11719 // An invisible predecessor or one with alpha zero means 11720 // that this view is not visible to the user. 11721 Object current = this; 11722 while (current instanceof View) { 11723 View view = (View) current; 11724 // We have attach info so this view is attached and there is no 11725 // need to check whether we reach to ViewRootImpl on the way up. 11726 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 11727 view.getVisibility() != VISIBLE) { 11728 return false; 11729 } 11730 current = view.mParent; 11731 } 11732 // Check if the view is entirely covered by its predecessors. 11733 Rect visibleRect = mAttachInfo.mTmpInvalRect; 11734 Point offset = mAttachInfo.mPoint; 11735 if (!getGlobalVisibleRect(visibleRect, offset)) { 11736 return false; 11737 } 11738 // Check if the visible portion intersects the rectangle of interest. 11739 if (boundInView != null) { 11740 visibleRect.offset(-offset.x, -offset.y); 11741 return boundInView.intersect(visibleRect); 11742 } 11743 return true; 11744 } 11745 return false; 11746 } 11747 11748 /** 11749 * Returns the delegate for implementing accessibility support via 11750 * composition. For more details see {@link AccessibilityDelegate}. 11751 * 11752 * @return The delegate, or null if none set. 11753 */ 11754 public AccessibilityDelegate getAccessibilityDelegate() { 11755 return mAccessibilityDelegate; 11756 } 11757 11758 /** 11759 * Sets a delegate for implementing accessibility support via composition 11760 * (as opposed to inheritance). For more details, see 11761 * {@link AccessibilityDelegate}. 11762 * <p> 11763 * <strong>Note:</strong> On platform versions prior to 11764 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 11765 * views in the {@code android.widget.*} package are called <i>before</i> 11766 * host methods. This prevents certain properties such as class name from 11767 * being modified by overriding 11768 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 11769 * as any changes will be overwritten by the host class. 11770 * <p> 11771 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 11772 * methods are called <i>after</i> host methods, which all properties to be 11773 * modified without being overwritten by the host class. 11774 * 11775 * @param delegate the object to which accessibility method calls should be 11776 * delegated 11777 * @see AccessibilityDelegate 11778 */ 11779 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 11780 mAccessibilityDelegate = delegate; 11781 } 11782 11783 /** 11784 * Gets the provider for managing a virtual view hierarchy rooted at this View 11785 * and reported to {@link android.accessibilityservice.AccessibilityService}s 11786 * that explore the window content. 11787 * <p> 11788 * If this method returns an instance, this instance is responsible for managing 11789 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 11790 * View including the one representing the View itself. Similarly the returned 11791 * instance is responsible for performing accessibility actions on any virtual 11792 * view or the root view itself. 11793 * </p> 11794 * <p> 11795 * If an {@link AccessibilityDelegate} has been specified via calling 11796 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 11797 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 11798 * is responsible for handling this call. 11799 * </p> 11800 * 11801 * @return The provider. 11802 * 11803 * @see AccessibilityNodeProvider 11804 */ 11805 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 11806 if (mAccessibilityDelegate != null) { 11807 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 11808 } else { 11809 return null; 11810 } 11811 } 11812 11813 /** 11814 * Gets the unique identifier of this view on the screen for accessibility purposes. 11815 * 11816 * @return The view accessibility id. 11817 * 11818 * @hide 11819 */ 11820 @UnsupportedAppUsage 11821 public int getAccessibilityViewId() { 11822 if (mAccessibilityViewId == NO_ID) { 11823 mAccessibilityViewId = sNextAccessibilityViewId++; 11824 } 11825 return mAccessibilityViewId; 11826 } 11827 11828 /** 11829 * Gets the unique identifier of this view on the screen for autofill purposes. 11830 * 11831 * @return The view autofill id. 11832 * 11833 * @hide 11834 */ 11835 public int getAutofillViewId() { 11836 if (mAutofillViewId == NO_ID) { 11837 mAutofillViewId = mContext.getNextAutofillId(); 11838 } 11839 return mAutofillViewId; 11840 } 11841 11842 /** 11843 * Gets the unique identifier of the window in which this View resides. 11844 * 11845 * @return The window accessibility id. 11846 * 11847 * @hide 11848 */ 11849 public int getAccessibilityWindowId() { 11850 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 11851 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 11852 } 11853 11854 /** 11855 * Returns the {@link View}'s state description. 11856 * <p> 11857 * <strong>Note:</strong> Do not override this method, as it will have no 11858 * effect on the state description presented to accessibility services. 11859 * You must call {@link #setStateDescription(CharSequence)} to modify the 11860 * state description. 11861 * 11862 * @return the state description 11863 * @see #setStateDescription(CharSequence) 11864 */ 11865 @ViewDebug.ExportedProperty(category = "accessibility") 11866 public final @Nullable CharSequence getStateDescription() { 11867 return mStateDescription; 11868 } 11869 11870 /** 11871 * Returns the {@link View}'s content description. 11872 * <p> 11873 * <strong>Note:</strong> Do not override this method, as it will have no 11874 * effect on the content description presented to accessibility services. 11875 * You must call {@link #setContentDescription(CharSequence)} to modify the 11876 * content description. 11877 * 11878 * @return the content description 11879 * @see #setContentDescription(CharSequence) 11880 * @attr ref android.R.styleable#View_contentDescription 11881 */ 11882 @ViewDebug.ExportedProperty(category = "accessibility") 11883 @InspectableProperty 11884 public CharSequence getContentDescription() { 11885 return mContentDescription; 11886 } 11887 11888 /** 11889 * Returns the {@link View}'s supplemental description. 11890 * <p> 11891 * A supplemental description provides 11892 * brief supplemental information for this node, such as the purpose of the node when 11893 * that purpose is not conveyed within its textual representation. For example, if a 11894 * dropdown select has a purpose of setting font family, the supplemental description 11895 * could be "font family". If this node has children, its supplemental description serves 11896 * as additional information and is not intended to replace any existing information 11897 * in the subtree. This is different from the {@link #getContentDescription()} in that 11898 * this description is purely supplemental while a content description may be used 11899 * to replace a description for a node or its subtree that an assistive technology 11900 * would otherwise compute based on other properties of the node and its descendants. 11901 * 11902 * <p> 11903 * <strong>Note:</strong> Do not override this method, as it will have no 11904 * effect on the supplemental description presented to accessibility services. 11905 * You must call {@link #setSupplementalDescription(CharSequence)} to modify the 11906 * supplemental description. 11907 * 11908 * @return the supplemental description 11909 * @see #setSupplementalDescription(CharSequence) 11910 * @see #getContentDescription() 11911 * @attr ref android.R.styleable#View_supplementalDescription 11912 */ 11913 @FlaggedApi(FLAG_SUPPLEMENTAL_DESCRIPTION) 11914 @ViewDebug.ExportedProperty(category = "accessibility") 11915 @InspectableProperty 11916 @Nullable 11917 public CharSequence getSupplementalDescription() { 11918 return mSupplementalDescription; 11919 } 11920 11921 /** 11922 * Sets the {@link View}'s state description. 11923 * <p> 11924 * A state description briefly describes the states of the view and is primarily used 11925 * for accessibility support to determine how the states of a view should be presented to 11926 * the user. It is a supplement to the boolean states (for example, checked/unchecked) and 11927 * it is used for customized state description (for example, "wifi, connected, three bars"). 11928 * State description changes frequently while content description should change less often. 11929 * State description should be localized. For android widgets which have default state 11930 * descriptions, app developers can call this method to override the state descriptions. 11931 * Setting state description to null restores the default behavior. 11932 * 11933 * @param stateDescription The state description. 11934 * @see #getStateDescription() 11935 * @see #setContentDescription(CharSequence) for the difference between content and 11936 * state descriptions. 11937 */ 11938 @RemotableViewMethod 11939 public void setStateDescription(@Nullable CharSequence stateDescription) { 11940 if (mStateDescription == null) { 11941 if (stateDescription == null) { 11942 return; 11943 } 11944 } else if (mStateDescription.equals(stateDescription)) { 11945 return; 11946 } 11947 mStateDescription = stateDescription; 11948 if (!TextUtils.isEmpty(stateDescription) 11949 && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 11950 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 11951 } 11952 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 11953 AccessibilityEvent event = AccessibilityEvent.obtain(); 11954 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 11955 event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION); 11956 sendAccessibilityEventUnchecked(event); 11957 } 11958 } 11959 11960 /** 11961 * Sets the {@link View}'s content description. 11962 * <p> 11963 * A content description briefly describes the view and is primarily used 11964 * for accessibility support to determine how a view should be presented to 11965 * the user. In the case of a view with no textual representation, such as 11966 * {@link android.widget.ImageButton}, a useful content description 11967 * explains what the view does. For example, an image button with a phone 11968 * icon that is used to place a call may use "Call" as its content 11969 * description. An image of a floppy disk that is used to save a file may 11970 * use "Save". 11971 * 11972 * <p> 11973 * This should omit role or state. Role refers to the kind of user-interface element the View 11974 * is, such as a Button or Checkbox. State refers to a frequently changing property of the View, 11975 * such as an On/Off state of a button or the audio level of a volume slider. 11976 * 11977 * <p> 11978 * Content description updates are not frequent, and are used when the semantic content - not 11979 * the state - of the element changes. For example, a Play button might change to a Pause 11980 * button during music playback. 11981 * 11982 * @param contentDescription The content description. 11983 * @see #getContentDescription() 11984 * @see #setStateDescription(CharSequence)} for state changes. 11985 * @attr ref android.R.styleable#View_contentDescription 11986 */ 11987 @RemotableViewMethod 11988 public void setContentDescription(CharSequence contentDescription) { 11989 if (mContentDescription == null) { 11990 if (contentDescription == null) { 11991 return; 11992 } 11993 } else if (mContentDescription.equals(contentDescription)) { 11994 return; 11995 } 11996 mContentDescription = contentDescription; 11997 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 11998 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 11999 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 12000 notifySubtreeAccessibilityStateChangedIfNeeded(); 12001 } else { 12002 notifyViewAccessibilityStateChangedIfNeeded( 12003 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 12004 } 12005 } 12006 12007 /** 12008 * Sets the {@link View}'s supplemental description. 12009 * <p> 12010 * A supplemental description provides 12011 * brief supplemental information for this node, such as the purpose of the node when 12012 * that purpose is not conveyed within its textual representation. For example, if a 12013 * dropdown select has a purpose of setting font family, the supplemental description 12014 * could be "font family". If this node has children, its supplemental description serves 12015 * as additional information and is not intended to replace any existing information 12016 * in the subtree. This is different from the {@link #setContentDescription(CharSequence)} 12017 * in that this description is purely supplemental while a content description may be used 12018 * to replace a description for a node or its subtree that an assistive technology 12019 * would otherwise compute based on other properties of the node and its descendants. 12020 * 12021 * <p> 12022 * This should omit role or state. Role refers to the kind of user-interface element the View 12023 * is, such as a Button or Checkbox. State refers to a frequently changing property of the View, 12024 * such as an On/Off state of a button or the audio level of a volume slider. 12025 * 12026 * @param supplementalDescription The supplemental description. 12027 * @see #getSupplementalDescription() 12028 * @see #setContentDescription(CharSequence) 12029 * @see #setStateDescription(CharSequence) for state changes. 12030 * @attr ref android.R.styleable#View_supplementalDescription 12031 */ 12032 @FlaggedApi(FLAG_SUPPLEMENTAL_DESCRIPTION) 12033 @RemotableViewMethod 12034 public void setSupplementalDescription(@Nullable CharSequence supplementalDescription) { 12035 if (mSupplementalDescription == null) { 12036 if (supplementalDescription == null) { 12037 return; 12038 } 12039 } else if (mSupplementalDescription.equals(supplementalDescription)) { 12040 return; 12041 } 12042 mSupplementalDescription = supplementalDescription; 12043 final boolean nonEmptyDesc = supplementalDescription != null 12044 && !supplementalDescription.isEmpty(); 12045 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 12046 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 12047 notifySubtreeAccessibilityStateChangedIfNeeded(); 12048 } else { 12049 notifyViewAccessibilityStateChangedIfNeeded( 12050 AccessibilityEvent.CONTENT_CHANGE_TYPE_SUPPLEMENTAL_DESCRIPTION); 12051 } 12052 } 12053 12054 /** 12055 * Sets the id of a view that screen readers are requested to visit after this view. 12056 * 12057 * <p> 12058 * 12059 * For example, if view B should be visited before view A, with 12060 * B.setAccessibilityTraversalBefore(A), this requests that screen readers visit and traverse 12061 * view B before visiting view A. 12062 * 12063 * <p> 12064 * <b>Note:</b> Views are visited in the order determined by the screen reader. Avoid 12065 * explicitly manipulating focus order, as this may result in inconsistent user 12066 * experiences between apps. Instead, use other semantics, such as restructuring the view 12067 * hierarchy layout, to communicate order. 12068 * 12069 * <p> 12070 * Setting this view to be after a view that is not important for accessibility, 12071 * or if this view is not important for accessibility, means this method will have no effect if 12072 * the service is not aware of unimportant views. 12073 * 12074 * <p> 12075 * To avoid a risk of loops, set clear relationships between views. For example, if focus order 12076 * should be B -> A, and B.setAccessibilityTraversalBefore(A), then also call 12077 * A.setAccessibilityTraversalAfter(B). 12078 * 12079 * @param beforeId The id of a view this one precedes in accessibility traversal. 12080 * 12081 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 12082 * 12083 * @see #setImportantForAccessibility(int) 12084 * @see #setAccessibilityTraversalAfter(int) 12085 */ 12086 @RemotableViewMethod 12087 public void setAccessibilityTraversalBefore(@IdRes int beforeId) { 12088 if (mAccessibilityTraversalBeforeId == beforeId) { 12089 return; 12090 } 12091 mAccessibilityTraversalBeforeId = beforeId; 12092 notifyViewAccessibilityStateChangedIfNeeded( 12093 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12094 } 12095 12096 /** 12097 * Gets the id of a view before which this one is visited in accessibility traversal. 12098 * 12099 * @return The id of a view this one precedes in accessibility traversal if 12100 * specified, otherwise {@link #NO_ID}. 12101 * 12102 * @see #setAccessibilityTraversalBefore(int) 12103 */ 12104 @IdRes 12105 @InspectableProperty 12106 public int getAccessibilityTraversalBefore() { 12107 return mAccessibilityTraversalBeforeId; 12108 } 12109 12110 /** 12111 * Sets the id of a view that screen readers are requested to visit before this view. 12112 * 12113 * <p> 12114 * For example, if view B should be visited after A, with B.setAccessibilityTraversalAfter(A), 12115 * then this requests that screen readers visit and traverse view A before visiting view B. 12116 * 12117 * <p> 12118 * <b>Note:</b> Views are visited in the order determined by the screen reader. Avoid 12119 * explicitly manipulating focus order, as this may result in inconsistent user 12120 * experiences between apps. Instead, use other semantics, such as restructuring the view 12121 * hierarchy layout, to communicate order. 12122 * 12123 * <p> 12124 * Setting this view to be after a view that is not important for accessibility, 12125 * or if this view is not important for accessibility, means this method will have no effect if 12126 * the service is not aware of unimportant views. 12127 * 12128 * <p> 12129 * To avoid a risk of loops, set clear relationships between views. For example, if focus order 12130 * should be B -> A, and B.setAccessibilityTraversalBefore(A), then also call 12131 * A.setAccessibilityTraversalAfter(B). 12132 * 12133 * @param afterId The id of a view this one succeeds in accessibility traversal. 12134 * 12135 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 12136 * 12137 * @see #setImportantForAccessibility(int) 12138 * @see #setAccessibilityTraversalBefore(int) 12139 */ 12140 @RemotableViewMethod 12141 public void setAccessibilityTraversalAfter(@IdRes int afterId) { 12142 if (mAccessibilityTraversalAfterId == afterId) { 12143 return; 12144 } 12145 mAccessibilityTraversalAfterId = afterId; 12146 notifyViewAccessibilityStateChangedIfNeeded( 12147 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12148 } 12149 12150 /** 12151 * Gets the id of a view after which this one is visited in accessibility traversal. 12152 * 12153 * @return The id of a view this one succeedes in accessibility traversal if 12154 * specified, otherwise {@link #NO_ID}. 12155 * 12156 * @see #setAccessibilityTraversalAfter(int) 12157 */ 12158 @IdRes 12159 @InspectableProperty 12160 public int getAccessibilityTraversalAfter() { 12161 return mAccessibilityTraversalAfterId; 12162 } 12163 12164 /** 12165 * Gets the id of a view for which this view serves as a label for 12166 * accessibility purposes. 12167 * 12168 * @return The labeled view id. 12169 */ 12170 @IdRes 12171 @ViewDebug.ExportedProperty(category = "accessibility") 12172 @InspectableProperty 12173 public int getLabelFor() { 12174 return mLabelForId; 12175 } 12176 12177 /** 12178 * Sets the id of a view for which this view serves as a label for 12179 * accessibility purposes. 12180 * 12181 * @param id The labeled view id. 12182 */ 12183 @RemotableViewMethod 12184 public void setLabelFor(@IdRes int id) { 12185 if (mLabelForId == id) { 12186 return; 12187 } 12188 mLabelForId = id; 12189 if (mLabelForId != View.NO_ID 12190 && mID == View.NO_ID) { 12191 mID = generateViewId(); 12192 } 12193 notifyViewAccessibilityStateChangedIfNeeded( 12194 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12195 } 12196 12197 /** 12198 * Invoked whenever this view loses focus, either by losing window focus or by losing 12199 * focus within its window. This method can be used to clear any state tied to the 12200 * focus. For instance, if a button is held pressed with the trackball and the window 12201 * loses focus, this method can be used to cancel the press. 12202 * 12203 * Subclasses of View overriding this method should always call super.onFocusLost(). 12204 * 12205 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 12206 * @see #onWindowFocusChanged(boolean) 12207 * 12208 * @hide pending API council approval 12209 */ 12210 @CallSuper 12211 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 12212 protected void onFocusLost() { 12213 resetPressedState(); 12214 } 12215 12216 private void resetPressedState() { 12217 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 12218 return; 12219 } 12220 12221 if (isPressed()) { 12222 setPressed(false); 12223 12224 if (!mHasPerformedLongPress) { 12225 removeLongPressCallback(); 12226 } 12227 } 12228 } 12229 12230 /** 12231 * Returns true if this view has focus 12232 * 12233 * @return True if this view has focus, false otherwise. 12234 */ 12235 @ViewDebug.ExportedProperty(category = "focus") 12236 @InspectableProperty(hasAttributeId = false) 12237 public boolean isFocused() { 12238 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 12239 } 12240 12241 /** 12242 * Find the view in the hierarchy rooted at this view that currently has 12243 * focus. 12244 * 12245 * @return The view that currently has focus, or null if no focused view can 12246 * be found. 12247 */ 12248 public View findFocus() { 12249 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 12250 } 12251 12252 /** 12253 * Indicates whether this view is one of the set of scrollable containers in 12254 * its window. 12255 * 12256 * @return whether this view is one of the set of scrollable containers in 12257 * its window 12258 * 12259 * @attr ref android.R.styleable#View_isScrollContainer 12260 */ 12261 @InspectableProperty(name = "isScrollContainer") 12262 public boolean isScrollContainer() { 12263 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 12264 } 12265 12266 /** 12267 * Change whether this view is one of the set of scrollable containers in 12268 * its window. This will be used to determine whether the window can 12269 * resize or must pan when a soft input area is open -- scrollable 12270 * containers allow the window to use resize mode since the container 12271 * will appropriately shrink. 12272 * 12273 * @attr ref android.R.styleable#View_isScrollContainer 12274 */ 12275 public void setScrollContainer(boolean isScrollContainer) { 12276 if (isScrollContainer) { 12277 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 12278 mAttachInfo.mScrollContainers.add(this); 12279 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 12280 } 12281 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 12282 } else { 12283 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 12284 mAttachInfo.mScrollContainers.remove(this); 12285 } 12286 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 12287 } 12288 } 12289 12290 /** 12291 * Returns the quality of the drawing cache. 12292 * 12293 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 12294 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 12295 * 12296 * @see #setDrawingCacheQuality(int) 12297 * @see #setDrawingCacheEnabled(boolean) 12298 * @see #isDrawingCacheEnabled() 12299 * 12300 * @attr ref android.R.styleable#View_drawingCacheQuality 12301 * 12302 * @deprecated The view drawing cache was largely made obsolete with the introduction of 12303 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 12304 * layers are largely unnecessary and can easily result in a net loss in performance due to the 12305 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 12306 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 12307 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 12308 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 12309 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 12310 * software-rendered usages are discouraged and have compatibility issues with hardware-only 12311 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 12312 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 12313 * reports or unit testing the {@link PixelCopy} API is recommended. 12314 */ 12315 @Deprecated 12316 @DrawingCacheQuality 12317 @InspectableProperty(enumMapping = { 12318 @EnumEntry(value = DRAWING_CACHE_QUALITY_LOW, name = "low"), 12319 @EnumEntry(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"), 12320 @EnumEntry(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto") 12321 }) 12322 public int getDrawingCacheQuality() { 12323 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 12324 } 12325 12326 /** 12327 * Set the drawing cache quality of this view. This value is used only when the 12328 * drawing cache is enabled 12329 * 12330 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 12331 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 12332 * 12333 * @see #getDrawingCacheQuality() 12334 * @see #setDrawingCacheEnabled(boolean) 12335 * @see #isDrawingCacheEnabled() 12336 * 12337 * @attr ref android.R.styleable#View_drawingCacheQuality 12338 * 12339 * @deprecated The view drawing cache was largely made obsolete with the introduction of 12340 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 12341 * layers are largely unnecessary and can easily result in a net loss in performance due to the 12342 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 12343 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 12344 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 12345 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 12346 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 12347 * software-rendered usages are discouraged and have compatibility issues with hardware-only 12348 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 12349 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 12350 * reports or unit testing the {@link PixelCopy} API is recommended. 12351 */ 12352 @Deprecated 12353 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 12354 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 12355 } 12356 12357 /** 12358 * Returns whether the screen should remain on, corresponding to the current 12359 * value of {@link #KEEP_SCREEN_ON}. 12360 * 12361 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 12362 * 12363 * @see #setKeepScreenOn(boolean) 12364 * 12365 * @attr ref android.R.styleable#View_keepScreenOn 12366 */ 12367 @InspectableProperty 12368 public boolean getKeepScreenOn() { 12369 return (mViewFlags & KEEP_SCREEN_ON) != 0; 12370 } 12371 12372 /** 12373 * Controls whether the screen should remain on, modifying the 12374 * value of {@link #KEEP_SCREEN_ON}. 12375 * 12376 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 12377 * 12378 * @see #getKeepScreenOn() 12379 * 12380 * @attr ref android.R.styleable#View_keepScreenOn 12381 */ 12382 public void setKeepScreenOn(boolean keepScreenOn) { 12383 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 12384 } 12385 12386 /** 12387 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 12388 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 12389 * 12390 * @attr ref android.R.styleable#View_nextFocusLeft 12391 */ 12392 @IdRes 12393 @InspectableProperty(name = "nextFocusLeft") 12394 public int getNextFocusLeftId() { 12395 return mNextFocusLeftId; 12396 } 12397 12398 /** 12399 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 12400 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 12401 * decide automatically. 12402 * 12403 * @attr ref android.R.styleable#View_nextFocusLeft 12404 */ 12405 public void setNextFocusLeftId(@IdRes int nextFocusLeftId) { 12406 mNextFocusLeftId = nextFocusLeftId; 12407 } 12408 12409 /** 12410 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 12411 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 12412 * 12413 * @attr ref android.R.styleable#View_nextFocusRight 12414 */ 12415 @IdRes 12416 @InspectableProperty(name = "nextFocusRight") 12417 public int getNextFocusRightId() { 12418 return mNextFocusRightId; 12419 } 12420 12421 /** 12422 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 12423 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 12424 * decide automatically. 12425 * 12426 * @attr ref android.R.styleable#View_nextFocusRight 12427 */ 12428 public void setNextFocusRightId(@IdRes int nextFocusRightId) { 12429 mNextFocusRightId = nextFocusRightId; 12430 } 12431 12432 /** 12433 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 12434 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 12435 * 12436 * @attr ref android.R.styleable#View_nextFocusUp 12437 */ 12438 @IdRes 12439 @InspectableProperty(name = "nextFocusUp") 12440 public int getNextFocusUpId() { 12441 return mNextFocusUpId; 12442 } 12443 12444 /** 12445 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 12446 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 12447 * decide automatically. 12448 * 12449 * @attr ref android.R.styleable#View_nextFocusUp 12450 */ 12451 public void setNextFocusUpId(@IdRes int nextFocusUpId) { 12452 mNextFocusUpId = nextFocusUpId; 12453 } 12454 12455 /** 12456 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 12457 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 12458 * 12459 * @attr ref android.R.styleable#View_nextFocusDown 12460 */ 12461 @IdRes 12462 @InspectableProperty(name = "nextFocusDown") 12463 public int getNextFocusDownId() { 12464 return mNextFocusDownId; 12465 } 12466 12467 /** 12468 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 12469 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 12470 * decide automatically. 12471 * 12472 * @attr ref android.R.styleable#View_nextFocusDown 12473 */ 12474 public void setNextFocusDownId(@IdRes int nextFocusDownId) { 12475 mNextFocusDownId = nextFocusDownId; 12476 } 12477 12478 /** 12479 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 12480 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 12481 * 12482 * @attr ref android.R.styleable#View_nextFocusForward 12483 */ 12484 @IdRes 12485 @InspectableProperty(name = "nextFocusForward") 12486 public int getNextFocusForwardId() { 12487 return mNextFocusForwardId; 12488 } 12489 12490 /** 12491 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 12492 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 12493 * decide automatically. 12494 * 12495 * @attr ref android.R.styleable#View_nextFocusForward 12496 */ 12497 public void setNextFocusForwardId(@IdRes int nextFocusForwardId) { 12498 mNextFocusForwardId = nextFocusForwardId; 12499 } 12500 12501 /** 12502 * Gets the id of the root of the next keyboard navigation cluster. 12503 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 12504 * decide automatically. 12505 * 12506 * @attr ref android.R.styleable#View_nextClusterForward 12507 */ 12508 @IdRes 12509 @InspectableProperty(name = "nextClusterForward") 12510 public int getNextClusterForwardId() { 12511 return mNextClusterForwardId; 12512 } 12513 12514 /** 12515 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 12516 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 12517 * decide automatically. 12518 * 12519 * @attr ref android.R.styleable#View_nextClusterForward 12520 */ 12521 public void setNextClusterForwardId(@IdRes int nextClusterForwardId) { 12522 mNextClusterForwardId = nextClusterForwardId; 12523 } 12524 12525 /** 12526 * Returns the visibility of this view and all of its ancestors 12527 * 12528 * @return True if this view and all of its ancestors are {@link #VISIBLE} 12529 */ 12530 public boolean isShown() { 12531 View current = this; 12532 //noinspection ConstantConditions 12533 do { 12534 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 12535 return false; 12536 } 12537 ViewParent parent = current.mParent; 12538 if (parent == null) { 12539 return false; // We are not attached to the view root 12540 } 12541 if (!(parent instanceof View)) { 12542 return true; 12543 } 12544 current = (View) parent; 12545 } while (current != null); 12546 12547 return false; 12548 } 12549 12550 private boolean detached() { 12551 View current = this; 12552 //noinspection ConstantConditions 12553 do { 12554 if ((current.mPrivateFlags4 & PFLAG4_DETACHED) != 0) { 12555 return true; 12556 } 12557 ViewParent parent = current.mParent; 12558 if (parent == null) { 12559 return false; 12560 } 12561 if (!(parent instanceof View)) { 12562 return false; 12563 } 12564 current = (View) parent; 12565 } while (current != null); 12566 12567 return false; 12568 } 12569 12570 /** 12571 * Called by the view hierarchy when the content insets for a window have 12572 * changed, to allow it to adjust its content to fit within those windows. 12573 * The content insets tell you the space that the status bar, input method, 12574 * and other system windows infringe on the application's window. 12575 * 12576 * <p>You do not normally need to deal with this function, since the default 12577 * window decoration given to applications takes care of applying it to the 12578 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 12579 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 12580 * and your content can be placed under those system elements. You can then 12581 * use this method within your view hierarchy if you have parts of your UI 12582 * which you would like to ensure are not being covered. 12583 * 12584 * <p>The default implementation of this method simply applies the content 12585 * insets to the view's padding, consuming that content (modifying the 12586 * insets to be 0), and returning true. This behavior is off by default, but can 12587 * be enabled through {@link #setFitsSystemWindows(boolean)}. 12588 * 12589 * <p>This function's traversal down the hierarchy is depth-first. The same content 12590 * insets object is propagated down the hierarchy, so any changes made to it will 12591 * be seen by all following views (including potentially ones above in 12592 * the hierarchy since this is a depth-first traversal). The first view 12593 * that returns true will abort the entire traversal. 12594 * 12595 * <p>The default implementation works well for a situation where it is 12596 * used with a container that covers the entire window, allowing it to 12597 * apply the appropriate insets to its content on all edges. If you need 12598 * a more complicated layout (such as two different views fitting system 12599 * windows, one on the top of the window, and one on the bottom), 12600 * you can override the method and handle the insets however you would like. 12601 * Note that the insets provided by the framework are always relative to the 12602 * far edges of the window, not accounting for the location of the called view 12603 * within that window. (In fact when this method is called you do not yet know 12604 * where the layout will place the view, as it is done before layout happens.) 12605 * 12606 * <p>Note: unlike many View methods, there is no dispatch phase to this 12607 * call. If you are overriding it in a ViewGroup and want to allow the 12608 * call to continue to your children, you must be sure to call the super 12609 * implementation. 12610 * 12611 * <p>Here is a sample layout that makes use of fitting system windows 12612 * to have controls for a video view placed inside of the window decorations 12613 * that it hides and shows. This can be used with code like the second 12614 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 12615 * 12616 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 12617 * 12618 * @param insets Current content insets of the window. Prior to 12619 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 12620 * the insets or else you and Android will be unhappy. 12621 * 12622 * @return {@code true} if this view applied the insets and it should not 12623 * continue propagating further down the hierarchy, {@code false} otherwise. 12624 * @see #getFitsSystemWindows() 12625 * @see #setFitsSystemWindows(boolean) 12626 * @see #setSystemUiVisibility(int) 12627 * 12628 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 12629 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 12630 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 12631 * to implement handling their own insets. 12632 */ 12633 @Deprecated 12634 protected boolean fitSystemWindows(Rect insets) { 12635 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 12636 if (insets == null) { 12637 // Null insets by definition have already been consumed. 12638 // This call cannot apply insets since there are none to apply, 12639 // so return false. 12640 return false; 12641 } 12642 // If we're not in the process of dispatching the newer apply insets call, 12643 // that means we're not in the compatibility path. Dispatch into the newer 12644 // apply insets path and take things from there. 12645 try { 12646 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 12647 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 12648 } finally { 12649 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 12650 } 12651 } else { 12652 // We're being called from the newer apply insets path. 12653 // Perform the standard fallback behavior. 12654 return fitSystemWindowsInt(insets); 12655 } 12656 } 12657 12658 private boolean fitSystemWindowsInt(Rect insets) { 12659 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 12660 Rect localInsets = sThreadLocal.get(); 12661 boolean res = computeFitSystemWindows(insets, localInsets); 12662 applyInsets(localInsets); 12663 return res; 12664 } 12665 return false; 12666 } 12667 12668 private void applyInsets(Rect insets) { 12669 mUserPaddingStart = UNDEFINED_PADDING; 12670 mUserPaddingEnd = UNDEFINED_PADDING; 12671 mUserPaddingLeftInitial = insets.left; 12672 mUserPaddingRightInitial = insets.right; 12673 internalSetPadding(insets.left, insets.top, insets.right, insets.bottom); 12674 } 12675 12676 /** 12677 * Called when the view should apply {@link WindowInsets} according to its internal policy. 12678 * 12679 * <p>This method should be overridden by views that wish to apply a policy different from or 12680 * in addition to the default behavior. Clients that wish to force a view subtree 12681 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 12682 * 12683 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 12684 * it will be called during dispatch instead of this method. The listener may optionally 12685 * call this method from its own implementation if it wishes to apply the view's default 12686 * insets policy in addition to its own.</p> 12687 * 12688 * <p>Implementations of this method should either return the insets parameter unchanged 12689 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 12690 * that this view applied itself. This allows new inset types added in future platform 12691 * versions to pass through existing implementations unchanged without being erroneously 12692 * consumed.</p> 12693 * 12694 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 12695 * property is set then the view will consume the system window insets and apply them 12696 * as padding for the view.</p> 12697 * 12698 * @param insets Insets to apply 12699 * @return The supplied insets with any applied insets consumed 12700 */ 12701 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 12702 if ((mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 12703 && (mViewFlags & FITS_SYSTEM_WINDOWS) != 0) { 12704 return onApplyFrameworkOptionalFitSystemWindows(insets); 12705 } 12706 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 12707 // We weren't called from within a direct call to fitSystemWindows, 12708 // call into it as a fallback in case we're in a class that overrides it 12709 // and has logic to perform. 12710 if (fitSystemWindows(insets.getSystemWindowInsetsAsRect())) { 12711 return insets.consumeSystemWindowInsets(); 12712 } 12713 } else { 12714 // We were called from within a direct call to fitSystemWindows. 12715 if (fitSystemWindowsInt(insets.getSystemWindowInsetsAsRect())) { 12716 return insets.consumeSystemWindowInsets(); 12717 } 12718 } 12719 return insets; 12720 } 12721 12722 private WindowInsets onApplyFrameworkOptionalFitSystemWindows(WindowInsets insets) { 12723 Rect localInsets = sThreadLocal.get(); 12724 WindowInsets result = computeSystemWindowInsets(insets, localInsets); 12725 applyInsets(localInsets); 12726 return result; 12727 } 12728 12729 /** 12730 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 12731 * window insets to this view. The listener's 12732 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 12733 * method will be called instead of the view's 12734 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 12735 * 12736 * @param listener Listener to set 12737 * 12738 * @see #onApplyWindowInsets(WindowInsets) 12739 */ 12740 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 12741 getListenerInfo().mOnApplyWindowInsetsListener = listener; 12742 } 12743 12744 /** 12745 * Request to apply the given window insets to this view or another view in its subtree. 12746 * 12747 * <p>This method should be called by clients wishing to apply insets corresponding to areas 12748 * obscured by window decorations or overlays. This can include the status and navigation bars, 12749 * action bars, input methods and more. New inset categories may be added in the future. 12750 * The method returns the insets provided minus any that were applied by this view or its 12751 * children.</p> 12752 * 12753 * <p>Clients wishing to provide custom behavior should override the 12754 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 12755 * {@link OnApplyWindowInsetsListener} via the 12756 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 12757 * method.</p> 12758 * 12759 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 12760 * </p> 12761 * 12762 * @param insets Insets to apply 12763 * @return The provided insets minus the insets that were consumed 12764 */ 12765 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 12766 try { 12767 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 12768 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 12769 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 12770 } else { 12771 return onApplyWindowInsets(insets); 12772 } 12773 } finally { 12774 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 12775 } 12776 } 12777 12778 /** 12779 * Sets a {@link WindowInsetsAnimation.Callback} to be notified about animations of windows that 12780 * cause insets. 12781 * <p> 12782 * The callback's {@link WindowInsetsAnimation.Callback#getDispatchMode() 12783 * dispatch mode} will affect whether animation callbacks are dispatched to the children of 12784 * this view. 12785 * </p> 12786 * @param callback The callback to set. 12787 */ 12788 public void setWindowInsetsAnimationCallback( 12789 @Nullable WindowInsetsAnimation.Callback callback) { 12790 getListenerInfo().mWindowInsetsAnimationCallback = callback; 12791 } 12792 12793 /** 12794 * @return {@code true} if any {@link WindowInsetsAnimation.Callback} is registered on the view 12795 * or view tree of the sub-hierarchy {@code false} otherwise. 12796 * @hide 12797 */ 12798 public boolean hasWindowInsetsAnimationCallback() { 12799 return getListenerInfo().mWindowInsetsAnimationCallback != null; 12800 } 12801 12802 /** 12803 * Dispatches {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)} 12804 * when Window Insets animation is being prepared. 12805 * @param animation current animation 12806 * 12807 * @see WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation) 12808 */ 12809 public void dispatchWindowInsetsAnimationPrepare( 12810 @NonNull WindowInsetsAnimation animation) { 12811 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 12812 mListenerInfo.mWindowInsetsAnimationCallback.onPrepare(animation); 12813 } 12814 } 12815 12816 /** 12817 * Dispatches {@link WindowInsetsAnimation.Callback#onStart(WindowInsetsAnimation, Bounds)} 12818 * when Window Insets animation is started. 12819 * @param animation current animation 12820 * @param bounds the upper and lower {@link Bounds} that provides range of 12821 * {@link WindowInsetsAnimation}. 12822 * @return the upper and lower {@link Bounds}. 12823 */ 12824 @NonNull 12825 public Bounds dispatchWindowInsetsAnimationStart( 12826 @NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds) { 12827 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 12828 return mListenerInfo.mWindowInsetsAnimationCallback.onStart(animation, bounds); 12829 } 12830 return bounds; 12831 } 12832 12833 /** 12834 * Dispatches {@link WindowInsetsAnimation.Callback#onProgress(WindowInsets, List)} 12835 * when Window Insets animation makes progress. 12836 * @param insets The current {@link WindowInsets}. 12837 * @param runningAnimations The currently running {@link WindowInsetsAnimation}s. 12838 * @return current {@link WindowInsets}. 12839 */ 12840 @NonNull 12841 public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets, 12842 @NonNull List<WindowInsetsAnimation> runningAnimations) { 12843 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 12844 return mListenerInfo.mWindowInsetsAnimationCallback.onProgress(insets, 12845 runningAnimations); 12846 } else { 12847 return insets; 12848 } 12849 } 12850 12851 /** 12852 * Dispatches {@link WindowInsetsAnimation.Callback#onEnd(WindowInsetsAnimation)} 12853 * when Window Insets animation ends. 12854 * @param animation The current ongoing {@link WindowInsetsAnimation}. 12855 */ 12856 public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) { 12857 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 12858 mListenerInfo.mWindowInsetsAnimationCallback.onEnd(animation); 12859 } 12860 } 12861 12862 /** 12863 * Sets a list of areas within this view's post-layout coordinate space where the system 12864 * should not intercept touch or other pointing device gestures. <em>This method should 12865 * be called by {@link #onLayout(boolean, int, int, int, int)} or {@link #onDraw(Canvas)}.</em> 12866 * 12867 * <p>Use this to tell the system which specific sub-areas of a view need to receive gesture 12868 * input in order to function correctly in the presence of global system gestures that may 12869 * conflict. For example, if the system wishes to capture swipe-in-from-screen-edge gestures 12870 * to provide system-level navigation functionality, a view such as a navigation drawer 12871 * container can mark the left (or starting) edge of itself as requiring gesture capture 12872 * priority using this API. The system may then choose to relax its own gesture recognition 12873 * to allow the app to consume the user's gesture. It is not necessary for an app to register 12874 * exclusion rects for broadly spanning regions such as the entirety of a 12875 * <code>ScrollView</code> or for simple press and release click targets such as 12876 * <code>Button</code>. Mark an exclusion rect when interacting with a view requires 12877 * a precision touch gesture in a small area in either the X or Y dimension, such as 12878 * an edge swipe or dragging a <code>SeekBar</code> thumb.</p> 12879 * 12880 * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the 12881 * exclusions it takes into account. The limit does not apply while the navigation 12882 * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the 12883 * {@link android.inputmethodservice.InputMethodService input method} and 12884 * {@link Intent#CATEGORY_HOME home activity}. 12885 * </p> 12886 * 12887 * @param rects A list of precision gesture regions that this view needs to function correctly 12888 */ 12889 public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) { 12890 if (rects.isEmpty() && mListenerInfo == null) return; 12891 12892 final ListenerInfo info = getListenerInfo(); 12893 final boolean rectsChanged = !reduceChangedExclusionRectsMsgs() 12894 || !Objects.deepEquals(info.mSystemGestureExclusionRects, rects); 12895 if (info.mSystemGestureExclusionRects == null) { 12896 info.mSystemGestureExclusionRects = new ArrayList<>(); 12897 } 12898 if (rectsChanged) { 12899 deepCopyRectsObjectRecycling(info.mSystemGestureExclusionRects, rects); 12900 updatePositionUpdateListener(); 12901 postUpdate(this::updateSystemGestureExclusionRects); 12902 } 12903 } 12904 12905 private void deepCopyRectsObjectRecycling(@NonNull ArrayList<Rect> dest, List<Rect> src) { 12906 dest.ensureCapacity(src.size()); 12907 for (int i = 0; i < src.size(); i++) { 12908 if (i < dest.size()) { 12909 // Replace if there is an old rect to refresh 12910 dest.get(i).set(src.get(i)); 12911 } else { 12912 // Add a rect if the list enlarged 12913 dest.add(Rect.copyOrNull(src.get(i))); 12914 } 12915 } 12916 while (dest.size() > src.size()) { 12917 // Remove elements if the list shrank 12918 dest.removeLast(); 12919 } 12920 } 12921 12922 private void updatePositionUpdateListener() { 12923 final ListenerInfo info = getListenerInfo(); 12924 if (getSystemGestureExclusionRects().isEmpty() 12925 && collectPreferKeepClearRects().isEmpty() 12926 && collectUnrestrictedPreferKeepClearRects().isEmpty() 12927 && (info.mHandwritingArea == null || !shouldTrackHandwritingArea())) { 12928 if (info.mPositionUpdateListener != null) { 12929 mRenderNode.removePositionUpdateListener(info.mPositionUpdateListener); 12930 info.mPositionUpdateListener = null; 12931 info.mPositionChangedUpdate = null; 12932 } 12933 } else { 12934 if (info.mPositionUpdateListener == null) { 12935 info.mPositionChangedUpdate = () -> { 12936 updateSystemGestureExclusionRects(); 12937 updateKeepClearRects(); 12938 updateHandwritingArea(); 12939 }; 12940 info.mPositionUpdateListener = new RenderNode.PositionUpdateListener() { 12941 @Override 12942 public void positionChanged(long n, int l, int t, int r, int b) { 12943 postUpdate(info.mPositionChangedUpdate); 12944 } 12945 12946 @Override 12947 public void positionLost(long frameNumber) { 12948 postUpdate(info.mPositionChangedUpdate); 12949 } 12950 }; 12951 mRenderNode.addPositionUpdateListener(info.mPositionUpdateListener); 12952 } 12953 } 12954 } 12955 12956 /** 12957 * WARNING: this can be called by a hwui worker thread, not just the UI thread! 12958 */ 12959 private void postUpdate(Runnable r) { 12960 // Potentially racey from a background thread. It's ok if it's not perfect. 12961 final Handler h = getHandler(); 12962 if (h != null) { 12963 h.postAtFrontOfQueue(r); 12964 } 12965 } 12966 12967 void updateSystemGestureExclusionRects() { 12968 final AttachInfo ai = mAttachInfo; 12969 if (ai != null) { 12970 ai.mViewRootImpl.updateSystemGestureExclusionRectsForView(this); 12971 } 12972 } 12973 12974 /** 12975 * Retrieve the list of areas within this view's post-layout coordinate space where the system 12976 * should not intercept touch or other pointing device gestures. 12977 * 12978 * <p>Do not modify the returned list.</p> 12979 * 12980 * @return the list set by {@link #setSystemGestureExclusionRects(List)} 12981 */ 12982 @NonNull 12983 public List<Rect> getSystemGestureExclusionRects() { 12984 final ListenerInfo info = mListenerInfo; 12985 if (info != null) { 12986 final List<Rect> list = info.mSystemGestureExclusionRects; 12987 if (list != null) { 12988 return list; 12989 } 12990 } 12991 return Collections.emptyList(); 12992 } 12993 12994 /** 12995 * Set a preference to keep the bounds of this view clear from floating windows above this 12996 * view's window. This informs the system that the view is considered a vital area for the 12997 * user and that ideally it should not be covered. Setting this is only appropriate for UI 12998 * where the user would likely take action to uncover it. 12999 * <p> 13000 * The system will try to respect this preference, but when not possible will ignore it. 13001 * <p> 13002 * Note: This is independent from {@link #setPreferKeepClearRects}. If both are set, both will 13003 * be taken into account. 13004 * <p> 13005 * @see #setPreferKeepClearRects 13006 * @see #isPreferKeepClear 13007 * @attr ref android.R.styleable#View_preferKeepClear 13008 */ 13009 public final void setPreferKeepClear(boolean preferKeepClear) { 13010 getListenerInfo().mPreferKeepClear = preferKeepClear; 13011 updatePositionUpdateListener(); 13012 postUpdate(this::updateKeepClearRects); 13013 } 13014 13015 /** 13016 * Retrieve the preference for this view to be kept clear. This is set either by 13017 * {@link #setPreferKeepClear} or via the attribute android.R.styleable#View_preferKeepClear. 13018 * <p> 13019 * If this is {@code true}, the system will ignore the Rects set by 13020 * {@link #setPreferKeepClearRects} and try to keep the whole view clear. 13021 * <p> 13022 * @see #setPreferKeepClear 13023 * @attr ref android.R.styleable#View_preferKeepClear 13024 */ 13025 public final boolean isPreferKeepClear() { 13026 return mListenerInfo != null && mListenerInfo.mPreferKeepClear; 13027 } 13028 13029 /** 13030 * Set a preference to keep the provided rects clear from floating windows above this 13031 * view's window. This informs the system that these rects are considered vital areas for the 13032 * user and that ideally they should not be covered. Setting this is only appropriate for UI 13033 * where the user would likely take action to uncover it. 13034 * <p> 13035 * The system will try to respect this preference, but when not possible will ignore it. 13036 * <p> 13037 * Note: This is independent from {@link #setPreferKeepClear}. If both are set, both will be 13038 * taken into account. 13039 * <p> 13040 * @see #setPreferKeepClear 13041 * @see #getPreferKeepClearRects 13042 * 13043 * @param rects A list of rects in this view's local coordinate system 13044 */ 13045 public final void setPreferKeepClearRects(@NonNull List<Rect> rects) { 13046 final ListenerInfo info = getListenerInfo(); 13047 final boolean rectsChanged = !reduceChangedExclusionRectsMsgs() 13048 || !Objects.deepEquals(info.mKeepClearRects, rects); 13049 if (info.mKeepClearRects == null) { 13050 info.mKeepClearRects = new ArrayList<>(); 13051 } 13052 if (rectsChanged) { 13053 deepCopyRectsObjectRecycling(info.mKeepClearRects, rects); 13054 updatePositionUpdateListener(); 13055 postUpdate(this::updateKeepClearRects); 13056 } 13057 } 13058 13059 /** 13060 * @return the list of rects, set by {@link #setPreferKeepClearRects}. 13061 * 13062 * @see #setPreferKeepClearRects 13063 */ 13064 @NonNull 13065 public final List<Rect> getPreferKeepClearRects() { 13066 final ListenerInfo info = mListenerInfo; 13067 if (info != null && info.mKeepClearRects != null) { 13068 return new ArrayList(info.mKeepClearRects); 13069 } 13070 13071 return Collections.emptyList(); 13072 } 13073 13074 /** 13075 * Set a preference to keep the provided rects clear from floating windows above this 13076 * view's window. This informs the system that these rects are considered vital areas for the 13077 * user and that ideally they should not be covered. Setting this is only appropriate for UI 13078 * where the user would likely take action to uncover it. 13079 * <p> 13080 * Note: The difference with {@link #setPreferKeepClearRects} is that the system won't apply 13081 * restrictions to the rects set here. 13082 * <p> 13083 * @see #setPreferKeepClear 13084 * @see #getPreferKeepClearRects 13085 * 13086 * @param rects A list of rects in this view's local coordinate system 13087 * 13088 * @hide 13089 */ 13090 @SystemApi 13091 @RequiresPermission(android.Manifest.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS) 13092 public final void setUnrestrictedPreferKeepClearRects(@NonNull List<Rect> rects) { 13093 final ListenerInfo info = getListenerInfo(); 13094 final boolean rectsChanged = !reduceChangedExclusionRectsMsgs() 13095 || !Objects.deepEquals(info.mUnrestrictedKeepClearRects, rects); 13096 if (info.mUnrestrictedKeepClearRects == null) { 13097 info.mUnrestrictedKeepClearRects = new ArrayList<>(); 13098 } 13099 if (rectsChanged) { 13100 deepCopyRectsObjectRecycling(info.mUnrestrictedKeepClearRects, rects); 13101 updatePositionUpdateListener(); 13102 postUpdate(this::updateKeepClearRects); 13103 } 13104 } 13105 13106 /** 13107 * @return the list of rects, set by {@link #setPreferKeepClearRects}. 13108 * 13109 * @see #setPreferKeepClearRects 13110 * 13111 * @hide 13112 */ 13113 @SystemApi 13114 @NonNull 13115 public final List<Rect> getUnrestrictedPreferKeepClearRects() { 13116 final ListenerInfo info = mListenerInfo; 13117 if (info != null && info.mUnrestrictedKeepClearRects != null) { 13118 return new ArrayList(info.mUnrestrictedKeepClearRects); 13119 } 13120 13121 return Collections.emptyList(); 13122 } 13123 13124 void updateKeepClearRects() { 13125 final AttachInfo ai = mAttachInfo; 13126 if (ai != null) { 13127 ai.mViewRootImpl.updateKeepClearRectsForView(this); 13128 } 13129 } 13130 13131 /** 13132 * Retrieve the list of areas within this view's post-layout coordinate space which the 13133 * system will try to not cover with other floating elements, like the pip window. 13134 */ 13135 @NonNull 13136 List<Rect> collectPreferKeepClearRects() { 13137 ListenerInfo info = mListenerInfo; 13138 boolean keepClearForFocus = isFocused() 13139 && ViewConfiguration.get(mContext).isPreferKeepClearForFocusEnabled(); 13140 boolean keepBoundsClear = (info != null && info.mPreferKeepClear) || keepClearForFocus; 13141 boolean hasCustomKeepClearRects = info != null && info.mKeepClearRects != null; 13142 13143 if (!keepBoundsClear && !hasCustomKeepClearRects) { 13144 return Collections.emptyList(); 13145 } else if (keepBoundsClear && !hasCustomKeepClearRects) { 13146 return Collections.singletonList(new Rect(0, 0, getWidth(), getHeight())); 13147 } 13148 13149 final List<Rect> list = new ArrayList<>(); 13150 if (keepBoundsClear) { 13151 list.add(new Rect(0, 0, getWidth(), getHeight())); 13152 } 13153 13154 if (hasCustomKeepClearRects) { 13155 list.addAll(info.mKeepClearRects); 13156 } 13157 13158 return list; 13159 } 13160 13161 private void updatePreferKeepClearForFocus() { 13162 if (ViewConfiguration.get(mContext).isPreferKeepClearForFocusEnabled()) { 13163 updatePositionUpdateListener(); 13164 post(this::updateKeepClearRects); 13165 } 13166 } 13167 13168 /** 13169 * Retrieve the list of unrestricted areas within this view's post-layout coordinate space 13170 * which the system will try to not cover with other floating elements, like the pip window. 13171 */ 13172 @NonNull 13173 List<Rect> collectUnrestrictedPreferKeepClearRects() { 13174 final ListenerInfo info = mListenerInfo; 13175 if (info != null && info.mUnrestrictedKeepClearRects != null) { 13176 return info.mUnrestrictedKeepClearRects; 13177 } 13178 13179 return Collections.emptyList(); 13180 } 13181 13182 /** 13183 * Set the amount of offset applied to this view's stylus handwriting bounds. A positive offset 13184 * will offset the edge outwards.The base handwriting bounds of a view is its visible bounds. 13185 * The handwriting bounds offsets are applied to the base handwriting bounds to determine the 13186 * final handwriting bounds. 13187 * <p> This method is mainly used to enlarge the view's handwriting bounds for a better user 13188 * experience. 13189 * <p> Note that when the view is clipped (e.g. the view is in a 13190 * {@link android.widget.ScrollView}), the offsets are applied after the view's handwriting 13191 * bounds is clipped. 13192 * 13193 * @param offsetLeft the amount of pixel offset applied to the left edge outwards of the view's 13194 * handwriting bounds. 13195 * @param offsetTop the amount of pixel offset applied to the top edge outwards of the view's 13196 * handwriting bounds. 13197 * @param offsetRight the amount of pixel offset applied to the right edge outwards of the 13198 * view's handwriting bounds. 13199 * @param offsetBottom the amount of pixel offset applied to the bottom edge outwards of the 13200 * view's handwriting bounds. 13201 * 13202 * @see #setAutoHandwritingEnabled(boolean) 13203 * @see #getHandwritingBoundsOffsetLeft() 13204 * @see #getHandwritingBoundsOffsetTop() 13205 * @see #getHandwritingBoundsOffsetRight() 13206 * @see #getHandwritingBoundsOffsetBottom() 13207 */ 13208 public void setHandwritingBoundsOffsets(float offsetLeft, float offsetTop, 13209 float offsetRight, float offsetBottom) { 13210 mHandwritingBoundsOffsetLeft = offsetLeft; 13211 mHandwritingBoundsOffsetTop = offsetTop; 13212 mHandwritingBoundsOffsetRight = offsetRight; 13213 mHandwritingBoundsOffsetBottom = offsetBottom; 13214 } 13215 13216 /** 13217 * Return the amount of offset applied to the left edge of this view's handwriting bounds, 13218 * in the unit of pixel. 13219 * 13220 * @see #setAutoHandwritingEnabled(boolean) 13221 * @see #setHandwritingBoundsOffsets(float, float, float, float) 13222 */ 13223 public float getHandwritingBoundsOffsetLeft() { 13224 return mHandwritingBoundsOffsetLeft; 13225 } 13226 13227 /** 13228 * Return the amount of offset applied to the top edge of this view's handwriting bounds, 13229 * in the unit of pixel. 13230 * 13231 * @see #setAutoHandwritingEnabled(boolean) 13232 * @see #setHandwritingBoundsOffsets(float, float, float, float) 13233 */ 13234 public float getHandwritingBoundsOffsetTop() { 13235 return mHandwritingBoundsOffsetTop; 13236 } 13237 13238 /** 13239 * Return the amount of offset applied to the right edge of this view's handwriting bounds, in 13240 * the unit of pixel. 13241 * 13242 * @see #setAutoHandwritingEnabled(boolean) 13243 * @see #setHandwritingBoundsOffsets(float, float, float, float) 13244 */ 13245 public float getHandwritingBoundsOffsetRight() { 13246 return mHandwritingBoundsOffsetRight; 13247 } 13248 13249 /** 13250 * Return the amount of offset applied to the bottom edge of this view's handwriting bounds, in 13251 * the unit of pixel. 13252 * 13253 * @see #setAutoHandwritingEnabled(boolean) 13254 * @see #setHandwritingBoundsOffsets(float, float, float, float) 13255 */ 13256 public float getHandwritingBoundsOffsetBottom() { 13257 return mHandwritingBoundsOffsetBottom; 13258 } 13259 13260 13261 /** 13262 * Set a handwriting area in this view. If there is any stylus {@link MotionEvent} 13263 * occurs within this area, it will trigger stylus handwriting mode. This can be disabled by 13264 * disabling the auto handwriting initiation by calling 13265 * {@link #setAutoHandwritingEnabled(boolean)} with false. 13266 * 13267 * @attr rect the handwriting area in the view's local coordiniates. 13268 * 13269 * @see android.view.inputmethod.InputMethodManager#startStylusHandwriting(View) 13270 * @see #setAutoHandwritingEnabled(boolean) 13271 * 13272 * @hide 13273 */ 13274 public void setHandwritingArea(@Nullable Rect rect) { 13275 final ListenerInfo info = getListenerInfo(); 13276 info.mHandwritingArea = rect; 13277 updatePositionUpdateListener(); 13278 postUpdate(this::updateHandwritingArea); 13279 } 13280 13281 /** 13282 * Return the handwriting areas set on this view, in its local coordinates. 13283 * @see #setHandwritingArea(Rect) 13284 * 13285 * @hide 13286 */ 13287 @Nullable 13288 public Rect getHandwritingArea() { 13289 final ListenerInfo info = mListenerInfo; 13290 if (info != null && info.mHandwritingArea != null) { 13291 return new Rect(info.mHandwritingArea); 13292 } 13293 return null; 13294 } 13295 13296 void updateHandwritingArea() { 13297 // If autoHandwritingArea is not enabled, do nothing. 13298 if (!shouldTrackHandwritingArea()) return; 13299 final AttachInfo ai = mAttachInfo; 13300 if (ai != null) { 13301 ai.mViewRootImpl.getHandwritingInitiator().updateHandwritingAreasForView(this); 13302 } 13303 } 13304 13305 /** 13306 * Returns true if a stylus {@link MotionEvent} within this view's bounds should initiate 13307 * handwriting mode, either for this view ({@link #isAutoHandwritingEnabled()} is {@code true}) 13308 * or for a handwriting delegate view ({@link #getHandwritingDelegatorCallback()} is not {@code 13309 * null}). 13310 */ 13311 boolean shouldInitiateHandwriting() { 13312 return isAutoHandwritingEnabled() || getHandwritingDelegatorCallback() != null; 13313 } 13314 13315 /** 13316 * Returns whether the handwriting initiator should track the handwriting area for this view, 13317 * either to initiate handwriting mode, or to prepare handwriting delegation, or to show the 13318 * handwriting unsupported message. 13319 * @hide 13320 */ 13321 public boolean shouldTrackHandwritingArea() { 13322 return shouldInitiateHandwriting(); 13323 } 13324 13325 /** 13326 * Sets a callback which should be called when a stylus {@link MotionEvent} occurs within this 13327 * view's bounds. The callback will be called from the UI thread. 13328 * 13329 * <p>Setting a callback allows this view to act as a handwriting delegator, so that handwriting 13330 * mode for a delegate editor view can be initiated by stylus movement on this delegator view. 13331 * The callback implementation is expected to show and focus the delegate editor view. If a view 13332 * which returns {@code true} for {@link #isHandwritingDelegate()} creates an input connection 13333 * while the same stylus {@link MotionEvent} sequence is ongoing, handwriting mode will be 13334 * initiated for that view. 13335 * 13336 * <p>A common use case is a custom view which looks like a text editor but does not actually 13337 * support text editing itself, and clicking on the custom view causes an EditText to be shown. 13338 * To support handwriting initiation in this case, this method can be called on the custom view 13339 * to configure it as a delegator. The EditText should call {@link #setIsHandwritingDelegate} to 13340 * set it as a delegate. The {@code callback} implementation is typically the same as the click 13341 * listener implementation which shows the EditText. 13342 * 13343 * <p>If {@code null} is passed, this view will no longer act as a handwriting initiation 13344 * delegator. 13345 * 13346 * @param callback a callback which should be called when a stylus {@link MotionEvent} occurs 13347 * within this view's bounds 13348 */ 13349 public void setHandwritingDelegatorCallback(@Nullable Runnable callback) { 13350 mHandwritingDelegatorCallback = callback; 13351 if (callback != null) { 13352 setHandwritingArea(new Rect(0, 0, getWidth(), getHeight())); 13353 } 13354 } 13355 13356 /** 13357 * Returns the callback set by {@link #setHandwritingDelegatorCallback} which should be called 13358 * when a stylus {@link MotionEvent} occurs within this view's bounds. The callback should only 13359 * be called from the UI thread. 13360 */ 13361 @Nullable 13362 public Runnable getHandwritingDelegatorCallback() { 13363 return mHandwritingDelegatorCallback; 13364 } 13365 13366 /** 13367 * Specifies that this view may act as a handwriting initiation delegator for a delegate editor 13368 * view from the specified package. If this method is not called, delegators may only be used to 13369 * initiate handwriting mode for a delegate editor view from the same package as the delegator 13370 * view. This method allows specifying a different trusted package which may contain a delegate 13371 * editor view linked to this delegator view. 13372 * 13373 * <p>This method has no effect unless {@link #setHandwritingDelegatorCallback} is also called 13374 * to configure this view to act as a handwriting delegator. 13375 * 13376 * <p>If this method is called on the delegator view, then {@link 13377 * #setAllowedHandwritingDelegatorPackage} should also be called on the delegate editor view. 13378 * 13379 * <p>For example, to configure a delegator view in package 1: 13380 * 13381 * <pre> 13382 * delegatorView.setHandwritingDelegatorCallback(callback); 13383 * delegatorView.setAllowedHandwritingDelegatePackage(package2);</pre> 13384 * 13385 * Then to configure the corresponding delegate editor view in package 2: 13386 * 13387 * <pre> 13388 * delegateEditorView.setIsHandwritingDelegate(true); 13389 * delegateEditorView.setAllowedHandwritingDelegatorPackage(package1);</pre> 13390 * 13391 * @param allowedPackageName the package name of a delegate editor view linked to this delegator 13392 * view, or {@code null} to restore the default behavior of only allowing delegate editor 13393 * views from the same package as this delegator view 13394 */ 13395 public void setAllowedHandwritingDelegatePackage(@Nullable String allowedPackageName) { 13396 mAllowedHandwritingDelegatePackageName = allowedPackageName; 13397 } 13398 13399 /** 13400 * Returns the allowed package for delegate editor views for which this view may act as a 13401 * handwriting delegator, as set by {@link #setAllowedHandwritingDelegatePackage}. If {@link 13402 * #setAllowedHandwritingDelegatePackage} has not been called, or called with {@code null} 13403 * argument, this will return {@code null}, meaning that this delegator view may only be used to 13404 * initiate handwriting mode for a delegate editor view from the same package as this delegator 13405 * view. 13406 */ 13407 @Nullable 13408 public String getAllowedHandwritingDelegatePackageName() { 13409 return mAllowedHandwritingDelegatePackageName; 13410 } 13411 13412 /** 13413 * Sets this view to be a handwriting delegate. If a delegate view creates an input connection 13414 * while a stylus {@link MotionEvent} sequence from a delegator view is ongoing, handwriting 13415 * mode will be initiated for the delegate view. 13416 * 13417 * @param isHandwritingDelegate whether this view is a handwriting initiation delegate 13418 * @see #setHandwritingDelegatorCallback(Runnable) 13419 */ 13420 public void setIsHandwritingDelegate(boolean isHandwritingDelegate) { 13421 mIsHandwritingDelegate = isHandwritingDelegate; 13422 } 13423 13424 /** 13425 * Returns whether this view has been set as a handwriting delegate by {@link 13426 * #setIsHandwritingDelegate}. 13427 */ 13428 public boolean isHandwritingDelegate() { 13429 return mIsHandwritingDelegate; 13430 } 13431 13432 /** 13433 * Specifies that a view from the specified package may act as a handwriting delegator for this 13434 * delegate editor view. If this method is not called, only views from the same package as this 13435 * delegate editor view may act as a handwriting delegator. This method allows specifying a 13436 * different trusted package which may contain a delegator view linked to this delegate editor 13437 * view. 13438 * 13439 * <p>This method has no effect unless {@link #setIsHandwritingDelegate} is also called to 13440 * configure this view to act as a handwriting delegate. 13441 * 13442 * <p>If this method is called on the delegate editor view, then {@link 13443 * #setAllowedHandwritingDelegatePackage} should also be called on the delegator view. 13444 * 13445 * @param allowedPackageName the package name of a delegator view linked to this delegate editor 13446 * view, or {@code null} to restore the default behavior of only allowing delegator views 13447 * from the same package as this delegate editor view 13448 */ 13449 public void setAllowedHandwritingDelegatorPackage(@Nullable String allowedPackageName) { 13450 mAllowedHandwritingDelegatorPackageName = allowedPackageName; 13451 } 13452 13453 /** 13454 * Returns the allowed package for views which may act as a handwriting delegator for this 13455 * delegate editor view, as set by {@link #setAllowedHandwritingDelegatorPackage}. If {@link 13456 * #setAllowedHandwritingDelegatorPackage} has not been called, or called with {@code null} 13457 * argument, this will return {@code null}, meaning that only views from the same package as 13458 * this delegator editor view may act as a handwriting delegator. 13459 */ 13460 @Nullable 13461 public String getAllowedHandwritingDelegatorPackageName() { 13462 return mAllowedHandwritingDelegatorPackageName; 13463 } 13464 13465 /** 13466 * Sets flags configuring the handwriting delegation behavior for this delegate editor view. 13467 * 13468 * <p>This method has no effect unless {@link #setIsHandwritingDelegate} is also called to 13469 * configure this view to act as a handwriting delegate. 13470 * 13471 * @param flags {@link InputMethodManager#HANDWRITING_DELEGATE_FLAG_HOME_DELEGATOR_ALLOWED} or 13472 * {@code 0} 13473 */ 13474 @FlaggedApi(FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR) 13475 public void setHandwritingDelegateFlags( 13476 @InputMethodManager.HandwritingDelegateFlags int flags) { 13477 mHandwritingDelegateFlags = flags; 13478 } 13479 13480 /** 13481 * Returns flags configuring the handwriting delegation behavior for this delegate editor view, 13482 * as set by {@link #setHandwritingDelegateFlags}. 13483 */ 13484 @FlaggedApi(FLAG_HOME_SCREEN_HANDWRITING_DELEGATOR) 13485 public @InputMethodManager.HandwritingDelegateFlags int getHandwritingDelegateFlags() { 13486 return mHandwritingDelegateFlags; 13487 } 13488 13489 /** 13490 * Gets the coordinates of this view in the coordinate space of the 13491 * {@link Surface} that contains the view. 13492 * 13493 * <p>In multiple-screen scenarios, if the surface spans multiple screens, 13494 * the coordinate space of the surface also spans multiple screens. 13495 * 13496 * <p>After the method returns, the argument array contains the x and y 13497 * coordinates of the view relative to the view's left and top edges, 13498 * respectively. 13499 * 13500 * @param location A two-element integer array in which the view coordinates 13501 * are stored. The x-coordinate is at index 0; the y-coordinate, at 13502 * index 1. 13503 */ 13504 public void getLocationInSurface(@NonNull @Size(2) int[] location) { 13505 getLocationInWindow(location); 13506 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 13507 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 13508 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 13509 } 13510 } 13511 13512 /** 13513 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 13514 * only available if the view is attached. 13515 * 13516 * @return WindowInsets from the top of the view hierarchy or null if View is detached 13517 */ 13518 public WindowInsets getRootWindowInsets() { 13519 if (mAttachInfo != null) { 13520 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 13521 } 13522 return null; 13523 } 13524 13525 /** 13526 * Retrieves the single {@link WindowInsetsController} of the window this view is attached to. 13527 * 13528 * @return The {@link WindowInsetsController} or {@code null} if the view is neither attached to 13529 * a window nor a view tree with a decor. 13530 * @see Window#getInsetsController() 13531 */ 13532 public @Nullable WindowInsetsController getWindowInsetsController() { 13533 if (mAttachInfo != null) { 13534 return mAttachInfo.mViewRootImpl.getInsetsController(); 13535 } 13536 ViewParent parent = getParent(); 13537 if (parent instanceof View) { 13538 return ((View) parent).getWindowInsetsController(); 13539 } else if (parent instanceof ViewRootImpl) { 13540 // Between WindowManager.addView() and the first traversal AttachInfo isn't set yet. 13541 return ((ViewRootImpl) parent).getInsetsController(); 13542 } 13543 return null; 13544 } 13545 13546 13547 /** 13548 * Walk up the View hierarchy to find the nearest {@link OnBackInvokedDispatcher}. 13549 * 13550 * @return The {@link OnBackInvokedDispatcher} from this or the nearest 13551 * ancestor, or null if this view is both not attached and have no ancestor providing an 13552 * {@link OnBackInvokedDispatcher}. 13553 */ 13554 @Nullable 13555 public final OnBackInvokedDispatcher findOnBackInvokedDispatcher() { 13556 ViewParent parent = getParent(); 13557 if (parent != null) { 13558 return parent.findOnBackInvokedDispatcherForChild(this, this); 13559 } 13560 return null; 13561 } 13562 13563 /** 13564 * @hide Compute the insets that should be consumed by this view and the ones 13565 * that should propagate to those under it. 13566 * 13567 * Note: This is used by appcompat's ActionBarOverlayLayout through reflection. 13568 * 13569 * @param inoutInsets the insets given to this view 13570 * @param outLocalInsets the insets that should be applied to this view 13571 * @deprecated use {@link #computeSystemWindowInsets} 13572 * @return 13573 */ 13574 @Deprecated 13575 @UnsupportedAppUsage 13576 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 13577 WindowInsets innerInsets = computeSystemWindowInsets(new WindowInsets(inoutInsets), 13578 outLocalInsets); 13579 inoutInsets.set(innerInsets.getSystemWindowInsetsAsRect()); 13580 return innerInsets.isSystemWindowInsetsConsumed(); 13581 } 13582 13583 /** 13584 * Compute insets that should be consumed by this view and the ones that should propagate 13585 * to those under it. 13586 * 13587 * @param in Insets currently being processed by this View, likely received as a parameter 13588 * to {@link #onApplyWindowInsets(WindowInsets)}. 13589 * @param outLocalInsets A Rect that will receive the insets that should be consumed 13590 * by this view 13591 * @return Insets that should be passed along to views under this one 13592 */ 13593 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 13594 boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 13595 || (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; 13596 if (isOptionalFitSystemWindows && mAttachInfo != null) { 13597 OnContentApplyWindowInsetsListener listener = 13598 mAttachInfo.mContentOnApplyWindowInsetsListener; 13599 if (listener == null) { 13600 // The application wants to take care of fitting system window for 13601 // the content. 13602 outLocalInsets.setEmpty(); 13603 return in; 13604 } 13605 Pair<Insets, WindowInsets> result = listener.onContentApplyWindowInsets(this, in); 13606 outLocalInsets.set(result.first.toRect()); 13607 return result.second; 13608 } else { 13609 outLocalInsets.set(in.getSystemWindowInsetsAsRect()); 13610 return in.consumeSystemWindowInsets().inset(outLocalInsets); 13611 } 13612 } 13613 13614 /** 13615 * @return True if the window has the {@link OnContentApplyWindowInsetsListener}, and this means 13616 * the framework will apply window insets on the content of the window. 13617 * @hide 13618 */ 13619 protected boolean hasContentOnApplyWindowInsetsListener() { 13620 return mAttachInfo != null && mAttachInfo.mContentOnApplyWindowInsetsListener != null; 13621 } 13622 13623 /** 13624 * Sets whether or not this view should account for system screen decorations 13625 * such as the status bar and inset its content; that is, controlling whether 13626 * the default implementation of {@link #fitSystemWindows(Rect)} will be 13627 * executed. See that method for more details. 13628 * 13629 * <p>Note that if you are providing your own implementation of 13630 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 13631 * flag to true -- your implementation will be overriding the default 13632 * implementation that checks this flag. 13633 * 13634 * @param fitSystemWindows If true, then the default implementation of 13635 * {@link #fitSystemWindows(Rect)} will be executed. 13636 * 13637 * @attr ref android.R.styleable#View_fitsSystemWindows 13638 * @see #getFitsSystemWindows() 13639 * @see #fitSystemWindows(Rect) 13640 * @see #setSystemUiVisibility(int) 13641 */ 13642 public void setFitsSystemWindows(boolean fitSystemWindows) { 13643 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 13644 } 13645 13646 /** 13647 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 13648 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 13649 * will be executed. 13650 * 13651 * @return {@code true} if the default implementation of 13652 * {@link #fitSystemWindows(Rect)} will be executed. 13653 * 13654 * @attr ref android.R.styleable#View_fitsSystemWindows 13655 * @see #setFitsSystemWindows(boolean) 13656 * @see #fitSystemWindows(Rect) 13657 * @see #setSystemUiVisibility(int) 13658 */ 13659 @ViewDebug.ExportedProperty 13660 @InspectableProperty 13661 public boolean getFitsSystemWindows() { 13662 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 13663 } 13664 13665 /** @hide */ 13666 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 13667 public boolean fitsSystemWindows() { 13668 return getFitsSystemWindows(); 13669 } 13670 13671 /** 13672 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 13673 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 13674 */ 13675 @Deprecated 13676 public void requestFitSystemWindows() { 13677 if (mParent != null) { 13678 mParent.requestFitSystemWindows(); 13679 } 13680 } 13681 13682 /** 13683 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 13684 */ 13685 public void requestApplyInsets() { 13686 requestFitSystemWindows(); 13687 } 13688 13689 /** 13690 * @see #OPTIONAL_FITS_SYSTEM_WINDOWS 13691 * @hide 13692 */ 13693 @UnsupportedAppUsage 13694 public void makeOptionalFitsSystemWindows() { 13695 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 13696 } 13697 13698 /** 13699 * @see #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS 13700 * @hide 13701 */ 13702 public void makeFrameworkOptionalFitsSystemWindows() { 13703 mPrivateFlags4 |= PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS; 13704 } 13705 13706 /** 13707 * @hide 13708 */ 13709 public boolean isFrameworkOptionalFitsSystemWindows() { 13710 return (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; 13711 } 13712 13713 /** 13714 * Returns the visibility status for this view. 13715 * 13716 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 13717 * @attr ref android.R.styleable#View_visibility 13718 */ 13719 @ViewDebug.ExportedProperty(mapping = { 13720 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 13721 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 13722 @ViewDebug.IntToString(from = GONE, to = "GONE") 13723 }) 13724 @InspectableProperty(enumMapping = { 13725 @EnumEntry(value = VISIBLE, name = "visible"), 13726 @EnumEntry(value = INVISIBLE, name = "invisible"), 13727 @EnumEntry(value = GONE, name = "gone") 13728 }) 13729 @Visibility 13730 public int getVisibility() { 13731 return mViewFlags & VISIBILITY_MASK; 13732 } 13733 13734 /** 13735 * Set the visibility state of this view. 13736 * 13737 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 13738 * @attr ref android.R.styleable#View_visibility 13739 */ 13740 @RemotableViewMethod 13741 public void setVisibility(@Visibility int visibility) { 13742 setFlags(visibility, VISIBILITY_MASK); 13743 } 13744 13745 /** 13746 * Returns the enabled status for this view. The interpretation of the 13747 * enabled state varies by subclass. 13748 * 13749 * @return True if this view is enabled, false otherwise. 13750 */ 13751 @ViewDebug.ExportedProperty 13752 @InspectableProperty 13753 public boolean isEnabled() { 13754 return (mViewFlags & ENABLED_MASK) == ENABLED; 13755 } 13756 13757 /** 13758 * Set the enabled state of this view. The interpretation of the enabled 13759 * state varies by subclass. 13760 * 13761 * @param enabled True if this view is enabled, false otherwise. 13762 */ 13763 @RemotableViewMethod 13764 public void setEnabled(boolean enabled) { 13765 if (enabled == isEnabled()) return; 13766 13767 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 13768 13769 /* 13770 * The View most likely has to change its appearance, so refresh 13771 * the drawable state. 13772 */ 13773 refreshDrawableState(); 13774 13775 // Invalidate too, since the default behavior for views is to be 13776 // be drawn at 50% alpha rather than to change the drawable. 13777 invalidate(true); 13778 13779 if (!enabled) { 13780 cancelPendingInputEvents(); 13781 } 13782 notifyViewAccessibilityStateChangedIfNeeded( 13783 AccessibilityEvent.CONTENT_CHANGE_TYPE_ENABLED); 13784 } 13785 13786 /** 13787 * Set whether this view can receive the focus. 13788 * <p> 13789 * Setting this to false will also ensure that this view is not focusable 13790 * in touch mode. 13791 * 13792 * @param focusable If true, this view can receive the focus. 13793 * 13794 * @see #setFocusableInTouchMode(boolean) 13795 * @see #setFocusable(int) 13796 * @attr ref android.R.styleable#View_focusable 13797 */ 13798 @RemotableViewMethod 13799 public void setFocusable(boolean focusable) { 13800 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 13801 } 13802 13803 /** 13804 * Sets whether this view can receive focus. 13805 * <p> 13806 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 13807 * automatically based on the view's interactivity. This is the default. 13808 * <p> 13809 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 13810 * in touch mode. 13811 * 13812 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 13813 * or {@link #FOCUSABLE_AUTO}. 13814 * @see #setFocusableInTouchMode(boolean) 13815 * @attr ref android.R.styleable#View_focusable 13816 */ 13817 @RemotableViewMethod 13818 public void setFocusable(@Focusable int focusable) { 13819 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 13820 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 13821 } 13822 setFlags(focusable, FOCUSABLE_MASK); 13823 } 13824 13825 /** 13826 * Set whether this view can receive focus while in touch mode. 13827 * 13828 * Setting this to true will also ensure that this view is focusable. 13829 * 13830 * @param focusableInTouchMode If true, this view can receive the focus while 13831 * in touch mode. 13832 * 13833 * @see #setFocusable(boolean) 13834 * @attr ref android.R.styleable#View_focusableInTouchMode 13835 */ 13836 @RemotableViewMethod 13837 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 13838 // Focusable in touch mode should always be set before the focusable flag 13839 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 13840 // which, in touch mode, will not successfully request focus on this view 13841 // because the focusable in touch mode flag is not set 13842 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 13843 13844 // Clear FOCUSABLE_AUTO if set. 13845 if (focusableInTouchMode) { 13846 // Clears FOCUSABLE_AUTO if set. 13847 setFlags(FOCUSABLE, FOCUSABLE_MASK); 13848 } 13849 } 13850 13851 /** 13852 * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how 13853 * to autofill the view with the user's data. 13854 * 13855 * <p>Typically, there is only one way to autofill a view, but there could be more than one. 13856 * For example, if the application accepts either an username or email address to identify 13857 * an user. 13858 * 13859 * <p>These hints are not validated by the Android System, but passed "as is" to the service. 13860 * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_} 13861 * constants such as: 13862 * {@link #AUTOFILL_HINT_USERNAME}, {@link #AUTOFILL_HINT_PASSWORD}, 13863 * {@link #AUTOFILL_HINT_EMAIL_ADDRESS}, 13864 * {@link #AUTOFILL_HINT_NAME}, 13865 * {@link #AUTOFILL_HINT_PHONE}, 13866 * {@link #AUTOFILL_HINT_POSTAL_ADDRESS}, {@link #AUTOFILL_HINT_POSTAL_CODE}, 13867 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 13868 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 13869 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 13870 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or 13871 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}. 13872 * 13873 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set. 13874 * @attr ref android.R.styleable#View_autofillHints 13875 */ 13876 public void setAutofillHints(@Nullable String... autofillHints) { 13877 if (autofillHints == null || autofillHints.length == 0) { 13878 mAutofillHints = null; 13879 } else { 13880 mAutofillHints = autofillHints; 13881 } 13882 if (sensitiveContentAppProtection()) { 13883 if (getContentSensitivity() == CONTENT_SENSITIVITY_AUTO) { 13884 updateSensitiveViewsCountIfNeeded(isAggregatedVisible()); 13885 } 13886 } 13887 } 13888 13889 /** 13890 * @hide 13891 */ 13892 @TestApi 13893 public void setAutofilled(boolean isAutofilled, boolean hideHighlight) { 13894 boolean wasChanged = isAutofilled != isAutofilled(); 13895 13896 if (wasChanged) { 13897 if (isAutofilled) { 13898 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; 13899 } else { 13900 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; 13901 } 13902 13903 if (hideHighlight) { 13904 mPrivateFlags4 |= PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; 13905 } else { 13906 mPrivateFlags4 &= ~PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; 13907 } 13908 13909 invalidate(); 13910 } 13911 } 13912 13913 /** 13914 * Set whether this view should have sound effects enabled for events such as 13915 * clicking and touching. 13916 * 13917 * <p>You may wish to disable sound effects for a view if you already play sounds, 13918 * for instance, a dial key that plays dtmf tones. 13919 * 13920 * @param soundEffectsEnabled whether sound effects are enabled for this view. 13921 * @see #isSoundEffectsEnabled() 13922 * @see #playSoundEffect(int) 13923 * @attr ref android.R.styleable#View_soundEffectsEnabled 13924 */ 13925 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 13926 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 13927 } 13928 13929 /** 13930 * @return whether this view should have sound effects enabled for events such as 13931 * clicking and touching. 13932 * 13933 * @see #setSoundEffectsEnabled(boolean) 13934 * @see #playSoundEffect(int) 13935 * @attr ref android.R.styleable#View_soundEffectsEnabled 13936 */ 13937 @ViewDebug.ExportedProperty 13938 @InspectableProperty 13939 public boolean isSoundEffectsEnabled() { 13940 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 13941 } 13942 13943 /** 13944 * Set whether this view should have haptic feedback for events such as 13945 * long presses. 13946 * 13947 * <p>You may wish to disable haptic feedback if your view already controls 13948 * its own haptic feedback. 13949 * 13950 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 13951 * @see #isHapticFeedbackEnabled() 13952 * @see #performHapticFeedback(int) 13953 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 13954 */ 13955 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 13956 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 13957 } 13958 13959 /** 13960 * @return whether this view should have haptic feedback enabled for events 13961 * such as long presses. 13962 * 13963 * @see #setHapticFeedbackEnabled(boolean) 13964 * @see #performHapticFeedback(int) 13965 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 13966 */ 13967 @ViewDebug.ExportedProperty 13968 @InspectableProperty 13969 public boolean isHapticFeedbackEnabled() { 13970 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 13971 } 13972 13973 /** 13974 * Returns the layout direction for this view. 13975 * 13976 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 13977 * {@link #LAYOUT_DIRECTION_RTL}, 13978 * {@link #LAYOUT_DIRECTION_INHERIT} or 13979 * {@link #LAYOUT_DIRECTION_LOCALE}. 13980 * 13981 * @attr ref android.R.styleable#View_layoutDirection 13982 * 13983 * @hide 13984 */ 13985 @ViewDebug.ExportedProperty(category = "layout", mapping = { 13986 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 13987 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 13988 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 13989 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 13990 }) 13991 @InspectableProperty(hasAttributeId = false, enumMapping = { 13992 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 13993 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl"), 13994 @EnumEntry(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"), 13995 @EnumEntry(value = LAYOUT_DIRECTION_LOCALE, name = "locale") 13996 }) 13997 @LayoutDir 13998 public int getRawLayoutDirection() { 13999 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 14000 } 14001 14002 /** 14003 * Set the layout direction for this view. This will propagate a reset of layout direction 14004 * resolution to the view's children and resolve layout direction for this view. 14005 * 14006 * @param layoutDirection the layout direction to set. Should be one of: 14007 * 14008 * {@link #LAYOUT_DIRECTION_LTR}, 14009 * {@link #LAYOUT_DIRECTION_RTL}, 14010 * {@link #LAYOUT_DIRECTION_INHERIT}, 14011 * {@link #LAYOUT_DIRECTION_LOCALE}. 14012 * 14013 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 14014 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 14015 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 14016 * 14017 * @attr ref android.R.styleable#View_layoutDirection 14018 */ 14019 @RemotableViewMethod 14020 public void setLayoutDirection(@LayoutDir int layoutDirection) { 14021 if (getRawLayoutDirection() != layoutDirection) { 14022 // Reset the current layout direction and the resolved one 14023 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 14024 resetRtlProperties(); 14025 // Set the new layout direction (filtered) 14026 mPrivateFlags2 |= 14027 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 14028 // We need to resolve all RTL properties as they all depend on layout direction 14029 resolveRtlPropertiesIfNeeded(); 14030 requestLayout(); 14031 invalidate(true); 14032 } 14033 } 14034 14035 /** 14036 * Returns the resolved layout direction for this view. 14037 * 14038 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 14039 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 14040 * 14041 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 14042 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 14043 * 14044 * @attr ref android.R.styleable#View_layoutDirection 14045 */ 14046 @ViewDebug.ExportedProperty(category = "layout", mapping = { 14047 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 14048 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 14049 }) 14050 @InspectableProperty(enumMapping = { 14051 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 14052 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl") 14053 }) 14054 @ResolvedLayoutDir 14055 public int getLayoutDirection() { 14056 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 14057 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 14058 } 14059 14060 /** 14061 * Indicates whether or not this view's layout is right-to-left. This is resolved from 14062 * layout attribute and/or the inherited value from the parent 14063 * 14064 * @return true if the layout is right-to-left. 14065 * 14066 * @hide 14067 */ 14068 @ViewDebug.ExportedProperty(category = "layout") 14069 @UnsupportedAppUsage 14070 public boolean isLayoutRtl() { 14071 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 14072 } 14073 14074 /** 14075 * Indicates whether the view is currently tracking transient state that the 14076 * app should not need to concern itself with saving and restoring, but that 14077 * the framework should take special note to preserve when possible. 14078 * 14079 * <p>A view with transient state cannot be trivially rebound from an external 14080 * data source, such as an adapter binding item views in a list. This may be 14081 * because the view is performing an animation, tracking user selection 14082 * of content, or similar.</p> 14083 * 14084 * @return true if the view has transient state 14085 */ 14086 @ViewDebug.ExportedProperty(category = "layout") 14087 public boolean hasTransientState() { 14088 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 14089 } 14090 14091 /** 14092 * Set whether this view is currently tracking transient state that the 14093 * framework should attempt to preserve when possible. This flag is reference counted, 14094 * so every call to setHasTransientState(true) should be paired with a later call 14095 * to setHasTransientState(false). 14096 * 14097 * <p>A view with transient state cannot be trivially rebound from an external 14098 * data source, such as an adapter binding item views in a list. This may be 14099 * because the view is performing an animation, tracking user selection 14100 * of content, or similar.</p> 14101 * 14102 * @param hasTransientState true if this view has transient state 14103 */ 14104 public void setHasTransientState(boolean hasTransientState) { 14105 final boolean oldHasTransientState = hasTransientState(); 14106 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 14107 mTransientStateCount - 1; 14108 if (mTransientStateCount < 0) { 14109 mTransientStateCount = 0; 14110 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 14111 "unmatched pair of setHasTransientState calls"); 14112 } else if ((hasTransientState && mTransientStateCount == 1) || 14113 (!hasTransientState && mTransientStateCount == 0)) { 14114 // update flag if we've just incremented up from 0 or decremented down to 0 14115 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 14116 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 14117 final boolean newHasTransientState = hasTransientState(); 14118 if (mParent != null && newHasTransientState != oldHasTransientState) { 14119 try { 14120 mParent.childHasTransientStateChanged(this, newHasTransientState); 14121 } catch (AbstractMethodError e) { 14122 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 14123 " does not fully implement ViewParent", e); 14124 } 14125 } 14126 } 14127 } 14128 14129 /** 14130 * Set the view is tracking translation transient state. This flag is used to check if the view 14131 * need to call setHasTransientState(false) to reset transient state that set when starting 14132 * translation. 14133 * 14134 * @param hasTranslationTransientState true if this view has translation transient state 14135 * @hide 14136 */ 14137 public void setHasTranslationTransientState(boolean hasTranslationTransientState) { 14138 if (hasTranslationTransientState) { 14139 mPrivateFlags4 |= PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 14140 } else { 14141 mPrivateFlags4 &= ~PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 14142 } 14143 } 14144 14145 /** 14146 * @hide 14147 */ 14148 public boolean hasTranslationTransientState() { 14149 return (mPrivateFlags4 & PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE) 14150 == PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 14151 } 14152 14153 /** 14154 * @hide 14155 */ 14156 public void clearTranslationState() { 14157 if (mViewTranslationCallback != null) { 14158 mViewTranslationCallback.onClearTranslation(this); 14159 } 14160 clearViewTranslationResponse(); 14161 if (hasTranslationTransientState()) { 14162 setHasTransientState(false); 14163 setHasTranslationTransientState(false); 14164 } 14165 } 14166 14167 /** 14168 * Returns true if this view is currently attached to a window. 14169 */ 14170 public boolean isAttachedToWindow() { 14171 return mAttachInfo != null; 14172 } 14173 14174 /** 14175 * Returns true if this view has been through at least one layout since it 14176 * was last attached to or detached from a window. 14177 */ 14178 public boolean isLaidOut() { 14179 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 14180 } 14181 14182 /** 14183 * @return {@code true} if laid-out and not about to do another layout. 14184 */ 14185 boolean isLayoutValid() { 14186 return isLaidOut() && ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == 0); 14187 } 14188 14189 /** 14190 * If this view doesn't do any drawing on its own, set this flag to 14191 * allow further optimizations. By default, this flag is not set on 14192 * View, but could be set on some View subclasses such as ViewGroup. 14193 * 14194 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 14195 * you should clear this flag. 14196 * 14197 * @param willNotDraw whether or not this View draw on its own 14198 */ 14199 public void setWillNotDraw(boolean willNotDraw) { 14200 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 14201 } 14202 14203 /** 14204 * Returns whether or not this View draws on its own. 14205 * 14206 * @return true if this view has nothing to draw, false otherwise 14207 */ 14208 @ViewDebug.ExportedProperty(category = "drawing") 14209 public boolean willNotDraw() { 14210 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 14211 } 14212 14213 /** 14214 * When a View's drawing cache is enabled, drawing is redirected to an 14215 * offscreen bitmap. Some views, like an ImageView, must be able to 14216 * bypass this mechanism if they already draw a single bitmap, to avoid 14217 * unnecessary usage of the memory. 14218 * 14219 * @param willNotCacheDrawing true if this view does not cache its 14220 * drawing, false otherwise 14221 * 14222 * @deprecated The view drawing cache was largely made obsolete with the introduction of 14223 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 14224 * layers are largely unnecessary and can easily result in a net loss in performance due to the 14225 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 14226 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 14227 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 14228 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 14229 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 14230 * software-rendered usages are discouraged and have compatibility issues with hardware-only 14231 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 14232 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 14233 * reports or unit testing the {@link PixelCopy} API is recommended. 14234 */ 14235 @Deprecated 14236 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 14237 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 14238 } 14239 14240 /** 14241 * Returns whether or not this View can cache its drawing or not. 14242 * 14243 * @return true if this view does not cache its drawing, false otherwise 14244 * 14245 * @deprecated The view drawing cache was largely made obsolete with the introduction of 14246 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 14247 * layers are largely unnecessary and can easily result in a net loss in performance due to the 14248 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 14249 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 14250 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 14251 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 14252 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 14253 * software-rendered usages are discouraged and have compatibility issues with hardware-only 14254 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 14255 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 14256 * reports or unit testing the {@link PixelCopy} API is recommended. 14257 */ 14258 @ViewDebug.ExportedProperty(category = "drawing") 14259 @Deprecated 14260 public boolean willNotCacheDrawing() { 14261 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 14262 } 14263 14264 /** 14265 * Indicates whether this view reacts to click events or not. 14266 * 14267 * @return true if the view is clickable, false otherwise 14268 * 14269 * @see #setClickable(boolean) 14270 * @attr ref android.R.styleable#View_clickable 14271 */ 14272 @ViewDebug.ExportedProperty 14273 @InspectableProperty 14274 public boolean isClickable() { 14275 return (mViewFlags & CLICKABLE) == CLICKABLE; 14276 } 14277 14278 /** 14279 * Enables or disables click events for this view. When a view 14280 * is clickable it will change its state to "pressed" on every click. 14281 * Subclasses should set the view clickable to visually react to 14282 * user's clicks. 14283 * 14284 * @param clickable true to make the view clickable, false otherwise 14285 * 14286 * @see #isClickable() 14287 * @attr ref android.R.styleable#View_clickable 14288 */ 14289 public void setClickable(boolean clickable) { 14290 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 14291 } 14292 14293 /** 14294 * Enables or disables click events for this view when disabled. 14295 * 14296 * @param clickableWhenDisabled true to make the view clickable, false otherwise 14297 * 14298 * @attr ref android.R.styleable#View_allowClickWhenDisabled 14299 */ 14300 public void setAllowClickWhenDisabled(boolean clickableWhenDisabled) { 14301 if (clickableWhenDisabled) { 14302 mPrivateFlags4 |= PFLAG4_ALLOW_CLICK_WHEN_DISABLED; 14303 } else { 14304 mPrivateFlags4 &= ~PFLAG4_ALLOW_CLICK_WHEN_DISABLED; 14305 } 14306 } 14307 14308 /** 14309 * Indicates whether this view reacts to long click events or not. 14310 * 14311 * @return true if the view is long clickable, false otherwise 14312 * 14313 * @see #setLongClickable(boolean) 14314 * @attr ref android.R.styleable#View_longClickable 14315 */ 14316 @InspectableProperty 14317 public boolean isLongClickable() { 14318 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 14319 } 14320 14321 /** 14322 * Enables or disables long click events for this view. When a view is long 14323 * clickable it reacts to the user holding down the button for a longer 14324 * duration than a tap. This event can either launch the listener or a 14325 * context menu. 14326 * 14327 * @param longClickable true to make the view long clickable, false otherwise 14328 * @see #isLongClickable() 14329 * @attr ref android.R.styleable#View_longClickable 14330 */ 14331 public void setLongClickable(boolean longClickable) { 14332 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 14333 } 14334 14335 /** 14336 * Indicates whether this view reacts to context clicks or not. 14337 * 14338 * @return true if the view is context clickable, false otherwise 14339 * @see #setContextClickable(boolean) 14340 * @attr ref android.R.styleable#View_contextClickable 14341 */ 14342 @InspectableProperty 14343 public boolean isContextClickable() { 14344 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 14345 } 14346 14347 /** 14348 * Enables or disables context clicking for this view. This event can launch the listener. 14349 * 14350 * @param contextClickable true to make the view react to a context click, false otherwise 14351 * @see #isContextClickable() 14352 * @attr ref android.R.styleable#View_contextClickable 14353 */ 14354 public void setContextClickable(boolean contextClickable) { 14355 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 14356 } 14357 14358 /** 14359 * Sets the pressed state for this view and provides a touch coordinate for 14360 * animation hinting. 14361 * 14362 * @param pressed Pass true to set the View's internal state to "pressed", 14363 * or false to reverts the View's internal state from a 14364 * previously set "pressed" state. 14365 * @param x The x coordinate of the touch that caused the press 14366 * @param y The y coordinate of the touch that caused the press 14367 */ 14368 private void setPressed(boolean pressed, float x, float y) { 14369 if (pressed) { 14370 drawableHotspotChanged(x, y); 14371 } 14372 14373 setPressed(pressed); 14374 } 14375 14376 /** 14377 * Sets the pressed state for this view. 14378 * 14379 * @see #isClickable() 14380 * @see #setClickable(boolean) 14381 * 14382 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 14383 * the View's internal state from a previously set "pressed" state. 14384 */ 14385 public void setPressed(boolean pressed) { 14386 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 14387 14388 if (pressed) { 14389 mPrivateFlags |= PFLAG_PRESSED; 14390 } else { 14391 mPrivateFlags &= ~PFLAG_PRESSED; 14392 } 14393 14394 if (needsRefresh) { 14395 refreshDrawableState(); 14396 } 14397 dispatchSetPressed(pressed); 14398 } 14399 14400 /** 14401 * Dispatch setPressed to all of this View's children. 14402 * 14403 * @see #setPressed(boolean) 14404 * 14405 * @param pressed The new pressed state 14406 */ 14407 protected void dispatchSetPressed(boolean pressed) { 14408 } 14409 14410 /** 14411 * Indicates whether the view is currently in pressed state. Unless 14412 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 14413 * the pressed state. 14414 * 14415 * @see #setPressed(boolean) 14416 * @see #isClickable() 14417 * @see #setClickable(boolean) 14418 * 14419 * @return true if the view is currently pressed, false otherwise 14420 */ 14421 @ViewDebug.ExportedProperty 14422 @InspectableProperty(hasAttributeId = false) 14423 public boolean isPressed() { 14424 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 14425 } 14426 14427 /** 14428 * @hide 14429 * Indicates whether this view will participate in data collection through 14430 * {@link ViewStructure}. If true, it will not provide any data 14431 * for itself or its children. If false, the normal data collection will be allowed. 14432 * 14433 * @return Returns false if assist data collection is not blocked, else true. 14434 * 14435 * @see #setAssistBlocked(boolean) 14436 * @attr ref android.R.styleable#View_assistBlocked 14437 */ 14438 public boolean isAssistBlocked() { 14439 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 14440 } 14441 14442 /** 14443 * @hide 14444 * Controls whether assist data collection from this view and its children is enabled 14445 * (that is, whether {@link #onProvideStructure} and 14446 * {@link #onProvideVirtualStructure} will be called). The default value is false, 14447 * allowing normal assist collection. Setting this to false will disable assist collection. 14448 * 14449 * @param enabled Set to true to <em>disable</em> assist data collection, or false 14450 * (the default) to allow it. 14451 * 14452 * @see #isAssistBlocked() 14453 * @see #onProvideStructure 14454 * @see #onProvideVirtualStructure 14455 * @attr ref android.R.styleable#View_assistBlocked 14456 */ 14457 @UnsupportedAppUsage 14458 public void setAssistBlocked(boolean enabled) { 14459 if (enabled) { 14460 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 14461 } else { 14462 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 14463 } 14464 } 14465 14466 /** 14467 * Indicates whether this view will save its state (that is, 14468 * whether its {@link #onSaveInstanceState} method will be called). 14469 * 14470 * @return Returns true if the view state saving is enabled, else false. 14471 * 14472 * @see #setSaveEnabled(boolean) 14473 * @attr ref android.R.styleable#View_saveEnabled 14474 */ 14475 @InspectableProperty 14476 public boolean isSaveEnabled() { 14477 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 14478 } 14479 14480 /** 14481 * Controls whether the saving of this view's state is 14482 * enabled (that is, whether its {@link #onSaveInstanceState} method 14483 * will be called). Note that even if freezing is enabled, the 14484 * view still must have an id assigned to it (via {@link #setId(int)}) 14485 * for its state to be saved. This flag can only disable the 14486 * saving of this view; any child views may still have their state saved. 14487 * 14488 * @param enabled Set to false to <em>disable</em> state saving, or true 14489 * (the default) to allow it. 14490 * 14491 * @see #isSaveEnabled() 14492 * @see #setId(int) 14493 * @see #onSaveInstanceState() 14494 * @attr ref android.R.styleable#View_saveEnabled 14495 */ 14496 public void setSaveEnabled(boolean enabled) { 14497 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 14498 } 14499 14500 /** 14501 * Gets whether the framework should discard touches when the view's 14502 * window is obscured by another visible window at the touched location. 14503 * Refer to the {@link View} security documentation for more details. 14504 * 14505 * @return True if touch filtering is enabled. 14506 * 14507 * @see #setFilterTouchesWhenObscured(boolean) 14508 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 14509 */ 14510 @ViewDebug.ExportedProperty 14511 @InspectableProperty 14512 public boolean getFilterTouchesWhenObscured() { 14513 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 14514 } 14515 14516 /** 14517 * Sets whether the framework should discard touches when the view's 14518 * window is obscured by another visible window at the touched location. 14519 * Refer to the {@link View} security documentation for more details. 14520 * 14521 * @param enabled True if touch filtering should be enabled. 14522 * 14523 * @see #getFilterTouchesWhenObscured 14524 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 14525 */ 14526 public void setFilterTouchesWhenObscured(boolean enabled) { 14527 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 14528 FILTER_TOUCHES_WHEN_OBSCURED); 14529 calculateAccessibilityDataSensitive(); 14530 } 14531 14532 /** 14533 * Indicates whether the entire hierarchy under this view will save its 14534 * state when a state saving traversal occurs from its parent. The default 14535 * is true; if false, these views will not be saved unless 14536 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 14537 * 14538 * @return Returns true if the view state saving from parent is enabled, else false. 14539 * 14540 * @see #setSaveFromParentEnabled(boolean) 14541 */ 14542 public boolean isSaveFromParentEnabled() { 14543 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 14544 } 14545 14546 /** 14547 * Controls whether the entire hierarchy under this view will save its 14548 * state when a state saving traversal occurs from its parent. The default 14549 * is true; if false, these views will not be saved unless 14550 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 14551 * 14552 * @param enabled Set to false to <em>disable</em> state saving, or true 14553 * (the default) to allow it. 14554 * 14555 * @see #isSaveFromParentEnabled() 14556 * @see #setId(int) 14557 * @see #onSaveInstanceState() 14558 */ 14559 public void setSaveFromParentEnabled(boolean enabled) { 14560 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 14561 } 14562 14563 14564 /** 14565 * Returns whether this View is currently able to take focus. 14566 * 14567 * @return True if this view can take focus, or false otherwise. 14568 */ 14569 @ViewDebug.ExportedProperty(category = "focus") 14570 public final boolean isFocusable() { 14571 return FOCUSABLE == (mViewFlags & FOCUSABLE); 14572 } 14573 14574 /** 14575 * Returns the focusable setting for this view. 14576 * 14577 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 14578 * @attr ref android.R.styleable#View_focusable 14579 */ 14580 @ViewDebug.ExportedProperty(mapping = { 14581 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 14582 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 14583 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 14584 }, category = "focus") 14585 @InspectableProperty(enumMapping = { 14586 @EnumEntry(value = NOT_FOCUSABLE, name = "false"), 14587 @EnumEntry(value = FOCUSABLE, name = "true"), 14588 @EnumEntry(value = FOCUSABLE_AUTO, name = "auto") 14589 }) 14590 @Focusable 14591 public int getFocusable() { 14592 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 14593 } 14594 14595 /** 14596 * When a view is focusable, it may not want to take focus when in touch mode. 14597 * For example, a button would like focus when the user is navigating via a D-pad 14598 * so that the user can click on it, but once the user starts touching the screen, 14599 * the button shouldn't take focus 14600 * @return Whether the view is focusable in touch mode. 14601 * @attr ref android.R.styleable#View_focusableInTouchMode 14602 */ 14603 @ViewDebug.ExportedProperty(category = "focus") 14604 @InspectableProperty 14605 public final boolean isFocusableInTouchMode() { 14606 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 14607 } 14608 14609 /** 14610 * Returns whether the view should be treated as a focusable unit by screen reader 14611 * accessibility tools. 14612 * <p> 14613 * <b>Note:</b> Use 14614 * {@link androidx.core.view.ViewCompat#setScreenReaderFocusable(View, boolean)} 14615 * for backwards-compatibility. </aside> 14616 * @see #setScreenReaderFocusable(boolean) 14617 * 14618 * @return Whether the view should be treated as a focusable unit by screen reader. 14619 * 14620 * @attr ref android.R.styleable#View_screenReaderFocusable 14621 */ 14622 @InspectableProperty 14623 public boolean isScreenReaderFocusable() { 14624 return (mPrivateFlags3 & PFLAG3_SCREEN_READER_FOCUSABLE) != 0; 14625 } 14626 14627 /** 14628 * Sets whether this View should be a focusable element for screen readers 14629 * and include non-focusable Views from its subtree when providing feedback. 14630 * <p> 14631 * Note: this is similar to using <a href="#attr_android:focusable">{@code android:focusable}, 14632 * but does not impact input focus behavior. 14633 * 14634 * @param screenReaderFocusable Whether the view should be treated as a unit by screen reader 14635 * accessibility tools. 14636 * 14637 * @attr ref android.R.styleable#View_screenReaderFocusable 14638 */ 14639 public void setScreenReaderFocusable(boolean screenReaderFocusable) { 14640 updatePflags3AndNotifyA11yIfChanged(PFLAG3_SCREEN_READER_FOCUSABLE, screenReaderFocusable); 14641 } 14642 14643 /** 14644 * Gets whether this view is a heading for accessibility purposes. 14645 * 14646 * @return {@code true} if the view is a heading, {@code false} otherwise. 14647 * 14648 * @attr ref android.R.styleable#View_accessibilityHeading 14649 */ 14650 @InspectableProperty 14651 public boolean isAccessibilityHeading() { 14652 return (mPrivateFlags3 & PFLAG3_ACCESSIBILITY_HEADING) != 0; 14653 } 14654 14655 /** 14656 * Set if view is a heading for a section of content for accessibility purposes. 14657 * <p> 14658 * Users of some accessibility services can choose to navigate between headings 14659 * instead of between paragraphs, words, etc. Apps that provide headings on 14660 * sections of text can help the text navigation experience. 14661 * <p> 14662 * <b>Note:</b> Use {@link androidx.core.view.ViewCompat#setAccessibilityHeading(View, boolean)} 14663 * for backwards-compatibility. </aside> 14664 * 14665 * @param isHeading {@code true} if the view is a heading, {@code false} otherwise. 14666 * 14667 * @attr ref android.R.styleable#View_accessibilityHeading 14668 */ 14669 public void setAccessibilityHeading(boolean isHeading) { 14670 updatePflags3AndNotifyA11yIfChanged(PFLAG3_ACCESSIBILITY_HEADING, isHeading); 14671 } 14672 14673 private void updatePflags3AndNotifyA11yIfChanged(int mask, boolean newValue) { 14674 int pflags3 = mPrivateFlags3; 14675 if (newValue) { 14676 pflags3 |= mask; 14677 } else { 14678 pflags3 &= ~mask; 14679 } 14680 14681 if (pflags3 != mPrivateFlags3) { 14682 mPrivateFlags3 = pflags3; 14683 notifyViewAccessibilityStateChangedIfNeeded( 14684 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 14685 } 14686 } 14687 14688 /** 14689 * Find the nearest view in the specified direction that can take focus. 14690 * This does not actually give focus to that view. 14691 * 14692 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 14693 * 14694 * @return The nearest focusable in the specified direction, or null if none 14695 * can be found. 14696 */ 14697 public View focusSearch(@FocusRealDirection int direction) { 14698 if (mParent != null) { 14699 return mParent.focusSearch(this, direction); 14700 } else { 14701 return null; 14702 } 14703 } 14704 14705 /** 14706 * Returns whether this View is a root of a keyboard navigation cluster. 14707 * 14708 * @return True if this view is a root of a cluster, or false otherwise. 14709 * @attr ref android.R.styleable#View_keyboardNavigationCluster 14710 */ 14711 @ViewDebug.ExportedProperty(category = "focus") 14712 @InspectableProperty 14713 public final boolean isKeyboardNavigationCluster() { 14714 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 14715 } 14716 14717 /** 14718 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters 14719 * will be ignored. 14720 * 14721 * @return the keyboard navigation cluster that this view is in (can be this view) 14722 * or {@code null} if not in one 14723 */ 14724 View findKeyboardNavigationCluster() { 14725 if (mParent instanceof View) { 14726 View cluster = ((View) mParent).findKeyboardNavigationCluster(); 14727 if (cluster != null) { 14728 return cluster; 14729 } else if (isKeyboardNavigationCluster()) { 14730 return this; 14731 } 14732 } 14733 return null; 14734 } 14735 14736 /** 14737 * Set whether this view is a root of a keyboard navigation cluster. 14738 * 14739 * @param isCluster If true, this view is a root of a cluster. 14740 * 14741 * @attr ref android.R.styleable#View_keyboardNavigationCluster 14742 */ 14743 public void setKeyboardNavigationCluster(boolean isCluster) { 14744 if (isCluster) { 14745 mPrivateFlags3 |= PFLAG3_CLUSTER; 14746 } else { 14747 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 14748 } 14749 } 14750 14751 /** 14752 * Sets this View as the one which receives focus the next time cluster navigation jumps 14753 * to the cluster containing this View. This does NOT change focus even if the cluster 14754 * containing this view is current. 14755 * 14756 * @hide 14757 */ 14758 @TestApi 14759 public final void setFocusedInCluster() { 14760 setFocusedInCluster(findKeyboardNavigationCluster()); 14761 } 14762 14763 private void setFocusedInCluster(View cluster) { 14764 if (this instanceof ViewGroup) { 14765 ((ViewGroup) this).mFocusedInCluster = null; 14766 } 14767 if (cluster == this) { 14768 return; 14769 } 14770 ViewParent parent = mParent; 14771 View child = this; 14772 while (parent instanceof ViewGroup) { 14773 ((ViewGroup) parent).mFocusedInCluster = child; 14774 if (parent == cluster) { 14775 break; 14776 } 14777 child = (View) parent; 14778 parent = parent.getParent(); 14779 } 14780 } 14781 14782 private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) { 14783 if (oldFocus != null) { 14784 View oldCluster = oldFocus.findKeyboardNavigationCluster(); 14785 View cluster = findKeyboardNavigationCluster(); 14786 if (oldCluster != cluster) { 14787 // Going from one cluster to another, so save last-focused. 14788 // This covers cluster jumps because they are always FOCUS_DOWN 14789 oldFocus.setFocusedInCluster(oldCluster); 14790 if (!(oldFocus.mParent instanceof ViewGroup)) { 14791 return; 14792 } 14793 if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) { 14794 // This is a result of ordered navigation so consider navigation through 14795 // the previous cluster "complete" and clear its last-focused memory. 14796 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 14797 } else if (oldFocus instanceof ViewGroup 14798 && ((ViewGroup) oldFocus).getDescendantFocusability() 14799 == ViewGroup.FOCUS_AFTER_DESCENDANTS 14800 && ViewRootImpl.isViewDescendantOf(this, oldFocus)) { 14801 // This means oldFocus is not focusable since it obviously has a focusable 14802 // child (this). Don't restore focus to it in the future. 14803 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 14804 } 14805 } 14806 } 14807 } 14808 14809 /** 14810 * Returns whether this View should receive focus when the focus is restored for the view 14811 * hierarchy containing this view. 14812 * <p> 14813 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 14814 * window or serves as a target of cluster navigation. 14815 * 14816 * @see #restoreDefaultFocus() 14817 * 14818 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 14819 * @attr ref android.R.styleable#View_focusedByDefault 14820 */ 14821 @ViewDebug.ExportedProperty(category = "focus") 14822 @InspectableProperty 14823 public final boolean isFocusedByDefault() { 14824 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 14825 } 14826 14827 /** 14828 * Sets whether this View should receive focus when the focus is restored for the view 14829 * hierarchy containing this view. 14830 * <p> 14831 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 14832 * window or serves as a target of cluster navigation. 14833 * 14834 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 14835 * {@code false} otherwise. 14836 * 14837 * @see #restoreDefaultFocus() 14838 * 14839 * @attr ref android.R.styleable#View_focusedByDefault 14840 */ 14841 @RemotableViewMethod 14842 public void setFocusedByDefault(boolean isFocusedByDefault) { 14843 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 14844 return; 14845 } 14846 14847 if (isFocusedByDefault) { 14848 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 14849 } else { 14850 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 14851 } 14852 14853 if (mParent instanceof ViewGroup) { 14854 if (isFocusedByDefault) { 14855 ((ViewGroup) mParent).setDefaultFocus(this); 14856 } else { 14857 ((ViewGroup) mParent).clearDefaultFocus(this); 14858 } 14859 } 14860 } 14861 14862 /** 14863 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 14864 * 14865 * @return {@code true} if this view has default focus, {@code false} otherwise 14866 */ 14867 boolean hasDefaultFocus() { 14868 return isFocusedByDefault(); 14869 } 14870 14871 /** 14872 * Find the nearest keyboard navigation cluster in the specified direction. 14873 * This does not actually give focus to that cluster. 14874 * 14875 * @param currentCluster The starting point of the search. Null means the current cluster is not 14876 * found yet 14877 * @param direction Direction to look 14878 * 14879 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 14880 * can be found 14881 */ 14882 public View keyboardNavigationClusterSearch(View currentCluster, 14883 @FocusDirection int direction) { 14884 if (isKeyboardNavigationCluster()) { 14885 currentCluster = this; 14886 } 14887 if (isRootNamespace()) { 14888 // Root namespace means we should consider ourselves the top of the 14889 // tree for group searching; otherwise we could be group searching 14890 // into other tabs. see LocalActivityManager and TabHost for more info. 14891 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 14892 this, currentCluster, direction); 14893 } else if (mParent != null) { 14894 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 14895 } 14896 return null; 14897 } 14898 14899 /** 14900 * This method is the last chance for the focused view and its ancestors to 14901 * respond to an arrow key. This is called when the focused view did not 14902 * consume the key internally, nor could the view system find a new view in 14903 * the requested direction to give focus to. 14904 * 14905 * @param focused The currently focused view. 14906 * @param direction The direction focus wants to move. One of FOCUS_UP, 14907 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 14908 * @return True if the this view consumed this unhandled move. 14909 */ 14910 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 14911 return false; 14912 } 14913 14914 /** 14915 * Sets whether this View should use a default focus highlight when it gets focused but doesn't 14916 * have {@link android.R.attr#state_focused} defined in its background. 14917 * 14918 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus 14919 * highlight, {@code false} otherwise. 14920 * 14921 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 14922 */ 14923 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { 14924 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; 14925 } 14926 14927 /** 14928 * Returns whether this View should use a default focus highlight when it gets focused but 14929 * doesn't have {@link android.R.attr#state_focused} defined in its background. 14930 * 14931 * @return True if this View should use a default focus highlight. 14932 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 14933 */ 14934 @ViewDebug.ExportedProperty(category = "focus") 14935 @InspectableProperty 14936 public final boolean getDefaultFocusHighlightEnabled() { 14937 return mDefaultFocusHighlightEnabled; 14938 } 14939 14940 /** 14941 * If a user manually specified the next view id for a particular direction, 14942 * use the root to look up the view. 14943 * @param root The root view of the hierarchy containing this view. 14944 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 14945 * or FOCUS_BACKWARD. 14946 * @return The user specified next view, or null if there is none. 14947 */ 14948 View findUserSetNextFocus(View root, @FocusDirection int direction) { 14949 switch (direction) { 14950 case FOCUS_LEFT: 14951 if (mNextFocusLeftId == View.NO_ID) return null; 14952 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 14953 case FOCUS_RIGHT: 14954 if (mNextFocusRightId == View.NO_ID) return null; 14955 return findViewInsideOutShouldExist(root, mNextFocusRightId); 14956 case FOCUS_UP: 14957 if (mNextFocusUpId == View.NO_ID) return null; 14958 return findViewInsideOutShouldExist(root, mNextFocusUpId); 14959 case FOCUS_DOWN: 14960 if (mNextFocusDownId == View.NO_ID) return null; 14961 return findViewInsideOutShouldExist(root, mNextFocusDownId); 14962 case FOCUS_FORWARD: 14963 if (mNextFocusForwardId == View.NO_ID) return null; 14964 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 14965 case FOCUS_BACKWARD: { 14966 if (mID == View.NO_ID) return null; 14967 final View rootView = root; 14968 final View startView = this; 14969 // Since we have forward links but no backward links, we need to find the view that 14970 // forward links to this view. We can't just find the view with the specified ID 14971 // because view IDs need not be unique throughout the tree. 14972 return root.findViewByPredicateInsideOut(startView, 14973 t -> findViewInsideOutShouldExist(rootView, t, t.mNextFocusForwardId) 14974 == startView); 14975 } 14976 } 14977 return null; 14978 } 14979 14980 /** 14981 * If a user manually specified the next keyboard-navigation cluster for a particular direction, 14982 * use the root to look up the view. 14983 * 14984 * @param root the root view of the hierarchy containing this view 14985 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD} 14986 * @return the user-specified next cluster, or {@code null} if there is none 14987 */ 14988 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { 14989 switch (direction) { 14990 case FOCUS_FORWARD: 14991 if (mNextClusterForwardId == View.NO_ID) return null; 14992 return findViewInsideOutShouldExist(root, mNextClusterForwardId); 14993 case FOCUS_BACKWARD: { 14994 if (mID == View.NO_ID) return null; 14995 final int id = mID; 14996 return root.findViewByPredicateInsideOut(this, 14997 (Predicate<View>) t -> t.mNextClusterForwardId == id); 14998 } 14999 } 15000 return null; 15001 } 15002 15003 private View findViewInsideOutShouldExist(View root, int id) { 15004 return findViewInsideOutShouldExist(root, this, id); 15005 } 15006 15007 private View findViewInsideOutShouldExist(View root, View start, int id) { 15008 if (mMatchIdPredicate == null) { 15009 mMatchIdPredicate = new MatchIdPredicate(); 15010 } 15011 mMatchIdPredicate.mId = id; 15012 View result = root.findViewByPredicateInsideOut(start, mMatchIdPredicate); 15013 if (result == null) { 15014 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 15015 } 15016 return result; 15017 } 15018 15019 /** 15020 * Find and return all focusable views that are descendants of this view, 15021 * possibly including this view if it is focusable itself. 15022 * 15023 * @param direction The direction of the focus 15024 * @return A list of focusable views 15025 */ 15026 public ArrayList<View> getFocusables(@FocusDirection int direction) { 15027 ArrayList<View> result = new ArrayList<View>(24); 15028 addFocusables(result, direction); 15029 return result; 15030 } 15031 15032 /** 15033 * Add any focusable views that are descendants of this view (possibly 15034 * including this view if it is focusable itself) to views. If we are in touch mode, 15035 * only add views that are also focusable in touch mode. 15036 * 15037 * @param views Focusable views found so far 15038 * @param direction The direction of the focus 15039 */ 15040 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 15041 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 15042 } 15043 15044 /** 15045 * Adds any focusable views that are descendants of this view (possibly 15046 * including this view if it is focusable itself) to views. This method 15047 * adds all focusable views regardless if we are in touch mode or 15048 * only views focusable in touch mode if we are in touch mode or 15049 * only views that can take accessibility focus if accessibility is enabled 15050 * depending on the focusable mode parameter. 15051 * 15052 * @param views Focusable views found so far or null if all we are interested is 15053 * the number of focusables. 15054 * @param direction The direction of the focus. 15055 * @param focusableMode The type of focusables to be added. 15056 * 15057 * @see #FOCUSABLES_ALL 15058 * @see #FOCUSABLES_TOUCH_MODE 15059 */ 15060 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 15061 @FocusableMode int focusableMode) { 15062 if (views == null) { 15063 return; 15064 } 15065 if (!canTakeFocus()) { 15066 return; 15067 } 15068 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 15069 && !isFocusableInTouchMode()) { 15070 return; 15071 } 15072 views.add(this); 15073 } 15074 15075 /** 15076 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 15077 * including this view if it is a cluster root itself) to views. 15078 * 15079 * @param views Keyboard navigation cluster roots found so far 15080 * @param direction Direction to look 15081 */ 15082 public void addKeyboardNavigationClusters( 15083 @NonNull Collection<View> views, 15084 int direction) { 15085 if (!isKeyboardNavigationCluster()) { 15086 return; 15087 } 15088 if (!hasFocusable()) { 15089 return; 15090 } 15091 views.add(this); 15092 } 15093 15094 /** 15095 * Finds the Views that contain given text. The containment is case insensitive. 15096 * The search is performed by either the text that the View renders or the content 15097 * description that describes the view for accessibility purposes and the view does 15098 * not render or both. Clients can specify how the search is to be performed via 15099 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 15100 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 15101 * 15102 * @param outViews The output list of matching Views. 15103 * @param searched The text to match against. 15104 * 15105 * @see #FIND_VIEWS_WITH_TEXT 15106 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 15107 * @see #setContentDescription(CharSequence) 15108 */ 15109 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 15110 @FindViewFlags int flags) { 15111 if (getAccessibilityNodeProvider() != null) { 15112 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 15113 outViews.add(this); 15114 } 15115 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 15116 && (searched != null && searched.length() > 0) 15117 && (mContentDescription != null && mContentDescription.length() > 0)) { 15118 String searchedLowerCase = searched.toString().toLowerCase(); 15119 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 15120 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 15121 outViews.add(this); 15122 } 15123 } 15124 } 15125 15126 /** 15127 * Find and return all touchable views that are descendants of this view, 15128 * possibly including this view if it is touchable itself. 15129 * 15130 * @return A list of touchable views 15131 */ 15132 public ArrayList<View> getTouchables() { 15133 ArrayList<View> result = new ArrayList<View>(); 15134 addTouchables(result); 15135 return result; 15136 } 15137 15138 /** 15139 * Add any touchable views that are descendants of this view (possibly 15140 * including this view if it is touchable itself) to views. 15141 * 15142 * @param views Touchable views found so far 15143 */ 15144 public void addTouchables(ArrayList<View> views) { 15145 final int viewFlags = mViewFlags; 15146 15147 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 15148 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 15149 && (viewFlags & ENABLED_MASK) == ENABLED) { 15150 views.add(this); 15151 } 15152 } 15153 15154 /** 15155 * Returns whether this View is accessibility focused. 15156 * 15157 * @return True if this View is accessibility focused. 15158 */ 15159 @InspectableProperty(hasAttributeId = false) 15160 public boolean isAccessibilityFocused() { 15161 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 15162 } 15163 15164 /** 15165 * Call this to try to give accessibility focus to this view. 15166 * 15167 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 15168 * returns false or the view is no visible or the view already has accessibility 15169 * focus. 15170 * 15171 * See also {@link #focusSearch(int)}, which is what you call to say that you 15172 * have focus, and you want your parent to look for the next one. 15173 * 15174 * <p> 15175 * <b>Note:</b> Avoid setting accessibility focus. This is intended to be controlled by screen 15176 * readers. Apps changing focus can confuse screen readers, so the resulting behavior can vary 15177 * by device and screen reader version. 15178 * 15179 * @return Whether this view actually took accessibility focus. 15180 * 15181 * @hide 15182 */ 15183 @UnsupportedAppUsage 15184 public boolean requestAccessibilityFocus() { 15185 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 15186 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 15187 return false; 15188 } 15189 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 15190 return false; 15191 } 15192 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 15193 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 15194 ViewRootImpl viewRootImpl = getViewRootImpl(); 15195 if (viewRootImpl != null) { 15196 viewRootImpl.setAccessibilityFocus(this, null); 15197 } 15198 invalidate(); 15199 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 15200 return true; 15201 } 15202 return false; 15203 } 15204 15205 /** 15206 * Call this to try to clear accessibility focus of this view. 15207 * 15208 * See also {@link #focusSearch(int)}, which is what you call to say that you 15209 * have focus, and you want your parent to look for the next one. 15210 * 15211 * @hide 15212 */ 15213 @UnsupportedAppUsage 15214 public void clearAccessibilityFocus() { 15215 clearAccessibilityFocusNoCallbacks(0); 15216 15217 // Clear the global reference of accessibility focus if this view or 15218 // any of its descendants had accessibility focus. This will NOT send 15219 // an event or update internal state if focus is cleared from a 15220 // descendant view, which may leave views in inconsistent states. 15221 final ViewRootImpl viewRootImpl = getViewRootImpl(); 15222 if (viewRootImpl != null) { 15223 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 15224 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 15225 viewRootImpl.setAccessibilityFocus(null, null); 15226 } 15227 } 15228 } 15229 15230 private void sendAccessibilityHoverEvent(int eventType) { 15231 // Since we are not delivering to a client accessibility events from not 15232 // important views (unless the clinet request that) we need to fire the 15233 // event from the deepest view exposed to the client. As a consequence if 15234 // the user crosses a not exposed view the client will see enter and exit 15235 // of the exposed predecessor followed by and enter and exit of that same 15236 // predecessor when entering and exiting the not exposed descendant. This 15237 // is fine since the client has a clear idea which view is hovered at the 15238 // price of a couple more events being sent. This is a simple and 15239 // working solution. 15240 View source = this; 15241 while (true) { 15242 if (source.includeForAccessibility(false)) { 15243 source.sendAccessibilityEvent(eventType); 15244 return; 15245 } 15246 ViewParent parent = source.getParent(); 15247 if (parent instanceof View) { 15248 source = (View) parent; 15249 } else { 15250 return; 15251 } 15252 } 15253 } 15254 15255 /** 15256 * Clears accessibility focus without calling any callback methods 15257 * normally invoked in {@link #clearAccessibilityFocus()}. This method 15258 * is used separately from that one for clearing accessibility focus when 15259 * giving this focus to another view. 15260 * 15261 * @param action The action, if any, that led to focus being cleared. Set to 15262 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 15263 * the window. 15264 */ 15265 void clearAccessibilityFocusNoCallbacks(int action) { 15266 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 15267 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 15268 invalidate(); 15269 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 15270 AccessibilityEvent event = AccessibilityEvent.obtain( 15271 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 15272 event.setAction(action); 15273 if (mAccessibilityDelegate != null) { 15274 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 15275 } else { 15276 sendAccessibilityEventUnchecked(event); 15277 } 15278 } 15279 15280 updatePreferKeepClearForFocus(); 15281 } 15282 } 15283 15284 /** 15285 * Call this to try to give focus to a specific view or to one of its 15286 * descendants. 15287 * 15288 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 15289 * false), or if it can't be focused due to other conditions (not focusable in touch mode 15290 * ({@link #isFocusableInTouchMode}) while the device is in touch mode, not visible, not 15291 * enabled, or has no size). 15292 * 15293 * See also {@link #focusSearch(int)}, which is what you call to say that you 15294 * have focus, and you want your parent to look for the next one. 15295 * 15296 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 15297 * {@link #FOCUS_DOWN} and <code>null</code>. 15298 * 15299 * @return Whether this view or one of its descendants actually took focus. 15300 */ 15301 public final boolean requestFocus() { 15302 return requestFocus(View.FOCUS_DOWN); 15303 } 15304 15305 /** 15306 * This will request focus for whichever View was last focused within this 15307 * cluster before a focus-jump out of it. 15308 * 15309 * @hide 15310 */ 15311 @TestApi 15312 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 15313 // Prioritize focusableByDefault over algorithmic focus selection. 15314 if (restoreDefaultFocus()) { 15315 return true; 15316 } 15317 return requestFocus(direction); 15318 } 15319 15320 /** 15321 * This will request focus for whichever View not in a cluster was last focused before a 15322 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 15323 * the "first" focusable view it finds. 15324 * 15325 * @hide 15326 */ 15327 @TestApi 15328 public boolean restoreFocusNotInCluster() { 15329 return requestFocus(View.FOCUS_DOWN); 15330 } 15331 15332 /** 15333 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 15334 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 15335 * 15336 * @return Whether this view or one of its descendants actually took focus 15337 */ 15338 public boolean restoreDefaultFocus() { 15339 return requestFocus(View.FOCUS_DOWN); 15340 } 15341 15342 /** 15343 * Call this to try to give focus to a specific view or to one of its 15344 * descendants and give it a hint about what direction focus is heading. 15345 * 15346 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 15347 * false), or if it is focusable and it is not focusable in touch mode 15348 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 15349 * 15350 * See also {@link #focusSearch(int)}, which is what you call to say that you 15351 * have focus, and you want your parent to look for the next one. 15352 * 15353 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 15354 * <code>null</code> set for the previously focused rectangle. 15355 * 15356 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 15357 * @return Whether this view or one of its descendants actually took focus. 15358 */ 15359 public final boolean requestFocus(int direction) { 15360 return requestFocus(direction, null); 15361 } 15362 15363 /** 15364 * Call this to try to give focus to a specific view or to one of its descendants 15365 * and give it hints about the direction and a specific rectangle that the focus 15366 * is coming from. The rectangle can help give larger views a finer grained hint 15367 * about where focus is coming from, and therefore, where to show selection, or 15368 * forward focus change internally. 15369 * 15370 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 15371 * false), or if it is focusable and it is not focusable in touch mode 15372 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 15373 * 15374 * A View will not take focus if it is not visible. 15375 * 15376 * A View will not take focus if one of its parents has 15377 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 15378 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 15379 * 15380 * See also {@link #focusSearch(int)}, which is what you call to say that you 15381 * have focus, and you want your parent to look for the next one. 15382 * 15383 * You may wish to override this method if your custom {@link View} has an internal 15384 * {@link View} that it wishes to forward the request to. 15385 * 15386 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 15387 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 15388 * to give a finer grained hint about where focus is coming from. May be null 15389 * if there is no hint. 15390 * @return Whether this view or one of its descendants actually took focus. 15391 */ 15392 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 15393 return requestFocusNoSearch(direction, previouslyFocusedRect); 15394 } 15395 15396 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 15397 // need to be focusable 15398 if (!canTakeFocus()) { 15399 return false; 15400 } 15401 15402 // need to be focusable in touch mode if in touch mode 15403 if (isInTouchMode() && 15404 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 15405 return false; 15406 } 15407 15408 // need to not have any parents blocking us 15409 if (hasAncestorThatBlocksDescendantFocus()) { 15410 return false; 15411 } 15412 15413 if (!isLayoutValid()) { 15414 mPrivateFlags |= PFLAG_WANTS_FOCUS; 15415 } else { 15416 clearParentsWantFocus(); 15417 } 15418 15419 handleFocusGainInternal(direction, previouslyFocusedRect); 15420 return true; 15421 } 15422 15423 void clearParentsWantFocus() { 15424 if (mParent instanceof View) { 15425 ((View) mParent).mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 15426 ((View) mParent).clearParentsWantFocus(); 15427 } 15428 } 15429 15430 /** 15431 * Call this to try to give focus to a specific view or to one of its descendants. This is a 15432 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 15433 * touch mode to request focus when they are touched. 15434 * 15435 * @return Whether this view or one of its descendants actually took focus. 15436 * 15437 * @see #isInTouchMode() 15438 * 15439 */ 15440 public final boolean requestFocusFromTouch() { 15441 // Leave touch mode if we need to 15442 if (isInTouchMode()) { 15443 ViewRootImpl viewRoot = getViewRootImpl(); 15444 if (viewRoot != null) { 15445 viewRoot.ensureTouchMode(false); 15446 } 15447 } 15448 return requestFocus(View.FOCUS_DOWN); 15449 } 15450 15451 /** 15452 * @return Whether any ancestor of this view blocks descendant focus. 15453 */ 15454 private boolean hasAncestorThatBlocksDescendantFocus() { 15455 final boolean focusableInTouchMode = isFocusableInTouchMode(); 15456 ViewParent ancestor = mParent; 15457 while (ancestor instanceof ViewGroup) { 15458 final ViewGroup vgAncestor = (ViewGroup) ancestor; 15459 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 15460 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 15461 return true; 15462 } else { 15463 ancestor = vgAncestor.getParent(); 15464 } 15465 } 15466 return false; 15467 } 15468 15469 /** 15470 * Gets the mode for determining whether this View is important for accessibility. 15471 * A view is important for accessibility if it fires accessibility events and if it 15472 * is reported to accessibility services that query the screen. 15473 * 15474 * @return The mode for determining whether a view is important for accessibility, one 15475 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 15476 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 15477 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 15478 * 15479 * @attr ref android.R.styleable#View_importantForAccessibility 15480 * 15481 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 15482 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 15483 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 15484 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 15485 */ 15486 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 15487 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 15488 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 15489 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 15490 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 15491 to = "noHideDescendants") 15492 }) 15493 @InspectableProperty(enumMapping = { 15494 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"), 15495 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"), 15496 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"), 15497 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 15498 name = "noHideDescendants"), 15499 }) 15500 public int getImportantForAccessibility() { 15501 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 15502 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 15503 } 15504 15505 /** 15506 * Sets the live region mode for this view. This indicates to accessibility 15507 * services whether they should automatically notify the user about changes 15508 * to the view's content description or text, or to the content descriptions 15509 * or text of the view's children (where applicable). 15510 * <p> 15511 * Different priority levels are available: 15512 * <ul> 15513 * <li> 15514 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}: 15515 * Indicates that updates to the region should be presented to the user. Suitable in most 15516 * cases for prominent updates within app content that don't require the user's immediate 15517 * attention. 15518 * </li> 15519 * <li> 15520 * {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}: Indicates that updates to the region have 15521 * the highest priority and should be presented to the user immediately. This may result 15522 * in disruptive notifications from an accessibility service, which may potentially 15523 * interrupt other feedback or user actions, so it should generally be used only for 15524 * critical, time-sensitive information. 15525 * </li> 15526 * <li> 15527 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}: Disables change announcements (the default for 15528 * most views). 15529 * </li> 15530 * </ul> 15531 * <p> 15532 * Examples: 15533 * <ul> 15534 * <li> 15535 * Selecting an option in a dropdown menu updates a panel below with the updated 15536 * content. This panel may be marked as a live region with 15537 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE} to notify users of the change. A screen 15538 * reader may queue changes as announcements that don't disrupt ongoing speech. 15539 * </li> 15540 * <li> 15541 * An emergency alert may be marked with {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 15542 * to immediately inform users of the emergency. 15543 * </li> 15544 * </ul> 15545 * <p> 15546 * For error notifications, like an "incorrect password" warning in a login screen, views 15547 * should send a {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} 15548 * {@code AccessibilityEvent} with a content change type 15549 * {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_ERROR} and set 15550 * {@link AccessibilityNodeInfo#setError(CharSequence)}. Custom widgets should provide 15551 * error-setting methods that support accessibility. For example, use 15552 * {@link android.widget.TextView#setError(CharSequence)} instead of explicitly sending events. 15553 * <p> 15554 * Don't use live regions for frequently-updating UI elements (e.g., progress bars), as this can 15555 * overwhelm the user with feedback from accessibility services. If necessary, use 15556 * {@link AccessibilityNodeInfo#setMinDurationBetweenContentChanges(Duration)} to throttle 15557 * feedback and reduce disruptions. 15558 * <p> 15559 * <aside><b>Note:</b> Use 15560 * {@link androidx.core.view.ViewCompat#setAccessibilityLiveRegion(View, int)} 15561 * for backwards-compatibility. </aside> 15562 * 15563 * @param mode The live region mode for this view, one of: 15564 * <ul> 15565 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 15566 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 15567 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 15568 * </ul> 15569 * @attr ref android.R.styleable#View_accessibilityLiveRegion 15570 */ 15571 public void setAccessibilityLiveRegion(int mode) { 15572 if (mode != getAccessibilityLiveRegion()) { 15573 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 15574 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 15575 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 15576 notifyViewAccessibilityStateChangedIfNeeded( 15577 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 15578 } 15579 } 15580 15581 /** 15582 * Gets the live region mode for this View. 15583 * 15584 * @return The live region mode for the view. 15585 * 15586 * @attr ref android.R.styleable#View_accessibilityLiveRegion 15587 * 15588 * @see #setAccessibilityLiveRegion(int) 15589 */ 15590 @InspectableProperty(enumMapping = { 15591 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"), 15592 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"), 15593 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive") 15594 }) 15595 public int getAccessibilityLiveRegion() { 15596 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 15597 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 15598 } 15599 15600 /** 15601 * Sets how to determine whether this view is important for accessibility 15602 * which is if it fires accessibility events and if it is reported to 15603 * accessibility services that query the screen. 15604 * 15605 * @param mode How to determine whether this view is important for accessibility. 15606 * 15607 * @attr ref android.R.styleable#View_importantForAccessibility 15608 * 15609 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 15610 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 15611 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 15612 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 15613 */ 15614 public void setImportantForAccessibility(int mode) { 15615 final int oldMode = getImportantForAccessibility(); 15616 if (mode != oldMode) { 15617 final boolean hideDescendants = 15618 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 15619 15620 // If this node or its descendants are no longer important, try to 15621 // clear accessibility focus. 15622 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 15623 final View focusHost = findAccessibilityFocusHost(hideDescendants); 15624 if (focusHost != null) { 15625 focusHost.clearAccessibilityFocus(); 15626 } 15627 } 15628 15629 // If we're moving between AUTO and another state, we might not need 15630 // to send a subtree changed notification. We'll store the computed 15631 // importance, since we'll need to check it later to make sure. 15632 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 15633 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 15634 final boolean oldIncludeForAccessibility = 15635 maySkipNotify && includeForAccessibility(false); 15636 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 15637 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 15638 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 15639 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility(false)) { 15640 notifySubtreeAccessibilityStateChangedIfNeeded(); 15641 } else { 15642 notifyViewAccessibilityStateChangedIfNeeded( 15643 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 15644 } 15645 } 15646 } 15647 15648 /** 15649 * Returns the view within this view's hierarchy that is hosting 15650 * accessibility focus. 15651 * 15652 * @param searchDescendants whether to search for focus in descendant views 15653 * @return the view hosting accessibility focus, or {@code null} 15654 */ 15655 private View findAccessibilityFocusHost(boolean searchDescendants) { 15656 if (isAccessibilityFocusedViewOrHost()) { 15657 return this; 15658 } 15659 15660 if (searchDescendants) { 15661 final ViewRootImpl viewRoot = getViewRootImpl(); 15662 if (viewRoot != null) { 15663 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 15664 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 15665 return focusHost; 15666 } 15667 } 15668 } 15669 15670 return null; 15671 } 15672 15673 /** 15674 * Computes whether this view should be exposed for accessibility. In 15675 * general, views that are interactive or provide information are exposed 15676 * while views that serve only as containers are hidden. 15677 * <p> 15678 * If an ancestor of this view has importance 15679 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 15680 * returns <code>false</code>. 15681 * <p> 15682 * Otherwise, the value is computed according to the view's 15683 * {@link #getImportantForAccessibility()} value: 15684 * <ol> 15685 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 15686 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 15687 * </code> 15688 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 15689 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 15690 * view satisfies any of the following: 15691 * <ul> 15692 * <li>Is actionable, e.g. {@link #isClickable()}, 15693 * {@link #isLongClickable()}, {@link #isContextClickable()}, 15694 * {@link #isScreenReaderFocusable()}, or {@link #isFocusable()} 15695 * <li>Has an {@link AccessibilityDelegate} 15696 * <li>Has an {@link AccessibilityNodeProvider} 15697 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 15698 * {@link OnKeyListener}, etc. 15699 * <li>Is an accessibility live region, e.g. 15700 * {@link #getAccessibilityLiveRegion()} is not 15701 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 15702 * </ul> 15703 * <li>Has an accessibility pane title, see {@link #setAccessibilityPaneTitle}</li> 15704 * <li>Is an accessibility heading, see {@link #setAccessibilityHeading(boolean)}.</li> 15705 * </ol> 15706 * 15707 * @return Whether the view is exposed for accessibility. 15708 * @see #setImportantForAccessibility(int) 15709 * @see #getImportantForAccessibility() 15710 */ 15711 public boolean isImportantForAccessibility() { 15712 final int mode = getImportantForAccessibility(); 15713 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 15714 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 15715 return false; 15716 } 15717 15718 // Check parent mode to ensure we're not hidden. 15719 ViewParent parent = mParent; 15720 while (parent instanceof View) { 15721 if (((View) parent).getImportantForAccessibility() 15722 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 15723 return false; 15724 } 15725 parent = parent.getParent(); 15726 } 15727 15728 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 15729 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 15730 || getAccessibilityDelegate() != null 15731 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE 15732 || isAccessibilityPane() || isAccessibilityHeading(); 15733 } 15734 15735 /** 15736 * Gets the parent for accessibility purposes. Note that the parent for 15737 * accessibility is not necessary the immediate parent. It is the first 15738 * predecessor that is important for accessibility. 15739 * 15740 * @return The parent for accessibility purposes. 15741 */ 15742 public ViewParent getParentForAccessibility() { 15743 if (mParent instanceof View) { 15744 View parentView = (View) mParent; 15745 if (parentView.includeForAccessibility()) { 15746 return mParent; 15747 } else { 15748 return mParent.getParentForAccessibility(); 15749 } 15750 } 15751 return null; 15752 } 15753 15754 /** @hide */ 15755 @Nullable 15756 View getSelfOrParentImportantForA11y() { 15757 if (isImportantForAccessibility()) return this; 15758 ViewParent parent = getParentForAccessibility(); 15759 if (parent instanceof View) return (View) parent; 15760 return null; 15761 } 15762 15763 /** 15764 * Adds the children of this View relevant for accessibility to the given list 15765 * as output. Since some Views are not important for accessibility the added 15766 * child views are not necessarily direct children of this view, rather they are 15767 * the first level of descendants important for accessibility. 15768 * 15769 * @param outChildren The output list that will receive children for accessibility. 15770 */ 15771 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 15772 15773 } 15774 15775 /** 15776 * @see #includeForAccessibility(boolean) 15777 * @hide 15778 */ 15779 @UnsupportedAppUsage 15780 public boolean includeForAccessibility() { 15781 return includeForAccessibility(true); 15782 } 15783 15784 /** 15785 * Whether to regard this view for accessibility. 15786 * 15787 * <p> 15788 * If this decision is used for generating the accessibility node tree then this returns false 15789 * for {@link #isAccessibilityDataPrivate()} views queried by non-accessibility tools. 15790 * </p> 15791 * <p> 15792 * Otherwise, a view is regarded for accessibility if: 15793 * <li>the view returns true for {@link #isImportantForAccessibility()}, or</li> 15794 * <li>the querying accessibility service has explicitly requested that views not important for 15795 * accessibility are regarded by setting 15796 * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS}</li> 15797 * </p> 15798 * 15799 * @param forNodeTree True if the result of this function will be used for generating a node 15800 * tree, otherwise false (like when sending {@link AccessibilityEvent}s). 15801 * @return Whether to regard the view for accessibility. 15802 * @hide 15803 */ 15804 public boolean includeForAccessibility(boolean forNodeTree) { 15805 if (mAttachInfo == null) { 15806 return false; 15807 } 15808 15809 if (forNodeTree) { 15810 // The AccessibilityDataPrivate property should not effect whether this View is 15811 // included for consideration when sending AccessibilityEvents. Events copy their 15812 // source View's AccessibilityDataPrivate value, and then filtering is done when 15813 // AccessibilityManagerService propagates events to each recipient AccessibilityService. 15814 if (!AccessibilityManager.getInstance(mContext).isRequestFromAccessibilityTool() 15815 && isAccessibilityDataSensitive()) { 15816 return false; 15817 } 15818 } 15819 15820 return (mAttachInfo.mAccessibilityFetchFlags 15821 & AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 15822 || isImportantForAccessibility(); 15823 } 15824 15825 /** 15826 * Whether this view should restrict accessibility service access only to services that have the 15827 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property 15828 * set to true. 15829 * 15830 * <p> 15831 * See default behavior provided by {@link #ACCESSIBILITY_DATA_SENSITIVE_AUTO}. Otherwise, 15832 * returns true for {@link #ACCESSIBILITY_DATA_SENSITIVE_YES} or false for {@link 15833 * #ACCESSIBILITY_DATA_SENSITIVE_NO}. 15834 * </p> 15835 * 15836 * @return True if this view should restrict accessibility service access to services that have 15837 * the isAccessibilityTool property. 15838 */ 15839 @ViewDebug.ExportedProperty(category = "accessibility") 15840 public boolean isAccessibilityDataSensitive() { 15841 if (mInferredAccessibilityDataSensitive == ACCESSIBILITY_DATA_SENSITIVE_AUTO) { 15842 calculateAccessibilityDataSensitive(); 15843 } 15844 return mInferredAccessibilityDataSensitive == ACCESSIBILITY_DATA_SENSITIVE_YES; 15845 } 15846 15847 /** 15848 * Calculate and cache the inferred value for {@link #isAccessibilityDataSensitive()}. 15849 * 15850 * <p> 15851 * <strong>Note:</strong> This method needs to be called any time one of the below conditions 15852 * changes, to recalculate the new value. 15853 * </p> 15854 */ 15855 void calculateAccessibilityDataSensitive() { 15856 // Use the explicit value if set. 15857 if (mExplicitAccessibilityDataSensitive != ACCESSIBILITY_DATA_SENSITIVE_AUTO) { 15858 mInferredAccessibilityDataSensitive = mExplicitAccessibilityDataSensitive; 15859 } else if (getFilterTouchesWhenObscured()) { 15860 // Views that set filterTouchesWhenObscured default to accessibilityDataSensitive. 15861 mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_YES; 15862 } else if (mParent instanceof View && ((View) mParent).isAccessibilityDataSensitive()) { 15863 // Descendants of accessibilityDataSensitive Views are also accessibilityDataSensitive. 15864 mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_YES; 15865 } else { 15866 // Otherwise, default to not accessibilityDataSensitive. 15867 mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_NO; 15868 } 15869 } 15870 15871 /** 15872 * Specifies whether this view should only allow interactions from 15873 * {@link android.accessibilityservice.AccessibilityService}s with the 15874 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property 15875 * set to true. 15876 */ 15877 public void setAccessibilityDataSensitive( 15878 @AccessibilityDataSensitive int accessibilityDataSensitive) { 15879 mExplicitAccessibilityDataSensitive = accessibilityDataSensitive; 15880 calculateAccessibilityDataSensitive(); 15881 } 15882 15883 /** 15884 * Returns whether the View is considered actionable from 15885 * accessibility perspective. Such view are important for 15886 * accessibility. 15887 * 15888 * @return True if the view is actionable for accessibility. 15889 * 15890 * @hide 15891 */ 15892 public boolean isActionableForAccessibility() { 15893 return (isClickable() || isLongClickable() || isFocusable() || isContextClickable() 15894 || isScreenReaderFocusable()); 15895 } 15896 15897 /** 15898 * Returns whether the View has registered callbacks which makes it 15899 * important for accessibility. 15900 * 15901 * @return True if the view is actionable for accessibility. 15902 */ 15903 private boolean hasListenersForAccessibility() { 15904 ListenerInfo info = getListenerInfo(); 15905 return mTouchDelegate != null || info.mOnKeyListener != null 15906 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 15907 || info.mOnHoverListener != null || info.mOnDragListener != null; 15908 } 15909 15910 /** 15911 * Notifies that the accessibility state of this view changed. The change 15912 * is local to this view and does not represent structural changes such 15913 * as children and parent. For example, the view became focusable. Some of 15914 * the notification is at at most once every 15915 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 15916 * to avoid unnecessary load to the system. Also once a view has a pending 15917 * notification this method is a NOP until the notification has been sent. 15918 * 15919 * @hide 15920 */ 15921 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 15922 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 15923 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 15924 return; 15925 } 15926 15927 // Changes to views with a pane title count as window state changes, as the pane title 15928 // marks them as significant parts of the UI. A visible view with a nulled title may send 15929 // a disappeared event. 15930 if ((changeType != AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) 15931 && (isAccessibilityPane() 15932 || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) 15933 && isAggregatedVisible())) { 15934 // If the pane isn't visible, content changed events are sufficient unless we're 15935 // reporting that the view just disappeared 15936 if ((isAggregatedVisible()) 15937 || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)) { 15938 final AccessibilityEvent event = AccessibilityEvent.obtain(); 15939 onInitializeAccessibilityEvent(event); 15940 event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 15941 event.setContentChangeTypes(changeType); 15942 event.setSource(this); 15943 onPopulateAccessibilityEvent(event); 15944 if (mParent != null) { 15945 try { 15946 mParent.requestSendAccessibilityEvent(this, event); 15947 } catch (AbstractMethodError e) { 15948 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() 15949 + " does not fully implement ViewParent", e); 15950 } 15951 } 15952 return; 15953 } 15954 } 15955 15956 // If this is a live region, we should send a subtree change event 15957 // from this view immediately. Otherwise, we can let it propagate up. 15958 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) { 15959 final AccessibilityEvent event = AccessibilityEvent.obtain(); 15960 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 15961 event.setContentChangeTypes(changeType); 15962 sendAccessibilityEventUnchecked(event); 15963 } else if (mParent != null) { 15964 try { 15965 mParent.notifySubtreeAccessibilityStateChanged(this, this, changeType); 15966 } catch (AbstractMethodError e) { 15967 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15968 " does not fully implement ViewParent", e); 15969 } 15970 } 15971 } 15972 15973 /** 15974 * Notifies that the accessibility state of this view changed. The change 15975 * is *not* local to this view and does represent structural changes such 15976 * as children and parent. For example, the view size changed. Some of the 15977 * notification is at at most once every 15978 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 15979 * to avoid unnecessary load to the system. Also once a view has a pending 15980 * notification this method is a NOP until the notification has been sent. 15981 * 15982 * @hide 15983 */ 15984 @UnsupportedAppUsage 15985 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 15986 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 15987 return; 15988 } 15989 15990 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 15991 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 15992 if (mParent != null) { 15993 try { 15994 mParent.notifySubtreeAccessibilityStateChanged( 15995 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 15996 } catch (AbstractMethodError e) { 15997 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15998 " does not fully implement ViewParent", e); 15999 } 16000 } 16001 } 16002 } 16003 16004 private void notifySubtreeAccessibilityStateChangedByParentIfNeeded() { 16005 if (!AccessibilityManager.getInstance(mContext).isEnabled()) { 16006 return; 16007 } 16008 16009 final View sendA11yEventView = (View) getParentForAccessibility(); 16010 if (sendA11yEventView != null && sendA11yEventView.isShown()) { 16011 sendA11yEventView.notifySubtreeAccessibilityStateChangedIfNeeded(); 16012 } 16013 } 16014 16015 /** 16016 * Changes the visibility of this View without triggering any other changes. This should only 16017 * be used by animation frameworks, such as {@link android.transition.Transition}, where 16018 * visibility changes should not adjust focus or trigger a new layout. Application developers 16019 * should use {@link #setVisibility} instead to ensure that the hierarchy is correctly updated. 16020 * 16021 * <p>Only call this method when a temporary visibility must be applied during an 16022 * animation and the original visibility value is guaranteed to be reset after the 16023 * animation completes. Use {@link #setVisibility} in all other cases.</p> 16024 * 16025 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 16026 * @see #setVisibility(int) 16027 */ 16028 public void setTransitionVisibility(@Visibility int visibility) { 16029 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 16030 } 16031 16032 /** 16033 * Reset the flag indicating the accessibility state of the subtree rooted 16034 * at this view changed. 16035 */ 16036 void resetSubtreeAccessibilityStateChanged() { 16037 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 16038 } 16039 16040 /** 16041 * Report an accessibility action to this view's parents for delegated processing. 16042 * 16043 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 16044 * call this method to delegate an accessibility action to a supporting parent. If the parent 16045 * returns true from its 16046 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 16047 * method this method will return true to signify that the action was consumed.</p> 16048 * 16049 * <p>This method is useful for implementing nested scrolling child views. If 16050 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 16051 * a custom view implementation may invoke this method to allow a parent to consume the 16052 * scroll first. If this method returns true the custom view should skip its own scrolling 16053 * behavior.</p> 16054 * 16055 * @param action Accessibility action to delegate 16056 * @param arguments Optional action arguments 16057 * @return true if the action was consumed by a parent 16058 */ 16059 public boolean dispatchNestedPrePerformAccessibilityAction(int action, 16060 @Nullable Bundle arguments) { 16061 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 16062 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 16063 return true; 16064 } 16065 } 16066 return false; 16067 } 16068 16069 /** 16070 * Performs the specified accessibility action on the view. For 16071 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 16072 * <p> 16073 * If an {@link AccessibilityDelegate} has been specified via calling 16074 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 16075 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 16076 * is responsible for handling this call. 16077 * </p> 16078 * 16079 * <p>The default implementation will delegate 16080 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 16081 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 16082 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 16083 * 16084 * <p> 16085 * <b>Note:</b> Avoid setting accessibility focus with 16086 * {@link AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS}. This is intended to be controlled 16087 * by screen readers. Apps changing focus can confuse screen readers, so the resulting behavior 16088 * can vary by device and screen reader version. 16089 * 16090 * @param action The action to perform. 16091 * @param arguments Optional action arguments. 16092 * @return Whether the action was performed. 16093 */ 16094 public boolean performAccessibilityAction(int action, @Nullable Bundle arguments) { 16095 if (mAccessibilityDelegate != null) { 16096 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 16097 } else { 16098 return performAccessibilityActionInternal(action, arguments); 16099 } 16100 } 16101 16102 /** 16103 * @see #performAccessibilityAction(int, Bundle) 16104 * 16105 * Note: Called from the default {@link AccessibilityDelegate}. 16106 * 16107 * @hide 16108 */ 16109 @UnsupportedAppUsage 16110 public boolean performAccessibilityActionInternal(int action, @Nullable Bundle arguments) { 16111 if (isNestedScrollingEnabled() 16112 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 16113 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 16114 || action == R.id.accessibilityActionScrollUp 16115 || action == R.id.accessibilityActionScrollLeft 16116 || action == R.id.accessibilityActionScrollDown 16117 || action == R.id.accessibilityActionScrollRight)) { 16118 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 16119 return true; 16120 } 16121 } 16122 16123 switch (action) { 16124 case AccessibilityNodeInfo.ACTION_CLICK: { 16125 if (isClickable()) { 16126 performClickInternal(); 16127 return true; 16128 } 16129 } break; 16130 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 16131 if (isLongClickable()) { 16132 performLongClick(); 16133 return true; 16134 } 16135 } break; 16136 case AccessibilityNodeInfo.ACTION_FOCUS: { 16137 if (!hasFocus()) { 16138 // Get out of touch mode since accessibility 16139 // wants to move focus around. 16140 getViewRootImpl().ensureTouchMode(false); 16141 return requestFocus(); 16142 } 16143 } break; 16144 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 16145 if (hasFocus()) { 16146 clearFocus(); 16147 return !isFocused(); 16148 } 16149 } break; 16150 case AccessibilityNodeInfo.ACTION_SELECT: { 16151 if (!isSelected()) { 16152 setSelected(true); 16153 return isSelected(); 16154 } 16155 } break; 16156 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 16157 if (isSelected()) { 16158 setSelected(false); 16159 return !isSelected(); 16160 } 16161 } break; 16162 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 16163 if (!isAccessibilityFocused()) { 16164 return requestAccessibilityFocus(); 16165 } 16166 } break; 16167 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 16168 if (isAccessibilityFocused()) { 16169 clearAccessibilityFocus(); 16170 return true; 16171 } 16172 } break; 16173 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 16174 if (arguments != null) { 16175 final int granularity = arguments.getInt( 16176 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 16177 final boolean extendSelection = arguments.getBoolean( 16178 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 16179 return traverseAtGranularity(granularity, true, extendSelection); 16180 } 16181 } break; 16182 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 16183 if (arguments != null) { 16184 final int granularity = arguments.getInt( 16185 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 16186 final boolean extendSelection = arguments.getBoolean( 16187 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 16188 return traverseAtGranularity(granularity, false, extendSelection); 16189 } 16190 } break; 16191 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 16192 CharSequence text = getIterableTextForAccessibility(); 16193 if (text == null) { 16194 return false; 16195 } 16196 final int start = (arguments != null) ? arguments.getInt( 16197 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 16198 final int end = (arguments != null) ? arguments.getInt( 16199 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 16200 // Only cursor position can be specified (selection length == 0) 16201 if ((getAccessibilitySelectionStart() != start 16202 || getAccessibilitySelectionEnd() != end) 16203 && (start == end)) { 16204 setAccessibilitySelection(start, end); 16205 notifyViewAccessibilityStateChangedIfNeeded( 16206 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 16207 return true; 16208 } 16209 } break; 16210 case R.id.accessibilityActionShowOnScreen: { 16211 if (mAttachInfo != null) { 16212 final Rect r = mAttachInfo.mTmpInvalRect; 16213 getDrawingRect(r); 16214 return requestRectangleOnScreen(r, true); 16215 } 16216 } break; 16217 case R.id.accessibilityActionContextClick: { 16218 if (isContextClickable()) { 16219 performContextClick(); 16220 return true; 16221 } 16222 } break; 16223 case R.id.accessibilityActionShowTooltip: { 16224 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipPopup != null)) { 16225 // Tooltip already showing 16226 return false; 16227 } 16228 return showLongClickTooltip(0, 0); 16229 } 16230 case R.id.accessibilityActionHideTooltip: { 16231 if ((mTooltipInfo == null) || (mTooltipInfo.mTooltipPopup == null)) { 16232 // No tooltip showing 16233 return false; 16234 } 16235 hideTooltip(); 16236 return true; 16237 } 16238 case R.id.accessibilityActionDragDrop: { 16239 if (!canAcceptAccessibilityDrop()) { 16240 return false; 16241 } 16242 try { 16243 if (mAttachInfo != null && mAttachInfo.mSession != null) { 16244 final int[] location = new int[2]; 16245 getLocationInWindow(location); 16246 final int centerX = location[0] + getWidth() / 2; 16247 final int centerY = location[1] + getHeight() / 2; 16248 return mAttachInfo.mSession.dropForAccessibility(mAttachInfo.mWindow, 16249 centerX, centerY); 16250 } 16251 } catch (RemoteException e) { 16252 Log.e(VIEW_LOG_TAG, "Unable to drop for accessibility", e); 16253 } 16254 return false; 16255 } 16256 case R.id.accessibilityActionDragCancel: { 16257 if (!startedSystemDragForAccessibility()) { 16258 return false; 16259 } 16260 if (mAttachInfo != null && mAttachInfo.mDragToken != null) { 16261 cancelDragAndDrop(); 16262 return true; 16263 } 16264 return false; 16265 } 16266 } 16267 return false; 16268 } 16269 16270 private boolean canAcceptAccessibilityDrop() { 16271 if (!canAcceptDrag()) { 16272 return false; 16273 } 16274 ListenerInfo li = mListenerInfo; 16275 return (li != null) && (li.mOnDragListener != null || li.mOnReceiveContentListener != null); 16276 } 16277 16278 private boolean traverseAtGranularity(int granularity, boolean forward, 16279 boolean extendSelection) { 16280 CharSequence text = getIterableTextForAccessibility(); 16281 if (text == null || text.length() == 0) { 16282 return false; 16283 } 16284 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 16285 if (iterator == null) { 16286 return false; 16287 } 16288 int current = getAccessibilitySelectionEnd(); 16289 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 16290 current = forward ? 0 : text.length(); 16291 } 16292 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 16293 if (range == null) { 16294 return false; 16295 } 16296 final int segmentStart = range[0]; 16297 final int segmentEnd = range[1]; 16298 int selectionStart; 16299 int selectionEnd; 16300 if (extendSelection && isAccessibilitySelectionExtendable()) { 16301 prepareForExtendedAccessibilitySelection(); 16302 selectionStart = getAccessibilitySelectionStart(); 16303 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 16304 selectionStart = forward ? segmentStart : segmentEnd; 16305 } 16306 selectionEnd = forward ? segmentEnd : segmentStart; 16307 } else { 16308 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 16309 } 16310 setAccessibilitySelection(selectionStart, selectionEnd); 16311 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 16312 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 16313 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 16314 return true; 16315 } 16316 16317 /** 16318 * Gets the text reported for accessibility purposes. 16319 * 16320 * @return The accessibility text. 16321 * 16322 * @hide 16323 */ 16324 @UnsupportedAppUsage 16325 public CharSequence getIterableTextForAccessibility() { 16326 return getContentDescription(); 16327 } 16328 16329 /** 16330 * Gets whether accessibility selection can be extended. 16331 * 16332 * @return If selection is extensible. 16333 * 16334 * @hide 16335 */ 16336 public boolean isAccessibilitySelectionExtendable() { 16337 return false; 16338 } 16339 16340 /** 16341 * Prepare for extended selection. 16342 * @hide 16343 */ 16344 public void prepareForExtendedAccessibilitySelection() { 16345 return; 16346 } 16347 16348 /** 16349 * @hide 16350 */ 16351 public int getAccessibilitySelectionStart() { 16352 return mAccessibilityCursorPosition; 16353 } 16354 16355 /** 16356 * @hide 16357 */ 16358 public int getAccessibilitySelectionEnd() { 16359 return getAccessibilitySelectionStart(); 16360 } 16361 16362 /** 16363 * @hide 16364 */ 16365 public void setAccessibilitySelection(int start, int end) { 16366 if (start == end && end == mAccessibilityCursorPosition) { 16367 return; 16368 } 16369 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 16370 mAccessibilityCursorPosition = start; 16371 } else { 16372 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 16373 } 16374 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 16375 } 16376 16377 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 16378 int fromIndex, int toIndex) { 16379 if (mParent == null) { 16380 return; 16381 } 16382 AccessibilityEvent event = AccessibilityEvent.obtain( 16383 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 16384 onInitializeAccessibilityEvent(event); 16385 onPopulateAccessibilityEvent(event); 16386 event.setFromIndex(fromIndex); 16387 event.setToIndex(toIndex); 16388 event.setAction(action); 16389 event.setMovementGranularity(granularity); 16390 mParent.requestSendAccessibilityEvent(this, event); 16391 } 16392 16393 /** 16394 * @hide 16395 */ 16396 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 16397 public TextSegmentIterator getIteratorForGranularity(int granularity) { 16398 switch (granularity) { 16399 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 16400 CharSequence text = getIterableTextForAccessibility(); 16401 if (text != null && text.length() > 0) { 16402 CharacterTextSegmentIterator iterator = 16403 CharacterTextSegmentIterator.getInstance( 16404 mContext.getResources().getConfiguration().locale); 16405 iterator.initialize(text.toString()); 16406 return iterator; 16407 } 16408 } break; 16409 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 16410 CharSequence text = getIterableTextForAccessibility(); 16411 if (text != null && text.length() > 0) { 16412 WordTextSegmentIterator iterator = 16413 WordTextSegmentIterator.getInstance( 16414 mContext.getResources().getConfiguration().locale); 16415 iterator.initialize(text.toString()); 16416 return iterator; 16417 } 16418 } break; 16419 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 16420 CharSequence text = getIterableTextForAccessibility(); 16421 if (text != null && text.length() > 0) { 16422 ParagraphTextSegmentIterator iterator = 16423 ParagraphTextSegmentIterator.getInstance(); 16424 iterator.initialize(text.toString()); 16425 return iterator; 16426 } 16427 } break; 16428 } 16429 return null; 16430 } 16431 16432 /** 16433 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 16434 * and {@link #onFinishTemporaryDetach()}. 16435 * 16436 * <p>This method always returns {@code true} when called directly or indirectly from 16437 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 16438 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 16439 * <ul> 16440 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 16441 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 16442 * </ul> 16443 * </p> 16444 * 16445 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 16446 * and {@link #onFinishTemporaryDetach()}. 16447 */ isTemporarilyDetached()16448 public final boolean isTemporarilyDetached() { 16449 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 16450 } 16451 16452 /** 16453 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 16454 * a container View. 16455 */ 16456 @CallSuper dispatchStartTemporaryDetach()16457 public void dispatchStartTemporaryDetach() { 16458 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 16459 notifyEnterOrExitForAutoFillIfNeeded(false); 16460 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 16461 onStartTemporaryDetach(); 16462 } 16463 16464 /** 16465 * This is called when a container is going to temporarily detach a child, with 16466 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 16467 * It will either be followed by {@link #onFinishTemporaryDetach()} or 16468 * {@link #onDetachedFromWindow()} when the container is done. 16469 */ onStartTemporaryDetach()16470 public void onStartTemporaryDetach() { 16471 removeUnsetPressCallback(); 16472 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 16473 } 16474 16475 /** 16476 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 16477 * a container View. 16478 */ 16479 @CallSuper dispatchFinishTemporaryDetach()16480 public void dispatchFinishTemporaryDetach() { 16481 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 16482 onFinishTemporaryDetach(); 16483 if (hasWindowFocus() && hasFocus()) { 16484 notifyFocusChangeToImeFocusController(true /* hasFocus */); 16485 } 16486 notifyEnterOrExitForAutoFillIfNeeded(true); 16487 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 16488 } 16489 16490 /** 16491 * Called after {@link #onStartTemporaryDetach} when the container is done 16492 * changing the view. 16493 */ onFinishTemporaryDetach()16494 public void onFinishTemporaryDetach() { 16495 } 16496 16497 /** 16498 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 16499 * for this view's window. Returns null if the view is not currently attached 16500 * to the window. Normally you will not need to use this directly, but 16501 * just use the standard high-level event callbacks like 16502 * {@link #onKeyDown(int, KeyEvent)}. 16503 */ getKeyDispatcherState()16504 public KeyEvent.DispatcherState getKeyDispatcherState() { 16505 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 16506 } 16507 16508 /** 16509 * Dispatch a key event before it is processed by any input method 16510 * associated with the view hierarchy. This can be used to intercept 16511 * key events in special situations before the IME consumes them; a 16512 * typical example would be handling the BACK key to update the application's 16513 * UI instead of allowing the IME to see it and close itself. 16514 * 16515 * @param event The key event to be dispatched. 16516 * @return True if the event was handled, false otherwise. 16517 */ dispatchKeyEventPreIme(KeyEvent event)16518 public boolean dispatchKeyEventPreIme(KeyEvent event) { 16519 return onKeyPreIme(event.getKeyCode(), event); 16520 } 16521 16522 /** 16523 * Dispatch a key event to the next view on the focus path. This path runs 16524 * from the top of the view tree down to the currently focused view. If this 16525 * view has focus, it will dispatch to itself. Otherwise it will dispatch 16526 * the next node down the focus path. This method also fires any key 16527 * listeners. 16528 * 16529 * @param event The key event to be dispatched. 16530 * @return True if the event was handled, false otherwise. 16531 */ dispatchKeyEvent(KeyEvent event)16532 public boolean dispatchKeyEvent(KeyEvent event) { 16533 if (mInputEventConsistencyVerifier != null) { 16534 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 16535 } 16536 16537 // Give any attached key listener a first crack at the event. 16538 //noinspection SimplifiableIfStatement 16539 ListenerInfo li = mListenerInfo; 16540 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 16541 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 16542 return true; 16543 } 16544 16545 if (event.dispatch(this, mAttachInfo != null 16546 ? mAttachInfo.mKeyDispatchState : null, this)) { 16547 return true; 16548 } 16549 16550 if (mInputEventConsistencyVerifier != null) { 16551 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 16552 } 16553 return false; 16554 } 16555 16556 /** 16557 * Dispatches a key shortcut event. 16558 * 16559 * @param event The key event to be dispatched. 16560 * @return True if the event was handled by the view, false otherwise. 16561 */ dispatchKeyShortcutEvent(KeyEvent event)16562 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 16563 return onKeyShortcut(event.getKeyCode(), event); 16564 } 16565 16566 /** 16567 * Pass the touch screen motion event down to the target view, or this 16568 * view if it is the target. 16569 * 16570 * @param event The motion event to be dispatched. 16571 * @return True if the event was handled by the view, false otherwise. 16572 * 16573 * @see #onTouchEvent(MotionEvent) 16574 */ dispatchTouchEvent(MotionEvent event)16575 public boolean dispatchTouchEvent(MotionEvent event) { 16576 // If the event should be handled by accessibility focus first. 16577 if (event.isTargetAccessibilityFocus()) { 16578 // We don't have focus or no virtual descendant has it, do not handle the event. 16579 if (!isAccessibilityFocusedViewOrHost()) { 16580 return false; 16581 } 16582 // We have focus and got the event, then use normal event dispatch. 16583 event.setTargetAccessibilityFocus(false); 16584 } 16585 boolean result = false; 16586 16587 if (mInputEventConsistencyVerifier != null) { 16588 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 16589 } 16590 16591 final int actionMasked = event.getActionMasked(); 16592 if (actionMasked == MotionEvent.ACTION_DOWN) { 16593 // Defensive cleanup for new gesture 16594 stopNestedScroll(); 16595 } 16596 16597 if (onFilterTouchEventForSecurity(event)) { 16598 result = performOnTouchCallback(event); 16599 } 16600 16601 if (!result && mInputEventConsistencyVerifier != null) { 16602 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 16603 } 16604 16605 // Clean up after nested scrolls if this is the end of a gesture; 16606 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 16607 // of the gesture. 16608 if (actionMasked == MotionEvent.ACTION_UP || 16609 actionMasked == MotionEvent.ACTION_CANCEL || 16610 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 16611 stopNestedScroll(); 16612 } 16613 16614 return result; 16615 } 16616 16617 /** 16618 * Returns {@code true} if the {@link MotionEvent} from {@link #dispatchTouchEvent} was 16619 * handled by this view. 16620 */ performOnTouchCallback(MotionEvent event)16621 private boolean performOnTouchCallback(MotionEvent event) { 16622 boolean handled = false; 16623 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 16624 handled = true; 16625 } 16626 //noinspection SimplifiableIfStatement 16627 ListenerInfo li = mListenerInfo; 16628 if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED) { 16629 try { 16630 if (Trace.isTagEnabled(TRACE_TAG_VIEW)) { 16631 Trace.traceBegin(TRACE_TAG_VIEW, 16632 "View.onTouchListener#onTouch - " + getClass().getSimpleName() 16633 + ", eventId - " + event.getId()); 16634 } 16635 handled = li.mOnTouchListener.onTouch(this, event); 16636 } finally { 16637 Trace.traceEnd(TRACE_TAG_VIEW); 16638 } 16639 } 16640 if (handled) { 16641 return true; 16642 } 16643 try { 16644 Trace.traceBegin(TRACE_TAG_VIEW, "View#onTouchEvent"); 16645 return onTouchEvent(event); 16646 } finally { 16647 Trace.traceEnd(TRACE_TAG_VIEW); 16648 } 16649 } 16650 isAccessibilityFocusedViewOrHost()16651 boolean isAccessibilityFocusedViewOrHost() { 16652 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 16653 .getAccessibilityFocusedHost() == this); 16654 } 16655 16656 /** 16657 * Returns whether this view can receive pointer events. 16658 * 16659 * @return {@code true} if this view can receive pointer events. 16660 * @hide 16661 */ canReceivePointerEvents()16662 protected boolean canReceivePointerEvents() { 16663 return (mViewFlags & VISIBILITY_MASK) == VISIBLE || getAnimation() != null; 16664 } 16665 16666 /** 16667 * Filter the touch event to apply security policies. 16668 * 16669 * @param event The motion event to be filtered. 16670 * @return True if the event should be dispatched, false if the event should be dropped. 16671 * 16672 * @see #getFilterTouchesWhenObscured 16673 */ onFilterTouchEventForSecurity(MotionEvent event)16674 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 16675 //noinspection RedundantIfStatement 16676 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 16677 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 16678 // Window is obscured, drop this touch. 16679 return false; 16680 } 16681 if (android.view.accessibility.Flags.preventA11yNontoolFromInjectingIntoSensitiveViews()) { 16682 if (event.isInjectedFromAccessibilityService() 16683 // If the event came from an Accessibility Service that does *not* declare 16684 // itself as AccessibilityServiceInfo#isAccessibilityTool and this View is 16685 // declared sensitive then drop the event. 16686 // Only Accessibility Tools are allowed to interact with sensitive Views. 16687 && !event.isInjectedFromAccessibilityTool() && isAccessibilityDataSensitive()) { 16688 return false; 16689 } 16690 } 16691 return true; 16692 } 16693 16694 /** 16695 * Pass a trackball motion event down to the focused view. 16696 * 16697 * @param event The motion event to be dispatched. 16698 * @return True if the event was handled by the view, false otherwise. 16699 * 16700 * @see #onTrackballEvent(MotionEvent) 16701 */ dispatchTrackballEvent(MotionEvent event)16702 public boolean dispatchTrackballEvent(MotionEvent event) { 16703 if (mInputEventConsistencyVerifier != null) { 16704 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 16705 } 16706 16707 return onTrackballEvent(event); 16708 } 16709 16710 /** 16711 * Pass a captured pointer event down to the focused view. 16712 * 16713 * @param event The motion event to be dispatched. 16714 * @return True if the event was handled by the view, false otherwise. 16715 */ dispatchCapturedPointerEvent(MotionEvent event)16716 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 16717 if (!hasPointerCapture()) { 16718 return false; 16719 } 16720 //noinspection SimplifiableIfStatement 16721 ListenerInfo li = mListenerInfo; 16722 if (li != null && li.mOnCapturedPointerListener != null 16723 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 16724 return true; 16725 } 16726 return onCapturedPointerEvent(event); 16727 } 16728 16729 /** 16730 * Dispatch a generic motion event. 16731 * <p> 16732 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 16733 * are delivered to the view under the pointer. All other generic motion events are 16734 * delivered to the focused view. Hover events are handled specially and are delivered 16735 * to {@link #onHoverEvent(MotionEvent)} first. 16736 * </p> 16737 * 16738 * @param event The motion event to be dispatched. 16739 * @return True if the event was handled by the view, false otherwise. 16740 * 16741 * @see #onHoverEvent(MotionEvent) 16742 * @see #onGenericMotionEvent(MotionEvent) 16743 */ dispatchGenericMotionEvent(MotionEvent event)16744 public boolean dispatchGenericMotionEvent(MotionEvent event) { 16745 if (mInputEventConsistencyVerifier != null) { 16746 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 16747 } 16748 16749 final int source = event.getSource(); 16750 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 16751 final int action = event.getAction(); 16752 if (action == MotionEvent.ACTION_HOVER_ENTER 16753 || action == MotionEvent.ACTION_HOVER_MOVE 16754 || action == MotionEvent.ACTION_HOVER_EXIT) { 16755 if (dispatchHoverEvent(event)) { 16756 return true; 16757 } 16758 } else if (dispatchGenericPointerEvent(event)) { 16759 return true; 16760 } 16761 } else if (dispatchGenericFocusedEvent(event)) { 16762 return true; 16763 } 16764 16765 if (dispatchGenericMotionEventInternal(event)) { 16766 return true; 16767 } 16768 16769 if (mInputEventConsistencyVerifier != null) { 16770 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 16771 } 16772 return false; 16773 } 16774 dispatchGenericMotionEventInternal(MotionEvent event)16775 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 16776 final boolean isRotaryEncoderEvent = event.isFromSource(InputDevice.SOURCE_ROTARY_ENCODER); 16777 if (isRotaryEncoderEvent) { 16778 // Determine and cache rotary scroll haptics support if it's not yet determined. 16779 // Caching the support is important for two reasons: 16780 // 1) Limits call to `ViewConfiguration#get`, which we should avoid if possible. 16781 // 2) Limits latency from the `ViewConfiguration` API, which may be slow due to feature 16782 // flag querying. 16783 if ((mPrivateFlags4 & PFLAG4_ROTARY_HAPTICS_DETERMINED) == 0) { 16784 if (ViewConfiguration.get(mContext) 16785 .isViewBasedRotaryEncoderHapticScrollFeedbackEnabled()) { 16786 mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_ENABLED; 16787 } 16788 mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_DETERMINED; 16789 } 16790 } 16791 if (isRotaryEncoderEvent && ((mPrivateFlags4 & PFLAG4_ROTARY_HAPTICS_ENABLED) != 0)) { 16792 mPrivateFlags4 &= ~PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT; 16793 mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT; 16794 } 16795 16796 //noinspection SimplifiableIfStatement 16797 ListenerInfo li = mListenerInfo; 16798 if (li != null && li.mOnGenericMotionListener != null 16799 && (mViewFlags & ENABLED_MASK) == ENABLED 16800 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 16801 return true; 16802 } 16803 16804 final boolean onGenericMotionEventResult = onGenericMotionEvent(event); 16805 // Process scroll haptics after `onGenericMotionEvent`, since that's where scrolling usually 16806 // happens. Some views may return false from `onGenericMotionEvent` even if they have done 16807 // scrolling, so disregard the return value when processing for scroll haptics. 16808 // Check for `PFLAG4_ROTARY_HAPTICS_ENABLED` again, because the View implementation may 16809 // call `disableRotaryScrollFeedback` in `onGenericMotionEvent`, which could change the 16810 // value of `PFLAG4_ROTARY_HAPTICS_ENABLED`. 16811 if (isRotaryEncoderEvent && ((mPrivateFlags4 & PFLAG4_ROTARY_HAPTICS_ENABLED) != 0)) { 16812 if ((mPrivateFlags4 & PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT) != 0) { 16813 doRotaryProgressForScrollHaptics(event); 16814 } else { 16815 doRotaryLimitForScrollHaptics(event); 16816 } 16817 } 16818 if (onGenericMotionEventResult) { 16819 return true; 16820 } 16821 16822 final int actionButton = event.getActionButton(); 16823 switch (event.getActionMasked()) { 16824 case MotionEvent.ACTION_BUTTON_PRESS: 16825 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 16826 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 16827 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 16828 if (performContextClick(event.getX(), event.getY())) { 16829 mInContextButtonPress = true; 16830 setPressed(true, event.getX(), event.getY()); 16831 removeTapCallback(); 16832 removeLongPressCallback(); 16833 return true; 16834 } 16835 } 16836 break; 16837 16838 case MotionEvent.ACTION_BUTTON_RELEASE: 16839 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 16840 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 16841 mInContextButtonPress = false; 16842 mIgnoreNextUpEvent = true; 16843 } 16844 break; 16845 } 16846 16847 if (mInputEventConsistencyVerifier != null) { 16848 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 16849 } 16850 return false; 16851 } 16852 16853 /** 16854 * Dispatch a hover event. 16855 * <p> 16856 * Do not call this method directly. 16857 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 16858 * </p> 16859 * 16860 * @param event The motion event to be dispatched. 16861 * @return True if the event was handled by the view, false otherwise. 16862 */ dispatchHoverEvent(MotionEvent event)16863 protected boolean dispatchHoverEvent(MotionEvent event) { 16864 ListenerInfo li = mListenerInfo; 16865 //noinspection SimplifiableIfStatement 16866 if (li != null && li.mOnHoverListener != null 16867 && (mViewFlags & ENABLED_MASK) == ENABLED 16868 && li.mOnHoverListener.onHover(this, event)) { 16869 return true; 16870 } 16871 16872 return onHoverEvent(event); 16873 } 16874 16875 /** 16876 * Returns true if the view has a child to which it has recently sent 16877 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 16878 * it does not have a hovered child, then it must be the innermost hovered view. 16879 * @hide 16880 */ hasHoveredChild()16881 protected boolean hasHoveredChild() { 16882 return false; 16883 } 16884 16885 /** 16886 * Returns true if the given point, in local coordinates, is inside the hovered child. 16887 * 16888 * @hide 16889 */ pointInHoveredChild(MotionEvent event)16890 protected boolean pointInHoveredChild(MotionEvent event) { 16891 return false; 16892 } 16893 16894 /** 16895 * Dispatch a generic motion event to the view under the first pointer. 16896 * <p> 16897 * Do not call this method directly. 16898 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 16899 * </p> 16900 * 16901 * @param event The motion event to be dispatched. 16902 * @return True if the event was handled by the view, false otherwise. 16903 */ dispatchGenericPointerEvent(MotionEvent event)16904 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 16905 return false; 16906 } 16907 16908 /** 16909 * Dispatch a generic motion event to the currently focused view. 16910 * <p> 16911 * Do not call this method directly. 16912 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 16913 * </p> 16914 * 16915 * @param event The motion event to be dispatched. 16916 * @return True if the event was handled by the view, false otherwise. 16917 */ dispatchGenericFocusedEvent(MotionEvent event)16918 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 16919 return false; 16920 } 16921 16922 /** 16923 * Dispatch a pointer event. 16924 * <p> 16925 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 16926 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 16927 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 16928 * and should not be expected to handle other pointing device features. 16929 * </p> 16930 * 16931 * @param event The motion event to be dispatched. 16932 * @return True if the event was handled by the view, false otherwise. 16933 * @hide 16934 */ 16935 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchPointerEvent(MotionEvent event)16936 public final boolean dispatchPointerEvent(MotionEvent event) { 16937 if (event.isTouchEvent()) { 16938 return dispatchTouchEvent(event); 16939 } else { 16940 return dispatchGenericMotionEvent(event); 16941 } 16942 } 16943 16944 /** 16945 * Called when the window containing this view gains or loses window focus. 16946 * ViewGroups should override to route to their children. 16947 * 16948 * @param hasFocus True if the window containing this view now has focus, 16949 * false otherwise. 16950 */ dispatchWindowFocusChanged(boolean hasFocus)16951 public void dispatchWindowFocusChanged(boolean hasFocus) { 16952 onWindowFocusChanged(hasFocus); 16953 } 16954 16955 /** 16956 * Called when the window containing this view gains or loses focus. Note 16957 * that this is separate from view focus: to receive key events, both 16958 * your view and its window must have focus. If a window is displayed 16959 * on top of yours that takes input focus, then your own window will lose 16960 * focus but the view focus will remain unchanged. 16961 * 16962 * @param hasWindowFocus True if the window containing this view now has 16963 * focus, false otherwise. 16964 */ onWindowFocusChanged(boolean hasWindowFocus)16965 public void onWindowFocusChanged(boolean hasWindowFocus) { 16966 if (!hasWindowFocus) { 16967 if (isPressed()) { 16968 setPressed(false); 16969 } 16970 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 16971 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 16972 notifyFocusChangeToImeFocusController(false /* hasFocus */); 16973 } 16974 removeLongPressCallback(); 16975 removeTapCallback(); 16976 onFocusLost(); 16977 } else if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 16978 notifyFocusChangeToImeFocusController(true /* hasFocus */); 16979 ViewRootImpl viewRoot = getViewRootImpl(); 16980 if (viewRoot != null && initiationWithoutInputConnection() && onCheckIsTextEditor()) { 16981 viewRoot.getHandwritingInitiator().onEditorFocused(this); 16982 } 16983 } 16984 16985 refreshDrawableState(); 16986 } 16987 16988 /** 16989 * Returns true if this view is in a window that currently has window focus. 16990 * Note that this is not the same as the view itself having focus. 16991 * 16992 * @return True if this view is in a window that currently has window focus. 16993 */ hasWindowFocus()16994 public boolean hasWindowFocus() { 16995 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 16996 } 16997 16998 /** 16999 * @return {@code true} if this view is in a window that currently has IME focusable state. 17000 * @hide 17001 */ hasImeFocus()17002 public boolean hasImeFocus() { 17003 return getViewRootImpl() != null && getViewRootImpl().getImeFocusController().hasImeFocus(); 17004 } 17005 17006 /** 17007 * Dispatch a view visibility change down the view hierarchy. 17008 * ViewGroups should override to route to their children. 17009 * @param changedView The view whose visibility changed. Could be 'this' or 17010 * an ancestor view. 17011 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 17012 * {@link #INVISIBLE} or {@link #GONE}. 17013 */ dispatchVisibilityChanged(@onNull View changedView, @Visibility int visibility)17014 protected void dispatchVisibilityChanged(@NonNull View changedView, 17015 @Visibility int visibility) { 17016 onVisibilityChanged(changedView, visibility); 17017 } 17018 17019 /** 17020 * Called when the visibility of the view or an ancestor of the view has 17021 * changed. 17022 * 17023 * @param changedView The view whose visibility changed. May be 17024 * {@code this} or an ancestor view. 17025 * @param visibility The new visibility, one of {@link #VISIBLE}, 17026 * {@link #INVISIBLE} or {@link #GONE}. 17027 */ onVisibilityChanged(@onNull View changedView, @Visibility int visibility)17028 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 17029 } 17030 17031 /** 17032 * Dispatch a hint about whether this view is displayed. For instance, when 17033 * a View moves out of the screen, it might receives a display hint indicating 17034 * the view is not displayed. Applications should not <em>rely</em> on this hint 17035 * as there is no guarantee that they will receive one. 17036 * 17037 * @param hint A hint about whether or not this view is displayed: 17038 * {@link #VISIBLE} or {@link #INVISIBLE}. 17039 */ dispatchDisplayHint(@isibility int hint)17040 public void dispatchDisplayHint(@Visibility int hint) { 17041 onDisplayHint(hint); 17042 } 17043 17044 /** 17045 * Gives this view a hint about whether is displayed or not. For instance, when 17046 * a View moves out of the screen, it might receives a display hint indicating 17047 * the view is not displayed. Applications should not <em>rely</em> on this hint 17048 * as there is no guarantee that they will receive one. 17049 * 17050 * @param hint A hint about whether or not this view is displayed: 17051 * {@link #VISIBLE} or {@link #INVISIBLE}. 17052 */ onDisplayHint(@isibility int hint)17053 protected void onDisplayHint(@Visibility int hint) { 17054 } 17055 17056 /** 17057 * Dispatch a window visibility change down the view hierarchy. 17058 * ViewGroups should override to route to their children. 17059 * 17060 * @param visibility The new visibility of the window. 17061 * 17062 * @see #onWindowVisibilityChanged(int) 17063 */ dispatchWindowVisibilityChanged(@isibility int visibility)17064 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 17065 onWindowVisibilityChanged(visibility); 17066 } 17067 17068 /** 17069 * Called when the window containing has change its visibility 17070 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 17071 * that this tells you whether or not your window is being made visible 17072 * to the window manager; this does <em>not</em> tell you whether or not 17073 * your window is obscured by other windows on the screen, even if it 17074 * is itself visible. 17075 * 17076 * @param visibility The new visibility of the window. 17077 */ onWindowVisibilityChanged(@isibility int visibility)17078 protected void onWindowVisibilityChanged(@Visibility int visibility) { 17079 if (visibility == VISIBLE) { 17080 initialAwakenScrollBars(); 17081 } 17082 } 17083 17084 /** 17085 * @return true if this view and all ancestors are visible as of the last 17086 * {@link #onVisibilityAggregated(boolean)} call. 17087 * 17088 * @hide 17089 */ isAggregatedVisible()17090 public boolean isAggregatedVisible() { 17091 return (mPrivateFlags3 & PFLAG3_AGGREGATED_VISIBLE) != 0; 17092 } 17093 17094 /** 17095 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 17096 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 17097 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 17098 * 17099 * @param isVisible true if this view's visibility to the user is uninterrupted by its 17100 * ancestors or by window visibility 17101 * @return true if this view is visible to the user, not counting clipping or overlapping 17102 */ dispatchVisibilityAggregated(boolean isVisible)17103 boolean dispatchVisibilityAggregated(boolean isVisible) { 17104 final boolean thisVisible = getVisibility() == VISIBLE; 17105 // If we're not visible but something is telling us we are, ignore it. 17106 if (thisVisible || !isVisible) { 17107 onVisibilityAggregated(isVisible); 17108 } 17109 return thisVisible && isVisible; 17110 } 17111 17112 /** 17113 * Called when the user-visibility of this View is potentially affected by a change 17114 * to this view itself, an ancestor view or the window this view is attached to. 17115 * 17116 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 17117 * and this view's window is also visible 17118 */ 17119 @CallSuper onVisibilityAggregated(boolean isVisible)17120 public void onVisibilityAggregated(boolean isVisible) { 17121 // Update our internal visibility tracking so we can detect changes 17122 boolean oldVisible = isAggregatedVisible(); 17123 mPrivateFlags3 = isVisible ? (mPrivateFlags3 | PFLAG3_AGGREGATED_VISIBLE) 17124 : (mPrivateFlags3 & ~PFLAG3_AGGREGATED_VISIBLE); 17125 if (isVisible && mAttachInfo != null) { 17126 initialAwakenScrollBars(); 17127 } 17128 17129 final Drawable dr = mBackground; 17130 if (dr != null && isVisible != dr.isVisible()) { 17131 dr.setVisible(isVisible, false); 17132 } 17133 final Drawable hl = mDefaultFocusHighlight; 17134 if (hl != null && isVisible != hl.isVisible()) { 17135 hl.setVisible(isVisible, false); 17136 } 17137 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 17138 if (fg != null && isVisible != fg.isVisible()) { 17139 fg.setVisible(isVisible, false); 17140 } 17141 notifyAutofillManagerViewVisibilityChanged(isVisible); 17142 if (isVisible != oldVisible) { 17143 if (isAccessibilityPane()) { 17144 notifyViewAccessibilityStateChangedIfNeeded(isVisible 17145 ? AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED 17146 : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); 17147 } 17148 17149 notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); 17150 updateSensitiveViewsCountIfNeeded(isVisible); 17151 17152 if (!getSystemGestureExclusionRects().isEmpty()) { 17153 postUpdate(this::updateSystemGestureExclusionRects); 17154 } 17155 17156 if (!collectPreferKeepClearRects().isEmpty()) { 17157 postUpdate(this::updateKeepClearRects); 17158 } 17159 } 17160 } 17161 notifyAutofillManagerViewVisibilityChanged(boolean isVisible)17162 private void notifyAutofillManagerViewVisibilityChanged(boolean isVisible) { 17163 if (isAutofillable()) { 17164 AutofillManager afm = getAutofillManager(); 17165 17166 if (afm != null && getAutofillViewId() > LAST_APP_AUTOFILL_ID) { 17167 if (mVisibilityChangeForAutofillHandler != null) { 17168 mVisibilityChangeForAutofillHandler.removeMessages(0); 17169 } 17170 17171 // If the view is in the background but still part of the hierarchy this is called 17172 // with isVisible=false. Hence visibility==false requires further checks 17173 if (isVisible) { 17174 afm.notifyViewVisibilityChanged(this, true); 17175 } else { 17176 if (mVisibilityChangeForAutofillHandler == null) { 17177 mVisibilityChangeForAutofillHandler = 17178 new VisibilityChangeForAutofillHandler(afm, this); 17179 } 17180 // Let current operation (e.g. removal of the view from the hierarchy) 17181 // finish before checking state 17182 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); 17183 } 17184 } 17185 } 17186 } 17187 17188 /** 17189 * Returns the current visibility of the window this view is attached to 17190 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 17191 * 17192 * @return Returns the current visibility of the view's window. 17193 */ 17194 @Visibility getWindowVisibility()17195 public int getWindowVisibility() { 17196 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 17197 } 17198 17199 /** 17200 * Retrieve the overall visible display size in which the window this view is 17201 * attached to has been positioned in. This takes into account screen 17202 * decorations above the window, for both cases where the window itself 17203 * is being position inside of them or the window is being placed under 17204 * then and covered insets are used for the window to position its content 17205 * inside. In effect, this tells you the available area where content can 17206 * be placed and remain visible to users. 17207 * 17208 * @param outRect Filled in with the visible display frame. If the view 17209 * is not attached to a window, this is simply the raw display size. 17210 */ getWindowVisibleDisplayFrame(Rect outRect)17211 public void getWindowVisibleDisplayFrame(Rect outRect) { 17212 if (mAttachInfo != null) { 17213 mAttachInfo.mViewRootImpl.getWindowVisibleDisplayFrame(outRect); 17214 return; 17215 } 17216 // TODO (b/327559224): Refine the behavior to better reflect the window environment with API 17217 // doc updates. 17218 final WindowManager windowManager = mContext.getSystemService(WindowManager.class); 17219 final WindowMetrics metrics = windowManager.getMaximumWindowMetrics(); 17220 final Insets insets = metrics.getWindowInsets().getInsets( 17221 WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout()); 17222 outRect.set(metrics.getBounds()); 17223 outRect.inset(insets); 17224 outRect.offsetTo(0, 0); 17225 } 17226 17227 /** 17228 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 17229 * is currently in without any insets. 17230 * 17231 * @hide 17232 */ 17233 @UnsupportedAppUsage 17234 @TestApi getWindowDisplayFrame(@onNull Rect outRect)17235 public void getWindowDisplayFrame(@NonNull Rect outRect) { 17236 if (mAttachInfo != null) { 17237 mAttachInfo.mViewRootImpl.getDisplayFrame(outRect); 17238 return; 17239 } 17240 // The view is not attached to a display so we don't have a context. 17241 // Make a best guess about the display size. 17242 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 17243 d.getRectSize(outRect); 17244 } 17245 17246 /** 17247 * Dispatch a notification about a resource configuration change down 17248 * the view hierarchy. 17249 * ViewGroups should override to route to their children. 17250 * 17251 * @param newConfig The new resource configuration. 17252 * 17253 * @see #onConfigurationChanged(android.content.res.Configuration) 17254 */ dispatchConfigurationChanged(Configuration newConfig)17255 public void dispatchConfigurationChanged(Configuration newConfig) { 17256 onConfigurationChanged(newConfig); 17257 } 17258 17259 /** 17260 * Called when the current configuration of the resources being used 17261 * by the application have changed. You can use this to decide when 17262 * to reload resources that can changed based on orientation and other 17263 * configuration characteristics. You only need to use this if you are 17264 * not relying on the normal {@link android.app.Activity} mechanism of 17265 * recreating the activity instance upon a configuration change. 17266 * 17267 * @param newConfig The new resource configuration. 17268 */ onConfigurationChanged(Configuration newConfig)17269 protected void onConfigurationChanged(Configuration newConfig) { 17270 } 17271 17272 /** 17273 * Private function to aggregate all per-view attributes in to the view 17274 * root. 17275 */ dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility)17276 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 17277 performCollectViewAttributes(attachInfo, visibility); 17278 } 17279 performCollectViewAttributes(AttachInfo attachInfo, int visibility)17280 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 17281 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 17282 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 17283 attachInfo.mKeepScreenOn = true; 17284 } 17285 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 17286 ListenerInfo li = mListenerInfo; 17287 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 17288 attachInfo.mHasSystemUiListeners = true; 17289 } 17290 } 17291 } 17292 needGlobalAttributesUpdate(boolean force)17293 void needGlobalAttributesUpdate(boolean force) { 17294 final AttachInfo ai = mAttachInfo; 17295 if (ai != null && !ai.mRecomputeGlobalAttributes) { 17296 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 17297 || ai.mHasSystemUiListeners) { 17298 ai.mRecomputeGlobalAttributes = true; 17299 } 17300 } 17301 } 17302 17303 /** 17304 * Returns the touch mode state associated with this view. 17305 * 17306 * Attached views return the touch mode state from the associated window's display. 17307 * Detached views just return the default touch mode value defined in 17308 * {@code com.android.internal.R.bool.config_defaultInTouchMode}. 17309 * 17310 * Touch mode is entered once the user begins interacting with the device by touch, and 17311 * affects various things like whether focus highlight is always visible to the user. 17312 * 17313 * @return the touch mode state associated with this view 17314 */ 17315 @ViewDebug.ExportedProperty isInTouchMode()17316 public boolean isInTouchMode() { 17317 if (mAttachInfo != null) { 17318 return mAttachInfo.mInTouchMode; 17319 } 17320 return mResources.getBoolean(com.android.internal.R.bool.config_defaultInTouchMode); 17321 } 17322 17323 /** 17324 * Returns the context the view is running in, through which it can 17325 * access the current theme, resources, etc. 17326 * 17327 * @return The view's Context. 17328 */ 17329 @ViewDebug.CapturedViewProperty 17330 @UiContext getContext()17331 public final Context getContext() { 17332 return mContext; 17333 } 17334 17335 /** 17336 * Handle a key event before it is processed by any input method 17337 * associated with the view hierarchy. This can be used to intercept 17338 * key events in special situations before the IME consumes them; a 17339 * typical example would be handling the BACK key to update the application's 17340 * UI instead of allowing the IME to see it and close itself. Due to a bug, 17341 * this function is not called for BACK key events on Android T and U, when 17342 * the IME is shown. 17343 * 17344 * @param keyCode The value in event.getKeyCode(). 17345 * @param event Description of the key event. 17346 * @return If you handled the event, return true. If you want to allow the 17347 * event to be handled by the next receiver, return false. 17348 */ onKeyPreIme(int keyCode, KeyEvent event)17349 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 17350 return false; 17351 } 17352 17353 /** 17354 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 17355 * KeyEvent.Callback.onKeyDown()}: perform press of the view 17356 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 17357 * is released, if the view is enabled and clickable. 17358 * <p> 17359 * Key presses in software keyboards will generally NOT trigger this 17360 * listener, although some may elect to do so in some situations. Do not 17361 * rely on this to catch software key presses. 17362 * 17363 * @param keyCode a key code that represents the button pressed, from 17364 * {@link android.view.KeyEvent} 17365 * @param event the KeyEvent object that defines the button action 17366 */ onKeyDown(int keyCode, KeyEvent event)17367 public boolean onKeyDown(int keyCode, KeyEvent event) { 17368 if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) { 17369 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 17370 return true; 17371 } 17372 17373 if (event.getRepeatCount() == 0) { 17374 // Long clickable items don't necessarily have to be clickable. 17375 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 17376 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 17377 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 17378 // For the purposes of menu anchoring and drawable hotspots, 17379 // key events are considered to be at the center of the view. 17380 final float x = getWidth() / 2f; 17381 final float y = getHeight() / 2f; 17382 if (clickable) { 17383 setPressed(true, x, y); 17384 } 17385 checkForLongClick( 17386 ViewConfiguration.getLongPressTimeout(), 17387 x, 17388 y, 17389 // This is not a touch gesture -- do not classify it as one. 17390 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION); 17391 return true; 17392 } 17393 } 17394 } 17395 17396 return false; 17397 } 17398 17399 /** 17400 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 17401 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 17402 * the event). 17403 * <p>Key presses in software keyboards will generally NOT trigger this listener, 17404 * although some may elect to do so in some situations. Do not rely on this to 17405 * catch software key presses. 17406 */ onKeyLongPress(int keyCode, KeyEvent event)17407 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 17408 return false; 17409 } 17410 17411 /** 17412 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 17413 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 17414 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 17415 * or {@link KeyEvent#KEYCODE_SPACE} is released. 17416 * <p>Key presses in software keyboards will generally NOT trigger this listener, 17417 * although some may elect to do so in some situations. Do not rely on this to 17418 * catch software key presses. 17419 * 17420 * @param keyCode A key code that represents the button pressed, from 17421 * {@link android.view.KeyEvent}. 17422 * @param event The KeyEvent object that defines the button action. 17423 */ onKeyUp(int keyCode, KeyEvent event)17424 public boolean onKeyUp(int keyCode, KeyEvent event) { 17425 if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) { 17426 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 17427 return true; 17428 } 17429 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 17430 setPressed(false); 17431 17432 if (!mHasPerformedLongPress) { 17433 // This is a tap, so remove the longpress check 17434 removeLongPressCallback(); 17435 if (!event.isCanceled()) { 17436 return performClickInternal(); 17437 } 17438 } 17439 } 17440 } 17441 return false; 17442 } 17443 17444 /** 17445 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 17446 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 17447 * the event). 17448 * <p>Key presses in software keyboards will generally NOT trigger this listener, 17449 * although some may elect to do so in some situations. Do not rely on this to 17450 * catch software key presses. 17451 * 17452 * @param keyCode A key code that represents the button pressed, from 17453 * {@link android.view.KeyEvent}. 17454 * @param repeatCount The number of times the action was made. 17455 * @param event The KeyEvent object that defines the button action. 17456 */ onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)17457 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 17458 return false; 17459 } 17460 17461 /** 17462 * Called on the focused view when a key shortcut event is not handled. 17463 * Override this method to implement local key shortcuts for the View. 17464 * Key shortcuts can also be implemented by setting the 17465 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 17466 * 17467 * @param keyCode The value in event.getKeyCode(). 17468 * @param event Description of the key event. 17469 * @return If you handled the event, return true. If you want to allow the 17470 * event to be handled by the next receiver, return false. 17471 */ onKeyShortcut(int keyCode, KeyEvent event)17472 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 17473 return false; 17474 } 17475 17476 /** 17477 * Check whether the called view is a text editor, in which case it 17478 * would make sense to automatically display a soft input window for 17479 * it. Subclasses should override this if they implement 17480 * {@link #onCreateInputConnection(EditorInfo)} to return true if 17481 * a call on that method would return a non-null InputConnection, and 17482 * they are really a first-class editor that the user would normally 17483 * start typing on when the go into a window containing your view. 17484 * 17485 * <p>The default implementation always returns false. This does 17486 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 17487 * will not be called or the user can not otherwise perform edits on your 17488 * view; it is just a hint to the system that this is not the primary 17489 * purpose of this view. 17490 * 17491 * @return Returns true if this view is a text editor, else false. 17492 */ onCheckIsTextEditor()17493 public boolean onCheckIsTextEditor() { 17494 return false; 17495 } 17496 17497 /** 17498 * Create a new InputConnection for an InputMethod to interact 17499 * with the view. The default implementation returns null, since it doesn't 17500 * support input methods. You can override this to implement such support. 17501 * This is only needed for views that take focus and text input. 17502 * 17503 * <p>When implementing this, you probably also want to implement 17504 * {@link #onCheckIsTextEditor()} to indicate you will return a 17505 * non-null InputConnection.</p> 17506 * 17507 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 17508 * object correctly and in its entirety, so that the connected IME can rely 17509 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 17510 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 17511 * must be filled in with the correct cursor position for IMEs to work correctly 17512 * with your application.</p> 17513 * 17514 * @param outAttrs Fill in with attribute information about the connection. 17515 */ onCreateInputConnection(EditorInfo outAttrs)17516 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 17517 return null; 17518 } 17519 17520 /** 17521 * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application 17522 * that the system has successfully initialized an {@link InputConnection} and it is ready for 17523 * use. 17524 * 17525 * <p>The default implementation does nothing, since a view doesn't support input methods by 17526 * default (see {@link #onCreateInputConnection}). 17527 * 17528 * @param inputConnection The {@link InputConnection} from {@link #onCreateInputConnection}, 17529 * after it's been fully initialized by the system. 17530 * @param editorInfo The {@link EditorInfo} that was used to create the {@link InputConnection}. 17531 * @param handler The dedicated {@link Handler} on which IPC method calls from input methods 17532 * will be dispatched. This is the handler returned by {@link InputConnection#getHandler()}. If 17533 * that method returns null, this parameter will be null also. 17534 * 17535 * @hide 17536 */ onInputConnectionOpenedInternal(@onNull InputConnection inputConnection, @NonNull EditorInfo editorInfo, @Nullable Handler handler)17537 public void onInputConnectionOpenedInternal(@NonNull InputConnection inputConnection, 17538 @NonNull EditorInfo editorInfo, @Nullable Handler handler) {} 17539 17540 /** 17541 * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application 17542 * that the {@link InputConnection} has been closed. 17543 * 17544 * <p>The default implementation does nothing, since a view doesn't support input methods by 17545 * default (see {@link #onCreateInputConnection}). 17546 * 17547 * <p><strong>Note:</strong> This callback is not invoked if the view is already detached when 17548 * the {@link InputConnection} is closed or the connection is not valid and managed by 17549 * {@link com.android.server.inputmethod.InputMethodManagerService}. 17550 * TODO(b/170645312): Before un-hiding this API, handle the detached view scenario. 17551 * 17552 * @hide 17553 */ onInputConnectionClosedInternal()17554 public void onInputConnectionClosedInternal() {} 17555 17556 /** 17557 * Called by the {@link android.view.inputmethod.InputMethodManager} 17558 * when a view who is not the current 17559 * input connection target is trying to make a call on the manager. The 17560 * default implementation returns false; you can override this to return 17561 * true for certain views if you are performing InputConnection proxying 17562 * to them. 17563 * @param view The View that is making the InputMethodManager call. 17564 * @return Return true to allow the call, false to reject. 17565 */ checkInputConnectionProxy(View view)17566 public boolean checkInputConnectionProxy(View view) { 17567 return false; 17568 } 17569 17570 /** 17571 * Show the context menu for this view. It is not safe to hold on to the 17572 * menu after returning from this method. 17573 * 17574 * You should normally not overload this method. Overload 17575 * {@link #onCreateContextMenu(ContextMenu)} or define an 17576 * {@link OnCreateContextMenuListener} to add items to the context menu. 17577 * 17578 * @param menu The context menu to populate 17579 */ createContextMenu(ContextMenu menu)17580 public void createContextMenu(ContextMenu menu) { 17581 ContextMenuInfo menuInfo = getContextMenuInfo(); 17582 17583 // Sets the current menu info so all items added to menu will have 17584 // my extra info set. 17585 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 17586 17587 onCreateContextMenu(menu); 17588 ListenerInfo li = mListenerInfo; 17589 if (li != null && li.mOnCreateContextMenuListener != null) { 17590 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 17591 } 17592 17593 // Clear the extra information so subsequent items that aren't mine don't 17594 // have my extra info. 17595 ((MenuBuilder)menu).setCurrentMenuInfo(null); 17596 17597 if (mParent != null) { 17598 mParent.createContextMenu(menu); 17599 } 17600 } 17601 17602 /** 17603 * Views should implement this if they have extra information to associate 17604 * with the context menu. The return result is supplied as a parameter to 17605 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 17606 * callback. 17607 * 17608 * @return Extra information about the item for which the context menu 17609 * should be shown. This information will vary across different 17610 * subclasses of View. 17611 */ getContextMenuInfo()17612 protected ContextMenuInfo getContextMenuInfo() { 17613 return null; 17614 } 17615 17616 /** 17617 * Views should implement this if the view itself is going to add items to 17618 * the context menu. 17619 * 17620 * @param menu the context menu to populate 17621 */ onCreateContextMenu(ContextMenu menu)17622 protected void onCreateContextMenu(ContextMenu menu) { 17623 } 17624 17625 /** 17626 * Implement this method to handle trackball motion events. 17627 * <p> 17628 * The <em>relative</em> movement of the trackball since the last event 17629 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 17630 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 17631 * that a movement of 1 corresponds to the user pressing one DPAD key (so 17632 * they will often be fractional values, representing the more fine-grained 17633 * movement information available from a trackball). 17634 * </p> 17635 * 17636 * @param event The motion event. 17637 * @return True if the event was handled, false otherwise. 17638 */ onTrackballEvent(MotionEvent event)17639 public boolean onTrackballEvent(MotionEvent event) { 17640 return false; 17641 } 17642 17643 /** 17644 * Implement this method to handle generic motion events. 17645 * <p> 17646 * Generic motion events describe joystick movements, hover events from mouse or stylus 17647 * devices, trackpad touches, scroll wheel movements and other motion events not handled 17648 * by {@link #onTouchEvent(MotionEvent)} or {@link #onTrackballEvent(MotionEvent)}. 17649 * The {@link MotionEvent#getSource() source} of the motion event specifies 17650 * the class of input that was received. Implementations of this method 17651 * must examine the bits in the source before processing the event. 17652 * The following code example shows how this is done. 17653 * </p><p> 17654 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 17655 * are delivered to the view under the pointer. All other generic motion events are 17656 * delivered to the focused view. 17657 * </p> 17658 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 17659 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 17660 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 17661 * // process the joystick movement... 17662 * return true; 17663 * } 17664 * } 17665 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 17666 * switch (event.getAction()) { 17667 * case MotionEvent.ACTION_HOVER_MOVE: 17668 * // process the hover movement... 17669 * return true; 17670 * case MotionEvent.ACTION_SCROLL: 17671 * // process the scroll wheel movement... 17672 * return true; 17673 * } 17674 * } 17675 * return super.onGenericMotionEvent(event); 17676 * }</pre> 17677 * 17678 * @param event The generic motion event being processed. 17679 * @return True if the event was handled, false otherwise. 17680 */ onGenericMotionEvent(MotionEvent event)17681 public boolean onGenericMotionEvent(MotionEvent event) { 17682 return false; 17683 } 17684 17685 /** 17686 * Dispatching hover events to {@link TouchDelegate} to improve accessibility. 17687 * <p> 17688 * This method is dispatching hover events to the delegate target to support explore by touch. 17689 * Similar to {@link ViewGroup#dispatchTouchEvent}, this method sends proper hover events to 17690 * the delegate target according to the pointer and the touch area of the delegate while touch 17691 * exploration is enabled. 17692 * </p> 17693 * 17694 * @param event The motion event dispatch to the delegate target. 17695 * @return True if the event was handled, false otherwise. 17696 * 17697 * @see #onHoverEvent 17698 */ dispatchTouchExplorationHoverEvent(MotionEvent event)17699 private boolean dispatchTouchExplorationHoverEvent(MotionEvent event) { 17700 final AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 17701 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 17702 return false; 17703 } 17704 17705 final boolean oldHoveringTouchDelegate = mHoveringTouchDelegate; 17706 final int action = event.getActionMasked(); 17707 boolean pointInDelegateRegion = false; 17708 boolean handled = false; 17709 17710 final AccessibilityNodeInfo.TouchDelegateInfo info = mTouchDelegate.getTouchDelegateInfo(); 17711 for (int i = 0; i < info.getRegionCount(); i++) { 17712 Region r = info.getRegionAt(i); 17713 if (r.contains((int) event.getX(), (int) event.getY())) { 17714 pointInDelegateRegion = true; 17715 } 17716 } 17717 17718 // Explore by touch should dispatch events to children under the pointer first if any 17719 // before dispatching to TouchDelegate. For non-hoverable views that do not consume 17720 // hover events but receive accessibility focus, it should also not delegate to these 17721 // views when hovered. 17722 if (!oldHoveringTouchDelegate) { 17723 if (removeChildHoverCheckForTouchExploration()) { 17724 if ((action == MotionEvent.ACTION_HOVER_ENTER 17725 || action == MotionEvent.ACTION_HOVER_MOVE) && pointInDelegateRegion) { 17726 mHoveringTouchDelegate = true; 17727 } 17728 } else { 17729 if ((action == MotionEvent.ACTION_HOVER_ENTER 17730 || action == MotionEvent.ACTION_HOVER_MOVE) 17731 && !pointInHoveredChild(event) 17732 && pointInDelegateRegion) { 17733 mHoveringTouchDelegate = true; 17734 } 17735 } 17736 } else { 17737 if (removeChildHoverCheckForTouchExploration()) { 17738 if (action == MotionEvent.ACTION_HOVER_EXIT 17739 || (action == MotionEvent.ACTION_HOVER_MOVE)) { 17740 if (!pointInDelegateRegion) { 17741 mHoveringTouchDelegate = false; 17742 } 17743 } 17744 } else { 17745 if (action == MotionEvent.ACTION_HOVER_EXIT 17746 || (action == MotionEvent.ACTION_HOVER_MOVE 17747 && (pointInHoveredChild(event) || !pointInDelegateRegion))) { 17748 mHoveringTouchDelegate = false; 17749 } 17750 } 17751 } 17752 switch (action) { 17753 case MotionEvent.ACTION_HOVER_MOVE: 17754 if (oldHoveringTouchDelegate && mHoveringTouchDelegate) { 17755 // Inside bounds, dispatch as is. 17756 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 17757 } else if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 17758 // Moving inbound, synthesize hover enter. 17759 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 17760 ? event : MotionEvent.obtainNoHistory(event); 17761 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER); 17762 handled = mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 17763 eventNoHistory.setAction(action); 17764 handled |= mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 17765 } else if (oldHoveringTouchDelegate && !mHoveringTouchDelegate) { 17766 // Moving outbound, synthesize hover exit. 17767 final boolean hoverExitPending = event.isHoverExitPending(); 17768 event.setHoverExitPending(true); 17769 mTouchDelegate.onTouchExplorationHoverEvent(event); 17770 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 17771 ? event : MotionEvent.obtainNoHistory(event); 17772 eventNoHistory.setHoverExitPending(hoverExitPending); 17773 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); 17774 mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 17775 } // else: outside bounds, do nothing. 17776 break; 17777 case MotionEvent.ACTION_HOVER_ENTER: 17778 if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 17779 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 17780 } 17781 break; 17782 case MotionEvent.ACTION_HOVER_EXIT: 17783 if (oldHoveringTouchDelegate) { 17784 mTouchDelegate.onTouchExplorationHoverEvent(event); 17785 } 17786 break; 17787 } 17788 return handled; 17789 } 17790 17791 /** 17792 * Implement this method to handle hover events. 17793 * <p> 17794 * This method is called whenever a pointer is hovering into, over, or out of the 17795 * bounds of a view and the view is not currently being touched. 17796 * Hover events are represented as pointer events with action 17797 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 17798 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 17799 * </p> 17800 * <ul> 17801 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 17802 * when the pointer enters the bounds of the view.</li> 17803 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 17804 * when the pointer has already entered the bounds of the view and has moved.</li> 17805 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 17806 * when the pointer has exited the bounds of the view or when the pointer is 17807 * about to go down due to a button click, tap, or similar user action that 17808 * causes the view to be touched.</li> 17809 * </ul> 17810 * <p> 17811 * The view should implement this method to return true to indicate that it is 17812 * handling the hover event, such as by changing its drawable state. 17813 * </p><p> 17814 * The default implementation calls {@link #setHovered} to update the hovered state 17815 * of the view when a hover enter or hover exit event is received, if the view 17816 * is enabled and is clickable. The default implementation also sends hover 17817 * accessibility events. 17818 * </p> 17819 * 17820 * @param event The motion event that describes the hover. 17821 * @return True if the view handled the hover event. 17822 * 17823 * @see #isHovered 17824 * @see #setHovered 17825 * @see #onHoverChanged 17826 */ onHoverEvent(MotionEvent event)17827 public boolean onHoverEvent(MotionEvent event) { 17828 if (mTouchDelegate != null && dispatchTouchExplorationHoverEvent(event)) { 17829 return true; 17830 } 17831 17832 // The root view may receive hover (or touch) events that are outside the bounds of 17833 // the window. This code ensures that we only send accessibility events for 17834 // hovers that are actually within the bounds of the root view. 17835 final int action = event.getActionMasked(); 17836 if (!mSendingHoverAccessibilityEvents) { 17837 if ((action == MotionEvent.ACTION_HOVER_ENTER 17838 || action == MotionEvent.ACTION_HOVER_MOVE) 17839 && !hasHoveredChild() 17840 && pointInView(event.getX(), event.getY())) { 17841 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 17842 mSendingHoverAccessibilityEvents = true; 17843 } 17844 } else { 17845 if (action == MotionEvent.ACTION_HOVER_EXIT 17846 || (action == MotionEvent.ACTION_HOVER_MOVE 17847 && !pointInView(event.getX(), event.getY()))) { 17848 mSendingHoverAccessibilityEvents = false; 17849 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 17850 } 17851 } 17852 17853 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 17854 && event.isFromSource(InputDevice.SOURCE_MOUSE) 17855 && isOnScrollbar(event.getX(), event.getY())) { 17856 awakenScrollBars(); 17857 } 17858 17859 // If we consider ourself hoverable, or if we we're already hovered, 17860 // handle changing state in response to ENTER and EXIT events. 17861 if (isHoverable() || isHovered()) { 17862 switch (action) { 17863 case MotionEvent.ACTION_HOVER_ENTER: 17864 setHovered(true); 17865 break; 17866 case MotionEvent.ACTION_HOVER_EXIT: 17867 setHovered(false); 17868 break; 17869 } 17870 17871 // Dispatch the event to onGenericMotionEvent before returning true. 17872 // This is to provide compatibility with existing applications that 17873 // handled HOVER_MOVE events in onGenericMotionEvent and that would 17874 // break because of the new default handling for hoverable views 17875 // in onHoverEvent. 17876 // Note that onGenericMotionEvent will be called by default when 17877 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 17878 dispatchGenericMotionEventInternal(event); 17879 // The event was already handled by calling setHovered(), so always 17880 // return true. 17881 return true; 17882 } 17883 17884 return false; 17885 } 17886 17887 /** 17888 * Returns true if the view should handle {@link #onHoverEvent} 17889 * by calling {@link #setHovered} to change its hovered state. 17890 * 17891 * @return True if the view is hoverable. 17892 */ isHoverable()17893 private boolean isHoverable() { 17894 final int viewFlags = mViewFlags; 17895 if ((viewFlags & ENABLED_MASK) == DISABLED) { 17896 return false; 17897 } 17898 17899 return (viewFlags & CLICKABLE) == CLICKABLE 17900 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 17901 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 17902 } 17903 17904 /** 17905 * Returns true if the view is currently hovered. 17906 * 17907 * @return True if the view is currently hovered. 17908 * 17909 * @see #setHovered 17910 * @see #onHoverChanged 17911 */ 17912 @ViewDebug.ExportedProperty isHovered()17913 public boolean isHovered() { 17914 return (mPrivateFlags & PFLAG_HOVERED) != 0; 17915 } 17916 17917 /** 17918 * Sets whether the view is currently hovered. 17919 * <p> 17920 * Calling this method also changes the drawable state of the view. This 17921 * enables the view to react to hover by using different drawable resources 17922 * to change its appearance. 17923 * </p><p> 17924 * The {@link #onHoverChanged} method is called when the hovered state changes. 17925 * </p> 17926 * 17927 * @param hovered True if the view is hovered. 17928 * 17929 * @see #isHovered 17930 * @see #onHoverChanged 17931 */ setHovered(boolean hovered)17932 public void setHovered(boolean hovered) { 17933 if (hovered) { 17934 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 17935 mPrivateFlags |= PFLAG_HOVERED; 17936 refreshDrawableState(); 17937 onHoverChanged(true); 17938 } 17939 } else { 17940 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 17941 mPrivateFlags &= ~PFLAG_HOVERED; 17942 refreshDrawableState(); 17943 onHoverChanged(false); 17944 } 17945 } 17946 } 17947 17948 /** 17949 * Implement this method to handle hover state changes. 17950 * <p> 17951 * This method is called whenever the hover state changes as a result of a 17952 * call to {@link #setHovered}. 17953 * </p> 17954 * 17955 * @param hovered The current hover state, as returned by {@link #isHovered}. 17956 * 17957 * @see #isHovered 17958 * @see #setHovered 17959 */ onHoverChanged(boolean hovered)17960 public void onHoverChanged(boolean hovered) { 17961 } 17962 17963 /** 17964 * Handles scroll bar dragging by mouse input. 17965 * 17966 * @hide 17967 * @param event The motion event. 17968 * 17969 * @return true if the event was handled as a scroll bar dragging, false otherwise. 17970 */ handleScrollBarDragging(MotionEvent event)17971 protected boolean handleScrollBarDragging(MotionEvent event) { 17972 if (mScrollCache == null) { 17973 return false; 17974 } 17975 final float x = event.getX(); 17976 final float y = event.getY(); 17977 final int action = event.getAction(); 17978 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 17979 && action != MotionEvent.ACTION_DOWN) 17980 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 17981 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 17982 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 17983 return false; 17984 } 17985 17986 switch (action) { 17987 case MotionEvent.ACTION_MOVE: 17988 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 17989 return false; 17990 } 17991 if (mScrollCache.mScrollBarDraggingState 17992 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 17993 final Rect bounds = mScrollCache.mScrollBarBounds; 17994 getVerticalScrollBarBounds(bounds, null); 17995 final int range = computeVerticalScrollRange(); 17996 final int offset = computeVerticalScrollOffset(); 17997 final int extent = computeVerticalScrollExtent(); 17998 17999 final int thumbLength = ScrollBarUtils.getThumbLength( 18000 bounds.height(), bounds.width(), extent, range); 18001 final int thumbOffset = ScrollBarUtils.getThumbOffset( 18002 bounds.height(), thumbLength, extent, range, offset); 18003 18004 final float diff = y - mScrollCache.mScrollBarDraggingPos; 18005 final float maxThumbOffset = bounds.height() - thumbLength; 18006 final float newThumbOffset = 18007 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 18008 final int height = getHeight(); 18009 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 18010 && height > 0 && extent > 0) { 18011 final int newY = Math.round((range - extent) 18012 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 18013 if (newY != getScrollY()) { 18014 mScrollCache.mScrollBarDraggingPos = y; 18015 setScrollY(newY); 18016 } 18017 } 18018 return true; 18019 } 18020 if (mScrollCache.mScrollBarDraggingState 18021 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 18022 final Rect bounds = mScrollCache.mScrollBarBounds; 18023 getHorizontalScrollBarBounds(bounds, null); 18024 final int range = computeHorizontalScrollRange(); 18025 final int offset = computeHorizontalScrollOffset(); 18026 final int extent = computeHorizontalScrollExtent(); 18027 18028 final int thumbLength = ScrollBarUtils.getThumbLength( 18029 bounds.width(), bounds.height(), extent, range); 18030 final int thumbOffset = ScrollBarUtils.getThumbOffset( 18031 bounds.width(), thumbLength, extent, range, offset); 18032 18033 final float diff = x - mScrollCache.mScrollBarDraggingPos; 18034 final float maxThumbOffset = bounds.width() - thumbLength; 18035 final float newThumbOffset = 18036 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 18037 final int width = getWidth(); 18038 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 18039 && width > 0 && extent > 0) { 18040 final int newX = Math.round((range - extent) 18041 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 18042 if (newX != getScrollX()) { 18043 mScrollCache.mScrollBarDraggingPos = x; 18044 setScrollX(newX); 18045 } 18046 } 18047 return true; 18048 } 18049 case MotionEvent.ACTION_DOWN: 18050 if (mScrollCache.state == ScrollabilityCache.OFF) { 18051 return false; 18052 } 18053 if (isOnVerticalScrollbarThumb(x, y)) { 18054 mScrollCache.mScrollBarDraggingState = 18055 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 18056 mScrollCache.mScrollBarDraggingPos = y; 18057 return true; 18058 } 18059 if (isOnHorizontalScrollbarThumb(x, y)) { 18060 mScrollCache.mScrollBarDraggingState = 18061 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 18062 mScrollCache.mScrollBarDraggingPos = x; 18063 return true; 18064 } 18065 } 18066 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 18067 return false; 18068 } 18069 18070 /** 18071 * Implement this method to handle pointer events. 18072 * <p> 18073 * This method is called to handle motion events where pointers are down on 18074 * the view. For example, this could include touchscreen touches, stylus 18075 * touches, or click-and-drag events from a mouse. However, it is not called 18076 * for motion events that do not involve pointers being down, such as hover 18077 * events or mouse scroll wheel movements. 18078 * <p> 18079 * If this method is used to detect click actions, it is recommended that 18080 * the actions be performed by implementing and calling 18081 * {@link #performClick()}. This will ensure consistent system behavior, 18082 * including: 18083 * <ul> 18084 * <li>obeying click sound preferences 18085 * <li>dispatching OnClickListener calls 18086 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 18087 * accessibility features are enabled 18088 * </ul> 18089 * 18090 * @param event The motion event. 18091 * @return True if the event was handled, false otherwise. 18092 */ onTouchEvent(MotionEvent event)18093 public boolean onTouchEvent(MotionEvent event) { 18094 final float x = event.getX(); 18095 final float y = event.getY(); 18096 final int viewFlags = mViewFlags; 18097 final int action = event.getAction(); 18098 18099 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 18100 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 18101 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 18102 18103 if ((viewFlags & ENABLED_MASK) == DISABLED 18104 && (mPrivateFlags4 & PFLAG4_ALLOW_CLICK_WHEN_DISABLED) == 0) { 18105 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 18106 setPressed(false); 18107 } 18108 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 18109 // A disabled view that is clickable still consumes the touch 18110 // events, it just doesn't respond to them. 18111 return clickable; 18112 } 18113 if (mTouchDelegate != null) { 18114 if (mTouchDelegate.onTouchEvent(event)) { 18115 return true; 18116 } 18117 } 18118 18119 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 18120 switch (action) { 18121 case MotionEvent.ACTION_UP: 18122 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 18123 if ((viewFlags & TOOLTIP) == TOOLTIP) { 18124 handleTooltipUp(); 18125 } 18126 if (!clickable) { 18127 removeTapCallback(); 18128 removeLongPressCallback(); 18129 mInContextButtonPress = false; 18130 mHasPerformedLongPress = false; 18131 mIgnoreNextUpEvent = false; 18132 break; 18133 } 18134 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 18135 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 18136 // take focus if we don't have it already and we should in 18137 // touch mode. 18138 boolean focusTaken = false; 18139 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 18140 focusTaken = requestFocus(); 18141 } 18142 18143 if (prepressed) { 18144 // The button is being released before we actually 18145 // showed it as pressed. Make it show the pressed 18146 // state now (before scheduling the click) to ensure 18147 // the user sees it. 18148 setPressed(true, x, y); 18149 } 18150 18151 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 18152 // This is a tap, so remove the longpress check 18153 removeLongPressCallback(); 18154 18155 // Only perform take click actions if we were in the pressed state 18156 if (!focusTaken) { 18157 // Use a Runnable and post this rather than calling 18158 // performClick directly. This lets other visual state 18159 // of the view update before click actions start. 18160 if (mPerformClick == null) { 18161 mPerformClick = new PerformClick(); 18162 } 18163 if (!post(mPerformClick)) { 18164 performClickInternal(); 18165 } 18166 } 18167 } 18168 18169 if (mUnsetPressedState == null) { 18170 mUnsetPressedState = new UnsetPressedState(); 18171 } 18172 18173 if (prepressed) { 18174 postDelayed(mUnsetPressedState, 18175 ViewConfiguration.getPressedStateDuration()); 18176 } else if (!post(mUnsetPressedState)) { 18177 // If the post failed, unpress right now 18178 mUnsetPressedState.run(); 18179 } 18180 18181 removeTapCallback(); 18182 } 18183 mIgnoreNextUpEvent = false; 18184 break; 18185 18186 case MotionEvent.ACTION_DOWN: 18187 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 18188 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 18189 } 18190 mHasPerformedLongPress = false; 18191 18192 if (!clickable) { 18193 checkForLongClick( 18194 ViewConfiguration.getLongPressTimeout(), 18195 x, 18196 y, 18197 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 18198 break; 18199 } 18200 18201 if (performButtonActionOnTouchDown(event)) { 18202 break; 18203 } 18204 18205 // Walk up the hierarchy to determine if we're inside a scrolling container. 18206 boolean isInScrollingContainer = isInScrollingContainer(); 18207 18208 // For views inside a scrolling container, delay the pressed feedback for 18209 // a short period in case this is a scroll. 18210 if (isInScrollingContainer) { 18211 mPrivateFlags |= PFLAG_PREPRESSED; 18212 if (mPendingCheckForTap == null) { 18213 mPendingCheckForTap = new CheckForTap(); 18214 } 18215 mPendingCheckForTap.x = event.getX(); 18216 mPendingCheckForTap.y = event.getY(); 18217 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 18218 } else { 18219 // Not inside a scrolling container, so show the feedback right away 18220 setPressed(true, x, y); 18221 checkForLongClick( 18222 ViewConfiguration.getLongPressTimeout(), 18223 x, 18224 y, 18225 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 18226 } 18227 break; 18228 18229 case MotionEvent.ACTION_CANCEL: 18230 if (clickable) { 18231 setPressed(false); 18232 } 18233 removeTapCallback(); 18234 removeLongPressCallback(); 18235 mInContextButtonPress = false; 18236 mHasPerformedLongPress = false; 18237 mIgnoreNextUpEvent = false; 18238 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 18239 break; 18240 18241 case MotionEvent.ACTION_MOVE: 18242 if (clickable) { 18243 drawableHotspotChanged(x, y); 18244 } 18245 18246 final int motionClassification = event.getClassification(); 18247 final boolean ambiguousGesture = 18248 motionClassification == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE; 18249 int touchSlop = mTouchSlop; 18250 if (ambiguousGesture && hasPendingLongPressCallback()) { 18251 if (!pointInView(x, y, touchSlop)) { 18252 // The default action here is to cancel long press. But instead, we 18253 // just extend the timeout here, in case the classification 18254 // stays ambiguous. 18255 removeLongPressCallback(); 18256 long delay = (long) (ViewConfiguration.getLongPressTimeout() 18257 * mAmbiguousGestureMultiplier); 18258 // Subtract the time already spent 18259 delay -= event.getEventTime() - event.getDownTime(); 18260 checkForLongClick( 18261 delay, 18262 x, 18263 y, 18264 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 18265 } 18266 touchSlop *= mAmbiguousGestureMultiplier; 18267 } 18268 18269 // Be lenient about moving outside of buttons 18270 if (!pointInView(x, y, touchSlop)) { 18271 // Outside button 18272 // Remove any future long press/tap checks 18273 removeTapCallback(); 18274 removeLongPressCallback(); 18275 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 18276 setPressed(false); 18277 } 18278 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 18279 } 18280 18281 final boolean deepPress = 18282 motionClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS; 18283 if (deepPress && hasPendingLongPressCallback()) { 18284 // process the long click action immediately 18285 removeLongPressCallback(); 18286 checkForLongClick( 18287 0 /* send immediately */, 18288 x, 18289 y, 18290 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS); 18291 } 18292 18293 break; 18294 } 18295 18296 return true; 18297 } 18298 18299 return false; 18300 } 18301 18302 /** 18303 * Called by {@link #measure(int, int)} to check if the current frame presentation got 18304 * delayed by an expensive view mesures during the input event dispatching. (e.g. scrolling) 18305 */ hasExpensiveMeasuresDuringInputEvent()18306 private boolean hasExpensiveMeasuresDuringInputEvent() { 18307 final AttachInfo attachInfo = mAttachInfo; 18308 if (attachInfo == null || attachInfo.mRootView == null) { 18309 return false; 18310 } 18311 if (!attachInfo.mHandlingPointerEvent) { 18312 return false; 18313 } 18314 final ViewFrameInfo info = attachInfo.mViewRootImpl.mViewFrameInfo; 18315 final long durationFromVsyncTimeMs = (System.nanoTime() 18316 - Choreographer.getInstance().getLastFrameTimeNanos()) / TimeUtils.NANOS_PER_MS; 18317 return durationFromVsyncTimeMs > 3L || info.getAndIncreaseViewMeasuredCount() > 10; 18318 } 18319 18320 /** 18321 * @hide 18322 */ 18323 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isInScrollingContainer()18324 public boolean isInScrollingContainer() { 18325 ViewParent p = getParent(); 18326 while (p != null && p instanceof ViewGroup) { 18327 if (((ViewGroup) p).shouldDelayChildPressedState()) { 18328 return true; 18329 } 18330 p = p.getParent(); 18331 } 18332 return false; 18333 } 18334 18335 /** 18336 * Remove the longpress detection timer. 18337 */ removeLongPressCallback()18338 private void removeLongPressCallback() { 18339 if (mPendingCheckForLongPress != null) { 18340 removeCallbacks(mPendingCheckForLongPress); 18341 } 18342 } 18343 18344 /** 18345 * Return true if the long press callback is scheduled to run sometime in the future. 18346 * Return false if there is no scheduled long press callback at the moment. 18347 */ hasPendingLongPressCallback()18348 private boolean hasPendingLongPressCallback() { 18349 if (mPendingCheckForLongPress == null) { 18350 return false; 18351 } 18352 final AttachInfo attachInfo = mAttachInfo; 18353 if (attachInfo == null) { 18354 return false; 18355 } 18356 return attachInfo.mHandler.hasCallbacks(mPendingCheckForLongPress); 18357 } 18358 18359 /** 18360 * Remove the pending click action 18361 */ 18362 @UnsupportedAppUsage removePerformClickCallback()18363 private void removePerformClickCallback() { 18364 if (mPerformClick != null) { 18365 removeCallbacks(mPerformClick); 18366 } 18367 } 18368 18369 /** 18370 * Remove the prepress detection timer. 18371 */ removeUnsetPressCallback()18372 private void removeUnsetPressCallback() { 18373 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 18374 setPressed(false); 18375 removeCallbacks(mUnsetPressedState); 18376 } 18377 } 18378 18379 /** 18380 * Remove the tap detection timer. 18381 */ removeTapCallback()18382 private void removeTapCallback() { 18383 if (mPendingCheckForTap != null) { 18384 mPrivateFlags &= ~PFLAG_PREPRESSED; 18385 removeCallbacks(mPendingCheckForTap); 18386 } 18387 } 18388 18389 /** 18390 * Cancels a pending long press. Your subclass can use this if you 18391 * want the context menu to come up if the user presses and holds 18392 * at the same place, but you don't want it to come up if they press 18393 * and then move around enough to cause scrolling. 18394 */ cancelLongPress()18395 public void cancelLongPress() { 18396 removeLongPressCallback(); 18397 18398 /* 18399 * The prepressed state handled by the tap callback is a display 18400 * construct, but the tap callback will post a long press callback 18401 * less its own timeout. Remove it here. 18402 */ 18403 removeTapCallback(); 18404 } 18405 18406 /** 18407 * Sets the TouchDelegate for this View. 18408 */ setTouchDelegate(TouchDelegate delegate)18409 public void setTouchDelegate(TouchDelegate delegate) { 18410 mTouchDelegate = delegate; 18411 } 18412 18413 /** 18414 * Gets the TouchDelegate for this View. 18415 */ getTouchDelegate()18416 public TouchDelegate getTouchDelegate() { 18417 return mTouchDelegate; 18418 } 18419 18420 /** 18421 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 18422 * 18423 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 18424 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 18425 * available. This method should only be called for touch events. 18426 * 18427 * <p class="note">This API is not intended for most applications. Buffered dispatch 18428 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 18429 * streams will not improve your input latency. Side effects include: increased latency, 18430 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 18431 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 18432 * you.</p> 18433 * 18434 * To receive unbuffered events for arbitrary input device source classes, use 18435 * {@link #requestUnbufferedDispatch(int)}, 18436 * 18437 * @see View#requestUnbufferedDispatch(int) 18438 */ requestUnbufferedDispatch(MotionEvent event)18439 public final void requestUnbufferedDispatch(MotionEvent event) { 18440 final int action = event.getAction(); 18441 if (mAttachInfo == null 18442 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 18443 || !event.isTouchEvent()) { 18444 return; 18445 } 18446 mAttachInfo.mUnbufferedDispatchRequested = true; 18447 } 18448 18449 /** 18450 * Request unbuffered dispatch of the given event source class to this view. 18451 * This is similar to {@link View#requestUnbufferedDispatch(MotionEvent)}, but does not 18452 * automatically terminate, and allows the specification of arbitrary input source classes. 18453 * 18454 * <p>Prior to {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, calling this method 18455 * will not result in any behavioral changes when this View is not attached to a window. 18456 * 18457 * @param source The combined input source class to request unbuffered dispatch for. All 18458 * events coming from these source classes will not be buffered. Set to 18459 * {@link InputDevice#SOURCE_CLASS_NONE} in order to return to default behaviour. 18460 * 18461 * @see View#requestUnbufferedDispatch(MotionEvent) 18462 */ requestUnbufferedDispatch(@nputSourceClass int source)18463 public final void requestUnbufferedDispatch(@InputSourceClass int source) { 18464 if (mUnbufferedInputSource == source) { 18465 return; 18466 } 18467 mUnbufferedInputSource = source; 18468 if (mParent != null) { 18469 mParent.onDescendantUnbufferedRequested(); 18470 } 18471 } 18472 hasSize()18473 private boolean hasSize() { 18474 return (mBottom > mTop) && (mRight > mLeft); 18475 } 18476 canTakeFocus()18477 private boolean canTakeFocus() { 18478 return ((mViewFlags & VISIBILITY_MASK) == VISIBLE) 18479 && ((mViewFlags & FOCUSABLE) == FOCUSABLE) 18480 && ((mViewFlags & ENABLED_MASK) == ENABLED) 18481 && (sCanFocusZeroSized || !isLayoutValid() || hasSize()); 18482 } 18483 18484 /** 18485 * Set flags controlling behavior of this view. 18486 * 18487 * @param flags Constant indicating the value which should be set 18488 * @param mask Constant indicating the bit range that should be changed 18489 */ 18490 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) setFlags(int flags, int mask)18491 void setFlags(int flags, int mask) { 18492 final boolean accessibilityEnabled = 18493 AccessibilityManager.getInstance(mContext).isEnabled(); 18494 final boolean oldIncludeForAccessibility = 18495 accessibilityEnabled && includeForAccessibility(false); 18496 18497 int old = mViewFlags; 18498 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 18499 18500 int changed = mViewFlags ^ old; 18501 if (changed == 0) { 18502 return; 18503 } 18504 int privateFlags = mPrivateFlags; 18505 boolean shouldNotifyFocusableAvailable = false; 18506 18507 // If focusable is auto, update the FOCUSABLE bit. 18508 int focusableChangedByAuto = 0; 18509 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 18510 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 18511 // Heuristic only takes into account whether view is clickable. 18512 final int newFocus; 18513 if ((mViewFlags & CLICKABLE) != 0) { 18514 newFocus = FOCUSABLE; 18515 } else { 18516 newFocus = NOT_FOCUSABLE; 18517 } 18518 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 18519 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 18520 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 18521 } 18522 18523 /* Check if the FOCUSABLE bit has changed */ 18524 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 18525 if (((old & FOCUSABLE) == FOCUSABLE) 18526 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 18527 /* Give up focus if we are no longer focusable */ 18528 clearFocus(); 18529 if (mParent instanceof ViewGroup) { 18530 ((ViewGroup) mParent).clearFocusedInCluster(); 18531 } 18532 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 18533 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 18534 /* 18535 * Tell the view system that we are now available to take focus 18536 * if no one else already has it. 18537 */ 18538 if (mParent != null) { 18539 ViewRootImpl viewRootImpl = getViewRootImpl(); 18540 if (!sAutoFocusableOffUIThreadWontNotifyParents 18541 || focusableChangedByAuto == 0 18542 || viewRootImpl == null 18543 || viewRootImpl.mThread == Thread.currentThread()) { 18544 shouldNotifyFocusableAvailable = canTakeFocus(); 18545 } 18546 } 18547 } 18548 } 18549 18550 final int newVisibility = flags & VISIBILITY_MASK; 18551 if (newVisibility == VISIBLE) { 18552 if ((changed & VISIBILITY_MASK) != 0) { 18553 /* 18554 * If this view is becoming visible, invalidate it in case it changed while 18555 * it was not visible. Marking it drawn ensures that the invalidation will 18556 * go through. 18557 */ 18558 mPrivateFlags |= PFLAG_DRAWN; 18559 invalidate(true); 18560 18561 needGlobalAttributesUpdate(true); 18562 18563 // a view becoming visible is worth notifying the parent about in case nothing has 18564 // focus. Even if this specific view isn't focusable, it may contain something that 18565 // is, so let the root view try to give this focus if nothing else does. 18566 shouldNotifyFocusableAvailable = hasSize(); 18567 } 18568 } 18569 18570 if ((changed & ENABLED_MASK) != 0) { 18571 if ((mViewFlags & ENABLED_MASK) == ENABLED) { 18572 // a view becoming enabled should notify the parent as long as the view is also 18573 // visible and the parent wasn't already notified by becoming visible during this 18574 // setFlags invocation. 18575 shouldNotifyFocusableAvailable = canTakeFocus(); 18576 } else { 18577 if (isFocused()) clearFocus(); 18578 } 18579 } 18580 18581 if (shouldNotifyFocusableAvailable && mParent != null) { 18582 mParent.focusableViewAvailable(this); 18583 } 18584 18585 /* Check if the GONE bit has changed */ 18586 if ((changed & GONE) != 0) { 18587 needGlobalAttributesUpdate(false); 18588 requestLayout(); 18589 18590 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 18591 if (hasFocus()) { 18592 clearFocus(); 18593 if (mParent instanceof ViewGroup) { 18594 ((ViewGroup) mParent).clearFocusedInCluster(); 18595 } 18596 } 18597 clearAccessibilityFocus(); 18598 destroyDrawingCache(); 18599 if (mParent instanceof View) { 18600 // GONE views noop invalidation, so invalidate the parent 18601 ((View) mParent).invalidate(true); 18602 } 18603 // Mark the view drawn to ensure that it gets invalidated properly the next 18604 // time it is visible and gets invalidated 18605 mPrivateFlags |= PFLAG_DRAWN; 18606 } 18607 if (mAttachInfo != null) { 18608 mAttachInfo.mViewVisibilityChanged = true; 18609 } 18610 } 18611 18612 /* Check if the VISIBLE bit has changed */ 18613 if ((changed & INVISIBLE) != 0) { 18614 needGlobalAttributesUpdate(false); 18615 /* 18616 * If this view is becoming invisible, set the DRAWN flag so that 18617 * the next invalidate() will not be skipped. 18618 */ 18619 mPrivateFlags |= PFLAG_DRAWN; 18620 18621 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 18622 // root view becoming invisible shouldn't clear focus and accessibility focus 18623 if (getRootView() != this) { 18624 if (hasFocus()) { 18625 clearFocus(); 18626 if (mParent instanceof ViewGroup) { 18627 ((ViewGroup) mParent).clearFocusedInCluster(); 18628 } 18629 } 18630 clearAccessibilityFocus(); 18631 } 18632 } 18633 if (mAttachInfo != null) { 18634 mAttachInfo.mViewVisibilityChanged = true; 18635 } 18636 } 18637 18638 if ((changed & VISIBILITY_MASK) != 0) { 18639 // If the view is invisible, cleanup its display list to free up resources 18640 if (newVisibility != VISIBLE && mAttachInfo != null) { 18641 cleanupDraw(); 18642 } 18643 18644 if (mParent instanceof ViewGroup) { 18645 ViewGroup parent = (ViewGroup) mParent; 18646 parent.onChildVisibilityChanged(this, (changed & VISIBILITY_MASK), 18647 newVisibility); 18648 parent.invalidate(true); 18649 } else if (mParent != null) { 18650 mParent.invalidateChild(this, null); 18651 } 18652 18653 if (mAttachInfo != null) { 18654 dispatchVisibilityChanged(this, newVisibility); 18655 18656 // Aggregated visibility changes are dispatched to attached views 18657 // in visible windows where the parent is currently shown/drawn 18658 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 18659 // discounting clipping or overlapping. This makes it a good place 18660 // to change animation states. 18661 if (mParent != null && getWindowVisibility() == VISIBLE && 18662 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 18663 dispatchVisibilityAggregated(newVisibility == VISIBLE); 18664 } 18665 // If this view is invisible from visible, then sending the A11y event by its 18666 // parent which is shown and has the accessibility important. 18667 if ((old & VISIBILITY_MASK) == VISIBLE) { 18668 notifySubtreeAccessibilityStateChangedByParentIfNeeded(); 18669 } else { 18670 notifySubtreeAccessibilityStateChangedIfNeeded(); 18671 } 18672 } 18673 } 18674 18675 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 18676 destroyDrawingCache(); 18677 } 18678 18679 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 18680 destroyDrawingCache(); 18681 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 18682 invalidateParentCaches(); 18683 } 18684 18685 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 18686 destroyDrawingCache(); 18687 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 18688 } 18689 18690 if ((changed & DRAW_MASK) != 0) { 18691 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 18692 if (mBackground != null 18693 || mDefaultFocusHighlight != null 18694 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 18695 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 18696 } else { 18697 mPrivateFlags |= PFLAG_SKIP_DRAW; 18698 } 18699 } else { 18700 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 18701 } 18702 requestLayout(); 18703 invalidate(true); 18704 } 18705 18706 if ((changed & KEEP_SCREEN_ON) != 0) { 18707 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 18708 mParent.recomputeViewAttributes(this); 18709 } 18710 } 18711 18712 if (accessibilityEnabled) { 18713 // If we're an accessibility pane and the visibility changed, we already have sent 18714 // a state change, so we really don't need to report other changes. 18715 if (isAccessibilityPane()) { 18716 changed &= ~VISIBILITY_MASK; 18717 } 18718 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 18719 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 18720 || (changed & CONTEXT_CLICKABLE) != 0) { 18721 if (oldIncludeForAccessibility != includeForAccessibility(false)) { 18722 notifySubtreeAccessibilityStateChangedIfNeeded(); 18723 } else { 18724 notifyViewAccessibilityStateChangedIfNeeded( 18725 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 18726 } 18727 } else if ((changed & ENABLED_MASK) != 0) { 18728 notifyViewAccessibilityStateChangedIfNeeded( 18729 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 18730 } 18731 } 18732 } 18733 18734 /** 18735 * Change the view's z order in the tree, so it's on top of other sibling 18736 * views. This ordering change may affect layout, if the parent container 18737 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 18738 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 18739 * method should be followed by calls to {@link #requestLayout()} and 18740 * {@link View#invalidate()} on the view's parent to force the parent to redraw 18741 * with the new child ordering. 18742 * 18743 * @see ViewGroup#bringChildToFront(View) 18744 */ bringToFront()18745 public void bringToFront() { 18746 if (mParent != null) { 18747 mParent.bringChildToFront(this); 18748 } 18749 } 18750 getScrollFeedbackProvider()18751 private HapticScrollFeedbackProvider getScrollFeedbackProvider() { 18752 if (mScrollFeedbackProvider == null) { 18753 mScrollFeedbackProvider = new HapticScrollFeedbackProvider(this, 18754 ViewConfiguration.get(mContext), /* isFromView= */ true); 18755 } 18756 return mScrollFeedbackProvider; 18757 } 18758 doRotaryProgressForScrollHaptics(MotionEvent rotaryEvent)18759 private void doRotaryProgressForScrollHaptics(MotionEvent rotaryEvent) { 18760 final float axisScrollValue = rotaryEvent.getAxisValue(MotionEvent.AXIS_SCROLL); 18761 final float verticalScrollFactor = 18762 ViewConfiguration.get(mContext).getScaledVerticalScrollFactor(); 18763 final int scrollAmount = -Math.round(axisScrollValue * verticalScrollFactor); 18764 getScrollFeedbackProvider().onScrollProgress( 18765 rotaryEvent.getDeviceId(), InputDevice.SOURCE_ROTARY_ENCODER, 18766 MotionEvent.AXIS_SCROLL, scrollAmount); 18767 } 18768 doRotaryLimitForScrollHaptics(MotionEvent rotaryEvent)18769 private void doRotaryLimitForScrollHaptics(MotionEvent rotaryEvent) { 18770 final boolean isStart = rotaryEvent.getAxisValue(MotionEvent.AXIS_SCROLL) > 0; 18771 getScrollFeedbackProvider().onScrollLimit( 18772 rotaryEvent.getDeviceId(), InputDevice.SOURCE_ROTARY_ENCODER, 18773 MotionEvent.AXIS_SCROLL, isStart); 18774 } 18775 processScrollEventForRotaryEncoderHaptics()18776 private void processScrollEventForRotaryEncoderHaptics() { 18777 if ((mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT) != 0) { 18778 mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_SCROLL_SINCE_LAST_ROTARY_INPUT; 18779 mPrivateFlags4 &= ~PFLAG4_ROTARY_HAPTICS_WAITING_FOR_SCROLL_EVENT; 18780 } 18781 } 18782 18783 /** 18784 * Disables the rotary scroll feedback implementation of the View class. 18785 * 18786 * <p>Note that this does NOT disable all rotary scroll feedback; it just disables the logic 18787 * implemented within the View class. The child implementation of the View may implement its own 18788 * rotary scroll feedback logic or use {@link ScrollFeedbackProvider} to generate rotary scroll 18789 * feedback. 18790 */ disableRotaryScrollFeedback()18791 void disableRotaryScrollFeedback() { 18792 // Force set PFLAG4_ROTARY_HAPTICS_DETERMINED to avoid recalculating 18793 // PFLAG4_ROTARY_HAPTICS_ENABLED under any circumstance. 18794 mPrivateFlags4 |= PFLAG4_ROTARY_HAPTICS_DETERMINED; 18795 mPrivateFlags4 &= ~PFLAG4_ROTARY_HAPTICS_ENABLED; 18796 } 18797 18798 /** 18799 * This is called in response to an internal scroll in this view (i.e., the 18800 * view scrolled its own contents). This is typically as a result of 18801 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 18802 * called. 18803 * 18804 * @param l Current horizontal scroll origin. 18805 * @param t Current vertical scroll origin. 18806 * @param oldl Previous horizontal scroll origin. 18807 * @param oldt Previous vertical scroll origin. 18808 */ onScrollChanged(int l, int t, int oldl, int oldt)18809 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 18810 notifySubtreeAccessibilityStateChangedIfNeeded(); 18811 postSendViewScrolledAccessibilityEventCallback(l - oldl, t - oldt); 18812 18813 processScrollEventForRotaryEncoderHaptics(); 18814 18815 mBackgroundSizeChanged = true; 18816 mDefaultFocusHighlightSizeChanged = true; 18817 if (mForegroundInfo != null) { 18818 mForegroundInfo.mBoundsChanged = true; 18819 } 18820 18821 final AttachInfo ai = mAttachInfo; 18822 if (ai != null) { 18823 ai.mViewScrollChanged = true; 18824 } 18825 18826 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 18827 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 18828 } 18829 } 18830 18831 /** 18832 * Interface definition for a callback to be invoked when the scroll 18833 * X or Y positions of a view change. 18834 * <p> 18835 * <b>Note:</b> Some views handle scrolling independently from View and may 18836 * have their own separate listeners for scroll-type events. For example, 18837 * {@link android.widget.ListView ListView} allows clients to register an 18838 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 18839 * to listen for changes in list scroll position. 18840 * 18841 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 18842 */ 18843 public interface OnScrollChangeListener { 18844 /** 18845 * Called when the scroll position of a view changes. 18846 * 18847 * @param v The view whose scroll position has changed. 18848 * @param scrollX Current horizontal scroll origin. 18849 * @param scrollY Current vertical scroll origin. 18850 * @param oldScrollX Previous horizontal scroll origin. 18851 * @param oldScrollY Previous vertical scroll origin. 18852 */ onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY)18853 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 18854 } 18855 18856 /** 18857 * Interface definition for a callback to be invoked when the layout bounds of a view 18858 * changes due to layout processing. 18859 */ 18860 public interface OnLayoutChangeListener { 18861 /** 18862 * Called when the layout bounds of a view changes due to layout processing. 18863 * 18864 * @param v The view whose bounds have changed. 18865 * @param left The new value of the view's left property. 18866 * @param top The new value of the view's top property. 18867 * @param right The new value of the view's right property. 18868 * @param bottom The new value of the view's bottom property. 18869 * @param oldLeft The previous value of the view's left property. 18870 * @param oldTop The previous value of the view's top property. 18871 * @param oldRight The previous value of the view's right property. 18872 * @param oldBottom The previous value of the view's bottom property. 18873 */ onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)18874 void onLayoutChange(View v, int left, int top, int right, int bottom, 18875 int oldLeft, int oldTop, int oldRight, int oldBottom); 18876 } 18877 18878 /** 18879 * This is called during layout when the size of this view has changed. If 18880 * you were just added to the view hierarchy, you're called with the old 18881 * values of 0. 18882 * 18883 * @param w Current width of this view. 18884 * @param h Current height of this view. 18885 * @param oldw Old width of this view. 18886 * @param oldh Old height of this view. 18887 */ onSizeChanged(int w, int h, int oldw, int oldh)18888 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 18889 } 18890 18891 /** 18892 * Called by draw to draw the child views. This may be overridden 18893 * by derived classes to gain control just before its children are drawn 18894 * (but after its own view has been drawn). 18895 * @param canvas the canvas on which to draw the view 18896 */ dispatchDraw(@onNull Canvas canvas)18897 protected void dispatchDraw(@NonNull Canvas canvas) { 18898 18899 } 18900 18901 /** 18902 * Gets the parent of this view. Note that the parent is a 18903 * ViewParent and not necessarily a View. 18904 * 18905 * @return Parent of this view. 18906 */ getParent()18907 public final ViewParent getParent() { 18908 return mParent; 18909 } 18910 18911 /** 18912 * Set the horizontal scrolled position of your view. This will cause a call to 18913 * {@link #onScrollChanged(int, int, int, int)} and the view will be 18914 * invalidated. 18915 * @param value the x position to scroll to 18916 */ setScrollX(int value)18917 public void setScrollX(int value) { 18918 scrollTo(value, mScrollY); 18919 } 18920 18921 /** 18922 * Set the vertical scrolled position of your view. This will cause a call to 18923 * {@link #onScrollChanged(int, int, int, int)} and the view will be 18924 * invalidated. 18925 * @param value the y position to scroll to 18926 */ setScrollY(int value)18927 public void setScrollY(int value) { 18928 scrollTo(mScrollX, value); 18929 } 18930 18931 /** 18932 * Return the scrolled left position of this view. This is the left edge of 18933 * the displayed part of your view. You do not need to draw any pixels 18934 * farther left, since those are outside of the frame of your view on 18935 * screen. 18936 * 18937 * @return The left edge of the displayed part of your view, in pixels. 18938 */ 18939 @InspectableProperty getScrollX()18940 public final int getScrollX() { 18941 return mScrollX; 18942 } 18943 18944 /** 18945 * Return the scrolled top position of this view. This is the top edge of 18946 * the displayed part of your view. You do not need to draw any pixels above 18947 * it, since those are outside of the frame of your view on screen. 18948 * 18949 * @return The top edge of the displayed part of your view, in pixels. 18950 */ 18951 @InspectableProperty getScrollY()18952 public final int getScrollY() { 18953 return mScrollY; 18954 } 18955 18956 /** 18957 * Return the width of your view. 18958 * 18959 * @return The width of your view, in pixels. 18960 */ 18961 @ViewDebug.ExportedProperty(category = "layout") getWidth()18962 public final int getWidth() { 18963 return mRight - mLeft; 18964 } 18965 18966 /** 18967 * Return the height of your view. 18968 * 18969 * @return The height of your view, in pixels. 18970 */ 18971 @ViewDebug.ExportedProperty(category = "layout") getHeight()18972 public final int getHeight() { 18973 return mBottom - mTop; 18974 } 18975 18976 /** 18977 * Return the visible drawing bounds of your view. Fills in the output 18978 * rectangle with the values from getScrollX(), getScrollY(), 18979 * getWidth(), and getHeight(). These bounds do not account for any 18980 * transformation properties currently set on the view, such as 18981 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 18982 * 18983 * @param outRect The (scrolled) drawing bounds of the view. 18984 */ getDrawingRect(Rect outRect)18985 public void getDrawingRect(Rect outRect) { 18986 outRect.left = mScrollX; 18987 outRect.top = mScrollY; 18988 outRect.right = mScrollX + (mRight - mLeft); 18989 outRect.bottom = mScrollY + (mBottom - mTop); 18990 } 18991 18992 /** 18993 * Like {@link #getMeasuredWidthAndState()}, but only returns the 18994 * raw width component (that is the result is masked by 18995 * {@link #MEASURED_SIZE_MASK}). 18996 * 18997 * @return The raw measured width of this view. 18998 */ getMeasuredWidth()18999 public final int getMeasuredWidth() { 19000 return mMeasuredWidth & MEASURED_SIZE_MASK; 19001 } 19002 19003 /** 19004 * Return the full width measurement information for this view as computed 19005 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 19006 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 19007 * This should be used during measurement and layout calculations only. Use 19008 * {@link #getWidth()} to see how wide a view is after layout. 19009 * 19010 * @return The measured width of this view as a bit mask. 19011 */ 19012 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 19013 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 19014 name = "MEASURED_STATE_TOO_SMALL"), 19015 }) getMeasuredWidthAndState()19016 public final int getMeasuredWidthAndState() { 19017 return mMeasuredWidth; 19018 } 19019 19020 /** 19021 * Like {@link #getMeasuredHeightAndState()}, but only returns the 19022 * raw height component (that is the result is masked by 19023 * {@link #MEASURED_SIZE_MASK}). 19024 * 19025 * @return The raw measured height of this view. 19026 */ getMeasuredHeight()19027 public final int getMeasuredHeight() { 19028 return mMeasuredHeight & MEASURED_SIZE_MASK; 19029 } 19030 19031 /** 19032 * Return the full height measurement information for this view as computed 19033 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 19034 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 19035 * This should be used during measurement and layout calculations only. Use 19036 * {@link #getHeight()} to see how high a view is after layout. 19037 * 19038 * @return The measured height of this view as a bit mask. 19039 */ 19040 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 19041 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 19042 name = "MEASURED_STATE_TOO_SMALL"), 19043 }) getMeasuredHeightAndState()19044 public final int getMeasuredHeightAndState() { 19045 return mMeasuredHeight; 19046 } 19047 19048 /** 19049 * Return only the state bits of {@link #getMeasuredWidthAndState()} 19050 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 19051 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 19052 * and the height component is at the shifted bits 19053 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 19054 */ getMeasuredState()19055 public final int getMeasuredState() { 19056 return (mMeasuredWidth&MEASURED_STATE_MASK) 19057 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 19058 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 19059 } 19060 19061 /** 19062 * The transform matrix of this view, which is calculated based on the current 19063 * rotation, scale, and pivot properties. 19064 * 19065 * @see #getRotation() 19066 * @see #getScaleX() 19067 * @see #getScaleY() 19068 * @see #getPivotX() 19069 * @see #getPivotY() 19070 * @return The current transform matrix for the view 19071 */ getMatrix()19072 public Matrix getMatrix() { 19073 ensureTransformationInfo(); 19074 final Matrix matrix = mTransformationInfo.mMatrix; 19075 mRenderNode.getMatrix(matrix); 19076 return matrix; 19077 } 19078 19079 /** 19080 * Returns true if the transform matrix is the identity matrix. 19081 * Recomputes the matrix if necessary. 19082 * 19083 * @return True if the transform matrix is the identity matrix, false otherwise. 19084 * @hide 19085 */ 19086 @UnsupportedAppUsage hasIdentityMatrix()19087 public final boolean hasIdentityMatrix() { 19088 return mRenderNode.hasIdentityMatrix(); 19089 } 19090 19091 @UnsupportedAppUsage ensureTransformationInfo()19092 void ensureTransformationInfo() { 19093 if (mTransformationInfo == null) { 19094 mTransformationInfo = new TransformationInfo(); 19095 } 19096 } 19097 19098 /** 19099 * Utility method to retrieve the inverse of the current mMatrix property. 19100 * We cache the matrix to avoid recalculating it when transform properties 19101 * have not changed. 19102 * 19103 * @return The inverse of the current matrix of this view. 19104 * @hide 19105 */ 19106 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getInverseMatrix()19107 public final Matrix getInverseMatrix() { 19108 ensureTransformationInfo(); 19109 if (mTransformationInfo.mInverseMatrix == null) { 19110 mTransformationInfo.mInverseMatrix = new Matrix(); 19111 } 19112 final Matrix matrix = mTransformationInfo.mInverseMatrix; 19113 mRenderNode.getInverseMatrix(matrix); 19114 return matrix; 19115 } 19116 19117 /** 19118 * Gets the distance along the Z axis from the camera to this view. 19119 * 19120 * @see #setCameraDistance(float) 19121 * 19122 * @return The distance along the Z axis. 19123 */ getCameraDistance()19124 public float getCameraDistance() { 19125 final float dpi = mResources.getDisplayMetrics().densityDpi; 19126 return mRenderNode.getCameraDistance() * dpi; 19127 } 19128 19129 /** 19130 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 19131 * views are drawn) from the camera to this view. The camera's distance 19132 * affects 3D transformations, for instance rotations around the X and Y 19133 * axis. If the rotationX or rotationY properties are changed and this view is 19134 * large (more than half the size of the screen), it is recommended to always 19135 * use a camera distance that's greater than the height (X axis rotation) or 19136 * the width (Y axis rotation) of this view.</p> 19137 * 19138 * <p>The distance of the camera from the view plane can have an affect on the 19139 * perspective distortion of the view when it is rotated around the x or y axis. 19140 * For example, a large distance will result in a large viewing angle, and there 19141 * will not be much perspective distortion of the view as it rotates. A short 19142 * distance may cause much more perspective distortion upon rotation, and can 19143 * also result in some drawing artifacts if the rotated view ends up partially 19144 * behind the camera (which is why the recommendation is to use a distance at 19145 * least as far as the size of the view, if the view is to be rotated.)</p> 19146 * 19147 * <p>The distance is expressed in "depth pixels." The default distance depends 19148 * on the screen density. For instance, on a medium density display, the 19149 * default distance is 1280. On a high density display, the default distance 19150 * is 1920.</p> 19151 * 19152 * <p>If you want to specify a distance that leads to visually consistent 19153 * results across various densities, use the following formula:</p> 19154 * <pre> 19155 * float scale = context.getResources().getDisplayMetrics().density; 19156 * view.setCameraDistance(distance * scale); 19157 * </pre> 19158 * 19159 * <p>The density scale factor of a high density display is 1.5, 19160 * and 1920 = 1280 * 1.5.</p> 19161 * 19162 * @param distance The distance in "depth pixels", if negative the opposite 19163 * value is used 19164 * 19165 * @see #setRotationX(float) 19166 * @see #setRotationY(float) 19167 */ setCameraDistance(float distance)19168 public void setCameraDistance(float distance) { 19169 final float dpi = mResources.getDisplayMetrics().densityDpi; 19170 19171 invalidateViewProperty(true, false); 19172 mRenderNode.setCameraDistance(Math.abs(distance) / dpi); 19173 invalidateViewProperty(false, false); 19174 19175 invalidateParentIfNeededAndWasQuickRejected(); 19176 } 19177 19178 /** 19179 * The degrees that the view is rotated around the pivot point. 19180 * 19181 * @see #setRotation(float) 19182 * @see #getPivotX() 19183 * @see #getPivotY() 19184 * 19185 * @return The degrees of rotation. 19186 */ 19187 @ViewDebug.ExportedProperty(category = "drawing") 19188 @InspectableProperty getRotation()19189 public float getRotation() { 19190 return mRenderNode.getRotationZ(); 19191 } 19192 19193 /** 19194 * Sets the degrees that the view is rotated around the pivot point. Increasing values 19195 * result in clockwise rotation. 19196 * 19197 * @param rotation The degrees of rotation. 19198 * 19199 * @see #getRotation() 19200 * @see #getPivotX() 19201 * @see #getPivotY() 19202 * @see #setRotationX(float) 19203 * @see #setRotationY(float) 19204 * 19205 * @attr ref android.R.styleable#View_rotation 19206 */ 19207 @RemotableViewMethod setRotation(float rotation)19208 public void setRotation(float rotation) { 19209 if (rotation != getRotation()) { 19210 // Double-invalidation is necessary to capture view's old and new areas 19211 invalidateViewProperty(true, false); 19212 mRenderNode.setRotationZ(rotation); 19213 invalidateViewProperty(false, true); 19214 19215 invalidateParentIfNeededAndWasQuickRejected(); 19216 notifySubtreeAccessibilityStateChangedIfNeeded(); 19217 } 19218 } 19219 19220 /** 19221 * The degrees that the view is rotated around the vertical axis through the pivot point. 19222 * 19223 * @see #getPivotX() 19224 * @see #getPivotY() 19225 * @see #setRotationY(float) 19226 * 19227 * @return The degrees of Y rotation. 19228 */ 19229 @ViewDebug.ExportedProperty(category = "drawing") 19230 @InspectableProperty getRotationY()19231 public float getRotationY() { 19232 return mRenderNode.getRotationY(); 19233 } 19234 19235 /** 19236 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 19237 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 19238 * down the y axis. 19239 * 19240 * When rotating large views, it is recommended to adjust the camera distance 19241 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 19242 * 19243 * @param rotationY The degrees of Y rotation. 19244 * 19245 * @see #getRotationY() 19246 * @see #getPivotX() 19247 * @see #getPivotY() 19248 * @see #setRotation(float) 19249 * @see #setRotationX(float) 19250 * @see #setCameraDistance(float) 19251 * 19252 * @attr ref android.R.styleable#View_rotationY 19253 */ 19254 @RemotableViewMethod setRotationY(float rotationY)19255 public void setRotationY(float rotationY) { 19256 if (rotationY != getRotationY()) { 19257 invalidateViewProperty(true, false); 19258 mRenderNode.setRotationY(rotationY); 19259 invalidateViewProperty(false, true); 19260 19261 invalidateParentIfNeededAndWasQuickRejected(); 19262 notifySubtreeAccessibilityStateChangedIfNeeded(); 19263 } 19264 } 19265 19266 /** 19267 * The degrees that the view is rotated around the horizontal axis through the pivot point. 19268 * 19269 * @see #getPivotX() 19270 * @see #getPivotY() 19271 * @see #setRotationX(float) 19272 * 19273 * @return The degrees of X rotation. 19274 */ 19275 @ViewDebug.ExportedProperty(category = "drawing") 19276 @InspectableProperty getRotationX()19277 public float getRotationX() { 19278 return mRenderNode.getRotationX(); 19279 } 19280 19281 /** 19282 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 19283 * Increasing values result in clockwise rotation from the viewpoint of looking down the 19284 * x axis. 19285 * 19286 * When rotating large views, it is recommended to adjust the camera distance 19287 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 19288 * 19289 * @param rotationX The degrees of X rotation. 19290 * 19291 * @see #getRotationX() 19292 * @see #getPivotX() 19293 * @see #getPivotY() 19294 * @see #setRotation(float) 19295 * @see #setRotationY(float) 19296 * @see #setCameraDistance(float) 19297 * 19298 * @attr ref android.R.styleable#View_rotationX 19299 */ 19300 @RemotableViewMethod setRotationX(float rotationX)19301 public void setRotationX(float rotationX) { 19302 if (rotationX != getRotationX()) { 19303 invalidateViewProperty(true, false); 19304 mRenderNode.setRotationX(rotationX); 19305 invalidateViewProperty(false, true); 19306 19307 invalidateParentIfNeededAndWasQuickRejected(); 19308 notifySubtreeAccessibilityStateChangedIfNeeded(); 19309 } 19310 } 19311 19312 /** 19313 * The amount that the view is scaled in x around the pivot point, as a proportion of 19314 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 19315 * 19316 * <p>By default, this is 1.0f. 19317 * 19318 * @see #getPivotX() 19319 * @see #getPivotY() 19320 * @return The scaling factor. 19321 */ 19322 @ViewDebug.ExportedProperty(category = "drawing") 19323 @InspectableProperty getScaleX()19324 public float getScaleX() { 19325 return mRenderNode.getScaleX(); 19326 } 19327 19328 /** 19329 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 19330 * the view's unscaled width. A value of 1 means that no scaling is applied. 19331 * 19332 * @param scaleX The scaling factor. 19333 * @see #getPivotX() 19334 * @see #getPivotY() 19335 * 19336 * @attr ref android.R.styleable#View_scaleX 19337 */ 19338 @RemotableViewMethod setScaleX(float scaleX)19339 public void setScaleX(float scaleX) { 19340 if (scaleX != getScaleX()) { 19341 scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX"); 19342 invalidateViewProperty(true, false); 19343 mRenderNode.setScaleX(scaleX); 19344 invalidateViewProperty(false, true); 19345 19346 invalidateParentIfNeededAndWasQuickRejected(); 19347 notifySubtreeAccessibilityStateChangedIfNeeded(); 19348 } 19349 } 19350 19351 /** 19352 * The amount that the view is scaled in y around the pivot point, as a proportion of 19353 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 19354 * 19355 * <p>By default, this is 1.0f. 19356 * 19357 * @see #getPivotX() 19358 * @see #getPivotY() 19359 * @return The scaling factor. 19360 */ 19361 @ViewDebug.ExportedProperty(category = "drawing") 19362 @InspectableProperty getScaleY()19363 public float getScaleY() { 19364 return mRenderNode.getScaleY(); 19365 } 19366 19367 /** 19368 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 19369 * the view's unscaled width. A value of 1 means that no scaling is applied. 19370 * 19371 * @param scaleY The scaling factor. 19372 * @see #getPivotX() 19373 * @see #getPivotY() 19374 * 19375 * @attr ref android.R.styleable#View_scaleY 19376 */ 19377 @RemotableViewMethod setScaleY(float scaleY)19378 public void setScaleY(float scaleY) { 19379 if (scaleY != getScaleY()) { 19380 scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY"); 19381 invalidateViewProperty(true, false); 19382 mRenderNode.setScaleY(scaleY); 19383 invalidateViewProperty(false, true); 19384 19385 invalidateParentIfNeededAndWasQuickRejected(); 19386 notifySubtreeAccessibilityStateChangedIfNeeded(); 19387 } 19388 } 19389 19390 /** 19391 * The x location of the point around which the view is {@link #setRotation(float) rotated} 19392 * and {@link #setScaleX(float) scaled}. 19393 * 19394 * @see #getRotation() 19395 * @see #getScaleX() 19396 * @see #getScaleY() 19397 * @see #getPivotY() 19398 * @return The x location of the pivot point. 19399 * 19400 * @attr ref android.R.styleable#View_transformPivotX 19401 */ 19402 @ViewDebug.ExportedProperty(category = "drawing") 19403 @InspectableProperty(name = "transformPivotX") getPivotX()19404 public float getPivotX() { 19405 return mRenderNode.getPivotX(); 19406 } 19407 19408 /** 19409 * Sets the x location of the point around which the view is 19410 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 19411 * By default, the pivot point is centered on the object. 19412 * Setting this property disables this behavior and causes the view to use only the 19413 * explicitly set pivotX and pivotY values. 19414 * 19415 * @param pivotX The x location of the pivot point. 19416 * @see #getRotation() 19417 * @see #getScaleX() 19418 * @see #getScaleY() 19419 * @see #getPivotY() 19420 * 19421 * @attr ref android.R.styleable#View_transformPivotX 19422 */ 19423 @RemotableViewMethod setPivotX(float pivotX)19424 public void setPivotX(float pivotX) { 19425 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 19426 invalidateViewProperty(true, false); 19427 mRenderNode.setPivotX(pivotX); 19428 invalidateViewProperty(false, true); 19429 19430 invalidateParentIfNeededAndWasQuickRejected(); 19431 } 19432 } 19433 19434 /** 19435 * The y location of the point around which the view is {@link #setRotation(float) rotated} 19436 * and {@link #setScaleY(float) scaled}. 19437 * 19438 * @see #getRotation() 19439 * @see #getScaleX() 19440 * @see #getScaleY() 19441 * @see #getPivotY() 19442 * @return The y location of the pivot point. 19443 * 19444 * @attr ref android.R.styleable#View_transformPivotY 19445 */ 19446 @ViewDebug.ExportedProperty(category = "drawing") 19447 @InspectableProperty(name = "transformPivotY") getPivotY()19448 public float getPivotY() { 19449 return mRenderNode.getPivotY(); 19450 } 19451 19452 /** 19453 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 19454 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 19455 * Setting this property disables this behavior and causes the view to use only the 19456 * explicitly set pivotX and pivotY values. 19457 * 19458 * @param pivotY The y location of the pivot point. 19459 * @see #getRotation() 19460 * @see #getScaleX() 19461 * @see #getScaleY() 19462 * @see #getPivotY() 19463 * 19464 * @attr ref android.R.styleable#View_transformPivotY 19465 */ 19466 @RemotableViewMethod setPivotY(float pivotY)19467 public void setPivotY(float pivotY) { 19468 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 19469 invalidateViewProperty(true, false); 19470 mRenderNode.setPivotY(pivotY); 19471 invalidateViewProperty(false, true); 19472 19473 invalidateParentIfNeededAndWasQuickRejected(); 19474 } 19475 } 19476 19477 /** 19478 * Returns whether or not a pivot has been set by a call to {@link #setPivotX(float)} or 19479 * {@link #setPivotY(float)}. If no pivot has been set then the pivot will be the center 19480 * of the view. 19481 * 19482 * @return True if a pivot has been set, false if the default pivot is being used 19483 */ isPivotSet()19484 public boolean isPivotSet() { 19485 return mRenderNode.isPivotExplicitlySet(); 19486 } 19487 19488 /** 19489 * Clears any pivot previously set by a call to {@link #setPivotX(float)} or 19490 * {@link #setPivotY(float)}. After calling this {@link #isPivotSet()} will be false 19491 * and the pivot used for rotation will return to default of being centered on the view. 19492 */ resetPivot()19493 public void resetPivot() { 19494 if (mRenderNode.resetPivot()) { 19495 invalidateViewProperty(false, false); 19496 } 19497 } 19498 19499 /** 19500 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 19501 * completely transparent and 1 means the view is completely opaque. 19502 * 19503 * <p>By default this is 1.0f. 19504 * @return The opacity of the view. 19505 */ 19506 @ViewDebug.ExportedProperty(category = "drawing") 19507 @InspectableProperty getAlpha()19508 public float getAlpha() { 19509 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 19510 } 19511 19512 /** 19513 * Sets the behavior for overlapping rendering for this view (see {@link 19514 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 19515 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 19516 * providing the value which is then used internally. That is, when {@link 19517 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 19518 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 19519 * instead. 19520 * 19521 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 19522 * instead of that returned by {@link #hasOverlappingRendering()}. 19523 * 19524 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 19525 */ forceHasOverlappingRendering(boolean hasOverlappingRendering)19526 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 19527 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 19528 if (hasOverlappingRendering) { 19529 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 19530 } else { 19531 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 19532 } 19533 } 19534 19535 /** 19536 * Returns the value for overlapping rendering that is used internally. This is either 19537 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 19538 * the return value of {@link #hasOverlappingRendering()}, otherwise. 19539 * 19540 * @return The value for overlapping rendering being used internally. 19541 */ getHasOverlappingRendering()19542 public final boolean getHasOverlappingRendering() { 19543 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 19544 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 19545 hasOverlappingRendering(); 19546 } 19547 19548 /** 19549 * Returns whether this View has content which overlaps. 19550 * 19551 * <p>This function, intended to be overridden by specific View types, is an optimization when 19552 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 19553 * an offscreen buffer and then composited into place, which can be expensive. If the view has 19554 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 19555 * directly. An example of overlapping rendering is a TextView with a background image, such as 19556 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 19557 * ImageView with only the foreground image. The default implementation returns true; subclasses 19558 * should override if they have cases which can be optimized.</p> 19559 * 19560 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 19561 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 19562 * 19563 * @return true if the content in this view might overlap, false otherwise. 19564 */ 19565 @ViewDebug.ExportedProperty(category = "drawing") hasOverlappingRendering()19566 public boolean hasOverlappingRendering() { 19567 return true; 19568 } 19569 19570 /** 19571 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 19572 * completely transparent and 1 means the view is completely opaque. 19573 * 19574 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 19575 * can have significant performance implications, especially for large views. It is best to use 19576 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 19577 * 19578 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 19579 * strongly recommended for performance reasons to either override 19580 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 19581 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 19582 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 19583 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 19584 * of rendering cost, even for simple or small views. Starting with 19585 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 19586 * applied to the view at the rendering level.</p> 19587 * 19588 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 19589 * responsible for applying the opacity itself.</p> 19590 * 19591 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 19592 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 19593 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 19594 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 19595 * 19596 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 19597 * value will clip a View to its bounds, unless the View returns <code>false</code> from 19598 * {@link #hasOverlappingRendering}.</p> 19599 * 19600 * @param alpha The opacity of the view. 19601 * 19602 * @see #hasOverlappingRendering() 19603 * @see #setLayerType(int, android.graphics.Paint) 19604 * 19605 * @attr ref android.R.styleable#View_alpha 19606 */ 19607 @RemotableViewMethod setAlpha(@loatRangefrom=0.0, to=1.0) float alpha)19608 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 19609 ensureTransformationInfo(); 19610 if (mTransformationInfo.mAlpha != alpha) { 19611 setAlphaInternal(alpha); 19612 if (onSetAlpha((int) (alpha * 255))) { 19613 mPrivateFlags |= PFLAG_ALPHA_SET; 19614 // subclass is handling alpha - don't optimize rendering cache invalidation 19615 invalidateParentCaches(); 19616 invalidate(true); 19617 } else { 19618 mPrivateFlags &= ~PFLAG_ALPHA_SET; 19619 invalidateViewProperty(true, false); 19620 mRenderNode.setAlpha(getFinalAlpha()); 19621 } 19622 } 19623 } 19624 19625 /** 19626 * Faster version of setAlpha() which performs the same steps except there are 19627 * no calls to invalidate(). The caller of this function should perform proper invalidation 19628 * on the parent and this object. The return value indicates whether the subclass handles 19629 * alpha (the return value for onSetAlpha()). 19630 * 19631 * @param alpha The new value for the alpha property 19632 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 19633 * the new value for the alpha property is different from the old value 19634 */ 19635 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768435) setAlphaNoInvalidation(float alpha)19636 boolean setAlphaNoInvalidation(float alpha) { 19637 ensureTransformationInfo(); 19638 if (mTransformationInfo.mAlpha != alpha) { 19639 setAlphaInternal(alpha); 19640 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 19641 if (subclassHandlesAlpha) { 19642 mPrivateFlags |= PFLAG_ALPHA_SET; 19643 return true; 19644 } else { 19645 mPrivateFlags &= ~PFLAG_ALPHA_SET; 19646 mRenderNode.setAlpha(getFinalAlpha()); 19647 } 19648 } 19649 return false; 19650 } 19651 setAlphaInternal(float alpha)19652 void setAlphaInternal(float alpha) { 19653 float oldAlpha = mTransformationInfo.mAlpha; 19654 mTransformationInfo.mAlpha = alpha; 19655 // Report visibility changes, which can affect children, to accessibility 19656 if ((alpha == 0) ^ (oldAlpha == 0)) { 19657 notifySubtreeAccessibilityStateChangedIfNeeded(); 19658 } 19659 } 19660 19661 /** 19662 * This property is intended only for use by the Fade transition, which animates it 19663 * to produce a visual translucency that does not side-effect (or get affected by) 19664 * the real alpha property. This value is composited with the other alpha value 19665 * (and the AlphaAnimation value, when that is present) to produce a final visual 19666 * translucency result, which is what is passed into the DisplayList. 19667 */ setTransitionAlpha(float alpha)19668 public void setTransitionAlpha(float alpha) { 19669 ensureTransformationInfo(); 19670 if (mTransformationInfo.mTransitionAlpha != alpha) { 19671 mTransformationInfo.mTransitionAlpha = alpha; 19672 mPrivateFlags &= ~PFLAG_ALPHA_SET; 19673 invalidateViewProperty(true, false); 19674 mRenderNode.setAlpha(getFinalAlpha()); 19675 } 19676 } 19677 19678 /** 19679 * Calculates the visual alpha of this view, which is a combination of the actual 19680 * alpha value and the transitionAlpha value (if set). 19681 */ getFinalAlpha()19682 private float getFinalAlpha() { 19683 if (mTransformationInfo != null) { 19684 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 19685 } 19686 return 1; 19687 } 19688 19689 /** 19690 * This property is intended only for use by the Fade transition, which animates 19691 * it to produce a visual translucency that does not side-effect (or get affected 19692 * by) the real alpha property. This value is composited with the other alpha 19693 * value (and the AlphaAnimation value, when that is present) to produce a final 19694 * visual translucency result, which is what is passed into the DisplayList. 19695 */ 19696 @ViewDebug.ExportedProperty(category = "drawing") getTransitionAlpha()19697 public float getTransitionAlpha() { 19698 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 19699 } 19700 19701 /** 19702 * Sets whether or not to allow force dark to apply to this view. 19703 * 19704 * Setting this to false will disable the auto-dark feature on everything this view 19705 * draws, including any descendants. 19706 * 19707 * Setting this to true will allow this view to be automatically made dark, however 19708 * a value of 'true' will not override any 'false' value in its parent chain nor will 19709 * it prevent any 'false' in any of its children. 19710 * 19711 * The default behavior of force dark is also influenced by the Theme's 19712 * {@link android.R.styleable#Theme_isLightTheme isLightTheme} attribute. 19713 * If a theme is isLightTheme="false", then force dark is globally disabled for that theme. 19714 * 19715 * @param allow Whether or not to allow force dark. 19716 */ setForceDarkAllowed(boolean allow)19717 public void setForceDarkAllowed(boolean allow) { 19718 if (mRenderNode.setForceDarkAllowed(allow)) { 19719 // Currently toggling force-dark requires a new display list push to apply 19720 // TODO: Make it not clobber the display list so this is just a damageSelf() instead 19721 invalidate(); 19722 } 19723 } 19724 19725 /** 19726 * See {@link #setForceDarkAllowed(boolean)} 19727 * 19728 * @return true if force dark is allowed (default), false if it is disabled 19729 */ 19730 @ViewDebug.ExportedProperty(category = "drawing") 19731 @InspectableProperty isForceDarkAllowed()19732 public boolean isForceDarkAllowed() { 19733 return mRenderNode.isForceDarkAllowed(); 19734 } 19735 19736 /** 19737 * Top position of this view relative to its parent. 19738 * 19739 * @return The top of this view, in pixels. 19740 */ 19741 @ViewDebug.CapturedViewProperty getTop()19742 public final int getTop() { 19743 return mTop; 19744 } 19745 19746 /** 19747 * Sets the top position of this view relative to its parent. This method is meant to be called 19748 * by the layout system and should not generally be called otherwise, because the property 19749 * may be changed at any time by the layout. 19750 * 19751 * @param top The top of this view, in pixels. 19752 */ setTop(int top)19753 public final void setTop(int top) { 19754 if (top != mTop) { 19755 final boolean matrixIsIdentity = hasIdentityMatrix(); 19756 if (matrixIsIdentity) { 19757 if (mAttachInfo != null) { 19758 int minTop; 19759 int yLoc; 19760 if (top < mTop) { 19761 minTop = top; 19762 yLoc = top - mTop; 19763 } else { 19764 minTop = mTop; 19765 yLoc = 0; 19766 } 19767 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 19768 } 19769 } else { 19770 // Double-invalidation is necessary to capture view's old and new areas 19771 invalidate(true); 19772 } 19773 19774 int width = mRight - mLeft; 19775 int oldHeight = mBottom - mTop; 19776 19777 mTop = top; 19778 mRenderNode.setTop(mTop); 19779 19780 sizeChange(width, mBottom - mTop, width, oldHeight); 19781 19782 if (!matrixIsIdentity) { 19783 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 19784 invalidate(true); 19785 } 19786 mBackgroundSizeChanged = true; 19787 mDefaultFocusHighlightSizeChanged = true; 19788 if (mForegroundInfo != null) { 19789 mForegroundInfo.mBoundsChanged = true; 19790 } 19791 invalidateParentIfNeeded(); 19792 } 19793 } 19794 19795 /** 19796 * Bottom position of this view relative to its parent. 19797 * 19798 * @return The bottom of this view, in pixels. 19799 */ 19800 @ViewDebug.CapturedViewProperty getBottom()19801 public final int getBottom() { 19802 return mBottom; 19803 } 19804 19805 /** 19806 * True if this view has changed since the last time being drawn. 19807 * 19808 * @return The dirty state of this view. 19809 */ isDirty()19810 public boolean isDirty() { 19811 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 19812 } 19813 19814 /** 19815 * Sets the bottom position of this view relative to its parent. This method is meant to be 19816 * called by the layout system and should not generally be called otherwise, because the 19817 * property may be changed at any time by the layout. 19818 * 19819 * @param bottom The bottom of this view, in pixels. 19820 */ setBottom(int bottom)19821 public final void setBottom(int bottom) { 19822 if (bottom != mBottom) { 19823 final boolean matrixIsIdentity = hasIdentityMatrix(); 19824 if (matrixIsIdentity) { 19825 if (mAttachInfo != null) { 19826 int maxBottom; 19827 if (bottom < mBottom) { 19828 maxBottom = mBottom; 19829 } else { 19830 maxBottom = bottom; 19831 } 19832 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 19833 } 19834 } else { 19835 // Double-invalidation is necessary to capture view's old and new areas 19836 invalidate(true); 19837 } 19838 19839 int width = mRight - mLeft; 19840 int oldHeight = mBottom - mTop; 19841 19842 mBottom = bottom; 19843 mRenderNode.setBottom(mBottom); 19844 19845 sizeChange(width, mBottom - mTop, width, oldHeight); 19846 19847 if (!matrixIsIdentity) { 19848 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 19849 invalidate(true); 19850 } 19851 mBackgroundSizeChanged = true; 19852 mDefaultFocusHighlightSizeChanged = true; 19853 if (mForegroundInfo != null) { 19854 mForegroundInfo.mBoundsChanged = true; 19855 } 19856 invalidateParentIfNeeded(); 19857 } 19858 } 19859 19860 /** 19861 * Left position of this view relative to its parent. 19862 * 19863 * @return The left edge of this view, in pixels. 19864 */ 19865 @ViewDebug.CapturedViewProperty getLeft()19866 public final int getLeft() { 19867 return mLeft; 19868 } 19869 19870 /** 19871 * Sets the left position of this view relative to its parent. This method is meant to be called 19872 * by the layout system and should not generally be called otherwise, because the property 19873 * may be changed at any time by the layout. 19874 * 19875 * @param left The left of this view, in pixels. 19876 */ setLeft(int left)19877 public final void setLeft(int left) { 19878 if (left != mLeft) { 19879 final boolean matrixIsIdentity = hasIdentityMatrix(); 19880 if (matrixIsIdentity) { 19881 if (mAttachInfo != null) { 19882 int minLeft; 19883 int xLoc; 19884 if (left < mLeft) { 19885 minLeft = left; 19886 xLoc = left - mLeft; 19887 } else { 19888 minLeft = mLeft; 19889 xLoc = 0; 19890 } 19891 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 19892 } 19893 } else { 19894 // Double-invalidation is necessary to capture view's old and new areas 19895 invalidate(true); 19896 } 19897 19898 int oldWidth = mRight - mLeft; 19899 int height = mBottom - mTop; 19900 19901 mLeft = left; 19902 mRenderNode.setLeft(left); 19903 19904 sizeChange(mRight - mLeft, height, oldWidth, height); 19905 19906 if (!matrixIsIdentity) { 19907 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 19908 invalidate(true); 19909 } 19910 mBackgroundSizeChanged = true; 19911 mDefaultFocusHighlightSizeChanged = true; 19912 if (mForegroundInfo != null) { 19913 mForegroundInfo.mBoundsChanged = true; 19914 } 19915 invalidateParentIfNeeded(); 19916 } 19917 } 19918 19919 /** 19920 * Right position of this view relative to its parent. 19921 * 19922 * @return The right edge of this view, in pixels. 19923 */ 19924 @ViewDebug.CapturedViewProperty getRight()19925 public final int getRight() { 19926 return mRight; 19927 } 19928 19929 /** 19930 * Sets the right position of this view relative to its parent. This method is meant to be called 19931 * by the layout system and should not generally be called otherwise, because the property 19932 * may be changed at any time by the layout. 19933 * 19934 * @param right The right of this view, in pixels. 19935 */ setRight(int right)19936 public final void setRight(int right) { 19937 if (right != mRight) { 19938 final boolean matrixIsIdentity = hasIdentityMatrix(); 19939 if (matrixIsIdentity) { 19940 if (mAttachInfo != null) { 19941 int maxRight; 19942 if (right < mRight) { 19943 maxRight = mRight; 19944 } else { 19945 maxRight = right; 19946 } 19947 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 19948 } 19949 } else { 19950 // Double-invalidation is necessary to capture view's old and new areas 19951 invalidate(true); 19952 } 19953 19954 int oldWidth = mRight - mLeft; 19955 int height = mBottom - mTop; 19956 19957 mRight = right; 19958 mRenderNode.setRight(mRight); 19959 19960 sizeChange(mRight - mLeft, height, oldWidth, height); 19961 19962 if (!matrixIsIdentity) { 19963 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 19964 invalidate(true); 19965 } 19966 mBackgroundSizeChanged = true; 19967 mDefaultFocusHighlightSizeChanged = true; 19968 if (mForegroundInfo != null) { 19969 mForegroundInfo.mBoundsChanged = true; 19970 } 19971 invalidateParentIfNeeded(); 19972 } 19973 } 19974 sanitizeFloatPropertyValue(float value, String propertyName)19975 private static float sanitizeFloatPropertyValue(float value, String propertyName) { 19976 return sanitizeFloatPropertyValue(value, propertyName, -Float.MAX_VALUE, Float.MAX_VALUE); 19977 } 19978 sanitizeFloatPropertyValue(float value, String propertyName, float min, float max)19979 private static float sanitizeFloatPropertyValue(float value, String propertyName, 19980 float min, float max) { 19981 // The expected "nothing bad happened" path 19982 if (value >= min && value <= max) return value; 19983 19984 if (value < min || value == Float.NEGATIVE_INFINITY) { 19985 if (sThrowOnInvalidFloatProperties) { 19986 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 19987 + value + ", the value must be >= " + min); 19988 } 19989 return min; 19990 } 19991 19992 if (value > max || value == Float.POSITIVE_INFINITY) { 19993 if (sThrowOnInvalidFloatProperties) { 19994 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 19995 + value + ", the value must be <= " + max); 19996 } 19997 return max; 19998 } 19999 20000 if (Float.isNaN(value)) { 20001 if (sThrowOnInvalidFloatProperties) { 20002 throw new IllegalArgumentException( 20003 "Cannot set '" + propertyName + "' to Float.NaN"); 20004 } 20005 return 0; // Unclear which direction this NaN went so... 0? 20006 } 20007 20008 // Shouldn't be possible to reach this. 20009 throw new IllegalStateException("How do you get here?? " + value); 20010 } 20011 20012 /** 20013 * The visual x position of this view, in pixels. This is equivalent to the 20014 * {@link #setTranslationX(float) translationX} property plus the current 20015 * {@link #getLeft() left} property. 20016 * 20017 * @return The visual x position of this view, in pixels. 20018 */ 20019 @ViewDebug.ExportedProperty(category = "drawing") getX()20020 public float getX() { 20021 return mLeft + getTranslationX(); 20022 } 20023 20024 /** 20025 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 20026 * {@link #setTranslationX(float) translationX} property to be the difference between 20027 * the x value passed in and the current {@link #getLeft() left} property. 20028 * 20029 * @param x The visual x position of this view, in pixels. 20030 */ setX(float x)20031 public void setX(float x) { 20032 setTranslationX(x - mLeft); 20033 } 20034 20035 /** 20036 * The visual y position of this view, in pixels. This is equivalent to the 20037 * {@link #setTranslationY(float) translationY} property plus the current 20038 * {@link #getTop() top} property. 20039 * 20040 * @return The visual y position of this view, in pixels. 20041 */ 20042 @ViewDebug.ExportedProperty(category = "drawing") getY()20043 public float getY() { 20044 return mTop + getTranslationY(); 20045 } 20046 20047 /** 20048 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 20049 * {@link #setTranslationY(float) translationY} property to be the difference between 20050 * the y value passed in and the current {@link #getTop() top} property. 20051 * 20052 * @param y The visual y position of this view, in pixels. 20053 */ setY(float y)20054 public void setY(float y) { 20055 setTranslationY(y - mTop); 20056 } 20057 20058 /** 20059 * The visual z position of this view, in pixels. This is equivalent to the 20060 * {@link #setTranslationZ(float) translationZ} property plus the current 20061 * {@link #getElevation() elevation} property. 20062 * 20063 * @return The visual z position of this view, in pixels. 20064 */ 20065 @ViewDebug.ExportedProperty(category = "drawing") getZ()20066 public float getZ() { 20067 return getElevation() + getTranslationZ(); 20068 } 20069 20070 /** 20071 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 20072 * {@link #setTranslationZ(float) translationZ} property to be the difference between 20073 * the z value passed in and the current {@link #getElevation() elevation} property. 20074 * 20075 * @param z The visual z position of this view, in pixels. 20076 */ setZ(float z)20077 public void setZ(float z) { 20078 setTranslationZ(z - getElevation()); 20079 } 20080 20081 /** 20082 * The base elevation of this view relative to its parent, in pixels. 20083 * 20084 * @return The base depth position of the view, in pixels. 20085 */ 20086 @ViewDebug.ExportedProperty(category = "drawing") 20087 @InspectableProperty getElevation()20088 public float getElevation() { 20089 return mRenderNode.getElevation(); 20090 } 20091 20092 /** 20093 * Sets the base elevation of this view, in pixels. 20094 * 20095 * @attr ref android.R.styleable#View_elevation 20096 */ 20097 @RemotableViewMethod setElevation(float elevation)20098 public void setElevation(float elevation) { 20099 if (elevation != getElevation()) { 20100 elevation = sanitizeFloatPropertyValue(elevation, "elevation"); 20101 invalidateViewProperty(true, false); 20102 mRenderNode.setElevation(elevation); 20103 invalidateViewProperty(false, true); 20104 20105 invalidateParentIfNeededAndWasQuickRejected(); 20106 } 20107 } 20108 20109 /** 20110 * The horizontal location of this view relative to its {@link #getLeft() left} position. 20111 * This position is post-layout, in addition to wherever the object's 20112 * layout placed it. 20113 * 20114 * @return The horizontal position of this view relative to its left position, in pixels. 20115 */ 20116 @ViewDebug.ExportedProperty(category = "drawing") 20117 @InspectableProperty getTranslationX()20118 public float getTranslationX() { 20119 return mRenderNode.getTranslationX(); 20120 } 20121 20122 /** 20123 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 20124 * This effectively positions the object post-layout, in addition to wherever the object's 20125 * layout placed it. 20126 * 20127 * @param translationX The horizontal position of this view relative to its left position, 20128 * in pixels. 20129 * 20130 * @attr ref android.R.styleable#View_translationX 20131 */ 20132 @RemotableViewMethod setTranslationX(float translationX)20133 public void setTranslationX(float translationX) { 20134 if (translationX != getTranslationX()) { 20135 mPrivateFlags4 |= PFLAG4_HAS_MOVED; 20136 invalidateViewProperty(true, false); 20137 mRenderNode.setTranslationX(translationX); 20138 invalidateViewProperty(false, true); 20139 20140 invalidateParentIfNeededAndWasQuickRejected(); 20141 notifySubtreeAccessibilityStateChangedIfNeeded(); 20142 } 20143 } 20144 20145 /** 20146 * The vertical location of this view relative to its {@link #getTop() top} position. 20147 * This position is post-layout, in addition to wherever the object's 20148 * layout placed it. 20149 * 20150 * @return The vertical position of this view relative to its top position, 20151 * in pixels. 20152 */ 20153 @ViewDebug.ExportedProperty(category = "drawing") 20154 @InspectableProperty getTranslationY()20155 public float getTranslationY() { 20156 return mRenderNode.getTranslationY(); 20157 } 20158 20159 /** 20160 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 20161 * This effectively positions the object post-layout, in addition to wherever the object's 20162 * layout placed it. 20163 * 20164 * @param translationY The vertical position of this view relative to its top position, 20165 * in pixels. 20166 * 20167 * @attr ref android.R.styleable#View_translationY 20168 */ 20169 @RemotableViewMethod setTranslationY(float translationY)20170 public void setTranslationY(float translationY) { 20171 if (translationY != getTranslationY()) { 20172 mPrivateFlags4 |= PFLAG4_HAS_MOVED; 20173 invalidateViewProperty(true, false); 20174 mRenderNode.setTranslationY(translationY); 20175 invalidateViewProperty(false, true); 20176 20177 invalidateParentIfNeededAndWasQuickRejected(); 20178 notifySubtreeAccessibilityStateChangedIfNeeded(); 20179 } 20180 } 20181 20182 /** 20183 * The depth location of this view relative to its {@link #getElevation() elevation}. 20184 * 20185 * @return The depth of this view relative to its elevation. 20186 */ 20187 @ViewDebug.ExportedProperty(category = "drawing") 20188 @InspectableProperty getTranslationZ()20189 public float getTranslationZ() { 20190 return mRenderNode.getTranslationZ(); 20191 } 20192 20193 /** 20194 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 20195 * 20196 * @attr ref android.R.styleable#View_translationZ 20197 */ 20198 @RemotableViewMethod setTranslationZ(float translationZ)20199 public void setTranslationZ(float translationZ) { 20200 if (translationZ != getTranslationZ()) { 20201 translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ"); 20202 invalidateViewProperty(true, false); 20203 mRenderNode.setTranslationZ(translationZ); 20204 invalidateViewProperty(false, true); 20205 20206 invalidateParentIfNeededAndWasQuickRejected(); 20207 } 20208 } 20209 20210 /** 20211 * Changes the transformation matrix on the view. This is used in animation frameworks, 20212 * such as {@link android.transition.Transition}. When the animation finishes, the matrix 20213 * should be cleared by calling this method with <code>null</code> as the matrix parameter. 20214 * Application developers should use transformation methods like {@link #setRotation(float)}, 20215 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 20216 * and {@link #setTranslationY(float)} (float)}} instead. 20217 * 20218 * @param matrix The matrix, null indicates that the matrix should be cleared. 20219 * @see #getAnimationMatrix() 20220 */ setAnimationMatrix(@ullable Matrix matrix)20221 public void setAnimationMatrix(@Nullable Matrix matrix) { 20222 invalidateViewProperty(true, false); 20223 mRenderNode.setAnimationMatrix(matrix); 20224 invalidateViewProperty(false, true); 20225 20226 invalidateParentIfNeededAndWasQuickRejected(); 20227 } 20228 20229 /** 20230 * Return the current transformation matrix of the view. This is used in animation frameworks, 20231 * such as {@link android.transition.Transition}. Returns <code>null</code> when there is no 20232 * transformation provided by {@link #setAnimationMatrix(Matrix)}. 20233 * Application developers should use transformation methods like {@link #setRotation(float)}, 20234 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 20235 * and {@link #setTranslationY(float)} (float)}} instead. 20236 * 20237 * @return the Matrix, null indicates there is no transformation 20238 * @see #setAnimationMatrix(Matrix) 20239 */ 20240 @Nullable getAnimationMatrix()20241 public Matrix getAnimationMatrix() { 20242 return mRenderNode.getAnimationMatrix(); 20243 } 20244 20245 /** 20246 * Returns the current StateListAnimator if exists. 20247 * 20248 * @return StateListAnimator or null if it does not exists 20249 * @see #setStateListAnimator(android.animation.StateListAnimator) 20250 */ 20251 @InspectableProperty getStateListAnimator()20252 public StateListAnimator getStateListAnimator() { 20253 return mStateListAnimator; 20254 } 20255 20256 /** 20257 * Attaches the provided StateListAnimator to this View. 20258 * <p> 20259 * Any previously attached StateListAnimator will be detached. 20260 * 20261 * @param stateListAnimator The StateListAnimator to update the view 20262 * @see android.animation.StateListAnimator 20263 */ setStateListAnimator(StateListAnimator stateListAnimator)20264 public void setStateListAnimator(StateListAnimator stateListAnimator) { 20265 if (mStateListAnimator == stateListAnimator) { 20266 return; 20267 } 20268 if (mStateListAnimator != null) { 20269 mStateListAnimator.setTarget(null); 20270 } 20271 mStateListAnimator = stateListAnimator; 20272 if (stateListAnimator != null) { 20273 stateListAnimator.setTarget(this); 20274 if (isAttachedToWindow()) { 20275 stateListAnimator.setState(getDrawableState()); 20276 } 20277 } 20278 } 20279 20280 /** 20281 * Returns whether the Outline should be used to clip the contents of the View. 20282 * <p> 20283 * Note that this flag will only be respected if the View's Outline returns true from 20284 * {@link Outline#canClip()}. 20285 * 20286 * @see #setOutlineProvider(ViewOutlineProvider) 20287 * @see #setClipToOutline(boolean) 20288 */ getClipToOutline()20289 public final boolean getClipToOutline() { 20290 return mRenderNode.getClipToOutline(); 20291 } 20292 20293 /** 20294 * Sets whether the View's Outline should be used to clip the contents of the View. 20295 * <p> 20296 * Only a single non-rectangular clip can be applied on a View at any time. 20297 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 20298 * circular reveal} animation take priority over Outline clipping, and 20299 * child Outline clipping takes priority over Outline clipping done by a 20300 * parent. 20301 * <p> 20302 * Note that this flag will only be respected if the View's Outline returns true from 20303 * {@link Outline#canClip()}. 20304 * 20305 * @see #setOutlineProvider(ViewOutlineProvider) 20306 * @see #getClipToOutline() 20307 * 20308 * @attr ref android.R.styleable#View_clipToOutline 20309 */ 20310 @RemotableViewMethod setClipToOutline(boolean clipToOutline)20311 public void setClipToOutline(boolean clipToOutline) { 20312 damageInParent(); 20313 if (getClipToOutline() != clipToOutline) { 20314 mRenderNode.setClipToOutline(clipToOutline); 20315 } 20316 } 20317 20318 // correspond to the enum values of View_outlineProvider 20319 private static final int PROVIDER_BACKGROUND = 0; 20320 private static final int PROVIDER_NONE = 1; 20321 private static final int PROVIDER_BOUNDS = 2; 20322 private static final int PROVIDER_PADDED_BOUNDS = 3; setOutlineProviderFromAttribute(int providerInt)20323 private void setOutlineProviderFromAttribute(int providerInt) { 20324 switch (providerInt) { 20325 case PROVIDER_BACKGROUND: 20326 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 20327 break; 20328 case PROVIDER_NONE: 20329 setOutlineProvider(null); 20330 break; 20331 case PROVIDER_BOUNDS: 20332 setOutlineProvider(ViewOutlineProvider.BOUNDS); 20333 break; 20334 case PROVIDER_PADDED_BOUNDS: 20335 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 20336 break; 20337 } 20338 } 20339 20340 /** 20341 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 20342 * the shape of the shadow it casts, and enables outline clipping. 20343 * <p> 20344 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 20345 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 20346 * outline provider with this method allows this behavior to be overridden. 20347 * <p> 20348 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 20349 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 20350 * <p> 20351 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 20352 * 20353 * @see #setClipToOutline(boolean) 20354 * @see #getClipToOutline() 20355 * @see #getOutlineProvider() 20356 */ setOutlineProvider(ViewOutlineProvider provider)20357 public void setOutlineProvider(ViewOutlineProvider provider) { 20358 if (mOutlineProvider != provider) { 20359 mOutlineProvider = provider; 20360 invalidateOutline(); 20361 } 20362 } 20363 20364 /** 20365 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 20366 * that defines the shape of the shadow it casts, and enables outline clipping. 20367 * 20368 * @see #setOutlineProvider(ViewOutlineProvider) 20369 */ 20370 @InspectableProperty getOutlineProvider()20371 public ViewOutlineProvider getOutlineProvider() { 20372 return mOutlineProvider; 20373 } 20374 20375 /** 20376 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 20377 * 20378 * @see #setOutlineProvider(ViewOutlineProvider) 20379 */ invalidateOutline()20380 public void invalidateOutline() { 20381 rebuildOutline(); 20382 20383 notifySubtreeAccessibilityStateChangedIfNeeded(); 20384 invalidateViewProperty(false, false); 20385 } 20386 20387 /** 20388 * Internal version of {@link #invalidateOutline()} which invalidates the 20389 * outline without invalidating the view itself. This is intended to be called from 20390 * within methods in the View class itself which are the result of the view being 20391 * invalidated already. For example, when we are drawing the background of a View, 20392 * we invalidate the outline in case it changed in the meantime, but we do not 20393 * need to invalidate the view because we're already drawing the background as part 20394 * of drawing the view in response to an earlier invalidation of the view. 20395 */ rebuildOutline()20396 private void rebuildOutline() { 20397 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 20398 if (mAttachInfo == null) return; 20399 20400 if (mOutlineProvider == null) { 20401 // no provider, remove outline 20402 mRenderNode.setOutline(null); 20403 } else { 20404 final Outline outline = mAttachInfo.mTmpOutline; 20405 outline.setEmpty(); 20406 outline.setAlpha(1.0f); 20407 20408 mOutlineProvider.getOutline(this, outline); 20409 mRenderNode.setOutline(outline); 20410 } 20411 } 20412 20413 /** 20414 * HierarchyViewer only 20415 * 20416 * @hide 20417 */ 20418 @ViewDebug.ExportedProperty(category = "drawing") hasShadow()20419 public boolean hasShadow() { 20420 return mRenderNode.hasShadow(); 20421 } 20422 20423 /** 20424 * Sets the color of the spot shadow that is drawn when the view has a positive Z or 20425 * elevation value. 20426 * <p> 20427 * By default the shadow color is black. Generally, this color will be opaque so the intensity 20428 * of the shadow is consistent between different views with different colors. 20429 * <p> 20430 * The opacity of the final spot shadow is a function of the shadow caster height, the 20431 * alpha channel of the outlineSpotShadowColor (typically opaque), and the 20432 * {@link android.R.attr#spotShadowAlpha} theme attribute. 20433 * 20434 * @attr ref android.R.styleable#View_outlineSpotShadowColor 20435 * @param color The color this View will cast for its elevation spot shadow. 20436 */ setOutlineSpotShadowColor(@olorInt int color)20437 public void setOutlineSpotShadowColor(@ColorInt int color) { 20438 if (mRenderNode.setSpotShadowColor(color)) { 20439 invalidateViewProperty(true, true); 20440 } 20441 } 20442 20443 /** 20444 * @return The shadow color set by {@link #setOutlineSpotShadowColor(int)}, or black if nothing 20445 * was set 20446 */ 20447 @InspectableProperty getOutlineSpotShadowColor()20448 public @ColorInt int getOutlineSpotShadowColor() { 20449 return mRenderNode.getSpotShadowColor(); 20450 } 20451 20452 /** 20453 * Sets the color of the ambient shadow that is drawn when the view has a positive Z or 20454 * elevation value. 20455 * <p> 20456 * By default the shadow color is black. Generally, this color will be opaque so the intensity 20457 * of the shadow is consistent between different views with different colors. 20458 * <p> 20459 * The opacity of the final ambient shadow is a function of the shadow caster height, the 20460 * alpha channel of the outlineAmbientShadowColor (typically opaque), and the 20461 * {@link android.R.attr#ambientShadowAlpha} theme attribute. 20462 * 20463 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 20464 * @param color The color this View will cast for its elevation shadow. 20465 */ setOutlineAmbientShadowColor(@olorInt int color)20466 public void setOutlineAmbientShadowColor(@ColorInt int color) { 20467 if (mRenderNode.setAmbientShadowColor(color)) { 20468 invalidateViewProperty(true, true); 20469 } 20470 } 20471 20472 /** 20473 * @return The shadow color set by {@link #setOutlineAmbientShadowColor(int)}, or black if 20474 * nothing was set 20475 */ 20476 @InspectableProperty getOutlineAmbientShadowColor()20477 public @ColorInt int getOutlineAmbientShadowColor() { 20478 return mRenderNode.getAmbientShadowColor(); 20479 } 20480 20481 20482 /** @hide */ setRevealClip(boolean shouldClip, float x, float y, float radius)20483 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 20484 mRenderNode.setRevealClip(shouldClip, x, y, radius); 20485 invalidateViewProperty(false, false); 20486 } 20487 20488 /** 20489 * Hit rectangle in parent's coordinates 20490 * 20491 * @param outRect The hit rectangle of the view. 20492 */ getHitRect(Rect outRect)20493 public void getHitRect(Rect outRect) { 20494 if (hasIdentityMatrix() || mAttachInfo == null) { 20495 outRect.set(mLeft, mTop, mRight, mBottom); 20496 } else { 20497 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 20498 tmpRect.set(0, 0, getWidth(), getHeight()); 20499 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 20500 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 20501 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 20502 } 20503 } 20504 20505 /** 20506 * Determines whether the given point, in local coordinates is inside the view. 20507 */ pointInView(float localX, float localY)20508 /*package*/ final boolean pointInView(float localX, float localY) { 20509 return pointInView(localX, localY, 0); 20510 } 20511 20512 /** 20513 * Utility method to determine whether the given point, in local coordinates, 20514 * is inside the view, where the area of the view is expanded by the slop factor. 20515 * This method is called while processing touch-move events to determine if the event 20516 * is still within the view. 20517 * 20518 * @hide 20519 */ 20520 @UnsupportedAppUsage pointInView(float localX, float localY, float slop)20521 public boolean pointInView(float localX, float localY, float slop) { 20522 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 20523 localY < ((mBottom - mTop) + slop); 20524 } 20525 20526 /** 20527 * When a view has focus and the user navigates away from it, the next view is searched for 20528 * starting from the rectangle filled in by this method. 20529 * 20530 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 20531 * of the view. However, if your view maintains some idea of internal selection, 20532 * such as a cursor, or a selected row or column, you should override this method and 20533 * fill in a more specific rectangle. 20534 * 20535 * @param r The rectangle to fill in, in this view's coordinates. 20536 */ getFocusedRect(Rect r)20537 public void getFocusedRect(Rect r) { 20538 getDrawingRect(r); 20539 } 20540 20541 /** 20542 * Sets {@code r} to the coordinates of the non-clipped area of this view in 20543 * the coordinate space of the view's root view. Sets {@code globalOffset} 20544 * to the offset of the view's x and y coordinates from the coordinate space 20545 * origin, which is the top left corner of the root view irrespective of 20546 * screen decorations and system UI elements. 20547 * 20548 * <p>To convert {@code r} to coordinates relative to the top left corner of 20549 * this view (without taking view rotations into account), offset {@code r} 20550 * by the inverse values of 20551 * {@code globalOffset}—{@code r.offset(-globalOffset.x, 20552 * -globalOffset.y)}—which is equivalent to calling 20553 * {@link #getLocalVisibleRect(Rect) getLocalVisibleRect(Rect)}. 20554 * 20555 * <p><b>Note:</b> Do not use this method to determine the size of a window 20556 * in multi-window mode; use 20557 * {@link WindowManager#getCurrentWindowMetrics()}. 20558 * 20559 * @param r If the method returns true, contains the coordinates of the 20560 * visible portion of this view in the coordinate space of the view's 20561 * root view. If the method returns false, the contents of {@code r} 20562 * are undefined. 20563 * @param globalOffset If the method returns true, contains the offset of 20564 * the x and y coordinates of this view from the top left corner of the 20565 * view's root view. If the method returns false, the contents of 20566 * {@code globalOffset} are undefined. The argument can be null (see 20567 * {@link #getGlobalVisibleRect(Rect) getGlobalVisibleRect(Rect)}. 20568 * @return true if at least part of the view is visible within the root 20569 * view; false if the view is completely clipped or translated out of 20570 * the visible area of the root view. 20571 * 20572 * @see #getLocalVisibleRect(Rect) 20573 */ getGlobalVisibleRect(Rect r, Point globalOffset)20574 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 20575 int width = mRight - mLeft; 20576 int height = mBottom - mTop; 20577 if (width > 0 && height > 0) { 20578 r.set(0, 0, width, height); 20579 if (globalOffset != null) { 20580 globalOffset.set(-mScrollX, -mScrollY); 20581 } 20582 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 20583 } 20584 return false; 20585 } 20586 20587 /** 20588 * Sets {@code r} to the coordinates of the non-clipped area of this view in 20589 * the coordinate space of the view's root view. 20590 * 20591 * <p>See {@link #getGlobalVisibleRect(Rect, Point) 20592 * getGlobalVisibleRect(Rect, Point)} for more information. 20593 * 20594 * @param r If the method returns true, contains the coordinates of the 20595 * visible portion of this view in the coordinate space of the view's 20596 * root view. If the method returns false, the contents of {@code r} 20597 * are undefined. 20598 * @return true if at least part of the view is visible within the root 20599 * view; otherwise false. 20600 */ getGlobalVisibleRect(Rect r)20601 public final boolean getGlobalVisibleRect(Rect r) { 20602 return getGlobalVisibleRect(r, null); 20603 } 20604 20605 /** 20606 * Sets {@code r} to the coordinates of the non-clipped area of this view 20607 * relative to the top left corner of the view. 20608 * 20609 * <p>If the view is clipped on the left or top, the left and top 20610 * coordinates are offset from 0 by the clipped amount. For example, if the 20611 * view is off screen 50px on the left and 30px at the top, the left and top 20612 * coordinates are 50 and 30 respectively. 20613 * 20614 * <p>If the view is clipped on the right or bottom, the right and bottom 20615 * coordinates are reduced by the clipped amount. For example, if the view 20616 * is off screen 40px on the right and 20px at the bottom, the right 20617 * coordinate is the view width - 40, and the bottom coordinate is the view 20618 * height - 20. 20619 * 20620 * @param r If the method returns true, contains the coordinates of the 20621 * visible portion of this view relative to the top left corner of the 20622 * view. If the method returns false, the contents of {@code r} are 20623 * undefined. 20624 * @return true if at least part of the view is visible; false if the view 20625 * is completely clipped or translated out of the visible area. 20626 * 20627 * @see #getGlobalVisibleRect(Rect, Point) 20628 */ getLocalVisibleRect(Rect r)20629 public final boolean getLocalVisibleRect(Rect r) { 20630 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 20631 if (getGlobalVisibleRect(r, offset)) { 20632 r.offset(-offset.x, -offset.y); // make r local 20633 return true; 20634 } 20635 return false; 20636 } 20637 20638 /** 20639 * Offset this view's vertical location by the specified number of pixels. 20640 * 20641 * @param offset the number of pixels to offset the view by 20642 */ offsetTopAndBottom(int offset)20643 public void offsetTopAndBottom(int offset) { 20644 if (offset != 0) { 20645 final boolean matrixIsIdentity = hasIdentityMatrix(); 20646 if (matrixIsIdentity) { 20647 if (isHardwareAccelerated()) { 20648 invalidateViewProperty(false, false); 20649 } else { 20650 final ViewParent p = mParent; 20651 if (p != null && mAttachInfo != null) { 20652 final Rect r = mAttachInfo.mTmpInvalRect; 20653 int minTop; 20654 int maxBottom; 20655 int yLoc; 20656 if (offset < 0) { 20657 minTop = mTop + offset; 20658 maxBottom = mBottom; 20659 yLoc = offset; 20660 } else { 20661 minTop = mTop; 20662 maxBottom = mBottom + offset; 20663 yLoc = 0; 20664 } 20665 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 20666 p.invalidateChild(this, r); 20667 } 20668 } 20669 } else { 20670 invalidateViewProperty(false, false); 20671 } 20672 20673 mTop += offset; 20674 mBottom += offset; 20675 mRenderNode.offsetTopAndBottom(offset); 20676 if (isHardwareAccelerated()) { 20677 invalidateViewProperty(false, false); 20678 invalidateParentIfNeededAndWasQuickRejected(); 20679 } else { 20680 if (!matrixIsIdentity) { 20681 invalidateViewProperty(false, true); 20682 } 20683 invalidateParentIfNeeded(); 20684 } 20685 notifySubtreeAccessibilityStateChangedIfNeeded(); 20686 } 20687 } 20688 20689 /** 20690 * Offset this view's horizontal location by the specified amount of pixels. 20691 * 20692 * @param offset the number of pixels to offset the view by 20693 */ offsetLeftAndRight(int offset)20694 public void offsetLeftAndRight(int offset) { 20695 if (offset != 0) { 20696 final boolean matrixIsIdentity = hasIdentityMatrix(); 20697 if (matrixIsIdentity) { 20698 if (isHardwareAccelerated()) { 20699 invalidateViewProperty(false, false); 20700 } else { 20701 final ViewParent p = mParent; 20702 if (p != null && mAttachInfo != null) { 20703 final Rect r = mAttachInfo.mTmpInvalRect; 20704 int minLeft; 20705 int maxRight; 20706 if (offset < 0) { 20707 minLeft = mLeft + offset; 20708 maxRight = mRight; 20709 } else { 20710 minLeft = mLeft; 20711 maxRight = mRight + offset; 20712 } 20713 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 20714 p.invalidateChild(this, r); 20715 } 20716 } 20717 } else { 20718 invalidateViewProperty(false, false); 20719 } 20720 20721 mLeft += offset; 20722 mRight += offset; 20723 mRenderNode.offsetLeftAndRight(offset); 20724 if (isHardwareAccelerated()) { 20725 invalidateViewProperty(false, false); 20726 invalidateParentIfNeededAndWasQuickRejected(); 20727 } else { 20728 if (!matrixIsIdentity) { 20729 invalidateViewProperty(false, true); 20730 } 20731 invalidateParentIfNeeded(); 20732 } 20733 notifySubtreeAccessibilityStateChangedIfNeeded(); 20734 } 20735 } 20736 20737 /** 20738 * Get the LayoutParams associated with this view. All views should have 20739 * layout parameters. These supply parameters to the <i>parent</i> of this 20740 * view specifying how it should be arranged. There are many subclasses of 20741 * ViewGroup.LayoutParams, and these correspond to the different subclasses 20742 * of ViewGroup that are responsible for arranging their children. 20743 * 20744 * This method may return null if this View is not attached to a parent 20745 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 20746 * was not invoked successfully. When a View is attached to a parent 20747 * ViewGroup, this method must not return null. 20748 * 20749 * @return The LayoutParams associated with this view, or null if no 20750 * parameters have been set yet 20751 */ 20752 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") getLayoutParams()20753 public ViewGroup.LayoutParams getLayoutParams() { 20754 return mLayoutParams; 20755 } 20756 20757 /** 20758 * Set the layout parameters associated with this view. These supply 20759 * parameters to the <i>parent</i> of this view specifying how it should be 20760 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 20761 * correspond to the different subclasses of ViewGroup that are responsible 20762 * for arranging their children. 20763 * 20764 * @param params The layout parameters for this view, cannot be null 20765 */ setLayoutParams(ViewGroup.LayoutParams params)20766 public void setLayoutParams(ViewGroup.LayoutParams params) { 20767 if (params == null) { 20768 throw new NullPointerException("Layout parameters cannot be null"); 20769 } 20770 mLayoutParams = params; 20771 resolveLayoutParams(); 20772 if (mParent instanceof ViewGroup) { 20773 ((ViewGroup) mParent).onSetLayoutParams(this, params); 20774 } 20775 requestLayout(); 20776 } 20777 20778 /** 20779 * Resolve the layout parameters depending on the resolved layout direction 20780 * 20781 * @hide 20782 */ resolveLayoutParams()20783 public void resolveLayoutParams() { 20784 if (mLayoutParams != null) { 20785 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 20786 } 20787 } 20788 20789 /** 20790 * Set the scrolled position of your view. This will cause a call to 20791 * {@link #onScrollChanged(int, int, int, int)} and the view will be 20792 * invalidated. 20793 * @param x the x position to scroll to 20794 * @param y the y position to scroll to 20795 */ scrollTo(int x, int y)20796 public void scrollTo(int x, int y) { 20797 if (mScrollX != x || mScrollY != y) { 20798 int oldX = mScrollX; 20799 int oldY = mScrollY; 20800 mScrollX = x; 20801 mScrollY = y; 20802 invalidateParentCaches(); 20803 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 20804 if (!awakenScrollBars()) { 20805 postInvalidateOnAnimation(); 20806 } 20807 } 20808 } 20809 20810 /** 20811 * Move the scrolled position of your view. This will cause a call to 20812 * {@link #onScrollChanged(int, int, int, int)} and the view will be 20813 * invalidated. 20814 * @param x the amount of pixels to scroll by horizontally 20815 * @param y the amount of pixels to scroll by vertically 20816 */ scrollBy(int x, int y)20817 public void scrollBy(int x, int y) { 20818 scrollTo(mScrollX + x, mScrollY + y); 20819 } 20820 20821 /** 20822 * <p>Trigger the scrollbars to draw. When invoked this method starts an 20823 * animation to fade the scrollbars out after a default delay. If a subclass 20824 * provides animated scrolling, the start delay should equal the duration 20825 * of the scrolling animation.</p> 20826 * 20827 * <p>The animation starts only if at least one of the scrollbars is 20828 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 20829 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 20830 * this method returns true, and false otherwise. If the animation is 20831 * started, this method calls {@link #invalidate()}; in that case the 20832 * caller should not call {@link #invalidate()}.</p> 20833 * 20834 * <p>This method should be invoked every time a subclass directly updates 20835 * the scroll parameters.</p> 20836 * 20837 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 20838 * and {@link #scrollTo(int, int)}.</p> 20839 * 20840 * @return true if the animation is played, false otherwise 20841 * 20842 * @see #awakenScrollBars(int) 20843 * @see #scrollBy(int, int) 20844 * @see #scrollTo(int, int) 20845 * @see #isHorizontalScrollBarEnabled() 20846 * @see #isVerticalScrollBarEnabled() 20847 * @see #setHorizontalScrollBarEnabled(boolean) 20848 * @see #setVerticalScrollBarEnabled(boolean) 20849 */ awakenScrollBars()20850 protected boolean awakenScrollBars() { 20851 return mScrollCache != null && 20852 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 20853 } 20854 20855 /** 20856 * Trigger the scrollbars to draw. 20857 * This method differs from awakenScrollBars() only in its default duration. 20858 * initialAwakenScrollBars() will show the scroll bars for longer than 20859 * usual to give the user more of a chance to notice them. 20860 * 20861 * @return true if the animation is played, false otherwise. 20862 */ initialAwakenScrollBars()20863 private boolean initialAwakenScrollBars() { 20864 return mScrollCache != null && 20865 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 20866 } 20867 20868 /** 20869 * <p> 20870 * Trigger the scrollbars to draw. When invoked this method starts an 20871 * animation to fade the scrollbars out after a fixed delay. If a subclass 20872 * provides animated scrolling, the start delay should equal the duration of 20873 * the scrolling animation. 20874 * </p> 20875 * 20876 * <p> 20877 * The animation starts only if at least one of the scrollbars is enabled, 20878 * as specified by {@link #isHorizontalScrollBarEnabled()} and 20879 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 20880 * this method returns true, and false otherwise. If the animation is 20881 * started, this method calls {@link #invalidate()}; in that case the caller 20882 * should not call {@link #invalidate()}. 20883 * </p> 20884 * 20885 * <p> 20886 * This method should be invoked every time a subclass directly updates the 20887 * scroll parameters. 20888 * </p> 20889 * 20890 * @param startDelay the delay, in milliseconds, after which the animation 20891 * should start; when the delay is 0, the animation starts 20892 * immediately 20893 * @return true if the animation is played, false otherwise 20894 * 20895 * @see #scrollBy(int, int) 20896 * @see #scrollTo(int, int) 20897 * @see #isHorizontalScrollBarEnabled() 20898 * @see #isVerticalScrollBarEnabled() 20899 * @see #setHorizontalScrollBarEnabled(boolean) 20900 * @see #setVerticalScrollBarEnabled(boolean) 20901 */ awakenScrollBars(int startDelay)20902 protected boolean awakenScrollBars(int startDelay) { 20903 return awakenScrollBars(startDelay, true); 20904 } 20905 20906 /** 20907 * <p> 20908 * Trigger the scrollbars to draw. When invoked this method starts an 20909 * animation to fade the scrollbars out after a fixed delay. If a subclass 20910 * provides animated scrolling, the start delay should equal the duration of 20911 * the scrolling animation. 20912 * </p> 20913 * 20914 * <p> 20915 * The animation starts only if at least one of the scrollbars is enabled, 20916 * as specified by {@link #isHorizontalScrollBarEnabled()} and 20917 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 20918 * this method returns true, and false otherwise. If the animation is 20919 * started, this method calls {@link #invalidate()} if the invalidate parameter 20920 * is set to true; in that case the caller 20921 * should not call {@link #invalidate()}. 20922 * </p> 20923 * 20924 * <p> 20925 * This method should be invoked every time a subclass directly updates the 20926 * scroll parameters. 20927 * </p> 20928 * 20929 * @param startDelay the delay, in milliseconds, after which the animation 20930 * should start; when the delay is 0, the animation starts 20931 * immediately 20932 * 20933 * @param invalidate Whether this method should call invalidate 20934 * 20935 * @return true if the animation is played, false otherwise 20936 * 20937 * @see #scrollBy(int, int) 20938 * @see #scrollTo(int, int) 20939 * @see #isHorizontalScrollBarEnabled() 20940 * @see #isVerticalScrollBarEnabled() 20941 * @see #setHorizontalScrollBarEnabled(boolean) 20942 * @see #setVerticalScrollBarEnabled(boolean) 20943 */ awakenScrollBars(int startDelay, boolean invalidate)20944 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 20945 final ScrollabilityCache scrollCache = mScrollCache; 20946 20947 if (scrollCache == null || !scrollCache.fadeScrollBars) { 20948 return false; 20949 } 20950 20951 if (scrollCache.scrollBar == null) { 20952 scrollCache.scrollBar = new ScrollBarDrawable(); 20953 scrollCache.scrollBar.setState(getDrawableState()); 20954 scrollCache.scrollBar.setCallback(this); 20955 } 20956 20957 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 20958 20959 if (invalidate) { 20960 // Invalidate to show the scrollbars 20961 postInvalidateOnAnimation(); 20962 } 20963 20964 if (scrollCache.state == ScrollabilityCache.OFF) { 20965 // FIXME: this is copied from WindowManagerService. 20966 // We should get this value from the system when it 20967 // is possible to do so. 20968 final int KEY_REPEAT_FIRST_DELAY = 750; 20969 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 20970 } 20971 20972 // Tell mScrollCache when we should start fading. This may 20973 // extend the fade start time if one was already scheduled 20974 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 20975 scrollCache.fadeStartTime = fadeStartTime; 20976 scrollCache.state = ScrollabilityCache.ON; 20977 20978 // Schedule our fader to run, unscheduling any old ones first 20979 if (mAttachInfo != null) { 20980 mAttachInfo.mHandler.removeCallbacks(scrollCache); 20981 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 20982 } 20983 20984 return true; 20985 } 20986 20987 return false; 20988 } 20989 20990 /** 20991 * Do not invalidate views which are not visible and which are not running an animation. They 20992 * will not get drawn and they should not set dirty flags as if they will be drawn 20993 */ skipInvalidate()20994 private boolean skipInvalidate() { 20995 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 20996 (!(mParent instanceof ViewGroup) || 20997 !((ViewGroup) mParent).isViewTransitioning(this)); 20998 } 20999 21000 /** 21001 * Mark the area defined by dirty as needing to be drawn. If the view is 21002 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 21003 * point in the future. 21004 * <p> 21005 * This must be called from a UI thread. To call from a non-UI thread, call 21006 * {@link #postInvalidate()}. 21007 * <p> 21008 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 21009 * {@code dirty}. 21010 * 21011 * @param dirty the rectangle representing the bounds of the dirty region 21012 * 21013 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 21014 * the importance of the dirty rectangle. In API 21 the given rectangle is 21015 * ignored entirely in favor of an internally-calculated area instead. 21016 * Because of this, clients are encouraged to just call {@link #invalidate()}. 21017 */ 21018 @Deprecated invalidate(Rect dirty)21019 public void invalidate(Rect dirty) { 21020 final int scrollX = mScrollX; 21021 final int scrollY = mScrollY; 21022 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 21023 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 21024 } 21025 21026 /** 21027 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 21028 * coordinates of the dirty rect are relative to the view. If the view is 21029 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 21030 * point in the future. 21031 * <p> 21032 * This must be called from a UI thread. To call from a non-UI thread, call 21033 * {@link #postInvalidate()}. 21034 * 21035 * @param l the left position of the dirty region 21036 * @param t the top position of the dirty region 21037 * @param r the right position of the dirty region 21038 * @param b the bottom position of the dirty region 21039 * 21040 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 21041 * the importance of the dirty rectangle. In API 21 the given rectangle is 21042 * ignored entirely in favor of an internally-calculated area instead. 21043 * Because of this, clients are encouraged to just call {@link #invalidate()}. 21044 */ 21045 @Deprecated invalidate(int l, int t, int r, int b)21046 public void invalidate(int l, int t, int r, int b) { 21047 final int scrollX = mScrollX; 21048 final int scrollY = mScrollY; 21049 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 21050 } 21051 21052 /** 21053 * Invalidate the whole view. If the view is visible, 21054 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 21055 * the future. 21056 * <p> 21057 * This must be called from a UI thread. To call from a non-UI thread, call 21058 * {@link #postInvalidate()}. 21059 */ invalidate()21060 public void invalidate() { 21061 invalidate(true); 21062 } 21063 21064 /** 21065 * This is where the invalidate() work actually happens. A full invalidate() 21066 * causes the drawing cache to be invalidated, but this function can be 21067 * called with invalidateCache set to false to skip that invalidation step 21068 * for cases that do not need it (for example, a component that remains at 21069 * the same dimensions with the same content). 21070 * 21071 * @param invalidateCache Whether the drawing cache for this view should be 21072 * invalidated as well. This is usually true for a full 21073 * invalidate, but may be set to false if the View's contents or 21074 * dimensions have not changed. 21075 * @hide 21076 */ 21077 @UnsupportedAppUsage invalidate(boolean invalidateCache)21078 public void invalidate(boolean invalidateCache) { 21079 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 21080 } 21081 invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate)21082 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 21083 boolean fullInvalidate) { 21084 if (mGhostView != null) { 21085 mGhostView.invalidate(true); 21086 return; 21087 } 21088 21089 if (skipInvalidate()) { 21090 return; 21091 } 21092 21093 // Reset content capture caches 21094 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; 21095 mContentCaptureSessionCached = false; 21096 21097 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 21098 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 21099 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 21100 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 21101 if (fullInvalidate) { 21102 mLastIsOpaque = isOpaque(); 21103 mPrivateFlags &= ~PFLAG_DRAWN; 21104 } 21105 21106 mPrivateFlags |= PFLAG_DIRTY; 21107 21108 if (invalidateCache) { 21109 mPrivateFlags |= PFLAG_INVALIDATED; 21110 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 21111 } 21112 21113 // Propagate the damage rectangle to the parent view. 21114 final AttachInfo ai = mAttachInfo; 21115 final ViewParent p = mParent; 21116 if (p != null && ai != null && l < r && t < b) { 21117 final Rect damage = ai.mTmpInvalRect; 21118 damage.set(l, t, r, b); 21119 p.invalidateChild(this, damage); 21120 } 21121 21122 // Damage the entire projection receiver, if necessary. 21123 if (mBackground != null && mBackground.isProjected()) { 21124 final View receiver = getProjectionReceiver(); 21125 if (receiver != null) { 21126 receiver.damageInParent(); 21127 } 21128 } 21129 } 21130 } 21131 21132 /** 21133 * @return this view's projection receiver, or {@code null} if none exists 21134 */ getProjectionReceiver()21135 private View getProjectionReceiver() { 21136 ViewParent p = getParent(); 21137 while (p != null && p instanceof View) { 21138 final View v = (View) p; 21139 if (v.isProjectionReceiver()) { 21140 return v; 21141 } 21142 p = p.getParent(); 21143 } 21144 21145 return null; 21146 } 21147 21148 /** 21149 * @return whether the view is a projection receiver 21150 */ isProjectionReceiver()21151 private boolean isProjectionReceiver() { 21152 return mBackground != null; 21153 } 21154 21155 /** 21156 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 21157 * set any flags or handle all of the cases handled by the default invalidation methods. 21158 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 21159 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 21160 * walk up the hierarchy, transforming the dirty rect as necessary. 21161 * 21162 * The method also handles normal invalidation logic if display list properties are not 21163 * being used in this view. The invalidateParent and forceRedraw flags are used by that 21164 * backup approach, to handle these cases used in the various property-setting methods. 21165 * 21166 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 21167 * are not being used in this view 21168 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 21169 * list properties are not being used in this view 21170 */ 21171 @UnsupportedAppUsage invalidateViewProperty(boolean invalidateParent, boolean forceRedraw)21172 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 21173 if (!isHardwareAccelerated() 21174 || !mRenderNode.hasDisplayList() 21175 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 21176 if (invalidateParent) { 21177 invalidateParentCaches(); 21178 } 21179 if (forceRedraw) { 21180 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 21181 } 21182 invalidate(false); 21183 } else { 21184 damageInParent(); 21185 } 21186 mPrivateFlags4 |= PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION; 21187 } 21188 21189 /** 21190 * Tells the parent view to damage this view's bounds. 21191 * 21192 * @hide 21193 */ damageInParent()21194 protected void damageInParent() { 21195 if (mParent != null && mAttachInfo != null) { 21196 mParent.onDescendantInvalidated(this, this); 21197 } 21198 } 21199 21200 /** 21201 * Used to indicate that the parent of this view should clear its caches. This functionality 21202 * is used to force the parent to rebuild its display list (when hardware-accelerated), 21203 * which is necessary when various parent-managed properties of the view change, such as 21204 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 21205 * clears the parent caches and does not causes an invalidate event. 21206 * 21207 * @hide 21208 */ 21209 @UnsupportedAppUsage invalidateParentCaches()21210 protected void invalidateParentCaches() { 21211 if (mParent instanceof View) { 21212 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 21213 } 21214 } 21215 21216 /** 21217 * Used to indicate that the parent of this view should be invalidated. This functionality 21218 * is used to force the parent to rebuild its display list (when hardware-accelerated), 21219 * which is necessary when various parent-managed properties of the view change, such as 21220 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 21221 * an invalidation event to the parent. 21222 * 21223 * @hide 21224 */ 21225 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) invalidateParentIfNeeded()21226 protected void invalidateParentIfNeeded() { 21227 if (isHardwareAccelerated() && mParent instanceof View) { 21228 ((View) mParent).invalidate(true); 21229 } 21230 } 21231 21232 /** 21233 * @hide 21234 */ invalidateParentIfNeededAndWasQuickRejected()21235 protected void invalidateParentIfNeededAndWasQuickRejected() { 21236 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 21237 // View was rejected last time it was drawn by its parent; this may have changed 21238 invalidateParentIfNeeded(); 21239 } 21240 } 21241 21242 /** 21243 * Indicates whether this View is opaque. An opaque View guarantees that it will 21244 * draw all the pixels overlapping its bounds using a fully opaque color. 21245 * 21246 * Subclasses of View should override this method whenever possible to indicate 21247 * whether an instance is opaque. Opaque Views are treated in a special way by 21248 * the View hierarchy, possibly allowing it to perform optimizations during 21249 * invalidate/draw passes. 21250 * 21251 * @return True if this View is guaranteed to be fully opaque, false otherwise. 21252 */ 21253 @ViewDebug.ExportedProperty(category = "drawing") isOpaque()21254 public boolean isOpaque() { 21255 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 21256 getFinalAlpha() >= 1.0f; 21257 } 21258 21259 /** 21260 * @hide 21261 */ 21262 @UnsupportedAppUsage computeOpaqueFlags()21263 protected void computeOpaqueFlags() { 21264 // Opaque if: 21265 // - Has a background 21266 // - Background is opaque 21267 // - Doesn't have scrollbars or scrollbars overlay 21268 21269 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 21270 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 21271 } else { 21272 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 21273 } 21274 21275 final int flags = mViewFlags; 21276 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 21277 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 21278 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 21279 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 21280 } else { 21281 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 21282 } 21283 } 21284 21285 /** 21286 * @hide 21287 */ hasOpaqueScrollbars()21288 protected boolean hasOpaqueScrollbars() { 21289 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 21290 } 21291 21292 /** 21293 * @return A handler associated with the thread running the View. This 21294 * handler can be used to pump events in the UI events queue. 21295 */ getHandler()21296 public Handler getHandler() { 21297 final AttachInfo attachInfo = mAttachInfo; 21298 if (attachInfo != null) { 21299 return attachInfo.mHandler; 21300 } 21301 return null; 21302 } 21303 21304 /** 21305 * Returns the queue of runnable for this view. 21306 * 21307 * @return the queue of runnables for this view 21308 */ getRunQueue()21309 private HandlerActionQueue getRunQueue() { 21310 if (mRunQueue == null) { 21311 mRunQueue = new HandlerActionQueue(); 21312 } 21313 return mRunQueue; 21314 } 21315 21316 /** 21317 * Gets the view root associated with the View. 21318 * @return The view root, or null if none. 21319 * @hide 21320 */ 21321 @UnsupportedAppUsage getViewRootImpl()21322 public ViewRootImpl getViewRootImpl() { 21323 if (mAttachInfo != null) { 21324 return mAttachInfo.mViewRootImpl; 21325 } 21326 return null; 21327 } 21328 21329 /** 21330 * @hide 21331 */ 21332 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getThreadedRenderer()21333 public ThreadedRenderer getThreadedRenderer() { 21334 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 21335 } 21336 21337 /** 21338 * <p>Causes the Runnable to be added to the message queue. 21339 * The runnable will be run on the user interface thread.</p> 21340 * 21341 * @param action The Runnable that will be executed. 21342 * 21343 * @return Returns true if the Runnable was successfully placed in to the 21344 * message queue. Returns false on failure, usually because the 21345 * looper processing the message queue is exiting. 21346 * 21347 * @see #postDelayed 21348 * @see #removeCallbacks 21349 */ post(Runnable action)21350 public boolean post(Runnable action) { 21351 final AttachInfo attachInfo = mAttachInfo; 21352 if (attachInfo != null) { 21353 return attachInfo.mHandler.post(action); 21354 } 21355 21356 // Postpone the runnable until we know on which thread it needs to run. 21357 // Assume that the runnable will be successfully placed after attach. 21358 getRunQueue().post(action); 21359 return true; 21360 } 21361 21362 /** 21363 * <p>Causes the Runnable to be added to the message queue, to be run 21364 * after the specified amount of time elapses. 21365 * The runnable will be run on the user interface thread.</p> 21366 * 21367 * @param action The Runnable that will be executed. 21368 * @param delayMillis The delay (in milliseconds) until the Runnable 21369 * will be executed. 21370 * 21371 * @return true if the Runnable was successfully placed in to the 21372 * message queue. Returns false on failure, usually because the 21373 * looper processing the message queue is exiting. Note that a 21374 * result of true does not mean the Runnable will be processed -- 21375 * if the looper is quit before the delivery time of the message 21376 * occurs then the message will be dropped. 21377 * 21378 * @see #post 21379 * @see #removeCallbacks 21380 */ postDelayed(Runnable action, long delayMillis)21381 public boolean postDelayed(Runnable action, long delayMillis) { 21382 final AttachInfo attachInfo = mAttachInfo; 21383 if (attachInfo != null) { 21384 return attachInfo.mHandler.postDelayed(action, delayMillis); 21385 } 21386 21387 // Postpone the runnable until we know on which thread it needs to run. 21388 // Assume that the runnable will be successfully placed after attach. 21389 getRunQueue().postDelayed(action, delayMillis); 21390 return true; 21391 } 21392 21393 /** 21394 * <p>Causes the Runnable to execute on the next animation time step. 21395 * The runnable will be run on the user interface thread.</p> 21396 * 21397 * @param action The Runnable that will be executed. 21398 * 21399 * @see #postOnAnimationDelayed 21400 * @see #removeCallbacks 21401 */ postOnAnimation(Runnable action)21402 public void postOnAnimation(Runnable action) { 21403 final AttachInfo attachInfo = mAttachInfo; 21404 if (attachInfo != null) { 21405 attachInfo.mViewRootImpl.mChoreographer.postCallback( 21406 Choreographer.CALLBACK_ANIMATION, action, null); 21407 } else { 21408 // Postpone the runnable until we know 21409 // on which thread it needs to run. 21410 getRunQueue().post(action); 21411 } 21412 } 21413 21414 /** 21415 * <p>Causes the Runnable to execute on the next animation time step, 21416 * after the specified amount of time elapses. 21417 * The runnable will be run on the user interface thread.</p> 21418 * 21419 * @param action The Runnable that will be executed. 21420 * @param delayMillis The delay (in milliseconds) until the Runnable 21421 * will be executed. 21422 * 21423 * @see #postOnAnimation 21424 * @see #removeCallbacks 21425 */ postOnAnimationDelayed(Runnable action, long delayMillis)21426 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 21427 final AttachInfo attachInfo = mAttachInfo; 21428 if (attachInfo != null) { 21429 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 21430 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 21431 } else { 21432 // Postpone the runnable until we know 21433 // on which thread it needs to run. 21434 getRunQueue().postDelayed(action, delayMillis); 21435 } 21436 } 21437 21438 /** 21439 * <p>Removes the specified Runnable from the message queue.</p> 21440 * 21441 * @param action The Runnable to remove from the message handling queue 21442 * 21443 * @return true if this view could ask the Handler to remove the Runnable, 21444 * false otherwise. When the returned value is true, the Runnable 21445 * may or may not have been actually removed from the message queue 21446 * (for instance, if the Runnable was not in the queue already.) 21447 * 21448 * @see #post 21449 * @see #postDelayed 21450 * @see #postOnAnimation 21451 * @see #postOnAnimationDelayed 21452 */ removeCallbacks(Runnable action)21453 public boolean removeCallbacks(Runnable action) { 21454 if (action != null) { 21455 final AttachInfo attachInfo = mAttachInfo; 21456 if (attachInfo != null) { 21457 attachInfo.mHandler.removeCallbacks(action); 21458 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 21459 Choreographer.CALLBACK_ANIMATION, action, null); 21460 } 21461 getRunQueue().removeCallbacks(action); 21462 } 21463 return true; 21464 } 21465 21466 /** 21467 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 21468 * Use this to invalidate the View from a non-UI thread.</p> 21469 * 21470 * <p>This method can be invoked from outside of the UI thread 21471 * only when this View is attached to a window.</p> 21472 * 21473 * @see #invalidate() 21474 * @see #postInvalidateDelayed(long) 21475 */ postInvalidate()21476 public void postInvalidate() { 21477 postInvalidateDelayed(0); 21478 } 21479 21480 /** 21481 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 21482 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 21483 * 21484 * <p>This method can be invoked from outside of the UI thread 21485 * only when this View is attached to a window.</p> 21486 * 21487 * @param left The left coordinate of the rectangle to invalidate. 21488 * @param top The top coordinate of the rectangle to invalidate. 21489 * @param right The right coordinate of the rectangle to invalidate. 21490 * @param bottom The bottom coordinate of the rectangle to invalidate. 21491 * 21492 * @see #invalidate(int, int, int, int) 21493 * @see #invalidate(Rect) 21494 * @see #postInvalidateDelayed(long, int, int, int, int) 21495 */ postInvalidate(int left, int top, int right, int bottom)21496 public void postInvalidate(int left, int top, int right, int bottom) { 21497 postInvalidateDelayed(0, left, top, right, bottom); 21498 } 21499 21500 /** 21501 * <p>Cause an invalidate to happen on a subsequent cycle through the event 21502 * loop. Waits for the specified amount of time.</p> 21503 * 21504 * <p>This method can be invoked from outside of the UI thread 21505 * only when this View is attached to a window.</p> 21506 * 21507 * @param delayMilliseconds the duration in milliseconds to delay the 21508 * invalidation by 21509 * 21510 * @see #invalidate() 21511 * @see #postInvalidate() 21512 */ postInvalidateDelayed(long delayMilliseconds)21513 public void postInvalidateDelayed(long delayMilliseconds) { 21514 // We try only with the AttachInfo because there's no point in invalidating 21515 // if we are not attached to our window 21516 final AttachInfo attachInfo = mAttachInfo; 21517 if (attachInfo != null) { 21518 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 21519 } 21520 } 21521 21522 /** 21523 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 21524 * through the event loop. Waits for the specified amount of time.</p> 21525 * 21526 * <p>This method can be invoked from outside of the UI thread 21527 * only when this View is attached to a window.</p> 21528 * 21529 * @param delayMilliseconds the duration in milliseconds to delay the 21530 * invalidation by 21531 * @param left The left coordinate of the rectangle to invalidate. 21532 * @param top The top coordinate of the rectangle to invalidate. 21533 * @param right The right coordinate of the rectangle to invalidate. 21534 * @param bottom The bottom coordinate of the rectangle to invalidate. 21535 * 21536 * @see #invalidate(int, int, int, int) 21537 * @see #invalidate(Rect) 21538 * @see #postInvalidate(int, int, int, int) 21539 */ postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom)21540 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 21541 int right, int bottom) { 21542 21543 // We try only with the AttachInfo because there's no point in invalidating 21544 // if we are not attached to our window 21545 final AttachInfo attachInfo = mAttachInfo; 21546 if (attachInfo != null) { 21547 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 21548 info.target = this; 21549 info.left = left; 21550 info.top = top; 21551 info.right = right; 21552 info.bottom = bottom; 21553 21554 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 21555 } 21556 } 21557 21558 /** 21559 * <p>Cause an invalidate to happen on the next animation time step, typically the 21560 * next display frame.</p> 21561 * 21562 * <p>This method can be invoked from outside of the UI thread 21563 * only when this View is attached to a window.</p> 21564 * 21565 * @see #invalidate() 21566 */ postInvalidateOnAnimation()21567 public void postInvalidateOnAnimation() { 21568 // We try only with the AttachInfo because there's no point in invalidating 21569 // if we are not attached to our window 21570 final AttachInfo attachInfo = mAttachInfo; 21571 if (attachInfo != null) { 21572 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 21573 } 21574 } 21575 21576 /** 21577 * <p>Cause an invalidate of the specified area to happen on the next animation 21578 * time step, typically the next display frame.</p> 21579 * 21580 * <p>This method can be invoked from outside of the UI thread 21581 * only when this View is attached to a window.</p> 21582 * 21583 * @param left The left coordinate of the rectangle to invalidate. 21584 * @param top The top coordinate of the rectangle to invalidate. 21585 * @param right The right coordinate of the rectangle to invalidate. 21586 * @param bottom The bottom coordinate of the rectangle to invalidate. 21587 * 21588 * @see #invalidate(int, int, int, int) 21589 * @see #invalidate(Rect) 21590 */ postInvalidateOnAnimation(int left, int top, int right, int bottom)21591 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 21592 // We try only with the AttachInfo because there's no point in invalidating 21593 // if we are not attached to our window 21594 final AttachInfo attachInfo = mAttachInfo; 21595 if (attachInfo != null) { 21596 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 21597 info.target = this; 21598 info.left = left; 21599 info.top = top; 21600 info.right = right; 21601 info.bottom = bottom; 21602 21603 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 21604 } 21605 } 21606 21607 /** 21608 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 21609 * This event is sent at most once every 21610 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 21611 */ postSendViewScrolledAccessibilityEventCallback(int dx, int dy)21612 private void postSendViewScrolledAccessibilityEventCallback(int dx, int dy) { 21613 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 21614 AccessibilityEvent event = 21615 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED); 21616 event.setScrollDeltaX(dx); 21617 event.setScrollDeltaY(dy); 21618 sendAccessibilityEventUnchecked(event); 21619 } 21620 } 21621 21622 /** 21623 * Called by a parent to request that a child update its values for mScrollX 21624 * and mScrollY if necessary. This will typically be done if the child is 21625 * animating a scroll using a {@link android.widget.Scroller Scroller} 21626 * object. 21627 */ computeScroll()21628 public void computeScroll() { 21629 } 21630 21631 /** 21632 * <p>Indicate whether the horizontal edges are faded when the view is 21633 * scrolled horizontally.</p> 21634 * 21635 * @return true if the horizontal edges should are faded on scroll, false 21636 * otherwise 21637 * 21638 * @see #setHorizontalFadingEdgeEnabled(boolean) 21639 * 21640 * @attr ref android.R.styleable#View_requiresFadingEdge 21641 */ isHorizontalFadingEdgeEnabled()21642 public boolean isHorizontalFadingEdgeEnabled() { 21643 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 21644 } 21645 21646 /** 21647 * <p>Define whether the horizontal edges should be faded when this view 21648 * is scrolled horizontally.</p> 21649 * 21650 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 21651 * be faded when the view is scrolled 21652 * horizontally 21653 * 21654 * @see #isHorizontalFadingEdgeEnabled() 21655 * 21656 * @attr ref android.R.styleable#View_requiresFadingEdge 21657 */ setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled)21658 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 21659 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 21660 if (horizontalFadingEdgeEnabled) { 21661 initScrollCache(); 21662 } 21663 21664 mViewFlags ^= FADING_EDGE_HORIZONTAL; 21665 } 21666 } 21667 21668 /** 21669 * <p>Indicate whether the vertical edges are faded when the view is 21670 * scrolled horizontally.</p> 21671 * 21672 * @return true if the vertical edges should are faded on scroll, false 21673 * otherwise 21674 * 21675 * @see #setVerticalFadingEdgeEnabled(boolean) 21676 * 21677 * @attr ref android.R.styleable#View_requiresFadingEdge 21678 */ isVerticalFadingEdgeEnabled()21679 public boolean isVerticalFadingEdgeEnabled() { 21680 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 21681 } 21682 21683 /** 21684 * <p>Define whether the vertical edges should be faded when this view 21685 * is scrolled vertically.</p> 21686 * 21687 * @param verticalFadingEdgeEnabled true if the vertical edges should 21688 * be faded when the view is scrolled 21689 * vertically 21690 * 21691 * @see #isVerticalFadingEdgeEnabled() 21692 * 21693 * @attr ref android.R.styleable#View_requiresFadingEdge 21694 */ setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled)21695 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 21696 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 21697 if (verticalFadingEdgeEnabled) { 21698 initScrollCache(); 21699 } 21700 21701 mViewFlags ^= FADING_EDGE_VERTICAL; 21702 } 21703 } 21704 21705 /** 21706 * Get the fading edge flags, used for inspection. 21707 * 21708 * @return One of {@link #FADING_EDGE_NONE}, {@link #FADING_EDGE_VERTICAL}, 21709 * or {@link #FADING_EDGE_HORIZONTAL} 21710 * @hide 21711 */ 21712 @InspectableProperty(name = "requiresFadingEdge", flagMapping = { 21713 @FlagEntry(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"), 21714 @FlagEntry(target = FADING_EDGE_VERTICAL, name = "vertical"), 21715 @FlagEntry(target = FADING_EDGE_HORIZONTAL, name = "horizontal") 21716 }) getFadingEdge()21717 public int getFadingEdge() { 21718 return mViewFlags & FADING_EDGE_MASK; 21719 } 21720 21721 /** 21722 * Get the fading edge length, used for inspection 21723 * 21724 * @return The fading edge length or 0 21725 * @hide 21726 */ 21727 @InspectableProperty getFadingEdgeLength()21728 public int getFadingEdgeLength() { 21729 if (mScrollCache != null && (mViewFlags & FADING_EDGE_MASK) != FADING_EDGE_NONE) { 21730 return mScrollCache.fadingEdgeLength; 21731 } 21732 return 0; 21733 } 21734 21735 /** 21736 * Returns the strength, or intensity, of the top faded edge. The strength is 21737 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 21738 * returns 0.0 or 1.0 but no value in between. 21739 * 21740 * Subclasses should override this method to provide a smoother fade transition 21741 * when scrolling occurs. 21742 * 21743 * @return the intensity of the top fade as a float between 0.0f and 1.0f 21744 */ getTopFadingEdgeStrength()21745 protected float getTopFadingEdgeStrength() { 21746 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 21747 } 21748 21749 /** 21750 * Returns the strength, or intensity, of the bottom faded edge. The strength is 21751 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 21752 * returns 0.0 or 1.0 but no value in between. 21753 * 21754 * Subclasses should override this method to provide a smoother fade transition 21755 * when scrolling occurs. 21756 * 21757 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 21758 */ getBottomFadingEdgeStrength()21759 protected float getBottomFadingEdgeStrength() { 21760 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 21761 computeVerticalScrollRange() ? 1.0f : 0.0f; 21762 } 21763 21764 /** 21765 * Returns the strength, or intensity, of the left faded edge. The strength is 21766 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 21767 * returns 0.0 or 1.0 but no value in between. 21768 * 21769 * Subclasses should override this method to provide a smoother fade transition 21770 * when scrolling occurs. 21771 * 21772 * @return the intensity of the left fade as a float between 0.0f and 1.0f 21773 */ getLeftFadingEdgeStrength()21774 protected float getLeftFadingEdgeStrength() { 21775 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 21776 } 21777 21778 /** 21779 * Returns the strength, or intensity, of the right faded edge. The strength is 21780 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 21781 * returns 0.0 or 1.0 but no value in between. 21782 * 21783 * Subclasses should override this method to provide a smoother fade transition 21784 * when scrolling occurs. 21785 * 21786 * @return the intensity of the right fade as a float between 0.0f and 1.0f 21787 */ getRightFadingEdgeStrength()21788 protected float getRightFadingEdgeStrength() { 21789 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 21790 computeHorizontalScrollRange() ? 1.0f : 0.0f; 21791 } 21792 21793 /** 21794 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 21795 * scrollbar is not drawn by default.</p> 21796 * 21797 * @return true if the horizontal scrollbar should be painted, false 21798 * otherwise 21799 * 21800 * @see #setHorizontalScrollBarEnabled(boolean) 21801 */ isHorizontalScrollBarEnabled()21802 public boolean isHorizontalScrollBarEnabled() { 21803 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 21804 } 21805 21806 /** 21807 * <p>Define whether the horizontal scrollbar should be drawn or not. The 21808 * scrollbar is not drawn by default.</p> 21809 * 21810 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 21811 * be painted 21812 * 21813 * @see #isHorizontalScrollBarEnabled() 21814 */ setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled)21815 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 21816 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 21817 mViewFlags ^= SCROLLBARS_HORIZONTAL; 21818 computeOpaqueFlags(); 21819 resolvePadding(); 21820 } 21821 } 21822 21823 /** 21824 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 21825 * scrollbar is not drawn by default.</p> 21826 * 21827 * @return true if the vertical scrollbar should be painted, false 21828 * otherwise 21829 * 21830 * @see #setVerticalScrollBarEnabled(boolean) 21831 */ isVerticalScrollBarEnabled()21832 public boolean isVerticalScrollBarEnabled() { 21833 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 21834 } 21835 21836 /** 21837 * <p>Define whether the vertical scrollbar should be drawn or not. The 21838 * scrollbar is not drawn by default.</p> 21839 * 21840 * @param verticalScrollBarEnabled true if the vertical scrollbar should 21841 * be painted 21842 * 21843 * @see #isVerticalScrollBarEnabled() 21844 */ setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled)21845 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 21846 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 21847 mViewFlags ^= SCROLLBARS_VERTICAL; 21848 computeOpaqueFlags(); 21849 resolvePadding(); 21850 } 21851 } 21852 21853 /** 21854 * @hide 21855 */ 21856 @UnsupportedAppUsage recomputePadding()21857 protected void recomputePadding() { 21858 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 21859 } 21860 21861 /** 21862 * Define whether scrollbars will fade when the view is not scrolling. 21863 * 21864 * @param fadeScrollbars whether to enable fading 21865 * 21866 * @attr ref android.R.styleable#View_fadeScrollbars 21867 */ setScrollbarFadingEnabled(boolean fadeScrollbars)21868 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 21869 initScrollCache(); 21870 final ScrollabilityCache scrollabilityCache = mScrollCache; 21871 scrollabilityCache.fadeScrollBars = fadeScrollbars; 21872 if (fadeScrollbars) { 21873 scrollabilityCache.state = ScrollabilityCache.OFF; 21874 } else { 21875 scrollabilityCache.state = ScrollabilityCache.ON; 21876 } 21877 } 21878 21879 /** 21880 * 21881 * Returns true if scrollbars will fade when this view is not scrolling 21882 * 21883 * @return true if scrollbar fading is enabled 21884 * 21885 * @attr ref android.R.styleable#View_fadeScrollbars 21886 */ isScrollbarFadingEnabled()21887 public boolean isScrollbarFadingEnabled() { 21888 return mScrollCache != null && mScrollCache.fadeScrollBars; 21889 } 21890 21891 /** 21892 * 21893 * Returns the delay before scrollbars fade. 21894 * 21895 * @return the delay before scrollbars fade 21896 * 21897 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 21898 */ 21899 @InspectableProperty(name = "scrollbarDefaultDelayBeforeFade") getScrollBarDefaultDelayBeforeFade()21900 public int getScrollBarDefaultDelayBeforeFade() { 21901 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 21902 mScrollCache.scrollBarDefaultDelayBeforeFade; 21903 } 21904 21905 /** 21906 * Define the delay before scrollbars fade. 21907 * 21908 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 21909 * 21910 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 21911 */ setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade)21912 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 21913 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 21914 } 21915 21916 /** 21917 * 21918 * Returns the scrollbar fade duration. 21919 * 21920 * @return the scrollbar fade duration, in milliseconds 21921 * 21922 * @attr ref android.R.styleable#View_scrollbarFadeDuration 21923 */ 21924 @InspectableProperty(name = "scrollbarFadeDuration") getScrollBarFadeDuration()21925 public int getScrollBarFadeDuration() { 21926 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 21927 mScrollCache.scrollBarFadeDuration; 21928 } 21929 21930 /** 21931 * Define the scrollbar fade duration. 21932 * 21933 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 21934 * 21935 * @attr ref android.R.styleable#View_scrollbarFadeDuration 21936 */ setScrollBarFadeDuration(int scrollBarFadeDuration)21937 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 21938 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 21939 } 21940 21941 /** 21942 * 21943 * Returns the scrollbar size. 21944 * 21945 * @return the scrollbar size 21946 * 21947 * @attr ref android.R.styleable#View_scrollbarSize 21948 */ 21949 @InspectableProperty(name = "scrollbarSize") getScrollBarSize()21950 public int getScrollBarSize() { 21951 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 21952 mScrollCache.scrollBarSize; 21953 } 21954 21955 /** 21956 * Define the scrollbar size. 21957 * 21958 * @param scrollBarSize - the scrollbar size 21959 * 21960 * @attr ref android.R.styleable#View_scrollbarSize 21961 */ setScrollBarSize(int scrollBarSize)21962 public void setScrollBarSize(int scrollBarSize) { 21963 getScrollCache().scrollBarSize = scrollBarSize; 21964 } 21965 21966 /** 21967 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 21968 * inset. When inset, they add to the padding of the view. And the scrollbars 21969 * can be drawn inside the padding area or on the edge of the view. For example, 21970 * if a view has a background drawable and you want to draw the scrollbars 21971 * inside the padding specified by the drawable, you can use 21972 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 21973 * appear at the edge of the view, ignoring the padding, then you can use 21974 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 21975 * @param style the style of the scrollbars. Should be one of 21976 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 21977 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 21978 * @see #SCROLLBARS_INSIDE_OVERLAY 21979 * @see #SCROLLBARS_INSIDE_INSET 21980 * @see #SCROLLBARS_OUTSIDE_OVERLAY 21981 * @see #SCROLLBARS_OUTSIDE_INSET 21982 * 21983 * @attr ref android.R.styleable#View_scrollbarStyle 21984 */ setScrollBarStyle(@crollBarStyle int style)21985 public void setScrollBarStyle(@ScrollBarStyle int style) { 21986 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 21987 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 21988 computeOpaqueFlags(); 21989 resolvePadding(); 21990 } 21991 } 21992 21993 /** 21994 * <p>Returns the current scrollbar style.</p> 21995 * @return the current scrollbar style 21996 * @see #SCROLLBARS_INSIDE_OVERLAY 21997 * @see #SCROLLBARS_INSIDE_INSET 21998 * @see #SCROLLBARS_OUTSIDE_OVERLAY 21999 * @see #SCROLLBARS_OUTSIDE_INSET 22000 * 22001 * @attr ref android.R.styleable#View_scrollbarStyle 22002 */ 22003 @ViewDebug.ExportedProperty(mapping = { 22004 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 22005 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 22006 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 22007 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 22008 }) 22009 @InspectableProperty(name = "scrollbarStyle", enumMapping = { 22010 @EnumEntry(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"), 22011 @EnumEntry(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"), 22012 @EnumEntry(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"), 22013 @EnumEntry(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset") 22014 }) 22015 @ScrollBarStyle getScrollBarStyle()22016 public int getScrollBarStyle() { 22017 return mViewFlags & SCROLLBARS_STYLE_MASK; 22018 } 22019 22020 /** 22021 * <p>Compute the horizontal range that the horizontal scrollbar 22022 * represents.</p> 22023 * 22024 * <p>The range is expressed in arbitrary units that must be the same as the 22025 * units used by {@link #computeHorizontalScrollExtent()} and 22026 * {@link #computeHorizontalScrollOffset()}.</p> 22027 * 22028 * <p>The default range is the drawing width of this view.</p> 22029 * 22030 * @return the total horizontal range represented by the horizontal 22031 * scrollbar 22032 * 22033 * @see #computeHorizontalScrollExtent() 22034 * @see #computeHorizontalScrollOffset() 22035 */ computeHorizontalScrollRange()22036 protected int computeHorizontalScrollRange() { 22037 return getWidth(); 22038 } 22039 22040 /** 22041 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 22042 * within the horizontal range. This value is used to compute the position 22043 * of the thumb within the scrollbar's track.</p> 22044 * 22045 * <p>The range is expressed in arbitrary units that must be the same as the 22046 * units used by {@link #computeHorizontalScrollRange()} and 22047 * {@link #computeHorizontalScrollExtent()}.</p> 22048 * 22049 * <p>The default offset is the scroll offset of this view.</p> 22050 * 22051 * @return the horizontal offset of the scrollbar's thumb 22052 * 22053 * @see #computeHorizontalScrollRange() 22054 * @see #computeHorizontalScrollExtent() 22055 */ computeHorizontalScrollOffset()22056 protected int computeHorizontalScrollOffset() { 22057 return mScrollX; 22058 } 22059 22060 /** 22061 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 22062 * within the horizontal range. This value is used to compute the length 22063 * of the thumb within the scrollbar's track.</p> 22064 * 22065 * <p>The range is expressed in arbitrary units that must be the same as the 22066 * units used by {@link #computeHorizontalScrollRange()} and 22067 * {@link #computeHorizontalScrollOffset()}.</p> 22068 * 22069 * <p>The default extent is the drawing width of this view.</p> 22070 * 22071 * @return the horizontal extent of the scrollbar's thumb 22072 * 22073 * @see #computeHorizontalScrollRange() 22074 * @see #computeHorizontalScrollOffset() 22075 */ computeHorizontalScrollExtent()22076 protected int computeHorizontalScrollExtent() { 22077 return getWidth(); 22078 } 22079 22080 /** 22081 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 22082 * 22083 * <p>The range is expressed in arbitrary units that must be the same as the 22084 * units used by {@link #computeVerticalScrollExtent()} and 22085 * {@link #computeVerticalScrollOffset()}.</p> 22086 * 22087 * @return the total vertical range represented by the vertical scrollbar 22088 * 22089 * <p>The default range is the drawing height of this view.</p> 22090 * 22091 * @see #computeVerticalScrollExtent() 22092 * @see #computeVerticalScrollOffset() 22093 */ computeVerticalScrollRange()22094 protected int computeVerticalScrollRange() { 22095 return getHeight(); 22096 } 22097 22098 /** 22099 * <p>Compute the vertical offset of the vertical scrollbar's thumb 22100 * within the horizontal range. This value is used to compute the position 22101 * of the thumb within the scrollbar's track.</p> 22102 * 22103 * <p>The range is expressed in arbitrary units that must be the same as the 22104 * units used by {@link #computeVerticalScrollRange()} and 22105 * {@link #computeVerticalScrollExtent()}.</p> 22106 * 22107 * <p>The default offset is the scroll offset of this view.</p> 22108 * 22109 * @return the vertical offset of the scrollbar's thumb 22110 * 22111 * @see #computeVerticalScrollRange() 22112 * @see #computeVerticalScrollExtent() 22113 */ computeVerticalScrollOffset()22114 protected int computeVerticalScrollOffset() { 22115 return mScrollY; 22116 } 22117 22118 /** 22119 * <p>Compute the vertical extent of the vertical scrollbar's thumb 22120 * within the vertical range. This value is used to compute the length 22121 * of the thumb within the scrollbar's track.</p> 22122 * 22123 * <p>The range is expressed in arbitrary units that must be the same as the 22124 * units used by {@link #computeVerticalScrollRange()} and 22125 * {@link #computeVerticalScrollOffset()}.</p> 22126 * 22127 * <p>The default extent is the drawing height of this view.</p> 22128 * 22129 * @return the vertical extent of the scrollbar's thumb 22130 * 22131 * @see #computeVerticalScrollRange() 22132 * @see #computeVerticalScrollOffset() 22133 */ computeVerticalScrollExtent()22134 protected int computeVerticalScrollExtent() { 22135 return getHeight(); 22136 } 22137 22138 /** 22139 * Check if this view can be scrolled horizontally in a certain direction. 22140 * 22141 * <p>This is without regard to whether the view is enabled or not, or if it will scroll 22142 * in response to user input or not. 22143 * 22144 * @param direction Negative to check scrolling left, positive to check scrolling right. 22145 * @return true if this view can be scrolled in the specified direction, false otherwise. 22146 */ canScrollHorizontally(int direction)22147 public boolean canScrollHorizontally(int direction) { 22148 final int offset = computeHorizontalScrollOffset(); 22149 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 22150 if (range == 0) return false; 22151 if (direction < 0) { 22152 return offset > 0; 22153 } else { 22154 return offset < range - 1; 22155 } 22156 } 22157 22158 /** 22159 * Check if this view can be scrolled vertically in a certain direction. 22160 * 22161 * <p>This is without regard to whether the view is enabled or not, or if it will scroll 22162 * in response to user input or not. 22163 * 22164 * @param direction Negative to check scrolling up, positive to check scrolling down. 22165 * @return true if this view can be scrolled in the specified direction, false otherwise. 22166 */ canScrollVertically(int direction)22167 public boolean canScrollVertically(int direction) { 22168 final int offset = computeVerticalScrollOffset(); 22169 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 22170 if (range == 0) return false; 22171 if (direction < 0) { 22172 return offset > 0; 22173 } else { 22174 return offset < range - 1; 22175 } 22176 } 22177 getScrollIndicatorBounds(@onNull Rect out)22178 void getScrollIndicatorBounds(@NonNull Rect out) { 22179 out.left = mScrollX; 22180 out.right = mScrollX + mRight - mLeft; 22181 out.top = mScrollY; 22182 out.bottom = mScrollY + mBottom - mTop; 22183 } 22184 onDrawScrollIndicators(@onNull Canvas c)22185 private void onDrawScrollIndicators(@NonNull Canvas c) { 22186 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 22187 // No scroll indicators enabled. 22188 return; 22189 } 22190 22191 final Drawable dr = mScrollIndicatorDrawable; 22192 if (dr == null) { 22193 // Scroll indicators aren't supported here. 22194 return; 22195 } 22196 22197 if (mAttachInfo == null) { 22198 // View is not attached. 22199 return; 22200 } 22201 22202 final int h = dr.getIntrinsicHeight(); 22203 final int w = dr.getIntrinsicWidth(); 22204 final Rect rect = mAttachInfo.mTmpInvalRect; 22205 getScrollIndicatorBounds(rect); 22206 22207 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 22208 final boolean canScrollUp = canScrollVertically(-1); 22209 if (canScrollUp) { 22210 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 22211 dr.draw(c); 22212 } 22213 } 22214 22215 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 22216 final boolean canScrollDown = canScrollVertically(1); 22217 if (canScrollDown) { 22218 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 22219 dr.draw(c); 22220 } 22221 } 22222 22223 final int leftRtl; 22224 final int rightRtl; 22225 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 22226 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 22227 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 22228 } else { 22229 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 22230 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 22231 } 22232 22233 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 22234 if ((mPrivateFlags3 & leftMask) != 0) { 22235 final boolean canScrollLeft = canScrollHorizontally(-1); 22236 if (canScrollLeft) { 22237 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 22238 dr.draw(c); 22239 } 22240 } 22241 22242 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 22243 if ((mPrivateFlags3 & rightMask) != 0) { 22244 final boolean canScrollRight = canScrollHorizontally(1); 22245 if (canScrollRight) { 22246 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 22247 dr.draw(c); 22248 } 22249 } 22250 } 22251 getHorizontalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)22252 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 22253 @Nullable Rect touchBounds) { 22254 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 22255 if (bounds == null) { 22256 return; 22257 } 22258 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 22259 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 22260 && !isVerticalScrollBarHidden(); 22261 final int size = getHorizontalScrollbarHeight(); 22262 final int verticalScrollBarGap = drawVerticalScrollBar ? 22263 getVerticalScrollbarWidth() : 0; 22264 final int width = mRight - mLeft; 22265 final int height = mBottom - mTop; 22266 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 22267 bounds.left = mScrollX + (mPaddingLeft & inside); 22268 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 22269 bounds.bottom = bounds.top + size; 22270 22271 if (touchBounds == null) { 22272 return; 22273 } 22274 if (touchBounds != bounds) { 22275 touchBounds.set(bounds); 22276 } 22277 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 22278 if (touchBounds.height() < minTouchTarget) { 22279 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 22280 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 22281 touchBounds.top = touchBounds.bottom - minTouchTarget; 22282 } 22283 if (touchBounds.width() < minTouchTarget) { 22284 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 22285 touchBounds.left -= adjust; 22286 touchBounds.right = touchBounds.left + minTouchTarget; 22287 } 22288 } 22289 getVerticalScrollBarBounds(@ullable Rect bounds, @Nullable Rect touchBounds)22290 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 22291 if (mRoundScrollbarRenderer == null) { 22292 getStraightVerticalScrollBarBounds(bounds, touchBounds); 22293 } else { 22294 mRoundScrollbarRenderer.getRoundVerticalScrollBarBounds( 22295 bounds != null ? bounds : touchBounds); 22296 } 22297 } 22298 getStraightVerticalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)22299 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 22300 @Nullable Rect touchBounds) { 22301 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 22302 if (bounds == null) { 22303 return; 22304 } 22305 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 22306 final int size = getVerticalScrollbarWidth(); 22307 int verticalScrollbarPosition = mVerticalScrollbarPosition; 22308 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 22309 verticalScrollbarPosition = isLayoutRtl() ? 22310 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 22311 } 22312 final int width = mRight - mLeft; 22313 final int height = mBottom - mTop; 22314 switch (verticalScrollbarPosition) { 22315 default: 22316 case SCROLLBAR_POSITION_RIGHT: 22317 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 22318 break; 22319 case SCROLLBAR_POSITION_LEFT: 22320 bounds.left = mScrollX + (mUserPaddingLeft & inside); 22321 break; 22322 } 22323 bounds.top = mScrollY + (mPaddingTop & inside); 22324 bounds.right = bounds.left + size; 22325 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 22326 22327 if (touchBounds == null) { 22328 return; 22329 } 22330 if (touchBounds != bounds) { 22331 touchBounds.set(bounds); 22332 } 22333 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 22334 if (touchBounds.width() < minTouchTarget) { 22335 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 22336 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 22337 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 22338 touchBounds.left = touchBounds.right - minTouchTarget; 22339 } else { 22340 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 22341 touchBounds.right = touchBounds.left + minTouchTarget; 22342 } 22343 } 22344 if (touchBounds.height() < minTouchTarget) { 22345 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 22346 touchBounds.top -= adjust; 22347 touchBounds.bottom = touchBounds.top + minTouchTarget; 22348 } 22349 } 22350 22351 /** 22352 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 22353 * scrollbars are painted only if they have been awakened first.</p> 22354 * 22355 * @param canvas the canvas on which to draw the scrollbars 22356 * 22357 * @see #awakenScrollBars(int) 22358 */ onDrawScrollBars(@onNull Canvas canvas)22359 protected final void onDrawScrollBars(@NonNull Canvas canvas) { 22360 // scrollbars are drawn only when the animation is running 22361 final ScrollabilityCache cache = mScrollCache; 22362 22363 if (cache != null) { 22364 22365 int state = cache.state; 22366 22367 if (state == ScrollabilityCache.OFF) { 22368 return; 22369 } 22370 22371 boolean invalidate = false; 22372 22373 if (state == ScrollabilityCache.FADING) { 22374 // We're fading -- get our fade interpolation 22375 if (cache.interpolatorValues == null) { 22376 cache.interpolatorValues = new float[1]; 22377 } 22378 22379 float[] values = cache.interpolatorValues; 22380 22381 // Stops the animation if we're done 22382 if (cache.scrollBarInterpolator.timeToValues(values) == 22383 Interpolator.Result.FREEZE_END) { 22384 cache.state = ScrollabilityCache.OFF; 22385 } else { 22386 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 22387 } 22388 22389 // This will make the scroll bars inval themselves after 22390 // drawing. We only want this when we're fading so that 22391 // we prevent excessive redraws 22392 invalidate = true; 22393 } else { 22394 // We're just on -- but we may have been fading before so 22395 // reset alpha 22396 cache.scrollBar.mutate().setAlpha(255); 22397 } 22398 22399 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 22400 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 22401 && !isVerticalScrollBarHidden(); 22402 22403 // Fork out the scroll bar drawing for round wearable devices. 22404 if (mRoundScrollbarRenderer != null) { 22405 if (drawVerticalScrollBar) { 22406 final Rect bounds = cache.mScrollBarBounds; 22407 getVerticalScrollBarBounds(bounds, null); 22408 boolean shouldDrawScrollbarAtLeft = 22409 (mVerticalScrollbarPosition == SCROLLBAR_POSITION_LEFT) 22410 || (mVerticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT 22411 && isLayoutRtl()); 22412 22413 mRoundScrollbarRenderer.drawRoundScrollbars( 22414 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds, 22415 shouldDrawScrollbarAtLeft); 22416 if (invalidate) { 22417 invalidate(); 22418 } 22419 } 22420 // Do not draw horizontal scroll bars for round wearable devices. 22421 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 22422 final ScrollBarDrawable scrollBar = cache.scrollBar; 22423 22424 if (drawHorizontalScrollBar) { 22425 scrollBar.setParameters(computeHorizontalScrollRange(), 22426 computeHorizontalScrollOffset(), 22427 computeHorizontalScrollExtent(), false); 22428 final Rect bounds = cache.mScrollBarBounds; 22429 getHorizontalScrollBarBounds(bounds, null); 22430 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 22431 bounds.right, bounds.bottom); 22432 if (invalidate) { 22433 invalidate(bounds); 22434 } 22435 } 22436 22437 if (drawVerticalScrollBar) { 22438 scrollBar.setParameters(computeVerticalScrollRange(), 22439 computeVerticalScrollOffset(), 22440 computeVerticalScrollExtent(), true); 22441 final Rect bounds = cache.mScrollBarBounds; 22442 getVerticalScrollBarBounds(bounds, null); 22443 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 22444 bounds.right, bounds.bottom); 22445 if (invalidate) { 22446 invalidate(bounds); 22447 } 22448 } 22449 } 22450 } 22451 } 22452 22453 /** 22454 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 22455 * FastScroller is visible. 22456 * @return whether to temporarily hide the vertical scrollbar 22457 * @hide 22458 */ isVerticalScrollBarHidden()22459 protected boolean isVerticalScrollBarHidden() { 22460 return false; 22461 } 22462 22463 /** 22464 * <p>Draw the horizontal scrollbar if 22465 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 22466 * 22467 * @param canvas the canvas on which to draw the scrollbar 22468 * @param scrollBar the scrollbar's drawable 22469 * 22470 * @see #isHorizontalScrollBarEnabled() 22471 * @see #computeHorizontalScrollRange() 22472 * @see #computeHorizontalScrollExtent() 22473 * @see #computeHorizontalScrollOffset() 22474 * @hide 22475 */ 22476 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onDrawHorizontalScrollBar(@onNull Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)22477 protected void onDrawHorizontalScrollBar(@NonNull Canvas canvas, Drawable scrollBar, 22478 int l, int t, int r, int b) { 22479 scrollBar.setBounds(l, t, r, b); 22480 scrollBar.draw(canvas); 22481 } 22482 22483 /** 22484 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 22485 * returns true.</p> 22486 * 22487 * @param canvas the canvas on which to draw the scrollbar 22488 * @param scrollBar the scrollbar's drawable 22489 * 22490 * @see #isVerticalScrollBarEnabled() 22491 * @see #computeVerticalScrollRange() 22492 * @see #computeVerticalScrollExtent() 22493 * @see #computeVerticalScrollOffset() 22494 * @hide 22495 */ 22496 @UnsupportedAppUsage onDrawVerticalScrollBar(@onNull Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)22497 protected void onDrawVerticalScrollBar(@NonNull Canvas canvas, Drawable scrollBar, 22498 int l, int t, int r, int b) { 22499 scrollBar.setBounds(l, t, r, b); 22500 scrollBar.draw(canvas); 22501 } 22502 22503 /** 22504 * Implement this to do your drawing. 22505 * 22506 * @param canvas the canvas on which the background will be drawn 22507 */ onDraw(@onNull Canvas canvas)22508 protected void onDraw(@NonNull Canvas canvas) { 22509 } 22510 22511 /* 22512 * Caller is responsible for calling requestLayout if necessary. 22513 * (This allows addViewInLayout to not request a new layout.) 22514 */ 22515 @UnsupportedAppUsage assignParent(ViewParent parent)22516 void assignParent(ViewParent parent) { 22517 if (mParent == null) { 22518 mParent = parent; 22519 } else if (parent == null) { 22520 mParent = null; 22521 } else { 22522 throw new RuntimeException("view " + this + " being added, but" 22523 + " it already has a parent"); 22524 } 22525 } 22526 22527 /** 22528 * This is called when the view is attached to a window. At this point it 22529 * has a Surface and will start drawing. Note that this function is 22530 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 22531 * however it may be called any time before the first onDraw -- including 22532 * before or after {@link #onMeasure(int, int)}. 22533 * 22534 * @see #onDetachedFromWindow() 22535 */ 22536 @CallSuper onAttachedToWindow()22537 protected void onAttachedToWindow() { 22538 if (mParent != null && (mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 22539 mParent.requestTransparentRegion(this); 22540 } 22541 22542 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 22543 22544 jumpDrawablesToCurrentState(); 22545 22546 AccessibilityNodeIdManager.getInstance().registerViewWithId(this, getAccessibilityViewId()); 22547 resetSubtreeAccessibilityStateChanged(); 22548 22549 // rebuild, since Outline not maintained while View is detached 22550 rebuildOutline(); 22551 22552 if (isFocused()) { 22553 notifyFocusChangeToImeFocusController(true /* hasFocus */); 22554 } 22555 22556 if (sTraceLayoutSteps) { 22557 setTraversalTracingEnabled(true); 22558 } 22559 if (sTraceRequestLayoutClass != null 22560 && sTraceRequestLayoutClass.equals(getClass().getSimpleName())) { 22561 setRelayoutTracingEnabled(true); 22562 } 22563 } 22564 22565 /** 22566 * Resolve all RTL related properties. 22567 * 22568 * @return true if resolution of RTL properties has been done 22569 * 22570 * @hide 22571 */ resolveRtlPropertiesIfNeeded()22572 public boolean resolveRtlPropertiesIfNeeded() { 22573 if (!needRtlPropertiesResolution()) return false; 22574 22575 // Order is important here: LayoutDirection MUST be resolved first 22576 if (!isLayoutDirectionResolved()) { 22577 resolveLayoutDirection(); 22578 resolveLayoutParams(); 22579 } 22580 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 22581 if (!isTextDirectionResolved()) { 22582 resolveTextDirection(); 22583 } 22584 if (!isTextAlignmentResolved()) { 22585 resolveTextAlignment(); 22586 } 22587 // Should resolve Drawables before Padding because we need the layout direction of the 22588 // Drawable to correctly resolve Padding. 22589 if (!areDrawablesResolved()) { 22590 resolveDrawables(); 22591 } 22592 if (!isPaddingResolved()) { 22593 resolvePadding(); 22594 } 22595 onRtlPropertiesChanged(getLayoutDirection()); 22596 return true; 22597 } 22598 22599 /** 22600 * Reset resolution of all RTL related properties. 22601 * 22602 * @hide 22603 */ 22604 @TestApi resetRtlProperties()22605 public void resetRtlProperties() { 22606 resetResolvedLayoutDirection(); 22607 resetResolvedTextDirection(); 22608 resetResolvedTextAlignment(); 22609 resetResolvedPadding(); 22610 resetResolvedDrawables(); 22611 } 22612 22613 /** 22614 * @see #onScreenStateChanged(int) 22615 */ dispatchScreenStateChanged(int screenState)22616 void dispatchScreenStateChanged(int screenState) { 22617 onScreenStateChanged(screenState); 22618 } 22619 22620 /** 22621 * This method is called whenever the state of the screen this view is 22622 * attached to changes. A state change will usually occurs when the screen 22623 * turns on or off (whether it happens automatically or the user does it 22624 * manually.) 22625 * 22626 * @param screenState The new state of the screen. Can be either 22627 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 22628 */ onScreenStateChanged(int screenState)22629 public void onScreenStateChanged(int screenState) { 22630 } 22631 22632 /** 22633 * @see #onMovedToDisplay(int, Configuration) 22634 */ dispatchMovedToDisplay(Display display, Configuration config)22635 void dispatchMovedToDisplay(Display display, Configuration config) { 22636 mAttachInfo.mDisplay = display; 22637 mAttachInfo.mDisplayState = display.getState(); 22638 onMovedToDisplay(display.getDisplayId(), config); 22639 } 22640 22641 /** 22642 * Called by the system when the hosting activity is moved from one display to another without 22643 * recreation. This means that the activity is declared to handle all changes to configuration 22644 * that happened when it was switched to another display, so it wasn't destroyed and created 22645 * again. 22646 * 22647 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 22648 * applied configuration actually changed. It is up to app developer to choose whether to handle 22649 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)} 22650 * call. 22651 * 22652 * <p>Use this callback to track changes to the displays if some functionality relies on an 22653 * association with some display properties. 22654 * 22655 * @param displayId The id of the display to which the view was moved. 22656 * @param config Configuration of the resources on new display after move. 22657 * 22658 * @see #onConfigurationChanged(Configuration) 22659 * @hide 22660 */ onMovedToDisplay(int displayId, Configuration config)22661 public void onMovedToDisplay(int displayId, Configuration config) { 22662 } 22663 22664 /** 22665 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 22666 */ 22667 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) hasRtlSupport()22668 private boolean hasRtlSupport() { 22669 return mContext.getApplicationInfo().hasRtlSupport(); 22670 } 22671 22672 /** 22673 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 22674 * RTL not supported) 22675 */ isRtlCompatibilityMode()22676 private boolean isRtlCompatibilityMode() { 22677 return !hasRtlSupport(); 22678 } 22679 22680 /** 22681 * @return true if RTL properties need resolution. 22682 * 22683 */ needRtlPropertiesResolution()22684 private boolean needRtlPropertiesResolution() { 22685 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 22686 } 22687 22688 /** 22689 * Called when any RTL property (layout direction or text direction or text alignment) has 22690 * been changed. 22691 * 22692 * Subclasses need to override this method to take care of cached information that depends on the 22693 * resolved layout direction, or to inform child views that inherit their layout direction. 22694 * 22695 * The default implementation does nothing. 22696 * 22697 * @param layoutDirection the direction of the layout 22698 * 22699 * @see #LAYOUT_DIRECTION_LTR 22700 * @see #LAYOUT_DIRECTION_RTL 22701 */ onRtlPropertiesChanged(@esolvedLayoutDir int layoutDirection)22702 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 22703 } 22704 22705 /** 22706 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 22707 * that the parent directionality can and will be resolved before its children. 22708 * 22709 * @return true if resolution has been done, false otherwise. 22710 * 22711 * @hide 22712 */ resolveLayoutDirection()22713 public boolean resolveLayoutDirection() { 22714 // Clear any previous layout direction resolution 22715 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 22716 22717 if (hasRtlSupport()) { 22718 // Set resolved depending on layout direction 22719 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 22720 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 22721 case LAYOUT_DIRECTION_INHERIT: 22722 // We cannot resolve yet. LTR is by default and let the resolution happen again 22723 // later to get the correct resolved value 22724 if (!canResolveLayoutDirection()) return false; 22725 22726 // Parent has not yet resolved, LTR is still the default 22727 try { 22728 if (!mParent.isLayoutDirectionResolved()) return false; 22729 22730 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 22731 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 22732 } 22733 } catch (AbstractMethodError e) { 22734 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22735 " does not fully implement ViewParent", e); 22736 } 22737 break; 22738 case LAYOUT_DIRECTION_RTL: 22739 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 22740 break; 22741 case LAYOUT_DIRECTION_LOCALE: 22742 if((LAYOUT_DIRECTION_RTL == 22743 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 22744 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 22745 } 22746 break; 22747 default: 22748 // Nothing to do, LTR by default 22749 } 22750 } 22751 22752 // Set to resolved 22753 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 22754 return true; 22755 } 22756 22757 /** 22758 * Check if layout direction resolution can be done. 22759 * 22760 * @return true if layout direction resolution can be done otherwise return false. 22761 */ canResolveLayoutDirection()22762 public boolean canResolveLayoutDirection() { 22763 switch (getRawLayoutDirection()) { 22764 case LAYOUT_DIRECTION_INHERIT: 22765 if (mParent != null) { 22766 try { 22767 return mParent.canResolveLayoutDirection(); 22768 } catch (AbstractMethodError e) { 22769 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 22770 " does not fully implement ViewParent", e); 22771 } 22772 } 22773 return false; 22774 22775 default: 22776 return true; 22777 } 22778 } 22779 22780 /** 22781 * Reset the resolved layout direction. Layout direction will be resolved during a call to 22782 * {@link #onMeasure(int, int)}. 22783 * 22784 * @hide 22785 */ 22786 @TestApi resetResolvedLayoutDirection()22787 public void resetResolvedLayoutDirection() { 22788 // Reset the current resolved bits 22789 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 22790 } 22791 22792 /** 22793 * @return true if the layout direction is inherited. 22794 * 22795 * @hide 22796 */ isLayoutDirectionInherited()22797 public boolean isLayoutDirectionInherited() { 22798 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 22799 } 22800 22801 /** 22802 * @return true if layout direction has been resolved. 22803 */ isLayoutDirectionResolved()22804 public boolean isLayoutDirectionResolved() { 22805 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 22806 } 22807 22808 /** 22809 * Return if padding has been resolved 22810 * 22811 * @hide 22812 */ 22813 @UnsupportedAppUsage isPaddingResolved()22814 boolean isPaddingResolved() { 22815 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 22816 } 22817 22818 /** 22819 * Resolves padding depending on layout direction, if applicable, and 22820 * recomputes internal padding values to adjust for scroll bars. 22821 * 22822 * @hide 22823 */ 22824 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resolvePadding()22825 public void resolvePadding() { 22826 final int resolvedLayoutDirection = getLayoutDirection(); 22827 22828 if (!isRtlCompatibilityMode()) { 22829 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 22830 // If start / end padding are defined, they will be resolved (hence overriding) to 22831 // left / right or right / left depending on the resolved layout direction. 22832 // If start / end padding are not defined, use the left / right ones. 22833 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 22834 Rect padding = sThreadLocal.get(); 22835 if (padding == null) { 22836 padding = new Rect(); 22837 sThreadLocal.set(padding); 22838 } 22839 mBackground.getPadding(padding); 22840 if (!mLeftPaddingDefined) { 22841 mUserPaddingLeftInitial = padding.left; 22842 } 22843 if (!mRightPaddingDefined) { 22844 mUserPaddingRightInitial = padding.right; 22845 } 22846 } 22847 switch (resolvedLayoutDirection) { 22848 case LAYOUT_DIRECTION_RTL: 22849 if (mUserPaddingStart != UNDEFINED_PADDING) { 22850 mUserPaddingRight = mUserPaddingStart; 22851 } else { 22852 mUserPaddingRight = mUserPaddingRightInitial; 22853 } 22854 if (mUserPaddingEnd != UNDEFINED_PADDING) { 22855 mUserPaddingLeft = mUserPaddingEnd; 22856 } else { 22857 mUserPaddingLeft = mUserPaddingLeftInitial; 22858 } 22859 break; 22860 case LAYOUT_DIRECTION_LTR: 22861 default: 22862 if (mUserPaddingStart != UNDEFINED_PADDING) { 22863 mUserPaddingLeft = mUserPaddingStart; 22864 } else { 22865 mUserPaddingLeft = mUserPaddingLeftInitial; 22866 } 22867 if (mUserPaddingEnd != UNDEFINED_PADDING) { 22868 mUserPaddingRight = mUserPaddingEnd; 22869 } else { 22870 mUserPaddingRight = mUserPaddingRightInitial; 22871 } 22872 } 22873 22874 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 22875 } 22876 22877 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 22878 onRtlPropertiesChanged(resolvedLayoutDirection); 22879 22880 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 22881 } 22882 22883 /** 22884 * Reset the resolved layout direction. 22885 * 22886 * @hide 22887 */ 22888 @TestApi resetResolvedPadding()22889 public void resetResolvedPadding() { 22890 resetResolvedPaddingInternal(); 22891 } 22892 22893 /** 22894 * Used when we only want to reset *this* view's padding and not trigger overrides 22895 * in ViewGroup that reset children too. 22896 */ resetResolvedPaddingInternal()22897 void resetResolvedPaddingInternal() { 22898 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 22899 } 22900 22901 /** 22902 * This is called when the view is detached from a window. At this point it 22903 * no longer has a surface for drawing. 22904 * 22905 * @see #onAttachedToWindow() 22906 */ 22907 @CallSuper onDetachedFromWindow()22908 protected void onDetachedFromWindow() { 22909 } 22910 22911 /** 22912 * This is a framework-internal mirror of onDetachedFromWindow() that's called 22913 * after onDetachedFromWindow(). 22914 * 22915 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 22916 * The super method should be called at the end of the overridden method to ensure 22917 * subclasses are destroyed first 22918 * 22919 * @hide 22920 */ 22921 @CallSuper 22922 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onDetachedFromWindowInternal()22923 protected void onDetachedFromWindowInternal() { 22924 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 22925 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 22926 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 22927 22928 removeUnsetPressCallback(); 22929 removeLongPressCallback(); 22930 removePerformClickCallback(); 22931 clearAccessibilityThrottles(); 22932 stopNestedScroll(); 22933 22934 // Anything that started animating right before detach should already 22935 // be in its final state when re-attached. 22936 jumpDrawablesToCurrentState(); 22937 22938 destroyDrawingCache(); 22939 22940 cleanupDraw(); 22941 mCurrentAnimation = null; 22942 22943 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 22944 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 22945 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 22946 hideTooltip(); 22947 } 22948 22949 AccessibilityNodeIdManager.getInstance().unregisterViewWithId(getAccessibilityViewId()); 22950 22951 if (mBackgroundRenderNode != null) { 22952 mBackgroundRenderNode.forceEndAnimators(); 22953 } 22954 mRenderNode.forceEndAnimators(); 22955 } 22956 cleanupDraw()22957 private void cleanupDraw() { 22958 resetDisplayList(); 22959 if (mAttachInfo != null) { 22960 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 22961 } 22962 } 22963 invalidateInheritedLayoutMode(int layoutModeOfRoot)22964 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 22965 } 22966 22967 /** 22968 * @return The number of times this view has been attached to a window 22969 */ getWindowAttachCount()22970 protected int getWindowAttachCount() { 22971 return mWindowAttachCount; 22972 } 22973 22974 /** 22975 * Retrieve a unique token identifying the window this view is attached to. 22976 * @return Return the window's token for use in 22977 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 22978 * This token maybe null if this view is not attached to a window. 22979 * @see #isAttachedToWindow() for current window attach state 22980 * @see OnAttachStateChangeListener to listen to window attach/detach state changes 22981 */ getWindowToken()22982 public IBinder getWindowToken() { 22983 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 22984 } 22985 22986 /** 22987 * Retrieve the {@link WindowId} for the window this view is 22988 * currently attached to. 22989 */ getWindowId()22990 public WindowId getWindowId() { 22991 AttachInfo ai = mAttachInfo; 22992 if (ai == null) { 22993 return null; 22994 } 22995 if (ai.mWindowId == null) { 22996 try { 22997 ai.mIWindowId = ai.mSession.getWindowId(ai.mWindowToken); 22998 if (ai.mIWindowId != null) { 22999 ai.mWindowId = new WindowId(ai.mIWindowId); 23000 } 23001 } catch (RemoteException e) { 23002 } 23003 } 23004 return ai.mWindowId; 23005 } 23006 23007 /** 23008 * Retrieve a unique token identifying the top-level "real" window of 23009 * the window that this view is attached to. That is, this is like 23010 * {@link #getWindowToken}, except if the window this view in is a panel 23011 * window (attached to another containing window), then the token of 23012 * the containing window is returned instead. 23013 * 23014 * @return Returns the associated window token, either 23015 * {@link #getWindowToken()} or the containing window's token. 23016 */ getApplicationWindowToken()23017 public IBinder getApplicationWindowToken() { 23018 AttachInfo ai = mAttachInfo; 23019 if (ai != null) { 23020 IBinder appWindowToken = ai.mPanelParentWindowToken; 23021 if (appWindowToken == null) { 23022 appWindowToken = ai.mWindowToken; 23023 } 23024 return appWindowToken; 23025 } 23026 return null; 23027 } 23028 23029 /** 23030 * Gets the logical display to which the view's window has been attached. 23031 * 23032 * @return The logical display, or null if the view is not currently attached to a window. 23033 */ getDisplay()23034 public Display getDisplay() { 23035 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 23036 } 23037 23038 /** 23039 * Retrieve private session object this view hierarchy is using to 23040 * communicate with the window manager. 23041 * @return the session object to communicate with the window manager 23042 */ 23043 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) getWindowSession()23044 /*package*/ IWindowSession getWindowSession() { 23045 return mAttachInfo != null ? mAttachInfo.mSession : null; 23046 } 23047 23048 /** 23049 * Return the window this view is currently attached to. 23050 * @hide 23051 */ getWindow()23052 protected IWindow getWindow() { 23053 return mAttachInfo != null ? mAttachInfo.mWindow : null; 23054 } 23055 23056 /** 23057 * Return the visibility value of the least visible component passed. 23058 */ combineVisibility(int vis1, int vis2)23059 int combineVisibility(int vis1, int vis2) { 23060 // This works because VISIBLE < INVISIBLE < GONE. 23061 return Math.max(vis1, vis2); 23062 } 23063 23064 private boolean mShouldFakeFocus = false; 23065 23066 /** 23067 * Fake send a focus event after attaching to window. 23068 * See {@link android.view.ViewRootImpl#dispatchCompatFakeFocus()} for details. 23069 * @hide 23070 */ fakeFocusAfterAttachingToWindow()23071 public void fakeFocusAfterAttachingToWindow() { 23072 mShouldFakeFocus = true; 23073 } 23074 23075 /** 23076 * @param info the {@link android.view.View.AttachInfo} to associated with 23077 * this view 23078 */ 23079 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchAttachedToWindow(AttachInfo info, int visibility)23080 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 23081 mAttachInfo = info; 23082 if (mOverlay != null) { 23083 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 23084 } 23085 mWindowAttachCount++; 23086 // We will need to evaluate the drawable state at least once. 23087 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 23088 if (mFloatingTreeObserver != null) { 23089 info.mTreeObserver.merge(mFloatingTreeObserver); 23090 mFloatingTreeObserver = null; 23091 } 23092 23093 registerPendingFrameMetricsObservers(); 23094 23095 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 23096 mAttachInfo.mScrollContainers.add(this); 23097 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 23098 } 23099 // Transfer all pending runnables. 23100 if (mRunQueue != null) { 23101 mRunQueue.executeActions(info.mHandler); 23102 mRunQueue = null; 23103 } 23104 performCollectViewAttributes(mAttachInfo, visibility); 23105 onAttachedToWindow(); 23106 23107 ListenerInfo li = mListenerInfo; 23108 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 23109 li != null ? li.mOnAttachStateChangeListeners : null; 23110 if (listeners != null && listeners.size() > 0) { 23111 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 23112 // perform the dispatching. The iterator is a safe guard against listeners that 23113 // could mutate the list by calling the various add/remove methods. This prevents 23114 // the array from being modified while we iterate it. 23115 for (OnAttachStateChangeListener listener : listeners) { 23116 listener.onViewAttachedToWindow(this); 23117 } 23118 } 23119 23120 int vis = info.mWindowVisibility; 23121 if (vis != GONE) { 23122 onWindowVisibilityChanged(vis); 23123 if (isShown()) { 23124 // Calling onVisibilityAggregated directly here since the subtree will also 23125 // receive dispatchAttachedToWindow and this same call 23126 onVisibilityAggregated(vis == VISIBLE); 23127 } 23128 } 23129 23130 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 23131 // As all views in the subtree will already receive dispatchAttachedToWindow 23132 // traversing the subtree again here is not desired. 23133 onVisibilityChanged(this, visibility); 23134 23135 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 23136 // If nobody has evaluated the drawable state yet, then do it now. 23137 refreshDrawableState(); 23138 } 23139 needGlobalAttributesUpdate(false); 23140 23141 notifyEnterOrExitForAutoFillIfNeeded(true); 23142 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 23143 23144 if (mShouldFakeFocus) { 23145 getViewRootImpl().dispatchCompatFakeFocus(); 23146 mShouldFakeFocus = false; 23147 } 23148 } 23149 23150 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchDetachedFromWindow()23151 void dispatchDetachedFromWindow() { 23152 AttachInfo info = mAttachInfo; 23153 if (info != null) { 23154 int vis = info.mWindowVisibility; 23155 if (vis != GONE) { 23156 onWindowVisibilityChanged(GONE); 23157 if (isShown()) { 23158 // Invoking onVisibilityAggregated directly here since the subtree 23159 // will also receive detached from window 23160 onVisibilityAggregated(false); 23161 } else { 23162 notifyAutofillManagerViewVisibilityChanged(false); 23163 } 23164 } 23165 } 23166 23167 onDetachedFromWindow(); 23168 onDetachedFromWindowInternal(); 23169 23170 if (info != null) { 23171 info.mViewRootImpl.getImeFocusController().onViewDetachedFromWindow(this); 23172 } 23173 23174 ListenerInfo li = mListenerInfo; 23175 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 23176 li != null ? li.mOnAttachStateChangeListeners : null; 23177 if (listeners != null && listeners.size() > 0) { 23178 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 23179 // perform the dispatching. The iterator is a safe guard against listeners that 23180 // could mutate the list by calling the various add/remove methods. This prevents 23181 // the array from being modified while we iterate it. 23182 for (OnAttachStateChangeListener listener : listeners) { 23183 listener.onViewDetachedFromWindow(this); 23184 } 23185 } 23186 23187 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 23188 mAttachInfo.mScrollContainers.remove(this); 23189 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 23190 } 23191 23192 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 23193 updateSensitiveViewsCountIfNeeded(false); 23194 23195 mAttachInfo = null; 23196 if (mOverlay != null) { 23197 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 23198 } 23199 23200 notifyEnterOrExitForAutoFillIfNeeded(false); 23201 23202 if (info != null && !collectPreferKeepClearRects().isEmpty()) { 23203 info.mViewRootImpl.updateKeepClearRectsForView(this); 23204 } 23205 } 23206 23207 /** 23208 * Cancel any deferred high-level input events that were previously posted to the event queue. 23209 * 23210 * <p>Many views post high-level events such as click handlers to the event queue 23211 * to run deferred in order to preserve a desired user experience - clearing visible 23212 * pressed states before executing, etc. This method will abort any events of this nature 23213 * that are currently in flight.</p> 23214 * 23215 * <p>Custom views that generate their own high-level deferred input events should override 23216 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 23217 * 23218 * <p>This will also cancel pending input events for any child views.</p> 23219 * 23220 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 23221 * This will not impact newer events posted after this call that may occur as a result of 23222 * lower-level input events still waiting in the queue. If you are trying to prevent 23223 * double-submitted events for the duration of some sort of asynchronous transaction 23224 * you should also take other steps to protect against unexpected double inputs e.g. calling 23225 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 23226 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 23227 */ cancelPendingInputEvents()23228 public final void cancelPendingInputEvents() { 23229 dispatchCancelPendingInputEvents(); 23230 } 23231 23232 /** 23233 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 23234 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 23235 */ dispatchCancelPendingInputEvents()23236 void dispatchCancelPendingInputEvents() { 23237 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 23238 onCancelPendingInputEvents(); 23239 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 23240 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 23241 " did not call through to super.onCancelPendingInputEvents()"); 23242 } 23243 } 23244 23245 /** 23246 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 23247 * a parent view. 23248 * 23249 * <p>This method is responsible for removing any pending high-level input events that were 23250 * posted to the event queue to run later. Custom view classes that post their own deferred 23251 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 23252 * {@link android.os.Handler} should override this method, call 23253 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 23254 * </p> 23255 */ onCancelPendingInputEvents()23256 public void onCancelPendingInputEvents() { 23257 removePerformClickCallback(); 23258 cancelLongPress(); 23259 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 23260 } 23261 23262 /** 23263 * Store this view hierarchy's frozen state into the given container. 23264 * 23265 * @param container The SparseArray in which to save the view's state. 23266 * 23267 * @see #restoreHierarchyState(android.util.SparseArray) 23268 * @see #dispatchSaveInstanceState(android.util.SparseArray) 23269 * @see #onSaveInstanceState() 23270 */ saveHierarchyState(SparseArray<Parcelable> container)23271 public void saveHierarchyState(SparseArray<Parcelable> container) { 23272 dispatchSaveInstanceState(container); 23273 } 23274 23275 /** 23276 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 23277 * this view and its children. May be overridden to modify how freezing happens to a 23278 * view's children; for example, some views may want to not store state for their children. 23279 * 23280 * @param container The SparseArray in which to save the view's state. 23281 * 23282 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 23283 * @see #saveHierarchyState(android.util.SparseArray) 23284 * @see #onSaveInstanceState() 23285 */ dispatchSaveInstanceState(SparseArray<Parcelable> container)23286 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 23287 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 23288 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 23289 Parcelable state = onSaveInstanceState(); 23290 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 23291 throw new IllegalStateException( 23292 "Derived class did not call super.onSaveInstanceState()"); 23293 } 23294 if (state != null) { 23295 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 23296 // + ": " + state); 23297 container.put(mID, state); 23298 } 23299 } 23300 } 23301 23302 /** 23303 * Hook allowing a view to generate a representation of its internal state 23304 * that can later be used to create a new instance with that same state. 23305 * This state should only contain information that is not persistent or can 23306 * not be reconstructed later. For example, you will never store your 23307 * current position on screen because that will be computed again when a 23308 * new instance of the view is placed in its view hierarchy. 23309 * <p> 23310 * Some examples of things you may store here: the current cursor position 23311 * in a text view (but usually not the text itself since that is stored in a 23312 * content provider or other persistent storage), the currently selected 23313 * item in a list view. 23314 * 23315 * @return Returns a Parcelable object containing the view's current dynamic 23316 * state, or null if there is nothing interesting to save. 23317 * @see #onRestoreInstanceState(Parcelable) 23318 * @see #saveHierarchyState(SparseArray) 23319 * @see #dispatchSaveInstanceState(SparseArray) 23320 * @see #setSaveEnabled(boolean) 23321 */ 23322 @CallSuper onSaveInstanceState()23323 @Nullable protected Parcelable onSaveInstanceState() { 23324 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 23325 if (mStartActivityRequestWho != null || isAutofilled() 23326 || mAutofillViewId > LAST_APP_AUTOFILL_ID) { 23327 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 23328 23329 if (mStartActivityRequestWho != null) { 23330 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; 23331 } 23332 23333 if (isAutofilled()) { 23334 state.mSavedData |= BaseSavedState.IS_AUTOFILLED; 23335 } 23336 23337 if (mAutofillViewId > LAST_APP_AUTOFILL_ID) { 23338 state.mSavedData |= BaseSavedState.AUTOFILL_ID; 23339 } 23340 23341 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 23342 state.mIsAutofilled = isAutofilled(); 23343 state.mHideHighlight = hideAutofillHighlight(); 23344 state.mAutofillViewId = mAutofillViewId; 23345 return state; 23346 } 23347 return BaseSavedState.EMPTY_STATE; 23348 } 23349 23350 /** 23351 * Restore this view hierarchy's frozen state from the given container. 23352 * 23353 * @param container The SparseArray which holds previously frozen states. 23354 * 23355 * @see #saveHierarchyState(android.util.SparseArray) 23356 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 23357 * @see #onRestoreInstanceState(android.os.Parcelable) 23358 */ restoreHierarchyState(SparseArray<Parcelable> container)23359 public void restoreHierarchyState(SparseArray<Parcelable> container) { 23360 dispatchRestoreInstanceState(container); 23361 } 23362 23363 /** 23364 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 23365 * state for this view and its children. May be overridden to modify how restoring 23366 * happens to a view's children; for example, some views may want to not store state 23367 * for their children. 23368 * 23369 * @param container The SparseArray which holds previously saved state. 23370 * 23371 * @see #dispatchSaveInstanceState(android.util.SparseArray) 23372 * @see #restoreHierarchyState(android.util.SparseArray) 23373 * @see #onRestoreInstanceState(android.os.Parcelable) 23374 */ dispatchRestoreInstanceState(SparseArray<Parcelable> container)23375 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 23376 if (mID != NO_ID) { 23377 Parcelable state = container.get(mID); 23378 if (state != null) { 23379 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 23380 // + ": " + state); 23381 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 23382 onRestoreInstanceState(state); 23383 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 23384 throw new IllegalStateException( 23385 "Derived class did not call super.onRestoreInstanceState()"); 23386 } 23387 } 23388 } 23389 } 23390 23391 /** 23392 * Hook allowing a view to re-apply a representation of its internal state that had previously 23393 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 23394 * null state. 23395 * 23396 * @param state The frozen state that had previously been returned by 23397 * {@link #onSaveInstanceState}. 23398 * 23399 * @see #onSaveInstanceState() 23400 * @see #restoreHierarchyState(android.util.SparseArray) 23401 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 23402 */ 23403 @CallSuper onRestoreInstanceState(Parcelable state)23404 protected void onRestoreInstanceState(Parcelable state) { 23405 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 23406 if (state != null && !(state instanceof AbsSavedState)) { 23407 throw new IllegalArgumentException("Wrong state class, expecting View State but " 23408 + "received " + state.getClass().toString() + " instead. This usually happens " 23409 + "when two views of different type have the same id in the same hierarchy. " 23410 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 23411 + "other views do not use the same id."); 23412 } 23413 if (state != null && state instanceof BaseSavedState) { 23414 BaseSavedState baseState = (BaseSavedState) state; 23415 23416 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { 23417 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; 23418 } 23419 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { 23420 setAutofilled(baseState.mIsAutofilled, baseState.mHideHighlight); 23421 } 23422 if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) { 23423 // It can happen that views have the same view id and the restoration path will not 23424 // be able to distinguish between them. The autofill id needs to be unique though. 23425 // Hence prevent the same autofill view id from being restored multiple times. 23426 ((BaseSavedState) state).mSavedData &= ~BaseSavedState.AUTOFILL_ID; 23427 23428 if ((mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) != 0) { 23429 // Ignore when view already set it through setAutofillId(); 23430 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.DEBUG)) { 23431 Log.d(AUTOFILL_LOG_TAG, "onRestoreInstanceState(): not setting autofillId " 23432 + "to " + baseState.mAutofillViewId + " because view explicitly set" 23433 + " it to " + mAutofillId); 23434 } 23435 } else { 23436 mAutofillViewId = baseState.mAutofillViewId; 23437 mAutofillId = null; // will be set on demand by getAutofillId() 23438 } 23439 } 23440 } 23441 } 23442 23443 /** 23444 * <p>Return the time at which the drawing of the view hierarchy started.</p> 23445 * 23446 * @return the drawing start time in milliseconds 23447 */ getDrawingTime()23448 public long getDrawingTime() { 23449 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 23450 } 23451 23452 /** 23453 * <p>Enables or disables the duplication of the parent's state into this view. When 23454 * duplication is enabled, this view gets its drawable state from its parent rather 23455 * than from its own internal properties.</p> 23456 * 23457 * <p>Note: in the current implementation, setting this property to true after the 23458 * view was added to a ViewGroup might have no effect at all. This property should 23459 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 23460 * 23461 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 23462 * property is enabled, an exception will be thrown.</p> 23463 * 23464 * <p>Note: if the child view uses and updates additional states which are unknown to the 23465 * parent, these states should not be affected by this method.</p> 23466 * 23467 * @param enabled True to enable duplication of the parent's drawable state, false 23468 * to disable it. 23469 * 23470 * @see #getDrawableState() 23471 * @see #isDuplicateParentStateEnabled() 23472 */ setDuplicateParentStateEnabled(boolean enabled)23473 public void setDuplicateParentStateEnabled(boolean enabled) { 23474 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 23475 } 23476 23477 /** 23478 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 23479 * 23480 * @return True if this view's drawable state is duplicated from the parent, 23481 * false otherwise 23482 * 23483 * @see #getDrawableState() 23484 * @see #setDuplicateParentStateEnabled(boolean) 23485 */ 23486 @InspectableProperty(name = "duplicateParentState") isDuplicateParentStateEnabled()23487 public boolean isDuplicateParentStateEnabled() { 23488 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 23489 } 23490 23491 /** 23492 * <p>Specifies the type of layer backing this view. The layer can be 23493 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 23494 * {@link #LAYER_TYPE_HARDWARE}.</p> 23495 * 23496 * <p>A layer is associated with an optional {@link android.graphics.Paint} 23497 * instance that controls how the layer is composed on screen. The following 23498 * properties of the paint are taken into account when composing the layer:</p> 23499 * <ul> 23500 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 23501 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 23502 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 23503 * </ul> 23504 * 23505 * <p>If this view has an alpha value set to < 1.0 by calling 23506 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 23507 * by this view's alpha value.</p> 23508 * 23509 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 23510 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 23511 * for more information on when and how to use layers.</p> 23512 * 23513 * @param layerType The type of layer to use with this view, must be one of 23514 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 23515 * {@link #LAYER_TYPE_HARDWARE} 23516 * @param paint The paint used to compose the layer. This argument is optional 23517 * and can be null. It is ignored when the layer type is 23518 * {@link #LAYER_TYPE_NONE} 23519 * 23520 * @see #getLayerType() 23521 * @see #LAYER_TYPE_NONE 23522 * @see #LAYER_TYPE_SOFTWARE 23523 * @see #LAYER_TYPE_HARDWARE 23524 * @see #setAlpha(float) 23525 * 23526 * @attr ref android.R.styleable#View_layerType 23527 */ setLayerType(@ayerType int layerType, @Nullable Paint paint)23528 public void setLayerType(@LayerType int layerType, @Nullable Paint paint) { 23529 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 23530 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 23531 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 23532 } 23533 23534 boolean typeChanged = mRenderNode.setLayerType(layerType); 23535 23536 if (!typeChanged) { 23537 setLayerPaint(paint); 23538 return; 23539 } 23540 23541 if (layerType != LAYER_TYPE_SOFTWARE) { 23542 // Destroy any previous software drawing cache if present 23543 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 23544 // drawing cache created in View#draw when drawing to a SW canvas. 23545 destroyDrawingCache(); 23546 } 23547 23548 mLayerType = layerType; 23549 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 23550 mRenderNode.setLayerPaint(mLayerPaint); 23551 23552 // draw() behaves differently if we are on a layer, so we need to 23553 // invalidate() here 23554 invalidateParentCaches(); 23555 invalidate(true); 23556 } 23557 23558 /** 23559 * Configure the {@link android.graphics.RenderEffect} to apply to this View. 23560 * This will apply a visual effect to the results of the View before it is drawn. For example if 23561 * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, Shader.TileMode)} 23562 * is provided, the contents will be drawn in a separate layer, then this layer will be blurred 23563 * when this View is drawn. 23564 * @param renderEffect to be applied to the View. Passing null clears the previously configured 23565 * {@link RenderEffect} 23566 */ setRenderEffect(@ullable RenderEffect renderEffect)23567 public void setRenderEffect(@Nullable RenderEffect renderEffect) { 23568 if (mRenderNode.setRenderEffect(renderEffect)) { 23569 invalidateViewProperty(true, true); 23570 } 23571 } 23572 23573 /** 23574 * Configure the {@link android.graphics.RenderEffect} to apply to the backdrop contents of this 23575 * View. This will apply a visual effect to the result of the backdrop contents of this View 23576 * before it is drawn. For example if 23577 * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, Shader.TileMode)} 23578 * is provided, the previous content behind this View will be blurred before this View is drawn. 23579 * @param renderEffect to be applied to the View. Passing null clears the previously configured 23580 * {@link RenderEffect} 23581 * @hide 23582 */ setBackdropRenderEffect(@ullable RenderEffect renderEffect)23583 public void setBackdropRenderEffect(@Nullable RenderEffect renderEffect) { 23584 if (mRenderNode.setBackdropRenderEffect(renderEffect)) { 23585 invalidateViewProperty(true, true); 23586 } 23587 } 23588 23589 /** 23590 * Updates the {@link Paint} object used with the current layer (used only if the current 23591 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 23592 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 23593 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 23594 * ensure that the view gets redrawn immediately. 23595 * 23596 * <p>A layer is associated with an optional {@link android.graphics.Paint} 23597 * instance that controls how the layer is composed on screen. The following 23598 * properties of the paint are taken into account when composing the layer:</p> 23599 * <ul> 23600 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 23601 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 23602 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 23603 * </ul> 23604 * 23605 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 23606 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 23607 * 23608 * @param paint The paint used to compose the layer. This argument is optional 23609 * and can be null. It is ignored when the layer type is 23610 * {@link #LAYER_TYPE_NONE} 23611 * 23612 * @see #setLayerType(int, android.graphics.Paint) 23613 */ setLayerPaint(@ullable Paint paint)23614 public void setLayerPaint(@Nullable Paint paint) { 23615 int layerType = getLayerType(); 23616 if (layerType != LAYER_TYPE_NONE) { 23617 mLayerPaint = paint; 23618 if (layerType == LAYER_TYPE_HARDWARE) { 23619 if (mRenderNode.setLayerPaint(paint)) { 23620 invalidateViewProperty(false, false); 23621 } 23622 } else { 23623 invalidate(); 23624 } 23625 } 23626 } 23627 23628 /** 23629 * Indicates what type of layer is currently associated with this view. By default 23630 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 23631 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 23632 * for more information on the different types of layers. 23633 * 23634 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 23635 * {@link #LAYER_TYPE_HARDWARE} 23636 * 23637 * @see #setLayerType(int, android.graphics.Paint) 23638 * @see #buildLayer() 23639 * @see #LAYER_TYPE_NONE 23640 * @see #LAYER_TYPE_SOFTWARE 23641 * @see #LAYER_TYPE_HARDWARE 23642 */ 23643 @InspectableProperty(enumMapping = { 23644 @EnumEntry(value = LAYER_TYPE_NONE, name = "none"), 23645 @EnumEntry(value = LAYER_TYPE_SOFTWARE, name = "software"), 23646 @EnumEntry(value = LAYER_TYPE_HARDWARE, name = "hardware") 23647 }) 23648 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 23649 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 23650 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 23651 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 23652 }) 23653 @LayerType getLayerType()23654 public int getLayerType() { 23655 return mLayerType; 23656 } 23657 23658 /** 23659 * Forces this view's layer to be created and this view to be rendered 23660 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 23661 * invoking this method will have no effect. 23662 * 23663 * This method can for instance be used to render a view into its layer before 23664 * starting an animation. If this view is complex, rendering into the layer 23665 * before starting the animation will avoid skipping frames. 23666 * 23667 * @throws IllegalStateException If this view is not attached to a window 23668 * 23669 * @see #setLayerType(int, android.graphics.Paint) 23670 */ buildLayer()23671 public void buildLayer() { 23672 if (mLayerType == LAYER_TYPE_NONE) return; 23673 23674 final AttachInfo attachInfo = mAttachInfo; 23675 if (attachInfo == null) { 23676 throw new IllegalStateException("This view must be attached to a window first"); 23677 } 23678 23679 if (getWidth() == 0 || getHeight() == 0) { 23680 return; 23681 } 23682 23683 switch (mLayerType) { 23684 case LAYER_TYPE_HARDWARE: 23685 updateDisplayListIfDirty(); 23686 if (attachInfo.mThreadedRenderer != null && mRenderNode.hasDisplayList()) { 23687 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 23688 } 23689 break; 23690 case LAYER_TYPE_SOFTWARE: 23691 buildDrawingCache(true); 23692 break; 23693 } 23694 } 23695 23696 /** 23697 * Determines whether an unprocessed input event is available on the window. 23698 * 23699 * This is only a performance hint (a.k.a. the Input Hint) and may return false negative 23700 * results. Callers should not rely on availability of the input event based on the return 23701 * value of this method. 23702 * 23703 * The Input Hint functionality is experimental, and can be removed in the future OS releases. 23704 * 23705 * This method only returns nontrivial results on a View that is attached to a Window. Such View 23706 * can be acquired using `Activity.getWindow().getDecorView()`, and only after the view 23707 * hierarchy is attached (via {@link android.app.Activity#setContentView(android.view.View)}). 23708 * 23709 * In multi-window mode the View can provide the Input Hint only for the window it is attached 23710 * to. Therefore, checking input availability for the whole application would require asking 23711 * for the hint from more than one View. 23712 * 23713 * The initial implementation does not return false positives, but callers should not rely on 23714 * it: false positives may occur in future OS releases. 23715 * 23716 * @hide 23717 */ probablyHasInput()23718 public boolean probablyHasInput() { 23719 ViewRootImpl viewRootImpl = getViewRootImpl(); 23720 if (viewRootImpl == null) { 23721 return false; 23722 } 23723 return viewRootImpl.probablyHasInput(); 23724 } 23725 23726 /** 23727 * Destroys all hardware rendering resources. This method is invoked 23728 * when the system needs to reclaim resources. Upon execution of this 23729 * method, you should free any OpenGL resources created by the view. 23730 * 23731 * Note: you <strong>must</strong> call 23732 * <code>super.destroyHardwareResources()</code> when overriding 23733 * this method. 23734 * 23735 * @hide 23736 */ 23737 @CallSuper 23738 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) destroyHardwareResources()23739 protected void destroyHardwareResources() { 23740 if (mOverlay != null) { 23741 mOverlay.getOverlayView().destroyHardwareResources(); 23742 } 23743 if (mGhostView != null) { 23744 mGhostView.destroyHardwareResources(); 23745 } 23746 } 23747 23748 /** 23749 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 23750 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 23751 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 23752 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 23753 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 23754 * null.</p> 23755 * 23756 * <p>Enabling the drawing cache is similar to 23757 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 23758 * acceleration is turned off. When hardware acceleration is turned on, enabling the 23759 * drawing cache has no effect on rendering because the system uses a different mechanism 23760 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 23761 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 23762 * for information on how to enable software and hardware layers.</p> 23763 * 23764 * <p>This API can be used to manually generate 23765 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 23766 * {@link #getDrawingCache()}.</p> 23767 * 23768 * @param enabled true to enable the drawing cache, false otherwise 23769 * 23770 * @see #isDrawingCacheEnabled() 23771 * @see #getDrawingCache() 23772 * @see #buildDrawingCache() 23773 * @see #setLayerType(int, android.graphics.Paint) 23774 * 23775 * @deprecated The view drawing cache was largely made obsolete with the introduction of 23776 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 23777 * layers are largely unnecessary and can easily result in a net loss in performance due to the 23778 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 23779 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 23780 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 23781 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 23782 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 23783 * software-rendered usages are discouraged and have compatibility issues with hardware-only 23784 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 23785 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 23786 * reports or unit testing the {@link PixelCopy} API is recommended. 23787 */ 23788 @Deprecated setDrawingCacheEnabled(boolean enabled)23789 public void setDrawingCacheEnabled(boolean enabled) { 23790 mCachingFailed = false; 23791 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 23792 } 23793 23794 /** 23795 * <p>Indicates whether the drawing cache is enabled for this view.</p> 23796 * 23797 * @return true if the drawing cache is enabled 23798 * 23799 * @see #setDrawingCacheEnabled(boolean) 23800 * @see #getDrawingCache() 23801 * 23802 * @deprecated The view drawing cache was largely made obsolete with the introduction of 23803 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 23804 * layers are largely unnecessary and can easily result in a net loss in performance due to the 23805 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 23806 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 23807 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 23808 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 23809 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 23810 * software-rendered usages are discouraged and have compatibility issues with hardware-only 23811 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 23812 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 23813 * reports or unit testing the {@link PixelCopy} API is recommended. 23814 */ 23815 @Deprecated 23816 @ViewDebug.ExportedProperty(category = "drawing") isDrawingCacheEnabled()23817 public boolean isDrawingCacheEnabled() { 23818 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 23819 } 23820 23821 /** 23822 * Debugging utility which recursively outputs the dirty state of a view and its 23823 * descendants. 23824 * 23825 * @hide 23826 */ 23827 @SuppressWarnings({"UnusedDeclaration"}) outputDirtyFlags(String indent, boolean clear, int clearMask)23828 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 23829 Log.d(VIEW_LOG_TAG, indent + this + " DIRTY(" 23830 + (mPrivateFlags & View.PFLAG_DIRTY_MASK) 23831 + ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" 23832 + (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) 23833 + ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 23834 if (clear) { 23835 mPrivateFlags &= clearMask; 23836 } 23837 if (this instanceof ViewGroup) { 23838 ViewGroup parent = (ViewGroup) this; 23839 final int count = parent.getChildCount(); 23840 for (int i = 0; i < count; i++) { 23841 final View child = parent.getChildAt(i); 23842 child.outputDirtyFlags(indent + " ", clear, clearMask); 23843 } 23844 } 23845 } 23846 23847 /** 23848 * This method is used by ViewGroup to cause its children to restore or recreate their 23849 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 23850 * to recreate its own display list, which would happen if it went through the normal 23851 * draw/dispatchDraw mechanisms. 23852 * 23853 * @hide 23854 */ dispatchGetDisplayList()23855 protected void dispatchGetDisplayList() {} 23856 23857 /** 23858 * A view that is not attached or hardware accelerated cannot create a display list. 23859 * This method checks these conditions and returns the appropriate result. 23860 * 23861 * @return true if view has the ability to create a display list, false otherwise. 23862 * 23863 * @hide 23864 */ canHaveDisplayList()23865 public boolean canHaveDisplayList() { 23866 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 23867 } 23868 23869 /** 23870 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 23871 * @hide 23872 */ 23873 @NonNull 23874 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) updateDisplayListIfDirty()23875 public RenderNode updateDisplayListIfDirty() { 23876 final RenderNode renderNode = mRenderNode; 23877 if (!canHaveDisplayList()) { 23878 // can't populate RenderNode, don't try 23879 return renderNode; 23880 } 23881 23882 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 23883 || !renderNode.hasDisplayList() 23884 || (mRecreateDisplayList)) { 23885 // Don't need to recreate the display list, just need to tell our 23886 // children to restore/recreate theirs 23887 if (renderNode.hasDisplayList() 23888 && !mRecreateDisplayList) { 23889 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 23890 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 23891 dispatchGetDisplayList(); 23892 23893 return renderNode; // no work needed 23894 } 23895 23896 // If we got here, we're recreating it. Mark it as such to ensure that 23897 // we copy in child display lists into ours in drawChild() 23898 mRecreateDisplayList = true; 23899 23900 int width = mRight - mLeft; 23901 int height = mBottom - mTop; 23902 int layerType = getLayerType(); 23903 23904 // Hacky hack: Reset any stretch effects as those are applied during the draw pass 23905 // instead of being "stateful" like other RenderNode properties 23906 renderNode.clearStretch(); 23907 23908 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 23909 23910 try { 23911 if (layerType == LAYER_TYPE_SOFTWARE) { 23912 buildDrawingCache(true); 23913 Bitmap cache = getDrawingCache(true); 23914 if (cache != null) { 23915 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 23916 } 23917 } else { 23918 computeScroll(); 23919 23920 canvas.translate(-mScrollX, -mScrollY); 23921 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 23922 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 23923 23924 mPrivateFlags4 |= PFLAG4_HAS_DRAWN; 23925 23926 // Fast path for layouts with no backgrounds 23927 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 23928 dispatchDraw(canvas); 23929 drawAutofilledHighlight(canvas); 23930 if (mOverlay != null && !mOverlay.isEmpty()) { 23931 mOverlay.getOverlayView().draw(canvas); 23932 } 23933 if (isShowingLayoutBounds()) { 23934 debugDrawFocus(canvas); 23935 } 23936 } else { 23937 draw(canvas); 23938 } 23939 23940 // For VRR to vote the preferred frame rate 23941 if (sToolkitSetFrameRateReadOnlyFlagValue 23942 && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { 23943 votePreferredFrameRate(); 23944 } 23945 } 23946 } finally { 23947 renderNode.endRecording(); 23948 setDisplayListProperties(renderNode); 23949 } 23950 } else { 23951 if ((mPrivateFlags4 & PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION) 23952 == PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION) { 23953 // For VRR to vote the preferred frame rate 23954 if (sToolkitSetFrameRateReadOnlyFlagValue 23955 && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { 23956 votePreferredFrameRate(); 23957 } 23958 mPrivateFlags4 &= ~PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION; 23959 } 23960 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 23961 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 23962 } 23963 mPrivateFlags4 &= ~PFLAG4_HAS_MOVED; 23964 mFrameContentVelocity = -1; 23965 return renderNode; 23966 } 23967 23968 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resetDisplayList()23969 private void resetDisplayList() { 23970 mRenderNode.discardDisplayList(); 23971 if (mBackgroundRenderNode != null) { 23972 mBackgroundRenderNode.discardDisplayList(); 23973 } 23974 } 23975 23976 /** 23977 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 23978 * 23979 * @return A non-scaled bitmap representing this view or null if cache is disabled. 23980 * 23981 * @see #getDrawingCache(boolean) 23982 * 23983 * @deprecated The view drawing cache was largely made obsolete with the introduction of 23984 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 23985 * layers are largely unnecessary and can easily result in a net loss in performance due to the 23986 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 23987 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 23988 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 23989 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 23990 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 23991 * software-rendered usages are discouraged and have compatibility issues with hardware-only 23992 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 23993 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 23994 * reports or unit testing the {@link PixelCopy} API is recommended. 23995 */ 23996 @Deprecated getDrawingCache()23997 public Bitmap getDrawingCache() { 23998 return getDrawingCache(false); 23999 } 24000 24001 /** 24002 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 24003 * is null when caching is disabled. If caching is enabled and the cache is not ready, 24004 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 24005 * draw from the cache when the cache is enabled. To benefit from the cache, you must 24006 * request the drawing cache by calling this method and draw it on screen if the 24007 * returned bitmap is not null.</p> 24008 * 24009 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 24010 * this method will create a bitmap of the same size as this view. Because this bitmap 24011 * will be drawn scaled by the parent ViewGroup, the result on screen might show 24012 * scaling artifacts. To avoid such artifacts, you should call this method by setting 24013 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 24014 * size than the view. This implies that your application must be able to handle this 24015 * size.</p> 24016 * 24017 * @param autoScale Indicates whether the generated bitmap should be scaled based on 24018 * the current density of the screen when the application is in compatibility 24019 * mode. 24020 * 24021 * @return A bitmap representing this view or null if cache is disabled. 24022 * 24023 * @see #setDrawingCacheEnabled(boolean) 24024 * @see #isDrawingCacheEnabled() 24025 * @see #buildDrawingCache(boolean) 24026 * @see #destroyDrawingCache() 24027 * 24028 * @deprecated The view drawing cache was largely made obsolete with the introduction of 24029 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 24030 * layers are largely unnecessary and can easily result in a net loss in performance due to the 24031 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 24032 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 24033 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 24034 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 24035 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 24036 * software-rendered usages are discouraged and have compatibility issues with hardware-only 24037 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 24038 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 24039 * reports or unit testing the {@link PixelCopy} API is recommended. 24040 */ 24041 @Deprecated getDrawingCache(boolean autoScale)24042 public Bitmap getDrawingCache(boolean autoScale) { 24043 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 24044 return null; 24045 } 24046 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 24047 buildDrawingCache(autoScale); 24048 } 24049 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 24050 } 24051 24052 /** 24053 * <p>Frees the resources used by the drawing cache. If you call 24054 * {@link #buildDrawingCache()} manually without calling 24055 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 24056 * should cleanup the cache with this method afterwards.</p> 24057 * 24058 * @see #setDrawingCacheEnabled(boolean) 24059 * @see #buildDrawingCache() 24060 * @see #getDrawingCache() 24061 * 24062 * @deprecated The view drawing cache was largely made obsolete with the introduction of 24063 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 24064 * layers are largely unnecessary and can easily result in a net loss in performance due to the 24065 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 24066 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 24067 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 24068 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 24069 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 24070 * software-rendered usages are discouraged and have compatibility issues with hardware-only 24071 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 24072 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 24073 * reports or unit testing the {@link PixelCopy} API is recommended. 24074 */ 24075 @Deprecated destroyDrawingCache()24076 public void destroyDrawingCache() { 24077 if (mDrawingCache != null) { 24078 mDrawingCache.recycle(); 24079 mDrawingCache = null; 24080 } 24081 if (mUnscaledDrawingCache != null) { 24082 mUnscaledDrawingCache.recycle(); 24083 mUnscaledDrawingCache = null; 24084 } 24085 } 24086 24087 /** 24088 * Setting a solid background color for the drawing cache's bitmaps will improve 24089 * performance and memory usage. Note, though that this should only be used if this 24090 * view will always be drawn on top of a solid color. 24091 * 24092 * @param color The background color to use for the drawing cache's bitmap 24093 * 24094 * @see #setDrawingCacheEnabled(boolean) 24095 * @see #buildDrawingCache() 24096 * @see #getDrawingCache() 24097 * 24098 * @deprecated The view drawing cache was largely made obsolete with the introduction of 24099 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 24100 * layers are largely unnecessary and can easily result in a net loss in performance due to the 24101 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 24102 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 24103 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 24104 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 24105 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 24106 * software-rendered usages are discouraged and have compatibility issues with hardware-only 24107 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 24108 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 24109 * reports or unit testing the {@link PixelCopy} API is recommended. 24110 */ 24111 @Deprecated setDrawingCacheBackgroundColor(@olorInt int color)24112 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 24113 if (color != mDrawingCacheBackgroundColor) { 24114 mDrawingCacheBackgroundColor = color; 24115 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 24116 } 24117 } 24118 24119 /** 24120 * @see #setDrawingCacheBackgroundColor(int) 24121 * 24122 * @return The background color to used for the drawing cache's bitmap 24123 * 24124 * @deprecated The view drawing cache was largely made obsolete with the introduction of 24125 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 24126 * layers are largely unnecessary and can easily result in a net loss in performance due to the 24127 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 24128 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 24129 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 24130 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 24131 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 24132 * software-rendered usages are discouraged and have compatibility issues with hardware-only 24133 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 24134 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 24135 * reports or unit testing the {@link PixelCopy} API is recommended. 24136 */ 24137 @Deprecated 24138 @ColorInt getDrawingCacheBackgroundColor()24139 public int getDrawingCacheBackgroundColor() { 24140 return mDrawingCacheBackgroundColor; 24141 } 24142 24143 /** 24144 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 24145 * 24146 * @see #buildDrawingCache(boolean) 24147 * 24148 * @deprecated The view drawing cache was largely made obsolete with the introduction of 24149 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 24150 * layers are largely unnecessary and can easily result in a net loss in performance due to the 24151 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 24152 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 24153 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 24154 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 24155 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 24156 * software-rendered usages are discouraged and have compatibility issues with hardware-only 24157 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 24158 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 24159 * reports or unit testing the {@link PixelCopy} API is recommended. 24160 */ 24161 @Deprecated buildDrawingCache()24162 public void buildDrawingCache() { 24163 buildDrawingCache(false); 24164 } 24165 24166 /** 24167 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 24168 * 24169 * <p>If you call {@link #buildDrawingCache()} manually without calling 24170 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 24171 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 24172 * 24173 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 24174 * this method will create a bitmap of the same size as this view. Because this bitmap 24175 * will be drawn scaled by the parent ViewGroup, the result on screen might show 24176 * scaling artifacts. To avoid such artifacts, you should call this method by setting 24177 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 24178 * size than the view. This implies that your application must be able to handle this 24179 * size.</p> 24180 * 24181 * <p>You should avoid calling this method when hardware acceleration is enabled. If 24182 * you do not need the drawing cache bitmap, calling this method will increase memory 24183 * usage and cause the view to be rendered in software once, thus negatively impacting 24184 * performance.</p> 24185 * 24186 * @see #getDrawingCache() 24187 * @see #destroyDrawingCache() 24188 * 24189 * @deprecated The view drawing cache was largely made obsolete with the introduction of 24190 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 24191 * layers are largely unnecessary and can easily result in a net loss in performance due to the 24192 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 24193 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 24194 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 24195 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 24196 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 24197 * software-rendered usages are discouraged and have compatibility issues with hardware-only 24198 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 24199 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 24200 * reports or unit testing the {@link PixelCopy} API is recommended. 24201 */ 24202 @Deprecated buildDrawingCache(boolean autoScale)24203 public void buildDrawingCache(boolean autoScale) { 24204 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 24205 mDrawingCache == null : mUnscaledDrawingCache == null)) { 24206 if (Trace.isTagEnabled(TRACE_TAG_VIEW)) { 24207 Trace.traceBegin(TRACE_TAG_VIEW, 24208 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 24209 } 24210 try { 24211 buildDrawingCacheImpl(autoScale); 24212 } finally { 24213 Trace.traceEnd(TRACE_TAG_VIEW); 24214 } 24215 } 24216 } 24217 24218 /** 24219 * private, internal implementation of buildDrawingCache, used to enable tracing 24220 */ buildDrawingCacheImpl(boolean autoScale)24221 private void buildDrawingCacheImpl(boolean autoScale) { 24222 mCachingFailed = false; 24223 24224 int width = mRight - mLeft; 24225 int height = mBottom - mTop; 24226 24227 final AttachInfo attachInfo = mAttachInfo; 24228 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 24229 24230 if (autoScale && scalingRequired) { 24231 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 24232 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 24233 } 24234 24235 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 24236 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 24237 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 24238 24239 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 24240 final long drawingCacheSize = 24241 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 24242 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 24243 if (width > 0 && height > 0) { 24244 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 24245 + " too large to fit into a software layer (or drawing cache), needs " 24246 + projectedBitmapSize + " bytes, only " 24247 + drawingCacheSize + " available"); 24248 } 24249 destroyDrawingCache(); 24250 mCachingFailed = true; 24251 return; 24252 } 24253 24254 boolean clear = true; 24255 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 24256 24257 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 24258 Bitmap.Config quality; 24259 if (!opaque) { 24260 // Never pick ARGB_4444 because it looks awful 24261 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 24262 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 24263 case DRAWING_CACHE_QUALITY_AUTO: 24264 case DRAWING_CACHE_QUALITY_LOW: 24265 case DRAWING_CACHE_QUALITY_HIGH: 24266 default: 24267 quality = Bitmap.Config.ARGB_8888; 24268 break; 24269 } 24270 } else { 24271 // Optimization for translucent windows 24272 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 24273 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 24274 } 24275 24276 // Try to cleanup memory 24277 if (bitmap != null) bitmap.recycle(); 24278 24279 try { 24280 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 24281 width, height, quality); 24282 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 24283 if (autoScale) { 24284 mDrawingCache = bitmap; 24285 } else { 24286 mUnscaledDrawingCache = bitmap; 24287 } 24288 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 24289 } catch (OutOfMemoryError e) { 24290 // If there is not enough memory to create the bitmap cache, just 24291 // ignore the issue as bitmap caches are not required to draw the 24292 // view hierarchy 24293 if (autoScale) { 24294 mDrawingCache = null; 24295 } else { 24296 mUnscaledDrawingCache = null; 24297 } 24298 mCachingFailed = true; 24299 return; 24300 } 24301 24302 clear = drawingCacheBackgroundColor != 0; 24303 } 24304 24305 Canvas canvas; 24306 if (attachInfo != null) { 24307 canvas = attachInfo.mCanvas; 24308 if (canvas == null) { 24309 canvas = new Canvas(); 24310 } 24311 canvas.setBitmap(bitmap); 24312 // Temporarily clobber the cached Canvas in case one of our children 24313 // is also using a drawing cache. Without this, the children would 24314 // steal the canvas by attaching their own bitmap to it and bad, bad 24315 // thing would happen (invisible views, corrupted drawings, etc.) 24316 attachInfo.mCanvas = null; 24317 } else { 24318 // This case should hopefully never or seldom happen 24319 canvas = new Canvas(bitmap); 24320 } 24321 24322 if (clear) { 24323 bitmap.eraseColor(drawingCacheBackgroundColor); 24324 } 24325 24326 computeScroll(); 24327 final int restoreCount = canvas.save(); 24328 24329 if (autoScale && scalingRequired) { 24330 final float scale = attachInfo.mApplicationScale; 24331 canvas.scale(scale, scale); 24332 } 24333 24334 canvas.translate(-mScrollX, -mScrollY); 24335 24336 mPrivateFlags |= PFLAG_DRAWN; 24337 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 24338 mLayerType != LAYER_TYPE_NONE) { 24339 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 24340 } 24341 24342 // Fast path for layouts with no backgrounds 24343 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 24344 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 24345 dispatchDraw(canvas); 24346 drawAutofilledHighlight(canvas); 24347 if (mOverlay != null && !mOverlay.isEmpty()) { 24348 mOverlay.getOverlayView().draw(canvas); 24349 } 24350 } else { 24351 draw(canvas); 24352 } 24353 24354 canvas.restoreToCount(restoreCount); 24355 canvas.setBitmap(null); 24356 24357 if (attachInfo != null) { 24358 // Restore the cached Canvas for our siblings 24359 attachInfo.mCanvas = canvas; 24360 } 24361 } 24362 24363 /** 24364 * Create a snapshot of the view into a bitmap. We should probably make 24365 * some form of this public, but should think about the API. 24366 * 24367 * @hide 24368 */ 24369 @UnsupportedAppUsage createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren)24370 public Bitmap createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren) { 24371 int width = mRight - mLeft; 24372 int height = mBottom - mTop; 24373 24374 final AttachInfo attachInfo = mAttachInfo; 24375 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 24376 width = (int) ((width * scale) + 0.5f); 24377 height = (int) ((height * scale) + 0.5f); 24378 24379 Canvas oldCanvas = null; 24380 try { 24381 Canvas canvas = canvasProvider.getCanvas(this, 24382 width > 0 ? width : 1, height > 0 ? height : 1); 24383 24384 if (attachInfo != null) { 24385 oldCanvas = attachInfo.mCanvas; 24386 // Temporarily clobber the cached Canvas in case one of our children 24387 // is also using a drawing cache. Without this, the children would 24388 // steal the canvas by attaching their own bitmap to it and bad, bad 24389 // things would happen (invisible views, corrupted drawings, etc.) 24390 attachInfo.mCanvas = null; 24391 } 24392 24393 computeScroll(); 24394 final int restoreCount = canvas.save(); 24395 canvas.scale(scale, scale); 24396 canvas.translate(-mScrollX, -mScrollY); 24397 24398 // Temporarily remove the dirty mask 24399 int flags = mPrivateFlags; 24400 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 24401 24402 // Fast path for layouts with no backgrounds 24403 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 24404 dispatchDraw(canvas); 24405 drawAutofilledHighlight(canvas); 24406 if (mOverlay != null && !mOverlay.isEmpty()) { 24407 mOverlay.getOverlayView().draw(canvas); 24408 } 24409 } else { 24410 draw(canvas); 24411 } 24412 24413 mPrivateFlags = flags; 24414 canvas.restoreToCount(restoreCount); 24415 return canvasProvider.createBitmap(); 24416 } finally { 24417 if (oldCanvas != null) { 24418 attachInfo.mCanvas = oldCanvas; 24419 } 24420 } 24421 } 24422 24423 /** 24424 * Indicates whether this View is currently in edit mode. A View is usually 24425 * in edit mode when displayed within a developer tool. For instance, if 24426 * this View is being drawn by a visual user interface builder, this method 24427 * should return true. 24428 * 24429 * Subclasses should check the return value of this method to provide 24430 * different behaviors if their normal behavior might interfere with the 24431 * host environment. For instance: the class spawns a thread in its 24432 * constructor, the drawing code relies on device-specific features, etc. 24433 * 24434 * This method is usually checked in the drawing code of custom widgets. 24435 * 24436 * @return True if this View is in edit mode, false otherwise. 24437 */ isInEditMode()24438 public boolean isInEditMode() { 24439 return false; 24440 } 24441 24442 /** 24443 * If the View draws content inside its padding and enables fading edges, 24444 * it needs to support padding offsets. Padding offsets are added to the 24445 * fading edges to extend the length of the fade so that it covers pixels 24446 * drawn inside the padding. 24447 * 24448 * Subclasses of this class should override this method if they need 24449 * to draw content inside the padding. 24450 * 24451 * @return True if padding offset must be applied, false otherwise. 24452 * 24453 * @see #getLeftPaddingOffset() 24454 * @see #getRightPaddingOffset() 24455 * @see #getTopPaddingOffset() 24456 * @see #getBottomPaddingOffset() 24457 * 24458 * @since CURRENT 24459 */ isPaddingOffsetRequired()24460 protected boolean isPaddingOffsetRequired() { 24461 return false; 24462 } 24463 24464 /** 24465 * Amount by which to extend the left fading region. Called only when 24466 * {@link #isPaddingOffsetRequired()} returns true. 24467 * 24468 * @return The left padding offset in pixels. 24469 * 24470 * @see #isPaddingOffsetRequired() 24471 * 24472 * @since CURRENT 24473 */ getLeftPaddingOffset()24474 protected int getLeftPaddingOffset() { 24475 return 0; 24476 } 24477 24478 /** 24479 * Amount by which to extend the right fading region. Called only when 24480 * {@link #isPaddingOffsetRequired()} returns true. 24481 * 24482 * @return The right padding offset in pixels. 24483 * 24484 * @see #isPaddingOffsetRequired() 24485 * 24486 * @since CURRENT 24487 */ getRightPaddingOffset()24488 protected int getRightPaddingOffset() { 24489 return 0; 24490 } 24491 24492 /** 24493 * Amount by which to extend the top fading region. Called only when 24494 * {@link #isPaddingOffsetRequired()} returns true. 24495 * 24496 * @return The top padding offset in pixels. 24497 * 24498 * @see #isPaddingOffsetRequired() 24499 * 24500 * @since CURRENT 24501 */ getTopPaddingOffset()24502 protected int getTopPaddingOffset() { 24503 return 0; 24504 } 24505 24506 /** 24507 * Amount by which to extend the bottom fading region. Called only when 24508 * {@link #isPaddingOffsetRequired()} returns true. 24509 * 24510 * @return The bottom padding offset in pixels. 24511 * 24512 * @see #isPaddingOffsetRequired() 24513 * 24514 * @since CURRENT 24515 */ getBottomPaddingOffset()24516 protected int getBottomPaddingOffset() { 24517 return 0; 24518 } 24519 24520 /** 24521 * @hide 24522 * @param offsetRequired 24523 */ getFadeTop(boolean offsetRequired)24524 protected int getFadeTop(boolean offsetRequired) { 24525 int top = mPaddingTop; 24526 if (offsetRequired) top += getTopPaddingOffset(); 24527 return top; 24528 } 24529 24530 /** 24531 * @hide 24532 * @param offsetRequired 24533 */ getFadeHeight(boolean offsetRequired)24534 protected int getFadeHeight(boolean offsetRequired) { 24535 int padding = mPaddingTop; 24536 if (offsetRequired) padding += getTopPaddingOffset(); 24537 return mBottom - mTop - mPaddingBottom - padding; 24538 } 24539 24540 /** 24541 * <p>Indicates whether this view is attached to a hardware accelerated 24542 * window or not.</p> 24543 * 24544 * <p>Even if this method returns true, it does not mean that every call 24545 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 24546 * accelerated {@link android.graphics.Canvas}. For instance, if this view 24547 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 24548 * window is hardware accelerated, 24549 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 24550 * return false, and this method will return true.</p> 24551 * 24552 * @return True if the view is attached to a window and the window is 24553 * hardware accelerated; false in any other case. 24554 */ 24555 @ViewDebug.ExportedProperty(category = "drawing") isHardwareAccelerated()24556 public boolean isHardwareAccelerated() { 24557 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 24558 } 24559 24560 /** 24561 * Sets a rectangular area on this view to which the view will be clipped 24562 * when it is drawn. Setting the value to null will remove the clip bounds 24563 * and the view will draw normally, using its full bounds. 24564 * 24565 * @param clipBounds The rectangular area, in the local coordinates of 24566 * this view, to which future drawing operations will be clipped. 24567 */ setClipBounds(Rect clipBounds)24568 public void setClipBounds(Rect clipBounds) { 24569 if (clipBounds == mClipBounds 24570 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 24571 return; 24572 } 24573 if (clipBounds != null) { 24574 if (mClipBounds == null) { 24575 mClipBounds = new Rect(clipBounds); 24576 } else { 24577 mClipBounds.set(clipBounds); 24578 } 24579 } else { 24580 mClipBounds = null; 24581 } 24582 mRenderNode.setClipRect(mClipBounds); 24583 invalidateViewProperty(false, false); 24584 } 24585 24586 /** 24587 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 24588 * 24589 * @return A copy of the current clip bounds if clip bounds are set, 24590 * otherwise null. 24591 */ getClipBounds()24592 public Rect getClipBounds() { 24593 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 24594 } 24595 24596 24597 /** 24598 * Populates an output rectangle with the clip bounds of the view, 24599 * returning {@code true} if successful or {@code false} if the view's 24600 * clip bounds are {@code null}. 24601 * 24602 * @param outRect rectangle in which to place the clip bounds of the view 24603 * @return {@code true} if successful or {@code false} if the view's 24604 * clip bounds are {@code null} 24605 */ getClipBounds(Rect outRect)24606 public boolean getClipBounds(Rect outRect) { 24607 if (mClipBounds != null) { 24608 outRect.set(mClipBounds); 24609 return true; 24610 } 24611 return false; 24612 } 24613 24614 /** 24615 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 24616 * case of an active Animation being run on the view. 24617 */ applyLegacyAnimation(ViewGroup parent, long drawingTime, Animation a, boolean scalingRequired)24618 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 24619 Animation a, boolean scalingRequired) { 24620 Transformation invalidationTransform; 24621 final int flags = parent.mGroupFlags; 24622 final boolean initialized = a.isInitialized(); 24623 if (!initialized) { 24624 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 24625 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 24626 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 24627 onAnimationStart(); 24628 } 24629 24630 final Transformation t = parent.getChildTransformation(); 24631 boolean more = a.getTransformation(drawingTime, t, 1f); 24632 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 24633 if (parent.mInvalidationTransformation == null) { 24634 parent.mInvalidationTransformation = new Transformation(); 24635 } 24636 invalidationTransform = parent.mInvalidationTransformation; 24637 a.getTransformation(drawingTime, invalidationTransform, 1f); 24638 } else { 24639 invalidationTransform = t; 24640 } 24641 24642 // Increase the frame rate if there is a transformation that applies a matrix. 24643 if (sToolkitFrameRateAnimationBugfix25q1FlagValue 24644 && ((t.getTransformationType() & Transformation.TYPE_MATRIX) != 0)) { 24645 mPrivateFlags4 |= PFLAG4_HAS_VIEW_PROPERTY_INVALIDATION; 24646 mPrivateFlags4 |= PFLAG4_HAS_MOVED; 24647 } 24648 24649 if (more) { 24650 if (!a.willChangeBounds()) { 24651 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 24652 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 24653 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 24654 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 24655 // The child need to draw an animation, potentially offscreen, so 24656 // make sure we do not cancel invalidate requests 24657 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 24658 parent.invalidate(mLeft, mTop, mRight, mBottom); 24659 } 24660 } else { 24661 if (parent.mInvalidateRegion == null) { 24662 parent.mInvalidateRegion = new RectF(); 24663 } 24664 final RectF region = parent.mInvalidateRegion; 24665 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 24666 invalidationTransform); 24667 24668 // The child need to draw an animation, potentially offscreen, so 24669 // make sure we do not cancel invalidate requests 24670 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 24671 24672 final int left = mLeft + (int) region.left; 24673 final int top = mTop + (int) region.top; 24674 parent.invalidate(left, top, left + (int) (region.width() + .5f), 24675 top + (int) (region.height() + .5f)); 24676 } 24677 } 24678 return more; 24679 } 24680 24681 /** 24682 * This method is called by getDisplayList() when a display list is recorded for a View. 24683 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 24684 */ setDisplayListProperties(RenderNode renderNode)24685 void setDisplayListProperties(RenderNode renderNode) { 24686 if (renderNode != null) { 24687 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 24688 renderNode.setClipToBounds(mParent instanceof ViewGroup 24689 && ((ViewGroup) mParent).getClipChildren()); 24690 24691 float alpha = 1; 24692 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 24693 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 24694 ViewGroup parentVG = (ViewGroup) mParent; 24695 final Transformation t = parentVG.getChildTransformation(); 24696 if (parentVG.getChildStaticTransformation(this, t)) { 24697 final int transformType = t.getTransformationType(); 24698 if (transformType != Transformation.TYPE_IDENTITY) { 24699 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 24700 alpha = t.getAlpha(); 24701 } 24702 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 24703 renderNode.setStaticMatrix(t.getMatrix()); 24704 } 24705 } 24706 } 24707 } 24708 if (mTransformationInfo != null) { 24709 alpha *= getFinalAlpha(); 24710 if (alpha < 1) { 24711 final int multipliedAlpha = (int) (255 * alpha); 24712 if (onSetAlpha(multipliedAlpha)) { 24713 alpha = 1; 24714 } 24715 } 24716 renderNode.setAlpha(alpha); 24717 } else if (alpha < 1) { 24718 renderNode.setAlpha(alpha); 24719 } 24720 } 24721 } 24722 24723 /** 24724 * If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 24725 * 24726 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 24727 * HW accelerated, it can't handle drawing RenderNodes. 24728 * 24729 * @hide 24730 */ drawsWithRenderNode(@onNull Canvas canvas)24731 protected final boolean drawsWithRenderNode(@NonNull Canvas canvas) { 24732 return mAttachInfo != null 24733 && mAttachInfo.mHardwareAccelerated 24734 && canvas.isHardwareAccelerated(); 24735 } 24736 24737 /** 24738 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 24739 * 24740 * This is where the View specializes rendering behavior based on layer type, 24741 * and hardware acceleration. 24742 */ draw(@onNull Canvas canvas, ViewGroup parent, long drawingTime)24743 boolean draw(@NonNull Canvas canvas, ViewGroup parent, long drawingTime) { 24744 24745 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 24746 24747 boolean drawingWithRenderNode = drawsWithRenderNode(canvas); 24748 24749 boolean more = false; 24750 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 24751 final int parentFlags = parent.mGroupFlags; 24752 24753 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 24754 parent.getChildTransformation().clear(); 24755 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 24756 } 24757 24758 Transformation transformToApply = null; 24759 boolean concatMatrix = false; 24760 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 24761 final Animation a = getAnimation(); 24762 if (a != null) { 24763 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 24764 concatMatrix = a.willChangeTransformationMatrix(); 24765 if (concatMatrix) { 24766 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 24767 } 24768 transformToApply = parent.getChildTransformation(); 24769 } else { 24770 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 24771 // No longer animating: clear out old animation matrix 24772 mRenderNode.setAnimationMatrix(null); 24773 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 24774 } 24775 if (!drawingWithRenderNode 24776 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 24777 final Transformation t = parent.getChildTransformation(); 24778 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 24779 if (hasTransform) { 24780 final int transformType = t.getTransformationType(); 24781 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 24782 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 24783 } 24784 } 24785 } 24786 24787 concatMatrix |= !childHasIdentityMatrix; 24788 24789 // Sets the flag as early as possible to allow draw() implementations 24790 // to call invalidate() successfully when doing animations 24791 mPrivateFlags |= PFLAG_DRAWN; 24792 24793 if (!concatMatrix && 24794 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 24795 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 24796 canvas.quickReject(mLeft, mTop, mRight, mBottom) && 24797 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 24798 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 24799 return more; 24800 } 24801 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 24802 24803 if (hardwareAcceleratedCanvas) { 24804 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 24805 // retain the flag's value temporarily in the mRecreateDisplayList flag 24806 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 24807 mPrivateFlags &= ~PFLAG_INVALIDATED; 24808 } 24809 24810 RenderNode renderNode = null; 24811 Bitmap cache = null; 24812 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 24813 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 24814 if (layerType != LAYER_TYPE_NONE) { 24815 // If not drawing with RenderNode, treat HW layers as SW 24816 layerType = LAYER_TYPE_SOFTWARE; 24817 buildDrawingCache(true); 24818 } 24819 cache = getDrawingCache(true); 24820 } 24821 24822 if (drawingWithRenderNode) { 24823 // Delay getting the display list until animation-driven alpha values are 24824 // set up and possibly passed on to the view 24825 renderNode = updateDisplayListIfDirty(); 24826 if (!renderNode.hasDisplayList()) { 24827 // Uncommon, but possible. If a view is removed from the hierarchy during the call 24828 // to getDisplayList(), the display list will be marked invalid and we should not 24829 // try to use it again. 24830 renderNode = null; 24831 drawingWithRenderNode = false; 24832 } 24833 } 24834 24835 int sx = 0; 24836 int sy = 0; 24837 if (!drawingWithRenderNode) { 24838 computeScroll(); 24839 sx = mScrollX; 24840 sy = mScrollY; 24841 } 24842 24843 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 24844 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 24845 24846 int restoreTo = -1; 24847 if (!drawingWithRenderNode || transformToApply != null) { 24848 restoreTo = canvas.save(); 24849 } 24850 if (offsetForScroll) { 24851 canvas.translate(mLeft - sx, mTop - sy); 24852 } else { 24853 if (!drawingWithRenderNode) { 24854 canvas.translate(mLeft, mTop); 24855 } 24856 if (scalingRequired) { 24857 if (drawingWithRenderNode) { 24858 // TODO: Might not need this if we put everything inside the DL 24859 restoreTo = canvas.save(); 24860 } 24861 // mAttachInfo cannot be null, otherwise scalingRequired == false 24862 final float scale = 1.0f / mAttachInfo.mApplicationScale; 24863 canvas.scale(scale, scale); 24864 } 24865 } 24866 24867 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 24868 if (transformToApply != null 24869 || alpha < 1 24870 || !hasIdentityMatrix() 24871 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 24872 if (transformToApply != null || !childHasIdentityMatrix) { 24873 int transX = 0; 24874 int transY = 0; 24875 24876 if (offsetForScroll) { 24877 transX = -sx; 24878 transY = -sy; 24879 } 24880 24881 if (transformToApply != null) { 24882 if (concatMatrix) { 24883 if (drawingWithRenderNode) { 24884 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 24885 } else { 24886 // Undo the scroll translation, apply the transformation matrix, 24887 // then redo the scroll translate to get the correct result. 24888 canvas.translate(-transX, -transY); 24889 canvas.concat(transformToApply.getMatrix()); 24890 canvas.translate(transX, transY); 24891 } 24892 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 24893 } 24894 24895 float transformAlpha = transformToApply.getAlpha(); 24896 if (transformAlpha < 1) { 24897 alpha *= transformAlpha; 24898 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 24899 } 24900 } 24901 24902 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 24903 canvas.translate(-transX, -transY); 24904 canvas.concat(getMatrix()); 24905 canvas.translate(transX, transY); 24906 } 24907 } 24908 24909 // Deal with alpha if it is or used to be <1 24910 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 24911 if (alpha < 1) { 24912 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 24913 } else { 24914 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 24915 } 24916 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 24917 if (!drawingWithDrawingCache) { 24918 final int multipliedAlpha = (int) (255 * alpha); 24919 if (!onSetAlpha(multipliedAlpha)) { 24920 if (drawingWithRenderNode) { 24921 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 24922 } else if (layerType == LAYER_TYPE_NONE) { 24923 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 24924 multipliedAlpha); 24925 } 24926 } else { 24927 // Alpha is handled by the child directly, clobber the layer's alpha 24928 mPrivateFlags |= PFLAG_ALPHA_SET; 24929 } 24930 } 24931 } 24932 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 24933 onSetAlpha(255); 24934 mPrivateFlags &= ~PFLAG_ALPHA_SET; 24935 } 24936 24937 if (!drawingWithRenderNode) { 24938 // apply clips directly, since RenderNode won't do it for this draw 24939 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 24940 if (offsetForScroll) { 24941 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 24942 } else { 24943 if (!scalingRequired || cache == null) { 24944 canvas.clipRect(0, 0, getWidth(), getHeight()); 24945 } else { 24946 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 24947 } 24948 } 24949 } 24950 24951 if (mClipBounds != null) { 24952 // clip bounds ignore scroll 24953 canvas.clipRect(mClipBounds); 24954 } 24955 } 24956 24957 if (!drawingWithDrawingCache) { 24958 if (drawingWithRenderNode) { 24959 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 24960 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 24961 } else { 24962 // Fast path for layouts with no backgrounds 24963 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 24964 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 24965 dispatchDraw(canvas); 24966 } else { 24967 draw(canvas); 24968 } 24969 } 24970 } else if (cache != null) { 24971 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 24972 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 24973 // no layer paint, use temporary paint to draw bitmap 24974 Paint cachePaint = parent.mCachePaint; 24975 if (cachePaint == null) { 24976 cachePaint = new Paint(); 24977 cachePaint.setDither(false); 24978 parent.mCachePaint = cachePaint; 24979 } 24980 cachePaint.setAlpha((int) (alpha * 255)); 24981 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 24982 } else { 24983 // use layer paint to draw the bitmap, merging the two alphas, but also restore 24984 int layerPaintAlpha = mLayerPaint.getAlpha(); 24985 if (alpha < 1) { 24986 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 24987 } 24988 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 24989 if (alpha < 1) { 24990 mLayerPaint.setAlpha(layerPaintAlpha); 24991 } 24992 } 24993 } 24994 24995 if (restoreTo >= 0) { 24996 canvas.restoreToCount(restoreTo); 24997 } 24998 24999 if (a != null && !more) { 25000 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 25001 onSetAlpha(255); 25002 } 25003 parent.finishAnimatingView(this, a); 25004 } 25005 25006 if (more && hardwareAcceleratedCanvas) { 25007 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 25008 // alpha animations should cause the child to recreate its display list 25009 invalidate(true); 25010 } 25011 } 25012 25013 mRecreateDisplayList = false; 25014 25015 return more; 25016 } 25017 getDebugPaint()25018 static Paint getDebugPaint() { 25019 if (sDebugPaint == null) { 25020 sDebugPaint = new Paint(); 25021 sDebugPaint.setAntiAlias(false); 25022 } 25023 return sDebugPaint; 25024 } 25025 dipsToPixels(int dips)25026 final int dipsToPixels(int dips) { 25027 float scale = getContext().getResources().getDisplayMetrics().density; 25028 return (int) (dips * scale + 0.5f); 25029 } 25030 debugDrawFocus(@onNull Canvas canvas)25031 private void debugDrawFocus(@NonNull Canvas canvas) { 25032 if (isFocused()) { 25033 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 25034 final int l = mScrollX; 25035 final int r = l + mRight - mLeft; 25036 final int t = mScrollY; 25037 final int b = t + mBottom - mTop; 25038 25039 final Paint paint = getDebugPaint(); 25040 paint.setColor(DEBUG_CORNERS_COLOR); 25041 25042 // Draw squares in corners. 25043 paint.setStyle(Paint.Style.FILL); 25044 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 25045 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 25046 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 25047 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 25048 25049 // Draw big X across the view. 25050 paint.setStyle(Paint.Style.STROKE); 25051 canvas.drawLine(l, t, r, b, paint); 25052 canvas.drawLine(l, b, r, t, paint); 25053 } 25054 } 25055 25056 /** 25057 * Manually render this view (and all of its children) to the given Canvas. 25058 * The view must have already done a full layout before this function is 25059 * called. When implementing a view, implement 25060 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 25061 * If you do need to override this method, call the superclass version. 25062 * 25063 * @param canvas The Canvas to which the View is rendered. 25064 */ 25065 @CallSuper draw(@onNull Canvas canvas)25066 public void draw(@NonNull Canvas canvas) { 25067 final int privateFlags = mPrivateFlags; 25068 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 25069 25070 /* 25071 * Draw traversal performs several drawing steps which must be executed 25072 * in the appropriate order: 25073 * 25074 * 1. Draw the background 25075 * 2. If necessary, save the canvas' layers to prepare for fading 25076 * 3. Draw view's content 25077 * 4. Draw children 25078 * 5. If necessary, draw the fading edges and restore layers 25079 * 6. Draw decorations (scrollbars for instance) 25080 * 7. If necessary, draw the default focus highlight 25081 */ 25082 25083 // Step 1, draw the background, if needed 25084 int saveCount; 25085 25086 drawBackground(canvas); 25087 25088 // skip step 2 & 5 if possible (common case) 25089 final int viewFlags = mViewFlags; 25090 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 25091 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 25092 if (!verticalEdges && !horizontalEdges) { 25093 // Step 3, draw the content 25094 onDraw(canvas); 25095 25096 // Step 4, draw the children 25097 dispatchDraw(canvas); 25098 25099 drawAutofilledHighlight(canvas); 25100 25101 // Overlay is part of the content and draws beneath Foreground 25102 if (mOverlay != null && !mOverlay.isEmpty()) { 25103 mOverlay.getOverlayView().dispatchDraw(canvas); 25104 } 25105 25106 // Step 6, draw decorations (foreground, scrollbars) 25107 onDrawForeground(canvas); 25108 25109 // Step 7, draw the default focus highlight 25110 drawDefaultFocusHighlight(canvas); 25111 25112 if (isShowingLayoutBounds()) { 25113 debugDrawFocus(canvas); 25114 } 25115 25116 // we're done... 25117 return; 25118 } 25119 25120 /* 25121 * Here we do the full fledged routine... 25122 * (this is an uncommon case where speed matters less, 25123 * this is why we repeat some of the tests that have been 25124 * done above) 25125 */ 25126 25127 boolean drawTop = false; 25128 boolean drawBottom = false; 25129 boolean drawLeft = false; 25130 boolean drawRight = false; 25131 25132 float topFadeStrength = 0.0f; 25133 float bottomFadeStrength = 0.0f; 25134 float leftFadeStrength = 0.0f; 25135 float rightFadeStrength = 0.0f; 25136 25137 // Step 2, save the canvas' layers 25138 int paddingLeft = mPaddingLeft; 25139 25140 final boolean offsetRequired = isPaddingOffsetRequired(); 25141 if (offsetRequired) { 25142 paddingLeft += getLeftPaddingOffset(); 25143 } 25144 25145 int left = mScrollX + paddingLeft; 25146 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 25147 int top = mScrollY + getFadeTop(offsetRequired); 25148 int bottom = top + getFadeHeight(offsetRequired); 25149 25150 if (offsetRequired) { 25151 right += getRightPaddingOffset(); 25152 bottom += getBottomPaddingOffset(); 25153 } 25154 25155 final ScrollabilityCache scrollabilityCache = mScrollCache; 25156 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 25157 int length = (int) fadeHeight; 25158 25159 // clip the fade length if top and bottom fades overlap 25160 // overlapping fades produce odd-looking artifacts 25161 if (verticalEdges && (top + length > bottom - length)) { 25162 length = (bottom - top) / 2; 25163 } 25164 25165 // also clip horizontal fades if necessary 25166 if (horizontalEdges && (left + length > right - length)) { 25167 length = (right - left) / 2; 25168 } 25169 25170 if (verticalEdges) { 25171 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 25172 drawTop = topFadeStrength * fadeHeight > 1.0f; 25173 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 25174 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 25175 } 25176 25177 if (horizontalEdges) { 25178 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 25179 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 25180 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 25181 drawRight = rightFadeStrength * fadeHeight > 1.0f; 25182 } 25183 25184 saveCount = canvas.getSaveCount(); 25185 int topSaveCount = -1; 25186 int bottomSaveCount = -1; 25187 int leftSaveCount = -1; 25188 int rightSaveCount = -1; 25189 25190 int solidColor = getSolidColor(); 25191 if (solidColor == 0) { 25192 if (drawTop) { 25193 topSaveCount = canvas.saveUnclippedLayer(left, top, right, top + length); 25194 } 25195 25196 if (drawBottom) { 25197 bottomSaveCount = canvas.saveUnclippedLayer(left, bottom - length, right, bottom); 25198 } 25199 25200 if (drawLeft) { 25201 leftSaveCount = canvas.saveUnclippedLayer(left, top, left + length, bottom); 25202 } 25203 25204 if (drawRight) { 25205 rightSaveCount = canvas.saveUnclippedLayer(right - length, top, right, bottom); 25206 } 25207 } else { 25208 scrollabilityCache.setFadeColor(solidColor); 25209 } 25210 25211 // Step 3, draw the content 25212 onDraw(canvas); 25213 25214 // Step 4, draw the children 25215 dispatchDraw(canvas); 25216 25217 // Step 5, draw the fade effect and restore layers 25218 final Paint p = scrollabilityCache.paint; 25219 final Matrix matrix = scrollabilityCache.matrix; 25220 final Shader fade = scrollabilityCache.shader; 25221 25222 // must be restored in the reverse order that they were saved 25223 if (drawRight) { 25224 matrix.setScale(1, fadeHeight * rightFadeStrength); 25225 matrix.postRotate(90); 25226 matrix.postTranslate(right, top); 25227 fade.setLocalMatrix(matrix); 25228 p.setShader(fade); 25229 if (solidColor == 0) { 25230 canvas.restoreUnclippedLayer(rightSaveCount, p); 25231 25232 } else { 25233 canvas.drawRect(right - length, top, right, bottom, p); 25234 } 25235 } 25236 25237 if (drawLeft) { 25238 matrix.setScale(1, fadeHeight * leftFadeStrength); 25239 matrix.postRotate(-90); 25240 matrix.postTranslate(left, top); 25241 fade.setLocalMatrix(matrix); 25242 p.setShader(fade); 25243 if (solidColor == 0) { 25244 canvas.restoreUnclippedLayer(leftSaveCount, p); 25245 } else { 25246 canvas.drawRect(left, top, left + length, bottom, p); 25247 } 25248 } 25249 25250 if (drawBottom) { 25251 matrix.setScale(1, fadeHeight * bottomFadeStrength); 25252 matrix.postRotate(180); 25253 matrix.postTranslate(left, bottom); 25254 fade.setLocalMatrix(matrix); 25255 p.setShader(fade); 25256 if (solidColor == 0) { 25257 canvas.restoreUnclippedLayer(bottomSaveCount, p); 25258 } else { 25259 canvas.drawRect(left, bottom - length, right, bottom, p); 25260 } 25261 } 25262 25263 if (drawTop) { 25264 matrix.setScale(1, fadeHeight * topFadeStrength); 25265 matrix.postTranslate(left, top); 25266 fade.setLocalMatrix(matrix); 25267 p.setShader(fade); 25268 if (solidColor == 0) { 25269 canvas.restoreUnclippedLayer(topSaveCount, p); 25270 } else { 25271 canvas.drawRect(left, top, right, top + length, p); 25272 } 25273 } 25274 25275 canvas.restoreToCount(saveCount); 25276 25277 drawAutofilledHighlight(canvas); 25278 25279 // Overlay is part of the content and draws beneath Foreground 25280 if (mOverlay != null && !mOverlay.isEmpty()) { 25281 mOverlay.getOverlayView().dispatchDraw(canvas); 25282 } 25283 25284 // Step 6, draw decorations (foreground, scrollbars) 25285 onDrawForeground(canvas); 25286 25287 // Step 7, draw the default focus highlight 25288 drawDefaultFocusHighlight(canvas); 25289 25290 if (isShowingLayoutBounds()) { 25291 debugDrawFocus(canvas); 25292 } 25293 } 25294 25295 /** 25296 * Draws the background onto the specified canvas. 25297 * 25298 * @param canvas Canvas on which to draw the background 25299 */ 25300 @UnsupportedAppUsage drawBackground(@onNull Canvas canvas)25301 private void drawBackground(@NonNull Canvas canvas) { 25302 final Drawable background = mBackground; 25303 if (background == null) { 25304 return; 25305 } 25306 25307 setBackgroundBounds(); 25308 25309 // Attempt to use a display list if requested. 25310 if (canvas.isHardwareAccelerated() && mAttachInfo != null 25311 && mAttachInfo.mThreadedRenderer != null) { 25312 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 25313 25314 final RenderNode renderNode = mBackgroundRenderNode; 25315 if (renderNode != null && renderNode.hasDisplayList()) { 25316 setBackgroundRenderNodeProperties(renderNode); 25317 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 25318 return; 25319 } 25320 } 25321 25322 final int scrollX = mScrollX; 25323 final int scrollY = mScrollY; 25324 if ((scrollX | scrollY) == 0) { 25325 background.draw(canvas); 25326 } else { 25327 canvas.translate(scrollX, scrollY); 25328 background.draw(canvas); 25329 canvas.translate(-scrollX, -scrollY); 25330 } 25331 } 25332 25333 /** 25334 * Sets the correct background bounds and rebuilds the outline, if needed. 25335 * <p/> 25336 * This is called by LayoutLib. 25337 */ setBackgroundBounds()25338 void setBackgroundBounds() { 25339 if (mBackgroundSizeChanged && mBackground != null) { 25340 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 25341 mBackgroundSizeChanged = false; 25342 rebuildOutline(); 25343 } 25344 } 25345 setBackgroundRenderNodeProperties(RenderNode renderNode)25346 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 25347 renderNode.setTranslationX(mScrollX); 25348 renderNode.setTranslationY(mScrollY); 25349 } 25350 25351 /** 25352 * Creates a new display list or updates the existing display list for the 25353 * specified Drawable. 25354 * 25355 * @param drawable Drawable for which to create a display list 25356 * @param renderNode Existing RenderNode, or {@code null} 25357 * @return A valid display list for the specified drawable 25358 */ getDrawableRenderNode(Drawable drawable, RenderNode renderNode)25359 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 25360 if (renderNode == null) { 25361 renderNode = RenderNode.create(drawable.getClass().getName(), 25362 new ViewAnimationHostBridge(this)); 25363 renderNode.setUsageHint(RenderNode.USAGE_BACKGROUND); 25364 } 25365 25366 final Rect bounds = drawable.getBounds(); 25367 final int width = bounds.width(); 25368 final int height = bounds.height(); 25369 25370 // Hacky hack: Reset any stretch effects as those are applied during the draw pass 25371 // instead of being "stateful" like other RenderNode properties 25372 renderNode.clearStretch(); 25373 25374 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 25375 25376 // Reverse left/top translation done by drawable canvas, which will 25377 // instead be applied by rendernode's LTRB bounds below. This way, the 25378 // drawable's bounds match with its rendernode bounds and its content 25379 // will lie within those bounds in the rendernode tree. 25380 canvas.translate(-bounds.left, -bounds.top); 25381 25382 try { 25383 drawable.draw(canvas); 25384 } finally { 25385 renderNode.endRecording(); 25386 } 25387 25388 // Set up drawable properties that are view-independent. 25389 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 25390 renderNode.setProjectBackwards(drawable.isProjected()); 25391 renderNode.setProjectionReceiver(true); 25392 renderNode.setClipToBounds(false); 25393 return renderNode; 25394 } 25395 25396 /** 25397 * Returns the overlay for this view, creating it if it does not yet exist. 25398 * Adding drawables to the overlay will cause them to be displayed whenever 25399 * the view itself is redrawn. Objects in the overlay should be actively 25400 * managed: remove them when they should not be displayed anymore. The 25401 * overlay will always have the same size as its host view. 25402 * 25403 * <p>Note: Overlays do not currently work correctly with {@link 25404 * SurfaceView} or {@link TextureView}; contents in overlays for these 25405 * types of views may not display correctly.</p> 25406 * 25407 * @return The ViewOverlay object for this view. 25408 * @see ViewOverlay 25409 */ getOverlay()25410 public ViewOverlay getOverlay() { 25411 if (mOverlay == null) { 25412 mOverlay = new ViewOverlay(mContext, this); 25413 } 25414 return mOverlay; 25415 } 25416 25417 /** 25418 * Override this if your view is known to always be drawn on top of a solid color background, 25419 * and needs to draw fading edges. Returning a non-zero color enables the view system to 25420 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 25421 * should be set to 0xFF. 25422 * 25423 * @see #setVerticalFadingEdgeEnabled(boolean) 25424 * @see #setHorizontalFadingEdgeEnabled(boolean) 25425 * 25426 * @return The known solid color background for this view, or 0 if the color may vary 25427 */ 25428 @ViewDebug.ExportedProperty(category = "drawing") 25429 @InspectableProperty 25430 @ColorInt getSolidColor()25431 public int getSolidColor() { 25432 return 0; 25433 } 25434 25435 /** 25436 * Build a human readable string representation of the specified view flags. 25437 * 25438 * @param flags the view flags to convert to a string 25439 * @return a String representing the supplied flags 25440 */ printFlags(int flags)25441 private static String printFlags(int flags) { 25442 String output = ""; 25443 int numFlags = 0; 25444 if ((flags & FOCUSABLE) == FOCUSABLE) { 25445 output += "TAKES_FOCUS"; 25446 numFlags++; 25447 } 25448 25449 switch (flags & VISIBILITY_MASK) { 25450 case INVISIBLE: 25451 if (numFlags > 0) { 25452 output += " "; 25453 } 25454 output += "INVISIBLE"; 25455 // USELESS HERE numFlags++; 25456 break; 25457 case GONE: 25458 if (numFlags > 0) { 25459 output += " "; 25460 } 25461 output += "GONE"; 25462 // USELESS HERE numFlags++; 25463 break; 25464 default: 25465 break; 25466 } 25467 return output; 25468 } 25469 25470 /** 25471 * Build a human readable string representation of the specified private 25472 * view flags. 25473 * 25474 * @param privateFlags the private view flags to convert to a string 25475 * @return a String representing the supplied flags 25476 */ printPrivateFlags(int privateFlags)25477 private static String printPrivateFlags(int privateFlags) { 25478 String output = ""; 25479 int numFlags = 0; 25480 25481 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 25482 output += "WANTS_FOCUS"; 25483 numFlags++; 25484 } 25485 25486 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 25487 if (numFlags > 0) { 25488 output += " "; 25489 } 25490 output += "FOCUSED"; 25491 numFlags++; 25492 } 25493 25494 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 25495 if (numFlags > 0) { 25496 output += " "; 25497 } 25498 output += "SELECTED"; 25499 numFlags++; 25500 } 25501 25502 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 25503 if (numFlags > 0) { 25504 output += " "; 25505 } 25506 output += "IS_ROOT_NAMESPACE"; 25507 numFlags++; 25508 } 25509 25510 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 25511 if (numFlags > 0) { 25512 output += " "; 25513 } 25514 output += "HAS_BOUNDS"; 25515 numFlags++; 25516 } 25517 25518 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 25519 if (numFlags > 0) { 25520 output += " "; 25521 } 25522 output += "DRAWN"; 25523 // USELESS HERE numFlags++; 25524 } 25525 return output; 25526 } 25527 25528 /** 25529 * <p>Indicates whether or not this view's layout will be requested during 25530 * the next hierarchy layout pass.</p> 25531 * 25532 * @return true if the layout will be forced during next layout pass 25533 */ isLayoutRequested()25534 public boolean isLayoutRequested() { 25535 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 25536 } 25537 25538 /** 25539 * Return true if o is a ViewGroup that is laying out using optical bounds. 25540 * @hide 25541 */ isLayoutModeOptical(Object o)25542 public static boolean isLayoutModeOptical(Object o) { 25543 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 25544 } 25545 25546 /** 25547 * Enable measure/layout debugging on traces. 25548 * 25549 * @see Trace 25550 * @hide 25551 */ setTraceLayoutSteps(boolean traceLayoutSteps)25552 public static void setTraceLayoutSteps(boolean traceLayoutSteps) { 25553 sTraceLayoutSteps = traceLayoutSteps; 25554 } 25555 25556 /** 25557 * Enable request layout tracing classes with {@code s} simple name. 25558 * <p> 25559 * When set, a {@link Trace} instant event and a log with the stacktrace is emitted every 25560 * time a requestLayout of a class matching {@code s} name happens. 25561 * This applies only to views attached from this point onwards. 25562 * 25563 * @see Trace#instant(long, String) 25564 * @hide 25565 */ setTracedRequestLayoutClassClass(String s)25566 public static void setTracedRequestLayoutClassClass(String s) { 25567 sTraceRequestLayoutClass = s; 25568 } 25569 setOpticalFrame(int left, int top, int right, int bottom)25570 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 25571 Insets parentInsets = mParent instanceof View ? 25572 ((View) mParent).getOpticalInsets() : Insets.NONE; 25573 Insets childInsets = getOpticalInsets(); 25574 return setFrame( 25575 left + parentInsets.left - childInsets.left, 25576 top + parentInsets.top - childInsets.top, 25577 right + parentInsets.left + childInsets.right, 25578 bottom + parentInsets.top + childInsets.bottom); 25579 } 25580 25581 /** 25582 * Assign a size and position to a view and all of its 25583 * descendants 25584 * 25585 * <p>This is the second phase of the layout mechanism. 25586 * (The first is measuring). In this phase, each parent calls 25587 * layout on all of its children to position them. 25588 * This is typically done using the child measurements 25589 * that were stored in the measure pass().</p> 25590 * 25591 * <p>Derived classes should not override this method. 25592 * Derived classes with children should override 25593 * onLayout. In that method, they should 25594 * call layout on each of their children.</p> 25595 * 25596 * @param l Left position, relative to parent 25597 * @param t Top position, relative to parent 25598 * @param r Right position, relative to parent 25599 * @param b Bottom position, relative to parent 25600 */ 25601 @SuppressWarnings({"unchecked"}) layout(int l, int t, int r, int b)25602 public void layout(int l, int t, int r, int b) { 25603 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 25604 if (isTraversalTracingEnabled()) { 25605 Trace.beginSection(mTracingStrings.onMeasureBeforeLayout); 25606 } 25607 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 25608 if (isTraversalTracingEnabled()) { 25609 Trace.endSection(); 25610 } 25611 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 25612 } 25613 25614 int oldL = mLeft; 25615 int oldT = mTop; 25616 int oldB = mBottom; 25617 int oldR = mRight; 25618 25619 boolean changed = isLayoutModeOptical(mParent) ? 25620 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 25621 25622 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 25623 if (isTraversalTracingEnabled()) { 25624 Trace.beginSection(mTracingStrings.onLayout); 25625 } 25626 onLayout(changed, l, t, r, b); 25627 if (isTraversalTracingEnabled()) { 25628 Trace.endSection(); 25629 } 25630 25631 if (shouldDrawRoundScrollbar()) { 25632 if(mRoundScrollbarRenderer == null) { 25633 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 25634 } 25635 } else { 25636 mRoundScrollbarRenderer = null; 25637 } 25638 25639 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 25640 25641 ListenerInfo li = mListenerInfo; 25642 if (li != null && li.mOnLayoutChangeListeners != null) { 25643 ArrayList<OnLayoutChangeListener> listenersCopy = 25644 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 25645 int numListeners = listenersCopy.size(); 25646 for (int i = 0; i < numListeners; ++i) { 25647 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 25648 } 25649 } 25650 } 25651 25652 final boolean wasLayoutValid = isLayoutValid(); 25653 25654 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 25655 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 25656 25657 if (!wasLayoutValid && isFocused()) { 25658 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 25659 if (canTakeFocus()) { 25660 // We have a robust focus, so parents should no longer be wanting focus. 25661 clearParentsWantFocus(); 25662 } else if (getViewRootImpl() == null || !getViewRootImpl().isInLayout()) { 25663 // This is a weird case. Most-likely the user, rather than ViewRootImpl, called 25664 // layout. In this case, there's no guarantee that parent layouts will be evaluated 25665 // and thus the safest action is to clear focus here. 25666 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 25667 clearParentsWantFocus(); 25668 } else if (!hasParentWantsFocus()) { 25669 // original requestFocus was likely on this view directly, so just clear focus 25670 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 25671 } 25672 // otherwise, we let parents handle re-assigning focus during their layout passes. 25673 } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 25674 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 25675 View focused = findFocus(); 25676 if (focused != null) { 25677 // Try to restore focus as close as possible to our starting focus. 25678 if (!restoreDefaultFocus() && !hasParentWantsFocus()) { 25679 // Give up and clear focus once we've reached the top-most parent which wants 25680 // focus. 25681 focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 25682 } 25683 } 25684 } 25685 25686 if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { 25687 mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 25688 notifyEnterOrExitForAutoFillIfNeeded(true); 25689 } 25690 25691 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 25692 } 25693 hasParentWantsFocus()25694 private boolean hasParentWantsFocus() { 25695 ViewParent parent = mParent; 25696 while (parent instanceof ViewGroup) { 25697 ViewGroup pv = (ViewGroup) parent; 25698 if ((pv.mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 25699 return true; 25700 } 25701 parent = pv.mParent; 25702 } 25703 return false; 25704 } 25705 25706 /** 25707 * Called from layout when this view should 25708 * assign a size and position to each of its children. 25709 * 25710 * Derived classes with children should override 25711 * this method and call layout on each of 25712 * their children. 25713 * @param changed This is a new size or position for this view 25714 * @param left Left position, relative to parent 25715 * @param top Top position, relative to parent 25716 * @param right Right position, relative to parent 25717 * @param bottom Bottom position, relative to parent 25718 */ onLayout(boolean changed, int left, int top, int right, int bottom)25719 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 25720 } 25721 25722 /** 25723 * Assign a size and position to this view. 25724 * 25725 * This is called from layout. 25726 * 25727 * @param left Left position, relative to parent 25728 * @param top Top position, relative to parent 25729 * @param right Right position, relative to parent 25730 * @param bottom Bottom position, relative to parent 25731 * @return true if the new size and position are different than the 25732 * previous ones 25733 * {@hide} 25734 */ 25735 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) setFrame(int left, int top, int right, int bottom)25736 protected boolean setFrame(int left, int top, int right, int bottom) { 25737 boolean changed = false; 25738 25739 if (DBG) { 25740 Log.d(VIEW_LOG_TAG, this + " View.setFrame(" + left + "," + top + "," 25741 + right + "," + bottom + ")"); 25742 } 25743 25744 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 25745 changed = true; 25746 25747 // Remember our drawn bit 25748 int drawn = mPrivateFlags & PFLAG_DRAWN; 25749 25750 int oldWidth = mRight - mLeft; 25751 int oldHeight = mBottom - mTop; 25752 int newWidth = right - left; 25753 int newHeight = bottom - top; 25754 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 25755 25756 // Invalidate our old position 25757 invalidate(sizeChanged); 25758 25759 mLeft = left; 25760 mTop = top; 25761 mRight = right; 25762 mBottom = bottom; 25763 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 25764 25765 mPrivateFlags |= PFLAG_HAS_BOUNDS; 25766 25767 25768 if (sizeChanged) { 25769 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 25770 } 25771 25772 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 25773 // If we are visible, force the DRAWN bit to on so that 25774 // this invalidate will go through (at least to our parent). 25775 // This is because someone may have invalidated this view 25776 // before this call to setFrame came in, thereby clearing 25777 // the DRAWN bit. 25778 mPrivateFlags |= PFLAG_DRAWN; 25779 invalidate(sizeChanged); 25780 // parent display list may need to be recreated based on a change in the bounds 25781 // of any child 25782 invalidateParentCaches(); 25783 } 25784 25785 // Reset drawn bit to original value (invalidate turns it off) 25786 mPrivateFlags |= drawn; 25787 25788 mBackgroundSizeChanged = true; 25789 mDefaultFocusHighlightSizeChanged = true; 25790 if (mForegroundInfo != null) { 25791 mForegroundInfo.mBoundsChanged = true; 25792 } 25793 25794 notifySubtreeAccessibilityStateChangedIfNeeded(); 25795 } 25796 return changed; 25797 } 25798 25799 /** 25800 * Assign a size and position to this view. 25801 * 25802 * This method is meant to be used in animations only as it applies this position and size 25803 * for the view only temporary and it can be changed back at any time by the layout. 25804 * 25805 * @param left Left position, relative to parent 25806 * @param top Top position, relative to parent 25807 * @param right Right position, relative to parent 25808 * @param bottom Bottom position, relative to parent 25809 * 25810 * @see #setLeft(int), #setRight(int), #setTop(int), #setBottom(int) 25811 */ setLeftTopRightBottom(int left, int top, int right, int bottom)25812 public final void setLeftTopRightBottom(int left, int top, int right, int bottom) { 25813 setFrame(left, top, right, bottom); 25814 } 25815 sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight)25816 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 25817 if (mAttachInfo != null && sToolkitFrameRateViewEnablingReadOnlyFlagValue) { 25818 boolean isSmall; 25819 if (sToolkitFrameRateSmallUsesPercentReadOnlyFlagValue) { 25820 int size = newWidth * newHeight; 25821 float percent = size / mAttachInfo.mDisplayPixelCount; 25822 isSmall = percent <= FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD; 25823 } else { 25824 float density = mAttachInfo.mDensity; 25825 int narrowSize = (int) (density * FRAME_RATE_NARROW_SIZE_DP); 25826 int smallSize = (int) (density * FRAME_RATE_SQUARE_SMALL_SIZE_DP); 25827 isSmall = newWidth <= narrowSize || newHeight <= narrowSize 25828 || (newWidth <= smallSize && newHeight <= smallSize); 25829 } 25830 if (isSmall) { 25831 int category = sToolkitFrameRateBySizeReadOnlyFlagValue 25832 ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL; 25833 mSizeBasedFrameRateCategoryAndReason = category | FRAME_RATE_CATEGORY_REASON_SMALL; 25834 } else { 25835 int category = sToolkitFrameRateDefaultNormalReadOnlyFlagValue 25836 ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; 25837 mSizeBasedFrameRateCategoryAndReason = category | FRAME_RATE_CATEGORY_REASON_LARGE; 25838 } 25839 mPrivateFlags4 |= PFLAG4_HAS_MOVED; 25840 } 25841 25842 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 25843 if (mOverlay != null) { 25844 mOverlay.getOverlayView().setRight(newWidth); 25845 mOverlay.getOverlayView().setBottom(newHeight); 25846 } 25847 // If this isn't laid out yet, focus assignment will be handled during the "deferment/ 25848 // backtracking" of requestFocus during layout, so don't touch focus here. 25849 if (!sCanFocusZeroSized && isLayoutValid() 25850 // Don't touch focus if animating 25851 && !(mParent instanceof ViewGroup && ((ViewGroup) mParent).isLayoutSuppressed())) { 25852 if (newWidth <= 0 || newHeight <= 0) { 25853 if (hasFocus()) { 25854 clearFocus(); 25855 if (mParent instanceof ViewGroup) { 25856 ((ViewGroup) mParent).clearFocusedInCluster(); 25857 } 25858 } 25859 clearAccessibilityFocus(); 25860 } else if (oldWidth <= 0 || oldHeight <= 0) { 25861 if (mParent != null && canTakeFocus()) { 25862 mParent.focusableViewAvailable(this); 25863 } 25864 } 25865 } 25866 rebuildOutline(); 25867 if (onCheckIsTextEditor() || mHandwritingDelegatorCallback != null) { 25868 setHandwritingArea(new Rect(0, 0, newWidth, newHeight)); 25869 } 25870 } 25871 25872 /** 25873 * Finalize inflating a view from XML. This is called as the last phase 25874 * of inflation, after all child views have been added. 25875 * 25876 * <p>Even if the subclass overrides onFinishInflate, they should always be 25877 * sure to call the super method, so that we get called. 25878 */ 25879 @CallSuper onFinishInflate()25880 protected void onFinishInflate() { 25881 } 25882 25883 /** 25884 * Returns the resources associated with this view. 25885 * 25886 * @return Resources object. 25887 */ getResources()25888 public Resources getResources() { 25889 return mResources; 25890 } 25891 25892 /** 25893 * Invalidates the specified Drawable. 25894 * 25895 * @param drawable the drawable to invalidate 25896 */ 25897 @Override invalidateDrawable(@onNull Drawable drawable)25898 public void invalidateDrawable(@NonNull Drawable drawable) { 25899 if (verifyDrawable(drawable)) { 25900 final Rect dirty = drawable.getDirtyBounds(); 25901 final int scrollX = mScrollX; 25902 final int scrollY = mScrollY; 25903 25904 invalidate(dirty.left + scrollX, dirty.top + scrollY, 25905 dirty.right + scrollX, dirty.bottom + scrollY); 25906 rebuildOutline(); 25907 } 25908 } 25909 25910 /** 25911 * Schedules an action on a drawable to occur at a specified time. 25912 * 25913 * @param who the recipient of the action 25914 * @param what the action to run on the drawable 25915 * @param when the time at which the action must occur. Uses the 25916 * {@link SystemClock#uptimeMillis} timebase. 25917 */ 25918 @Override scheduleDrawable(@onNull Drawable who, @NonNull Runnable what, long when)25919 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 25920 if (verifyDrawable(who) && what != null) { 25921 final long delay = when - SystemClock.uptimeMillis(); 25922 if (mAttachInfo != null) { 25923 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 25924 Choreographer.CALLBACK_ANIMATION, what, who, 25925 Choreographer.subtractFrameDelay(delay)); 25926 } else { 25927 // Postpone the runnable until we know 25928 // on which thread it needs to run. 25929 getRunQueue().postDelayed(what, delay); 25930 } 25931 } 25932 } 25933 25934 /** 25935 * Cancels a scheduled action on a drawable. 25936 * 25937 * @param who the recipient of the action 25938 * @param what the action to cancel 25939 */ 25940 @Override unscheduleDrawable(@onNull Drawable who, @NonNull Runnable what)25941 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 25942 if (verifyDrawable(who) && what != null) { 25943 if (mAttachInfo != null) { 25944 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 25945 Choreographer.CALLBACK_ANIMATION, what, who); 25946 } 25947 getRunQueue().removeCallbacks(what); 25948 } 25949 } 25950 25951 /** 25952 * Unschedule any events associated with the given Drawable. This can be 25953 * used when selecting a new Drawable into a view, so that the previous 25954 * one is completely unscheduled. 25955 * 25956 * @param who The Drawable to unschedule. 25957 * 25958 * @see #drawableStateChanged 25959 */ unscheduleDrawable(Drawable who)25960 public void unscheduleDrawable(Drawable who) { 25961 if (mAttachInfo != null && who != null) { 25962 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 25963 Choreographer.CALLBACK_ANIMATION, null, who); 25964 } 25965 } 25966 25967 /** 25968 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 25969 * that the View directionality can and will be resolved before its Drawables. 25970 * 25971 * Will call {@link View#onResolveDrawables} when resolution is done. 25972 * 25973 * @hide 25974 */ resolveDrawables()25975 protected void resolveDrawables() { 25976 // Drawables resolution may need to happen before resolving the layout direction (which is 25977 // done only during the measure() call). 25978 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 25979 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 25980 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 25981 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 25982 // direction to be resolved as its resolved value will be the same as its raw value. 25983 if (!isLayoutDirectionResolved() && 25984 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 25985 return; 25986 } 25987 25988 final int layoutDirection = isLayoutDirectionResolved() ? 25989 getLayoutDirection() : getRawLayoutDirection(); 25990 25991 if (mBackground != null) { 25992 mBackground.setLayoutDirection(layoutDirection); 25993 } 25994 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 25995 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 25996 } 25997 if (mDefaultFocusHighlight != null) { 25998 mDefaultFocusHighlight.setLayoutDirection(layoutDirection); 25999 } 26000 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 26001 onResolveDrawables(layoutDirection); 26002 } 26003 areDrawablesResolved()26004 boolean areDrawablesResolved() { 26005 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 26006 } 26007 26008 /** 26009 * Called when layout direction has been resolved. 26010 * 26011 * The default implementation does nothing. 26012 * 26013 * @param layoutDirection The resolved layout direction. 26014 * 26015 * @see #LAYOUT_DIRECTION_LTR 26016 * @see #LAYOUT_DIRECTION_RTL 26017 * 26018 * @hide 26019 */ onResolveDrawables(@esolvedLayoutDir int layoutDirection)26020 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 26021 } 26022 26023 /** 26024 * @hide 26025 */ 26026 @TestApi resetResolvedDrawables()26027 protected void resetResolvedDrawables() { 26028 resetResolvedDrawablesInternal(); 26029 } 26030 resetResolvedDrawablesInternal()26031 void resetResolvedDrawablesInternal() { 26032 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 26033 } 26034 26035 /** 26036 * If your view subclass is displaying its own Drawable objects, it should 26037 * override this function and return true for any Drawable it is 26038 * displaying. This allows animations for those drawables to be 26039 * scheduled. 26040 * 26041 * <p>Be sure to call through to the super class when overriding this 26042 * function. 26043 * 26044 * @param who The Drawable to verify. Return true if it is one you are 26045 * displaying, else return the result of calling through to the 26046 * super class. 26047 * 26048 * @return boolean If true then the Drawable is being displayed in the 26049 * view; else false and it is not allowed to animate. 26050 * 26051 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 26052 * @see #drawableStateChanged() 26053 */ 26054 @CallSuper verifyDrawable(@onNull Drawable who)26055 protected boolean verifyDrawable(@NonNull Drawable who) { 26056 // Avoid verifying the scroll bar drawable so that we don't end up in 26057 // an invalidation loop. This effectively prevents the scroll bar 26058 // drawable from triggering invalidations and scheduling runnables. 26059 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) 26060 || (mDefaultFocusHighlight == who); 26061 } 26062 26063 /** 26064 * This function is called whenever the state of the view changes in such 26065 * a way that it impacts the state of drawables being shown. 26066 * <p> 26067 * If the View has a StateListAnimator, it will also be called to run necessary state 26068 * change animations. 26069 * <p> 26070 * Be sure to call through to the superclass when overriding this function. 26071 * 26072 * @see Drawable#setState(int[]) 26073 */ 26074 @CallSuper drawableStateChanged()26075 protected void drawableStateChanged() { 26076 final int[] state = getDrawableState(); 26077 boolean changed = false; 26078 26079 final Drawable bg = mBackground; 26080 if (bg != null && bg.isStateful()) { 26081 changed |= bg.setState(state); 26082 } 26083 26084 final Drawable hl = mDefaultFocusHighlight; 26085 if (hl != null && hl.isStateful()) { 26086 changed |= hl.setState(state); 26087 } 26088 26089 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 26090 if (fg != null && fg.isStateful()) { 26091 changed |= fg.setState(state); 26092 } 26093 26094 if (mScrollCache != null) { 26095 final Drawable scrollBar = mScrollCache.scrollBar; 26096 if (scrollBar != null && scrollBar.isStateful()) { 26097 changed |= scrollBar.setState(state) 26098 && mScrollCache.state != ScrollabilityCache.OFF; 26099 } 26100 } 26101 26102 if (mStateListAnimator != null) { 26103 mStateListAnimator.setState(state); 26104 } 26105 26106 if (!isAggregatedVisible()) { 26107 // If we're not visible, skip any animated changes 26108 jumpDrawablesToCurrentState(); 26109 } 26110 26111 if (changed) { 26112 invalidate(); 26113 } 26114 } 26115 26116 /** 26117 * This function is called whenever the view hotspot changes and needs to 26118 * be propagated to drawables or child views managed by the view. 26119 * <p> 26120 * Dispatching to child views is handled by 26121 * {@link #dispatchDrawableHotspotChanged(float, float)}. 26122 * <p> 26123 * Be sure to call through to the superclass when overriding this function. 26124 * 26125 * @param x hotspot x coordinate 26126 * @param y hotspot y coordinate 26127 */ 26128 @CallSuper drawableHotspotChanged(float x, float y)26129 public void drawableHotspotChanged(float x, float y) { 26130 if (mBackground != null) { 26131 mBackground.setHotspot(x, y); 26132 } 26133 if (mDefaultFocusHighlight != null) { 26134 mDefaultFocusHighlight.setHotspot(x, y); 26135 } 26136 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 26137 mForegroundInfo.mDrawable.setHotspot(x, y); 26138 } 26139 26140 dispatchDrawableHotspotChanged(x, y); 26141 } 26142 26143 /** 26144 * Dispatches drawableHotspotChanged to all of this View's children. 26145 * 26146 * @param x hotspot x coordinate 26147 * @param y hotspot y coordinate 26148 * @see #drawableHotspotChanged(float, float) 26149 */ dispatchDrawableHotspotChanged(float x, float y)26150 public void dispatchDrawableHotspotChanged(float x, float y) { 26151 } 26152 26153 /** 26154 * Call this to force a view to update its drawable state. This will cause 26155 * drawableStateChanged to be called on this view. Views that are interested 26156 * in the new state should call getDrawableState. 26157 * 26158 * @see #drawableStateChanged 26159 * @see #getDrawableState 26160 */ refreshDrawableState()26161 public void refreshDrawableState() { 26162 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 26163 drawableStateChanged(); 26164 26165 ViewParent parent = mParent; 26166 if (parent != null) { 26167 parent.childDrawableStateChanged(this); 26168 } 26169 } 26170 26171 /** 26172 * Create a default focus highlight if it doesn't exist. 26173 * @return a default focus highlight. 26174 */ getDefaultFocusHighlightDrawable()26175 private Drawable getDefaultFocusHighlightDrawable() { 26176 if (mDefaultFocusHighlightCache == null) { 26177 if (mContext != null) { 26178 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; 26179 final TypedArray ta = mContext.obtainStyledAttributes(attrs); 26180 mDefaultFocusHighlightCache = ta.getDrawable(0); 26181 ta.recycle(); 26182 } 26183 } 26184 return mDefaultFocusHighlightCache; 26185 } 26186 26187 /** 26188 * Set the current default focus highlight. 26189 * @param highlight the highlight drawable, or {@code null} if it's no longer needed. 26190 */ setDefaultFocusHighlight(Drawable highlight)26191 private void setDefaultFocusHighlight(Drawable highlight) { 26192 mDefaultFocusHighlight = highlight; 26193 mDefaultFocusHighlightSizeChanged = true; 26194 if (highlight != null) { 26195 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 26196 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 26197 } 26198 highlight.setLayoutDirection(getLayoutDirection()); 26199 if (highlight.isStateful()) { 26200 highlight.setState(getDrawableState()); 26201 } 26202 if (isAttachedToWindow()) { 26203 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 26204 } 26205 // Set callback last, since the view may still be initializing. 26206 highlight.setCallback(this); 26207 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 26208 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 26209 mPrivateFlags |= PFLAG_SKIP_DRAW; 26210 } 26211 invalidate(); 26212 } 26213 26214 /** 26215 * Check whether we need to draw a default focus highlight when this view gets focused, 26216 * which requires: 26217 * <ul> 26218 * <li>In both background and foreground, {@link android.R.attr#state_focused} 26219 * is not defined.</li> 26220 * <li>This view is not in touch mode.</li> 26221 * <li>This view doesn't opt out for a default focus highlight, via 26222 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li> 26223 * <li>This view is attached to window.</li> 26224 * </ul> 26225 * @return {@code true} if a default focus highlight is needed. 26226 * @hide 26227 */ 26228 @TestApi isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground)26229 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { 26230 final boolean lackFocusState = (background == null || !background.isStateful() 26231 || !background.hasFocusStateSpecified()) 26232 && (foreground == null || !foreground.isStateful() 26233 || !foreground.hasFocusStateSpecified()); 26234 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState 26235 && isAttachedToWindow() && sUseDefaultFocusHighlight; 26236 } 26237 26238 /** 26239 * When this view is focused, switches on/off the default focused highlight. 26240 * <p> 26241 * This always happens when this view is focused, and only at this moment the default focus 26242 * highlight can be visible. 26243 */ switchDefaultFocusHighlight()26244 private void switchDefaultFocusHighlight() { 26245 if (isFocused()) { 26246 final boolean needed = isDefaultFocusHighlightNeeded(mBackground, 26247 mForegroundInfo == null ? null : mForegroundInfo.mDrawable); 26248 final boolean active = mDefaultFocusHighlight != null; 26249 if (needed && !active) { 26250 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); 26251 } else if (!needed && active) { 26252 // The highlight is no longer needed, so tear it down. 26253 setDefaultFocusHighlight(null); 26254 } 26255 } 26256 } 26257 26258 /** 26259 * Draw the default focus highlight onto the canvas if there is one and this view is focused. 26260 * @param canvas the canvas where we're drawing the highlight. 26261 */ drawDefaultFocusHighlight(@onNull Canvas canvas)26262 private void drawDefaultFocusHighlight(@NonNull Canvas canvas) { 26263 if (mDefaultFocusHighlight != null && isFocused()) { 26264 if (mDefaultFocusHighlightSizeChanged) { 26265 mDefaultFocusHighlightSizeChanged = false; 26266 final int l = mScrollX; 26267 final int r = l + mRight - mLeft; 26268 final int t = mScrollY; 26269 final int b = t + mBottom - mTop; 26270 mDefaultFocusHighlight.setBounds(l, t, r, b); 26271 } 26272 mDefaultFocusHighlight.draw(canvas); 26273 } 26274 } 26275 26276 /** 26277 * Return an array of resource IDs of the drawable states representing the 26278 * current state of the view. 26279 * 26280 * @return The current drawable state 26281 * 26282 * @see Drawable#setState(int[]) 26283 * @see #drawableStateChanged() 26284 * @see #onCreateDrawableState(int) 26285 */ getDrawableState()26286 public final int[] getDrawableState() { 26287 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 26288 return mDrawableState; 26289 } else { 26290 mDrawableState = onCreateDrawableState(0); 26291 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 26292 return mDrawableState; 26293 } 26294 } 26295 26296 /** 26297 * Generate the new {@link android.graphics.drawable.Drawable} state for 26298 * this view. This is called by the view 26299 * system when the cached Drawable state is determined to be invalid. To 26300 * retrieve the current state, you should use {@link #getDrawableState}. 26301 * 26302 * @param extraSpace if non-zero, this is the number of extra entries you 26303 * would like in the returned array in which you can place your own 26304 * states. 26305 * 26306 * @return Returns an array holding the current {@link Drawable} state of 26307 * the view. 26308 * 26309 * @see #mergeDrawableStates(int[], int[]) 26310 */ onCreateDrawableState(int extraSpace)26311 protected int[] onCreateDrawableState(int extraSpace) { 26312 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 26313 mParent instanceof View) { 26314 return ((View) mParent).onCreateDrawableState(extraSpace); 26315 } 26316 26317 int[] drawableState; 26318 26319 int privateFlags = mPrivateFlags; 26320 26321 int viewStateIndex = 0; 26322 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 26323 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 26324 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 26325 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 26326 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 26327 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 26328 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested) { 26329 // This is set if HW acceleration is requested, even if the current 26330 // process doesn't allow it. This is just to allow app preview 26331 // windows to better match their app. 26332 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 26333 } 26334 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 26335 26336 final int privateFlags2 = mPrivateFlags2; 26337 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 26338 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 26339 } 26340 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 26341 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 26342 } 26343 26344 drawableState = StateSet.get(viewStateIndex); 26345 26346 //noinspection ConstantIfStatement 26347 if (false) { 26348 Log.i("View", "drawableStateIndex=" + viewStateIndex); 26349 Log.i("View", toString() 26350 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 26351 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 26352 + " fo=" + hasFocus() 26353 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 26354 + " wf=" + hasWindowFocus() 26355 + ": " + Arrays.toString(drawableState)); 26356 } 26357 26358 if (extraSpace == 0) { 26359 return drawableState; 26360 } 26361 26362 final int[] fullState; 26363 if (drawableState != null) { 26364 fullState = new int[drawableState.length + extraSpace]; 26365 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 26366 } else { 26367 fullState = new int[extraSpace]; 26368 } 26369 26370 return fullState; 26371 } 26372 26373 /** 26374 * Merge your own state values in <var>additionalState</var> into the base 26375 * state values <var>baseState</var> that were returned by 26376 * {@link #onCreateDrawableState(int)}. 26377 * 26378 * @param baseState The base state values returned by 26379 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 26380 * own additional state values. 26381 * 26382 * @param additionalState The additional state values you would like 26383 * added to <var>baseState</var>; this array is not modified. 26384 * 26385 * @return As a convenience, the <var>baseState</var> array you originally 26386 * passed into the function is returned. 26387 * 26388 * @see #onCreateDrawableState(int) 26389 */ mergeDrawableStates(int[] baseState, int[] additionalState)26390 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 26391 final int N = baseState.length; 26392 int i = N - 1; 26393 while (i >= 0 && baseState[i] == 0) { 26394 i--; 26395 } 26396 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 26397 return baseState; 26398 } 26399 26400 /** 26401 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 26402 * on all Drawable objects associated with this view. 26403 * <p> 26404 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 26405 * attached to this view. 26406 */ 26407 @CallSuper jumpDrawablesToCurrentState()26408 public void jumpDrawablesToCurrentState() { 26409 if (mBackground != null) { 26410 mBackground.jumpToCurrentState(); 26411 } 26412 if (mStateListAnimator != null) { 26413 mStateListAnimator.jumpToCurrentState(); 26414 } 26415 if (mDefaultFocusHighlight != null) { 26416 mDefaultFocusHighlight.jumpToCurrentState(); 26417 } 26418 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 26419 mForegroundInfo.mDrawable.jumpToCurrentState(); 26420 } 26421 } 26422 26423 /** 26424 * Sets the background color for this view. 26425 * @param color the color of the background 26426 */ 26427 @RemotableViewMethod setBackgroundColor(@olorInt int color)26428 public void setBackgroundColor(@ColorInt int color) { 26429 if (mBackground instanceof ColorDrawable) { 26430 ((ColorDrawable) mBackground.mutate()).setColor(color); 26431 computeOpaqueFlags(); 26432 mBackgroundResource = 0; 26433 } else { 26434 setBackground(new ColorDrawable(color)); 26435 } 26436 } 26437 26438 /** 26439 * Set the background to a given resource. The resource should refer to 26440 * a Drawable object or 0 to remove the background. 26441 * @param resid The identifier of the resource. 26442 * 26443 * @attr ref android.R.styleable#View_background 26444 */ 26445 @RemotableViewMethod setBackgroundResource(@rawableRes int resid)26446 public void setBackgroundResource(@DrawableRes int resid) { 26447 if (resid != 0 && resid == mBackgroundResource) { 26448 return; 26449 } 26450 26451 Drawable d = null; 26452 if (resid != 0) { 26453 d = mContext.getDrawable(resid); 26454 } 26455 setBackground(d); 26456 26457 mBackgroundResource = resid; 26458 } 26459 26460 /** 26461 * Set the background to a given Drawable, or remove the background. If the 26462 * background has padding, this View's padding is set to the background's 26463 * padding. However, when a background is removed, this View's padding isn't 26464 * touched. If setting the padding is desired, please use 26465 * {@link #setPadding(int, int, int, int)}. 26466 * 26467 * @param background The Drawable to use as the background, or null to remove the 26468 * background 26469 */ setBackground(Drawable background)26470 public void setBackground(Drawable background) { 26471 //noinspection deprecation 26472 setBackgroundDrawable(background); 26473 } 26474 26475 /** 26476 * @deprecated use {@link #setBackground(Drawable)} instead 26477 */ 26478 @Deprecated setBackgroundDrawable(Drawable background)26479 public void setBackgroundDrawable(Drawable background) { 26480 computeOpaqueFlags(); 26481 26482 if (background == mBackground) { 26483 return; 26484 } 26485 26486 boolean requestLayout = false; 26487 26488 mBackgroundResource = 0; 26489 26490 /* 26491 * Regardless of whether we're setting a new background or not, we want 26492 * to clear the previous drawable. setVisible first while we still have the callback set. 26493 */ 26494 if (mBackground != null) { 26495 if (isAttachedToWindow()) { 26496 mBackground.setVisible(false, false); 26497 } 26498 mBackground.setCallback(null); 26499 unscheduleDrawable(mBackground); 26500 } 26501 26502 if (background != null) { 26503 Rect padding = sThreadLocal.get(); 26504 if (padding == null) { 26505 padding = new Rect(); 26506 sThreadLocal.set(padding); 26507 } 26508 resetResolvedDrawablesInternal(); 26509 background.setLayoutDirection(getLayoutDirection()); 26510 if (background.getPadding(padding)) { 26511 resetResolvedPaddingInternal(); 26512 switch (background.getLayoutDirection()) { 26513 case LAYOUT_DIRECTION_RTL: 26514 mUserPaddingLeftInitial = padding.right; 26515 mUserPaddingRightInitial = padding.left; 26516 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 26517 break; 26518 case LAYOUT_DIRECTION_LTR: 26519 default: 26520 mUserPaddingLeftInitial = padding.left; 26521 mUserPaddingRightInitial = padding.right; 26522 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 26523 } 26524 mLeftPaddingDefined = false; 26525 mRightPaddingDefined = false; 26526 } 26527 26528 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 26529 // if it has a different minimum size, we should layout again 26530 if (mBackground == null 26531 || mBackground.getMinimumHeight() != background.getMinimumHeight() 26532 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 26533 requestLayout = true; 26534 } 26535 26536 // Set mBackground before we set this as the callback and start making other 26537 // background drawable state change calls. In particular, the setVisible call below 26538 // can result in drawables attempting to start animations or otherwise invalidate, 26539 // which requires the view set as the callback (us) to recognize the drawable as 26540 // belonging to it as per verifyDrawable. 26541 mBackground = background; 26542 if (background.isStateful()) { 26543 background.setState(getDrawableState()); 26544 } 26545 if (isAttachedToWindow()) { 26546 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 26547 } 26548 26549 applyBackgroundTint(); 26550 26551 // Set callback last, since the view may still be initializing. 26552 background.setCallback(this); 26553 26554 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 26555 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 26556 requestLayout = true; 26557 } 26558 } else { 26559 /* Remove the background */ 26560 mBackground = null; 26561 if ((mViewFlags & WILL_NOT_DRAW) != 0 26562 && (mDefaultFocusHighlight == null) 26563 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 26564 mPrivateFlags |= PFLAG_SKIP_DRAW; 26565 } 26566 26567 /* 26568 * When the background is set, we try to apply its padding to this 26569 * View. When the background is removed, we don't touch this View's 26570 * padding. This is noted in the Javadocs. Hence, we don't need to 26571 * requestLayout(), the invalidate() below is sufficient. 26572 */ 26573 26574 // The old background's minimum size could have affected this 26575 // View's layout, so let's requestLayout 26576 requestLayout = true; 26577 } 26578 26579 computeOpaqueFlags(); 26580 26581 if (requestLayout) { 26582 requestLayout(); 26583 } 26584 26585 mBackgroundSizeChanged = true; 26586 invalidate(true); 26587 invalidateOutline(); 26588 } 26589 26590 /** 26591 * Gets the background drawable 26592 * 26593 * @return The drawable used as the background for this view, if any. 26594 * 26595 * @see #setBackground(Drawable) 26596 * 26597 * @attr ref android.R.styleable#View_background 26598 */ 26599 @InspectableProperty getBackground()26600 public Drawable getBackground() { 26601 return mBackground; 26602 } 26603 26604 /** 26605 * Applies a tint to the background drawable. Does not modify the current tint 26606 * mode, which is {@link BlendMode#SRC_IN} by default. 26607 * <p> 26608 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 26609 * mutate the drawable and apply the specified tint and tint mode using 26610 * {@link Drawable#setTintList(ColorStateList)}. 26611 * 26612 * @param tint the tint to apply, may be {@code null} to clear tint 26613 * 26614 * @attr ref android.R.styleable#View_backgroundTint 26615 * @see #getBackgroundTintList() 26616 * @see Drawable#setTintList(ColorStateList) 26617 */ 26618 @RemotableViewMethod setBackgroundTintList(@ullable ColorStateList tint)26619 public void setBackgroundTintList(@Nullable ColorStateList tint) { 26620 if (mBackgroundTint == null) { 26621 mBackgroundTint = new TintInfo(); 26622 } 26623 mBackgroundTint.mTintList = tint; 26624 mBackgroundTint.mHasTintList = true; 26625 26626 applyBackgroundTint(); 26627 } 26628 26629 /** 26630 * Return the tint applied to the background drawable, if specified. 26631 * 26632 * @return the tint applied to the background drawable 26633 * @attr ref android.R.styleable#View_backgroundTint 26634 * @see #setBackgroundTintList(ColorStateList) 26635 */ 26636 @InspectableProperty(name = "backgroundTint") 26637 @Nullable getBackgroundTintList()26638 public ColorStateList getBackgroundTintList() { 26639 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 26640 } 26641 26642 /** 26643 * Specifies the blending mode used to apply the tint specified by 26644 * {@link #setBackgroundTintList(ColorStateList)}} to the background 26645 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 26646 * 26647 * @param tintMode the blending mode used to apply the tint, may be 26648 * {@code null} to clear tint 26649 * @attr ref android.R.styleable#View_backgroundTintMode 26650 * @see #getBackgroundTintMode() 26651 * @see Drawable#setTintMode(PorterDuff.Mode) 26652 */ setBackgroundTintMode(@ullable PorterDuff.Mode tintMode)26653 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 26654 BlendMode mode = null; 26655 if (tintMode != null) { 26656 mode = BlendMode.fromValue(tintMode.nativeInt); 26657 } 26658 26659 setBackgroundTintBlendMode(mode); 26660 } 26661 26662 /** 26663 * Specifies the blending mode used to apply the tint specified by 26664 * {@link #setBackgroundTintList(ColorStateList)}} to the background 26665 * drawable. The default mode is {@link BlendMode#SRC_IN}. 26666 * 26667 * @param blendMode the blending mode used to apply the tint, may be 26668 * {@code null} to clear tint 26669 * @attr ref android.R.styleable#View_backgroundTintMode 26670 * @see #getBackgroundTintMode() 26671 * @see Drawable#setTintBlendMode(BlendMode) 26672 */ 26673 @RemotableViewMethod setBackgroundTintBlendMode(@ullable BlendMode blendMode)26674 public void setBackgroundTintBlendMode(@Nullable BlendMode blendMode) { 26675 if (mBackgroundTint == null) { 26676 mBackgroundTint = new TintInfo(); 26677 } 26678 26679 mBackgroundTint.mBlendMode = blendMode; 26680 mBackgroundTint.mHasTintMode = true; 26681 26682 applyBackgroundTint(); 26683 } 26684 26685 /** 26686 * Return the blending mode used to apply the tint to the background 26687 * drawable, if specified. 26688 * 26689 * @return the blending mode used to apply the tint to the background 26690 * drawable 26691 * @attr ref android.R.styleable#View_backgroundTintMode 26692 * @see #setBackgroundTintBlendMode(BlendMode) 26693 * 26694 */ 26695 @Nullable 26696 @InspectableProperty getBackgroundTintMode()26697 public PorterDuff.Mode getBackgroundTintMode() { 26698 PorterDuff.Mode porterDuffMode; 26699 if (mBackgroundTint != null && mBackgroundTint.mBlendMode != null) { 26700 porterDuffMode = BlendMode.blendModeToPorterDuffMode(mBackgroundTint.mBlendMode); 26701 } else { 26702 porterDuffMode = null; 26703 } 26704 return porterDuffMode; 26705 } 26706 26707 /** 26708 * Return the blending mode used to apply the tint to the background 26709 * drawable, if specified. 26710 * 26711 * @return the blending mode used to apply the tint to the background 26712 * drawable, null if no blend has previously been configured 26713 * @attr ref android.R.styleable#View_backgroundTintMode 26714 * @see #setBackgroundTintBlendMode(BlendMode) 26715 */ getBackgroundTintBlendMode()26716 public @Nullable BlendMode getBackgroundTintBlendMode() { 26717 return mBackgroundTint != null ? mBackgroundTint.mBlendMode : null; 26718 } 26719 applyBackgroundTint()26720 private void applyBackgroundTint() { 26721 if (mBackground != null && mBackgroundTint != null) { 26722 final TintInfo tintInfo = mBackgroundTint; 26723 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 26724 mBackground = mBackground.mutate(); 26725 26726 if (tintInfo.mHasTintList) { 26727 mBackground.setTintList(tintInfo.mTintList); 26728 } 26729 26730 if (tintInfo.mHasTintMode) { 26731 mBackground.setTintBlendMode(tintInfo.mBlendMode); 26732 } 26733 26734 // The drawable (or one of its children) may not have been 26735 // stateful before applying the tint, so let's try again. 26736 if (mBackground.isStateful()) { 26737 mBackground.setState(getDrawableState()); 26738 } 26739 } 26740 } 26741 } 26742 26743 /** 26744 * Returns the drawable used as the foreground of this View. The 26745 * foreground drawable, if non-null, is always drawn on top of the view's content. 26746 * 26747 * @return a Drawable or null if no foreground was set 26748 * 26749 * @see #onDrawForeground(Canvas) 26750 */ 26751 @InspectableProperty getForeground()26752 public Drawable getForeground() { 26753 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 26754 } 26755 26756 /** 26757 * Supply a Drawable that is to be rendered on top of all of the content in the view. 26758 * 26759 * @param foreground the Drawable to be drawn on top of the children 26760 * 26761 * @attr ref android.R.styleable#View_foreground 26762 */ setForeground(Drawable foreground)26763 public void setForeground(Drawable foreground) { 26764 if (mForegroundInfo == null) { 26765 if (foreground == null) { 26766 // Nothing to do. 26767 return; 26768 } 26769 mForegroundInfo = new ForegroundInfo(); 26770 } 26771 26772 if (foreground == mForegroundInfo.mDrawable) { 26773 // Nothing to do 26774 return; 26775 } 26776 26777 if (mForegroundInfo.mDrawable != null) { 26778 if (isAttachedToWindow()) { 26779 mForegroundInfo.mDrawable.setVisible(false, false); 26780 } 26781 mForegroundInfo.mDrawable.setCallback(null); 26782 unscheduleDrawable(mForegroundInfo.mDrawable); 26783 } 26784 26785 mForegroundInfo.mDrawable = foreground; 26786 mForegroundInfo.mBoundsChanged = true; 26787 if (foreground != null) { 26788 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 26789 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 26790 } 26791 foreground.setLayoutDirection(getLayoutDirection()); 26792 if (foreground.isStateful()) { 26793 foreground.setState(getDrawableState()); 26794 } 26795 applyForegroundTint(); 26796 if (isAttachedToWindow()) { 26797 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 26798 } 26799 // Set callback last, since the view may still be initializing. 26800 foreground.setCallback(this); 26801 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 26802 && (mDefaultFocusHighlight == null)) { 26803 mPrivateFlags |= PFLAG_SKIP_DRAW; 26804 } 26805 requestLayout(); 26806 invalidate(); 26807 } 26808 26809 /** 26810 * Magic bit used to support features of framework-internal window decor implementation details. 26811 * This used to live exclusively in FrameLayout. 26812 * 26813 * @return true if the foreground should draw inside the padding region or false 26814 * if it should draw inset by the view's padding 26815 * @hide internal use only; only used by FrameLayout and internal screen layouts. 26816 */ isForegroundInsidePadding()26817 public boolean isForegroundInsidePadding() { 26818 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 26819 } 26820 26821 /** 26822 * Describes how the foreground is positioned. 26823 * 26824 * @return foreground gravity. 26825 * 26826 * @see #setForegroundGravity(int) 26827 * 26828 * @attr ref android.R.styleable#View_foregroundGravity 26829 */ 26830 @InspectableProperty(valueType = InspectableProperty.ValueType.GRAVITY) getForegroundGravity()26831 public int getForegroundGravity() { 26832 return mForegroundInfo != null ? mForegroundInfo.mGravity 26833 : Gravity.START | Gravity.TOP; 26834 } 26835 26836 /** 26837 * Describes how the foreground is positioned. Defaults to START and TOP. 26838 * 26839 * @param gravity see {@link android.view.Gravity} 26840 * 26841 * @see #getForegroundGravity() 26842 * 26843 * @attr ref android.R.styleable#View_foregroundGravity 26844 */ setForegroundGravity(int gravity)26845 public void setForegroundGravity(int gravity) { 26846 if (mForegroundInfo == null) { 26847 mForegroundInfo = new ForegroundInfo(); 26848 } 26849 26850 if (mForegroundInfo.mGravity != gravity) { 26851 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 26852 gravity |= Gravity.START; 26853 } 26854 26855 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 26856 gravity |= Gravity.TOP; 26857 } 26858 26859 mForegroundInfo.mGravity = gravity; 26860 requestLayout(); 26861 } 26862 } 26863 26864 /** 26865 * Applies a tint to the foreground drawable. Does not modify the current tint 26866 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 26867 * <p> 26868 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 26869 * mutate the drawable and apply the specified tint and tint mode using 26870 * {@link Drawable#setTintList(ColorStateList)}. 26871 * 26872 * @param tint the tint to apply, may be {@code null} to clear tint 26873 * 26874 * @attr ref android.R.styleable#View_foregroundTint 26875 * @see #getForegroundTintList() 26876 * @see Drawable#setTintList(ColorStateList) 26877 */ 26878 @RemotableViewMethod setForegroundTintList(@ullable ColorStateList tint)26879 public void setForegroundTintList(@Nullable ColorStateList tint) { 26880 if (mForegroundInfo == null) { 26881 mForegroundInfo = new ForegroundInfo(); 26882 } 26883 if (mForegroundInfo.mTintInfo == null) { 26884 mForegroundInfo.mTintInfo = new TintInfo(); 26885 } 26886 mForegroundInfo.mTintInfo.mTintList = tint; 26887 mForegroundInfo.mTintInfo.mHasTintList = true; 26888 26889 applyForegroundTint(); 26890 } 26891 26892 /** 26893 * Return the tint applied to the foreground drawable, if specified. 26894 * 26895 * @return the tint applied to the foreground drawable 26896 * @attr ref android.R.styleable#View_foregroundTint 26897 * @see #setForegroundTintList(ColorStateList) 26898 */ 26899 @InspectableProperty(name = "foregroundTint") 26900 @Nullable getForegroundTintList()26901 public ColorStateList getForegroundTintList() { 26902 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 26903 ? mForegroundInfo.mTintInfo.mTintList : null; 26904 } 26905 26906 /** 26907 * Specifies the blending mode used to apply the tint specified by 26908 * {@link #setForegroundTintList(ColorStateList)}} to the background 26909 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 26910 * 26911 * @param tintMode the blending mode used to apply the tint, may be 26912 * {@code null} to clear tint 26913 * @attr ref android.R.styleable#View_foregroundTintMode 26914 * @see #getForegroundTintMode() 26915 * @see Drawable#setTintMode(PorterDuff.Mode) 26916 * 26917 */ setForegroundTintMode(@ullable PorterDuff.Mode tintMode)26918 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 26919 BlendMode mode = null; 26920 if (tintMode != null) { 26921 mode = BlendMode.fromValue(tintMode.nativeInt); 26922 } 26923 setForegroundTintBlendMode(mode); 26924 } 26925 26926 /** 26927 * Specifies the blending mode used to apply the tint specified by 26928 * {@link #setForegroundTintList(ColorStateList)}} to the background 26929 * drawable. The default mode is {@link BlendMode#SRC_IN}. 26930 * 26931 * @param blendMode the blending mode used to apply the tint, may be 26932 * {@code null} to clear tint 26933 * @attr ref android.R.styleable#View_foregroundTintMode 26934 * @see #getForegroundTintMode() 26935 * @see Drawable#setTintBlendMode(BlendMode) 26936 */ 26937 @RemotableViewMethod setForegroundTintBlendMode(@ullable BlendMode blendMode)26938 public void setForegroundTintBlendMode(@Nullable BlendMode blendMode) { 26939 if (mForegroundInfo == null) { 26940 mForegroundInfo = new ForegroundInfo(); 26941 } 26942 if (mForegroundInfo.mTintInfo == null) { 26943 mForegroundInfo.mTintInfo = new TintInfo(); 26944 } 26945 mForegroundInfo.mTintInfo.mBlendMode = blendMode; 26946 mForegroundInfo.mTintInfo.mHasTintMode = true; 26947 26948 applyForegroundTint(); 26949 } 26950 26951 /** 26952 * Return the blending mode used to apply the tint to the foreground 26953 * drawable, if specified. 26954 * 26955 * @return the blending mode used to apply the tint to the foreground 26956 * drawable 26957 * @attr ref android.R.styleable#View_foregroundTintMode 26958 * @see #setForegroundTintMode(PorterDuff.Mode) 26959 */ 26960 @InspectableProperty 26961 @Nullable getForegroundTintMode()26962 public PorterDuff.Mode getForegroundTintMode() { 26963 BlendMode blendMode = mForegroundInfo != null && mForegroundInfo.mTintInfo != null 26964 ? mForegroundInfo.mTintInfo.mBlendMode : null; 26965 if (blendMode != null) { 26966 return BlendMode.blendModeToPorterDuffMode(blendMode); 26967 } else { 26968 return null; 26969 } 26970 } 26971 26972 /** 26973 * Return the blending mode used to apply the tint to the foreground 26974 * drawable, if specified. 26975 * 26976 * @return the blending mode used to apply the tint to the foreground 26977 * drawable 26978 * @attr ref android.R.styleable#View_foregroundTintMode 26979 * @see #setForegroundTintBlendMode(BlendMode) 26980 * 26981 */ getForegroundTintBlendMode()26982 public @Nullable BlendMode getForegroundTintBlendMode() { 26983 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 26984 ? mForegroundInfo.mTintInfo.mBlendMode : null; 26985 } 26986 applyForegroundTint()26987 private void applyForegroundTint() { 26988 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 26989 && mForegroundInfo.mTintInfo != null) { 26990 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 26991 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 26992 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 26993 26994 if (tintInfo.mHasTintList) { 26995 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 26996 } 26997 26998 if (tintInfo.mHasTintMode) { 26999 mForegroundInfo.mDrawable.setTintBlendMode(tintInfo.mBlendMode); 27000 } 27001 27002 // The drawable (or one of its children) may not have been 27003 // stateful before applying the tint, so let's try again. 27004 if (mForegroundInfo.mDrawable.isStateful()) { 27005 mForegroundInfo.mDrawable.setState(getDrawableState()); 27006 } 27007 } 27008 } 27009 } 27010 27011 /** 27012 * Get the drawable to be overlayed when a view is autofilled 27013 * 27014 * @return The drawable 27015 * 27016 * @throws IllegalStateException if the drawable could not be found. 27017 */ getAutofilledDrawable()27018 @Nullable private Drawable getAutofilledDrawable() { 27019 if (mAttachInfo == null) { 27020 return null; 27021 } 27022 // Lazily load the isAutofilled drawable. 27023 if (mAttachInfo.mAutofilledDrawable == null) { 27024 Context rootContext = getRootView().getContext(); 27025 TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR); 27026 int attributeResourceId = a.getResourceId(0, 0); 27027 mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId); 27028 a.recycle(); 27029 } 27030 27031 return mAttachInfo.mAutofilledDrawable; 27032 } 27033 27034 /** 27035 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled, unless 27036 * {@link #PFLAG4_AUTOFILL_HIDE_HIGHLIGHT} is enabled. 27037 * 27038 * @param canvas The canvas to draw on 27039 */ drawAutofilledHighlight(@onNull Canvas canvas)27040 private void drawAutofilledHighlight(@NonNull Canvas canvas) { 27041 if (isAutofilled() && !hideAutofillHighlight()) { 27042 Drawable autofilledHighlight = getAutofilledDrawable(); 27043 27044 if (autofilledHighlight != null) { 27045 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); 27046 autofilledHighlight.draw(canvas); 27047 } 27048 } 27049 } 27050 27051 /** 27052 * Draw any foreground content for this view. 27053 * 27054 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 27055 * drawable or other view-specific decorations. The foreground is drawn on top of the 27056 * primary view content.</p> 27057 * 27058 * @param canvas canvas to draw into 27059 */ onDrawForeground(@onNull Canvas canvas)27060 public void onDrawForeground(@NonNull Canvas canvas) { 27061 onDrawScrollIndicators(canvas); 27062 onDrawScrollBars(canvas); 27063 27064 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 27065 if (foreground != null) { 27066 if (mForegroundInfo.mBoundsChanged) { 27067 mForegroundInfo.mBoundsChanged = false; 27068 final Rect selfBounds = mForegroundInfo.mSelfBounds; 27069 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 27070 27071 if (mForegroundInfo.mInsidePadding) { 27072 selfBounds.set(0, 0, getWidth(), getHeight()); 27073 } else { 27074 selfBounds.set(getPaddingLeft(), getPaddingTop(), 27075 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 27076 } 27077 27078 final int ld = getLayoutDirection(); 27079 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 27080 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 27081 foreground.setBounds(overlayBounds); 27082 } 27083 27084 foreground.draw(canvas); 27085 } 27086 } 27087 27088 /** 27089 * Sets the padding. The view may add on the space required to display 27090 * the scrollbars, depending on the style and visibility of the scrollbars. 27091 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 27092 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 27093 * from the values set in this call. 27094 * 27095 * @attr ref android.R.styleable#View_padding 27096 * @attr ref android.R.styleable#View_paddingBottom 27097 * @attr ref android.R.styleable#View_paddingLeft 27098 * @attr ref android.R.styleable#View_paddingRight 27099 * @attr ref android.R.styleable#View_paddingTop 27100 * @param left the left padding in pixels 27101 * @param top the top padding in pixels 27102 * @param right the right padding in pixels 27103 * @param bottom the bottom padding in pixels 27104 */ setPadding(int left, int top, int right, int bottom)27105 public void setPadding(int left, int top, int right, int bottom) { 27106 resetResolvedPaddingInternal(); 27107 27108 mUserPaddingStart = UNDEFINED_PADDING; 27109 mUserPaddingEnd = UNDEFINED_PADDING; 27110 27111 mUserPaddingLeftInitial = left; 27112 mUserPaddingRightInitial = right; 27113 27114 mLeftPaddingDefined = true; 27115 mRightPaddingDefined = true; 27116 27117 internalSetPadding(left, top, right, bottom); 27118 } 27119 27120 /** 27121 * @hide 27122 */ 27123 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768420) internalSetPadding(int left, int top, int right, int bottom)27124 protected void internalSetPadding(int left, int top, int right, int bottom) { 27125 mUserPaddingLeft = left; 27126 mUserPaddingRight = right; 27127 mUserPaddingBottom = bottom; 27128 27129 final int viewFlags = mViewFlags; 27130 boolean changed = false; 27131 27132 // Common case is there are no scroll bars. 27133 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 27134 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 27135 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 27136 ? 0 : getVerticalScrollbarWidth(); 27137 switch (mVerticalScrollbarPosition) { 27138 case SCROLLBAR_POSITION_DEFAULT: 27139 if (isLayoutRtl()) { 27140 left += offset; 27141 } else { 27142 right += offset; 27143 } 27144 break; 27145 case SCROLLBAR_POSITION_RIGHT: 27146 right += offset; 27147 break; 27148 case SCROLLBAR_POSITION_LEFT: 27149 left += offset; 27150 break; 27151 } 27152 } 27153 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 27154 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 27155 ? 0 : getHorizontalScrollbarHeight(); 27156 } 27157 } 27158 27159 if (mPaddingLeft != left) { 27160 changed = true; 27161 mPaddingLeft = left; 27162 } 27163 if (mPaddingTop != top) { 27164 changed = true; 27165 mPaddingTop = top; 27166 } 27167 if (mPaddingRight != right) { 27168 changed = true; 27169 mPaddingRight = right; 27170 } 27171 if (mPaddingBottom != bottom) { 27172 changed = true; 27173 mPaddingBottom = bottom; 27174 } 27175 27176 if (changed) { 27177 requestLayout(); 27178 invalidateOutline(); 27179 } 27180 } 27181 27182 /** 27183 * Sets the relative padding. The view may add on the space required to display 27184 * the scrollbars, depending on the style and visibility of the scrollbars. 27185 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 27186 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 27187 * from the values set in this call. 27188 * 27189 * @attr ref android.R.styleable#View_padding 27190 * @attr ref android.R.styleable#View_paddingBottom 27191 * @attr ref android.R.styleable#View_paddingStart 27192 * @attr ref android.R.styleable#View_paddingEnd 27193 * @attr ref android.R.styleable#View_paddingTop 27194 * @param start the start padding in pixels 27195 * @param top the top padding in pixels 27196 * @param end the end padding in pixels 27197 * @param bottom the bottom padding in pixels 27198 */ setPaddingRelative(int start, int top, int end, int bottom)27199 public void setPaddingRelative(int start, int top, int end, int bottom) { 27200 resetResolvedPaddingInternal(); 27201 27202 mUserPaddingStart = start; 27203 mUserPaddingEnd = end; 27204 mLeftPaddingDefined = true; 27205 mRightPaddingDefined = true; 27206 27207 switch(getLayoutDirection()) { 27208 case LAYOUT_DIRECTION_RTL: 27209 mUserPaddingLeftInitial = end; 27210 mUserPaddingRightInitial = start; 27211 internalSetPadding(end, top, start, bottom); 27212 break; 27213 case LAYOUT_DIRECTION_LTR: 27214 default: 27215 mUserPaddingLeftInitial = start; 27216 mUserPaddingRightInitial = end; 27217 internalSetPadding(start, top, end, bottom); 27218 } 27219 } 27220 27221 /** 27222 * A {@link View} can be inflated from an XML layout. For such Views this method returns the 27223 * resource ID of the source layout. 27224 * 27225 * @return The layout resource id if this view was inflated from XML, otherwise 27226 * {@link Resources#ID_NULL}. 27227 */ 27228 @LayoutRes getSourceLayoutResId()27229 public int getSourceLayoutResId() { 27230 return mSourceLayoutId; 27231 } 27232 27233 /** 27234 * Returns the top padding of this view. 27235 * 27236 * @return the top padding in pixels 27237 */ 27238 @InspectableProperty getPaddingTop()27239 public int getPaddingTop() { 27240 return mPaddingTop; 27241 } 27242 27243 /** 27244 * Returns the bottom padding of this view. If there are inset and enabled 27245 * scrollbars, this value may include the space required to display the 27246 * scrollbars as well. 27247 * 27248 * @return the bottom padding in pixels 27249 */ 27250 @InspectableProperty getPaddingBottom()27251 public int getPaddingBottom() { 27252 return mPaddingBottom; 27253 } 27254 27255 /** 27256 * Returns the left padding of this view. If there are inset and enabled 27257 * scrollbars, this value may include the space required to display the 27258 * scrollbars as well. 27259 * 27260 * @return the left padding in pixels 27261 */ 27262 @InspectableProperty getPaddingLeft()27263 public int getPaddingLeft() { 27264 if (!isPaddingResolved()) { 27265 resolvePadding(); 27266 } 27267 return mPaddingLeft; 27268 } 27269 27270 /** 27271 * Returns the start padding of this view depending on its resolved layout direction. 27272 * If there are inset and enabled scrollbars, this value may include the space 27273 * required to display the scrollbars as well. 27274 * 27275 * @return the start padding in pixels 27276 */ getPaddingStart()27277 public int getPaddingStart() { 27278 if (!isPaddingResolved()) { 27279 resolvePadding(); 27280 } 27281 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 27282 mPaddingRight : mPaddingLeft; 27283 } 27284 27285 /** 27286 * Returns the right padding of this view. If there are inset and enabled 27287 * scrollbars, this value may include the space required to display the 27288 * scrollbars as well. 27289 * 27290 * @return the right padding in pixels 27291 */ 27292 @InspectableProperty getPaddingRight()27293 public int getPaddingRight() { 27294 if (!isPaddingResolved()) { 27295 resolvePadding(); 27296 } 27297 return mPaddingRight; 27298 } 27299 27300 /** 27301 * Returns the end padding of this view depending on its resolved layout direction. 27302 * If there are inset and enabled scrollbars, this value may include the space 27303 * required to display the scrollbars as well. 27304 * 27305 * @return the end padding in pixels 27306 */ getPaddingEnd()27307 public int getPaddingEnd() { 27308 if (!isPaddingResolved()) { 27309 resolvePadding(); 27310 } 27311 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 27312 mPaddingLeft : mPaddingRight; 27313 } 27314 27315 /** 27316 * Return if the padding has been set through relative values 27317 * {@link #setPaddingRelative(int, int, int, int)} or through 27318 * @attr ref android.R.styleable#View_paddingStart or 27319 * @attr ref android.R.styleable#View_paddingEnd 27320 * 27321 * @return true if the padding is relative or false if it is not. 27322 */ isPaddingRelative()27323 public boolean isPaddingRelative() { 27324 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 27325 } 27326 computeOpticalInsets()27327 Insets computeOpticalInsets() { 27328 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 27329 } 27330 27331 /** 27332 * @hide 27333 */ 27334 @UnsupportedAppUsage resetPaddingToInitialValues()27335 public void resetPaddingToInitialValues() { 27336 if (isRtlCompatibilityMode()) { 27337 mPaddingLeft = mUserPaddingLeftInitial; 27338 mPaddingRight = mUserPaddingRightInitial; 27339 return; 27340 } 27341 if (isLayoutRtl()) { 27342 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 27343 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 27344 } else { 27345 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 27346 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 27347 } 27348 } 27349 27350 /** 27351 * @hide 27352 */ getOpticalInsets()27353 public Insets getOpticalInsets() { 27354 if (mLayoutInsets == null) { 27355 mLayoutInsets = computeOpticalInsets(); 27356 } 27357 return mLayoutInsets; 27358 } 27359 27360 /** 27361 * Set this view's optical insets. 27362 * 27363 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 27364 * property. Views that compute their own optical insets should call it as part of measurement. 27365 * This method does not request layout. If you are setting optical insets outside of 27366 * measure/layout itself you will want to call requestLayout() yourself. 27367 * </p> 27368 * @hide 27369 */ setOpticalInsets(Insets insets)27370 public void setOpticalInsets(Insets insets) { 27371 mLayoutInsets = insets; 27372 } 27373 27374 /** 27375 * Changes the selection state of this view. A view can be selected or not. 27376 * Note that selection is not the same as focus. Views are typically 27377 * selected in the context of an AdapterView like ListView or GridView; 27378 * the selected view is the view that is highlighted. 27379 * 27380 * @param selected true if the view must be selected, false otherwise 27381 */ setSelected(boolean selected)27382 public void setSelected(boolean selected) { 27383 //noinspection DoubleNegation 27384 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 27385 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 27386 if (!selected) resetPressedState(); 27387 invalidate(true); 27388 refreshDrawableState(); 27389 dispatchSetSelected(selected); 27390 if (selected) { 27391 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 27392 } else { 27393 notifyViewAccessibilityStateChangedIfNeeded( 27394 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 27395 } 27396 } 27397 } 27398 27399 /** 27400 * Dispatch setSelected to all of this View's children. 27401 * 27402 * @see #setSelected(boolean) 27403 * 27404 * @param selected The new selected state 27405 */ dispatchSetSelected(boolean selected)27406 protected void dispatchSetSelected(boolean selected) { 27407 } 27408 27409 /** 27410 * Indicates the selection state of this view. 27411 * 27412 * @return true if the view is selected, false otherwise 27413 */ 27414 @ViewDebug.ExportedProperty 27415 @InspectableProperty(hasAttributeId = false) isSelected()27416 public boolean isSelected() { 27417 return (mPrivateFlags & PFLAG_SELECTED) != 0; 27418 } 27419 27420 /** 27421 * Changes the activated state of this view. A view can be activated or not. 27422 * Note that activation is not the same as selection. Selection is 27423 * a transient property, representing the view (hierarchy) the user is 27424 * currently interacting with. Activation is a longer-term state that the 27425 * user can move views in and out of. For example, in a list view with 27426 * single or multiple selection enabled, the views in the current selection 27427 * set are activated. (Um, yeah, we are deeply sorry about the terminology 27428 * here.) The activated state is propagated down to children of the view it 27429 * is set on. 27430 * 27431 * @param activated true if the view must be activated, false otherwise 27432 */ setActivated(boolean activated)27433 public void setActivated(boolean activated) { 27434 //noinspection DoubleNegation 27435 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 27436 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 27437 invalidate(true); 27438 refreshDrawableState(); 27439 dispatchSetActivated(activated); 27440 } 27441 } 27442 27443 /** 27444 * Dispatch setActivated to all of this View's children. 27445 * 27446 * @see #setActivated(boolean) 27447 * 27448 * @param activated The new activated state 27449 */ dispatchSetActivated(boolean activated)27450 protected void dispatchSetActivated(boolean activated) { 27451 } 27452 27453 /** 27454 * Indicates the activation state of this view. 27455 * 27456 * @return true if the view is activated, false otherwise 27457 */ 27458 @ViewDebug.ExportedProperty 27459 @InspectableProperty(hasAttributeId = false) isActivated()27460 public boolean isActivated() { 27461 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 27462 } 27463 27464 /** 27465 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 27466 * observer can be used to get notifications when global events, like 27467 * layout, happen. 27468 * 27469 * The returned ViewTreeObserver observer is not guaranteed to remain 27470 * valid for the lifetime of this View. If the caller of this method keeps 27471 * a long-lived reference to ViewTreeObserver, it should always check for 27472 * the return value of {@link ViewTreeObserver#isAlive()}. 27473 * 27474 * @return The ViewTreeObserver for this view's hierarchy. 27475 */ getViewTreeObserver()27476 public ViewTreeObserver getViewTreeObserver() { 27477 if (mAttachInfo != null) { 27478 return mAttachInfo.mTreeObserver; 27479 } 27480 if (mFloatingTreeObserver == null) { 27481 mFloatingTreeObserver = new ViewTreeObserver(mContext); 27482 } 27483 return mFloatingTreeObserver; 27484 } 27485 27486 /** 27487 * <p>Finds the topmost view in the current view hierarchy.</p> 27488 * 27489 * @return the topmost view containing this view 27490 */ getRootView()27491 public View getRootView() { 27492 if (mAttachInfo != null) { 27493 final View v = mAttachInfo.mRootView; 27494 if (v != null) { 27495 return v; 27496 } 27497 } 27498 27499 View parent = this; 27500 27501 while (parent.mParent instanceof View) { 27502 parent = (View) parent.mParent; 27503 } 27504 27505 return parent; 27506 } 27507 27508 /** 27509 * Transforms a motion event from view-local coordinates to on-screen 27510 * coordinates. 27511 * 27512 * @param ev the view-local motion event 27513 * @return false if the transformation could not be applied 27514 * @hide 27515 */ 27516 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) toGlobalMotionEvent(MotionEvent ev)27517 public boolean toGlobalMotionEvent(MotionEvent ev) { 27518 final AttachInfo info = mAttachInfo; 27519 if (info == null) { 27520 return false; 27521 } 27522 27523 final Matrix m = info.mTmpMatrix; 27524 m.set(Matrix.IDENTITY_MATRIX); 27525 transformMatrixToGlobal(m); 27526 ev.transform(m); 27527 return true; 27528 } 27529 27530 /** 27531 * Transforms a motion event from on-screen coordinates to view-local 27532 * coordinates. 27533 * 27534 * @param ev the on-screen motion event 27535 * @return false if the transformation could not be applied 27536 * @hide 27537 */ 27538 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) toLocalMotionEvent(MotionEvent ev)27539 public boolean toLocalMotionEvent(MotionEvent ev) { 27540 final AttachInfo info = mAttachInfo; 27541 if (info == null) { 27542 return false; 27543 } 27544 27545 final Matrix m = info.mTmpMatrix; 27546 m.set(Matrix.IDENTITY_MATRIX); 27547 transformMatrixToLocal(m); 27548 ev.transform(m); 27549 return true; 27550 } 27551 27552 /** 27553 * Modifies the input matrix such that it maps view-local coordinates to 27554 * on-screen coordinates. 27555 * 27556 * @param matrix input matrix to modify 27557 */ transformMatrixToGlobal(@onNull Matrix matrix)27558 public void transformMatrixToGlobal(@NonNull Matrix matrix) { 27559 final ViewParent parent = mParent; 27560 if (parent instanceof View) { 27561 final View vp = (View) parent; 27562 vp.transformMatrixToGlobal(matrix); 27563 matrix.preTranslate(-vp.mScrollX, -vp.mScrollY); 27564 } else if (parent instanceof ViewRootImpl) { 27565 final ViewRootImpl vr = (ViewRootImpl) parent; 27566 vr.transformMatrixToGlobal(matrix); 27567 matrix.preTranslate(0, -vr.mCurScrollY); 27568 } 27569 27570 matrix.preTranslate(mLeft, mTop); 27571 27572 if (!hasIdentityMatrix()) { 27573 matrix.preConcat(getMatrix()); 27574 } 27575 } 27576 27577 /** 27578 * Modifies the input matrix such that it maps on-screen coordinates to 27579 * view-local coordinates. 27580 * 27581 * @param matrix input matrix to modify 27582 */ transformMatrixToLocal(@onNull Matrix matrix)27583 public void transformMatrixToLocal(@NonNull Matrix matrix) { 27584 final ViewParent parent = mParent; 27585 if (parent instanceof View) { 27586 final View vp = (View) parent; 27587 vp.transformMatrixToLocal(matrix); 27588 matrix.postTranslate(vp.mScrollX, vp.mScrollY); 27589 } else if (parent instanceof ViewRootImpl) { 27590 final ViewRootImpl vr = (ViewRootImpl) parent; 27591 vr.transformMatrixToLocal(matrix); 27592 matrix.postTranslate(0, vr.mCurScrollY); 27593 } 27594 27595 matrix.postTranslate(-mLeft, -mTop); 27596 27597 if (!hasIdentityMatrix()) { 27598 matrix.postConcat(getInverseMatrix()); 27599 } 27600 } 27601 27602 /** 27603 * Modifiers the input matrix such that it maps root view's coordinates to view-local 27604 * coordinates. 27605 * 27606 * @param matrix input matrix to modify 27607 * @hide 27608 */ transformMatrixRootToLocal(@onNull Matrix matrix)27609 public void transformMatrixRootToLocal(@NonNull Matrix matrix) { 27610 final ViewParent parent = mParent; 27611 if (parent instanceof final View vp) { 27612 vp.transformMatrixRootToLocal(matrix); 27613 matrix.postTranslate(vp.mScrollX, vp.mScrollY); 27614 } 27615 // This method is different from transformMatrixToLocal that it doesn't perform any 27616 // transformation for ViewRootImpl 27617 27618 matrix.postTranslate(-mLeft, -mTop); 27619 27620 if (!hasIdentityMatrix()) { 27621 matrix.postConcat(getInverseMatrix()); 27622 } 27623 } 27624 27625 /** 27626 * @hide 27627 */ 27628 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 27629 @ViewDebug.IntToString(from = 0, to = "x"), 27630 @ViewDebug.IntToString(from = 1, to = "y") 27631 }) 27632 @UnsupportedAppUsage getLocationOnScreen()27633 public int[] getLocationOnScreen() { 27634 int[] location = new int[2]; 27635 getLocationOnScreen(location); 27636 return location; 27637 } 27638 27639 /** 27640 * Gets the coordinates of this view in the coordinate space of the device 27641 * screen, irrespective of system decorations and whether the system is in 27642 * multi-window mode. 27643 * 27644 * <p>In multi-window mode, the coordinate space encompasses the entire 27645 * device screen, ignoring the bounds of the app window. For example, if the 27646 * view is in the bottom portion of a horizontal split screen, the top edge 27647 * of the screen—not the top edge of the window—is the origin 27648 * from which the y-coordinate is calculated. 27649 * 27650 * <p>In multiple-screen scenarios, the coordinate space can span screens. 27651 * For example, if the app is spanning both screens of a dual-screen device 27652 * and the view is located on the right-hand screen, the x-coordinate is 27653 * calculated from the left edge of the left-hand screen to the left edge of 27654 * the view. When the app is restricted to a single screen in a 27655 * multiple-screen environment, the coordinate space includes only the 27656 * screen on which the app is running. 27657 * 27658 * <p>After the method returns, the argument array contains the x and y 27659 * coordinates of the view relative to the view's left and top edges, 27660 * respectively. 27661 * 27662 * @param outLocation A two-element integer array in which the view 27663 * coordinates are stored. The x-coordinate is at index 0; the 27664 * y-coordinate, at index 1. 27665 */ getLocationOnScreen(@ize2) int[] outLocation)27666 public void getLocationOnScreen(@Size(2) int[] outLocation) { 27667 getLocationInWindow(outLocation); 27668 27669 final AttachInfo info = mAttachInfo; 27670 if (info != null) { 27671 outLocation[0] += info.mWindowLeft; 27672 outLocation[1] += info.mWindowTop; 27673 // If OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS override is enabled, 27674 // applyViewLocationSandboxingIfNeeded sandboxes outLocation within window bounds. 27675 info.mViewRootImpl.applyViewLocationSandboxingIfNeeded(outLocation); 27676 } 27677 } 27678 27679 /** 27680 * Gets the coordinates of this view in the coordinate space of the window 27681 * that contains the view, irrespective of system decorations. 27682 * 27683 * <p>In multi-window mode, the origin of the coordinate space is the 27684 * top left corner of the window that contains the view. In full screen 27685 * mode, the origin is the top left corner of the device screen. 27686 * 27687 * <p>In multiple-screen scenarios, if the app spans multiple screens, the 27688 * coordinate space also spans multiple screens. But if the app is 27689 * restricted to a single screen, the coordinate space includes only the 27690 * screen on which the app is running. 27691 * 27692 * <p>After the method returns, the argument array contains the x and y 27693 * coordinates of the view relative to the view's left and top edges, 27694 * respectively. 27695 * 27696 * @param outLocation A two-element integer array in which the view 27697 * coordinates are stored. The x-coordinate is at index 0; the 27698 * y-coordinate, at index 1. 27699 */ getLocationInWindow(@ize2) int[] outLocation)27700 public void getLocationInWindow(@Size(2) int[] outLocation) { 27701 if (outLocation == null || outLocation.length < 2) { 27702 throw new IllegalArgumentException("outLocation must be an array of two integers"); 27703 } 27704 27705 outLocation[0] = 0; 27706 outLocation[1] = 0; 27707 27708 transformFromViewToWindowSpace(outLocation); 27709 } 27710 27711 /** @hide */ transformFromViewToWindowSpace(@ize2) int[] inOutLocation)27712 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 27713 if (inOutLocation == null || inOutLocation.length < 2) { 27714 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 27715 } 27716 27717 if (mAttachInfo == null) { 27718 // When the view is not attached to a window, this method does not make sense 27719 inOutLocation[0] = inOutLocation[1] = 0; 27720 return; 27721 } 27722 27723 float position[] = mAttachInfo.mTmpTransformLocation; 27724 position[0] = inOutLocation[0]; 27725 position[1] = inOutLocation[1]; 27726 27727 if (!hasIdentityMatrix()) { 27728 getMatrix().mapPoints(position); 27729 } 27730 27731 position[0] += mLeft; 27732 position[1] += mTop; 27733 27734 ViewParent viewParent = mParent; 27735 while (viewParent instanceof View) { 27736 final View view = (View) viewParent; 27737 27738 position[0] -= view.mScrollX; 27739 position[1] -= view.mScrollY; 27740 27741 if (!view.hasIdentityMatrix()) { 27742 view.getMatrix().mapPoints(position); 27743 } 27744 27745 position[0] += view.mLeft; 27746 position[1] += view.mTop; 27747 27748 viewParent = view.mParent; 27749 } 27750 27751 if (viewParent instanceof ViewRootImpl) { 27752 // *cough* 27753 final ViewRootImpl vr = (ViewRootImpl) viewParent; 27754 position[1] -= vr.mCurScrollY; 27755 } 27756 27757 inOutLocation[0] = Math.round(position[0]); 27758 inOutLocation[1] = Math.round(position[1]); 27759 } 27760 27761 /** 27762 * @param id the id of the view to be found 27763 * @return the view of the specified id, null if cannot be found 27764 * @hide 27765 */ findViewTraversal(@dRes int id)27766 protected <T extends View> T findViewTraversal(@IdRes int id) { 27767 if (id == mID) { 27768 return (T) this; 27769 } 27770 return null; 27771 } 27772 27773 /** 27774 * @param tag the tag of the view to be found 27775 * @return the view of specified tag, null if cannot be found 27776 * @hide 27777 */ findViewWithTagTraversal(Object tag)27778 protected <T extends View> T findViewWithTagTraversal(Object tag) { 27779 if (tag != null && tag.equals(mTag)) { 27780 return (T) this; 27781 } 27782 return null; 27783 } 27784 27785 /** 27786 * @param predicate The predicate to evaluate. 27787 * @param childToSkip If not null, ignores this child during the recursive traversal. 27788 * @return The first view that matches the predicate or null. 27789 * @hide 27790 */ findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip)27791 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 27792 View childToSkip) { 27793 if (predicate.test(this)) { 27794 return (T) this; 27795 } 27796 return null; 27797 } 27798 27799 /** 27800 * Finds the first descendant view with the given ID, the view itself if 27801 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid 27802 * (< 0) or there is no matching view in the hierarchy. 27803 * <p> 27804 * <strong>Note:</strong> In most cases -- depending on compiler support -- 27805 * the resulting view is automatically cast to the target class type. If 27806 * the target class type is unconstrained, an explicit cast may be 27807 * necessary. 27808 * 27809 * @param id the ID to search for 27810 * @return a view with given ID if found, or {@code null} otherwise 27811 * @see View#requireViewById(int) 27812 */ 27813 // Strictly speaking this should be marked as @Nullable but the nullability of the return value 27814 // is deliberately left unspecified as idiomatically correct code can make assumptions either 27815 // way based on local context, e.g. layout specification. findViewById(@dRes int id)27816 public final <T extends View> T findViewById(@IdRes int id) { 27817 if (id == NO_ID) { 27818 return null; 27819 } 27820 return findViewTraversal(id); 27821 } 27822 27823 /** 27824 * Finds the first descendant view with the given ID, the view itself if the ID matches 27825 * {@link #getId()}, or throws an IllegalArgumentException if the ID is invalid or there is no 27826 * matching view in the hierarchy. 27827 * <p> 27828 * <strong>Note:</strong> In most cases -- depending on compiler support -- 27829 * the resulting view is automatically cast to the target class type. If 27830 * the target class type is unconstrained, an explicit cast may be 27831 * necessary. 27832 * 27833 * @param id the ID to search for 27834 * @return a view with given ID 27835 * @see View#findViewById(int) 27836 */ 27837 @NonNull requireViewById(@dRes int id)27838 public final <T extends View> T requireViewById(@IdRes int id) { 27839 T view = findViewById(id); 27840 if (view == null) { 27841 throw new IllegalArgumentException("ID does not reference a View inside this View"); 27842 } 27843 return view; 27844 } 27845 27846 /** 27847 * Performs the traversal to find a view by its unique and stable accessibility id. 27848 * 27849 * <strong>Note:</strong>This method does not stop at the root namespace 27850 * boundary since the user can touch the screen at an arbitrary location 27851 * potentially crossing the root namespace boundary which will send an 27852 * accessibility event to accessibility services and they should be able 27853 * to obtain the event source. Also accessibility ids are guaranteed to be 27854 * unique in the window. 27855 * 27856 * @param accessibilityId The accessibility id. 27857 * @return The found view. 27858 * @hide 27859 */ findViewByAccessibilityIdTraversal(int accessibilityId)27860 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 27861 if (getAccessibilityViewId() == accessibilityId) { 27862 return (T) this; 27863 } 27864 return null; 27865 } 27866 27867 /** 27868 * Performs the traversal to find a view by its autofill id. 27869 * 27870 * <strong>Note:</strong>This method does not stop at the root namespace 27871 * boundary. 27872 * 27873 * @param autofillId The autofill id. 27874 * @return The found view. 27875 * @hide 27876 */ findViewByAutofillIdTraversal(int autofillId)27877 public <T extends View> T findViewByAutofillIdTraversal(int autofillId) { 27878 if (getAutofillViewId() == autofillId) { 27879 return (T) this; 27880 } 27881 return null; 27882 } 27883 27884 27885 /** 27886 * Performs the traversal to find views that are autofillable. 27887 * Autofillable views are added to the provided list. 27888 * 27889 * <strong>Note:</strong>This method does not stop at the root namespace 27890 * boundary. 27891 * 27892 * @param autofillableViews The output list of autofillable Views. 27893 * @hide 27894 */ findAutofillableViewsByTraversal(@onNull List<View> autofillableViews)27895 public void findAutofillableViewsByTraversal(@NonNull List<View> autofillableViews) { 27896 if (isAutofillable()) { 27897 autofillableViews.add(this); 27898 } 27899 } 27900 27901 /** 27902 * Look for a child view with the given tag. If this view has the given 27903 * tag, return this view. 27904 * 27905 * @param tag The tag to search for, using "tag.equals(getTag())". 27906 * @return The View that has the given tag in the hierarchy or null 27907 */ findViewWithTag(Object tag)27908 public final <T extends View> T findViewWithTag(Object tag) { 27909 if (tag == null) { 27910 return null; 27911 } 27912 return findViewWithTagTraversal(tag); 27913 } 27914 27915 /** 27916 * Look for a child view that matches the specified predicate. 27917 * If this view matches the predicate, return this view. 27918 * 27919 * @param predicate The predicate to evaluate. 27920 * @return The first view that matches the predicate or null. 27921 * @hide 27922 */ findViewByPredicate(Predicate<View> predicate)27923 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 27924 return findViewByPredicateTraversal(predicate, null); 27925 } 27926 27927 /** 27928 * Look for a child view that matches the specified predicate, 27929 * starting with the specified view and its descendents and then 27930 * recusively searching the ancestors and siblings of that view 27931 * until this view is reached. 27932 * 27933 * This method is useful in cases where the predicate does not match 27934 * a single unique view (perhaps multiple views use the same id) 27935 * and we are trying to find the view that is "closest" in scope to the 27936 * starting view. 27937 * 27938 * @param start The view to start from. 27939 * @param predicate The predicate to evaluate. 27940 * @return The first view that matches the predicate or null. 27941 * @hide 27942 */ findViewByPredicateInsideOut( View start, Predicate<View> predicate)27943 public final <T extends View> T findViewByPredicateInsideOut( 27944 View start, Predicate<View> predicate) { 27945 View childToSkip = null; 27946 for (;;) { 27947 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 27948 if (view != null || start == this) { 27949 return view; 27950 } 27951 27952 ViewParent parent = start.getParent(); 27953 if (parent == null || !(parent instanceof View)) { 27954 return null; 27955 } 27956 27957 childToSkip = start; 27958 start = (View) parent; 27959 } 27960 } 27961 27962 /** 27963 * Sets the identifier for this view. The identifier does not have to be 27964 * unique in this view's hierarchy. The identifier should be a positive 27965 * number. 27966 * 27967 * @see #NO_ID 27968 * @see #getId() 27969 * @see #findViewById(int) 27970 * 27971 * @param id a number used to identify the view 27972 * 27973 * @attr ref android.R.styleable#View_id 27974 */ setId(@dRes int id)27975 public void setId(@IdRes int id) { 27976 mID = id; 27977 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 27978 mID = generateViewId(); 27979 } 27980 } 27981 27982 /** 27983 * {@hide} 27984 * 27985 * @param isRoot true if the view belongs to the root namespace, false 27986 * otherwise 27987 */ 27988 @UnsupportedAppUsage 27989 @TestApi setIsRootNamespace(boolean isRoot)27990 public void setIsRootNamespace(boolean isRoot) { 27991 if (isRoot) { 27992 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 27993 } else { 27994 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 27995 } 27996 } 27997 27998 /** 27999 * {@hide} 28000 * 28001 * @return true if the view belongs to the root namespace, false otherwise 28002 */ 28003 @UnsupportedAppUsage isRootNamespace()28004 public boolean isRootNamespace() { 28005 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 28006 } 28007 28008 /** 28009 * Returns this view's identifier. 28010 * 28011 * @return a positive integer used to identify the view or {@link #NO_ID} 28012 * if the view has no ID 28013 * 28014 * @see #setId(int) 28015 * @see #findViewById(int) 28016 * @attr ref android.R.styleable#View_id 28017 */ 28018 @IdRes 28019 @ViewDebug.CapturedViewProperty 28020 @InspectableProperty getId()28021 public int getId() { 28022 return mID; 28023 } 28024 28025 /** 28026 * Get the identifier used for this view by the drawing system. 28027 * 28028 * @see RenderNode#getUniqueId() 28029 * @return A long that uniquely identifies this view's drawing component 28030 */ getUniqueDrawingId()28031 public long getUniqueDrawingId() { 28032 return mRenderNode.getUniqueId(); 28033 } 28034 28035 /** 28036 * Returns this view's tag. 28037 * 28038 * @return the Object stored in this view as a tag, or {@code null} if not 28039 * set 28040 * 28041 * @see #setTag(Object) 28042 * @see #getTag(int) 28043 */ 28044 @ViewDebug.ExportedProperty 28045 @InspectableProperty getTag()28046 public Object getTag() { 28047 return mTag; 28048 } 28049 28050 /** 28051 * Sets the tag associated with this view. A tag can be used to mark 28052 * a view in its hierarchy and does not have to be unique within the 28053 * hierarchy. Tags can also be used to store data within a view without 28054 * resorting to another data structure. 28055 * 28056 * @param tag an Object to tag the view with 28057 * 28058 * @see #getTag() 28059 * @see #setTag(int, Object) 28060 */ setTag(final Object tag)28061 public void setTag(final Object tag) { 28062 mTag = tag; 28063 } 28064 28065 /** 28066 * Returns the tag associated with this view and the specified key. 28067 * 28068 * @param key The key identifying the tag 28069 * 28070 * @return the Object stored in this view as a tag, or {@code null} if not 28071 * set 28072 * 28073 * @see #setTag(int, Object) 28074 * @see #getTag() 28075 */ getTag(int key)28076 public Object getTag(int key) { 28077 if (mKeyedTags != null) return mKeyedTags.get(key); 28078 return null; 28079 } 28080 28081 /** 28082 * Sets a tag associated with this view and a key. A tag can be used 28083 * to mark a view in its hierarchy and does not have to be unique within 28084 * the hierarchy. Tags can also be used to store data within a view 28085 * without resorting to another data structure. 28086 * 28087 * The specified key should be an id declared in the resources of the 28088 * application to ensure it is unique (see the <a 28089 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 28090 * Keys identified as belonging to 28091 * the Android framework or not associated with any package will cause 28092 * an {@link IllegalArgumentException} to be thrown. 28093 * 28094 * @param key The key identifying the tag 28095 * @param tag An Object to tag the view with 28096 * 28097 * @throws IllegalArgumentException If they specified key is not valid 28098 * 28099 * @see #setTag(Object) 28100 * @see #getTag(int) 28101 */ setTag(int key, final Object tag)28102 public void setTag(int key, final Object tag) { 28103 // If the package id is 0x00 or 0x01, it's either an undefined package 28104 // or a framework id 28105 if ((key >>> 24) < 2) { 28106 throw new IllegalArgumentException("The key must be an application-specific " 28107 + "resource id."); 28108 } 28109 28110 setKeyedTag(key, tag); 28111 } 28112 28113 /** 28114 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 28115 * framework id. 28116 * 28117 * @hide 28118 */ 28119 @UnsupportedAppUsage setTagInternal(int key, Object tag)28120 public void setTagInternal(int key, Object tag) { 28121 if ((key >>> 24) != 0x1) { 28122 throw new IllegalArgumentException("The key must be a framework-specific " 28123 + "resource id."); 28124 } 28125 28126 setKeyedTag(key, tag); 28127 } 28128 setKeyedTag(int key, Object tag)28129 private void setKeyedTag(int key, Object tag) { 28130 if (mKeyedTags == null) { 28131 mKeyedTags = new SparseArray<Object>(2); 28132 } 28133 28134 mKeyedTags.put(key, tag); 28135 } 28136 28137 /** 28138 * Prints information about this view in the log output, with the tag 28139 * {@link #VIEW_LOG_TAG}. 28140 * 28141 * @hide 28142 */ 28143 @UnsupportedAppUsage debug()28144 public void debug() { 28145 debug(0); 28146 } 28147 28148 /** 28149 * Prints information about this view in the log output, with the tag 28150 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 28151 * indentation defined by the <code>depth</code>. 28152 * 28153 * @param depth the indentation level 28154 * 28155 * @hide 28156 */ 28157 @UnsupportedAppUsage debug(int depth)28158 protected void debug(int depth) { 28159 String output = debugIndent(depth - 1); 28160 28161 output += "+ " + this; 28162 int id = getId(); 28163 if (id != -1) { 28164 output += " (id=" + id + ")"; 28165 } 28166 Object tag = getTag(); 28167 if (tag != null) { 28168 output += " (tag=" + tag + ")"; 28169 } 28170 Log.d(VIEW_LOG_TAG, output); 28171 28172 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 28173 output = debugIndent(depth) + " FOCUSED"; 28174 Log.d(VIEW_LOG_TAG, output); 28175 } 28176 28177 output = debugIndent(depth); 28178 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 28179 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 28180 + "} "; 28181 Log.d(VIEW_LOG_TAG, output); 28182 28183 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 28184 || mPaddingBottom != 0) { 28185 output = debugIndent(depth); 28186 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 28187 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 28188 Log.d(VIEW_LOG_TAG, output); 28189 } 28190 28191 output = debugIndent(depth); 28192 output += "mMeasureWidth=" + mMeasuredWidth + 28193 " mMeasureHeight=" + mMeasuredHeight; 28194 Log.d(VIEW_LOG_TAG, output); 28195 28196 output = debugIndent(depth); 28197 if (mLayoutParams == null) { 28198 output += "BAD! no layout params"; 28199 } else { 28200 output = mLayoutParams.debug(output); 28201 } 28202 Log.d(VIEW_LOG_TAG, output); 28203 28204 output = debugIndent(depth); 28205 output += "flags={"; 28206 output += View.printFlags(mViewFlags); 28207 output += "}"; 28208 Log.d(VIEW_LOG_TAG, output); 28209 28210 output = debugIndent(depth); 28211 output += "privateFlags={"; 28212 output += View.printPrivateFlags(mPrivateFlags); 28213 output += "}"; 28214 Log.d(VIEW_LOG_TAG, output); 28215 } 28216 28217 /** 28218 * Creates a string of whitespaces used for indentation. 28219 * 28220 * @param depth the indentation level 28221 * @return a String containing (depth * 2 + 3) * 2 white spaces 28222 * 28223 * @hide 28224 */ debugIndent(int depth)28225 protected static String debugIndent(int depth) { 28226 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 28227 for (int i = 0; i < (depth * 2) + 3; i++) { 28228 spaces.append(' ').append(' '); 28229 } 28230 return spaces.toString(); 28231 } 28232 28233 /** 28234 * <p>Return the offset of the widget's text baseline from the widget's top 28235 * boundary. If this widget does not support baseline alignment, this 28236 * method returns -1. </p> 28237 * 28238 * @return the offset of the baseline within the widget's bounds or -1 28239 * if baseline alignment is not supported 28240 */ 28241 @ViewDebug.ExportedProperty(category = "layout") 28242 @InspectableProperty getBaseline()28243 public int getBaseline() { 28244 return -1; 28245 } 28246 28247 /** 28248 * Returns whether the view hierarchy is currently undergoing a layout pass. This 28249 * information is useful to avoid situations such as calling {@link #requestLayout()} during 28250 * a layout pass. 28251 * 28252 * @return whether the view hierarchy is currently undergoing a layout pass 28253 */ isInLayout()28254 public boolean isInLayout() { 28255 ViewRootImpl viewRoot = getViewRootImpl(); 28256 return (viewRoot != null && viewRoot.isInLayout()); 28257 } 28258 28259 /** To be used only for debugging purposes. */ printStackStrace(String name)28260 private void printStackStrace(String name) { 28261 Log.d(VIEW_LOG_TAG, "---- ST:" + name); 28262 28263 StringBuilder sb = new StringBuilder(); 28264 StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); 28265 int startIndex = 1; 28266 int endIndex = Math.min(stackTraceElements.length, startIndex + 20); // max 20 entries. 28267 for (int i = startIndex; i < endIndex; i++) { 28268 StackTraceElement s = stackTraceElements[i]; 28269 sb.append(s.getMethodName()) 28270 .append("(") 28271 .append(s.getFileName()) 28272 .append(":") 28273 .append(s.getLineNumber()) 28274 .append(") <- "); 28275 } 28276 Log.d(VIEW_LOG_TAG, name + ": " + sb); 28277 } 28278 /** 28279 * Call this when something has changed which has invalidated the 28280 * layout of this view. This will schedule a layout pass of the view 28281 * tree. This should not be called while the view hierarchy is currently in a layout 28282 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 28283 * end of the current layout pass (and then layout will run again) or after the current 28284 * frame is drawn and the next layout occurs. 28285 * 28286 * <p>Subclasses which override this method should call the superclass method to 28287 * handle possible request-during-layout errors correctly.</p> 28288 */ 28289 @CallSuper requestLayout()28290 public void requestLayout() { 28291 if (isRelayoutTracingEnabled()) { 28292 Trace.instantForTrack(TRACE_TAG_APP, "requestLayoutTracing", 28293 mTracingStrings.classSimpleName); 28294 printStackStrace(mTracingStrings.requestLayoutStacktracePrefix); 28295 } 28296 28297 if (mMeasureCache != null) mMeasureCache.clear(); 28298 28299 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 28300 // Only trigger request-during-layout logic if this is the view requesting it, 28301 // not the views in its parent hierarchy 28302 ViewRootImpl viewRoot = getViewRootImpl(); 28303 if (viewRoot != null && viewRoot.isInLayout()) { 28304 if (!viewRoot.requestLayoutDuringLayout(this)) { 28305 return; 28306 } 28307 } 28308 mAttachInfo.mViewRequestingLayout = this; 28309 } 28310 28311 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 28312 mPrivateFlags |= PFLAG_INVALIDATED; 28313 28314 if (mParent != null && !mParent.isLayoutRequested()) { 28315 mParent.requestLayout(); 28316 } 28317 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 28318 mAttachInfo.mViewRequestingLayout = null; 28319 } 28320 } 28321 28322 /** 28323 * Forces this view to be laid out during the next layout pass. 28324 * This method does not call requestLayout() or forceLayout() 28325 * on the parent. 28326 */ forceLayout()28327 public void forceLayout() { 28328 if (mMeasureCache != null) mMeasureCache.clear(); 28329 28330 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 28331 mPrivateFlags |= PFLAG_INVALIDATED; 28332 } 28333 28334 /** 28335 * <p> 28336 * This is called to find out how big a view should be. The parent 28337 * supplies constraint information in the width and height parameters. 28338 * </p> 28339 * 28340 * <p> 28341 * The actual measurement work of a view is performed in 28342 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 28343 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 28344 * </p> 28345 * 28346 * 28347 * @param widthMeasureSpec Horizontal space requirements as imposed by the 28348 * parent 28349 * @param heightMeasureSpec Vertical space requirements as imposed by the 28350 * parent 28351 * 28352 * @see #onMeasure(int, int) 28353 */ measure(int widthMeasureSpec, int heightMeasureSpec)28354 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 28355 boolean optical = isLayoutModeOptical(this); 28356 if (optical != isLayoutModeOptical(mParent)) { 28357 Insets insets = getOpticalInsets(); 28358 int oWidth = insets.left + insets.right; 28359 int oHeight = insets.top + insets.bottom; 28360 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 28361 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 28362 } 28363 28364 // Suppress sign extension for the low bytes 28365 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 28366 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 28367 28368 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 28369 28370 // Optimize layout by avoiding an extra EXACTLY pass when the view is 28371 // already measured as the correct size. In API 23 and below, this 28372 // extra pass is required to make LinearLayout re-distribute weight. 28373 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 28374 || heightMeasureSpec != mOldHeightMeasureSpec; 28375 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 28376 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 28377 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 28378 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 28379 final boolean needsLayout = specChanged 28380 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 28381 28382 if (forceLayout || needsLayout) { 28383 // first clears the measured dimension flag 28384 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 28385 28386 resolveRtlPropertiesIfNeeded(); 28387 28388 int cacheIndex; 28389 if (sUseMeasureCacheDuringForceLayoutFlagValue) { 28390 cacheIndex = mMeasureCache.indexOfKey(key); 28391 } else { 28392 cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 28393 } 28394 28395 if (cacheIndex < 0) { 28396 if (isTraversalTracingEnabled()) { 28397 Trace.beginSection(mTracingStrings.onMeasure); 28398 } 28399 if (android.os.Flags.adpfMeasureDuringInputEventBoost()) { 28400 final boolean notifyRenderer = hasExpensiveMeasuresDuringInputEvent(); 28401 if (notifyRenderer) { 28402 getViewRootImpl().notifyRendererOfExpensiveFrame( 28403 "ADPF_SendHint: hasExpensiveMeasuresDuringInputEvent"); 28404 } 28405 } 28406 // measure ourselves, this should set the measured dimension flag back 28407 onMeasure(widthMeasureSpec, heightMeasureSpec); 28408 if (isTraversalTracingEnabled()) { 28409 Trace.endSection(); 28410 } 28411 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 28412 } else { 28413 long value = mMeasureCache.valueAt(cacheIndex); 28414 // Casting a long to int drops the high 32 bits, no mask needed 28415 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 28416 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 28417 } 28418 28419 // flag not set, setMeasuredDimension() was not invoked, we raise 28420 // an exception to warn the developer 28421 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 28422 throw new IllegalStateException("View with id " + getId() + ": " 28423 + getClass().getName() + "#onMeasure() did not set the" 28424 + " measured dimension by calling" 28425 + " setMeasuredDimension()"); 28426 } 28427 28428 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 28429 } 28430 28431 mOldWidthMeasureSpec = widthMeasureSpec; 28432 mOldHeightMeasureSpec = heightMeasureSpec; 28433 28434 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 28435 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 28436 } 28437 28438 /** 28439 * <p> 28440 * Measure the view and its content to determine the measured width and the 28441 * measured height. This method is invoked by {@link #measure(int, int)} and 28442 * should be overridden by subclasses to provide accurate and efficient 28443 * measurement of their contents. 28444 * </p> 28445 * 28446 * <p> 28447 * <strong>CONTRACT:</strong> When overriding this method, you 28448 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 28449 * measured width and height of this view. Failure to do so will trigger an 28450 * <code>IllegalStateException</code>, thrown by 28451 * {@link #measure(int, int)}. Calling the superclass' 28452 * {@link #onMeasure(int, int)} is a valid use. 28453 * </p> 28454 * 28455 * <p> 28456 * The base class implementation of measure defaults to the background size, 28457 * unless a larger size is allowed by the MeasureSpec. Subclasses should 28458 * override {@link #onMeasure(int, int)} to provide better measurements of 28459 * their content. 28460 * </p> 28461 * 28462 * <p> 28463 * If this method is overridden, it is the subclass's responsibility to make 28464 * sure the measured height and width are at least the view's minimum height 28465 * and width ({@link #getSuggestedMinimumHeight()} and 28466 * {@link #getSuggestedMinimumWidth()}). 28467 * </p> 28468 * 28469 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 28470 * The requirements are encoded with 28471 * {@link android.view.View.MeasureSpec}. 28472 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 28473 * The requirements are encoded with 28474 * {@link android.view.View.MeasureSpec}. 28475 * 28476 * @see #getMeasuredWidth() 28477 * @see #getMeasuredHeight() 28478 * @see #setMeasuredDimension(int, int) 28479 * @see #getSuggestedMinimumHeight() 28480 * @see #getSuggestedMinimumWidth() 28481 * @see android.view.View.MeasureSpec#getMode(int) 28482 * @see android.view.View.MeasureSpec#getSize(int) 28483 */ onMeasure(int widthMeasureSpec, int heightMeasureSpec)28484 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 28485 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 28486 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 28487 } 28488 28489 /** 28490 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 28491 * measured width and measured height. Failing to do so will trigger an 28492 * exception at measurement time.</p> 28493 * 28494 * @param measuredWidth The measured width of this view. May be a complex 28495 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 28496 * {@link #MEASURED_STATE_TOO_SMALL}. 28497 * @param measuredHeight The measured height of this view. May be a complex 28498 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 28499 * {@link #MEASURED_STATE_TOO_SMALL}. 28500 */ setMeasuredDimension(int measuredWidth, int measuredHeight)28501 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 28502 boolean optical = isLayoutModeOptical(this); 28503 if (optical != isLayoutModeOptical(mParent)) { 28504 Insets insets = getOpticalInsets(); 28505 int opticalWidth = insets.left + insets.right; 28506 int opticalHeight = insets.top + insets.bottom; 28507 28508 measuredWidth += optical ? opticalWidth : -opticalWidth; 28509 measuredHeight += optical ? opticalHeight : -opticalHeight; 28510 } 28511 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 28512 } 28513 28514 /** 28515 * Sets the measured dimension without extra processing for things like optical bounds. 28516 * Useful for reapplying consistent values that have already been cooked with adjustments 28517 * for optical bounds, etc. such as those from the measurement cache. 28518 * 28519 * @param measuredWidth The measured width of this view. May be a complex 28520 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 28521 * {@link #MEASURED_STATE_TOO_SMALL}. 28522 * @param measuredHeight The measured height of this view. May be a complex 28523 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 28524 * {@link #MEASURED_STATE_TOO_SMALL}. 28525 */ setMeasuredDimensionRaw(int measuredWidth, int measuredHeight)28526 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 28527 mMeasuredWidth = measuredWidth; 28528 mMeasuredHeight = measuredHeight; 28529 28530 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 28531 } 28532 28533 /** 28534 * Merge two states as returned by {@link #getMeasuredState()}. 28535 * @param curState The current state as returned from a view or the result 28536 * of combining multiple views. 28537 * @param newState The new view state to combine. 28538 * @return Returns a new integer reflecting the combination of the two 28539 * states. 28540 */ combineMeasuredStates(int curState, int newState)28541 public static int combineMeasuredStates(int curState, int newState) { 28542 return curState | newState; 28543 } 28544 28545 /** 28546 * Version of {@link #resolveSizeAndState(int, int, int)} 28547 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 28548 */ resolveSize(int size, int measureSpec)28549 public static int resolveSize(int size, int measureSpec) { 28550 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 28551 } 28552 28553 /** 28554 * Utility to reconcile a desired size and state, with constraints imposed 28555 * by a MeasureSpec. Will take the desired size, unless a different size 28556 * is imposed by the constraints. The returned value is a compound integer, 28557 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 28558 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 28559 * resulting size is smaller than the size the view wants to be. 28560 * 28561 * @param size How big the view wants to be. 28562 * @param measureSpec Constraints imposed by the parent. 28563 * @param childMeasuredState Size information bit mask for the view's 28564 * children. 28565 * @return Size information bit mask as defined by 28566 * {@link #MEASURED_SIZE_MASK} and 28567 * {@link #MEASURED_STATE_TOO_SMALL}. 28568 */ resolveSizeAndState(int size, int measureSpec, int childMeasuredState)28569 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 28570 final int specMode = MeasureSpec.getMode(measureSpec); 28571 final int specSize = MeasureSpec.getSize(measureSpec); 28572 final int result; 28573 switch (specMode) { 28574 case MeasureSpec.AT_MOST: 28575 if (specSize < size) { 28576 result = specSize | MEASURED_STATE_TOO_SMALL; 28577 } else { 28578 result = size; 28579 } 28580 break; 28581 case MeasureSpec.EXACTLY: 28582 result = specSize; 28583 break; 28584 case MeasureSpec.UNSPECIFIED: 28585 default: 28586 result = size; 28587 } 28588 return result | (childMeasuredState & MEASURED_STATE_MASK); 28589 } 28590 28591 /** 28592 * Utility to return a default size. Uses the supplied size if the 28593 * MeasureSpec imposed no constraints. Will get larger if allowed 28594 * by the MeasureSpec. 28595 * 28596 * @param size Default size for this view 28597 * @param measureSpec Constraints imposed by the parent 28598 * @return The size this view should be. 28599 */ getDefaultSize(int size, int measureSpec)28600 public static int getDefaultSize(int size, int measureSpec) { 28601 int result = size; 28602 int specMode = MeasureSpec.getMode(measureSpec); 28603 int specSize = MeasureSpec.getSize(measureSpec); 28604 28605 switch (specMode) { 28606 case MeasureSpec.UNSPECIFIED: 28607 result = size; 28608 break; 28609 case MeasureSpec.AT_MOST: 28610 case MeasureSpec.EXACTLY: 28611 result = specSize; 28612 break; 28613 } 28614 return result; 28615 } 28616 28617 /** 28618 * Returns the suggested minimum height that the view should use. This 28619 * returns the maximum of the view's minimum height 28620 * and the background's minimum height 28621 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 28622 * <p> 28623 * When being used in {@link #onMeasure(int, int)}, the caller should still 28624 * ensure the returned height is within the requirements of the parent. 28625 * 28626 * @return The suggested minimum height of the view. 28627 */ getSuggestedMinimumHeight()28628 protected int getSuggestedMinimumHeight() { 28629 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 28630 28631 } 28632 28633 /** 28634 * Returns the suggested minimum width that the view should use. This 28635 * returns the maximum of the view's minimum width 28636 * and the background's minimum width 28637 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 28638 * <p> 28639 * When being used in {@link #onMeasure(int, int)}, the caller should still 28640 * ensure the returned width is within the requirements of the parent. 28641 * 28642 * @return The suggested minimum width of the view. 28643 */ getSuggestedMinimumWidth()28644 protected int getSuggestedMinimumWidth() { 28645 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 28646 } 28647 28648 /** 28649 * Returns the minimum height of the view. 28650 * 28651 * @return the minimum height the view will try to be, in pixels 28652 * 28653 * @see #setMinimumHeight(int) 28654 * 28655 * @attr ref android.R.styleable#View_minHeight 28656 */ 28657 @InspectableProperty(name = "minHeight") getMinimumHeight()28658 public int getMinimumHeight() { 28659 return mMinHeight; 28660 } 28661 28662 /** 28663 * Sets the minimum height of the view. It is not guaranteed the view will 28664 * be able to achieve this minimum height (for example, if its parent layout 28665 * constrains it with less available height). 28666 * 28667 * @param minHeight The minimum height the view will try to be, in pixels 28668 * 28669 * @see #getMinimumHeight() 28670 * 28671 * @attr ref android.R.styleable#View_minHeight 28672 */ 28673 @RemotableViewMethod setMinimumHeight(int minHeight)28674 public void setMinimumHeight(int minHeight) { 28675 mMinHeight = minHeight; 28676 requestLayout(); 28677 } 28678 28679 /** 28680 * Returns the minimum width of the view. 28681 * 28682 * @return the minimum width the view will try to be, in pixels 28683 * 28684 * @see #setMinimumWidth(int) 28685 * 28686 * @attr ref android.R.styleable#View_minWidth 28687 */ 28688 @InspectableProperty(name = "minWidth") getMinimumWidth()28689 public int getMinimumWidth() { 28690 return mMinWidth; 28691 } 28692 28693 /** 28694 * Sets the minimum width of the view. It is not guaranteed the view will 28695 * be able to achieve this minimum width (for example, if its parent layout 28696 * constrains it with less available width). 28697 * 28698 * @param minWidth The minimum width the view will try to be, in pixels 28699 * 28700 * @see #getMinimumWidth() 28701 * 28702 * @attr ref android.R.styleable#View_minWidth 28703 */ 28704 @RemotableViewMethod setMinimumWidth(int minWidth)28705 public void setMinimumWidth(int minWidth) { 28706 mMinWidth = minWidth; 28707 requestLayout(); 28708 28709 } 28710 28711 /** 28712 * Get the animation currently associated with this view. 28713 * 28714 * @return The animation that is currently playing or 28715 * scheduled to play for this view. 28716 */ getAnimation()28717 public Animation getAnimation() { 28718 return mCurrentAnimation; 28719 } 28720 28721 /** 28722 * Start the specified animation now. 28723 * 28724 * @param animation the animation to start now 28725 */ startAnimation(Animation animation)28726 public void startAnimation(Animation animation) { 28727 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 28728 setAnimation(animation); 28729 invalidateParentCaches(); 28730 invalidate(true); 28731 } 28732 28733 /** 28734 * Cancels any animations for this view. 28735 */ clearAnimation()28736 public void clearAnimation() { 28737 if (mCurrentAnimation != null) { 28738 mCurrentAnimation.detach(); 28739 } 28740 mCurrentAnimation = null; 28741 invalidateParentIfNeeded(); 28742 } 28743 28744 /** 28745 * Sets the next animation to play for this view. 28746 * If you want the animation to play immediately, use 28747 * {@link #startAnimation(android.view.animation.Animation)} instead. 28748 * This method provides allows fine-grained 28749 * control over the start time and invalidation, but you 28750 * must make sure that 1) the animation has a start time set, and 28751 * 2) the view's parent (which controls animations on its children) 28752 * will be invalidated when the animation is supposed to 28753 * start. 28754 * 28755 * @param animation The next animation, or null. 28756 */ setAnimation(Animation animation)28757 public void setAnimation(Animation animation) { 28758 mCurrentAnimation = animation; 28759 28760 if (animation != null) { 28761 // If the screen is off assume the animation start time is now instead of 28762 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 28763 // would cause the animation to start when the screen turns back on 28764 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 28765 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 28766 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 28767 } 28768 animation.reset(); 28769 } 28770 } 28771 28772 /** 28773 * Invoked by a parent ViewGroup to notify the start of the animation 28774 * currently associated with this view. If you override this method, 28775 * always call super.onAnimationStart(); 28776 * 28777 * @see #setAnimation(android.view.animation.Animation) 28778 * @see #getAnimation() 28779 */ 28780 @CallSuper onAnimationStart()28781 protected void onAnimationStart() { 28782 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 28783 } 28784 28785 /** 28786 * Invoked by a parent ViewGroup to notify the end of the animation 28787 * currently associated with this view. If you override this method, 28788 * always call super.onAnimationEnd(); 28789 * 28790 * @see #setAnimation(android.view.animation.Animation) 28791 * @see #getAnimation() 28792 */ 28793 @CallSuper onAnimationEnd()28794 protected void onAnimationEnd() { 28795 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 28796 } 28797 28798 /** 28799 * Invoked if there is a Transform that involves alpha. Subclass that can 28800 * draw themselves with the specified alpha should return true, and then 28801 * respect that alpha when their onDraw() is called. If this returns false 28802 * then the view may be redirected to draw into an offscreen buffer to 28803 * fulfill the request, which will look fine, but may be slower than if the 28804 * subclass handles it internally. The default implementation returns false. 28805 * 28806 * @param alpha The alpha (0..255) to apply to the view's drawing 28807 * @return true if the view can draw with the specified alpha. 28808 */ onSetAlpha(int alpha)28809 protected boolean onSetAlpha(int alpha) { 28810 return false; 28811 } 28812 28813 /** 28814 * This is used by the ViewRoot to perform an optimization when 28815 * the view hierarchy contains one or several SurfaceView. 28816 * SurfaceView is always considered transparent, but its children are not, 28817 * therefore all View objects remove themselves from the global transparent 28818 * region (passed as a parameter to this function). 28819 * 28820 * @param region The transparent region for this ViewAncestor (window). 28821 * 28822 * @return Returns true if the effective visibility of the view at this 28823 * point is opaque, regardless of the transparent region; returns false 28824 * if it is possible for underlying windows to be seen behind the view. 28825 * 28826 */ gatherTransparentRegion(@ullable Region region)28827 public boolean gatherTransparentRegion(@Nullable Region region) { 28828 final AttachInfo attachInfo = mAttachInfo; 28829 if (region != null && attachInfo != null) { 28830 final int pflags = mPrivateFlags; 28831 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 28832 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 28833 // remove it from the transparent region. 28834 final int[] location = attachInfo.mTransparentLocation; 28835 getLocationInWindow(location); 28836 // When a view has Z value, then it will be better to leave some area below the view 28837 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 28838 // the bottom part needs more offset than the left, top and right parts due to the 28839 // spot light effects. 28840 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 28841 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 28842 location[0] + mRight - mLeft + shadowOffset, 28843 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 28844 } else { 28845 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 28846 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 28847 // the background drawable's non-transparent parts from this transparent region. 28848 applyDrawableToTransparentRegion(mBackground, region); 28849 } 28850 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 28851 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 28852 // Similarly, we remove the foreground drawable's non-transparent parts. 28853 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 28854 } 28855 if (mDefaultFocusHighlight != null 28856 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { 28857 // Similarly, we remove the default focus highlight's non-transparent parts. 28858 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); 28859 } 28860 } 28861 } 28862 return true; 28863 } 28864 28865 /** 28866 * Play a sound effect for this view. 28867 * 28868 * <p>The framework will play sound effects for some built in actions, such as 28869 * clicking, but you may wish to play these effects in your widget, 28870 * for instance, for internal navigation. 28871 * 28872 * <p>The sound effect will only be played if sound effects are enabled by the user, and 28873 * {@link #isSoundEffectsEnabled()} is true. 28874 * 28875 * @param soundConstant One of the constants defined in {@link SoundEffectConstants}. 28876 */ playSoundEffect(@oundEffectConstants.SoundEffect int soundConstant)28877 public void playSoundEffect(@SoundEffectConstants.SoundEffect int soundConstant) { 28878 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 28879 return; 28880 } 28881 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 28882 } 28883 28884 /** 28885 * BZZZTT!!1! 28886 * 28887 * <p>Provide haptic feedback to the user for this view. 28888 * 28889 * <p>The framework will provide haptic feedback for some built in actions, 28890 * such as long presses, but you may wish to provide feedback for your 28891 * own widget. 28892 * 28893 * <p>The feedback will only be performed if 28894 * {@link #isHapticFeedbackEnabled()} is true. 28895 * 28896 * @param feedbackConstant One of the constants defined in 28897 * {@link HapticFeedbackConstants} 28898 */ performHapticFeedback(int feedbackConstant)28899 public boolean performHapticFeedback(int feedbackConstant) { 28900 return performHapticFeedback(feedbackConstant, 0); 28901 } 28902 28903 /** 28904 * BZZZTT!!1! 28905 * 28906 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 28907 * 28908 * @param feedbackConstant One of the constants defined in 28909 * {@link HapticFeedbackConstants} 28910 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 28911 */ performHapticFeedback(int feedbackConstant, int flags)28912 public boolean performHapticFeedback(int feedbackConstant, int flags) { 28913 if (isPerformHapticFeedbackSuppressed(feedbackConstant, flags)) { 28914 return false; 28915 } 28916 28917 int privFlags = computeHapticFeedbackPrivateFlags(); 28918 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, flags, privFlags); 28919 } 28920 28921 /** 28922 * <p>Provide haptic feedback to the user for this view. 28923 * 28924 * <p>Call this method (vs {@link #performHapticFeedback(int)}) to specify more details about 28925 * the {@link InputDevice} that caused this haptic feedback. The framework will choose and 28926 * provide a haptic feedback based on these details. 28927 * 28928 * <p>The feedback will only be performed if {@link #isHapticFeedbackEnabled()} is {@code true}. 28929 * 28930 * @param feedbackConstant One of the constants defined in {@link HapticFeedbackConstants}. 28931 * @param inputDeviceId The ID of the {@link InputDevice} that generated the event which 28932 * triggered this haptic feedback request. 28933 * @param inputSource The input source of the event which triggered this haptic feedback 28934 * request, defined as {@code InputDevice#SOURCE_*}. 28935 * 28936 * @hide 28937 */ performHapticFeedbackForInputDevice(int feedbackConstant, int inputDeviceId, int inputSource, int flags)28938 public void performHapticFeedbackForInputDevice(int feedbackConstant, int inputDeviceId, 28939 int inputSource, int flags) { 28940 if (isPerformHapticFeedbackSuppressed(feedbackConstant, flags)) { 28941 return; 28942 } 28943 28944 int privFlags = computeHapticFeedbackPrivateFlags(); 28945 mAttachInfo.mRootCallbacks.performHapticFeedbackForInputDevice( 28946 feedbackConstant, inputDeviceId, inputSource, flags, privFlags); 28947 } 28948 isPerformHapticFeedbackSuppressed(int feedbackConstant, int flags)28949 private boolean isPerformHapticFeedbackSuppressed(int feedbackConstant, int flags) { 28950 if (feedbackConstant == HapticFeedbackConstants.NO_HAPTICS 28951 || mAttachInfo == null 28952 || mAttachInfo.mSession == null) { 28953 return true; 28954 } 28955 //noinspection SimplifiableIfStatement 28956 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 28957 && !isHapticFeedbackEnabled()) { 28958 return true; 28959 } 28960 return false; 28961 } 28962 computeHapticFeedbackPrivateFlags()28963 private int computeHapticFeedbackPrivateFlags() { 28964 int privFlags = 0; 28965 if (mAttachInfo.mViewRootImpl != null 28966 && mAttachInfo.mViewRootImpl.mWindowAttributes.type == TYPE_INPUT_METHOD) { 28967 privFlags = HapticFeedbackConstants.PRIVATE_FLAG_APPLY_INPUT_METHOD_SETTINGS; 28968 } 28969 return privFlags; 28970 } 28971 28972 /** 28973 * Request that the visibility of the status bar or other screen/window 28974 * decorations be changed. 28975 * 28976 * <p>This method is used to put the over device UI into temporary modes 28977 * where the user's attention is focused more on the application content, 28978 * by dimming or hiding surrounding system affordances. This is typically 28979 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 28980 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 28981 * to be placed behind the action bar (and with these flags other system 28982 * affordances) so that smooth transitions between hiding and showing them 28983 * can be done. 28984 * 28985 * <p>Two representative examples of the use of system UI visibility is 28986 * implementing a content browsing application (like a magazine reader) 28987 * and a video playing application. 28988 * 28989 * <p>The first code shows a typical implementation of a View in a content 28990 * browsing application. In this implementation, the application goes 28991 * into a content-oriented mode by hiding the status bar and action bar, 28992 * and putting the navigation elements into lights out mode. The user can 28993 * then interact with content while in this mode. Such an application should 28994 * provide an easy way for the user to toggle out of the mode (such as to 28995 * check information in the status bar or access notifications). In the 28996 * implementation here, this is done simply by tapping on the content. 28997 * 28998 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 28999 * content} 29000 * 29001 * <p>This second code sample shows a typical implementation of a View 29002 * in a video playing application. In this situation, while the video is 29003 * playing the application would like to go into a complete full-screen mode, 29004 * to use as much of the display as possible for the video. When in this state 29005 * the user can not interact with the application; the system intercepts 29006 * touching on the screen to pop the UI out of full screen mode. See 29007 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 29008 * 29009 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 29010 * content} 29011 * 29012 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 29013 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 29014 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 29015 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 29016 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 29017 * 29018 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 29019 * instead. 29020 */ 29021 @Deprecated setSystemUiVisibility(int visibility)29022 public void setSystemUiVisibility(int visibility) { 29023 if (visibility != mSystemUiVisibility) { 29024 mSystemUiVisibility = visibility; 29025 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 29026 mParent.recomputeViewAttributes(this); 29027 } 29028 } 29029 } 29030 29031 /** 29032 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 29033 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 29034 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 29035 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 29036 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 29037 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 29038 * 29039 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 29040 * instead. 29041 */ 29042 @Deprecated getSystemUiVisibility()29043 public int getSystemUiVisibility() { 29044 return mSystemUiVisibility; 29045 } 29046 29047 /** 29048 * Returns the current system UI visibility that is currently set for 29049 * the entire window. This is the combination of the 29050 * {@link #setSystemUiVisibility(int)} values supplied by all of the 29051 * views in the window. 29052 * 29053 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 29054 * instead. 29055 */ 29056 @Deprecated getWindowSystemUiVisibility()29057 public int getWindowSystemUiVisibility() { 29058 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 29059 } 29060 29061 /** 29062 * Override to find out when the window's requested system UI visibility 29063 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 29064 * This is different from the callbacks received through 29065 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 29066 * in that this is only telling you about the local request of the window, 29067 * not the actual values applied by the system. 29068 * 29069 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 29070 * instead. 29071 */ 29072 @Deprecated onWindowSystemUiVisibilityChanged(int visible)29073 public void onWindowSystemUiVisibilityChanged(int visible) { 29074 } 29075 29076 /** 29077 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 29078 * the view hierarchy. 29079 * 29080 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 29081 * instead. 29082 */ 29083 @Deprecated dispatchWindowSystemUiVisiblityChanged(int visible)29084 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 29085 onWindowSystemUiVisibilityChanged(visible); 29086 } 29087 29088 /** 29089 * Set a listener to receive callbacks when the visibility of the system bar changes. 29090 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 29091 * 29092 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 29093 * by setting a {@link OnApplyWindowInsetsListener} on this view. 29094 */ 29095 @Deprecated setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l)29096 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 29097 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 29098 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 29099 mParent.recomputeViewAttributes(this); 29100 } 29101 } 29102 29103 /** 29104 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 29105 * the view hierarchy. 29106 * 29107 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 29108 * by setting a {@link OnApplyWindowInsetsListener} on this view. 29109 */ 29110 @Deprecated dispatchSystemUiVisibilityChanged(int visibility)29111 public void dispatchSystemUiVisibilityChanged(int visibility) { 29112 ListenerInfo li = mListenerInfo; 29113 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 29114 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 29115 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 29116 } 29117 } 29118 updateLocalSystemUiVisibility(int localValue, int localChanges)29119 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 29120 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 29121 if (val != mSystemUiVisibility) { 29122 setSystemUiVisibility(val); 29123 return true; 29124 } 29125 return false; 29126 } 29127 29128 /** @hide */ 29129 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setDisabledSystemUiVisibility(int flags)29130 public void setDisabledSystemUiVisibility(int flags) { 29131 if (mAttachInfo != null) { 29132 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 29133 mAttachInfo.mDisabledSystemUiVisibility = flags; 29134 if (mParent != null) { 29135 mParent.recomputeViewAttributes(this); 29136 } 29137 } 29138 } 29139 } 29140 29141 /** 29142 * This needs to be a better API before it is exposed. For now, only the root view will get 29143 * notified. 29144 * @hide 29145 */ onSystemBarAppearanceChanged(@indowInsetsController.Appearance int appearance)29146 public void onSystemBarAppearanceChanged(@WindowInsetsController.Appearance int appearance) { 29147 } 29148 29149 /** 29150 * Creates an image that the system displays during the drag and drop 29151 * operation. This is called a "drag shadow". The default implementation 29152 * for a DragShadowBuilder based on a View returns an image that has exactly the same 29153 * appearance as the given View. The default also positions the center of the drag shadow 29154 * directly under the touch point. If no View is provided (the constructor with no parameters 29155 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 29156 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 29157 * default is an invisible drag shadow. 29158 * <p> 29159 * You are not required to use the View you provide to the constructor as the basis of the 29160 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 29161 * anything you want as the drag shadow. 29162 * </p> 29163 * <p> 29164 * You pass a DragShadowBuilder object to the system when you start the drag. The system 29165 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 29166 * size and position of the drag shadow. It uses this data to construct a 29167 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 29168 * so that your application can draw the shadow image in the Canvas. 29169 * </p> 29170 * 29171 * <div class="special reference"> 29172 * <h3>Developer Guides</h3> 29173 * <p>For a guide to implementing drag and drop features, read the 29174 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 29175 * </div> 29176 */ 29177 public static class DragShadowBuilder { 29178 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 29179 private final WeakReference<View> mView; 29180 29181 /** 29182 * Constructs a shadow image builder based on a View. By default, the resulting drag 29183 * shadow will have the same appearance and dimensions as the View, with the touch point 29184 * over the center of the View. 29185 * @param view A View. Any View in scope can be used. 29186 */ DragShadowBuilder(View view)29187 public DragShadowBuilder(View view) { 29188 mView = new WeakReference<View>(view); 29189 } 29190 29191 /** 29192 * Construct a shadow builder object with no associated View. This 29193 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 29194 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 29195 * to supply the drag shadow's dimensions and appearance without 29196 * reference to any View object. 29197 */ DragShadowBuilder()29198 public DragShadowBuilder() { 29199 mView = new WeakReference<View>(null); 29200 } 29201 29202 /** 29203 * Returns the View object that had been passed to the 29204 * {@link #DragShadowBuilder(View)} 29205 * constructor. If that View parameter was {@code null} or if the 29206 * {@link #DragShadowBuilder()} 29207 * constructor was used to instantiate the builder object, this method will return 29208 * null. 29209 * 29210 * @return The View object associate with this builder object. 29211 */ 29212 @SuppressWarnings({"JavadocReference"}) getView()29213 final public View getView() { 29214 return mView.get(); 29215 } 29216 29217 /** 29218 * Provides the metrics for the shadow image. These include the dimensions of 29219 * the shadow image, and the point within that shadow that should 29220 * be centered under the touch location while dragging. 29221 * <p> 29222 * The default implementation sets the dimensions of the shadow to be the 29223 * same as the dimensions of the View itself and centers the shadow under 29224 * the touch point. 29225 * </p> 29226 * 29227 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 29228 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 29229 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 29230 * image. Since Android P, the width and height must be positive values. 29231 * 29232 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 29233 * shadow image that should be underneath the touch point during the drag and drop 29234 * operation. Your application must set {@link android.graphics.Point#x} to the 29235 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 29236 */ onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint)29237 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 29238 final View view = mView.get(); 29239 if (view != null) { 29240 outShadowSize.set(view.getWidth(), view.getHeight()); 29241 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 29242 } else { 29243 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 29244 } 29245 } 29246 29247 /** 29248 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 29249 * based on the dimensions it received from the 29250 * {@link #onProvideShadowMetrics(Point, Point)} callback. 29251 * 29252 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 29253 */ onDrawShadow(@onNull Canvas canvas)29254 public void onDrawShadow(@NonNull Canvas canvas) { 29255 final View view = mView.get(); 29256 if (view != null) { 29257 view.draw(canvas); 29258 } else { 29259 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 29260 } 29261 } 29262 } 29263 29264 /** 29265 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 29266 * startDragAndDrop()} for newer platform versions. 29267 */ 29268 @Deprecated startDrag(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)29269 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 29270 Object myLocalState, int flags) { 29271 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 29272 } 29273 29274 /** 29275 * Starts a drag and drop operation. When your application calls this method, it passes a 29276 * {@link android.view.View.DragShadowBuilder} object to the system. The 29277 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 29278 * to get metrics for the drag shadow, and then calls the object's 29279 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 29280 * <p> 29281 * Once the system has the drag shadow, it begins the drag and drop operation by sending 29282 * drag events to all the View objects in your application that are currently visible. It does 29283 * this either by calling the View object's drag listener (an implementation of 29284 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 29285 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 29286 * Both are passed a {@link android.view.DragEvent} object that has a 29287 * {@link android.view.DragEvent#getAction()} value of 29288 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 29289 * </p> 29290 * <p> 29291 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 29292 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 29293 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 29294 * to the View the user selected for dragging. 29295 * </p> 29296 * @param data A {@link android.content.ClipData} object pointing to the data to be 29297 * transferred by the drag and drop operation. 29298 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 29299 * drag shadow. 29300 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 29301 * drop operation. When dispatching drag events to views in the same activity this object 29302 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 29303 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 29304 * will return null). 29305 * <p> 29306 * myLocalState is a lightweight mechanism for the sending information from the dragged View 29307 * to the target Views. For example, it can contain flags that differentiate between a 29308 * a copy operation and a move operation. 29309 * </p> 29310 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 29311 * flags, or any combination of the following: 29312 * <ul> 29313 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 29314 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 29315 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 29316 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 29317 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 29318 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 29319 * <li>{@link #DRAG_FLAG_ACCESSIBILITY_ACTION}</li> 29320 * </ul> 29321 * @return {@code true} if the method completes successfully, or 29322 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 29323 * do a drag because of another ongoing operation or some other reasons. 29324 */ startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)29325 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 29326 Object myLocalState, int flags) { 29327 if (ViewDebug.DEBUG_DRAG) { 29328 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 29329 } 29330 if (mAttachInfo == null) { 29331 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 29332 return false; 29333 } 29334 if (!mAttachInfo.mViewRootImpl.mSurface.isValid()) { 29335 Log.w(VIEW_LOG_TAG, "startDragAndDrop called with an invalid surface."); 29336 return false; 29337 } 29338 if ((flags & DRAG_FLAG_GLOBAL) != 0 && ((flags & DRAG_FLAG_GLOBAL_SAME_APPLICATION) != 0)) { 29339 Log.w(VIEW_LOG_TAG, "startDragAndDrop called with both DRAG_FLAG_GLOBAL " 29340 + "and DRAG_FLAG_GLOBAL_SAME_APPLICATION, the drag will default to " 29341 + "DRAG_FLAG_GLOBAL_SAME_APPLICATION"); 29342 flags &= ~DRAG_FLAG_GLOBAL; 29343 } 29344 29345 if (data != null) { 29346 if (com.android.window.flags.Flags.delegateUnhandledDrags()) { 29347 data.prepareToLeaveProcess( 29348 (flags & (DRAG_FLAG_GLOBAL_SAME_APPLICATION | DRAG_FLAG_GLOBAL)) != 0); 29349 if ((flags & DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG) != 0) { 29350 if (!hasActivityPendingIntents(data)) { 29351 // Reset the flag if there is no launchable activity intent 29352 flags &= ~DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG; 29353 Log.w(VIEW_LOG_TAG, "startDragAndDrop called with " 29354 + "DRAG_FLAG_START_INTENT_ON_UNHANDLED_DRAG but the clip data " 29355 + "contains non-activity PendingIntents"); 29356 } 29357 } 29358 } else { 29359 data.prepareToLeaveProcess((flags & DRAG_FLAG_GLOBAL) != 0); 29360 } 29361 } 29362 29363 Rect bounds = new Rect(); 29364 getBoundsOnScreen(bounds, true); 29365 29366 Point lastTouchPoint = new Point(); 29367 mAttachInfo.mViewRootImpl.getLastTouchPoint(lastTouchPoint); 29368 final ViewRootImpl root = mAttachInfo.mViewRootImpl; 29369 29370 // Skip surface logic since shadows and animation are not required during the a11y drag 29371 final boolean a11yEnabled = AccessibilityManager.getInstance(mContext).isEnabled(); 29372 if (a11yEnabled && (flags & View.DRAG_FLAG_ACCESSIBILITY_ACTION) != 0) { 29373 try { 29374 IBinder token = mAttachInfo.mSession.performDrag( 29375 mAttachInfo.mWindow, flags, null, 29376 mAttachInfo.mViewRootImpl.getLastTouchSource(), 29377 mAttachInfo.mViewRootImpl.getLastTouchDeviceId(), 29378 mAttachInfo.mViewRootImpl.getLastTouchPointerId(), 29379 0f, 0f, 0f, 0f, data); 29380 if (ViewDebug.DEBUG_DRAG) { 29381 Log.d(VIEW_LOG_TAG, "startDragAndDrop via a11y action returned " + token); 29382 } 29383 if (token != null) { 29384 root.setLocalDragState(myLocalState); 29385 mAttachInfo.mDragToken = token; 29386 mAttachInfo.mDragData = data; 29387 mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this); 29388 setAccessibilityDragStarted(true); 29389 } 29390 return token != null; 29391 } catch (Exception e) { 29392 Log.e(VIEW_LOG_TAG, "Unable to initiate a11y drag", e); 29393 return false; 29394 } 29395 } 29396 29397 Point shadowSize = new Point(); 29398 Point shadowTouchPoint = new Point(); 29399 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 29400 29401 if ((shadowSize.x < 0) || (shadowSize.y < 0) 29402 || (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 29403 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 29404 } 29405 final float overrideInvScale = CompatibilityInfo.getOverrideInvertedScale(); 29406 if (overrideInvScale != 1f) { 29407 shadowTouchPoint.x = (int) (shadowTouchPoint.x / overrideInvScale); 29408 shadowTouchPoint.y = (int) (shadowTouchPoint.y / overrideInvScale); 29409 } 29410 29411 // Create 1x1 surface when zero surface size is specified because SurfaceControl.Builder 29412 // does not accept zero size surface. 29413 if (shadowSize.x == 0 || shadowSize.y == 0) { 29414 if (!sAcceptZeroSizeDragShadow) { 29415 throw new IllegalStateException("Drag shadow dimensions must be positive"); 29416 } 29417 shadowSize.x = 1; 29418 shadowSize.y = 1; 29419 } 29420 29421 if (ViewDebug.DEBUG_DRAG) { 29422 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 29423 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 29424 } 29425 29426 final SurfaceControl surfaceControl = new SurfaceControl.Builder() 29427 .setName("drag surface") 29428 .setParent(root.getSurfaceControl()) 29429 .setBufferSize(shadowSize.x, shadowSize.y) 29430 .setFormat(PixelFormat.TRANSLUCENT) 29431 .setCallsite("View.startDragAndDrop") 29432 .build(); 29433 if (overrideInvScale != 1f) { 29434 final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); 29435 transaction.setMatrix(surfaceControl, 1 / overrideInvScale, 0, 0, 1 / overrideInvScale) 29436 .apply(); 29437 } 29438 final Surface surface = new Surface(); 29439 surface.copyFrom(surfaceControl); 29440 IBinder token = null; 29441 try { 29442 Trace.traceBegin(TRACE_TAG_VIEW, "startDragAndDrop#drawDragShadow"); 29443 final Canvas canvas = isHardwareAccelerated() 29444 ? surface.lockHardwareCanvas() 29445 : surface.lockCanvas(null); 29446 try { 29447 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 29448 shadowBuilder.onDrawShadow(canvas); 29449 } finally { 29450 surface.unlockCanvasAndPost(canvas); 29451 Trace.traceEnd(TRACE_TAG_VIEW); 29452 } 29453 29454 Trace.traceBegin(TRACE_TAG_VIEW, "startDragAndDrop#performDrag"); 29455 try { 29456 token = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, flags, surfaceControl, 29457 root.getLastTouchSource(), root.getLastTouchDeviceId(), 29458 root.getLastTouchPointerId(), lastTouchPoint.x, lastTouchPoint.y, 29459 shadowTouchPoint.x, shadowTouchPoint.y, data); 29460 if (ViewDebug.DEBUG_DRAG) { 29461 Log.d(VIEW_LOG_TAG, "performDrag returned " + token); 29462 } 29463 if (token != null) { 29464 if (mAttachInfo.mDragSurface != null) { 29465 mAttachInfo.mDragSurface.release(); 29466 } 29467 if (mAttachInfo.mDragData != null) { 29468 // Clean up previous drag data intents 29469 View.cleanUpPendingIntents(mAttachInfo.mDragData); 29470 } 29471 mAttachInfo.mDragSurface = surface; 29472 mAttachInfo.mDragToken = token; 29473 mAttachInfo.mDragData = data; 29474 // Cache the local state object for delivery with DragEvents 29475 root.setLocalDragState(myLocalState); 29476 if (a11yEnabled) { 29477 // Set for AccessibilityEvents 29478 mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this); 29479 } 29480 } 29481 return token != null; 29482 } finally { 29483 Trace.traceEnd(TRACE_TAG_VIEW); 29484 } 29485 } catch (Exception e) { 29486 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 29487 return false; 29488 } finally { 29489 if (token == null) { 29490 surface.destroy(); 29491 } 29492 surfaceControl.release(); 29493 } 29494 } 29495 29496 /** 29497 * Checks if this clip data has a pending intent that is an activity type. 29498 * @hide 29499 */ hasActivityPendingIntents(ClipData data)29500 static boolean hasActivityPendingIntents(ClipData data) { 29501 final int size = data.getItemCount(); 29502 for (int i = 0; i < size; i++) { 29503 final ClipData.Item item = data.getItemAt(i); 29504 if (item.getIntentSender() != null) { 29505 final PendingIntent pi = new PendingIntent(item.getIntentSender().getTarget()); 29506 if (pi.isActivity()) { 29507 return true; 29508 } 29509 } 29510 } 29511 return false; 29512 } 29513 29514 /** 29515 * Cleans up all pending intents in the ClipData. 29516 * @hide 29517 */ cleanUpPendingIntents(ClipData data)29518 static void cleanUpPendingIntents(ClipData data) { 29519 final int size = data.getItemCount(); 29520 for (int i = 0; i < size; i++) { 29521 final ClipData.Item item = data.getItemAt(i); 29522 if (item.getIntentSender() != null) { 29523 final PendingIntent pi = new PendingIntent(item.getIntentSender().getTarget()); 29524 pi.cancel(); 29525 } 29526 } 29527 } 29528 setAccessibilityDragStarted(boolean started)29529 void setAccessibilityDragStarted(boolean started) { 29530 int pflags4 = mPrivateFlags4; 29531 if (started) { 29532 pflags4 |= PFLAG4_DRAG_A11Y_STARTED; 29533 } else { 29534 pflags4 &= ~PFLAG4_DRAG_A11Y_STARTED; 29535 } 29536 29537 if (pflags4 != mPrivateFlags4) { 29538 mPrivateFlags4 = pflags4; 29539 sendWindowContentChangedAccessibilityEvent(CONTENT_CHANGE_TYPE_UNDEFINED); 29540 } 29541 } 29542 startedSystemDragForAccessibility()29543 private boolean startedSystemDragForAccessibility() { 29544 return (mPrivateFlags4 & PFLAG4_DRAG_A11Y_STARTED) != 0; 29545 } 29546 29547 /** 29548 * Cancels an ongoing drag and drop operation. 29549 * <p> 29550 * A {@link android.view.DragEvent} object with 29551 * {@link android.view.DragEvent#getAction()} value of 29552 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 29553 * {@link android.view.DragEvent#getResult()} value of {@code false} 29554 * will be sent to every 29555 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 29556 * even if they are not currently visible. 29557 * </p> 29558 * <p> 29559 * This method can be called on any View in the same window as the View on which 29560 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 29561 * was called. 29562 * </p> 29563 */ cancelDragAndDrop()29564 public final void cancelDragAndDrop() { 29565 if (ViewDebug.DEBUG_DRAG) { 29566 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 29567 } 29568 if (mAttachInfo == null) { 29569 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 29570 return; 29571 } 29572 if (mAttachInfo.mDragToken != null) { 29573 try { 29574 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken, false); 29575 } catch (Exception e) { 29576 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 29577 } 29578 mAttachInfo.mDragToken = null; 29579 } else { 29580 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 29581 } 29582 } 29583 29584 /** 29585 * Updates the drag shadow for the ongoing drag and drop operation. 29586 * 29587 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 29588 * new drag shadow. 29589 */ updateDragShadow(DragShadowBuilder shadowBuilder)29590 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 29591 if (ViewDebug.DEBUG_DRAG) { 29592 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 29593 } 29594 if (mAttachInfo == null) { 29595 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 29596 return; 29597 } 29598 if (mAttachInfo.mDragToken != null) { 29599 try { 29600 Canvas canvas = isHardwareAccelerated() 29601 ? mAttachInfo.mDragSurface.lockHardwareCanvas() 29602 : mAttachInfo.mDragSurface.lockCanvas(null); 29603 try { 29604 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 29605 shadowBuilder.onDrawShadow(canvas); 29606 } finally { 29607 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 29608 } 29609 } catch (Exception e) { 29610 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 29611 } 29612 } else { 29613 Log.e(VIEW_LOG_TAG, "No active drag"); 29614 } 29615 } 29616 29617 /** 29618 * Starts a move from {startX, startY}, the amount of the movement will be the offset 29619 * between {startX, startY} and the new cursor positon. 29620 * @param startX horizontal coordinate where the move started. 29621 * @param startY vertical coordinate where the move started. 29622 * @return whether moving was started successfully. 29623 * @hide 29624 */ startMovingTask(float startX, float startY)29625 public final boolean startMovingTask(float startX, float startY) { 29626 if (ViewDebug.DEBUG_POSITIONING) { 29627 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 29628 } 29629 try { 29630 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 29631 } catch (RemoteException e) { 29632 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 29633 } 29634 return false; 29635 } 29636 29637 /** 29638 * Finish a window move task. 29639 * @hide 29640 */ finishMovingTask()29641 public void finishMovingTask() { 29642 if (ViewDebug.DEBUG_POSITIONING) { 29643 Log.d(VIEW_LOG_TAG, "finishMovingTask"); 29644 } 29645 try { 29646 mAttachInfo.mSession.finishMovingTask(mAttachInfo.mWindow); 29647 } catch (RemoteException e) { 29648 Log.e(VIEW_LOG_TAG, "Unable to finish moving", e); 29649 } 29650 } 29651 29652 /** 29653 * Handles drag events sent by the system following a call to 29654 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 29655 * startDragAndDrop()}. 29656 * <p> 29657 * The system calls this method and passes a {@link DragEvent} object in response to drag and 29658 * drop events. This method can then call {@link DragEvent#getAction()} to determine the state 29659 * of the drag and drop operation. 29660 * <p> 29661 * The default implementation returns {@code false} unless an {@link OnReceiveContentListener} 29662 * has been set for this view (see {@link #setOnReceiveContentListener}), in which case 29663 * the default implementation does the following: 29664 * <ul> 29665 * <li>Returns {@code true} for an 29666 * {@link DragEvent#ACTION_DRAG_STARTED ACTION_DRAG_STARTED} event 29667 * <li>Calls {@link #performReceiveContent} for an 29668 * {@link DragEvent#ACTION_DROP ACTION_DROP} event 29669 * <li>Returns {@code true} for an {@link DragEvent#ACTION_DROP ACTION_DROP} event if the 29670 * {@code OnReceiveContentListener} consumed some or all of the content 29671 * </ul> 29672 * 29673 * @param event The {@link DragEvent} object sent by the system. The 29674 * {@link DragEvent#getAction()} method returns an action type constant that indicates the 29675 * type of drag event represented by this object. 29676 * @return {@code true} if the method successfully handled the drag event, otherwise 29677 * {@code false}. 29678 * <p> 29679 * The method must return {@code true} in response to an 29680 * {@link DragEvent#ACTION_DRAG_STARTED ACTION_DRAG_STARTED} action type to continue to 29681 * receive drag events for the current drag and drop operation. 29682 * <p> 29683 * The method should return {@code true} in response to an 29684 * {@link DragEvent#ACTION_DROP ACTION_DROP} action type if the dropped data was consumed 29685 * (at least partially); {@code false}, if none of the data was consumed. 29686 * <p> 29687 * For all other events, the return value is {@code false}. 29688 */ onDragEvent(DragEvent event)29689 public boolean onDragEvent(DragEvent event) { 29690 if (mListenerInfo == null || mListenerInfo.mOnReceiveContentListener == null) { 29691 return false; 29692 } 29693 // Accept drag events by default if there's an OnReceiveContentListener set. 29694 if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) { 29695 return true; 29696 } 29697 if (event.getAction() == DragEvent.ACTION_DROP) { 29698 final DragAndDropPermissions permissions = DragAndDropPermissions.obtain(event); 29699 if (permissions != null) { 29700 permissions.takeTransient(); 29701 } 29702 final ContentInfo payload = 29703 new ContentInfo.Builder(event.getClipData(), SOURCE_DRAG_AND_DROP) 29704 .setDragAndDropPermissions(permissions) 29705 .build(); 29706 ContentInfo remainingPayload = performReceiveContent(payload); 29707 // Return true unless none of the payload was consumed. 29708 return remainingPayload != payload; 29709 } 29710 return false; 29711 } 29712 29713 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. dispatchDragEnterExitInPreN(DragEvent event)29714 boolean dispatchDragEnterExitInPreN(DragEvent event) { 29715 return callDragEventHandler(event); 29716 } 29717 29718 /** 29719 * Detects if this View is enabled and has a drag event listener. 29720 * If both are true, then it calls the drag event listener with the 29721 * {@link android.view.DragEvent} it received. If the drag event listener returns 29722 * {@code true}, then dispatchDragEvent() returns {@code true}. 29723 * <p> 29724 * For all other cases, the method calls the 29725 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 29726 * method and returns its result. 29727 * </p> 29728 * <p> 29729 * This ensures that a drag event is always consumed, even if the View does not have a drag 29730 * event listener. However, if the View has a listener and the listener returns true, then 29731 * onDragEvent() is not called. 29732 * </p> 29733 */ dispatchDragEvent(DragEvent event)29734 public boolean dispatchDragEvent(DragEvent event) { 29735 event.mEventHandlerWasCalled = true; 29736 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 29737 event.mAction == DragEvent.ACTION_DROP) { 29738 // About to deliver an event with coordinates to this view. Notify that now this view 29739 // has drag focus. This will send exit/enter events as needed. 29740 getViewRootImpl().setDragFocus(this, event); 29741 } 29742 return callDragEventHandler(event); 29743 } 29744 callDragEventHandler(DragEvent event)29745 final boolean callDragEventHandler(DragEvent event) { 29746 final boolean result; 29747 29748 ListenerInfo li = mListenerInfo; 29749 //noinspection SimplifiableIfStatement 29750 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 29751 && li.mOnDragListener.onDrag(this, event)) { 29752 result = true; 29753 } else { 29754 result = onDragEvent(event); 29755 } 29756 29757 switch (event.mAction) { 29758 case DragEvent.ACTION_DRAG_STARTED: { 29759 if (result && li != null && li.mOnDragListener != null) { 29760 sendWindowContentChangedAccessibilityEvent( 29761 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 29762 } 29763 } break; 29764 case DragEvent.ACTION_DRAG_ENTERED: { 29765 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 29766 refreshDrawableState(); 29767 } break; 29768 case DragEvent.ACTION_DRAG_EXITED: { 29769 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 29770 refreshDrawableState(); 29771 } break; 29772 case DragEvent.ACTION_DROP: { 29773 if (result && li != null && (li.mOnDragListener != null 29774 || li.mOnReceiveContentListener != null)) { 29775 sendWindowContentChangedAccessibilityEvent( 29776 AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_DROPPED); 29777 } 29778 } break; 29779 case DragEvent.ACTION_DRAG_ENDED: { 29780 sendWindowContentChangedAccessibilityEvent( 29781 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 29782 mPrivateFlags2 &= ~View.DRAG_MASK; 29783 refreshDrawableState(); 29784 } break; 29785 } 29786 29787 return result; 29788 } 29789 canAcceptDrag()29790 boolean canAcceptDrag() { 29791 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 29792 } 29793 sendWindowContentChangedAccessibilityEvent(int changeType)29794 void sendWindowContentChangedAccessibilityEvent(int changeType) { 29795 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 29796 AccessibilityEvent event = AccessibilityEvent.obtain(); 29797 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 29798 event.setContentChangeTypes(changeType); 29799 sendAccessibilityEventUnchecked(event); 29800 } 29801 } 29802 29803 /** 29804 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 29805 * it is ever exposed at all. 29806 * @hide 29807 */ 29808 @UnsupportedAppUsage onCloseSystemDialogs(String reason)29809 public void onCloseSystemDialogs(String reason) { 29810 } 29811 29812 /** 29813 * Given a Drawable whose bounds have been set to draw into this view, 29814 * update a Region being computed for 29815 * {@link #gatherTransparentRegion(android.graphics.Region)} so 29816 * that any non-transparent parts of the Drawable are removed from the 29817 * given transparent region. 29818 * 29819 * @param dr The Drawable whose transparency is to be applied to the region. 29820 * @param region A Region holding the current transparency information, 29821 * where any parts of the region that are set are considered to be 29822 * transparent. On return, this region will be modified to have the 29823 * transparency information reduced by the corresponding parts of the 29824 * Drawable that are not transparent. 29825 * {@hide} 29826 */ 29827 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) applyDrawableToTransparentRegion(Drawable dr, Region region)29828 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 29829 if (DBG) { 29830 Log.i("View", "Getting transparent region for: " + this); 29831 } 29832 final Region r = dr.getTransparentRegion(); 29833 final Rect db = dr.getBounds(); 29834 final AttachInfo attachInfo = mAttachInfo; 29835 if (r != null && attachInfo != null) { 29836 final int w = getRight()-getLeft(); 29837 final int h = getBottom()-getTop(); 29838 if (db.left > 0) { 29839 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 29840 r.op(0, 0, db.left, h, Region.Op.UNION); 29841 } 29842 if (db.right < w) { 29843 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 29844 r.op(db.right, 0, w, h, Region.Op.UNION); 29845 } 29846 if (db.top > 0) { 29847 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 29848 r.op(0, 0, w, db.top, Region.Op.UNION); 29849 } 29850 if (db.bottom < h) { 29851 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 29852 r.op(0, db.bottom, w, h, Region.Op.UNION); 29853 } 29854 final int[] location = attachInfo.mTransparentLocation; 29855 getLocationInWindow(location); 29856 r.translate(location[0], location[1]); 29857 region.op(r, Region.Op.INTERSECT); 29858 } else { 29859 region.op(db, Region.Op.DIFFERENCE); 29860 } 29861 } 29862 checkForLongClick(long delay, float x, float y, int classification)29863 private void checkForLongClick(long delay, float x, float y, int classification) { 29864 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 29865 mHasPerformedLongPress = false; 29866 29867 if (mPendingCheckForLongPress == null) { 29868 mPendingCheckForLongPress = new CheckForLongPress(); 29869 } 29870 mPendingCheckForLongPress.setAnchor(x, y); 29871 mPendingCheckForLongPress.rememberWindowAttachCount(); 29872 mPendingCheckForLongPress.rememberPressedState(); 29873 mPendingCheckForLongPress.setClassification(classification); 29874 postDelayed(mPendingCheckForLongPress, delay); 29875 } 29876 } 29877 29878 /** 29879 * Inflate a view from an XML resource. This convenience method wraps the {@link 29880 * LayoutInflater} class, which provides a full range of options for view inflation. 29881 * 29882 * @param context The Context object for your activity or application. 29883 * @param resource The resource ID to inflate 29884 * @param root A view group that will be the parent. Used to properly inflate the 29885 * layout_* parameters. 29886 * @see LayoutInflater 29887 */ inflate(Context context, @LayoutRes int resource, ViewGroup root)29888 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 29889 LayoutInflater factory = LayoutInflater.from(context); 29890 return factory.inflate(resource, root); 29891 } 29892 29893 /** 29894 * Scroll the view with standard behavior for scrolling beyond the normal 29895 * content boundaries. Views that call this method should override 29896 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 29897 * results of an over-scroll operation. 29898 * 29899 * Views can use this method to handle any touch or fling-based scrolling. 29900 * 29901 * @param deltaX Change in X in pixels 29902 * @param deltaY Change in Y in pixels 29903 * @param scrollX Current X scroll value in pixels before applying deltaX 29904 * @param scrollY Current Y scroll value in pixels before applying deltaY 29905 * @param scrollRangeX Maximum content scroll range along the X axis 29906 * @param scrollRangeY Maximum content scroll range along the Y axis 29907 * @param maxOverScrollX Number of pixels to overscroll by in either direction 29908 * along the X axis. 29909 * @param maxOverScrollY Number of pixels to overscroll by in either direction 29910 * along the Y axis. 29911 * @param isTouchEvent true if this scroll operation is the result of a touch event. 29912 * @return true if scrolling was clamped to an over-scroll boundary along either 29913 * axis, false otherwise. 29914 */ 29915 @SuppressWarnings({"UnusedParameters"}) overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent)29916 protected boolean overScrollBy(int deltaX, int deltaY, 29917 int scrollX, int scrollY, 29918 int scrollRangeX, int scrollRangeY, 29919 int maxOverScrollX, int maxOverScrollY, 29920 boolean isTouchEvent) { 29921 final int overScrollMode = mOverScrollMode; 29922 final boolean canScrollHorizontal = 29923 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 29924 final boolean canScrollVertical = 29925 computeVerticalScrollRange() > computeVerticalScrollExtent(); 29926 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 29927 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 29928 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 29929 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 29930 29931 int newScrollX = scrollX + deltaX; 29932 if (!overScrollHorizontal) { 29933 maxOverScrollX = 0; 29934 } 29935 29936 int newScrollY = scrollY + deltaY; 29937 if (!overScrollVertical) { 29938 maxOverScrollY = 0; 29939 } 29940 29941 // Clamp values if at the limits and record 29942 final int left = -maxOverScrollX; 29943 final int right = maxOverScrollX + scrollRangeX; 29944 final int top = -maxOverScrollY; 29945 final int bottom = maxOverScrollY + scrollRangeY; 29946 29947 boolean clampedX = false; 29948 if (newScrollX > right) { 29949 newScrollX = right; 29950 clampedX = true; 29951 } else if (newScrollX < left) { 29952 newScrollX = left; 29953 clampedX = true; 29954 } 29955 29956 boolean clampedY = false; 29957 if (newScrollY > bottom) { 29958 newScrollY = bottom; 29959 clampedY = true; 29960 } else if (newScrollY < top) { 29961 newScrollY = top; 29962 clampedY = true; 29963 } 29964 29965 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 29966 29967 return clampedX || clampedY; 29968 } 29969 29970 /** 29971 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 29972 * respond to the results of an over-scroll operation. 29973 * 29974 * @param scrollX New X scroll value in pixels 29975 * @param scrollY New Y scroll value in pixels 29976 * @param clampedX True if scrollX was clamped to an over-scroll boundary 29977 * @param clampedY True if scrollY was clamped to an over-scroll boundary 29978 */ onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY)29979 protected void onOverScrolled(int scrollX, int scrollY, 29980 boolean clampedX, boolean clampedY) { 29981 // Intentionally empty. 29982 } 29983 29984 /** 29985 * Returns the over-scroll mode for this view. The result will be 29986 * one of {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 29987 * (allow over-scrolling only if the view content is larger than the container), 29988 * or {@link #OVER_SCROLL_NEVER}. 29989 * 29990 * @return This view's over-scroll mode. 29991 */ 29992 @InspectableProperty(enumMapping = { 29993 @EnumEntry(value = OVER_SCROLL_ALWAYS, name = "always"), 29994 @EnumEntry(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"), 29995 @EnumEntry(value = OVER_SCROLL_NEVER, name = "never") 29996 }) getOverScrollMode()29997 public int getOverScrollMode() { 29998 return mOverScrollMode; 29999 } 30000 30001 /** 30002 * Set the over-scroll mode for this view. Valid over-scroll modes are 30003 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 30004 * (allow over-scrolling only if the view content is larger than the container), 30005 * or {@link #OVER_SCROLL_NEVER}. 30006 * 30007 * Setting the over-scroll mode of a view will have an effect only if the 30008 * view is capable of scrolling. 30009 * 30010 * @param overScrollMode The new over-scroll mode for this view. 30011 */ setOverScrollMode(int overScrollMode)30012 public void setOverScrollMode(int overScrollMode) { 30013 if (overScrollMode != OVER_SCROLL_ALWAYS && 30014 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 30015 overScrollMode != OVER_SCROLL_NEVER) { 30016 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 30017 } 30018 mOverScrollMode = overScrollMode; 30019 } 30020 30021 /** 30022 * Enable or disable nested scrolling for this view. 30023 * 30024 * <p>If this property is set to true the view will be permitted to initiate nested 30025 * scrolling operations with a compatible parent view in the current hierarchy. If this 30026 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 30027 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 30028 * the nested scroll.</p> 30029 * 30030 * @param enabled true to enable nested scrolling, false to disable 30031 * 30032 * @see #isNestedScrollingEnabled() 30033 */ setNestedScrollingEnabled(boolean enabled)30034 public void setNestedScrollingEnabled(boolean enabled) { 30035 if (enabled) { 30036 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 30037 } else { 30038 stopNestedScroll(); 30039 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 30040 } 30041 } 30042 30043 /** 30044 * Returns true if nested scrolling is enabled for this view. 30045 * 30046 * <p>If nested scrolling is enabled and this View class implementation supports it, 30047 * this view will act as a nested scrolling child view when applicable, forwarding data 30048 * about the scroll operation in progress to a compatible and cooperating nested scrolling 30049 * parent.</p> 30050 * 30051 * @return true if nested scrolling is enabled 30052 * 30053 * @see #setNestedScrollingEnabled(boolean) 30054 */ 30055 @InspectableProperty isNestedScrollingEnabled()30056 public boolean isNestedScrollingEnabled() { 30057 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 30058 PFLAG3_NESTED_SCROLLING_ENABLED; 30059 } 30060 30061 /** 30062 * Begin a nestable scroll operation along the given axes. 30063 * 30064 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 30065 * 30066 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 30067 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 30068 * In the case of touch scrolling the nested scroll will be terminated automatically in 30069 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 30070 * In the event of programmatic scrolling the caller must explicitly call 30071 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 30072 * 30073 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 30074 * If it returns false the caller may ignore the rest of this contract until the next scroll. 30075 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 30076 * 30077 * <p>At each incremental step of the scroll the caller should invoke 30078 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 30079 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 30080 * parent at least partially consumed the scroll and the caller should adjust the amount it 30081 * scrolls by.</p> 30082 * 30083 * <p>After applying the remainder of the scroll delta the caller should invoke 30084 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 30085 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 30086 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 30087 * </p> 30088 * 30089 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 30090 * {@link #SCROLL_AXIS_VERTICAL}. 30091 * @return true if a cooperative parent was found and nested scrolling has been enabled for 30092 * the current gesture. 30093 * 30094 * @see #stopNestedScroll() 30095 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 30096 * @see #dispatchNestedScroll(int, int, int, int, int[]) 30097 */ startNestedScroll(int axes)30098 public boolean startNestedScroll(int axes) { 30099 if (hasNestedScrollingParent()) { 30100 // Already in progress 30101 return true; 30102 } 30103 if (isNestedScrollingEnabled()) { 30104 ViewParent p = getParent(); 30105 View child = this; 30106 while (p != null) { 30107 try { 30108 if (p.onStartNestedScroll(child, this, axes)) { 30109 mNestedScrollingParent = p; 30110 p.onNestedScrollAccepted(child, this, axes); 30111 return true; 30112 } 30113 } catch (AbstractMethodError e) { 30114 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 30115 "method onStartNestedScroll", e); 30116 // Allow the search upward to continue 30117 } 30118 if (p instanceof View) { 30119 child = (View) p; 30120 } 30121 p = p.getParent(); 30122 } 30123 } 30124 return false; 30125 } 30126 30127 /** 30128 * Stop a nested scroll in progress. 30129 * 30130 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 30131 * 30132 * @see #startNestedScroll(int) 30133 */ stopNestedScroll()30134 public void stopNestedScroll() { 30135 if (mNestedScrollingParent != null) { 30136 mNestedScrollingParent.onStopNestedScroll(this); 30137 mNestedScrollingParent = null; 30138 } 30139 } 30140 30141 /** 30142 * Returns true if this view has a nested scrolling parent. 30143 * 30144 * <p>The presence of a nested scrolling parent indicates that this view has initiated 30145 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 30146 * 30147 * @return whether this view has a nested scrolling parent 30148 */ hasNestedScrollingParent()30149 public boolean hasNestedScrollingParent() { 30150 return mNestedScrollingParent != null; 30151 } 30152 30153 /** 30154 * Dispatch one step of a nested scroll in progress. 30155 * 30156 * <p>Implementations of views that support nested scrolling should call this to report 30157 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 30158 * is not currently in progress or nested scrolling is not 30159 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 30160 * 30161 * <p>Compatible View implementations should also call 30162 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 30163 * consuming a component of the scroll event themselves.</p> 30164 * 30165 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 30166 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 30167 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 30168 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 30169 * @param offsetInWindow Optional. If not null, on return this will contain the offset 30170 * in local view coordinates of this view from before this operation 30171 * to after it completes. View implementations may use this to adjust 30172 * expected input coordinate tracking. 30173 * @return true if the event was dispatched, false if it could not be dispatched. 30174 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 30175 */ dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow)30176 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 30177 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 30178 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 30179 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 30180 int startX = 0; 30181 int startY = 0; 30182 if (offsetInWindow != null) { 30183 getLocationInWindow(offsetInWindow); 30184 startX = offsetInWindow[0]; 30185 startY = offsetInWindow[1]; 30186 } 30187 30188 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 30189 dxUnconsumed, dyUnconsumed); 30190 30191 if (offsetInWindow != null) { 30192 getLocationInWindow(offsetInWindow); 30193 offsetInWindow[0] -= startX; 30194 offsetInWindow[1] -= startY; 30195 } 30196 return true; 30197 } else if (offsetInWindow != null) { 30198 // No motion, no dispatch. Keep offsetInWindow up to date. 30199 offsetInWindow[0] = 0; 30200 offsetInWindow[1] = 0; 30201 } 30202 } 30203 return false; 30204 } 30205 30206 /** 30207 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 30208 * 30209 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 30210 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 30211 * scrolling operation to consume some or all of the scroll operation before the child view 30212 * consumes it.</p> 30213 * 30214 * @param dx Horizontal scroll distance in pixels 30215 * @param dy Vertical scroll distance in pixels 30216 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 30217 * and consumed[1] the consumed dy. 30218 * @param offsetInWindow Optional. If not null, on return this will contain the offset 30219 * in local view coordinates of this view from before this operation 30220 * to after it completes. View implementations may use this to adjust 30221 * expected input coordinate tracking. 30222 * @return true if the parent consumed some or all of the scroll delta 30223 * @see #dispatchNestedScroll(int, int, int, int, int[]) 30224 */ dispatchNestedPreScroll(int dx, int dy, @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow)30225 public boolean dispatchNestedPreScroll(int dx, int dy, 30226 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 30227 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 30228 if (dx != 0 || dy != 0) { 30229 int startX = 0; 30230 int startY = 0; 30231 if (offsetInWindow != null) { 30232 getLocationInWindow(offsetInWindow); 30233 startX = offsetInWindow[0]; 30234 startY = offsetInWindow[1]; 30235 } 30236 30237 if (consumed == null) { 30238 if (mTempNestedScrollConsumed == null) { 30239 mTempNestedScrollConsumed = new int[2]; 30240 } 30241 consumed = mTempNestedScrollConsumed; 30242 } 30243 consumed[0] = 0; 30244 consumed[1] = 0; 30245 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 30246 30247 if (offsetInWindow != null) { 30248 getLocationInWindow(offsetInWindow); 30249 offsetInWindow[0] -= startX; 30250 offsetInWindow[1] -= startY; 30251 } 30252 return consumed[0] != 0 || consumed[1] != 0; 30253 } else if (offsetInWindow != null) { 30254 offsetInWindow[0] = 0; 30255 offsetInWindow[1] = 0; 30256 } 30257 } 30258 return false; 30259 } 30260 30261 /** 30262 * Dispatch a fling to a nested scrolling parent. 30263 * 30264 * <p>This method should be used to indicate that a nested scrolling child has detected 30265 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 30266 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 30267 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 30268 * along a scrollable axis.</p> 30269 * 30270 * <p>If a nested scrolling child view would normally fling but it is at the edge of 30271 * its own content, it can use this method to delegate the fling to its nested scrolling 30272 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 30273 * 30274 * @param velocityX Horizontal fling velocity in pixels per second 30275 * @param velocityY Vertical fling velocity in pixels per second 30276 * @param consumed true if the child consumed the fling, false otherwise 30277 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 30278 */ dispatchNestedFling(float velocityX, float velocityY, boolean consumed)30279 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 30280 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 30281 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 30282 } 30283 return false; 30284 } 30285 30286 /** 30287 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 30288 * 30289 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 30290 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 30291 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 30292 * before the child view consumes it. If this method returns <code>true</code>, a nested 30293 * parent view consumed the fling and this view should not scroll as a result.</p> 30294 * 30295 * <p>For a better user experience, only one view in a nested scrolling chain should consume 30296 * the fling at a time. If a parent view consumed the fling this method will return false. 30297 * Custom view implementations should account for this in two ways:</p> 30298 * 30299 * <ul> 30300 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 30301 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 30302 * position regardless.</li> 30303 * <li>If a nested parent does consume the fling, this view should not scroll at all, 30304 * even to settle back to a valid idle position.</li> 30305 * </ul> 30306 * 30307 * <p>Views should also not offer fling velocities to nested parent views along an axis 30308 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 30309 * should not offer a horizontal fling velocity to its parents since scrolling along that 30310 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 30311 * 30312 * @param velocityX Horizontal fling velocity in pixels per second 30313 * @param velocityY Vertical fling velocity in pixels per second 30314 * @return true if a nested scrolling parent consumed the fling 30315 */ dispatchNestedPreFling(float velocityX, float velocityY)30316 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 30317 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 30318 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 30319 } 30320 return false; 30321 } 30322 30323 /** 30324 * Gets a scale factor that determines the distance the view should scroll 30325 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 30326 * @return The vertical scroll scale factor. 30327 * @hide 30328 */ 30329 @UnsupportedAppUsage getVerticalScrollFactor()30330 protected float getVerticalScrollFactor() { 30331 if (mVerticalScrollFactor == 0) { 30332 TypedValue outValue = new TypedValue(); 30333 if (!mContext.getTheme().resolveAttribute( 30334 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 30335 throw new IllegalStateException( 30336 "Expected theme to define listPreferredItemHeight."); 30337 } 30338 mVerticalScrollFactor = outValue.getDimension( 30339 mContext.getResources().getDisplayMetrics()); 30340 } 30341 return mVerticalScrollFactor; 30342 } 30343 30344 /** 30345 * Gets a scale factor that determines the distance the view should scroll 30346 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 30347 * @return The horizontal scroll scale factor. 30348 * @hide 30349 */ 30350 @UnsupportedAppUsage getHorizontalScrollFactor()30351 protected float getHorizontalScrollFactor() { 30352 // TODO: Should use something else. 30353 return getVerticalScrollFactor(); 30354 } 30355 30356 /** 30357 * Return the value specifying the text direction or policy that was set with 30358 * {@link #setTextDirection(int)}. 30359 * 30360 * @return the defined text direction. It can be one of: 30361 * 30362 * {@link #TEXT_DIRECTION_INHERIT}, 30363 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 30364 * {@link #TEXT_DIRECTION_ANY_RTL}, 30365 * {@link #TEXT_DIRECTION_LTR}, 30366 * {@link #TEXT_DIRECTION_RTL}, 30367 * {@link #TEXT_DIRECTION_LOCALE}, 30368 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 30369 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 30370 * 30371 * @attr ref android.R.styleable#View_textDirection 30372 * 30373 * @hide 30374 */ 30375 @ViewDebug.ExportedProperty(category = "text", mapping = { 30376 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 30377 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 30378 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 30379 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 30380 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 30381 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 30382 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 30383 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 30384 }) 30385 @InspectableProperty(hasAttributeId = false, enumMapping = { 30386 @EnumEntry(value = TEXT_DIRECTION_INHERIT, name = "inherit"), 30387 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 30388 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 30389 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 30390 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 30391 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 30392 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 30393 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 30394 }) 30395 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getRawTextDirection()30396 public int getRawTextDirection() { 30397 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 30398 } 30399 30400 /** 30401 * Set the text direction. 30402 * 30403 * @param textDirection the direction to set. Should be one of: 30404 * 30405 * {@link #TEXT_DIRECTION_INHERIT}, 30406 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 30407 * {@link #TEXT_DIRECTION_ANY_RTL}, 30408 * {@link #TEXT_DIRECTION_LTR}, 30409 * {@link #TEXT_DIRECTION_RTL}, 30410 * {@link #TEXT_DIRECTION_LOCALE} 30411 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 30412 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 30413 * 30414 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 30415 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 30416 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 30417 * 30418 * @attr ref android.R.styleable#View_textDirection 30419 */ setTextDirection(int textDirection)30420 public void setTextDirection(int textDirection) { 30421 if (getRawTextDirection() != textDirection) { 30422 // Reset the current text direction and the resolved one 30423 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 30424 resetResolvedTextDirection(); 30425 // Set the new text direction 30426 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 30427 // Do resolution 30428 resolveTextDirection(); 30429 // Notify change 30430 onRtlPropertiesChanged(getLayoutDirection()); 30431 // Refresh 30432 requestLayout(); 30433 invalidate(true); 30434 } 30435 } 30436 30437 /** 30438 * Return the resolved text direction. 30439 * 30440 * @return the resolved text direction. Returns one of: 30441 * 30442 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 30443 * {@link #TEXT_DIRECTION_ANY_RTL}, 30444 * {@link #TEXT_DIRECTION_LTR}, 30445 * {@link #TEXT_DIRECTION_RTL}, 30446 * {@link #TEXT_DIRECTION_LOCALE}, 30447 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 30448 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 30449 * 30450 * @attr ref android.R.styleable#View_textDirection 30451 */ 30452 @ViewDebug.ExportedProperty(category = "text", mapping = { 30453 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 30454 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 30455 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 30456 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 30457 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 30458 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 30459 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 30460 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 30461 }) 30462 @InspectableProperty(hasAttributeId = false, enumMapping = { 30463 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 30464 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 30465 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 30466 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 30467 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 30468 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 30469 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 30470 }) getTextDirection()30471 public int getTextDirection() { 30472 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 30473 } 30474 30475 /** 30476 * Resolve the text direction. 30477 * 30478 * @return true if resolution has been done, false otherwise. 30479 * 30480 * @hide 30481 */ resolveTextDirection()30482 public boolean resolveTextDirection() { 30483 // Reset any previous text direction resolution 30484 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 30485 30486 if (hasRtlSupport()) { 30487 // Set resolved text direction flag depending on text direction flag 30488 final int textDirection = getRawTextDirection(); 30489 switch(textDirection) { 30490 case TEXT_DIRECTION_INHERIT: 30491 if (!canResolveTextDirection()) { 30492 // We cannot do the resolution if there is no parent, so use the default one 30493 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 30494 // Resolution will need to happen again later 30495 return false; 30496 } 30497 30498 // Parent has not yet resolved, so we still return the default 30499 try { 30500 if (!mParent.isTextDirectionResolved()) { 30501 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 30502 // Resolution will need to happen again later 30503 return false; 30504 } 30505 } catch (AbstractMethodError e) { 30506 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 30507 " does not fully implement ViewParent", e); 30508 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 30509 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 30510 return true; 30511 } 30512 30513 // Set current resolved direction to the same value as the parent's one 30514 int parentResolvedDirection; 30515 try { 30516 parentResolvedDirection = mParent.getTextDirection(); 30517 } catch (AbstractMethodError e) { 30518 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 30519 " does not fully implement ViewParent", e); 30520 parentResolvedDirection = TEXT_DIRECTION_LTR; 30521 } 30522 switch (parentResolvedDirection) { 30523 case TEXT_DIRECTION_FIRST_STRONG: 30524 case TEXT_DIRECTION_ANY_RTL: 30525 case TEXT_DIRECTION_LTR: 30526 case TEXT_DIRECTION_RTL: 30527 case TEXT_DIRECTION_LOCALE: 30528 case TEXT_DIRECTION_FIRST_STRONG_LTR: 30529 case TEXT_DIRECTION_FIRST_STRONG_RTL: 30530 mPrivateFlags2 |= 30531 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 30532 break; 30533 default: 30534 // Default resolved direction is "first strong" heuristic 30535 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 30536 } 30537 break; 30538 case TEXT_DIRECTION_FIRST_STRONG: 30539 case TEXT_DIRECTION_ANY_RTL: 30540 case TEXT_DIRECTION_LTR: 30541 case TEXT_DIRECTION_RTL: 30542 case TEXT_DIRECTION_LOCALE: 30543 case TEXT_DIRECTION_FIRST_STRONG_LTR: 30544 case TEXT_DIRECTION_FIRST_STRONG_RTL: 30545 // Resolved direction is the same as text direction 30546 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 30547 break; 30548 default: 30549 // Default resolved direction is "first strong" heuristic 30550 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 30551 } 30552 } else { 30553 // Default resolved direction is "first strong" heuristic 30554 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 30555 } 30556 30557 // Set to resolved 30558 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 30559 return true; 30560 } 30561 30562 /** 30563 * Check if text direction resolution can be done. 30564 * 30565 * @return true if text direction resolution can be done otherwise return false. 30566 */ canResolveTextDirection()30567 public boolean canResolveTextDirection() { 30568 switch (getRawTextDirection()) { 30569 case TEXT_DIRECTION_INHERIT: 30570 if (mParent != null) { 30571 try { 30572 return mParent.canResolveTextDirection(); 30573 } catch (AbstractMethodError e) { 30574 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 30575 " does not fully implement ViewParent", e); 30576 } 30577 } 30578 return false; 30579 30580 default: 30581 return true; 30582 } 30583 } 30584 30585 /** 30586 * Reset resolved text direction. Text direction will be resolved during a call to 30587 * {@link #onMeasure(int, int)}. 30588 * 30589 * @hide 30590 */ 30591 @TestApi resetResolvedTextDirection()30592 public void resetResolvedTextDirection() { 30593 // Reset any previous text direction resolution 30594 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 30595 // Set to default value 30596 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 30597 } 30598 30599 /** 30600 * @return true if text direction is inherited. 30601 * 30602 * @hide 30603 */ isTextDirectionInherited()30604 public boolean isTextDirectionInherited() { 30605 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 30606 } 30607 30608 /** 30609 * @return true if text direction is resolved. 30610 */ isTextDirectionResolved()30611 public boolean isTextDirectionResolved() { 30612 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 30613 } 30614 30615 /** 30616 * Return the value specifying the text alignment or policy that was set with 30617 * {@link #setTextAlignment(int)}. 30618 * 30619 * @return the defined text alignment. It can be one of: 30620 * 30621 * {@link #TEXT_ALIGNMENT_INHERIT}, 30622 * {@link #TEXT_ALIGNMENT_GRAVITY}, 30623 * {@link #TEXT_ALIGNMENT_CENTER}, 30624 * {@link #TEXT_ALIGNMENT_TEXT_START}, 30625 * {@link #TEXT_ALIGNMENT_TEXT_END}, 30626 * {@link #TEXT_ALIGNMENT_VIEW_START}, 30627 * {@link #TEXT_ALIGNMENT_VIEW_END} 30628 * 30629 * @attr ref android.R.styleable#View_textAlignment 30630 * 30631 * @hide 30632 */ 30633 @ViewDebug.ExportedProperty(category = "text", mapping = { 30634 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 30635 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 30636 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 30637 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 30638 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 30639 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 30640 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 30641 }) 30642 @InspectableProperty(hasAttributeId = false, enumMapping = { 30643 @EnumEntry(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"), 30644 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 30645 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 30646 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 30647 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 30648 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 30649 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 30650 }) 30651 @TextAlignment 30652 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getRawTextAlignment()30653 public int getRawTextAlignment() { 30654 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 30655 } 30656 30657 /** 30658 * Set the text alignment. 30659 * 30660 * @param textAlignment The text alignment to set. Should be one of 30661 * 30662 * {@link #TEXT_ALIGNMENT_INHERIT}, 30663 * {@link #TEXT_ALIGNMENT_GRAVITY}, 30664 * {@link #TEXT_ALIGNMENT_CENTER}, 30665 * {@link #TEXT_ALIGNMENT_TEXT_START}, 30666 * {@link #TEXT_ALIGNMENT_TEXT_END}, 30667 * {@link #TEXT_ALIGNMENT_VIEW_START}, 30668 * {@link #TEXT_ALIGNMENT_VIEW_END} 30669 * 30670 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 30671 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 30672 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 30673 * 30674 * @attr ref android.R.styleable#View_textAlignment 30675 */ setTextAlignment(@extAlignment int textAlignment)30676 public void setTextAlignment(@TextAlignment int textAlignment) { 30677 if (textAlignment != getRawTextAlignment()) { 30678 // Reset the current and resolved text alignment 30679 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 30680 resetResolvedTextAlignment(); 30681 // Set the new text alignment 30682 mPrivateFlags2 |= 30683 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 30684 // Do resolution 30685 resolveTextAlignment(); 30686 // Notify change 30687 onRtlPropertiesChanged(getLayoutDirection()); 30688 // Refresh 30689 requestLayout(); 30690 invalidate(true); 30691 } 30692 } 30693 30694 /** 30695 * Return the resolved text alignment. 30696 * 30697 * @return the resolved text alignment. Returns one of: 30698 * 30699 * {@link #TEXT_ALIGNMENT_GRAVITY}, 30700 * {@link #TEXT_ALIGNMENT_CENTER}, 30701 * {@link #TEXT_ALIGNMENT_TEXT_START}, 30702 * {@link #TEXT_ALIGNMENT_TEXT_END}, 30703 * {@link #TEXT_ALIGNMENT_VIEW_START}, 30704 * {@link #TEXT_ALIGNMENT_VIEW_END} 30705 * 30706 * @attr ref android.R.styleable#View_textAlignment 30707 */ 30708 @ViewDebug.ExportedProperty(category = "text", mapping = { 30709 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 30710 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 30711 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 30712 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 30713 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 30714 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 30715 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 30716 }) 30717 @InspectableProperty(enumMapping = { 30718 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 30719 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 30720 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 30721 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 30722 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 30723 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 30724 }) 30725 @TextAlignment getTextAlignment()30726 public int getTextAlignment() { 30727 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 30728 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 30729 } 30730 30731 /** 30732 * Resolve the text alignment. 30733 * 30734 * @return true if resolution has been done, false otherwise. 30735 * 30736 * @hide 30737 */ resolveTextAlignment()30738 public boolean resolveTextAlignment() { 30739 // Reset any previous text alignment resolution 30740 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 30741 30742 if (hasRtlSupport()) { 30743 // Set resolved text alignment flag depending on text alignment flag 30744 final int textAlignment = getRawTextAlignment(); 30745 switch (textAlignment) { 30746 case TEXT_ALIGNMENT_INHERIT: 30747 // Check if we can resolve the text alignment 30748 if (!canResolveTextAlignment()) { 30749 // We cannot do the resolution if there is no parent so use the default 30750 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 30751 // Resolution will need to happen again later 30752 return false; 30753 } 30754 30755 // Parent has not yet resolved, so we still return the default 30756 try { 30757 if (!mParent.isTextAlignmentResolved()) { 30758 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 30759 // Resolution will need to happen again later 30760 return false; 30761 } 30762 } catch (AbstractMethodError e) { 30763 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 30764 " does not fully implement ViewParent", e); 30765 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 30766 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 30767 return true; 30768 } 30769 30770 int parentResolvedTextAlignment; 30771 try { 30772 parentResolvedTextAlignment = mParent.getTextAlignment(); 30773 } catch (AbstractMethodError e) { 30774 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 30775 " does not fully implement ViewParent", e); 30776 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 30777 } 30778 switch (parentResolvedTextAlignment) { 30779 case TEXT_ALIGNMENT_GRAVITY: 30780 case TEXT_ALIGNMENT_TEXT_START: 30781 case TEXT_ALIGNMENT_TEXT_END: 30782 case TEXT_ALIGNMENT_CENTER: 30783 case TEXT_ALIGNMENT_VIEW_START: 30784 case TEXT_ALIGNMENT_VIEW_END: 30785 // Resolved text alignment is the same as the parent resolved 30786 // text alignment 30787 mPrivateFlags2 |= 30788 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 30789 break; 30790 default: 30791 // Use default resolved text alignment 30792 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 30793 } 30794 break; 30795 case TEXT_ALIGNMENT_GRAVITY: 30796 case TEXT_ALIGNMENT_TEXT_START: 30797 case TEXT_ALIGNMENT_TEXT_END: 30798 case TEXT_ALIGNMENT_CENTER: 30799 case TEXT_ALIGNMENT_VIEW_START: 30800 case TEXT_ALIGNMENT_VIEW_END: 30801 // Resolved text alignment is the same as text alignment 30802 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 30803 break; 30804 default: 30805 // Use default resolved text alignment 30806 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 30807 } 30808 } else { 30809 // Use default resolved text alignment 30810 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 30811 } 30812 30813 // Set the resolved 30814 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 30815 return true; 30816 } 30817 30818 /** 30819 * Check if text alignment resolution can be done. 30820 * 30821 * @return true if text alignment resolution can be done otherwise return false. 30822 */ canResolveTextAlignment()30823 public boolean canResolveTextAlignment() { 30824 switch (getRawTextAlignment()) { 30825 case TEXT_DIRECTION_INHERIT: 30826 if (mParent != null) { 30827 try { 30828 return mParent.canResolveTextAlignment(); 30829 } catch (AbstractMethodError e) { 30830 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 30831 " does not fully implement ViewParent", e); 30832 } 30833 } 30834 return false; 30835 30836 default: 30837 return true; 30838 } 30839 } 30840 30841 /** 30842 * Reset resolved text alignment. Text alignment will be resolved during a call to 30843 * {@link #onMeasure(int, int)}. 30844 * 30845 * @hide 30846 */ 30847 @TestApi resetResolvedTextAlignment()30848 public void resetResolvedTextAlignment() { 30849 // Reset any previous text alignment resolution 30850 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 30851 // Set to default 30852 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 30853 } 30854 30855 /** 30856 * @return true if text alignment is inherited. 30857 * 30858 * @hide 30859 */ isTextAlignmentInherited()30860 public boolean isTextAlignmentInherited() { 30861 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 30862 } 30863 30864 /** 30865 * @return true if text alignment is resolved. 30866 */ isTextAlignmentResolved()30867 public boolean isTextAlignmentResolved() { 30868 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 30869 } 30870 30871 /** 30872 * Generate a value suitable for use in {@link #setId(int)}. 30873 * This value will not collide with ID values generated at build time by aapt for R.id. 30874 * 30875 * @return a generated ID value 30876 */ generateViewId()30877 public static int generateViewId() { 30878 for (;;) { 30879 final int result = sNextGeneratedId.get(); 30880 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 30881 int newValue = result + 1; 30882 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 30883 if (sNextGeneratedId.compareAndSet(result, newValue)) { 30884 return result; 30885 } 30886 } 30887 } 30888 30889 // Note that if the function returns true, it indicates aapt did not generate this id. 30890 // However false value does not indicate that aapt did generated this id. isViewIdGenerated(int id)30891 private static boolean isViewIdGenerated(int id) { 30892 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 30893 } 30894 30895 /** 30896 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 30897 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 30898 * a normal View or a ViewGroup with 30899 * {@link android.view.ViewGroup#isTransitionGroup()} true. 30900 * @hide 30901 */ captureTransitioningViews(List<View> transitioningViews)30902 public void captureTransitioningViews(List<View> transitioningViews) { 30903 if (getVisibility() == View.VISIBLE) { 30904 transitioningViews.add(this); 30905 } 30906 } 30907 30908 /** 30909 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 30910 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 30911 * @hide 30912 */ findNamedViews(Map<String, View> namedElements)30913 public void findNamedViews(Map<String, View> namedElements) { 30914 if (getVisibility() == VISIBLE || mGhostView != null) { 30915 String transitionName = getTransitionName(); 30916 if (transitionName != null) { 30917 namedElements.put(transitionName, this); 30918 } 30919 } 30920 } 30921 30922 /** 30923 * Resolve the pointer icon that should be used for specified pointer in the motion event. 30924 * 30925 * The default implementation will resolve the pointer icon to one set using 30926 * {@link #setPointerIcon(PointerIcon)} for mouse devices. Subclasses may override this to 30927 * customize the icon for the given pointer. 30928 * 30929 * For example, to always show the PointerIcon.TYPE_HANDWRITING icon for a stylus pointer, 30930 * the event can be resolved in the following way: 30931 * <code><pre> 30932 * @Override 30933 * public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 30934 * final int toolType = event.getToolType(pointerIndex); 30935 * if (!event.isFromSource(InputDevice.SOURCE_MOUSE) 30936 * && event.isFromSource(InputDevice.SOURCE_STYLUS) 30937 * && (toolType == MotionEvent.TOOL_TYPE_STYLUS 30938 * || toolType == MotionEvent.TOOL_TYPE_ERASER)) { 30939 * // Show this pointer icon only if this pointer is a stylus. 30940 * return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_HANDWRITING); 30941 * } 30942 * // Use the default logic for determining the pointer icon for other non-stylus pointers, 30943 * // like for the mouse cursor. 30944 * return super.onResolvePointerIcon(event, pointerIndex); 30945 * } 30946 * </pre></code> 30947 * 30948 * @param event The {@link MotionEvent} that requires a pointer icon to be resolved for one of 30949 * pointers. 30950 * @param pointerIndex The index of the pointer in {@code event} for which to retrieve the 30951 * {@link PointerIcon}. This will be between 0 and {@link MotionEvent#getPointerCount()}. 30952 * @return the pointer icon to use for specified pointer, or {@code null} if a pointer icon 30953 * is not specified and the default icon should be used. 30954 * @see PointerIcon 30955 * @see InputManager#isStylusPointerIconEnabled() 30956 */ onResolvePointerIcon(MotionEvent event, int pointerIndex)30957 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 30958 final float x = event.getX(pointerIndex); 30959 final float y = event.getY(pointerIndex); 30960 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 30961 // Use the default pointer icon. 30962 return null; 30963 } 30964 30965 // Note: A drawing tablet will have both SOURCE_MOUSE and SOURCE_STYLUS, but it would use 30966 // TOOL_TYPE_STYLUS. For now, treat drawing tablets the same way as a mouse or touchpad. 30967 if (event.isFromSource(InputDevice.SOURCE_MOUSE)) { 30968 return mMousePointerIcon; 30969 } 30970 30971 return null; 30972 } 30973 30974 /** 30975 * Set the pointer icon to be used for a mouse pointer in the current view. 30976 * 30977 * Passing {@code null} will restore the pointer icon to its default value. 30978 * Note that setting the pointer icon using this method will only set it for events coming from 30979 * a mouse device (i.e. with source {@link InputDevice#SOURCE_MOUSE}). To resolve 30980 * the pointer icon for other device types like styluses, override 30981 * {@link #onResolvePointerIcon(MotionEvent, int)}. 30982 * 30983 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 30984 * @see #onResolvePointerIcon(MotionEvent, int) 30985 * @see PointerIcon 30986 */ setPointerIcon(PointerIcon pointerIcon)30987 public void setPointerIcon(PointerIcon pointerIcon) { 30988 mMousePointerIcon = pointerIcon; 30989 final ViewRootImpl viewRootImpl = getViewRootImpl(); 30990 if (viewRootImpl == null) { 30991 return; 30992 } 30993 viewRootImpl.refreshPointerIcon(); 30994 } 30995 30996 /** 30997 * Gets the mouse pointer icon for the current view. 30998 * 30999 * @see #setPointerIcon(PointerIcon) 31000 */ 31001 @InspectableProperty getPointerIcon()31002 public PointerIcon getPointerIcon() { 31003 return mMousePointerIcon; 31004 } 31005 31006 /** 31007 * Checks pointer capture status. 31008 * 31009 * @return true if the view has pointer capture. 31010 * @see #requestPointerCapture() 31011 * @see #hasPointerCapture() 31012 */ hasPointerCapture()31013 public boolean hasPointerCapture() { 31014 final ViewRootImpl viewRootImpl = getViewRootImpl(); 31015 if (viewRootImpl == null) { 31016 return false; 31017 } 31018 return viewRootImpl.hasPointerCapture(); 31019 } 31020 31021 /** 31022 * Requests pointer capture mode. 31023 * <p> 31024 * When the window has pointer capture, the mouse pointer icon will disappear and will not 31025 * change its position. Enabling pointer capture will change the behavior of input devices in 31026 * the following ways: 31027 * <ul> 31028 * <li>Events from a mouse will be delivered with the source 31029 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be 31030 * available through {@link MotionEvent#getX} and {@link MotionEvent#getY}.</li> 31031 * 31032 * <li>Events from a touchpad or trackpad will be delivered with the source 31033 * {@link InputDevice#SOURCE_TOUCHPAD}, where the absolute position of each of the pointers 31034 * on the touchpad will be available through {@link MotionEvent#getX(int)} and 31035 * {@link MotionEvent#getY(int)}, and their relative movements are stored in 31036 * {@link MotionEvent#AXIS_RELATIVE_X} and {@link MotionEvent#AXIS_RELATIVE_Y}.</li> 31037 * 31038 * <li>Events from other types of devices, such as touchscreens, will not be affected.</li> 31039 * </ul> 31040 * <p> 31041 * When pointer capture changes, connected mouse and trackpad devices may be reconfigured, 31042 * and their properties (such as their sources or motion ranges) may change. Use an 31043 * {@link android.hardware.input.InputManager.InputDeviceListener} to be notified when a device 31044 * changes (which may happen after enabling or disabling pointer capture), and use 31045 * {@link InputDevice#getDevice(int)} to get the updated {@link InputDevice}. 31046 * <p> 31047 * Events captured through pointer capture will be dispatched to 31048 * {@link OnCapturedPointerListener#onCapturedPointer(View, MotionEvent)} if an 31049 * {@link OnCapturedPointerListener} is set, and otherwise to 31050 * {@link #onCapturedPointerEvent(MotionEvent)}. 31051 * <p> 31052 * If the window already has pointer capture, this call does nothing. 31053 * <p> 31054 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 31055 * automatically when the window loses focus. 31056 * 31057 * @see #releasePointerCapture() 31058 * @see #hasPointerCapture() 31059 * @see #onPointerCaptureChange(boolean) 31060 */ requestPointerCapture()31061 public void requestPointerCapture() { 31062 final ViewRootImpl viewRootImpl = getViewRootImpl(); 31063 if (viewRootImpl != null) { 31064 viewRootImpl.requestPointerCapture(true); 31065 } 31066 } 31067 31068 31069 /** 31070 * Releases the pointer capture. 31071 * <p> 31072 * If the window does not have pointer capture, this call will do nothing. 31073 * @see #requestPointerCapture() 31074 * @see #hasPointerCapture() 31075 * @see #onPointerCaptureChange(boolean) 31076 */ releasePointerCapture()31077 public void releasePointerCapture() { 31078 final ViewRootImpl viewRootImpl = getViewRootImpl(); 31079 if (viewRootImpl != null) { 31080 viewRootImpl.requestPointerCapture(false); 31081 } 31082 } 31083 31084 /** 31085 * Called when the window has just acquired or lost pointer capture. 31086 * 31087 * @param hasCapture True if the view now has pointerCapture, false otherwise. 31088 */ 31089 @CallSuper onPointerCaptureChange(boolean hasCapture)31090 public void onPointerCaptureChange(boolean hasCapture) { 31091 } 31092 31093 /** 31094 * @see #onPointerCaptureChange 31095 */ dispatchPointerCaptureChanged(boolean hasCapture)31096 public void dispatchPointerCaptureChanged(boolean hasCapture) { 31097 onPointerCaptureChange(hasCapture); 31098 } 31099 31100 /** 31101 * Implement this method to handle captured pointer events 31102 * 31103 * @param event The captured pointer event. 31104 * @return True if the event was handled, false otherwise. 31105 * @see #requestPointerCapture() 31106 */ onCapturedPointerEvent(MotionEvent event)31107 public boolean onCapturedPointerEvent(MotionEvent event) { 31108 return false; 31109 } 31110 31111 /** 31112 * Interface definition for a callback to be invoked when a captured pointer event 31113 * is being dispatched this view. The callback will be invoked before the event is 31114 * given to the view. 31115 */ 31116 public interface OnCapturedPointerListener { 31117 /** 31118 * Called when a captured pointer event is dispatched to a view. 31119 * @param view The view this event has been dispatched to. 31120 * @param event The captured event. 31121 * @return True if the listener has consumed the event, false otherwise. 31122 */ onCapturedPointer(View view, MotionEvent event)31123 boolean onCapturedPointer(View view, MotionEvent event); 31124 } 31125 31126 /** 31127 * Set a listener to receive callbacks when the pointer capture state of a view changes. 31128 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 31129 */ setOnCapturedPointerListener(OnCapturedPointerListener l)31130 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 31131 getListenerInfo().mOnCapturedPointerListener = l; 31132 } 31133 31134 // Properties 31135 // 31136 /** 31137 * A Property wrapper around the <code>alpha</code> functionality handled by the 31138 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 31139 */ 31140 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 31141 @Override 31142 public void setValue(View object, float value) { 31143 object.setAlpha(value); 31144 } 31145 31146 @Override 31147 public Float get(View object) { 31148 return object.getAlpha(); 31149 } 31150 }; 31151 31152 /** 31153 * A Property wrapper around the <code>translationX</code> functionality handled by the 31154 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 31155 */ 31156 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 31157 @Override 31158 public void setValue(View object, float value) { 31159 object.setTranslationX(value); 31160 } 31161 31162 @Override 31163 public Float get(View object) { 31164 return object.getTranslationX(); 31165 } 31166 }; 31167 31168 /** 31169 * A Property wrapper around the <code>translationY</code> functionality handled by the 31170 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 31171 */ 31172 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 31173 @Override 31174 public void setValue(View object, float value) { 31175 object.setTranslationY(value); 31176 } 31177 31178 @Override 31179 public Float get(View object) { 31180 return object.getTranslationY(); 31181 } 31182 }; 31183 31184 /** 31185 * A Property wrapper around the <code>translationZ</code> functionality handled by the 31186 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 31187 */ 31188 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 31189 @Override 31190 public void setValue(View object, float value) { 31191 object.setTranslationZ(value); 31192 } 31193 31194 @Override 31195 public Float get(View object) { 31196 return object.getTranslationZ(); 31197 } 31198 }; 31199 31200 /** 31201 * A Property wrapper around the <code>x</code> functionality handled by the 31202 * {@link View#setX(float)} and {@link View#getX()} methods. 31203 */ 31204 public static final Property<View, Float> X = new FloatProperty<View>("x") { 31205 @Override 31206 public void setValue(View object, float value) { 31207 object.setX(value); 31208 } 31209 31210 @Override 31211 public Float get(View object) { 31212 return object.getX(); 31213 } 31214 }; 31215 31216 /** 31217 * A Property wrapper around the <code>y</code> functionality handled by the 31218 * {@link View#setY(float)} and {@link View#getY()} methods. 31219 */ 31220 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 31221 @Override 31222 public void setValue(View object, float value) { 31223 object.setY(value); 31224 } 31225 31226 @Override 31227 public Float get(View object) { 31228 return object.getY(); 31229 } 31230 }; 31231 31232 /** 31233 * A Property wrapper around the <code>z</code> functionality handled by the 31234 * {@link View#setZ(float)} and {@link View#getZ()} methods. 31235 */ 31236 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 31237 @Override 31238 public void setValue(View object, float value) { 31239 object.setZ(value); 31240 } 31241 31242 @Override 31243 public Float get(View object) { 31244 return object.getZ(); 31245 } 31246 }; 31247 31248 /** 31249 * A Property wrapper around the <code>rotation</code> functionality handled by the 31250 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 31251 */ 31252 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 31253 @Override 31254 public void setValue(View object, float value) { 31255 object.setRotation(value); 31256 } 31257 31258 @Override 31259 public Float get(View object) { 31260 return object.getRotation(); 31261 } 31262 }; 31263 31264 /** 31265 * A Property wrapper around the <code>rotationX</code> functionality handled by the 31266 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 31267 */ 31268 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 31269 @Override 31270 public void setValue(View object, float value) { 31271 object.setRotationX(value); 31272 } 31273 31274 @Override 31275 public Float get(View object) { 31276 return object.getRotationX(); 31277 } 31278 }; 31279 31280 /** 31281 * A Property wrapper around the <code>rotationY</code> functionality handled by the 31282 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 31283 */ 31284 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 31285 @Override 31286 public void setValue(View object, float value) { 31287 object.setRotationY(value); 31288 } 31289 31290 @Override 31291 public Float get(View object) { 31292 return object.getRotationY(); 31293 } 31294 }; 31295 31296 /** 31297 * A Property wrapper around the <code>scaleX</code> functionality handled by the 31298 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 31299 */ 31300 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 31301 @Override 31302 public void setValue(View object, float value) { 31303 object.setScaleX(value); 31304 } 31305 31306 @Override 31307 public Float get(View object) { 31308 return object.getScaleX(); 31309 } 31310 }; 31311 31312 /** 31313 * A Property wrapper around the <code>scaleY</code> functionality handled by the 31314 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 31315 */ 31316 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 31317 @Override 31318 public void setValue(View object, float value) { 31319 object.setScaleY(value); 31320 } 31321 31322 @Override 31323 public Float get(View object) { 31324 return object.getScaleY(); 31325 } 31326 }; 31327 31328 /** 31329 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 31330 * Each MeasureSpec represents a requirement for either the width or the height. 31331 * A MeasureSpec is comprised of a size and a mode. There are three possible 31332 * modes: 31333 * <dl> 31334 * <dt>UNSPECIFIED</dt> 31335 * <dd> 31336 * The parent has not imposed any constraint on the child. It can be whatever size 31337 * it wants. 31338 * </dd> 31339 * 31340 * <dt>EXACTLY</dt> 31341 * <dd> 31342 * The parent has determined an exact size for the child. The child is going to be 31343 * given those bounds regardless of how big it wants to be. 31344 * </dd> 31345 * 31346 * <dt>AT_MOST</dt> 31347 * <dd> 31348 * The child can be as large as it wants up to the specified size. 31349 * </dd> 31350 * </dl> 31351 * 31352 * MeasureSpecs are implemented as ints to reduce object allocation. This class 31353 * is provided to pack and unpack the <size, mode> tuple into the int. 31354 */ 31355 public static class MeasureSpec { 31356 private static final int MODE_SHIFT = 30; 31357 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 31358 31359 /** @hide */ 31360 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 31361 @Retention(RetentionPolicy.SOURCE) 31362 public @interface MeasureSpecMode {} 31363 31364 /** 31365 * Measure specification mode: The parent has not imposed any constraint 31366 * on the child. It can be whatever size it wants. 31367 */ 31368 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 31369 31370 /** 31371 * Measure specification mode: The parent has determined an exact size 31372 * for the child. The child is going to be given those bounds regardless 31373 * of how big it wants to be. 31374 */ 31375 public static final int EXACTLY = 1 << MODE_SHIFT; 31376 31377 /** 31378 * Measure specification mode: The child can be as large as it wants up 31379 * to the specified size. 31380 */ 31381 public static final int AT_MOST = 2 << MODE_SHIFT; 31382 31383 /** 31384 * Creates a measure specification based on the supplied size and mode. 31385 * 31386 * The mode must always be one of the following: 31387 * <ul> 31388 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 31389 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 31390 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 31391 * </ul> 31392 * 31393 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 31394 * implementation was such that the order of arguments did not matter 31395 * and overflow in either value could impact the resulting MeasureSpec. 31396 * {@link android.widget.RelativeLayout} was affected by this bug. 31397 * Apps targeting API levels greater than 17 will get the fixed, more strict 31398 * behavior.</p> 31399 * 31400 * @param size the size of the measure specification 31401 * @param mode the mode of the measure specification 31402 * @return the measure specification based on size and mode 31403 */ makeMeasureSpec(@ntRangefrom = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode)31404 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 31405 @MeasureSpecMode int mode) { 31406 return (size & ~MODE_MASK) | (mode & MODE_MASK); 31407 } 31408 31409 /** 31410 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 31411 * will automatically get a size of 0. Older apps expect this. 31412 * 31413 * @hide internal use only for compatibility with system widgets and older apps 31414 */ 31415 @UnsupportedAppUsage makeSafeMeasureSpec(int size, int mode)31416 public static int makeSafeMeasureSpec(int size, int mode) { 31417 return makeMeasureSpec(size, mode); 31418 } 31419 31420 /** 31421 * Extracts the mode from the supplied measure specification. 31422 * 31423 * @param measureSpec the measure specification to extract the mode from 31424 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 31425 * {@link android.view.View.MeasureSpec#AT_MOST} or 31426 * {@link android.view.View.MeasureSpec#EXACTLY} 31427 */ 31428 @MeasureSpecMode getMode(int measureSpec)31429 public static int getMode(int measureSpec) { 31430 //noinspection ResourceType 31431 return (measureSpec & MODE_MASK); 31432 } 31433 31434 /** 31435 * Extracts the size from the supplied measure specification. 31436 * 31437 * @param measureSpec the measure specification to extract the size from 31438 * @return the size in pixels defined in the supplied measure specification 31439 */ getSize(int measureSpec)31440 public static int getSize(int measureSpec) { 31441 return (measureSpec & ~MODE_MASK); 31442 } 31443 adjust(int measureSpec, int delta)31444 static int adjust(int measureSpec, int delta) { 31445 final int mode = getMode(measureSpec); 31446 int size = getSize(measureSpec); 31447 if (mode == UNSPECIFIED) { 31448 // No need to adjust size for UNSPECIFIED mode. 31449 return makeMeasureSpec(size, UNSPECIFIED); 31450 } 31451 size += delta; 31452 if (size < 0) { 31453 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 31454 ") spec: " + toString(measureSpec) + " delta: " + delta); 31455 size = 0; 31456 } 31457 return makeMeasureSpec(size, mode); 31458 } 31459 31460 /** 31461 * Returns a String representation of the specified measure 31462 * specification. 31463 * 31464 * @param measureSpec the measure specification to convert to a String 31465 * @return a String with the following format: "MeasureSpec: MODE SIZE" 31466 */ toString(int measureSpec)31467 public static String toString(int measureSpec) { 31468 int mode = getMode(measureSpec); 31469 int size = getSize(measureSpec); 31470 31471 StringBuilder sb = new StringBuilder("MeasureSpec: "); 31472 31473 if (mode == UNSPECIFIED) 31474 sb.append("UNSPECIFIED "); 31475 else if (mode == EXACTLY) 31476 sb.append("EXACTLY "); 31477 else if (mode == AT_MOST) 31478 sb.append("AT_MOST "); 31479 else 31480 sb.append(mode).append(" "); 31481 31482 sb.append(size); 31483 return sb.toString(); 31484 } 31485 } 31486 31487 private final class CheckForLongPress implements Runnable { 31488 private int mOriginalWindowAttachCount; 31489 private float mX; 31490 private float mY; 31491 private boolean mOriginalPressedState; 31492 /** 31493 * The classification of the long click being checked: one of the 31494 * FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__* constants. 31495 */ 31496 private int mClassification; 31497 31498 @UnsupportedAppUsage CheckForLongPress()31499 private CheckForLongPress() { 31500 } 31501 31502 @Override run()31503 public void run() { 31504 if ((mOriginalPressedState == isPressed()) && (mParent != null) 31505 && mOriginalWindowAttachCount == mWindowAttachCount) { 31506 recordGestureClassification(mClassification); 31507 if (performLongClick(mX, mY)) { 31508 mHasPerformedLongPress = true; 31509 } 31510 } 31511 } 31512 setAnchor(float x, float y)31513 public void setAnchor(float x, float y) { 31514 mX = x; 31515 mY = y; 31516 } 31517 rememberWindowAttachCount()31518 public void rememberWindowAttachCount() { 31519 mOriginalWindowAttachCount = mWindowAttachCount; 31520 } 31521 rememberPressedState()31522 public void rememberPressedState() { 31523 mOriginalPressedState = isPressed(); 31524 } 31525 setClassification(int classification)31526 public void setClassification(int classification) { 31527 mClassification = classification; 31528 } 31529 } 31530 31531 private final class CheckForTap implements Runnable { 31532 public float x; 31533 public float y; 31534 31535 @Override run()31536 public void run() { 31537 mPrivateFlags &= ~PFLAG_PREPRESSED; 31538 setPressed(true, x, y); 31539 final long delay = 31540 ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout(); 31541 checkForLongClick(delay, x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 31542 } 31543 } 31544 31545 private final class PerformClick implements Runnable { 31546 @Override run()31547 public void run() { 31548 recordGestureClassification(TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP); 31549 performClickInternal(); 31550 } 31551 } 31552 31553 /** Records a classification for the current event stream. */ recordGestureClassification(int classification)31554 private void recordGestureClassification(int classification) { 31555 if (classification == TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION) { 31556 return; 31557 } 31558 // To avoid negatively impacting View performance, the latency and displacement metrics 31559 // are omitted. 31560 FrameworkStatsLog.write(FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED, getClass().getName(), 31561 classification); 31562 } 31563 31564 /** 31565 * This method returns a ViewPropertyAnimator object, which can be used to animate 31566 * specific properties on this View. 31567 * 31568 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 31569 */ animate()31570 public ViewPropertyAnimator animate() { 31571 if (mAnimator == null) { 31572 mAnimator = new ViewPropertyAnimator(this); 31573 } 31574 return mAnimator; 31575 } 31576 31577 /** 31578 * Sets the name of the View to be used to identify Views in Transitions. 31579 * Names should be unique in the View hierarchy. 31580 * 31581 * @param transitionName The name of the View to uniquely identify it for Transitions. 31582 */ setTransitionName(String transitionName)31583 public final void setTransitionName(String transitionName) { 31584 mTransitionName = transitionName; 31585 } 31586 31587 /** 31588 * Returns the name of the View to be used to identify Views in Transitions. 31589 * Names should be unique in the View hierarchy. 31590 * 31591 * <p>This returns null if the View has not been given a name.</p> 31592 * 31593 * @return The name used of the View to be used to identify Views in Transitions or null 31594 * if no name has been given. 31595 */ 31596 @ViewDebug.ExportedProperty 31597 @InspectableProperty getTransitionName()31598 public String getTransitionName() { 31599 return mTransitionName; 31600 } 31601 31602 /** 31603 * @hide 31604 */ requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId)31605 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 31606 // Do nothing. 31607 } 31608 31609 /** 31610 * Interface definition for a callback to be invoked when a hardware key event is 31611 * dispatched to this view. The callback will be invoked before the key event is 31612 * given to the view. This is only useful for hardware keyboards; a software input 31613 * method has no obligation to trigger this listener. 31614 */ 31615 public interface OnKeyListener { 31616 /** 31617 * Called when a hardware key is dispatched to a view. This allows listeners to 31618 * get a chance to respond before the target view. 31619 * <p>Key presses in software keyboards will generally NOT trigger this method, 31620 * although some may elect to do so in some situations. Do not assume a 31621 * software input method has to be key-based; even if it is, it may use key presses 31622 * in a different way than you expect, so there is no way to reliably catch soft 31623 * input key presses. 31624 * 31625 * @param v The view the key has been dispatched to. 31626 * @param keyCode The code for the physical key that was pressed 31627 * @param event The KeyEvent object containing full information about 31628 * the event. 31629 * @return True if the listener has consumed the event, false otherwise. 31630 */ onKey(View v, int keyCode, KeyEvent event)31631 boolean onKey(View v, int keyCode, KeyEvent event); 31632 } 31633 31634 /** 31635 * Interface definition for a callback to be invoked when a hardware key event hasn't 31636 * been handled by the view hierarchy. 31637 */ 31638 public interface OnUnhandledKeyEventListener { 31639 /** 31640 * Called when a hardware key is dispatched to a view after being unhandled during normal 31641 * {@link KeyEvent} dispatch. 31642 * 31643 * @param v The view the key has been dispatched to. 31644 * @param event The KeyEvent object containing information about the event. 31645 * @return {@code true} if the listener has consumed the event, {@code false} otherwise. 31646 */ onUnhandledKeyEvent(View v, KeyEvent event)31647 boolean onUnhandledKeyEvent(View v, KeyEvent event); 31648 } 31649 31650 /** 31651 * Interface definition for a callback to be invoked when a touch event is 31652 * dispatched to this view. The callback will be invoked before the touch 31653 * event is given to the view. 31654 */ 31655 public interface OnTouchListener { 31656 /** 31657 * Called when a touch event is dispatched to a view. This allows listeners to 31658 * get a chance to respond before the target view. 31659 * 31660 * @param v The view the touch event has been dispatched to. 31661 * @param event The MotionEvent object containing full information about 31662 * the event. 31663 * @return True if the listener has consumed the event, false otherwise. 31664 */ onTouch(View v, MotionEvent event)31665 boolean onTouch(View v, MotionEvent event); 31666 } 31667 31668 /** 31669 * Interface definition for a callback to be invoked when a hover event is 31670 * dispatched to this view. The callback will be invoked before the hover 31671 * event is given to the view. 31672 */ 31673 public interface OnHoverListener { 31674 /** 31675 * Called when a hover event is dispatched to a view. This allows listeners to 31676 * get a chance to respond before the target view. 31677 * 31678 * @param v The view the hover event has been dispatched to. 31679 * @param event The MotionEvent object containing full information about 31680 * the event. 31681 * @return True if the listener has consumed the event, false otherwise. 31682 */ onHover(View v, MotionEvent event)31683 boolean onHover(View v, MotionEvent event); 31684 } 31685 31686 /** 31687 * Interface definition for a callback to be invoked when a generic motion event is 31688 * dispatched to this view. The callback will be invoked before the generic motion 31689 * event is given to the view. 31690 */ 31691 public interface OnGenericMotionListener { 31692 /** 31693 * Called when a generic motion event is dispatched to a view. This allows listeners to 31694 * get a chance to respond before the target view. 31695 * 31696 * @param v The view the generic motion event has been dispatched to. 31697 * @param event The MotionEvent object containing full information about 31698 * the event. 31699 * @return True if the listener has consumed the event, false otherwise. 31700 */ onGenericMotion(View v, MotionEvent event)31701 boolean onGenericMotion(View v, MotionEvent event); 31702 } 31703 31704 /** 31705 * Interface definition for a callback to be invoked when a view has been clicked and held. 31706 */ 31707 public interface OnLongClickListener { 31708 /** 31709 * Called when a view has been clicked and held. 31710 * 31711 * @param v The view that was clicked and held. 31712 * 31713 * @return true if the callback consumed the long click, false otherwise. 31714 */ onLongClick(View v)31715 boolean onLongClick(View v); 31716 31717 /** 31718 * Returns whether the default {@link HapticFeedbackConstants#LONG_PRESS} haptic feedback 31719 * is performed when this listener has consumed the long click. This method is called 31720 * immediately after {@link #onLongClick} has returned true. 31721 * 31722 * @param v The view that was clicked and held. 31723 * @return true to perform the default {@link HapticFeedbackConstants#LONG_PRESS} haptic 31724 * feedback, or false if the handler manages all haptics itself. 31725 */ onLongClickUseDefaultHapticFeedback(@onNull View v)31726 default boolean onLongClickUseDefaultHapticFeedback(@NonNull View v) { 31727 return true; 31728 } 31729 } 31730 31731 /** 31732 * Interface definition for a listener that's invoked when a drag event is dispatched to this 31733 * view. The listener is invoked before the view's own 31734 * {@link #onDragEvent(DragEvent)} method. To fall back to the view's 31735 * {@code onDragEvent(DragEvent)} behavior, return {@code false} from the listener method. 31736 * 31737 * <div class="special reference"> 31738 * <h3>Developer Guides</h3> 31739 * <p>For a guide to implementing drag and drop features, see the 31740 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and drop</a> developer guide.</p> 31741 * </div> 31742 */ 31743 public interface OnDragListener { 31744 /** 31745 * Called when a drag event is dispatched to a view. Enables listeners to override the 31746 * base behavior provided by {@link #onDragEvent(DragEvent)}. 31747 * 31748 * @param v The {@code View} that received the drag event. 31749 * @param event The event object for the drag event. 31750 * @return {@code true} if the drag event was handled successfully; {@code false}, if the 31751 * drag event was not handled. <b>Note:</b> A {@code false} return value triggers the 31752 * view's {@link #onDragEvent(DragEvent)} handler. 31753 */ onDrag(View v, DragEvent event)31754 boolean onDrag(View v, DragEvent event); 31755 } 31756 31757 /** 31758 * Interface definition for a callback to be invoked when the focus state of 31759 * a view changed. 31760 */ 31761 public interface OnFocusChangeListener { 31762 /** 31763 * Called when the focus state of a view has changed. 31764 * 31765 * @param v The view whose state has changed. 31766 * @param hasFocus The new focus state of v. 31767 */ onFocusChange(View v, boolean hasFocus)31768 void onFocusChange(View v, boolean hasFocus); 31769 } 31770 31771 /** 31772 * Interface definition for a callback to be invoked when a view is clicked. 31773 */ 31774 public interface OnClickListener { 31775 /** 31776 * Called when a view has been clicked. 31777 * 31778 * @param v The view that was clicked. 31779 */ onClick(View v)31780 void onClick(View v); 31781 } 31782 31783 /** 31784 * Interface definition for a callback to be invoked when a view is context clicked. 31785 */ 31786 public interface OnContextClickListener { 31787 /** 31788 * Called when a view is context clicked. 31789 * 31790 * @param v The view that has been context clicked. 31791 * @return true if the callback consumed the context click, false otherwise. 31792 */ onContextClick(View v)31793 boolean onContextClick(View v); 31794 } 31795 31796 /** 31797 * Interface definition for a callback to be invoked when the context menu 31798 * for this view is being built. 31799 */ 31800 public interface OnCreateContextMenuListener { 31801 /** 31802 * Called when the context menu for this view is being built. It is not 31803 * safe to hold onto the menu after this method returns. 31804 * 31805 * @param menu The context menu that is being built 31806 * @param v The view for which the context menu is being built 31807 * @param menuInfo Extra information about the item for which the 31808 * context menu should be shown. This information will vary 31809 * depending on the class of v. 31810 */ onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)31811 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 31812 } 31813 31814 /** 31815 * Interface definition for a callback to be invoked when the status bar changes 31816 * visibility. This reports <strong>global</strong> changes to the system UI 31817 * state, not what the application is requesting. 31818 * 31819 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 31820 * 31821 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 31822 * by setting a {@link OnApplyWindowInsetsListener} on this view. 31823 */ 31824 @Deprecated 31825 public interface OnSystemUiVisibilityChangeListener { 31826 /** 31827 * Called when the status bar changes visibility because of a call to 31828 * {@link View#setSystemUiVisibility(int)}. 31829 * 31830 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 31831 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 31832 * This tells you the <strong>global</strong> state of these UI visibility 31833 * flags, not what your app is currently applying. 31834 */ onSystemUiVisibilityChange(int visibility)31835 public void onSystemUiVisibilityChange(int visibility); 31836 } 31837 31838 /** 31839 * Interface definition for a callback to be invoked when this view is attached 31840 * or detached from its window. 31841 */ 31842 public interface OnAttachStateChangeListener { 31843 /** 31844 * Called when the view is attached to a window. 31845 * @param v The view that was attached 31846 */ onViewAttachedToWindow(@onNull View v)31847 public void onViewAttachedToWindow(@NonNull View v); 31848 /** 31849 * Called when the view is detached from a window. 31850 * @param v The view that was detached 31851 */ onViewDetachedFromWindow(@onNull View v)31852 public void onViewDetachedFromWindow(@NonNull View v); 31853 } 31854 31855 /** 31856 * Listener for applying window insets on a view in a custom way. 31857 * 31858 * <p>Apps may choose to implement this interface if they want to apply custom policy 31859 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 31860 * is set, its 31861 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 31862 * method will be called instead of the View's own 31863 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 31864 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 31865 * the View's normal behavior as part of its own.</p> 31866 */ 31867 public interface OnApplyWindowInsetsListener { 31868 /** 31869 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 31870 * on a View, this listener method will be called instead of the view's own 31871 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 31872 * 31873 * @param v The view applying window insets 31874 * @param insets The insets to apply 31875 * @return The insets supplied, minus any insets that were consumed 31876 */ onApplyWindowInsets(@onNull View v, @NonNull WindowInsets insets)31877 public @NonNull WindowInsets onApplyWindowInsets(@NonNull View v, 31878 @NonNull WindowInsets insets); 31879 } 31880 31881 private final class UnsetPressedState implements Runnable { 31882 @Override run()31883 public void run() { 31884 setPressed(false); 31885 } 31886 } 31887 31888 /** 31889 * When a view becomes invisible checks if autofill considers the view invisible too. This 31890 * happens after the regular removal operation to make sure the operation is finished by the 31891 * time this is called. 31892 */ 31893 private static class VisibilityChangeForAutofillHandler extends Handler { 31894 private final AutofillManager mAfm; 31895 private final View mView; 31896 VisibilityChangeForAutofillHandler(@onNull AutofillManager afm, @NonNull View view)31897 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, 31898 @NonNull View view) { 31899 mAfm = afm; 31900 mView = view; 31901 } 31902 31903 @Override handleMessage(Message msg)31904 public void handleMessage(Message msg) { 31905 mAfm.notifyViewVisibilityChanged(mView, mView.isShown()); 31906 } 31907 } 31908 31909 /** 31910 * Base class for derived classes that want to save and restore their own 31911 * state in {@link android.view.View#onSaveInstanceState()}. 31912 */ 31913 public static class BaseSavedState extends AbsSavedState { 31914 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; 31915 static final int IS_AUTOFILLED = 0b10; 31916 static final int AUTOFILL_ID = 0b100; 31917 31918 // Flags that describe what data in this state is valid 31919 int mSavedData; 31920 String mStartActivityRequestWhoSaved; 31921 boolean mIsAutofilled; 31922 boolean mHideHighlight; 31923 int mAutofillViewId; 31924 31925 /** 31926 * Constructor used when reading from a parcel. Reads the state of the superclass. 31927 * 31928 * @param source parcel to read from 31929 */ BaseSavedState(Parcel source)31930 public BaseSavedState(Parcel source) { 31931 this(source, null); 31932 } 31933 31934 /** 31935 * Constructor used when reading from a parcel using a given class loader. 31936 * Reads the state of the superclass. 31937 * 31938 * @param source parcel to read from 31939 * @param loader ClassLoader to use for reading 31940 */ BaseSavedState(Parcel source, ClassLoader loader)31941 public BaseSavedState(Parcel source, ClassLoader loader) { 31942 super(source, loader); 31943 mSavedData = source.readInt(); 31944 mStartActivityRequestWhoSaved = source.readString(); 31945 mIsAutofilled = source.readBoolean(); 31946 mHideHighlight = source.readBoolean(); 31947 mAutofillViewId = source.readInt(); 31948 } 31949 31950 /** 31951 * Constructor called by derived classes when creating their SavedState objects 31952 * 31953 * @param superState The state of the superclass of this view 31954 */ BaseSavedState(Parcelable superState)31955 public BaseSavedState(Parcelable superState) { 31956 super(superState); 31957 } 31958 31959 @Override writeToParcel(Parcel out, int flags)31960 public void writeToParcel(Parcel out, int flags) { 31961 super.writeToParcel(out, flags); 31962 31963 out.writeInt(mSavedData); 31964 out.writeString(mStartActivityRequestWhoSaved); 31965 out.writeBoolean(mIsAutofilled); 31966 out.writeBoolean(mHideHighlight); 31967 out.writeInt(mAutofillViewId); 31968 } 31969 31970 public static final @android.annotation.NonNull Parcelable.Creator<BaseSavedState> CREATOR 31971 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 31972 @Override 31973 public BaseSavedState createFromParcel(Parcel in) { 31974 return new BaseSavedState(in); 31975 } 31976 31977 @Override 31978 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 31979 return new BaseSavedState(in, loader); 31980 } 31981 31982 @Override 31983 public BaseSavedState[] newArray(int size) { 31984 return new BaseSavedState[size]; 31985 } 31986 }; 31987 } 31988 31989 /** 31990 * A set of information given to a view when it is attached to its parent 31991 * window. 31992 */ 31993 final static class AttachInfo { 31994 31995 interface Callbacks { playSoundEffect(int effectId)31996 void playSoundEffect(int effectId); 31997 performHapticFeedback(int effectId, @HapticFeedbackConstants.Flags int flags, @HapticFeedbackConstants.PrivateFlags int privFlags)31998 boolean performHapticFeedback(int effectId, 31999 @HapticFeedbackConstants.Flags int flags, 32000 @HapticFeedbackConstants.PrivateFlags int privFlags); 32001 performHapticFeedbackForInputDevice(int effectId, int inputDeviceId, int inputSource, @HapticFeedbackConstants.Flags int flags, @HapticFeedbackConstants.PrivateFlags int privFlags)32002 void performHapticFeedbackForInputDevice(int effectId, 32003 int inputDeviceId, int inputSource, 32004 @HapticFeedbackConstants.Flags int flags, 32005 @HapticFeedbackConstants.PrivateFlags int privFlags); 32006 } 32007 32008 /** 32009 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 32010 * to a Handler. This class contains the target (View) to invalidate and 32011 * the coordinates of the dirty rectangle. 32012 * 32013 * For performance purposes, this class also implements a pool of up to 32014 * POOL_LIMIT objects that get reused. This reduces memory allocations 32015 * whenever possible. 32016 */ 32017 static class InvalidateInfo { 32018 32019 @UnsupportedAppUsage InvalidateInfo()32020 InvalidateInfo() { 32021 } 32022 32023 private static final int POOL_LIMIT = 10; 32024 32025 private static final SynchronizedPool<InvalidateInfo> sPool = 32026 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 32027 32028 @UnsupportedAppUsage 32029 View target; 32030 32031 @UnsupportedAppUsage 32032 int left; 32033 @UnsupportedAppUsage 32034 int top; 32035 @UnsupportedAppUsage 32036 int right; 32037 @UnsupportedAppUsage 32038 int bottom; 32039 obtain()32040 public static InvalidateInfo obtain() { 32041 InvalidateInfo instance = sPool.acquire(); 32042 return (instance != null) ? instance : new InvalidateInfo(); 32043 } 32044 recycle()32045 public void recycle() { 32046 target = null; 32047 sPool.release(this); 32048 } 32049 } 32050 32051 @UnsupportedAppUsage 32052 final IWindowSession mSession; 32053 32054 @UnsupportedAppUsage 32055 final IWindow mWindow; 32056 32057 final IBinder mWindowToken; 32058 32059 Display mDisplay; 32060 32061 final Callbacks mRootCallbacks; 32062 32063 IWindowId mIWindowId; 32064 WindowId mWindowId; 32065 32066 /** 32067 * The top view of the hierarchy. 32068 */ 32069 View mRootView; 32070 32071 IBinder mPanelParentWindowToken; 32072 32073 boolean mHardwareAccelerated; 32074 boolean mHardwareAccelerationRequested; 32075 ThreadedRenderer mThreadedRenderer; 32076 List<RenderNode> mPendingAnimatingRenderNodes; 32077 32078 /** 32079 * The state of the display to which the window is attached, as reported 32080 * by {@link Display#getState()}. Note that the display state constants 32081 * declared by {@link Display} do not exactly line up with the screen state 32082 * constants declared by {@link View} (there are more display states than 32083 * screen states). 32084 */ 32085 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 32086 int mDisplayState = Display.STATE_UNKNOWN; 32087 32088 /** 32089 * Scale factor used by the compatibility mode 32090 */ 32091 @UnsupportedAppUsage 32092 float mApplicationScale; 32093 32094 /** 32095 * Indicates whether the application is in compatibility mode 32096 */ 32097 @UnsupportedAppUsage 32098 boolean mScalingRequired; 32099 32100 /** 32101 * Left position of this view's window 32102 */ 32103 int mWindowLeft; 32104 32105 /** 32106 * Top position of this view's window 32107 */ 32108 int mWindowTop; 32109 32110 /** 32111 * Indicates whether views need to use 32-bit drawing caches 32112 */ 32113 boolean mUse32BitDrawingCache; 32114 32115 /** 32116 * For windows that are full-screen but using insets to layout inside 32117 * of the screen decorations, these are the current insets for the 32118 * content of the window. 32119 */ 32120 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 32121 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 32122 final Rect mContentInsets = new Rect(); 32123 32124 /** 32125 * For windows that are full-screen but using insets to layout inside 32126 * of the screen decorations, these are the current insets for the 32127 * actual visible parts of the window. 32128 */ 32129 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 32130 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 32131 final Rect mVisibleInsets = new Rect(); 32132 32133 /** 32134 * For windows that are full-screen but using insets to layout inside 32135 * of the screen decorations, these are the current insets for the 32136 * stable system windows. 32137 */ 32138 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 32139 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 32140 final Rect mStableInsets = new Rect(); 32141 32142 /** 32143 * Current caption insets to the display coordinate. 32144 */ 32145 final Rect mCaptionInsets = new Rect(); 32146 32147 /** 32148 * In multi-window we force show the system bars. Because we don't want that the surface 32149 * size changes in this mode, we instead have a flag whether the system bars sizes should 32150 * always be consumed, so the app is treated like there are no virtual system bars at all. 32151 */ 32152 boolean mAlwaysConsumeSystemBars; 32153 32154 /** 32155 * The internal insets given by this window. This value is 32156 * supplied by the client (through 32157 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 32158 * be given to the window manager when changed to be used in laying 32159 * out windows behind it. 32160 */ 32161 @UnsupportedAppUsage 32162 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 32163 = new ViewTreeObserver.InternalInsetsInfo(); 32164 32165 /** 32166 * Set to true when mGivenInternalInsets is non-empty. 32167 */ 32168 boolean mHasNonEmptyGivenInternalInsets; 32169 32170 /** 32171 * All views in the window's hierarchy that serve as scroll containers, 32172 * used to determine if the window can be resized or must be panned 32173 * to adjust for a soft input area. 32174 */ 32175 @UnsupportedAppUsage 32176 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 32177 32178 @UnsupportedAppUsage 32179 final KeyEvent.DispatcherState mKeyDispatchState 32180 = new KeyEvent.DispatcherState(); 32181 32182 /** 32183 * Indicates whether the view's window currently has the focus. 32184 */ 32185 @UnsupportedAppUsage 32186 boolean mHasWindowFocus; 32187 32188 /** 32189 * The current visibility of the window. 32190 */ 32191 int mWindowVisibility; 32192 32193 /** 32194 * Indicates the time at which drawing started to occur. 32195 */ 32196 @UnsupportedAppUsage 32197 long mDrawingTime; 32198 32199 /** 32200 * Indicates whether the view's window is currently in touch mode. 32201 */ 32202 @UnsupportedAppUsage 32203 boolean mInTouchMode; 32204 32205 /** 32206 * Indicates whether the view has requested unbuffered input dispatching for the current 32207 * event stream. 32208 */ 32209 boolean mUnbufferedDispatchRequested; 32210 32211 /** 32212 * Indicates that ViewAncestor should trigger a global layout change 32213 * the next time it performs a traversal 32214 */ 32215 @UnsupportedAppUsage 32216 boolean mRecomputeGlobalAttributes; 32217 32218 /** 32219 * Always report new attributes at next traversal. 32220 */ 32221 boolean mForceReportNewAttributes; 32222 32223 /** 32224 * Set during a traveral if any views want to keep the screen on. 32225 */ 32226 @UnsupportedAppUsage 32227 boolean mKeepScreenOn; 32228 32229 /** 32230 * Set during a traveral if the light center needs to be updated. 32231 */ 32232 boolean mNeedsUpdateLightCenter; 32233 32234 /** 32235 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 32236 */ 32237 int mSystemUiVisibility; 32238 32239 /** 32240 * Hack to force certain system UI visibility flags to be cleared. 32241 */ 32242 int mDisabledSystemUiVisibility; 32243 32244 /** 32245 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 32246 * attached. 32247 */ 32248 boolean mHasSystemUiListeners; 32249 32250 /** 32251 * Set if the visibility of any views has changed. 32252 */ 32253 @UnsupportedAppUsage 32254 boolean mViewVisibilityChanged; 32255 32256 /** 32257 * Set to true if a view has been scrolled. 32258 */ 32259 @UnsupportedAppUsage 32260 boolean mViewScrollChanged; 32261 32262 /** 32263 * Set to true if a pointer event is currently being handled. 32264 */ 32265 boolean mHandlingPointerEvent; 32266 32267 /** 32268 * The window matrix of this view when it's on a {@link SurfaceControlViewHost} that is 32269 * embedded within a SurfaceView. 32270 */ 32271 Matrix mWindowMatrixInEmbeddedHierarchy; 32272 32273 /** 32274 * Global to the view hierarchy used as a temporary for dealing with 32275 * x/y points in the transparent region computations. 32276 */ 32277 final int[] mTransparentLocation = new int[2]; 32278 32279 /** 32280 * Global to the view hierarchy used as a temporary for dealing with 32281 * x/y points in the ViewGroup.invalidateChild implementation. 32282 */ 32283 final int[] mInvalidateChildLocation = new int[2]; 32284 32285 /** 32286 * Global to the view hierarchy used as a temporary for dealing with 32287 * computing absolute on-screen location. 32288 */ 32289 final int[] mTmpLocation = new int[2]; 32290 32291 /** 32292 * Global to the view hierarchy used as a temporary for dealing with 32293 * x/y location when view is transformed. 32294 */ 32295 final float[] mTmpTransformLocation = new float[2]; 32296 32297 /** 32298 * The view tree observer used to dispatch global events like 32299 * layout, pre-draw, touch mode change, etc. 32300 */ 32301 @UnsupportedAppUsage 32302 final ViewTreeObserver mTreeObserver; 32303 32304 /** 32305 * A Canvas used by the view hierarchy to perform bitmap caching. 32306 */ 32307 Canvas mCanvas; 32308 32309 /** 32310 * The view root impl. 32311 */ 32312 final ViewRootImpl mViewRootImpl; 32313 32314 /** 32315 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 32316 * handler can be used to pump events in the UI events queue. 32317 */ 32318 @UnsupportedAppUsage 32319 final Handler mHandler; 32320 32321 /** 32322 * Temporary for use in computing invalidate rectangles while 32323 * calling up the hierarchy. 32324 */ 32325 final Rect mTmpInvalRect = new Rect(); 32326 32327 /** 32328 * Temporary for use in computing hit areas with transformed views 32329 */ 32330 final RectF mTmpTransformRect = new RectF(); 32331 32332 /** 32333 * Temporary for use in computing hit areas with transformed views 32334 */ 32335 final RectF mTmpTransformRect1 = new RectF(); 32336 32337 /** 32338 * Temporary list of rectanges. 32339 */ 32340 final List<RectF> mTmpRectList = new ArrayList<>(); 32341 32342 /** 32343 * Temporary for use in transforming invalidation rect 32344 */ 32345 final Matrix mTmpMatrix = new Matrix(); 32346 32347 /** 32348 * Temporary for use in transforming invalidation rect 32349 */ 32350 final Transformation mTmpTransformation = new Transformation(); 32351 32352 /** 32353 * Temporary for use in querying outlines from OutlineProviders 32354 */ 32355 final Outline mTmpOutline = new Outline(); 32356 32357 /** 32358 * Temporary list for use in collecting focusable descendents of a view. 32359 */ 32360 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 32361 32362 /** 32363 * Indicates if the next focus will be looped back to the first focusable view of the entire 32364 * hierarchy when finding in the direction of {@link #FOCUS_FORWARD} or to the last 32365 * focusable view when finding in the direction of {@link #FOCUS_BACKWARD}. 32366 */ 32367 boolean mNextFocusLooped = false; 32368 32369 /** 32370 * The id of the window for accessibility purposes. 32371 */ 32372 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 32373 32374 /** 32375 * Flags related to accessibility processing. 32376 * 32377 * @see AccessibilityNodeInfo#FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS 32378 * @see AccessibilityNodeInfo#FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS 32379 */ 32380 int mAccessibilityFetchFlags; 32381 32382 /** 32383 * The drawable for highlighting accessibility focus. 32384 */ 32385 Drawable mAccessibilityFocusDrawable; 32386 32387 /** 32388 * The drawable for highlighting autofilled views. 32389 * 32390 * @see #isAutofilled() 32391 */ 32392 Drawable mAutofilledDrawable; 32393 32394 /** 32395 * Show where the margins, bounds and layout bounds are for each view. 32396 */ 32397 boolean mDebugLayout = DisplayProperties.debug_layout().orElse(false); 32398 32399 /** 32400 * Point used to compute visible regions. 32401 */ 32402 final Point mPoint = new Point(); 32403 32404 /** 32405 * Used to track which View originated a requestLayout() call, used when 32406 * requestLayout() is called during layout. 32407 */ 32408 View mViewRequestingLayout; 32409 32410 /** 32411 * Used to track the identity of the current drag operation. 32412 */ 32413 IBinder mDragToken; 32414 32415 /** 32416 * Used to track the data of the current drag operation for cleanup later. 32417 */ 32418 ClipData mDragData; 32419 32420 /** 32421 * The drag shadow surface for the current drag operation. 32422 */ 32423 public Surface mDragSurface; 32424 32425 /** 32426 * The view that currently has a tooltip displayed. 32427 */ 32428 View mTooltipHost; 32429 32430 /** 32431 * The initial structure has been reported so the view is ready to report updates. 32432 */ 32433 boolean mReadyForContentCaptureUpdates; 32434 32435 /** 32436 * Map(keyed by session) of content capture events that need to be notified after the view 32437 * hierarchy is traversed: value is either the view itself for appearead events, or its 32438 * autofill id for disappeared. 32439 */ 32440 SparseArray<ArrayList<Object>> mContentCaptureEvents; 32441 32442 /** 32443 * Cached reference to the {@link ContentCaptureManager}. 32444 */ 32445 ContentCaptureManager mContentCaptureManager; 32446 32447 /** 32448 * Listener used to fit content on window level. 32449 */ 32450 OnContentApplyWindowInsetsListener mContentOnApplyWindowInsetsListener; 32451 32452 /** 32453 * The leash token of this view's parent when it's in an embedded hierarchy that is 32454 * re-parented to another window. 32455 */ 32456 IBinder mLeashedParentToken; 32457 32458 /** 32459 * The accessibility view id of this view's parent when it's in an embedded 32460 * hierarchy that is re-parented to another window. 32461 */ 32462 int mLeashedParentAccessibilityViewId; 32463 32464 /** 32465 * 32466 */ 32467 ScrollCaptureInternal mScrollCaptureInternal; 32468 32469 /** 32470 * sensitive views attached to the window 32471 */ 32472 int mSensitiveViewsCount; 32473 32474 /** 32475 * The value of viewVelocityApi(), read only once per ViewRootImpl 32476 */ 32477 final boolean mViewVelocityApi = viewVelocityApi(); 32478 32479 /** 32480 * Density so that it doesn't need to be retrieved on every invalidation. 32481 */ 32482 final float mDensity; 32483 32484 /** 32485 * The number of pixels in the display (width * height). 32486 */ 32487 final float mDisplayPixelCount; 32488 32489 /** 32490 * Creates a new set of attachment information with the specified 32491 * events handler and thread. 32492 * 32493 * @param handler the events handler the view must use 32494 */ AttachInfo(IWindowSession session, IWindow window, Display display, ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, Context context)32495 AttachInfo(IWindowSession session, IWindow window, Display display, 32496 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 32497 Context context) { 32498 mSession = session; 32499 mWindow = window; 32500 mWindowToken = window.asBinder(); 32501 mDisplay = display; 32502 mViewRootImpl = viewRootImpl; 32503 mHandler = handler; 32504 mRootCallbacks = effectPlayer; 32505 mTreeObserver = new ViewTreeObserver(context); 32506 DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); 32507 mDensity = displayMetrics.density; 32508 float pixelCount = (float) displayMetrics.widthPixels * displayMetrics.heightPixels; 32509 mDisplayPixelCount = pixelCount == 0f ? Float.POSITIVE_INFINITY : pixelCount; 32510 } 32511 increaseSensitiveViewsCount()32512 void increaseSensitiveViewsCount() { 32513 if (mSensitiveViewsCount == 0) { 32514 mViewRootImpl.addSensitiveContentAppProtection(); 32515 } 32516 mSensitiveViewsCount++; 32517 } 32518 decreaseSensitiveViewsCount()32519 void decreaseSensitiveViewsCount() { 32520 mSensitiveViewsCount--; 32521 if (mSensitiveViewsCount == 0) { 32522 mViewRootImpl.removeSensitiveContentAppProtection(); 32523 } 32524 if (mSensitiveViewsCount < 0) { 32525 Log.wtf(VIEW_LOG_TAG, "mSensitiveViewsCount is negative" + mSensitiveViewsCount); 32526 mSensitiveViewsCount = 0; 32527 } 32528 } 32529 32530 @Nullable getContentCaptureManager(@onNull Context context)32531 ContentCaptureManager getContentCaptureManager(@NonNull Context context) { 32532 if (mContentCaptureManager != null) { 32533 return mContentCaptureManager; 32534 } 32535 mContentCaptureManager = context.getSystemService(ContentCaptureManager.class); 32536 return mContentCaptureManager; 32537 } 32538 delayNotifyContentCaptureInsetsEvent(@onNull Insets insets)32539 void delayNotifyContentCaptureInsetsEvent(@NonNull Insets insets) { 32540 if (mContentCaptureManager == null) { 32541 return; 32542 } 32543 32544 ArrayList<Object> events = ensureEvents( 32545 mContentCaptureManager.getMainContentCaptureSession()); 32546 events.add(insets); 32547 } 32548 delayNotifyContentCaptureEvent(@onNull ContentCaptureSession session, @NonNull View view, boolean appeared)32549 private void delayNotifyContentCaptureEvent(@NonNull ContentCaptureSession session, 32550 @NonNull View view, boolean appeared) { 32551 ArrayList<Object> events = ensureEvents(session); 32552 events.add(appeared ? view : view.getAutofillId()); 32553 } 32554 32555 @NonNull ensureEvents(@onNull ContentCaptureSession session)32556 private ArrayList<Object> ensureEvents(@NonNull ContentCaptureSession session) { 32557 if (mContentCaptureEvents == null) { 32558 // Most of the time there will be just one session, so intial capacity is 1 32559 mContentCaptureEvents = new SparseArray<>(1); 32560 } 32561 int sessionId = session.getId(); 32562 // TODO: life would be much easier if we provided a MultiMap implementation somwhere... 32563 ArrayList<Object> events = mContentCaptureEvents.get(sessionId); 32564 if (events == null) { 32565 events = new ArrayList<>(); 32566 mContentCaptureEvents.put(sessionId, events); 32567 } 32568 32569 return events; 32570 } 32571 32572 @Nullable getScrollCaptureInternal()32573 ScrollCaptureInternal getScrollCaptureInternal() { 32574 if (mScrollCaptureInternal != null) { 32575 mScrollCaptureInternal = new ScrollCaptureInternal(); 32576 } 32577 return mScrollCaptureInternal; 32578 } 32579 getRootSurfaceControl()32580 AttachedSurfaceControl getRootSurfaceControl() { 32581 return mViewRootImpl; 32582 } 32583 dump(String prefix, PrintWriter writer)32584 public void dump(String prefix, PrintWriter writer) { 32585 String innerPrefix = prefix + " "; 32586 writer.println(prefix + "AttachInfo:"); 32587 writer.println(innerPrefix + "mHasWindowFocus=" + mHasWindowFocus); 32588 writer.println(innerPrefix + "mWindowVisibility=" + mWindowVisibility); 32589 writer.println(innerPrefix + "mInTouchMode=" + mInTouchMode); 32590 writer.println(innerPrefix + "mUnbufferedDispatchRequested=" 32591 + mUnbufferedDispatchRequested); 32592 } 32593 } 32594 32595 /** 32596 * <p>ScrollabilityCache holds various fields used by a View when scrolling 32597 * is supported. This avoids keeping too many unused fields in most 32598 * instances of View.</p> 32599 */ 32600 private static class ScrollabilityCache implements Runnable { 32601 32602 /** 32603 * Scrollbars are not visible 32604 */ 32605 public static final int OFF = 0; 32606 32607 /** 32608 * Scrollbars are visible 32609 */ 32610 public static final int ON = 1; 32611 32612 /** 32613 * Scrollbars are fading away 32614 */ 32615 public static final int FADING = 2; 32616 32617 public boolean fadeScrollBars; 32618 32619 public int fadingEdgeLength; 32620 public int scrollBarDefaultDelayBeforeFade; 32621 public int scrollBarFadeDuration; 32622 32623 public int scrollBarSize; 32624 public int scrollBarMinTouchTarget; 32625 @UnsupportedAppUsage 32626 public ScrollBarDrawable scrollBar; 32627 public float[] interpolatorValues; 32628 @UnsupportedAppUsage 32629 public View host; 32630 32631 public final Paint paint; 32632 public final Matrix matrix; 32633 public Shader shader; 32634 32635 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 32636 32637 private static final float[] OPAQUE = { 255 }; 32638 private static final float[] TRANSPARENT = { 0.0f }; 32639 32640 /** 32641 * When fading should start. This time moves into the future every time 32642 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 32643 */ 32644 public long fadeStartTime; 32645 32646 32647 /** 32648 * The current state of the scrollbars: ON, OFF, or FADING 32649 */ 32650 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 32651 public int state = OFF; 32652 32653 private int mLastColor; 32654 32655 public final Rect mScrollBarBounds = new Rect(); 32656 public final Rect mScrollBarTouchBounds = new Rect(); 32657 32658 public static final int NOT_DRAGGING = 0; 32659 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 32660 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 32661 public int mScrollBarDraggingState = NOT_DRAGGING; 32662 32663 public float mScrollBarDraggingPos = 0; 32664 ScrollabilityCache(ViewConfiguration configuration, View host)32665 public ScrollabilityCache(ViewConfiguration configuration, View host) { 32666 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 32667 scrollBarSize = configuration.getScaledScrollBarSize(); 32668 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 32669 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 32670 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 32671 32672 paint = new Paint(); 32673 matrix = new Matrix(); 32674 // use use a height of 1, and then wack the matrix each time we 32675 // actually use it. 32676 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 32677 paint.setShader(shader); 32678 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 32679 32680 this.host = host; 32681 } 32682 setFadeColor(int color)32683 public void setFadeColor(int color) { 32684 if (color != mLastColor) { 32685 mLastColor = color; 32686 32687 if (color != 0) { 32688 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 32689 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 32690 paint.setShader(shader); 32691 // Restore the default transfer mode (src_over) 32692 paint.setXfermode(null); 32693 } else { 32694 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 32695 paint.setShader(shader); 32696 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 32697 } 32698 } 32699 } 32700 run()32701 public void run() { 32702 long now = AnimationUtils.currentAnimationTimeMillis(); 32703 if (now >= fadeStartTime) { 32704 32705 // the animation fades the scrollbars out by changing 32706 // the opacity (alpha) from fully opaque to fully 32707 // transparent 32708 int nextFrame = (int) now; 32709 int framesCount = 0; 32710 32711 Interpolator interpolator = scrollBarInterpolator; 32712 32713 // Start opaque 32714 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 32715 32716 // End transparent 32717 nextFrame += scrollBarFadeDuration; 32718 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 32719 32720 state = FADING; 32721 32722 // Kick off the fade animation 32723 host.invalidate(true); 32724 } 32725 } 32726 } 32727 32728 private class SendAccessibilityEventThrottle implements Runnable { 32729 public volatile boolean mIsPending; 32730 private AccessibilityEvent mAccessibilityEvent; 32731 post(AccessibilityEvent accessibilityEvent)32732 public void post(AccessibilityEvent accessibilityEvent) { 32733 updateWithAccessibilityEvent(accessibilityEvent); 32734 if (!mIsPending) { 32735 mIsPending = true; 32736 postDelayed(this, 32737 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 32738 } 32739 } 32740 32741 @Override run()32742 public void run() { 32743 if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) { 32744 requestParentSendAccessibilityEvent(mAccessibilityEvent); 32745 } 32746 reset(); 32747 } 32748 updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent)32749 public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { 32750 mAccessibilityEvent = accessibilityEvent; 32751 } 32752 reset()32753 public void reset() { 32754 mIsPending = false; 32755 mAccessibilityEvent = null; 32756 } 32757 32758 } 32759 32760 /** 32761 * Resuable callback for sending 32762 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 32763 */ 32764 private class SendViewScrolledAccessibilityEvent extends SendAccessibilityEventThrottle { 32765 public int mDeltaX; 32766 public int mDeltaY; 32767 32768 @Override updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent)32769 public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { 32770 super.updateWithAccessibilityEvent(accessibilityEvent); 32771 mDeltaX += accessibilityEvent.getScrollDeltaX(); 32772 mDeltaY += accessibilityEvent.getScrollDeltaY(); 32773 accessibilityEvent.setScrollDeltaX(mDeltaX); 32774 accessibilityEvent.setScrollDeltaY(mDeltaY); 32775 } 32776 32777 @Override reset()32778 public void reset() { 32779 super.reset(); 32780 mDeltaX = 0; 32781 mDeltaY = 0; 32782 } 32783 } 32784 /** 32785 * Remove the pending callback for sending a throttled accessibility event. 32786 */ 32787 @UnsupportedAppUsage cancel(@ullable SendAccessibilityEventThrottle callback)32788 private void cancel(@Nullable SendAccessibilityEventThrottle callback) { 32789 if (callback == null || !callback.mIsPending) return; 32790 removeCallbacks(callback); 32791 callback.reset(); 32792 } 32793 32794 /** 32795 * <p> 32796 * This class represents a delegate that can be registered in a {@link View} 32797 * to enhance accessibility support via composition rather via inheritance. 32798 * It is specifically targeted to widget developers that extend basic View 32799 * classes i.e. classes in package android.view, that would like their 32800 * applications to be backwards compatible. 32801 * </p> 32802 * <div class="special reference"> 32803 * <h3>Developer Guides</h3> 32804 * <p>For more information about making applications accessible, read the 32805 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 32806 * developer guide.</p> 32807 * </div> 32808 * <p> 32809 * A scenario in which a developer would like to use an accessibility delegate 32810 * is overriding a method introduced in a later API version than the minimal API 32811 * version supported by the application. For example, the method 32812 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 32813 * in API version 4 when the accessibility APIs were first introduced. If a 32814 * developer would like their application to run on API version 4 devices (assuming 32815 * all other APIs used by the application are version 4 or lower) and take advantage 32816 * of this method, instead of overriding the method which would break the application's 32817 * backwards compatibility, they can override the corresponding method in this 32818 * delegate and register the delegate in the target View if the API version of 32819 * the system is high enough, i.e. the API version is the same as or higher than the API 32820 * version that introduced 32821 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 32822 * </p> 32823 * <p> 32824 * Here is an example implementation: 32825 * </p> 32826 * <code><pre><p> 32827 * if (Build.VERSION.SDK_INT >= 14) { 32828 * // If the API version is equal of higher than the version in 32829 * // which onInitializeAccessibilityNodeInfo was introduced we 32830 * // register a delegate with a customized implementation. 32831 * View view = findViewById(R.id.view_id); 32832 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 32833 * public void onInitializeAccessibilityNodeInfo(View host, 32834 * AccessibilityNodeInfo info) { 32835 * // Let the default implementation populate the info. 32836 * super.onInitializeAccessibilityNodeInfo(host, info); 32837 * // Set some other information. 32838 * info.setEnabled(host.isEnabled()); 32839 * } 32840 * }); 32841 * } 32842 * </code></pre></p> 32843 * <p> 32844 * This delegate contains methods that correspond to the accessibility methods 32845 * in View. If a delegate has been specified the implementation in View hands 32846 * off handling to the corresponding method in this delegate. The default 32847 * implementation the delegate methods behaves exactly as the corresponding 32848 * method in View for the case of no accessibility delegate been set. Hence, 32849 * to customize the behavior of a View method, clients can override only the 32850 * corresponding delegate method without altering the behavior of the rest 32851 * accessibility related methods of the host view. 32852 * </p> 32853 * <p> 32854 * <strong>Note:</strong> On platform versions prior to 32855 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 32856 * views in the {@code android.widget.*} package are called <i>before</i> 32857 * host methods. This prevents certain properties such as class name from 32858 * being modified by overriding 32859 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 32860 * as any changes will be overwritten by the host class. 32861 * <p> 32862 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 32863 * methods are called <i>after</i> host methods, which all properties to be 32864 * modified without being overwritten by the host class. 32865 * <aside class="note"> 32866 * <b>Note:</b> Use a {@link androidx.core.view.AccessibilityDelegateCompat} 32867 * wrapper instead of this class for backwards-compatibility. 32868 * </aside> 32869 * 32870 */ 32871 public static class AccessibilityDelegate { 32872 32873 /** 32874 * Sends an accessibility event of the given type. If accessibility is not 32875 * enabled this method has no effect. 32876 * <p> 32877 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 32878 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 32879 * been set. 32880 * </p> 32881 * 32882 * @param host The View hosting the delegate. 32883 * @param eventType The type of the event to send. 32884 * 32885 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 32886 */ sendAccessibilityEvent(@onNull View host, int eventType)32887 public void sendAccessibilityEvent(@NonNull View host, int eventType) { 32888 host.sendAccessibilityEventInternal(eventType); 32889 } 32890 32891 /** 32892 * Performs the specified accessibility action on the view. For 32893 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 32894 * <p> 32895 * The default implementation behaves as 32896 * {@link View#performAccessibilityAction(int, Bundle) 32897 * View#performAccessibilityAction(int, Bundle)} for the case of 32898 * no accessibility delegate been set. 32899 * </p> 32900 * 32901 * @param action The action to perform. 32902 * @return Whether the action was performed. 32903 * 32904 * @see View#performAccessibilityAction(int, Bundle) 32905 * View#performAccessibilityAction(int, Bundle) 32906 */ performAccessibilityAction(@onNull View host, int action, @Nullable Bundle args)32907 public boolean performAccessibilityAction(@NonNull View host, int action, 32908 @Nullable Bundle args) { 32909 return host.performAccessibilityActionInternal(action, args); 32910 } 32911 32912 /** 32913 * Sends an accessibility event. This method behaves exactly as 32914 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 32915 * empty {@link AccessibilityEvent} and does not perform a check whether 32916 * accessibility is enabled. 32917 * <p> 32918 * The default implementation behaves as 32919 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 32920 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 32921 * the case of no accessibility delegate been set. 32922 * </p> 32923 * 32924 * @param host The View hosting the delegate. 32925 * @param event The event to send. 32926 * 32927 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 32928 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 32929 */ sendAccessibilityEventUnchecked(@onNull View host, @NonNull AccessibilityEvent event)32930 public void sendAccessibilityEventUnchecked(@NonNull View host, 32931 @NonNull AccessibilityEvent event) { 32932 host.sendAccessibilityEventUncheckedInternal(event); 32933 } 32934 32935 /** 32936 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 32937 * to its children for adding their text content to the event. 32938 * <p> 32939 * The default implementation behaves as 32940 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 32941 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 32942 * the case of no accessibility delegate been set. 32943 * </p> 32944 * 32945 * @param host The View hosting the delegate. 32946 * @param event The event. 32947 * @return True if the event population was completed. 32948 * 32949 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 32950 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 32951 */ dispatchPopulateAccessibilityEvent(@onNull View host, @NonNull AccessibilityEvent event)32952 public boolean dispatchPopulateAccessibilityEvent(@NonNull View host, 32953 @NonNull AccessibilityEvent event) { 32954 return host.dispatchPopulateAccessibilityEventInternal(event); 32955 } 32956 32957 /** 32958 * Gives a chance to the host View to populate the accessibility event with its 32959 * text content. 32960 * <p> 32961 * The default implementation behaves as 32962 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 32963 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 32964 * the case of no accessibility delegate been set. 32965 * </p> 32966 * 32967 * @param host The View hosting the delegate. 32968 * @param event The accessibility event which to populate. 32969 * 32970 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 32971 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 32972 */ onPopulateAccessibilityEvent(@onNull View host, @NonNull AccessibilityEvent event)32973 public void onPopulateAccessibilityEvent(@NonNull View host, 32974 @NonNull AccessibilityEvent event) { 32975 host.onPopulateAccessibilityEventInternal(event); 32976 } 32977 32978 /** 32979 * Initializes an {@link AccessibilityEvent} with information about the 32980 * the host View which is the event source. 32981 * <p> 32982 * The default implementation behaves as 32983 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 32984 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 32985 * the case of no accessibility delegate been set. 32986 * </p> 32987 * 32988 * @param host The View hosting the delegate. 32989 * @param event The event to initialize. 32990 * 32991 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 32992 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 32993 */ onInitializeAccessibilityEvent(@onNull View host, @NonNull AccessibilityEvent event)32994 public void onInitializeAccessibilityEvent(@NonNull View host, 32995 @NonNull AccessibilityEvent event) { 32996 host.onInitializeAccessibilityEventInternal(event); 32997 } 32998 32999 /** 33000 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 33001 * <p> 33002 * The default implementation behaves as 33003 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 33004 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 33005 * the case of no accessibility delegate been set. 33006 * </p> 33007 * 33008 * @param host The View hosting the delegate. 33009 * @param info The instance to initialize. 33010 * 33011 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 33012 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 33013 */ onInitializeAccessibilityNodeInfo(@onNull View host, @NonNull AccessibilityNodeInfo info)33014 public void onInitializeAccessibilityNodeInfo(@NonNull View host, 33015 @NonNull AccessibilityNodeInfo info) { 33016 host.onInitializeAccessibilityNodeInfoInternal(info); 33017 } 33018 33019 /** 33020 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 33021 * additional data. 33022 * <p> 33023 * This method only needs to be implemented if the View offers to provide additional data. 33024 * </p> 33025 * <p> 33026 * The default implementation behaves as 33027 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle) 33028 * for the case where no accessibility delegate is set. 33029 * </p> 33030 * 33031 * @param host The View hosting the delegate. Never {@code null}. 33032 * @param info The info to which to add the extra data. Never {@code null}. 33033 * @param extraDataKey A key specifying the type of extra data to add to the info. The 33034 * extra data should be added to the {@link Bundle} returned by 33035 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 33036 * {@code null}. 33037 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 33038 * May be {@code null} if the if the service provided no arguments. 33039 * 33040 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 33041 */ addExtraDataToAccessibilityNodeInfo(@onNull View host, @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, @Nullable Bundle arguments)33042 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 33043 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 33044 @Nullable Bundle arguments) { 33045 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 33046 } 33047 33048 /** 33049 * Called when a child of the host View has requested sending an 33050 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 33051 * to augment the event. 33052 * <p> 33053 * The default implementation behaves as 33054 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 33055 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 33056 * the case of no accessibility delegate been set. 33057 * </p> 33058 * 33059 * @param host The View hosting the delegate. 33060 * @param child The child which requests sending the event. 33061 * @param event The event to be sent. 33062 * @return True if the event should be sent 33063 * 33064 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 33065 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 33066 */ onRequestSendAccessibilityEvent(@onNull ViewGroup host, @NonNull View child, @NonNull AccessibilityEvent event)33067 public boolean onRequestSendAccessibilityEvent(@NonNull ViewGroup host, @NonNull View child, 33068 @NonNull AccessibilityEvent event) { 33069 return host.onRequestSendAccessibilityEventInternal(child, event); 33070 } 33071 33072 /** 33073 * Gets the provider for managing a virtual view hierarchy rooted at this View 33074 * and reported to {@link android.accessibilityservice.AccessibilityService}s 33075 * that explore the window content. 33076 * <p> 33077 * The default implementation behaves as 33078 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 33079 * the case of no accessibility delegate been set. 33080 * </p> 33081 * 33082 * @return The provider. 33083 * 33084 * @see AccessibilityNodeProvider 33085 */ getAccessibilityNodeProvider( @onNull View host)33086 public @Nullable AccessibilityNodeProvider getAccessibilityNodeProvider( 33087 @NonNull View host) { 33088 return null; 33089 } 33090 33091 /** 33092 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 33093 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 33094 * This method is responsible for obtaining an accessibility node info from a 33095 * pool of reusable instances and calling 33096 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 33097 * view to initialize the former. 33098 * <p> 33099 * <strong>Note:</strong> The client is responsible for recycling the obtained 33100 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 33101 * creation. 33102 * </p> 33103 * <p> 33104 * The default implementation behaves as 33105 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 33106 * the case of no accessibility delegate been set. 33107 * </p> 33108 * @return A populated {@link AccessibilityNodeInfo}. 33109 * 33110 * @see AccessibilityNodeInfo 33111 * 33112 * @hide 33113 */ 33114 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) createAccessibilityNodeInfo(@onNull View host)33115 public AccessibilityNodeInfo createAccessibilityNodeInfo(@NonNull View host) { 33116 return host.createAccessibilityNodeInfoInternal(); 33117 } 33118 } 33119 33120 private static class MatchIdPredicate implements Predicate<View> { 33121 public int mId; 33122 33123 @Override test(View view)33124 public boolean test(View view) { 33125 return (view.mID == mId); 33126 } 33127 } 33128 33129 private static class MatchLabelForPredicate implements Predicate<View> { 33130 private int mLabeledId; 33131 33132 @Override test(View view)33133 public boolean test(View view) { 33134 return (view.mLabelForId == mLabeledId); 33135 } 33136 } 33137 33138 private static class SensitiveAutofillHintsHelper { 33139 /** 33140 * List of autofill hints deemed sensitive for screen protection during screen share. 33141 */ 33142 private static final ArraySet<String> SENSITIVE_CONTENT_AUTOFILL_HINTS = new ArraySet<>(); 33143 static { 33144 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_USERNAME); 33145 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_PASSWORD_AUTO); 33146 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_PASSWORD); 33147 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_NUMBER); 33148 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE); 33149 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE); 33150 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY); 33151 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH); 33152 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR); 33153 SENSITIVE_CONTENT_AUTOFILL_HINTS.add(View.AUTOFILL_HINT_CREDENTIAL_MANAGER); 33154 } 33155 33156 /** 33157 * Whether View's autofill hints contains a sensitive autofill hint. 33158 * 33159 * @see #SENSITIVE_CONTENT_AUTOFILL_HINTS 33160 */ containsSensitiveAutofillHint(@ullable String[] autofillHints)33161 static boolean containsSensitiveAutofillHint(@Nullable String[] autofillHints) { 33162 if (autofillHints == null) { 33163 return false; 33164 } 33165 33166 int size = autofillHints.length; 33167 for (int i = 0; i < size; i++) { 33168 if (SENSITIVE_CONTENT_AUTOFILL_HINTS.contains(autofillHints[i])) { 33169 return true; 33170 } 33171 } 33172 return false; 33173 } 33174 } 33175 33176 /** 33177 * Returns the current scroll capture hint for this view. 33178 * 33179 * @return the current scroll capture hint 33180 */ 33181 @ScrollCaptureHint getScrollCaptureHint()33182 public int getScrollCaptureHint() { 33183 return (mPrivateFlags4 & PFLAG4_SCROLL_CAPTURE_HINT_MASK) 33184 >> PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; 33185 } 33186 33187 /** 33188 * Sets the scroll capture hint for this View. These flags affect the search for a potential 33189 * scroll capture targets. 33190 * 33191 * @param hint the scrollCaptureHint flags value to set 33192 */ setScrollCaptureHint(@crollCaptureHint int hint)33193 public void setScrollCaptureHint(@ScrollCaptureHint int hint) { 33194 mPrivateFlags4 &= ~PFLAG4_SCROLL_CAPTURE_HINT_MASK; 33195 // Since include/exclude are mutually exclusive, exclude takes precedence. 33196 if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) { 33197 hint &= ~SCROLL_CAPTURE_HINT_INCLUDE; 33198 } 33199 mPrivateFlags4 |= ((hint << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT) 33200 & PFLAG4_SCROLL_CAPTURE_HINT_MASK); 33201 } 33202 33203 /** 33204 * Sets the callback to receive scroll capture requests. This component is the adapter between 33205 * the scroll capture API and application UI code. If no callback is set, the system may provide 33206 * an implementation. Any value provided here will take precedence over a system version. 33207 * <p> 33208 * This view will be ignored when {@link #SCROLL_CAPTURE_HINT_EXCLUDE} is set in its {@link 33209 * #setScrollCaptureHint(int) scrollCaptureHint}, regardless whether a callback has been set. 33210 * <p> 33211 * It is recommended to set the scroll capture hint {@link #SCROLL_CAPTURE_HINT_INCLUDE} when 33212 * setting a custom callback to help ensure it is selected as the target. 33213 * 33214 * @param callback the new callback to assign 33215 */ setScrollCaptureCallback(@ullable ScrollCaptureCallback callback)33216 public final void setScrollCaptureCallback(@Nullable ScrollCaptureCallback callback) { 33217 getListenerInfo().mScrollCaptureCallback = callback; 33218 } 33219 33220 /** {@hide} */ 33221 @Nullable createScrollCaptureCallbackInternal(@onNull Rect localVisibleRect, @NonNull Point windowOffset)33222 public ScrollCaptureCallback createScrollCaptureCallbackInternal(@NonNull Rect localVisibleRect, 33223 @NonNull Point windowOffset) { 33224 if (mAttachInfo == null) { 33225 return null; 33226 } 33227 if (mAttachInfo.mScrollCaptureInternal == null) { 33228 mAttachInfo.mScrollCaptureInternal = new ScrollCaptureInternal(); 33229 } 33230 return mAttachInfo.mScrollCaptureInternal.requestCallback(this, localVisibleRect, 33231 windowOffset); 33232 } 33233 33234 /** 33235 * Dispatch a scroll capture search request down the view hierarchy. 33236 * 33237 * @param localVisibleRect the visible area of this ViewGroup in local coordinates, according to 33238 * the parent 33239 * @param windowOffset the offset of this view within the window 33240 * @param targets accepts potential scroll capture targets; {@link Consumer#accept 33241 * results.accept} may be called zero or more times on the calling 33242 * thread before onScrollCaptureSearch returns 33243 */ dispatchScrollCaptureSearch( @onNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets)33244 public void dispatchScrollCaptureSearch( 33245 @NonNull Rect localVisibleRect, @NonNull Point windowOffset, 33246 @NonNull Consumer<ScrollCaptureTarget> targets) { 33247 onScrollCaptureSearch(localVisibleRect, windowOffset, targets); 33248 } 33249 33250 /** 33251 * Called when scroll capture is requested, to search for appropriate content to scroll. If 33252 * applicable, this view adds itself to the provided list for consideration, subject to the 33253 * flags set by {@link #setScrollCaptureHint}. 33254 * 33255 * @param localVisibleRect the local visible rect of this view 33256 * @param windowOffset the offset of localVisibleRect within the window 33257 * @param targets accepts potential scroll capture targets; {@link Consumer#accept 33258 * results.accept} may be called zero or more times on the calling 33259 * thread before onScrollCaptureSearch returns 33260 * @throws IllegalStateException if this view is not attached to a window 33261 */ onScrollCaptureSearch(@onNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets)33262 public void onScrollCaptureSearch(@NonNull Rect localVisibleRect, 33263 @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets) { 33264 int hint = getScrollCaptureHint(); 33265 if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) { 33266 return; 33267 } 33268 boolean rectIsVisible = true; 33269 33270 // Apply clipBounds if present. 33271 if (mClipBounds != null) { 33272 rectIsVisible = localVisibleRect.intersect(mClipBounds); 33273 } 33274 if (!rectIsVisible) { 33275 return; 33276 } 33277 33278 // Get a callback provided by the framework, library or application. 33279 ScrollCaptureCallback callback = 33280 (mListenerInfo == null) ? null : mListenerInfo.mScrollCaptureCallback; 33281 33282 // Try framework support for standard scrolling containers. 33283 if (callback == null) { 33284 callback = createScrollCaptureCallbackInternal(localVisibleRect, windowOffset); 33285 } 33286 33287 // If found, then add it to the list. 33288 if (callback != null) { 33289 // Add to the list for consideration 33290 Point offset = new Point(windowOffset.x, windowOffset.y); 33291 Rect rect = new Rect(localVisibleRect); 33292 targets.accept(new ScrollCaptureTarget(this, rect, offset, callback)); 33293 } 33294 } 33295 33296 /** 33297 * Dump all private flags in readable format, useful for documentation and 33298 * consistency checking. 33299 */ dumpFlags()33300 private static void dumpFlags() { 33301 final HashMap<String, String> found = Maps.newHashMap(); 33302 try { 33303 for (Field field : View.class.getDeclaredFields()) { 33304 final int modifiers = field.getModifiers(); 33305 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 33306 if (field.getType().equals(int.class)) { 33307 final int value = field.getInt(null); 33308 dumpFlag(found, field.getName(), value); 33309 } else if (field.getType().equals(int[].class)) { 33310 final int[] values = (int[]) field.get(null); 33311 for (int i = 0; i < values.length; i++) { 33312 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 33313 } 33314 } 33315 } 33316 } 33317 } catch (IllegalAccessException e) { 33318 throw new RuntimeException(e); 33319 } 33320 33321 final ArrayList<String> keys = Lists.newArrayList(); 33322 keys.addAll(found.keySet()); 33323 Collections.sort(keys); 33324 for (String key : keys) { 33325 Log.d(VIEW_LOG_TAG, found.get(key)); 33326 } 33327 } 33328 dumpFlag(HashMap<String, String> found, String name, int value)33329 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 33330 // Sort flags by prefix, then by bits, always keeping unique keys 33331 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 33332 final int prefix = name.indexOf('_'); 33333 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 33334 final String output = bits + " " + name; 33335 found.put(key, output); 33336 } 33337 33338 /** {@hide} */ encode(@onNull ViewHierarchyEncoder stream)33339 public void encode(@NonNull ViewHierarchyEncoder stream) { 33340 stream.beginObject(this); 33341 encodeProperties(stream); 33342 stream.endObject(); 33343 } 33344 33345 /** {@hide} */ 33346 @CallSuper encodeProperties(@onNull ViewHierarchyEncoder stream)33347 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 33348 Object resolveId = ViewDebug.resolveId(getContext(), mID); 33349 if (resolveId instanceof String) { 33350 stream.addProperty("id", (String) resolveId); 33351 } else { 33352 stream.addProperty("id", mID); 33353 } 33354 33355 stream.addProperty("misc:transformation.alpha", 33356 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 33357 stream.addProperty("misc:transitionName", getTransitionName()); 33358 33359 // layout 33360 stream.addProperty("layout:left", mLeft); 33361 stream.addProperty("layout:right", mRight); 33362 stream.addProperty("layout:top", mTop); 33363 stream.addProperty("layout:bottom", mBottom); 33364 stream.addProperty("layout:width", getWidth()); 33365 stream.addProperty("layout:height", getHeight()); 33366 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 33367 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 33368 stream.addProperty("layout:hasTransientState", hasTransientState()); 33369 stream.addProperty("layout:baseline", getBaseline()); 33370 33371 // layout params 33372 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 33373 if (layoutParams != null) { 33374 stream.addPropertyKey("layoutParams"); 33375 layoutParams.encode(stream); 33376 } 33377 33378 // scrolling 33379 stream.addProperty("scrolling:scrollX", mScrollX); 33380 stream.addProperty("scrolling:scrollY", mScrollY); 33381 33382 // padding 33383 stream.addProperty("padding:paddingLeft", mPaddingLeft); 33384 stream.addProperty("padding:paddingRight", mPaddingRight); 33385 stream.addProperty("padding:paddingTop", mPaddingTop); 33386 stream.addProperty("padding:paddingBottom", mPaddingBottom); 33387 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 33388 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 33389 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 33390 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 33391 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 33392 33393 // measurement 33394 stream.addProperty("measurement:minHeight", mMinHeight); 33395 stream.addProperty("measurement:minWidth", mMinWidth); 33396 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 33397 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 33398 33399 // drawing 33400 stream.addProperty("drawing:elevation", getElevation()); 33401 stream.addProperty("drawing:translationX", getTranslationX()); 33402 stream.addProperty("drawing:translationY", getTranslationY()); 33403 stream.addProperty("drawing:translationZ", getTranslationZ()); 33404 stream.addProperty("drawing:rotation", getRotation()); 33405 stream.addProperty("drawing:rotationX", getRotationX()); 33406 stream.addProperty("drawing:rotationY", getRotationY()); 33407 stream.addProperty("drawing:scaleX", getScaleX()); 33408 stream.addProperty("drawing:scaleY", getScaleY()); 33409 stream.addProperty("drawing:pivotX", getPivotX()); 33410 stream.addProperty("drawing:pivotY", getPivotY()); 33411 stream.addProperty("drawing:clipBounds", 33412 mClipBounds == null ? null : mClipBounds.toString()); 33413 stream.addProperty("drawing:opaque", isOpaque()); 33414 stream.addProperty("drawing:alpha", getAlpha()); 33415 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 33416 stream.addProperty("drawing:shadow", hasShadow()); 33417 stream.addProperty("drawing:solidColor", getSolidColor()); 33418 stream.addProperty("drawing:layerType", mLayerType); 33419 stream.addProperty("drawing:willNotDraw", willNotDraw()); 33420 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 33421 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 33422 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 33423 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 33424 stream.addProperty("drawing:outlineAmbientShadowColor", getOutlineAmbientShadowColor()); 33425 stream.addProperty("drawing:outlineSpotShadowColor", getOutlineSpotShadowColor()); 33426 33427 // focus 33428 stream.addProperty("focus:hasFocus", hasFocus()); 33429 stream.addProperty("focus:isFocused", isFocused()); 33430 stream.addProperty("focus:focusable", getFocusable()); 33431 stream.addProperty("focus:isFocusable", isFocusable()); 33432 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 33433 33434 stream.addProperty("misc:clickable", isClickable()); 33435 stream.addProperty("misc:pressed", isPressed()); 33436 stream.addProperty("misc:selected", isSelected()); 33437 stream.addProperty("misc:touchMode", isInTouchMode()); 33438 stream.addProperty("misc:hovered", isHovered()); 33439 stream.addProperty("misc:activated", isActivated()); 33440 33441 stream.addProperty("misc:visibility", getVisibility()); 33442 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 33443 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 33444 33445 stream.addProperty("misc:enabled", isEnabled()); 33446 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 33447 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 33448 33449 // theme attributes 33450 Resources.Theme theme = getContext().getTheme(); 33451 if (theme != null) { 33452 stream.addPropertyKey("theme"); 33453 theme.encode(stream); 33454 } 33455 33456 // view attribute information 33457 int n = mAttributes != null ? mAttributes.length : 0; 33458 stream.addProperty("meta:__attrCount__", n/2); 33459 for (int i = 0; i < n; i += 2) { 33460 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 33461 } 33462 33463 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 33464 33465 // text 33466 stream.addProperty("text:textDirection", getTextDirection()); 33467 stream.addProperty("text:textAlignment", getTextAlignment()); 33468 33469 // accessibility 33470 CharSequence contentDescription = getContentDescription(); 33471 stream.addUserProperty("accessibility:contentDescription", 33472 contentDescription == null ? "" : contentDescription.toString()); 33473 stream.addProperty("accessibility:labelFor", getLabelFor()); 33474 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 33475 } 33476 33477 /** 33478 * Determine if this view is rendered on a round wearable device and is the main view 33479 * on the screen. 33480 */ shouldDrawRoundScrollbar()33481 boolean shouldDrawRoundScrollbar() { 33482 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 33483 return false; 33484 } 33485 33486 final View rootView = getRootView(); 33487 final WindowInsets insets = getRootWindowInsets(); 33488 33489 int height = getHeight(); 33490 int width = getWidth(); 33491 int displayHeight = rootView.getHeight(); 33492 int displayWidth = rootView.getWidth(); 33493 33494 if (height != displayHeight || width != displayWidth) { 33495 return false; 33496 } 33497 33498 return true; 33499 } 33500 33501 /** 33502 * Sets the tooltip text which will be displayed in a small popup next to the view. 33503 * <p> 33504 * The tooltip will be displayed: 33505 * <ul> 33506 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context 33507 * menu). </li> 33508 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 33509 * </ul> 33510 * <p> 33511 * <strong>Note:</strong> Do not override this method, as it will have no 33512 * effect on the text displayed in the tooltip. 33513 * 33514 * @param tooltipText the tooltip text, or null if no tooltip is required 33515 * @see #getTooltipText() 33516 * @attr ref android.R.styleable#View_tooltipText 33517 */ setTooltipText(@ullable CharSequence tooltipText)33518 public void setTooltipText(@Nullable CharSequence tooltipText) { 33519 if (TextUtils.isEmpty(tooltipText)) { 33520 setFlags(0, TOOLTIP); 33521 hideTooltip(); 33522 mTooltipInfo = null; 33523 } else { 33524 setFlags(TOOLTIP, TOOLTIP); 33525 if (mTooltipInfo == null) { 33526 mTooltipInfo = new TooltipInfo(); 33527 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 33528 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 33529 mTooltipInfo.mHoverSlop = ViewConfiguration.get(mContext).getScaledHoverSlop(); 33530 mTooltipInfo.clearAnchorPos(); 33531 } 33532 mTooltipInfo.mTooltipText = tooltipText; 33533 } 33534 } 33535 33536 /** 33537 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 33538 */ 33539 @UnsupportedAppUsage setTooltip(@ullable CharSequence tooltipText)33540 public void setTooltip(@Nullable CharSequence tooltipText) { 33541 setTooltipText(tooltipText); 33542 } 33543 33544 /** 33545 * Returns the view's tooltip text. 33546 * 33547 * <strong>Note:</strong> Do not override this method, as it will have no 33548 * effect on the text displayed in the tooltip. You must call 33549 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 33550 * 33551 * @return the tooltip text 33552 * @see #setTooltipText(CharSequence) 33553 * @attr ref android.R.styleable#View_tooltipText 33554 */ 33555 @InspectableProperty 33556 @Nullable getTooltipText()33557 public CharSequence getTooltipText() { 33558 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 33559 } 33560 33561 /** 33562 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 33563 */ 33564 @Nullable getTooltip()33565 public CharSequence getTooltip() { 33566 return getTooltipText(); 33567 } 33568 showTooltip(int x, int y, boolean fromLongClick)33569 private boolean showTooltip(int x, int y, boolean fromLongClick) { 33570 if (mAttachInfo == null || mTooltipInfo == null) { 33571 return false; 33572 } 33573 if (fromLongClick && (mViewFlags & ENABLED_MASK) != ENABLED) { 33574 return false; 33575 } 33576 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 33577 return false; 33578 } 33579 hideTooltip(); 33580 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 33581 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 33582 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 33583 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 33584 mAttachInfo.mTooltipHost = this; 33585 // The available accessibility actions have changed 33586 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 33587 return true; 33588 } 33589 33590 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) hideTooltip()33591 void hideTooltip() { 33592 if (mTooltipInfo == null) { 33593 return; 33594 } 33595 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 33596 if (mTooltipInfo.mTooltipPopup == null) { 33597 return; 33598 } 33599 mTooltipInfo.mTooltipPopup.hide(); 33600 mTooltipInfo.mTooltipPopup = null; 33601 mTooltipInfo.mTooltipFromLongClick = false; 33602 mTooltipInfo.clearAnchorPos(); 33603 if (mAttachInfo != null) { 33604 mAttachInfo.mTooltipHost = null; 33605 } 33606 // The available accessibility actions have changed 33607 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 33608 } 33609 showLongClickTooltip(int x, int y)33610 private boolean showLongClickTooltip(int x, int y) { 33611 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 33612 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 33613 return showTooltip(x, y, true); 33614 } 33615 showHoverTooltip()33616 private boolean showHoverTooltip() { 33617 return showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 33618 } 33619 dispatchTooltipHoverEvent(MotionEvent event)33620 boolean dispatchTooltipHoverEvent(MotionEvent event) { 33621 if (mTooltipInfo == null) { 33622 return false; 33623 } 33624 switch(event.getAction()) { 33625 case MotionEvent.ACTION_HOVER_MOVE: 33626 if ((mViewFlags & TOOLTIP) != TOOLTIP) { 33627 break; 33628 } 33629 if (!mTooltipInfo.mTooltipFromLongClick && mTooltipInfo.updateAnchorPos(event)) { 33630 if (mTooltipInfo.mTooltipPopup == null) { 33631 // Schedule showing the tooltip after a timeout. 33632 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 33633 postDelayed(mTooltipInfo.mShowTooltipRunnable, 33634 ViewConfiguration.getHoverTooltipShowTimeout()); 33635 } 33636 33637 // Hide hover-triggered tooltip after a period of inactivity. 33638 // Match the timeout used by NativeInputManager to hide the mouse pointer 33639 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 33640 final int timeout; 33641 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 33642 == SYSTEM_UI_FLAG_LOW_PROFILE) { 33643 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 33644 } else { 33645 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 33646 } 33647 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 33648 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 33649 } 33650 return true; 33651 33652 case MotionEvent.ACTION_HOVER_EXIT: 33653 mTooltipInfo.clearAnchorPos(); 33654 if (!mTooltipInfo.mTooltipFromLongClick) { 33655 hideTooltip(); 33656 } 33657 break; 33658 } 33659 return false; 33660 } 33661 handleTooltipKey(KeyEvent event)33662 void handleTooltipKey(KeyEvent event) { 33663 switch (event.getAction()) { 33664 case KeyEvent.ACTION_DOWN: 33665 if (event.getRepeatCount() == 0) { 33666 hideTooltip(); 33667 } 33668 break; 33669 33670 case KeyEvent.ACTION_UP: 33671 handleTooltipUp(); 33672 break; 33673 } 33674 } 33675 handleTooltipUp()33676 private void handleTooltipUp() { 33677 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 33678 return; 33679 } 33680 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 33681 postDelayed(mTooltipInfo.mHideTooltipRunnable, 33682 ViewConfiguration.getLongPressTooltipHideTimeout()); 33683 } 33684 getFocusableAttribute(TypedArray attributes)33685 private int getFocusableAttribute(TypedArray attributes) { 33686 TypedValue val = new TypedValue(); 33687 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 33688 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 33689 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 33690 } else { 33691 return val.data; 33692 } 33693 } else { 33694 return FOCUSABLE_AUTO; 33695 } 33696 } 33697 33698 /** 33699 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 33700 * is not showing. 33701 * @hide 33702 */ 33703 @TestApi getTooltipView()33704 public View getTooltipView() { 33705 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 33706 return null; 33707 } 33708 return mTooltipInfo.mTooltipPopup.getContentView(); 33709 } 33710 33711 /** 33712 * @return {@code true} if the default focus highlight is enabled, {@code false} otherwies. 33713 * @hide 33714 */ 33715 @TestApi isDefaultFocusHighlightEnabled()33716 public static boolean isDefaultFocusHighlightEnabled() { 33717 return sUseDefaultFocusHighlight; 33718 } 33719 33720 /** 33721 * Dispatch a previously unhandled {@link KeyEvent} to this view. Unlike normal key dispatch, 33722 * this dispatches to ALL child views until it is consumed. The dispatch order is z-order 33723 * (visually on-top views first). 33724 * 33725 * @param evt the previously unhandled {@link KeyEvent}. 33726 * @return the {@link View} which consumed the event or {@code null} if not consumed. 33727 */ dispatchUnhandledKeyEvent(KeyEvent evt)33728 View dispatchUnhandledKeyEvent(KeyEvent evt) { 33729 if (onUnhandledKeyEvent(evt)) { 33730 return this; 33731 } 33732 return null; 33733 } 33734 33735 /** 33736 * Allows this view to handle {@link KeyEvent}s which weren't handled by normal dispatch. This 33737 * occurs after the normal view hierarchy dispatch, but before the window callback. By default, 33738 * this will dispatch into all the listeners registered via 33739 * {@link #addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener)} in last-in-first-out 33740 * order (most recently added will receive events first). 33741 * 33742 * @param event An unhandled event. 33743 * @return {@code true} if the event was handled, {@code false} otherwise. 33744 * @see #addOnUnhandledKeyEventListener 33745 */ onUnhandledKeyEvent(@onNull KeyEvent event)33746 boolean onUnhandledKeyEvent(@NonNull KeyEvent event) { 33747 if (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null) { 33748 for (int i = mListenerInfo.mUnhandledKeyListeners.size() - 1; i >= 0; --i) { 33749 if (mListenerInfo.mUnhandledKeyListeners.get(i).onUnhandledKeyEvent(this, event)) { 33750 return true; 33751 } 33752 } 33753 } 33754 return false; 33755 } 33756 hasUnhandledKeyListener()33757 boolean hasUnhandledKeyListener() { 33758 return (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null 33759 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()); 33760 } 33761 33762 /** 33763 * Adds a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 33764 * UI thread. 33765 * 33766 * @param listener a receiver of unhandled {@link KeyEvent}s. 33767 * @see #removeOnUnhandledKeyEventListener 33768 */ addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)33769 public void addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 33770 ArrayList<OnUnhandledKeyEventListener> listeners = getListenerInfo().mUnhandledKeyListeners; 33771 if (listeners == null) { 33772 listeners = new ArrayList<>(); 33773 getListenerInfo().mUnhandledKeyListeners = listeners; 33774 } 33775 listeners.add(listener); 33776 if (listeners.size() == 1 && mParent instanceof ViewGroup) { 33777 ((ViewGroup) mParent).incrementChildUnhandledKeyListeners(); 33778 } 33779 } 33780 33781 /** 33782 * Removes a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 33783 * UI thread. 33784 * 33785 * @param listener a receiver of unhandled {@link KeyEvent}s. 33786 * @see #addOnUnhandledKeyEventListener 33787 */ removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)33788 public void removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 33789 if (mListenerInfo != null) { 33790 if (mListenerInfo.mUnhandledKeyListeners != null 33791 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 33792 mListenerInfo.mUnhandledKeyListeners.remove(listener); 33793 if (mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 33794 mListenerInfo.mUnhandledKeyListeners = null; 33795 if (mParent instanceof ViewGroup) { 33796 ((ViewGroup) mParent).decrementChildUnhandledKeyListeners(); 33797 } 33798 } 33799 } 33800 } 33801 } 33802 33803 /** 33804 * Set the view to be detached or not detached. 33805 * 33806 * @param detached Whether the view is detached. 33807 * 33808 * @hide 33809 */ setDetached(boolean detached)33810 protected void setDetached(boolean detached) { 33811 if (detached) { 33812 mPrivateFlags4 |= PFLAG4_DETACHED; 33813 } else { 33814 mPrivateFlags4 &= ~PFLAG4_DETACHED; 33815 } 33816 } 33817 33818 /** 33819 * Sets whether this view is a credential for Credential Manager purposes. 33820 * 33821 * <p>See {@link #isCredential()}. 33822 * 33823 * @param isCredential Whether the view is a credential. 33824 * 33825 * @attr ref android.R.styleable#View_isCredential 33826 */ setIsCredential(boolean isCredential)33827 public void setIsCredential(boolean isCredential) { 33828 if (isCredential) { 33829 mPrivateFlags4 |= PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER; 33830 } else { 33831 mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER; 33832 } 33833 } 33834 33835 /** 33836 * Gets the mode for determining whether this view is a credential. 33837 * 33838 * <p>See {@link #setIsCredential(boolean)}. 33839 * 33840 * @return false by default, or value passed to {@link #setIsCredential(boolean)}. 33841 * 33842 * @attr ref android.R.styleable#View_isCredential 33843 */ isCredential()33844 public boolean isCredential() { 33845 return ((mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER) 33846 == PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER); 33847 } 33848 33849 // TODO(316208691): Revive following removed API docs. 33850 // @see EditorInfo#setStylusHandwritingEnabled(boolean) 33851 /** 33852 * Set whether this view enables automatic handwriting initiation. 33853 * 33854 * For a view with an active {@link InputConnection}, if auto handwriting is enabled then 33855 * stylus movement within its view boundary will automatically trigger the handwriting mode. 33856 * Check {@link android.view.inputmethod.InputMethodManager#startStylusHandwriting(View)} for 33857 * more details about handwriting mode. 33858 * 33859 * If the View wants to initiate handwriting mode by itself, it can set this field to 33860 * {@code false} and call 33861 * {@link android.view.inputmethod.InputMethodManager#startStylusHandwriting(View)} when there 33862 * is stylus movement detected. 33863 * 33864 * Note that this attribute has no effect on the View's children. For example, if a 33865 * {@link ViewGroup} disables auto handwriting but its children set auto handwriting to true, 33866 * auto handwriting will still work for the children, and vice versa. 33867 * 33868 * @see #onCreateInputConnection(EditorInfo) 33869 * @see android.view.inputmethod.InputMethodManager#startStylusHandwriting(View) 33870 * @param enabled whether auto handwriting initiation is enabled for this view. 33871 * @attr ref android.R.styleable#View_autoHandwritingEnabled 33872 */ setAutoHandwritingEnabled(boolean enabled)33873 public void setAutoHandwritingEnabled(boolean enabled) { 33874 if (enabled) { 33875 mPrivateFlags4 |= PFLAG4_AUTO_HANDWRITING_ENABLED; 33876 } else { 33877 mPrivateFlags4 &= ~PFLAG4_AUTO_HANDWRITING_ENABLED; 33878 } 33879 updatePositionUpdateListener(); 33880 postUpdate(this::updateHandwritingArea); 33881 } 33882 33883 /** 33884 * Return whether the View allows automatic handwriting initiation. Returns true if automatic 33885 * handwriting initiation is enabled, and vice versa. 33886 * @see #setAutoHandwritingEnabled(boolean) 33887 */ isAutoHandwritingEnabled()33888 public boolean isAutoHandwritingEnabled() { 33889 return (mPrivateFlags4 & PFLAG4_AUTO_HANDWRITING_ENABLED) 33890 == PFLAG4_AUTO_HANDWRITING_ENABLED; 33891 } 33892 33893 /** 33894 * Return whether the stylus handwriting is available for this View. 33895 * @hide 33896 */ isStylusHandwritingAvailable()33897 public boolean isStylusHandwritingAvailable() { 33898 return getContext().getSystemService(InputMethodManager.class) 33899 .isStylusHandwritingAvailable(); 33900 } 33901 setTraversalTracingEnabled(boolean enabled)33902 private void setTraversalTracingEnabled(boolean enabled) { 33903 if (enabled) { 33904 if (mTracingStrings == null) { 33905 mTracingStrings = new ViewTraversalTracingStrings(this); 33906 } 33907 mPrivateFlags4 |= PFLAG4_TRAVERSAL_TRACING_ENABLED; 33908 } else { 33909 mPrivateFlags4 &= ~PFLAG4_TRAVERSAL_TRACING_ENABLED; 33910 } 33911 } 33912 isTraversalTracingEnabled()33913 private boolean isTraversalTracingEnabled() { 33914 return (mPrivateFlags4 & PFLAG4_TRAVERSAL_TRACING_ENABLED) 33915 == PFLAG4_TRAVERSAL_TRACING_ENABLED; 33916 } 33917 setRelayoutTracingEnabled(boolean enabled)33918 private void setRelayoutTracingEnabled(boolean enabled) { 33919 if (enabled) { 33920 if (mTracingStrings == null) { 33921 mTracingStrings = new ViewTraversalTracingStrings(this); 33922 } 33923 mPrivateFlags4 |= PFLAG4_RELAYOUT_TRACING_ENABLED; 33924 } else { 33925 mPrivateFlags4 &= ~PFLAG4_RELAYOUT_TRACING_ENABLED; 33926 } 33927 } 33928 isRelayoutTracingEnabled()33929 private boolean isRelayoutTracingEnabled() { 33930 return (mPrivateFlags4 & PFLAG4_RELAYOUT_TRACING_ENABLED) 33931 == PFLAG4_RELAYOUT_TRACING_ENABLED; 33932 } 33933 33934 /** 33935 * Collects a {@link ViewTranslationRequest} which represents the content to be translated in 33936 * the view. 33937 * 33938 * <p>The default implementation does nothing.</p> 33939 * 33940 * @param supportedFormats the supported translation formats. For now, the only possible value 33941 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 33942 * @param requestsCollector a {@link ViewTranslationRequest} collector that can be used to 33943 * collect the information to be translated in the view. The {@code requestsCollector} only 33944 * accepts one request; an IllegalStateException is thrown if more than one 33945 * {@link ViewTranslationRequest} is submitted to it. The {@link AutofillId} must be set on the 33946 * {@link ViewTranslationRequest}. 33947 */ onCreateViewTranslationRequest(@onNull @ataFormat int[] supportedFormats, @NonNull Consumer<ViewTranslationRequest> requestsCollector)33948 public void onCreateViewTranslationRequest(@NonNull @DataFormat int[] supportedFormats, 33949 @NonNull Consumer<ViewTranslationRequest> requestsCollector) { 33950 } 33951 33952 /** 33953 * Collects {@link ViewTranslationRequest}s which represents the content to be translated 33954 * for the virtual views in the host view. This is called if this view returned a virtual 33955 * view structure from {@link #onProvideContentCaptureStructure} and the system determined that 33956 * those virtual views were relevant for translation. 33957 * 33958 * <p>The default implementation does nothing.</p> 33959 * 33960 * @param virtualIds the virtual view ids which represents the virtual views in the host 33961 * view. 33962 * @param supportedFormats the supported translation formats. For now, the only possible value 33963 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 33964 * @param requestsCollector a {@link ViewTranslationRequest} collector that can be called 33965 * multiple times to collect the information to be translated in the host view. One 33966 * {@link ViewTranslationRequest} per virtual child. The {@link ViewTranslationRequest} must 33967 * contains the {@link AutofillId} corresponding to the virtualChildIds. Do not keep this 33968 * Consumer after the method returns. 33969 */ 33970 @SuppressLint("NullableCollection") onCreateVirtualViewTranslationRequests(@onNull long[] virtualIds, @NonNull @DataFormat int[] supportedFormats, @NonNull Consumer<ViewTranslationRequest> requestsCollector)33971 public void onCreateVirtualViewTranslationRequests(@NonNull long[] virtualIds, 33972 @NonNull @DataFormat int[] supportedFormats, 33973 @NonNull Consumer<ViewTranslationRequest> requestsCollector) { 33974 // no-op 33975 } 33976 33977 /** 33978 * Returns a {@link ViewTranslationCallback} that is used to display the translated information 33979 * or {@code null} if this View doesn't support translation. 33980 * 33981 * @hide 33982 */ 33983 @Nullable getViewTranslationCallback()33984 public ViewTranslationCallback getViewTranslationCallback() { 33985 return mViewTranslationCallback; 33986 } 33987 33988 /** 33989 * Sets a {@link ViewTranslationCallback} that is used to display/hide the translated 33990 * information. Developers can provide the customized implementation for show/hide translated 33991 * information. 33992 * 33993 * @param callback a {@link ViewTranslationCallback} that is used to control how to display the 33994 * translated information 33995 */ setViewTranslationCallback(@onNull ViewTranslationCallback callback)33996 public void setViewTranslationCallback(@NonNull ViewTranslationCallback callback) { 33997 mViewTranslationCallback = callback; 33998 } 33999 34000 /** 34001 * Clear the {@link ViewTranslationCallback} from this view. 34002 */ clearViewTranslationCallback()34003 public void clearViewTranslationCallback() { 34004 mViewTranslationCallback = null; 34005 } 34006 34007 /** 34008 * Returns the {@link ViewTranslationResponse} associated with this view. The response will be 34009 * set when the translation is done then {@link #onViewTranslationResponse} is called. The 34010 * {@link ViewTranslationCallback} can use to get {@link ViewTranslationResponse} to display the 34011 * translated information. 34012 * 34013 * @return a {@link ViewTranslationResponse} that contains the translated information associated 34014 * with this view or {@code null} if this View doesn't have the translation. 34015 */ 34016 @Nullable getViewTranslationResponse()34017 public ViewTranslationResponse getViewTranslationResponse() { 34018 return mViewTranslationResponse; 34019 } 34020 34021 /** 34022 * Called when the content from {@link View#onCreateViewTranslationRequest} had been translated 34023 * by the TranslationService. The {@link ViewTranslationResponse} should be saved here so that 34024 * the {@link ViewTranslationResponse} can be used to display the translation when the system 34025 * calls {@link ViewTranslationCallback#onShowTranslation}. 34026 * 34027 * <p> The default implementation will set the ViewTranslationResponse that can be get from 34028 * {@link View#getViewTranslationResponse}. </p> 34029 * 34030 * @param response a {@link ViewTranslationResponse} that contains the translated information 34031 * which can be shown in the view. 34032 */ onViewTranslationResponse(@onNull ViewTranslationResponse response)34033 public void onViewTranslationResponse(@NonNull ViewTranslationResponse response) { 34034 mViewTranslationResponse = response; 34035 } 34036 34037 /** 34038 * Clears the ViewTranslationResponse stored by the default implementation of {@link 34039 * #onViewTranslationResponse}. 34040 * 34041 * @hide 34042 */ clearViewTranslationResponse()34043 public void clearViewTranslationResponse() { 34044 mViewTranslationResponse = null; 34045 } 34046 34047 /** 34048 * Called when the content from {@link View#onCreateVirtualViewTranslationRequests} had been 34049 * translated by the TranslationService. 34050 * 34051 * <p> The default implementation does nothing.</p> 34052 * 34053 * @param response a {@link ViewTranslationResponse} SparseArray for the request that send by 34054 * {@link View#onCreateVirtualViewTranslationRequests} that contains the translated information 34055 * which can be shown in the view. The key of SparseArray is the virtual child ids. 34056 */ onVirtualViewTranslationResponses( @onNull LongSparseArray<ViewTranslationResponse> response)34057 public void onVirtualViewTranslationResponses( 34058 @NonNull LongSparseArray<ViewTranslationResponse> response) { 34059 // no-op 34060 } 34061 34062 /** 34063 * Dispatch to collect the {@link ViewTranslationRequest}s for translation purpose by traversing 34064 * the hierarchy when the app requests ui translation. Typically, this method should only be 34065 * overridden by subclasses that provide a view hierarchy (such as {@link ViewGroup}). Other 34066 * classes should override {@link View#onCreateViewTranslationRequest} for normal view or 34067 * override {@link View#onVirtualViewTranslationResponses} for view contains virtual children. 34068 * When requested to start the ui translation, the system will call this method to traverse the 34069 * view hierarchy to collect {@link ViewTranslationRequest}s and create a 34070 * {@link android.view.translation.Translator} to translate the requests. All the 34071 * {@link ViewTranslationRequest}s must be added when the traversal is done. 34072 * 34073 * <p> The default implementation calls {@link View#onCreateViewTranslationRequest} for normal 34074 * view or calls {@link View#onVirtualViewTranslationResponses} for view contains virtual 34075 * children to build {@link ViewTranslationRequest} if the view should be translated. 34076 * The view is marked as having {@link #setHasTransientState(boolean) transient state} so that 34077 * recycling of views doesn't prevent the system from attaching the response to it. Therefore, 34078 * if overriding this method, you should set or reset the transient state. </p> 34079 * 34080 * @param viewIds a map for the view's {@link AutofillId} and its virtual child ids or 34081 * {@code null} if the view doesn't have virtual child that should be translated. The virtual 34082 * child ids are the same virtual ids provided by ContentCapture. 34083 * @param supportedFormats the supported translation formats. For now, the only possible value 34084 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 34085 * @param capability a {@link TranslationCapability} that holds translation capability. 34086 * information, e.g. source spec, target spec. 34087 * @param requests fill in with {@link ViewTranslationRequest}s for translation purpose. 34088 */ dispatchCreateViewTranslationRequest(@onNull Map<AutofillId, long[]> viewIds, @NonNull @DataFormat int[] supportedFormats, @NonNull TranslationCapability capability, @NonNull List<ViewTranslationRequest> requests)34089 public void dispatchCreateViewTranslationRequest(@NonNull Map<AutofillId, long[]> viewIds, 34090 @NonNull @DataFormat int[] supportedFormats, 34091 @NonNull TranslationCapability capability, 34092 @NonNull List<ViewTranslationRequest> requests) { 34093 AutofillId autofillId = getAutofillId(); 34094 if (viewIds.containsKey(autofillId)) { 34095 if (viewIds.get(autofillId) == null) { 34096 // TODO: avoiding the allocation per view 34097 onCreateViewTranslationRequest(supportedFormats, 34098 new ViewTranslationRequestConsumer(requests)); 34099 } else { 34100 onCreateVirtualViewTranslationRequests(viewIds.get(autofillId), supportedFormats, 34101 request -> { 34102 requests.add(request); 34103 }); 34104 } 34105 } 34106 } 34107 34108 private class ViewTranslationRequestConsumer implements Consumer<ViewTranslationRequest> { 34109 private final List<ViewTranslationRequest> mRequests; 34110 private boolean mCalled; 34111 ViewTranslationRequestConsumer(List<ViewTranslationRequest> requests)34112 ViewTranslationRequestConsumer(List<ViewTranslationRequest> requests) { 34113 mRequests = requests; 34114 } 34115 34116 @Override accept(ViewTranslationRequest request)34117 public void accept(ViewTranslationRequest request) { 34118 if (mCalled) { 34119 throw new IllegalStateException("The translation Consumer is not reusable."); 34120 } 34121 mCalled = true; 34122 if (request != null && request.getKeys().size() > 0) { 34123 mRequests.add(request); 34124 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 34125 Log.v(CONTENT_CAPTURE_LOG_TAG, "Calling setHasTransientState(true) for " 34126 + getAutofillId()); 34127 } 34128 setHasTransientState(true); 34129 setHasTranslationTransientState(true); 34130 } 34131 } 34132 } 34133 34134 /** 34135 * Called to generate a {@link DisplayHash} for this view. 34136 * 34137 * @param hashAlgorithm The hash algorithm to use when hashing the display. Must be one of 34138 * the values returned from 34139 * {@link DisplayHashManager#getSupportedHashAlgorithms()} 34140 * @param bounds The bounds for the content within the View to generate the hash for. If 34141 * bounds are null, the entire View's bounds will be used. If empty, it will 34142 * invoke the callback 34143 * {@link DisplayHashResultCallback#onDisplayHashError} with error 34144 * {@link DisplayHashResultCallback#DISPLAY_HASH_ERROR_INVALID_BOUNDS} 34145 * @param executor The executor that the callback should be invoked on. 34146 * @param callback The callback to handle the results of generating the display hash 34147 */ generateDisplayHash(@onNull String hashAlgorithm, @Nullable Rect bounds, @NonNull Executor executor, @NonNull DisplayHashResultCallback callback)34148 public void generateDisplayHash(@NonNull String hashAlgorithm, 34149 @Nullable Rect bounds, @NonNull Executor executor, 34150 @NonNull DisplayHashResultCallback callback) { 34151 IWindowSession session = getWindowSession(); 34152 if (session == null) { 34153 callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); 34154 return; 34155 } 34156 IWindow window = getWindow(); 34157 if (window == null) { 34158 callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); 34159 return; 34160 } 34161 34162 Rect visibleBounds = new Rect(); 34163 getGlobalVisibleRect(visibleBounds); 34164 34165 if (bounds != null && bounds.isEmpty()) { 34166 callback.onDisplayHashError(DISPLAY_HASH_ERROR_INVALID_BOUNDS); 34167 return; 34168 } 34169 34170 if (bounds != null) { 34171 bounds.offset(visibleBounds.left, visibleBounds.top); 34172 visibleBounds.intersectUnchecked(bounds); 34173 } 34174 34175 if (visibleBounds.isEmpty()) { 34176 callback.onDisplayHashError(DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN); 34177 return; 34178 } 34179 34180 RemoteCallback remoteCallback = new RemoteCallback(result -> 34181 executor.execute(() -> { 34182 DisplayHash displayHash = result.getParcelable(EXTRA_DISPLAY_HASH, android.view.displayhash.DisplayHash.class); 34183 int errorCode = result.getInt(EXTRA_DISPLAY_HASH_ERROR_CODE, 34184 DISPLAY_HASH_ERROR_UNKNOWN); 34185 if (displayHash != null) { 34186 callback.onDisplayHashResult(displayHash); 34187 } else { 34188 callback.onDisplayHashError(errorCode); 34189 } 34190 })); 34191 34192 try { 34193 session.generateDisplayHash(window, visibleBounds, hashAlgorithm, remoteCallback); 34194 } catch (RemoteException e) { 34195 Log.e(VIEW_LOG_TAG, "Failed to call generateDisplayHash"); 34196 callback.onDisplayHashError(DISPLAY_HASH_ERROR_UNKNOWN); 34197 } 34198 } 34199 34200 /** 34201 * The AttachedSurfaceControl itself is not a View, it is just the interface to the 34202 * windowing-system object that contains the entire view hierarchy. 34203 * For the root View of a given hierarchy see {@link #getRootView}. 34204 34205 * @return The {@link android.view.AttachedSurfaceControl} interface for this View. 34206 * This will only return a non-null value when called between {@link #onAttachedToWindow} 34207 * and {@link #onDetachedFromWindow}. 34208 */ getRootSurfaceControl()34209 public @Nullable AttachedSurfaceControl getRootSurfaceControl() { 34210 if (mAttachInfo != null) { 34211 return mAttachInfo.getRootSurfaceControl(); 34212 } 34213 return null; 34214 } 34215 34216 /** 34217 * Used to calculate the frame rate category of a View. 34218 * 34219 * @hide 34220 */ calculateFrameRateCategory()34221 protected int calculateFrameRateCategory() { 34222 ViewRootImpl viewRootImpl = getViewRootImpl(); 34223 ViewParent parent = mParent; 34224 boolean isInputMethodWindowType = 34225 viewRootImpl.mWindowAttributes.type == TYPE_INPUT_METHOD; 34226 34227 // boost frame rate when the position or the size changed. 34228 if (((mPrivateFlags4 & (PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)) == ( 34229 PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN) || mLastFrameLeft != mLeft 34230 || mLastFrameTop != mTop) 34231 && viewRootImpl.shouldCheckFrameRateCategory() 34232 && parent instanceof View 34233 && ((View) parent).getFrameContentVelocity() <= 0 34234 && !isInputMethodWindowType 34235 && viewRootImpl.getFrameRateCompatibility() != FRAME_RATE_COMPATIBILITY_AT_LEAST) { 34236 34237 return FRAME_RATE_CATEGORY_HIGH_HINT | FRAME_RATE_CATEGORY_REASON_BOOST; 34238 } 34239 int category; 34240 switch (viewRootImpl.intermittentUpdateState()) { 34241 case ViewRootImpl.INTERMITTENT_STATE_INTERMITTENT -> { 34242 if (!sToolkitFrameRateBySizeReadOnlyFlagValue) { 34243 category = FRAME_RATE_CATEGORY_NORMAL; 34244 } else { 34245 // The size based frame rate category can only be LOW or NORMAL. If the size 34246 // based frame rate category is LOW, we shouldn't vote for NORMAL for 34247 // intermittent. 34248 category = Math.min( 34249 mSizeBasedFrameRateCategoryAndReason & ~FRAME_RATE_CATEGORY_REASON_MASK, 34250 FRAME_RATE_CATEGORY_NORMAL); 34251 } 34252 category |= FRAME_RATE_CATEGORY_REASON_INTERMITTENT; 34253 } 34254 case ViewRootImpl.INTERMITTENT_STATE_NOT_INTERMITTENT -> 34255 category = mSizeBasedFrameRateCategoryAndReason; 34256 default -> category = mLastFrameRateCategory; 34257 } 34258 return category; 34259 } 34260 34261 /** 34262 * Used to vote the preferred frame rate and frame rate category to ViewRootImpl 34263 * 34264 * @hide 34265 */ votePreferredFrameRate()34266 protected void votePreferredFrameRate() { 34267 // use toolkitSetFrameRate flag to gate the change 34268 ViewRootImpl viewRootImpl = getViewRootImpl(); 34269 if (viewRootImpl == null) { 34270 return; // can't vote if not connected 34271 } 34272 float velocity = mFrameContentVelocity; 34273 final float frameRate = mPreferredFrameRate; 34274 34275 if (viewRootImpl.shouldCheckFrameRate(frameRate > 0f) 34276 && (frameRate > 0 || (mAttachInfo.mViewVelocityApi && velocity > 0f))) { 34277 float velocityFrameRate = 0f; 34278 if (mAttachInfo.mViewVelocityApi && velocity > 0f) { 34279 velocityFrameRate = convertVelocityToFrameRate(velocity); 34280 } 34281 int compatibility; 34282 float frameRateToSet; 34283 if (frameRate >= velocityFrameRate) { 34284 compatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE; 34285 frameRateToSet = frameRate; 34286 } else { 34287 compatibility = FRAME_RATE_COMPATIBILITY_AT_LEAST; 34288 frameRateToSet = velocityFrameRate; 34289 } 34290 viewRootImpl.votePreferredFrameRate(frameRateToSet, compatibility); 34291 34292 if (Trace.isTagEnabled(TRACE_TAG_VIEW)) { 34293 Trace.instant(TRACE_TAG_VIEW, 34294 getClass().getSimpleName() 34295 + " - votePreferredFrameRate: " + frameRateToSet); 34296 } 34297 } 34298 34299 if (viewRootImpl.shouldCheckFrameRateCategory()) { 34300 if (sToolkitMetricsForFrameRateDecisionFlagValue) { 34301 int width = mRight - mLeft; 34302 int height = mBottom - mTop; 34303 float sizePercentage = width * height / mAttachInfo.mDisplayPixelCount; 34304 viewRootImpl.recordViewPercentage(sizePercentage); 34305 } 34306 34307 int frameRateCategory; 34308 if (Float.isNaN(frameRate)) { 34309 frameRateCategory = calculateFrameRateCategory(); 34310 } else if (frameRate < 0) { 34311 switch ((int) frameRate) { 34312 case (int) REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE -> 34313 frameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE 34314 | FRAME_RATE_CATEGORY_REASON_REQUESTED; 34315 case (int) REQUESTED_FRAME_RATE_CATEGORY_LOW -> 34316 frameRateCategory = FRAME_RATE_CATEGORY_LOW 34317 | FRAME_RATE_CATEGORY_REASON_REQUESTED; 34318 case (int) REQUESTED_FRAME_RATE_CATEGORY_NORMAL -> 34319 frameRateCategory = FRAME_RATE_CATEGORY_NORMAL 34320 | FRAME_RATE_CATEGORY_REASON_REQUESTED; 34321 case (int) REQUESTED_FRAME_RATE_CATEGORY_HIGH -> 34322 frameRateCategory = FRAME_RATE_CATEGORY_HIGH 34323 | FRAME_RATE_CATEGORY_REASON_REQUESTED; 34324 default -> { 34325 // invalid frame rate, use default 34326 int category = sToolkitFrameRateDefaultNormalReadOnlyFlagValue 34327 ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH; 34328 frameRateCategory = category 34329 | FRAME_RATE_CATEGORY_REASON_INVALID; 34330 } 34331 } 34332 34333 if (Trace.isTagEnabled(TRACE_TAG_VIEW)) { 34334 Trace.instant(TRACE_TAG_VIEW, 34335 getClass().getSimpleName() + " - votePreferredFrameRate: " 34336 + viewRootImpl.categoryToString( 34337 frameRateCategory & ~FRAME_RATE_CATEGORY_REASON_MASK)); 34338 } 34339 } else { 34340 // Category doesn't control it. It is directly controlled by frame rate 34341 frameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE 34342 | FRAME_RATE_CATEGORY_REASON_REQUESTED; 34343 } 34344 34345 int category = frameRateCategory & ~FRAME_RATE_CATEGORY_REASON_MASK; 34346 int reason = frameRateCategory & FRAME_RATE_CATEGORY_REASON_MASK; 34347 viewRootImpl.votePreferredFrameRateCategory(category, reason, this); 34348 mLastFrameRateCategory = frameRateCategory; 34349 } 34350 mLastFrameLeft = mLeft; 34351 mLastFrameTop = mTop; 34352 } 34353 convertVelocityToFrameRate(float velocityPps)34354 private float convertVelocityToFrameRate(float velocityPps) { 34355 // Internal testing has shown that this gives a premium experience: 34356 // above 300dp/s => 120fps 34357 // between 300dp/s and 125fps => 80fps 34358 // below 125dp/s => 60fps 34359 float density = mAttachInfo.mDensity; 34360 float velocityDps = velocityPps / density; 34361 float frameRate; 34362 if (velocityDps > 300f) { 34363 frameRate = MAX_FRAME_RATE; // Use maximum at fast motion 34364 } else if (velocityDps > 125f) { 34365 frameRate = 80f; // Use medium frame rate when motion is slower 34366 } else { 34367 frameRate = 60f; // Use minimum frame rate when motion is very slow 34368 } 34369 return frameRate; 34370 } 34371 34372 /** 34373 * Set the current velocity of the View, we only track positive value. 34374 * We will use the velocity information to adjust the frame rate when applicable. 34375 * For example, we could potentially lower the frame rate when 34376 * the velocity of a fling gesture becomes slower. 34377 * Note that this is only valid till the next drawn frame. 34378 * 34379 * @param pixelsPerSecond how many pixels move per second. 34380 */ 34381 @FlaggedApi(FLAG_VIEW_VELOCITY_API) setFrameContentVelocity(float pixelsPerSecond)34382 public void setFrameContentVelocity(float pixelsPerSecond) { 34383 if (mAttachInfo != null && mAttachInfo.mViewVelocityApi) { 34384 mFrameContentVelocity = Math.abs(pixelsPerSecond); 34385 34386 if (sToolkitMetricsForFrameRateDecisionFlagValue) { 34387 Trace.setCounter("Set frame velocity", (long) mFrameContentVelocity); 34388 } 34389 } 34390 } 34391 34392 /** 34393 * Get the current velocity of the View. 34394 * The value should always be greater than or equal to 0. 34395 * Note that this is only valid till the next drawn frame. 34396 * 34397 * @return 0 by default, or value passed to {@link #setFrameContentVelocity(float)}. 34398 */ 34399 @FlaggedApi(FLAG_VIEW_VELOCITY_API) getFrameContentVelocity()34400 public float getFrameContentVelocity() { 34401 if (mAttachInfo != null && mAttachInfo.mViewVelocityApi) { 34402 return Math.max(mFrameContentVelocity, 0f); 34403 } 34404 return 0; 34405 } 34406 34407 /** 34408 * You can set the preferred frame rate for a View using a positive number 34409 * or by specifying the preferred frame rate category using constants, including 34410 * REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE, REQUESTED_FRAME_RATE_CATEGORY_LOW, 34411 * REQUESTED_FRAME_RATE_CATEGORY_NORMAL, REQUESTED_FRAME_RATE_CATEGORY_HIGH. 34412 * Keep in mind that the preferred frame rate affects the frame rate for the next frame, 34413 * so use this method carefully. It's important to note that the preference is valid as 34414 * long as the View is invalidated. Please also be aware that the requested frame rate 34415 * will not propagate to child views when this API is used on a ViewGroup. 34416 * 34417 * @param frameRate the preferred frame rate of the view. 34418 */ 34419 @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) setRequestedFrameRate(float frameRate)34420 public void setRequestedFrameRate(float frameRate) { 34421 // Skip setting the frame rate if it's currently in forced override mode. 34422 if (sToolkitViewGroupFrameRateApiFlagValue && getForcedOverrideFrameRateFlag()) { 34423 return; 34424 } 34425 34426 if (sToolkitSetFrameRateReadOnlyFlagValue) { 34427 mPreferredFrameRate = frameRate; 34428 } 34429 34430 if (sToolkitViewGroupFrameRateApiFlagValue) { 34431 // If frameRate is Float.NaN, it means it's set to the default value. 34432 // We only want to make the flag true, when the value is not Float.nan 34433 setSelfRequestedFrameRateFlag(!Float.isNaN(mPreferredFrameRate)); 34434 } 34435 } 34436 34437 /** 34438 * Get the current preferred frame rate of the View. 34439 * The value could be negative when preferred frame rate category is set 34440 * instead of perferred frame rate. 34441 * The frame rate category includes 34442 * REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE, REQUESTED_FRAME_RATE_CATEGORY_LOW, 34443 * REQUESTED_FRAME_RATE_CATEGORY_NORMAL, and REQUESTED_FRAME_RATE_CATEGORY_HIGH. 34444 * Note that the frame rate value is valid as long as the View is invalidated. 34445 * Please also be aware that the requested frame rate will not propagate to 34446 * child views when this API is used on a ViewGroup. 34447 * 34448 * @return REQUESTED_FRAME_RATE_CATEGORY_DEFAULT by default, 34449 * or value passed to {@link #setRequestedFrameRate(float)}. 34450 */ 34451 @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY) getRequestedFrameRate()34452 public float getRequestedFrameRate() { 34453 if (sToolkitSetFrameRateReadOnlyFlagValue) { 34454 return mPreferredFrameRate; 34455 } 34456 return 0; 34457 } 34458 overrideFrameRate(float frameRate, boolean forceOverride)34459 void overrideFrameRate(float frameRate, boolean forceOverride) { 34460 setForcedOverrideFrameRateFlag(forceOverride); 34461 if (forceOverride || !getSelfRequestedFrameRateFlag()) { 34462 mPreferredFrameRate = frameRate; 34463 } 34464 } 34465 setForcedOverrideFrameRateFlag(boolean forcedOverride)34466 void setForcedOverrideFrameRateFlag(boolean forcedOverride) { 34467 if (forcedOverride) { 34468 mPrivateFlags4 |= PFLAG4_FORCED_OVERRIDE_FRAME_RATE; 34469 } else { 34470 mPrivateFlags4 &= ~PFLAG4_FORCED_OVERRIDE_FRAME_RATE; 34471 } 34472 } 34473 getForcedOverrideFrameRateFlag()34474 boolean getForcedOverrideFrameRateFlag() { 34475 return (mPrivateFlags4 & PFLAG4_FORCED_OVERRIDE_FRAME_RATE) != 0; 34476 } 34477 setSelfRequestedFrameRateFlag(boolean forcedOverride)34478 void setSelfRequestedFrameRateFlag(boolean forcedOverride) { 34479 if (forcedOverride) { 34480 mPrivateFlags4 |= PFLAG4_SELF_REQUESTED_FRAME_RATE; 34481 } else { 34482 mPrivateFlags4 &= ~PFLAG4_SELF_REQUESTED_FRAME_RATE; 34483 } 34484 } 34485 getSelfRequestedFrameRateFlag()34486 boolean getSelfRequestedFrameRateFlag() { 34487 return (mPrivateFlags4 & PFLAG4_SELF_REQUESTED_FRAME_RATE) != 0; 34488 } 34489 34490 /** 34491 * Called from apps when they want to report jank stats to the system. 34492 * @param appJankStats the stats that will be merged with the stats collected by the system. 34493 */ 34494 @FlaggedApi(android.app.jank.Flags.FLAG_DETAILED_APP_JANK_METRICS_API) reportAppJankStats(@onNull AppJankStats appJankStats)34495 public void reportAppJankStats(@NonNull AppJankStats appJankStats) { 34496 View rootView = getRootView(); 34497 if (rootView == this) return; 34498 34499 rootView.reportAppJankStats(appJankStats); 34500 } 34501 34502 /** 34503 * Called by widgets to get a reference to JankTracker in order to update states. 34504 * @hide 34505 */ getJankTracker()34506 public @Nullable JankTracker getJankTracker() { 34507 View rootView = getRootView(); 34508 if (rootView == this) { 34509 return null; 34510 } 34511 return rootView.getJankTracker(); 34512 } 34513 } 34514