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.view.ContentInfo.SOURCE_DRAG_AND_DROP; 22 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; 23 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_INVALID_BOUNDS; 24 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_MISSING_WINDOW; 25 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN; 26 import static android.view.displayhash.DisplayHashResultCallback.DISPLAY_HASH_ERROR_UNKNOWN; 27 import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH; 28 import static android.view.displayhash.DisplayHashResultCallback.EXTRA_DISPLAY_HASH_ERROR_CODE; 29 30 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS; 31 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS; 32 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP; 33 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; 34 35 import static java.lang.Math.max; 36 37 import android.animation.AnimatorInflater; 38 import android.animation.StateListAnimator; 39 import android.annotation.AttrRes; 40 import android.annotation.CallSuper; 41 import android.annotation.ColorInt; 42 import android.annotation.DrawableRes; 43 import android.annotation.FloatRange; 44 import android.annotation.IdRes; 45 import android.annotation.IntDef; 46 import android.annotation.IntRange; 47 import android.annotation.LayoutRes; 48 import android.annotation.NonNull; 49 import android.annotation.Nullable; 50 import android.annotation.RequiresPermission; 51 import android.annotation.Size; 52 import android.annotation.StyleRes; 53 import android.annotation.SuppressLint; 54 import android.annotation.SystemApi; 55 import android.annotation.TestApi; 56 import android.annotation.UiContext; 57 import android.annotation.UiThread; 58 import android.compat.annotation.UnsupportedAppUsage; 59 import android.content.AutofillOptions; 60 import android.content.ClipData; 61 import android.content.ClipDescription; 62 import android.content.Context; 63 import android.content.ContextWrapper; 64 import android.content.Intent; 65 import android.content.res.ColorStateList; 66 import android.content.res.CompatibilityInfo; 67 import android.content.res.Configuration; 68 import android.content.res.Resources; 69 import android.content.res.TypedArray; 70 import android.graphics.Bitmap; 71 import android.graphics.BlendMode; 72 import android.graphics.Canvas; 73 import android.graphics.Color; 74 import android.graphics.Insets; 75 import android.graphics.Interpolator; 76 import android.graphics.LinearGradient; 77 import android.graphics.Matrix; 78 import android.graphics.Outline; 79 import android.graphics.Paint; 80 import android.graphics.PixelFormat; 81 import android.graphics.Point; 82 import android.graphics.PorterDuff; 83 import android.graphics.PorterDuffXfermode; 84 import android.graphics.RecordingCanvas; 85 import android.graphics.Rect; 86 import android.graphics.RectF; 87 import android.graphics.Region; 88 import android.graphics.RenderEffect; 89 import android.graphics.RenderNode; 90 import android.graphics.Shader; 91 import android.graphics.drawable.ColorDrawable; 92 import android.graphics.drawable.Drawable; 93 import android.graphics.drawable.GradientDrawable; 94 import android.hardware.display.DisplayManagerGlobal; 95 import android.hardware.input.InputManager; 96 import android.net.Uri; 97 import android.os.Build; 98 import android.os.Bundle; 99 import android.os.Handler; 100 import android.os.IBinder; 101 import android.os.Message; 102 import android.os.Parcel; 103 import android.os.Parcelable; 104 import android.os.RemoteCallback; 105 import android.os.RemoteException; 106 import android.os.SystemClock; 107 import android.os.Trace; 108 import android.sysprop.DisplayProperties; 109 import android.text.InputType; 110 import android.text.TextUtils; 111 import android.util.AttributeSet; 112 import android.util.FloatProperty; 113 import android.util.LayoutDirection; 114 import android.util.Log; 115 import android.util.LongSparseArray; 116 import android.util.LongSparseLongArray; 117 import android.util.Pair; 118 import android.util.Pools.SynchronizedPool; 119 import android.util.Property; 120 import android.util.SparseArray; 121 import android.util.SparseIntArray; 122 import android.util.StateSet; 123 import android.util.SuperNotCalledException; 124 import android.util.TypedValue; 125 import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 126 import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 127 import android.view.AccessibilityIterators.TextSegmentIterator; 128 import android.view.AccessibilityIterators.WordTextSegmentIterator; 129 import android.view.ContextMenu.ContextMenuInfo; 130 import android.view.InputDevice.InputSourceClass; 131 import android.view.Window.OnContentApplyWindowInsetsListener; 132 import android.view.WindowInsets.Type; 133 import android.view.WindowInsetsAnimation.Bounds; 134 import android.view.WindowManager.LayoutParams; 135 import android.view.accessibility.AccessibilityEvent; 136 import android.view.accessibility.AccessibilityEventSource; 137 import android.view.accessibility.AccessibilityManager; 138 import android.view.accessibility.AccessibilityNodeIdManager; 139 import android.view.accessibility.AccessibilityNodeInfo; 140 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 141 import android.view.accessibility.AccessibilityNodeProvider; 142 import android.view.accessibility.AccessibilityWindowInfo; 143 import android.view.animation.Animation; 144 import android.view.animation.AnimationUtils; 145 import android.view.animation.Transformation; 146 import android.view.autofill.AutofillId; 147 import android.view.autofill.AutofillManager; 148 import android.view.autofill.AutofillValue; 149 import android.view.contentcapture.ContentCaptureContext; 150 import android.view.contentcapture.ContentCaptureManager; 151 import android.view.contentcapture.ContentCaptureSession; 152 import android.view.displayhash.DisplayHash; 153 import android.view.displayhash.DisplayHashManager; 154 import android.view.displayhash.DisplayHashResultCallback; 155 import android.view.inputmethod.EditorInfo; 156 import android.view.inputmethod.InputConnection; 157 import android.view.inputmethod.InputMethodManager; 158 import android.view.inspector.InspectableProperty; 159 import android.view.inspector.InspectableProperty.EnumEntry; 160 import android.view.inspector.InspectableProperty.FlagEntry; 161 import android.view.translation.TranslationCapability; 162 import android.view.translation.TranslationSpec.DataFormat; 163 import android.view.translation.ViewTranslationCallback; 164 import android.view.translation.ViewTranslationRequest; 165 import android.view.translation.ViewTranslationResponse; 166 import android.widget.Checkable; 167 import android.widget.FrameLayout; 168 import android.widget.ScrollBarDrawable; 169 import android.window.OnBackInvokedDispatcher; 170 171 import com.android.internal.R; 172 import com.android.internal.util.ArrayUtils; 173 import com.android.internal.util.FrameworkStatsLog; 174 import com.android.internal.util.Preconditions; 175 import com.android.internal.view.ScrollCaptureInternal; 176 import com.android.internal.view.TooltipPopup; 177 import com.android.internal.view.menu.MenuBuilder; 178 import com.android.internal.widget.ScrollBarUtils; 179 180 import com.google.android.collect.Lists; 181 import com.google.android.collect.Maps; 182 183 import java.io.PrintWriter; 184 import java.lang.annotation.Retention; 185 import java.lang.annotation.RetentionPolicy; 186 import java.lang.ref.WeakReference; 187 import java.lang.reflect.Field; 188 import java.lang.reflect.InvocationTargetException; 189 import java.lang.reflect.Method; 190 import java.lang.reflect.Modifier; 191 import java.util.ArrayList; 192 import java.util.Arrays; 193 import java.util.Calendar; 194 import java.util.Collection; 195 import java.util.Collections; 196 import java.util.HashMap; 197 import java.util.List; 198 import java.util.Locale; 199 import java.util.Map; 200 import java.util.concurrent.CopyOnWriteArrayList; 201 import java.util.concurrent.Executor; 202 import java.util.concurrent.atomic.AtomicInteger; 203 import java.util.function.Consumer; 204 import java.util.function.Predicate; 205 206 /** 207 * <p> 208 * This class represents the basic building block for user interface components. A View 209 * occupies a rectangular area on the screen and is responsible for drawing and 210 * event handling. View is the base class for <em>widgets</em>, which are 211 * used to create interactive UI components (buttons, text fields, etc.). The 212 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 213 * are invisible containers that hold other Views (or other ViewGroups) and define 214 * their layout properties. 215 * </p> 216 * 217 * <div class="special reference"> 218 * <h3>Developer Guides</h3> 219 * <p>For information about using this class to develop your application's user interface, 220 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 221 * </div> 222 * 223 * <a name="Using"></a> 224 * <h3>Using Views</h3> 225 * <p> 226 * All of the views in a window are arranged in a single tree. You can add views 227 * either from code or by specifying a tree of views in one or more XML layout 228 * files. There are many specialized subclasses of views that act as controls or 229 * are capable of displaying text, images, or other content. 230 * </p> 231 * <p> 232 * Once you have created a tree of views, there are typically a few types of 233 * common operations you may wish to perform: 234 * <ul> 235 * <li><strong>Set properties:</strong> for example setting the text of a 236 * {@link android.widget.TextView}. The available properties and the methods 237 * that set them will vary among the different subclasses of views. Note that 238 * properties that are known at build time can be set in the XML layout 239 * files.</li> 240 * <li><strong>Set focus:</strong> The framework will handle moving focus in 241 * response to user input. To force focus to a specific view, call 242 * {@link #requestFocus}.</li> 243 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 244 * that will be notified when something interesting happens to the view. For 245 * example, all views will let you set a listener to be notified when the view 246 * gains or loses focus. You can register such a listener using 247 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 248 * Other view subclasses offer more specialized listeners. For example, a Button 249 * exposes a listener to notify clients when the button is clicked.</li> 250 * <li><strong>Set visibility:</strong> You can hide or show views using 251 * {@link #setVisibility(int)}.</li> 252 * </ul> 253 * </p> 254 * <p><em> 255 * Note: The Android framework is responsible for measuring, laying out and 256 * drawing views. You should not call methods that perform these actions on 257 * views yourself unless you are actually implementing a 258 * {@link android.view.ViewGroup}. 259 * </em></p> 260 * 261 * <a name="Lifecycle"></a> 262 * <h3>Implementing a Custom View</h3> 263 * 264 * <p> 265 * To implement a custom view, you will usually begin by providing overrides for 266 * some of the standard methods that the framework calls on all views. You do 267 * not need to override all of these methods. In fact, you can start by just 268 * overriding {@link #onDraw(android.graphics.Canvas)}. 269 * <table border="2" width="85%" align="center" cellpadding="5"> 270 * <thead> 271 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 272 * </thead> 273 * 274 * <tbody> 275 * <tr> 276 * <td rowspan="2">Creation</td> 277 * <td>Constructors</td> 278 * <td>There is a form of the constructor that are called when the view 279 * is created from code and a form that is called when the view is 280 * inflated from a layout file. The second form should parse and apply 281 * any attributes defined in the layout file. 282 * </td> 283 * </tr> 284 * <tr> 285 * <td><code>{@link #onFinishInflate()}</code></td> 286 * <td>Called after a view and all of its children has been inflated 287 * from XML.</td> 288 * </tr> 289 * 290 * <tr> 291 * <td rowspan="3">Layout</td> 292 * <td><code>{@link #onMeasure(int, int)}</code></td> 293 * <td>Called to determine the size requirements for this view and all 294 * of its children. 295 * </td> 296 * </tr> 297 * <tr> 298 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 299 * <td>Called when this view should assign a size and position to all 300 * of its children. 301 * </td> 302 * </tr> 303 * <tr> 304 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 305 * <td>Called when the size of this view has changed. 306 * </td> 307 * </tr> 308 * 309 * <tr> 310 * <td>Drawing</td> 311 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 312 * <td>Called when the view should render its content. 313 * </td> 314 * </tr> 315 * 316 * <tr> 317 * <td rowspan="6">Event processing</td> 318 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 319 * <td>Called when a new hardware key event occurs. 320 * </td> 321 * </tr> 322 * <tr> 323 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 324 * <td>Called when a hardware key up event occurs. 325 * </td> 326 * </tr> 327 * <tr> 328 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 329 * <td>Called when a trackball motion event occurs. 330 * </td> 331 * </tr> 332 * <tr> 333 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 334 * <td>Called when a touch screen motion event occurs. 335 * </td> 336 * </tr> 337 * <tr> 338 * <td><code>{@link #onGenericMotionEvent(MotionEvent)}</code></td> 339 * <td>Called when a generic motion event occurs. 340 * </td> 341 * </tr> 342 * <tr> 343 * <td><code>{@link #onHoverEvent(MotionEvent)}</code></td> 344 * <td>Called when a hover motion event occurs. 345 * </td> 346 * </tr> 347 * 348 * <tr> 349 * <td rowspan="2">Focus</td> 350 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 351 * <td>Called when the view gains or loses focus. 352 * </td> 353 * </tr> 354 * 355 * <tr> 356 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 357 * <td>Called when the window containing the view gains or loses focus. 358 * </td> 359 * </tr> 360 * 361 * <tr> 362 * <td rowspan="3">Attaching</td> 363 * <td><code>{@link #onAttachedToWindow()}</code></td> 364 * <td>Called when the view is attached to a window. 365 * </td> 366 * </tr> 367 * 368 * <tr> 369 * <td><code>{@link #onDetachedFromWindow}</code></td> 370 * <td>Called when the view is detached from its window. 371 * </td> 372 * </tr> 373 * 374 * <tr> 375 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 376 * <td>Called when the visibility of the window containing the view 377 * has changed. 378 * </td> 379 * </tr> 380 * </tbody> 381 * 382 * </table> 383 * </p> 384 * 385 * <a name="IDs"></a> 386 * <h3>IDs</h3> 387 * Views may have an integer id associated with them. These ids are typically 388 * assigned in the layout XML files, and are used to find specific views within 389 * the view tree. A common pattern is to: 390 * <ul> 391 * <li>Define a Button in the layout file and assign it a unique ID. 392 * <pre> 393 * <Button 394 * android:id="@+id/my_button" 395 * android:layout_width="wrap_content" 396 * android:layout_height="wrap_content" 397 * android:text="@string/my_button_text"/> 398 * </pre></li> 399 * <li>From the onCreate method of an Activity, find the Button 400 * <pre class="prettyprint"> 401 * Button myButton = findViewById(R.id.my_button); 402 * </pre></li> 403 * </ul> 404 * <p> 405 * View IDs need not be unique throughout the tree, but it is good practice to 406 * ensure that they are at least unique within the part of the tree you are 407 * searching. 408 * </p> 409 * 410 * <a name="Position"></a> 411 * <h3>Position</h3> 412 * <p> 413 * The geometry of a view is that of a rectangle. A view has a location, 414 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 415 * two dimensions, expressed as a width and a height. The unit for location 416 * and dimensions is the pixel. 417 * </p> 418 * 419 * <p> 420 * It is possible to retrieve the location of a view by invoking the methods 421 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 422 * coordinate of the rectangle representing the view. The latter returns the 423 * top, or Y, coordinate of the rectangle representing the view. These methods 424 * both return the location of the view relative to its parent. For instance, 425 * when getLeft() returns 20, that means the view is located 20 pixels to the 426 * right of the left edge of its direct parent. 427 * </p> 428 * 429 * <p> 430 * In addition, several convenience methods are offered to avoid unnecessary 431 * computations, namely {@link #getRight()} and {@link #getBottom()}. 432 * These methods return the coordinates of the right and bottom edges of the 433 * rectangle representing the view. For instance, calling {@link #getRight()} 434 * is similar to the following computation: <code>getLeft() + getWidth()</code> 435 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 436 * </p> 437 * 438 * <a name="SizePaddingMargins"></a> 439 * <h3>Size, padding and margins</h3> 440 * <p> 441 * The size of a view is expressed with a width and a height. A view actually 442 * possess two pairs of width and height values. 443 * </p> 444 * 445 * <p> 446 * The first pair is known as <em>measured width</em> and 447 * <em>measured height</em>. These dimensions define how big a view wants to be 448 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 449 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 450 * and {@link #getMeasuredHeight()}. 451 * </p> 452 * 453 * <p> 454 * The second pair is simply known as <em>width</em> and <em>height</em>, or 455 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 456 * dimensions define the actual size of the view on screen, at drawing time and 457 * after layout. These values may, but do not have to, be different from the 458 * measured width and height. The width and height can be obtained by calling 459 * {@link #getWidth()} and {@link #getHeight()}. 460 * </p> 461 * 462 * <p> 463 * To measure its dimensions, a view takes into account its padding. The padding 464 * is expressed in pixels for the left, top, right and bottom parts of the view. 465 * Padding can be used to offset the content of the view by a specific amount of 466 * pixels. For instance, a left padding of 2 will push the view's content by 467 * 2 pixels to the right of the left edge. Padding can be set using the 468 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 469 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 470 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 471 * {@link #getPaddingEnd()}. 472 * </p> 473 * 474 * <p> 475 * Even though a view can define a padding, it does not provide any support for 476 * margins. However, view groups provide such a support. Refer to 477 * {@link android.view.ViewGroup} and 478 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 479 * </p> 480 * 481 * <a name="Layout"></a> 482 * <h3>Layout</h3> 483 * <p> 484 * Layout is a two pass process: a measure pass and a layout pass. The measuring 485 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 486 * of the view tree. Each view pushes dimension specifications down the tree 487 * during the recursion. At the end of the measure pass, every view has stored 488 * its measurements. The second pass happens in 489 * {@link #layout(int,int,int,int)} and is also top-down. During 490 * this pass each parent is responsible for positioning all of its children 491 * using the sizes computed in the measure pass. 492 * </p> 493 * 494 * <p> 495 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 496 * {@link #getMeasuredHeight()} values must be set, along with those for all of 497 * that view's descendants. A view's measured width and measured height values 498 * must respect the constraints imposed by the view's parents. This guarantees 499 * that at the end of the measure pass, all parents accept all of their 500 * children's measurements. A parent view may call measure() more than once on 501 * its children. For example, the parent may measure each child once with 502 * unspecified dimensions to find out how big they want to be, then call 503 * measure() on them again with actual numbers if the sum of all the children's 504 * unconstrained sizes is too big or too small. 505 * </p> 506 * 507 * <p> 508 * The measure pass uses two classes to communicate dimensions. The 509 * {@link MeasureSpec} class is used by views to tell their parents how they 510 * want to be measured and positioned. The base LayoutParams class just 511 * describes how big the view wants to be for both width and height. For each 512 * dimension, it can specify one of: 513 * <ul> 514 * <li> an exact number 515 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 516 * (minus padding) 517 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 518 * enclose its content (plus padding). 519 * </ul> 520 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 521 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 522 * an X and Y value. 523 * </p> 524 * 525 * <p> 526 * MeasureSpecs are used to push requirements down the tree from parent to 527 * child. A MeasureSpec can be in one of three modes: 528 * <ul> 529 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 530 * of a child view. For example, a LinearLayout may call measure() on its child 531 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 532 * tall the child view wants to be given a width of 240 pixels. 533 * <li>EXACTLY: This is used by the parent to impose an exact size on the 534 * child. The child must use this size, and guarantee that all of its 535 * descendants will fit within this size. 536 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 537 * child. The child must guarantee that it and all of its descendants will fit 538 * within this size. 539 * </ul> 540 * </p> 541 * 542 * <p> 543 * To initiate a layout, call {@link #requestLayout}. This method is typically 544 * called by a view on itself when it believes that it can no longer fit within 545 * its current bounds. 546 * </p> 547 * 548 * <a name="Drawing"></a> 549 * <h3>Drawing</h3> 550 * <p> 551 * Drawing is handled by walking the tree and recording the drawing commands of 552 * any View that needs to update. After this, the drawing commands of the 553 * entire tree are issued to screen, clipped to the newly damaged area. 554 * </p> 555 * 556 * <p> 557 * The tree is largely recorded and drawn in order, with parents drawn before 558 * (i.e., behind) their children, with siblings drawn in the order they appear 559 * in the tree. If you set a background drawable for a View, then the View will 560 * draw it before calling back to its <code>onDraw()</code> method. The child 561 * drawing order can be overridden with 562 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 563 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 564 * </p> 565 * 566 * <p> 567 * To force a view to draw, call {@link #invalidate()}. 568 * </p> 569 * 570 * <a name="EventHandlingThreading"></a> 571 * <h3>Event Handling and Threading</h3> 572 * <p> 573 * The basic cycle of a view is as follows: 574 * <ol> 575 * <li>An event comes in and is dispatched to the appropriate view. The view 576 * handles the event and notifies any listeners.</li> 577 * <li>If in the course of processing the event, the view's bounds may need 578 * to be changed, the view will call {@link #requestLayout()}.</li> 579 * <li>Similarly, if in the course of processing the event the view's appearance 580 * may need to be changed, the view will call {@link #invalidate()}.</li> 581 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 582 * the framework will take care of measuring, laying out, and drawing the tree 583 * as appropriate.</li> 584 * </ol> 585 * </p> 586 * 587 * <p><em>Note: The entire view tree is single threaded. You must always be on 588 * the UI thread when calling any method on any view.</em> 589 * If you are doing work on other threads and want to update the state of a view 590 * from that thread, you should use a {@link Handler}. 591 * </p> 592 * 593 * <a name="FocusHandling"></a> 594 * <h3>Focus Handling</h3> 595 * <p> 596 * The framework will handle routine focus movement in response to user input. 597 * This includes changing the focus as views are removed or hidden, or as new 598 * views become available. Views indicate their willingness to take focus 599 * through the {@link #isFocusable} method. To change whether a view can take 600 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 601 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 602 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 603 * </p> 604 * <p> 605 * Focus movement is based on an algorithm which finds the nearest neighbor in a 606 * given direction. In rare cases, the default algorithm may not match the 607 * intended behavior of the developer. In these situations, you can provide 608 * explicit overrides by using these XML attributes in the layout file: 609 * <pre> 610 * nextFocusDown 611 * nextFocusLeft 612 * nextFocusRight 613 * nextFocusUp 614 * </pre> 615 * </p> 616 * 617 * 618 * <p> 619 * To get a particular view to take focus, call {@link #requestFocus()}. 620 * </p> 621 * 622 * <a name="TouchMode"></a> 623 * <h3>Touch Mode</h3> 624 * <p> 625 * When a user is navigating a user interface via directional keys such as a D-pad, it is 626 * necessary to give focus to actionable items such as buttons so the user can see 627 * what will take input. If the device has touch capabilities, however, and the user 628 * begins interacting with the interface by touching it, it is no longer necessary to 629 * always highlight, or give focus to, a particular view. This motivates a mode 630 * for interaction named 'touch mode'. 631 * </p> 632 * <p> 633 * For a touch capable device, once the user touches the screen, the device 634 * will enter touch mode. From this point onward, only views for which 635 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 636 * Other views that are touchable, like buttons, will not take focus when touched; they will 637 * only fire the on click listeners. 638 * </p> 639 * <p> 640 * Any time a user hits a directional key, such as a D-pad direction, the view device will 641 * exit touch mode, and find a view to take focus, so that the user may resume interacting 642 * with the user interface without touching the screen again. 643 * </p> 644 * <p> 645 * The touch mode state is maintained across {@link android.app.Activity}s. Call 646 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 647 * </p> 648 * 649 * <a name="Scrolling"></a> 650 * <h3>Scrolling</h3> 651 * <p> 652 * The framework provides basic support for views that wish to internally 653 * scroll their content. This includes keeping track of the X and Y scroll 654 * offset as well as mechanisms for drawing scrollbars. See 655 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 656 * {@link #awakenScrollBars()} for more details. 657 * </p> 658 * 659 * <a name="Tags"></a> 660 * <h3>Tags</h3> 661 * <p> 662 * Unlike IDs, tags are not used to identify views. Tags are essentially an 663 * extra piece of information that can be associated with a view. They are most 664 * often used as a convenience to store data related to views in the views 665 * themselves rather than by putting them in a separate structure. 666 * </p> 667 * <p> 668 * Tags may be specified with character sequence values in layout XML as either 669 * a single tag using the {@link android.R.styleable#View_tag android:tag} 670 * attribute or multiple tags using the {@code <tag>} child element: 671 * <pre> 672 * <View ... 673 * android:tag="@string/mytag_value" /> 674 * <View ...> 675 * <tag android:id="@+id/mytag" 676 * android:value="@string/mytag_value" /> 677 * </View> 678 * </pre> 679 * </p> 680 * <p> 681 * Tags may also be specified with arbitrary objects from code using 682 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 683 * </p> 684 * 685 * <a name="Themes"></a> 686 * <h3>Themes</h3> 687 * <p> 688 * By default, Views are created using the theme of the Context object supplied 689 * to their constructor; however, a different theme may be specified by using 690 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 691 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 692 * code. 693 * </p> 694 * <p> 695 * When the {@link android.R.styleable#View_theme android:theme} attribute is 696 * used in XML, the specified theme is applied on top of the inflation 697 * context's theme (see {@link LayoutInflater}) and used for the view itself as 698 * well as any child elements. 699 * </p> 700 * <p> 701 * In the following example, both views will be created using the Material dark 702 * color scheme; however, because an overlay theme is used which only defines a 703 * subset of attributes, the value of 704 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 705 * the inflation context's theme (e.g. the Activity theme) will be preserved. 706 * <pre> 707 * <LinearLayout 708 * ... 709 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 710 * <View ...> 711 * </LinearLayout> 712 * </pre> 713 * </p> 714 * 715 * <a name="Properties"></a> 716 * <h3>Properties</h3> 717 * <p> 718 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 719 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 720 * available both in the {@link Property} form as well as in similarly-named setter/getter 721 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 722 * be used to set persistent state associated with these rendering-related properties on the view. 723 * The properties and methods can also be used in conjunction with 724 * {@link android.animation.Animator Animator}-based animations, described more in the 725 * <a href="#Animation">Animation</a> section. 726 * </p> 727 * 728 * <a name="Animation"></a> 729 * <h3>Animation</h3> 730 * <p> 731 * Starting with Android 3.0, the preferred way of animating views is to use the 732 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 733 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 734 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 735 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 736 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 737 * makes animating these View properties particularly easy and efficient. 738 * </p> 739 * <p> 740 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 741 * You can attach an {@link Animation} object to a view using 742 * {@link #setAnimation(Animation)} or 743 * {@link #startAnimation(Animation)}. The animation can alter the scale, 744 * rotation, translation and alpha of a view over time. If the animation is 745 * attached to a view that has children, the animation will affect the entire 746 * subtree rooted by that node. When an animation is started, the framework will 747 * take care of redrawing the appropriate views until the animation completes. 748 * </p> 749 * 750 * <a name="Security"></a> 751 * <h3>Security</h3> 752 * <p> 753 * Sometimes it is essential that an application be able to verify that an action 754 * is being performed with the full knowledge and consent of the user, such as 755 * granting a permission request, making a purchase or clicking on an advertisement. 756 * Unfortunately, a malicious application could try to spoof the user into 757 * performing these actions, unaware, by concealing the intended purpose of the view. 758 * As a remedy, the framework offers a touch filtering mechanism that can be used to 759 * improve the security of views that provide access to sensitive functionality. 760 * </p><p> 761 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 762 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 763 * will discard touches that are received whenever the view's window is obscured by 764 * another visible window at the touched location. As a result, the view will not receive touches 765 * whenever the touch passed through a toast, dialog or other window that appears above the view's 766 * window. 767 * </p><p> 768 * For more fine-grained control over security, consider overriding the 769 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 770 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 771 * </p> 772 * 773 * @attr ref android.R.styleable#View_accessibilityHeading 774 * @attr ref android.R.styleable#View_allowClickWhenDisabled 775 * @attr ref android.R.styleable#View_alpha 776 * @attr ref android.R.styleable#View_background 777 * @attr ref android.R.styleable#View_clickable 778 * @attr ref android.R.styleable#View_clipToOutline 779 * @attr ref android.R.styleable#View_contentDescription 780 * @attr ref android.R.styleable#View_drawingCacheQuality 781 * @attr ref android.R.styleable#View_duplicateParentState 782 * @attr ref android.R.styleable#View_id 783 * @attr ref android.R.styleable#View_requiresFadingEdge 784 * @attr ref android.R.styleable#View_fadeScrollbars 785 * @attr ref android.R.styleable#View_fadingEdgeLength 786 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 787 * @attr ref android.R.styleable#View_fitsSystemWindows 788 * @attr ref android.R.styleable#View_isScrollContainer 789 * @attr ref android.R.styleable#View_focusable 790 * @attr ref android.R.styleable#View_focusableInTouchMode 791 * @attr ref android.R.styleable#View_focusedByDefault 792 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 793 * @attr ref android.R.styleable#View_keepScreenOn 794 * @attr ref android.R.styleable#View_keyboardNavigationCluster 795 * @attr ref android.R.styleable#View_layerType 796 * @attr ref android.R.styleable#View_layoutDirection 797 * @attr ref android.R.styleable#View_longClickable 798 * @attr ref android.R.styleable#View_minHeight 799 * @attr ref android.R.styleable#View_minWidth 800 * @attr ref android.R.styleable#View_nextClusterForward 801 * @attr ref android.R.styleable#View_nextFocusDown 802 * @attr ref android.R.styleable#View_nextFocusLeft 803 * @attr ref android.R.styleable#View_nextFocusRight 804 * @attr ref android.R.styleable#View_nextFocusUp 805 * @attr ref android.R.styleable#View_onClick 806 * @attr ref android.R.styleable#View_outlineSpotShadowColor 807 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 808 * @attr ref android.R.styleable#View_padding 809 * @attr ref android.R.styleable#View_paddingHorizontal 810 * @attr ref android.R.styleable#View_paddingVertical 811 * @attr ref android.R.styleable#View_paddingBottom 812 * @attr ref android.R.styleable#View_paddingLeft 813 * @attr ref android.R.styleable#View_paddingRight 814 * @attr ref android.R.styleable#View_paddingTop 815 * @attr ref android.R.styleable#View_paddingStart 816 * @attr ref android.R.styleable#View_paddingEnd 817 * @attr ref android.R.styleable#View_saveEnabled 818 * @attr ref android.R.styleable#View_rotation 819 * @attr ref android.R.styleable#View_rotationX 820 * @attr ref android.R.styleable#View_rotationY 821 * @attr ref android.R.styleable#View_scaleX 822 * @attr ref android.R.styleable#View_scaleY 823 * @attr ref android.R.styleable#View_scrollX 824 * @attr ref android.R.styleable#View_scrollY 825 * @attr ref android.R.styleable#View_scrollbarSize 826 * @attr ref android.R.styleable#View_scrollbarStyle 827 * @attr ref android.R.styleable#View_scrollbars 828 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 829 * @attr ref android.R.styleable#View_scrollbarFadeDuration 830 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 831 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 832 * @attr ref android.R.styleable#View_scrollbarThumbVertical 833 * @attr ref android.R.styleable#View_scrollbarTrackVertical 834 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 835 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 836 * @attr ref android.R.styleable#View_stateListAnimator 837 * @attr ref android.R.styleable#View_transitionName 838 * @attr ref android.R.styleable#View_soundEffectsEnabled 839 * @attr ref android.R.styleable#View_tag 840 * @attr ref android.R.styleable#View_textAlignment 841 * @attr ref android.R.styleable#View_textDirection 842 * @attr ref android.R.styleable#View_transformPivotX 843 * @attr ref android.R.styleable#View_transformPivotY 844 * @attr ref android.R.styleable#View_translationX 845 * @attr ref android.R.styleable#View_translationY 846 * @attr ref android.R.styleable#View_translationZ 847 * @attr ref android.R.styleable#View_visibility 848 * @attr ref android.R.styleable#View_theme 849 * 850 * @see android.view.ViewGroup 851 */ 852 @UiThread 853 public class View implements Drawable.Callback, KeyEvent.Callback, 854 AccessibilityEventSource { 855 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 856 private static final boolean DBG = false; 857 858 /** @hide */ 859 public static boolean DEBUG_DRAW = false; 860 861 /** 862 * The logging tag used by this class with android.util.Log. 863 */ 864 protected static final String VIEW_LOG_TAG = "View"; 865 866 /** 867 * The logging tag used by this class when logging verbose, autofill-related messages. 868 */ 869 // NOTE: We cannot use android.view.autofill.Helper.sVerbose because that variable is not 870 // set if a session is not started. 871 private static final String AUTOFILL_LOG_TAG = "View.Autofill"; 872 873 /** 874 * The logging tag used by this class when logging content capture-related messages. 875 */ 876 private static final String CONTENT_CAPTURE_LOG_TAG = "View.ContentCapture"; 877 878 private static final boolean DEBUG_CONTENT_CAPTURE = false; 879 880 /** 881 * When set to true, this view will save its attribute data. 882 * 883 * @hide 884 */ 885 public static boolean sDebugViewAttributes = false; 886 887 /** 888 * When set to this application package view will save its attribute data. 889 * 890 * @hide 891 */ 892 public static String sDebugViewAttributesApplicationPackage; 893 894 /** 895 * Used to mark a View that has no ID. 896 */ 897 public static final int NO_ID = -1; 898 899 /** 900 * Last ID that is given to Views that are no part of activities. 901 * 902 * {@hide} 903 */ 904 public static final int LAST_APP_AUTOFILL_ID = Integer.MAX_VALUE / 2; 905 906 /** 907 * Attribute to find the autofilled highlight 908 * 909 * @see #getAutofilledDrawable() 910 */ 911 private static final int[] AUTOFILL_HIGHLIGHT_ATTR = 912 new int[]{android.R.attr.autofilledHighlight}; 913 914 /** 915 * Signals that compatibility booleans have been initialized according to 916 * target SDK versions. 917 */ 918 private static boolean sCompatibilityDone = false; 919 920 /** 921 * Use the old (broken) way of building MeasureSpecs. 922 */ 923 private static boolean sUseBrokenMakeMeasureSpec = false; 924 925 /** 926 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 927 */ 928 static boolean sUseZeroUnspecifiedMeasureSpec = false; 929 930 /** 931 * Ignore any optimizations using the measure cache. 932 */ 933 private static boolean sIgnoreMeasureCache = false; 934 935 /** 936 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 937 */ 938 private static boolean sAlwaysRemeasureExactly = false; 939 940 /** 941 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 942 * without throwing 943 */ 944 static boolean sTextureViewIgnoresDrawableSetters = false; 945 946 /** 947 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 948 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 949 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 950 * check is implemented for backwards compatibility. 951 * 952 * {@hide} 953 */ 954 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 955 956 /** 957 * Prior to N, when drag enters into child of a view that has already received an 958 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 959 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 960 * false from its event handler for these events. 961 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 962 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 963 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 964 */ 965 static boolean sCascadedDragDrop; 966 967 /** 968 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 969 * to determine things like whether or not to permit item click events. We can't break 970 * apps that do this just because more things (clickable things) are now auto-focusable 971 * and they would get different results, so give old behavior to old apps. 972 */ 973 static boolean sHasFocusableExcludeAutoFocusable; 974 975 /** 976 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 977 * made focusable by default. As a result, apps could (incorrectly) change the clickable 978 * setting of views off the UI thread. Now that clickable can effect the focusable state, 979 * changing the clickable attribute off the UI thread will cause an exception (since changing 980 * the focusable state checks). In order to prevent apps from crashing, we will handle this 981 * specific case and just not notify parents on new focusables resulting from marking views 982 * clickable from outside the UI thread. 983 */ 984 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 985 986 /** 987 * Prior to P things like setScaleX() allowed passing float values that were bogus such as 988 * Float.NaN. If the app is targetting P or later then passing these values will result in an 989 * exception being thrown. If the app is targetting an earlier SDK version, then we will 990 * silently clamp these values to avoid crashes elsewhere when the rendering code hits 991 * these bogus values. 992 */ 993 private static boolean sThrowOnInvalidFloatProperties; 994 995 /** 996 * Prior to P, {@code #startDragAndDrop} accepts a builder which produces an empty drag shadow. 997 * Currently zero size SurfaceControl cannot be created thus we create a 1x1 surface instead. 998 */ 999 private static boolean sAcceptZeroSizeDragShadow; 1000 1001 /** 1002 * When true, measure and layout passes of all the newly attached views will be logged with 1003 * {@link Trace}, so we can better debug jank due to complex view hierarchies. 1004 */ 1005 private static boolean sTraceLayoutSteps; 1006 1007 /** 1008 * When not null, emits a {@link Trace} instant event and the stacktrace every time a relayout 1009 * of a class having this name happens. 1010 */ 1011 private static String sTraceRequestLayoutClass; 1012 1013 /** Used to avoid computing the full strings each time when layout tracing is enabled. */ 1014 @Nullable 1015 private ViewTraversalTracingStrings mTracingStrings; 1016 1017 /** 1018 * Prior to R, {@link #dispatchApplyWindowInsets} had an issue: 1019 * <p>The modified insets changed by {@link #onApplyWindowInsets} were passed to the 1020 * entire view hierarchy in prefix order, including siblings as well as siblings of parents 1021 * further down the hierarchy. This violates the basic concepts of the view hierarchy, and 1022 * thus, the hierarchical dispatching mechanism was hard to use for apps. 1023 * <p> 1024 * In order to make window inset dispatching work properly, we dispatch window insets 1025 * in the view hierarchy in a proper hierarchical manner if this flag is set to {@code false}. 1026 */ 1027 static boolean sBrokenInsetsDispatch; 1028 1029 /** 1030 * Prior to Q, calling 1031 * {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} 1032 * did not call update the window format so the opacity of the background was not correctly 1033 * applied to the window. Some applications rely on this misbehavior to work properly. 1034 * <p> 1035 * From Q, {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} is 1036 * the same as {@link com.android.internal.policy.DecorView#setWindowBackground(Drawable)} 1037 * which updates the window format. 1038 * @hide 1039 */ 1040 protected static boolean sBrokenWindowBackground; 1041 1042 /** 1043 * Prior to R, we were always forcing a layout of the entire hierarchy when insets changed from 1044 * the server. This is inefficient and not all apps use it. Instead, we want to rely on apps 1045 * calling {@link #requestLayout} when they need to relayout based on an insets change. 1046 */ 1047 static boolean sForceLayoutWhenInsetsChanged; 1048 1049 /** @hide */ 1050 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 1051 @Retention(RetentionPolicy.SOURCE) 1052 public @interface Focusable {} 1053 1054 /** 1055 * This view does not want keystrokes. 1056 * <p> 1057 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1058 * android:focusable}. 1059 */ 1060 public static final int NOT_FOCUSABLE = 0x00000000; 1061 1062 /** 1063 * This view wants keystrokes. 1064 * <p> 1065 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1066 * android:focusable}. 1067 */ 1068 public static final int FOCUSABLE = 0x00000001; 1069 1070 /** 1071 * This view determines focusability automatically. This is the default. 1072 * <p> 1073 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1074 * android:focusable}. 1075 */ 1076 public static final int FOCUSABLE_AUTO = 0x00000010; 1077 1078 /** 1079 * Mask for use with setFlags indicating bits used for focus. 1080 */ 1081 private static final int FOCUSABLE_MASK = 0x00000011; 1082 1083 /** 1084 * This view will adjust its padding to fit sytem windows (e.g. status bar) 1085 */ 1086 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 1087 1088 /** @hide */ 1089 @IntDef({VISIBLE, INVISIBLE, GONE}) 1090 @Retention(RetentionPolicy.SOURCE) 1091 public @interface Visibility {} 1092 1093 /** 1094 * This view is visible. 1095 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1096 * android:visibility}. 1097 */ 1098 public static final int VISIBLE = 0x00000000; 1099 1100 /** 1101 * This view is invisible, but it still takes up space for layout purposes. 1102 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1103 * android:visibility}. 1104 */ 1105 public static final int INVISIBLE = 0x00000004; 1106 1107 /** 1108 * This view is invisible, and it doesn't take any space for layout 1109 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1110 * android:visibility}. 1111 */ 1112 public static final int GONE = 0x00000008; 1113 1114 /** 1115 * Mask for use with setFlags indicating bits used for visibility. 1116 * {@hide} 1117 */ 1118 static final int VISIBILITY_MASK = 0x0000000C; 1119 1120 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 1121 1122 /** 1123 * Hint indicating that this view can be autofilled with an email address. 1124 * 1125 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1126 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1127 * value should be <code>{@value #AUTOFILL_HINT_EMAIL_ADDRESS}</code>). 1128 * 1129 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1130 */ 1131 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 1132 1133 /** 1134 * Hint indicating that this view can be autofilled with a user's real name. 1135 * 1136 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1137 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1138 * value should be <code>{@value #AUTOFILL_HINT_NAME}</code>). 1139 * 1140 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1141 */ 1142 public static final String AUTOFILL_HINT_NAME = "name"; 1143 1144 /** 1145 * Hint indicating that this view can be autofilled with a username. 1146 * 1147 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1148 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1149 * value should be <code>{@value #AUTOFILL_HINT_USERNAME}</code>). 1150 * 1151 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1152 */ 1153 public static final String AUTOFILL_HINT_USERNAME = "username"; 1154 1155 /** 1156 * Hint indicating that this view can be autofilled with a password. 1157 * 1158 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1159 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1160 * value should be <code>{@value #AUTOFILL_HINT_PASSWORD}</code>). 1161 * 1162 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1163 */ 1164 public static final String AUTOFILL_HINT_PASSWORD = "password"; 1165 1166 /** 1167 * Hint indicating that this view can be autofilled with a phone number. 1168 * 1169 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1170 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1171 * value should be <code>{@value #AUTOFILL_HINT_PHONE}</code>). 1172 * 1173 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1174 */ 1175 public static final String AUTOFILL_HINT_PHONE = "phone"; 1176 1177 /** 1178 * Hint indicating that this view can be autofilled with a postal address. 1179 * 1180 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1181 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1182 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_ADDRESS}</code>). 1183 * 1184 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1185 */ 1186 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1187 1188 /** 1189 * Hint indicating that this view can be autofilled with a postal code. 1190 * 1191 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1192 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1193 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_CODE}</code>). 1194 * 1195 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1196 */ 1197 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1198 1199 /** 1200 * Hint indicating that this view can be autofilled with a credit card number. 1201 * 1202 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1203 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1204 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_NUMBER}</code>). 1205 * 1206 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1207 */ 1208 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1209 1210 /** 1211 * Hint indicating that this view can be autofilled with a credit card security code. 1212 * 1213 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1214 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1215 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}</code>). 1216 * 1217 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1218 */ 1219 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1220 1221 /** 1222 * Hint indicating that this view can be autofilled with a credit card expiration date. 1223 * 1224 * <p>It should be used when the credit card expiration date is represented by just one view; 1225 * if it is represented by more than one (for example, one view for the month and another view 1226 * for the year), then each of these views should use the hint specific for the unit 1227 * ({@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 1228 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 1229 * or {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}). 1230 * 1231 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1232 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1233 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}</code>). 1234 * 1235 * <p>When annotating a view with this hint, it's recommended to use a date autofill value to 1236 * avoid ambiguity when the autofill service provides a value for it. To understand why a 1237 * value can be ambiguous, consider "April of 2020", which could be represented as either of 1238 * the following options: 1239 * 1240 * <ul> 1241 * <li>{@code "04/2020"} 1242 * <li>{@code "4/2020"} 1243 * <li>{@code "2020/04"} 1244 * <li>{@code "2020/4"} 1245 * <li>{@code "April/2020"} 1246 * <li>{@code "Apr/2020"} 1247 * </ul> 1248 * 1249 * <p>You define a date autofill value for the view by overriding the following methods: 1250 * 1251 * <ol> 1252 * <li>{@link #getAutofillType()} to return {@link #AUTOFILL_TYPE_DATE}. 1253 * <li>{@link #getAutofillValue()} to return a 1254 * {@link AutofillValue#forDate(long) date autofillvalue}. 1255 * <li>{@link #autofill(AutofillValue)} to expect a data autofillvalue. 1256 * </ol> 1257 * 1258 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1259 */ 1260 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1261 "creditCardExpirationDate"; 1262 1263 /** 1264 * Hint indicating that this view can be autofilled with a credit card expiration month. 1265 * 1266 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1267 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1268 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}</code>). 1269 * 1270 * <p>When annotating a view with this hint, it's recommended to use a text autofill value 1271 * whose value is the numerical representation of the month, starting on {@code 1} to avoid 1272 * ambiguity when the autofill service provides a value for it. To understand why a 1273 * value can be ambiguous, consider "January", which could be represented as either of 1274 * 1275 * <ul> 1276 * <li>{@code "1"}: recommended way. 1277 * <li>{@code "0"}: if following the {@link Calendar#MONTH} convention. 1278 * <li>{@code "January"}: full name, in English. 1279 * <li>{@code "jan"}: abbreviated name, in English. 1280 * <li>{@code "Janeiro"}: full name, in another language. 1281 * </ul> 1282 * 1283 * <p>Another recommended approach is to use a date autofill value - see 1284 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE} for more details. 1285 * 1286 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1287 */ 1288 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1289 "creditCardExpirationMonth"; 1290 1291 /** 1292 * Hint indicating that this view can be autofilled with a credit card expiration year. 1293 * 1294 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1295 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1296 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}</code>). 1297 * 1298 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1299 */ 1300 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1301 "creditCardExpirationYear"; 1302 1303 /** 1304 * Hint indicating that this view can be autofilled with a credit card expiration day. 1305 * 1306 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1307 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1308 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}</code>). 1309 * 1310 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1311 */ 1312 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1313 1314 /** 1315 * A hint indicating that this view can be autofilled with a password. 1316 * 1317 * This is a heuristic-based hint that is meant to be used by UI Toolkit developers when a 1318 * view is a password field but doesn't specify a 1319 * <code>{@value View#AUTOFILL_HINT_PASSWORD}</code>. 1320 * @hide 1321 */ 1322 // TODO(229765029): unhide this for UI toolkit 1323 public static final String AUTOFILL_HINT_PASSWORD_AUTO = "passwordAuto"; 1324 1325 /** 1326 * Hints for the autofill services that describes the content of the view. 1327 */ 1328 private @Nullable String[] mAutofillHints; 1329 1330 /** 1331 * Autofill id, lazily created on calls to {@link #getAutofillId()}. 1332 */ 1333 private AutofillId mAutofillId; 1334 1335 /** @hide */ 1336 @IntDef(prefix = { "AUTOFILL_TYPE_" }, value = { 1337 AUTOFILL_TYPE_NONE, 1338 AUTOFILL_TYPE_TEXT, 1339 AUTOFILL_TYPE_TOGGLE, 1340 AUTOFILL_TYPE_LIST, 1341 AUTOFILL_TYPE_DATE, 1342 }) 1343 @Retention(RetentionPolicy.SOURCE) 1344 public @interface AutofillType {} 1345 1346 /** 1347 * Autofill type for views that cannot be autofilled. 1348 * 1349 * <p>Typically used when the view is read-only; for example, a text label. 1350 * 1351 * @see #getAutofillType() 1352 */ 1353 public static final int AUTOFILL_TYPE_NONE = 0; 1354 1355 /** 1356 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1357 * 1358 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1359 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1360 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1361 * 1362 * @see #getAutofillType() 1363 */ 1364 public static final int AUTOFILL_TYPE_TEXT = 1; 1365 1366 /** 1367 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1368 * 1369 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1370 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1371 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1372 * 1373 * @see #getAutofillType() 1374 */ 1375 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1376 1377 /** 1378 * Autofill type for a selection list field, which is filled by an {@code int} 1379 * representing the element index inside the list (starting at {@code 0}). 1380 * 1381 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1382 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1383 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1384 * 1385 * <p>The available options in the selection list are typically provided by 1386 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1387 * 1388 * @see #getAutofillType() 1389 */ 1390 public static final int AUTOFILL_TYPE_LIST = 3; 1391 1392 /** 1393 * Autofill type for a field that contains a date, which is represented by a long representing 1394 * the number of milliseconds since the standard base time known as "the epoch", namely 1395 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1396 * 1397 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1398 * {@link AutofillValue#forDate(long)}, and the values passed to 1399 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1400 * 1401 * @see #getAutofillType() 1402 */ 1403 public static final int AUTOFILL_TYPE_DATE = 4; 1404 1405 1406 /** @hide */ 1407 @IntDef(prefix = { "IMPORTANT_FOR_AUTOFILL_" }, value = { 1408 IMPORTANT_FOR_AUTOFILL_AUTO, 1409 IMPORTANT_FOR_AUTOFILL_YES, 1410 IMPORTANT_FOR_AUTOFILL_NO, 1411 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 1412 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 1413 }) 1414 @Retention(RetentionPolicy.SOURCE) 1415 public @interface AutofillImportance {} 1416 1417 /** 1418 * Automatically determine whether a view is important for autofill. 1419 * 1420 * @see #isImportantForAutofill() 1421 * @see #setImportantForAutofill(int) 1422 */ 1423 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1424 1425 /** 1426 * The view is important for autofill, and its children (if any) will be traversed. 1427 * 1428 * @see #isImportantForAutofill() 1429 * @see #setImportantForAutofill(int) 1430 */ 1431 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1432 1433 /** 1434 * The view is not important for autofill, but its children (if any) will be traversed. 1435 * 1436 * @see #isImportantForAutofill() 1437 * @see #setImportantForAutofill(int) 1438 */ 1439 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1440 1441 /** 1442 * The view is important for autofill, but its children (if any) will not be traversed. 1443 * 1444 * @see #isImportantForAutofill() 1445 * @see #setImportantForAutofill(int) 1446 */ 1447 public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; 1448 1449 /** 1450 * The view is not important for autofill, and its children (if any) will not be traversed. 1451 * 1452 * @see #isImportantForAutofill() 1453 * @see #setImportantForAutofill(int) 1454 */ 1455 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; 1456 1457 /** @hide */ 1458 @IntDef(flag = true, prefix = { "AUTOFILL_FLAG_" }, value = { 1459 AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 1460 }) 1461 @Retention(RetentionPolicy.SOURCE) 1462 public @interface AutofillFlags {} 1463 1464 /** 1465 * Flag requesting you to add views that are marked as not important for autofill 1466 * (see {@link #setImportantForAutofill(int)}) to a {@link ViewStructure}. 1467 */ 1468 public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; 1469 1470 /** @hide */ 1471 @IntDef(prefix = { "IMPORTANT_FOR_CONTENT_CAPTURE_" }, value = { 1472 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, 1473 IMPORTANT_FOR_CONTENT_CAPTURE_YES, 1474 IMPORTANT_FOR_CONTENT_CAPTURE_NO, 1475 IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 1476 IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 1477 }) 1478 @Retention(RetentionPolicy.SOURCE) 1479 public @interface ContentCaptureImportance {} 1480 1481 /** 1482 * Automatically determine whether a view is important for content capture. 1483 * 1484 * @see #isImportantForContentCapture() 1485 * @see #setImportantForContentCapture(int) 1486 */ 1487 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0x0; 1488 1489 /** 1490 * The view is important for content capture, and its children (if any) will be traversed. 1491 * 1492 * @see #isImportantForContentCapture() 1493 * @see #setImportantForContentCapture(int) 1494 */ 1495 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 0x1; 1496 1497 /** 1498 * The view is not important for content capture, but its children (if any) will be traversed. 1499 * 1500 * @see #isImportantForContentCapture() 1501 * @see #setImportantForContentCapture(int) 1502 */ 1503 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 0x2; 1504 1505 /** 1506 * The view is important for content capture, but its children (if any) will not be traversed. 1507 * 1508 * @see #isImportantForContentCapture() 1509 * @see #setImportantForContentCapture(int) 1510 */ 1511 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 0x4; 1512 1513 /** 1514 * The view is not important for content capture, and its children (if any) will not be 1515 * traversed. 1516 * 1517 * @see #isImportantForContentCapture() 1518 * @see #setImportantForContentCapture(int) 1519 */ 1520 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 0x8; 1521 1522 /** {@hide} */ 1523 @IntDef(flag = true, prefix = {"SCROLL_CAPTURE_HINT_"}, 1524 value = { 1525 SCROLL_CAPTURE_HINT_AUTO, 1526 SCROLL_CAPTURE_HINT_EXCLUDE, 1527 SCROLL_CAPTURE_HINT_INCLUDE, 1528 SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS 1529 }) 1530 @Retention(RetentionPolicy.SOURCE) 1531 public @interface ScrollCaptureHint {} 1532 1533 /** 1534 * The content of this view will be considered for scroll capture if scrolling is possible. 1535 * 1536 * @see #getScrollCaptureHint() 1537 * @see #setScrollCaptureHint(int) 1538 */ 1539 public static final int SCROLL_CAPTURE_HINT_AUTO = 0; 1540 1541 /** 1542 * Explicitly exclude this view as a potential scroll capture target. The system will not 1543 * consider it. Mutually exclusive with {@link #SCROLL_CAPTURE_HINT_INCLUDE}, which this flag 1544 * takes precedence over. 1545 * 1546 * @see #getScrollCaptureHint() 1547 * @see #setScrollCaptureHint(int) 1548 */ 1549 public static final int SCROLL_CAPTURE_HINT_EXCLUDE = 0x1; 1550 1551 /** 1552 * Explicitly include this view as a potential scroll capture target. When locating a scroll 1553 * capture target, this view will be prioritized before others without this flag. Mutually 1554 * exclusive with {@link #SCROLL_CAPTURE_HINT_EXCLUDE}, which takes precedence. 1555 * 1556 * @see #getScrollCaptureHint() 1557 * @see #setScrollCaptureHint(int) 1558 */ 1559 public static final int SCROLL_CAPTURE_HINT_INCLUDE = 0x2; 1560 1561 /** 1562 * Explicitly exclude all children of this view as potential scroll capture targets. This view 1563 * is unaffected. Note: Excluded children are not considered, regardless of {@link 1564 * #SCROLL_CAPTURE_HINT_INCLUDE}. 1565 * 1566 * @see #getScrollCaptureHint() 1567 * @see #setScrollCaptureHint(int) 1568 */ 1569 public static final int SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS = 0x4; 1570 1571 /** 1572 * This view is enabled. Interpretation varies by subclass. 1573 * Use with ENABLED_MASK when calling setFlags. 1574 * {@hide} 1575 */ 1576 static final int ENABLED = 0x00000000; 1577 1578 /** 1579 * This view is disabled. Interpretation varies by subclass. 1580 * Use with ENABLED_MASK when calling setFlags. 1581 * {@hide} 1582 */ 1583 static final int DISABLED = 0x00000020; 1584 1585 /** 1586 * Mask for use with setFlags indicating bits used for indicating whether 1587 * this view is enabled 1588 * {@hide} 1589 */ 1590 static final int ENABLED_MASK = 0x00000020; 1591 1592 /** 1593 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1594 * called and further optimizations will be performed. It is okay to have 1595 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1596 * {@hide} 1597 */ 1598 static final int WILL_NOT_DRAW = 0x00000080; 1599 1600 /** 1601 * Mask for use with setFlags indicating bits used for indicating whether 1602 * this view is will draw 1603 * {@hide} 1604 */ 1605 static final int DRAW_MASK = 0x00000080; 1606 1607 /** 1608 * <p>This view doesn't show scrollbars.</p> 1609 * {@hide} 1610 */ 1611 static final int SCROLLBARS_NONE = 0x00000000; 1612 1613 /** 1614 * <p>This view shows horizontal scrollbars.</p> 1615 * {@hide} 1616 */ 1617 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1618 1619 /** 1620 * <p>This view shows vertical scrollbars.</p> 1621 * {@hide} 1622 */ 1623 static final int SCROLLBARS_VERTICAL = 0x00000200; 1624 1625 /** 1626 * <p>Mask for use with setFlags indicating bits used for indicating which 1627 * scrollbars are enabled.</p> 1628 * {@hide} 1629 */ 1630 static final int SCROLLBARS_MASK = 0x00000300; 1631 1632 /** 1633 * Indicates that the view should filter touches when its window is obscured. 1634 * Refer to the class comments for more information about this security feature. 1635 * {@hide} 1636 */ 1637 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1638 1639 /** 1640 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1641 * that they are optional and should be skipped if the window has 1642 * requested system UI flags that ignore those insets for layout. 1643 * <p> 1644 * This is only used for support library as of Android R. The framework now uses 1645 * {@link #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS} such that it can skip the legacy 1646 * insets path that loses insets information. 1647 */ 1648 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1649 1650 /** 1651 * <p>This view doesn't show fading edges.</p> 1652 * {@hide} 1653 */ 1654 static final int FADING_EDGE_NONE = 0x00000000; 1655 1656 /** 1657 * <p>This view shows horizontal fading edges.</p> 1658 * {@hide} 1659 */ 1660 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1661 1662 /** 1663 * <p>This view shows vertical fading edges.</p> 1664 * {@hide} 1665 */ 1666 static final int FADING_EDGE_VERTICAL = 0x00002000; 1667 1668 /** 1669 * <p>Mask for use with setFlags indicating bits used for indicating which 1670 * fading edges are enabled.</p> 1671 * {@hide} 1672 */ 1673 static final int FADING_EDGE_MASK = 0x00003000; 1674 1675 /** 1676 * <p>Indicates this view can be clicked. When clickable, a View reacts 1677 * to clicks by notifying the OnClickListener.<p> 1678 * {@hide} 1679 */ 1680 static final int CLICKABLE = 0x00004000; 1681 1682 /** 1683 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1684 * {@hide} 1685 */ 1686 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1687 1688 /** 1689 * <p>Indicates that no icicle should be saved for this view.<p> 1690 * {@hide} 1691 */ 1692 static final int SAVE_DISABLED = 0x000010000; 1693 1694 /** 1695 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1696 * property.</p> 1697 * {@hide} 1698 */ 1699 static final int SAVE_DISABLED_MASK = 0x000010000; 1700 1701 /** 1702 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1703 * {@hide} 1704 */ 1705 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1706 1707 /** 1708 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1709 * {@hide} 1710 */ 1711 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1712 1713 /** @hide */ 1714 @Retention(RetentionPolicy.SOURCE) 1715 @IntDef(prefix = { "DRAWING_CACHE_QUALITY_" }, value = { 1716 DRAWING_CACHE_QUALITY_LOW, 1717 DRAWING_CACHE_QUALITY_HIGH, 1718 DRAWING_CACHE_QUALITY_AUTO 1719 }) 1720 public @interface DrawingCacheQuality {} 1721 1722 /** 1723 * <p>Enables low quality mode for the drawing cache.</p> 1724 * 1725 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1726 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1727 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1728 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1729 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1730 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1731 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1732 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1733 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1734 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1735 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1736 * reports or unit testing the {@link PixelCopy} API is recommended. 1737 */ 1738 @Deprecated 1739 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1740 1741 /** 1742 * <p>Enables high quality mode for the drawing cache.</p> 1743 * 1744 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1745 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1746 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1747 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1748 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1749 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1750 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1751 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1752 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1753 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1754 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1755 * reports or unit testing the {@link PixelCopy} API is recommended. 1756 */ 1757 @Deprecated 1758 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1759 1760 /** 1761 * <p>Enables automatic quality mode for the drawing cache.</p> 1762 * 1763 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1764 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1765 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1766 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1767 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1768 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1769 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1770 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1771 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1772 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1773 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1774 * reports or unit testing the {@link PixelCopy} API is recommended. 1775 */ 1776 @Deprecated 1777 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1778 1779 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1780 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1781 }; 1782 1783 /** 1784 * <p>Mask for use with setFlags indicating bits used for the cache 1785 * quality property.</p> 1786 * {@hide} 1787 */ 1788 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1789 1790 /** 1791 * <p> 1792 * Indicates this view can be long clicked. When long clickable, a View 1793 * reacts to long clicks by notifying the OnLongClickListener or showing a 1794 * context menu. 1795 * </p> 1796 * {@hide} 1797 */ 1798 static final int LONG_CLICKABLE = 0x00200000; 1799 1800 /** 1801 * <p>Indicates that this view gets its drawable states from its direct parent 1802 * and ignores its original internal states.</p> 1803 * 1804 * @hide 1805 */ 1806 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1807 1808 /** 1809 * <p> 1810 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1811 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1812 * OnContextClickListener. 1813 * </p> 1814 * {@hide} 1815 */ 1816 static final int CONTEXT_CLICKABLE = 0x00800000; 1817 1818 /** @hide */ 1819 @IntDef(prefix = { "SCROLLBARS_" }, value = { 1820 SCROLLBARS_INSIDE_OVERLAY, 1821 SCROLLBARS_INSIDE_INSET, 1822 SCROLLBARS_OUTSIDE_OVERLAY, 1823 SCROLLBARS_OUTSIDE_INSET 1824 }) 1825 @Retention(RetentionPolicy.SOURCE) 1826 public @interface ScrollBarStyle {} 1827 1828 /** 1829 * The scrollbar style to display the scrollbars inside the content area, 1830 * without increasing the padding. The scrollbars will be overlaid with 1831 * translucency on the view's content. 1832 */ 1833 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1834 1835 /** 1836 * The scrollbar style to display the scrollbars inside the padded area, 1837 * increasing the padding of the view. The scrollbars will not overlap the 1838 * content area of the view. 1839 */ 1840 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1841 1842 /** 1843 * The scrollbar style to display the scrollbars at the edge of the view, 1844 * without increasing the padding. The scrollbars will be overlaid with 1845 * translucency. 1846 */ 1847 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1848 1849 /** 1850 * The scrollbar style to display the scrollbars at the edge of the view, 1851 * increasing the padding of the view. The scrollbars will only overlap the 1852 * background, if any. 1853 */ 1854 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1855 1856 /** 1857 * Mask to check if the scrollbar style is overlay or inset. 1858 * {@hide} 1859 */ 1860 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1861 1862 /** 1863 * Mask to check if the scrollbar style is inside or outside. 1864 * {@hide} 1865 */ 1866 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1867 1868 /** 1869 * Mask for scrollbar style. 1870 * {@hide} 1871 */ 1872 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1873 1874 /** 1875 * View flag indicating that the screen should remain on while the 1876 * window containing this view is visible to the user. This effectively 1877 * takes care of automatically setting the WindowManager's 1878 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1879 */ 1880 public static final int KEEP_SCREEN_ON = 0x04000000; 1881 1882 /** 1883 * View flag indicating whether this view should have sound effects enabled 1884 * for events such as clicking and touching. 1885 */ 1886 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1887 1888 /** 1889 * View flag indicating whether this view should have haptic feedback 1890 * enabled for events such as long presses. 1891 */ 1892 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1893 1894 /** 1895 * <p>Indicates that the view hierarchy should stop saving state when 1896 * it reaches this view. If state saving is initiated immediately at 1897 * the view, it will be allowed. 1898 * {@hide} 1899 */ 1900 static final int PARENT_SAVE_DISABLED = 0x20000000; 1901 1902 /** 1903 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1904 * {@hide} 1905 */ 1906 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1907 1908 private static Paint sDebugPaint; 1909 1910 /** 1911 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1912 * {@hide} 1913 */ 1914 static final int TOOLTIP = 0x40000000; 1915 1916 /** @hide */ 1917 @IntDef(flag = true, prefix = { "FOCUSABLES_" }, value = { 1918 FOCUSABLES_ALL, 1919 FOCUSABLES_TOUCH_MODE 1920 }) 1921 @Retention(RetentionPolicy.SOURCE) 1922 public @interface FocusableMode {} 1923 1924 /** 1925 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1926 * should add all focusable Views regardless if they are focusable in touch mode. 1927 */ 1928 public static final int FOCUSABLES_ALL = 0x00000000; 1929 1930 /** 1931 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1932 * should add only Views focusable in touch mode. 1933 */ 1934 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1935 1936 /** @hide */ 1937 @IntDef(prefix = { "FOCUS_" }, value = { 1938 FOCUS_BACKWARD, 1939 FOCUS_FORWARD, 1940 FOCUS_LEFT, 1941 FOCUS_UP, 1942 FOCUS_RIGHT, 1943 FOCUS_DOWN 1944 }) 1945 @Retention(RetentionPolicy.SOURCE) 1946 public @interface FocusDirection {} 1947 1948 /** @hide */ 1949 @IntDef(prefix = { "FOCUS_" }, value = { 1950 FOCUS_LEFT, 1951 FOCUS_UP, 1952 FOCUS_RIGHT, 1953 FOCUS_DOWN 1954 }) 1955 @Retention(RetentionPolicy.SOURCE) 1956 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1957 1958 /** 1959 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1960 * item. 1961 */ 1962 public static final int FOCUS_BACKWARD = 0x00000001; 1963 1964 /** 1965 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1966 * item. 1967 */ 1968 public static final int FOCUS_FORWARD = 0x00000002; 1969 1970 /** 1971 * Use with {@link #focusSearch(int)}. Move focus to the left. 1972 */ 1973 public static final int FOCUS_LEFT = 0x00000011; 1974 1975 /** 1976 * Use with {@link #focusSearch(int)}. Move focus up. 1977 */ 1978 public static final int FOCUS_UP = 0x00000021; 1979 1980 /** 1981 * Use with {@link #focusSearch(int)}. Move focus to the right. 1982 */ 1983 public static final int FOCUS_RIGHT = 0x00000042; 1984 1985 /** 1986 * Use with {@link #focusSearch(int)}. Move focus down. 1987 */ 1988 public static final int FOCUS_DOWN = 0x00000082; 1989 1990 /** 1991 * Bits of {@link #getMeasuredWidthAndState()} and 1992 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1993 */ 1994 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1995 1996 /** 1997 * Bits of {@link #getMeasuredWidthAndState()} and 1998 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1999 */ 2000 public static final int MEASURED_STATE_MASK = 0xff000000; 2001 2002 /** 2003 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 2004 * for functions that combine both width and height into a single int, 2005 * such as {@link #getMeasuredState()} and the childState argument of 2006 * {@link #resolveSizeAndState(int, int, int)}. 2007 */ 2008 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 2009 2010 /** 2011 * Bit of {@link #getMeasuredWidthAndState()} and 2012 * {@link #getMeasuredWidthAndState()} that indicates the measured size 2013 * is smaller that the space the view would like to have. 2014 */ 2015 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 2016 2017 /** 2018 * Base View state sets 2019 */ 2020 // Singles 2021 /** 2022 * Indicates the view has no states set. States are used with 2023 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2024 * view depending on its state. 2025 * 2026 * @see android.graphics.drawable.Drawable 2027 * @see #getDrawableState() 2028 */ 2029 protected static final int[] EMPTY_STATE_SET; 2030 /** 2031 * Indicates the view is enabled. States are used with 2032 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2033 * view depending on its state. 2034 * 2035 * @see android.graphics.drawable.Drawable 2036 * @see #getDrawableState() 2037 */ 2038 protected static final int[] ENABLED_STATE_SET; 2039 /** 2040 * Indicates the view is focused. States are used with 2041 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2042 * view depending on its state. 2043 * 2044 * @see android.graphics.drawable.Drawable 2045 * @see #getDrawableState() 2046 */ 2047 protected static final int[] FOCUSED_STATE_SET; 2048 /** 2049 * Indicates the view is selected. States are used with 2050 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2051 * view depending on its state. 2052 * 2053 * @see android.graphics.drawable.Drawable 2054 * @see #getDrawableState() 2055 */ 2056 protected static final int[] SELECTED_STATE_SET; 2057 /** 2058 * Indicates the view is pressed. States are used with 2059 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2060 * view depending on its state. 2061 * 2062 * @see android.graphics.drawable.Drawable 2063 * @see #getDrawableState() 2064 */ 2065 protected static final int[] PRESSED_STATE_SET; 2066 /** 2067 * Indicates the view's window has focus. States are used with 2068 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2069 * view depending on its state. 2070 * 2071 * @see android.graphics.drawable.Drawable 2072 * @see #getDrawableState() 2073 */ 2074 protected static final int[] WINDOW_FOCUSED_STATE_SET; 2075 // Doubles 2076 /** 2077 * Indicates the view is enabled and has the focus. 2078 * 2079 * @see #ENABLED_STATE_SET 2080 * @see #FOCUSED_STATE_SET 2081 */ 2082 protected static final int[] ENABLED_FOCUSED_STATE_SET; 2083 /** 2084 * Indicates the view is enabled and selected. 2085 * 2086 * @see #ENABLED_STATE_SET 2087 * @see #SELECTED_STATE_SET 2088 */ 2089 protected static final int[] ENABLED_SELECTED_STATE_SET; 2090 /** 2091 * Indicates the view is enabled and that its window has focus. 2092 * 2093 * @see #ENABLED_STATE_SET 2094 * @see #WINDOW_FOCUSED_STATE_SET 2095 */ 2096 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 2097 /** 2098 * Indicates the view is focused and selected. 2099 * 2100 * @see #FOCUSED_STATE_SET 2101 * @see #SELECTED_STATE_SET 2102 */ 2103 protected static final int[] FOCUSED_SELECTED_STATE_SET; 2104 /** 2105 * Indicates the view has the focus and that its window has the focus. 2106 * 2107 * @see #FOCUSED_STATE_SET 2108 * @see #WINDOW_FOCUSED_STATE_SET 2109 */ 2110 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 2111 /** 2112 * Indicates the view is selected and that its window has the focus. 2113 * 2114 * @see #SELECTED_STATE_SET 2115 * @see #WINDOW_FOCUSED_STATE_SET 2116 */ 2117 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 2118 // Triples 2119 /** 2120 * Indicates the view is enabled, focused and selected. 2121 * 2122 * @see #ENABLED_STATE_SET 2123 * @see #FOCUSED_STATE_SET 2124 * @see #SELECTED_STATE_SET 2125 */ 2126 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 2127 /** 2128 * Indicates the view is enabled, focused and its window has the focus. 2129 * 2130 * @see #ENABLED_STATE_SET 2131 * @see #FOCUSED_STATE_SET 2132 * @see #WINDOW_FOCUSED_STATE_SET 2133 */ 2134 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2135 /** 2136 * Indicates the view is enabled, selected and its window has the focus. 2137 * 2138 * @see #ENABLED_STATE_SET 2139 * @see #SELECTED_STATE_SET 2140 * @see #WINDOW_FOCUSED_STATE_SET 2141 */ 2142 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2143 /** 2144 * Indicates the view is focused, selected and its window has the focus. 2145 * 2146 * @see #FOCUSED_STATE_SET 2147 * @see #SELECTED_STATE_SET 2148 * @see #WINDOW_FOCUSED_STATE_SET 2149 */ 2150 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2151 /** 2152 * Indicates the view is enabled, focused, selected and its window 2153 * has the focus. 2154 * 2155 * @see #ENABLED_STATE_SET 2156 * @see #FOCUSED_STATE_SET 2157 * @see #SELECTED_STATE_SET 2158 * @see #WINDOW_FOCUSED_STATE_SET 2159 */ 2160 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2161 /** 2162 * Indicates the view is pressed and its window has the focus. 2163 * 2164 * @see #PRESSED_STATE_SET 2165 * @see #WINDOW_FOCUSED_STATE_SET 2166 */ 2167 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 2168 /** 2169 * Indicates the view is pressed and selected. 2170 * 2171 * @see #PRESSED_STATE_SET 2172 * @see #SELECTED_STATE_SET 2173 */ 2174 protected static final int[] PRESSED_SELECTED_STATE_SET; 2175 /** 2176 * Indicates the view is pressed, selected and its window has the focus. 2177 * 2178 * @see #PRESSED_STATE_SET 2179 * @see #SELECTED_STATE_SET 2180 * @see #WINDOW_FOCUSED_STATE_SET 2181 */ 2182 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2183 /** 2184 * Indicates the view is pressed and focused. 2185 * 2186 * @see #PRESSED_STATE_SET 2187 * @see #FOCUSED_STATE_SET 2188 */ 2189 protected static final int[] PRESSED_FOCUSED_STATE_SET; 2190 /** 2191 * Indicates the view is pressed, focused and its window has the focus. 2192 * 2193 * @see #PRESSED_STATE_SET 2194 * @see #FOCUSED_STATE_SET 2195 * @see #WINDOW_FOCUSED_STATE_SET 2196 */ 2197 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2198 /** 2199 * Indicates the view is pressed, focused and selected. 2200 * 2201 * @see #PRESSED_STATE_SET 2202 * @see #SELECTED_STATE_SET 2203 * @see #FOCUSED_STATE_SET 2204 */ 2205 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 2206 /** 2207 * Indicates the view is pressed, focused, selected and its window has the focus. 2208 * 2209 * @see #PRESSED_STATE_SET 2210 * @see #FOCUSED_STATE_SET 2211 * @see #SELECTED_STATE_SET 2212 * @see #WINDOW_FOCUSED_STATE_SET 2213 */ 2214 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2215 /** 2216 * Indicates the view is pressed and enabled. 2217 * 2218 * @see #PRESSED_STATE_SET 2219 * @see #ENABLED_STATE_SET 2220 */ 2221 protected static final int[] PRESSED_ENABLED_STATE_SET; 2222 /** 2223 * Indicates the view is pressed, enabled and its window has the focus. 2224 * 2225 * @see #PRESSED_STATE_SET 2226 * @see #ENABLED_STATE_SET 2227 * @see #WINDOW_FOCUSED_STATE_SET 2228 */ 2229 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 2230 /** 2231 * Indicates the view is pressed, enabled and selected. 2232 * 2233 * @see #PRESSED_STATE_SET 2234 * @see #ENABLED_STATE_SET 2235 * @see #SELECTED_STATE_SET 2236 */ 2237 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 2238 /** 2239 * Indicates the view is pressed, enabled, selected and its window has the 2240 * focus. 2241 * 2242 * @see #PRESSED_STATE_SET 2243 * @see #ENABLED_STATE_SET 2244 * @see #SELECTED_STATE_SET 2245 * @see #WINDOW_FOCUSED_STATE_SET 2246 */ 2247 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2248 /** 2249 * Indicates the view is pressed, enabled and focused. 2250 * 2251 * @see #PRESSED_STATE_SET 2252 * @see #ENABLED_STATE_SET 2253 * @see #FOCUSED_STATE_SET 2254 */ 2255 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 2256 /** 2257 * Indicates the view is pressed, enabled, focused and its window has the 2258 * focus. 2259 * 2260 * @see #PRESSED_STATE_SET 2261 * @see #ENABLED_STATE_SET 2262 * @see #FOCUSED_STATE_SET 2263 * @see #WINDOW_FOCUSED_STATE_SET 2264 */ 2265 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2266 /** 2267 * Indicates the view is pressed, enabled, focused and selected. 2268 * 2269 * @see #PRESSED_STATE_SET 2270 * @see #ENABLED_STATE_SET 2271 * @see #SELECTED_STATE_SET 2272 * @see #FOCUSED_STATE_SET 2273 */ 2274 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 2275 /** 2276 * Indicates the view is pressed, enabled, focused, selected and its window 2277 * has the focus. 2278 * 2279 * @see #PRESSED_STATE_SET 2280 * @see #ENABLED_STATE_SET 2281 * @see #SELECTED_STATE_SET 2282 * @see #FOCUSED_STATE_SET 2283 * @see #WINDOW_FOCUSED_STATE_SET 2284 */ 2285 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2286 2287 static { 2288 EMPTY_STATE_SET = StateSet.get(0); 2289 2290 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 2291 2292 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 2293 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2294 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 2295 2296 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 2297 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2298 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 2299 FOCUSED_SELECTED_STATE_SET = StateSet.get( 2300 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 2301 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2302 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2303 | StateSet.VIEW_STATE_FOCUSED); 2304 2305 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 2306 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2307 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2308 ENABLED_SELECTED_STATE_SET = StateSet.get( 2309 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 2310 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2311 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2312 | StateSet.VIEW_STATE_ENABLED); 2313 ENABLED_FOCUSED_STATE_SET = StateSet.get( 2314 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2315 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2316 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2317 | StateSet.VIEW_STATE_ENABLED); 2318 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2319 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2320 | StateSet.VIEW_STATE_ENABLED); 2321 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2322 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2323 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 2324 2325 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 2326 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2327 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2328 PRESSED_SELECTED_STATE_SET = StateSet.get( 2329 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 2330 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2331 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2332 | StateSet.VIEW_STATE_PRESSED); 2333 PRESSED_FOCUSED_STATE_SET = StateSet.get( 2334 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2335 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2336 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2337 | StateSet.VIEW_STATE_PRESSED); 2338 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2339 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2340 | StateSet.VIEW_STATE_PRESSED); 2341 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2342 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2343 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2344 PRESSED_ENABLED_STATE_SET = StateSet.get( 2345 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2346 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2347 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 2348 | StateSet.VIEW_STATE_PRESSED); 2349 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 2350 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 2351 | StateSet.VIEW_STATE_PRESSED); 2352 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2353 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2354 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2355 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 2356 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 2357 | StateSet.VIEW_STATE_PRESSED); 2358 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2359 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2360 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2361 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2362 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2363 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2364 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2365 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2366 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 2367 | StateSet.VIEW_STATE_PRESSED); 2368 } 2369 2370 /** 2371 * Accessibility event types that are dispatched for text population. 2372 */ 2373 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 2374 AccessibilityEvent.TYPE_VIEW_CLICKED 2375 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 2376 | AccessibilityEvent.TYPE_VIEW_SELECTED 2377 | AccessibilityEvent.TYPE_VIEW_FOCUSED 2378 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 2379 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 2380 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 2381 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 2382 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 2383 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 2384 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 2385 2386 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 2387 2388 static final int DEBUG_CORNERS_SIZE_DIP = 8; 2389 2390 /** 2391 * Temporary Rect currently for use in setBackground(). This will probably 2392 * be extended in the future to hold our own class with more than just 2393 * a Rect. :) 2394 */ 2395 static final ThreadLocal<Rect> sThreadLocal = ThreadLocal.withInitial(Rect::new); 2396 2397 /** 2398 * Map used to store views' tags. 2399 */ 2400 @UnsupportedAppUsage 2401 private SparseArray<Object> mKeyedTags; 2402 2403 /** 2404 * The next available accessibility id. 2405 */ 2406 private static int sNextAccessibilityViewId; 2407 2408 /** 2409 * The animation currently associated with this view. 2410 * @hide 2411 */ 2412 protected Animation mCurrentAnimation = null; 2413 2414 /** 2415 * Width as measured during measure pass. 2416 * {@hide} 2417 */ 2418 @ViewDebug.ExportedProperty(category = "measurement") 2419 @UnsupportedAppUsage 2420 int mMeasuredWidth; 2421 2422 /** 2423 * Height as measured during measure pass. 2424 * {@hide} 2425 */ 2426 @ViewDebug.ExportedProperty(category = "measurement") 2427 @UnsupportedAppUsage 2428 int mMeasuredHeight; 2429 2430 /** 2431 * Flag to indicate that this view was marked INVALIDATED, or had its display list 2432 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 2433 * its display list. This flag, used only when hw accelerated, allows us to clear the 2434 * flag while retaining this information until it's needed (at getDisplayList() time and 2435 * in drawChild(), when we decide to draw a view's children's display lists into our own). 2436 * 2437 * {@hide} 2438 */ 2439 @UnsupportedAppUsage 2440 boolean mRecreateDisplayList = false; 2441 2442 /** 2443 * The view's identifier. 2444 * {@hide} 2445 * 2446 * @see #setId(int) 2447 * @see #getId() 2448 */ 2449 @IdRes 2450 @ViewDebug.ExportedProperty(resolveId = true) 2451 int mID = NO_ID; 2452 2453 /** The ID of this view for autofill purposes. 2454 * <ul> 2455 * <li>== {@link #NO_ID}: ID has not been assigned yet 2456 * <li>≤ {@link #LAST_APP_AUTOFILL_ID}: View is not part of a activity. The ID is 2457 * unique in the process. This might change 2458 * over activity lifecycle events. 2459 * <li>> {@link #LAST_APP_AUTOFILL_ID}: View is part of a activity. The ID is 2460 * unique in the activity. This stays the same 2461 * over activity lifecycle events. 2462 */ 2463 private int mAutofillViewId = NO_ID; 2464 2465 // ID for accessibility purposes. This ID must be unique for every window 2466 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2467 private int mAccessibilityViewId = NO_ID; 2468 2469 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2470 2471 /** 2472 * The view's tag. 2473 * {@hide} 2474 * 2475 * @see #setTag(Object) 2476 * @see #getTag() 2477 */ 2478 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 2479 protected Object mTag = null; 2480 2481 /* 2482 * Masks for mPrivateFlags, as generated by dumpFlags(): 2483 * 2484 * |-------|-------|-------|-------| 2485 * 1 PFLAG_WANTS_FOCUS 2486 * 1 PFLAG_FOCUSED 2487 * 1 PFLAG_SELECTED 2488 * 1 PFLAG_IS_ROOT_NAMESPACE 2489 * 1 PFLAG_HAS_BOUNDS 2490 * 1 PFLAG_DRAWN 2491 * 1 PFLAG_DRAW_ANIMATION 2492 * 1 PFLAG_SKIP_DRAW 2493 * 1 PFLAG_REQUEST_TRANSPARENT_REGIONS 2494 * 1 PFLAG_DRAWABLE_STATE_DIRTY 2495 * 1 PFLAG_MEASURED_DIMENSION_SET 2496 * 1 PFLAG_FORCE_LAYOUT 2497 * 1 PFLAG_LAYOUT_REQUIRED 2498 * 1 PFLAG_PRESSED 2499 * 1 PFLAG_DRAWING_CACHE_VALID 2500 * 1 PFLAG_ANIMATION_STARTED 2501 * 1 PFLAG_SAVE_STATE_CALLED 2502 * 1 PFLAG_ALPHA_SET 2503 * 1 PFLAG_SCROLL_CONTAINER 2504 * 1 PFLAG_SCROLL_CONTAINER_ADDED 2505 * 1 PFLAG_DIRTY 2506 * 1 PFLAG_DIRTY_MASK 2507 * 1 PFLAG_OPAQUE_BACKGROUND 2508 * 1 PFLAG_OPAQUE_SCROLLBARS 2509 * 11 PFLAG_OPAQUE_MASK 2510 * 1 PFLAG_PREPRESSED 2511 * 1 PFLAG_CANCEL_NEXT_UP_EVENT 2512 * 1 PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH 2513 * 1 PFLAG_HOVERED 2514 * 1 PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK 2515 * 1 PFLAG_ACTIVATED 2516 * 1 PFLAG_INVALIDATED 2517 * |-------|-------|-------|-------| 2518 */ 2519 /** {@hide} */ 2520 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2521 /** {@hide} */ 2522 static final int PFLAG_FOCUSED = 0x00000002; 2523 /** {@hide} */ 2524 static final int PFLAG_SELECTED = 0x00000004; 2525 /** {@hide} */ 2526 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2527 /** {@hide} */ 2528 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2529 /** {@hide} */ 2530 static final int PFLAG_DRAWN = 0x00000020; 2531 /** 2532 * When this flag is set, this view is running an animation on behalf of its 2533 * children and should therefore not cancel invalidate requests, even if they 2534 * lie outside of this view's bounds. 2535 * 2536 * {@hide} 2537 */ 2538 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2539 /** {@hide} */ 2540 static final int PFLAG_SKIP_DRAW = 0x00000080; 2541 /** {@hide} */ 2542 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2543 /** {@hide} */ 2544 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2545 /** {@hide} */ 2546 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2547 /** {@hide} */ 2548 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2549 /** {@hide} */ 2550 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2551 2552 private static final int PFLAG_PRESSED = 0x00004000; 2553 2554 /** {@hide} */ 2555 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2556 /** 2557 * Flag used to indicate that this view should be drawn once more (and only once 2558 * more) after its animation has completed. 2559 * {@hide} 2560 */ 2561 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2562 2563 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2564 2565 /** 2566 * Indicates that the View returned true when onSetAlpha() was called and that 2567 * the alpha must be restored. 2568 * {@hide} 2569 */ 2570 static final int PFLAG_ALPHA_SET = 0x00040000; 2571 2572 /** 2573 * Set by {@link #setScrollContainer(boolean)}. 2574 */ 2575 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2576 2577 /** 2578 * Set by {@link #setScrollContainer(boolean)}. 2579 */ 2580 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2581 2582 /** 2583 * View flag indicating whether this view was invalidated (fully or partially.) 2584 * 2585 * @hide 2586 */ 2587 static final int PFLAG_DIRTY = 0x00200000; 2588 2589 /** 2590 * Mask for {@link #PFLAG_DIRTY}. 2591 * 2592 * @hide 2593 */ 2594 static final int PFLAG_DIRTY_MASK = 0x00200000; 2595 2596 /** 2597 * Indicates whether the background is opaque. 2598 * 2599 * @hide 2600 */ 2601 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2602 2603 /** 2604 * Indicates whether the scrollbars are opaque. 2605 * 2606 * @hide 2607 */ 2608 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2609 2610 /** 2611 * Indicates whether the view is opaque. 2612 * 2613 * @hide 2614 */ 2615 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2616 2617 /** 2618 * Indicates a prepressed state; 2619 * the short time between ACTION_DOWN and recognizing 2620 * a 'real' press. Prepressed is used to recognize quick taps 2621 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2622 * 2623 * @hide 2624 */ 2625 private static final int PFLAG_PREPRESSED = 0x02000000; 2626 2627 /** 2628 * Indicates whether the view is temporarily detached. 2629 * 2630 * @hide 2631 */ 2632 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2633 2634 /** 2635 * Indicates that we should awaken scroll bars once attached 2636 * 2637 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2638 * during window attachment and it is no longer needed. Feel free to repurpose it. 2639 * 2640 * @hide 2641 */ 2642 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2643 2644 /** 2645 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2646 * @hide 2647 */ 2648 private static final int PFLAG_HOVERED = 0x10000000; 2649 2650 /** 2651 * Flag set by {@link AutofillManager} if it needs to be notified when this view is clicked. 2652 */ 2653 private static final int PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK = 0x20000000; 2654 2655 /** {@hide} */ 2656 static final int PFLAG_ACTIVATED = 0x40000000; 2657 2658 /** 2659 * Indicates that this view was specifically invalidated, not just dirtied because some 2660 * child view was invalidated. The flag is used to determine when we need to recreate 2661 * a view's display list (as opposed to just returning a reference to its existing 2662 * display list). 2663 * 2664 * @hide 2665 */ 2666 static final int PFLAG_INVALIDATED = 0x80000000; 2667 2668 /* End of masks for mPrivateFlags */ 2669 2670 /* 2671 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2672 * 2673 * |-------|-------|-------|-------| 2674 * 1 PFLAG2_DRAG_CAN_ACCEPT 2675 * 1 PFLAG2_DRAG_HOVERED 2676 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2677 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2678 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2679 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2680 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2681 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2682 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2683 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2684 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2685 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2686 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2687 * 111 PFLAG2_TEXT_DIRECTION_MASK 2688 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2689 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2690 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2691 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2692 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2693 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2694 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2695 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2696 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2697 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2698 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2699 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2700 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2701 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2702 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2703 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2704 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2705 * 1 PFLAG2_VIEW_QUICK_REJECTED 2706 * 1 PFLAG2_PADDING_RESOLVED 2707 * 1 PFLAG2_DRAWABLE_RESOLVED 2708 * 1 PFLAG2_HAS_TRANSIENT_STATE 2709 * |-------|-------|-------|-------| 2710 */ 2711 2712 /** 2713 * Indicates that this view has reported that it can accept the current drag's content. 2714 * Cleared when the drag operation concludes. 2715 * @hide 2716 */ 2717 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2718 2719 /** 2720 * Indicates that this view is currently directly under the drag location in a 2721 * drag-and-drop operation involving content that it can accept. Cleared when 2722 * the drag exits the view, or when the drag operation concludes. 2723 * @hide 2724 */ 2725 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2726 2727 /** @hide */ 2728 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2729 LAYOUT_DIRECTION_LTR, 2730 LAYOUT_DIRECTION_RTL, 2731 LAYOUT_DIRECTION_INHERIT, 2732 LAYOUT_DIRECTION_LOCALE 2733 }) 2734 @Retention(RetentionPolicy.SOURCE) 2735 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2736 public @interface LayoutDir {} 2737 2738 /** @hide */ 2739 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2740 LAYOUT_DIRECTION_LTR, 2741 LAYOUT_DIRECTION_RTL 2742 }) 2743 @Retention(RetentionPolicy.SOURCE) 2744 public @interface ResolvedLayoutDir {} 2745 2746 /** 2747 * A flag to indicate that the layout direction of this view has not been defined yet. 2748 * @hide 2749 */ 2750 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2751 2752 /** 2753 * Horizontal layout direction of this view is from Left to Right. 2754 * Use with {@link #setLayoutDirection}. 2755 */ 2756 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2757 2758 /** 2759 * Horizontal layout direction of this view is from Right to Left. 2760 * Use with {@link #setLayoutDirection}. 2761 */ 2762 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2763 2764 /** 2765 * Horizontal layout direction of this view is inherited from its parent. 2766 * Use with {@link #setLayoutDirection}. 2767 */ 2768 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2769 2770 /** 2771 * Horizontal layout direction of this view is from deduced from the default language 2772 * script for the locale. Use with {@link #setLayoutDirection}. 2773 */ 2774 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2775 2776 /** 2777 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2778 * @hide 2779 */ 2780 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2781 2782 /** 2783 * Mask for use with private flags indicating bits used for horizontal layout direction. 2784 * @hide 2785 */ 2786 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2787 2788 /** 2789 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2790 * right-to-left direction. 2791 * @hide 2792 */ 2793 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2794 2795 /** 2796 * Indicates whether the view horizontal layout direction has been resolved. 2797 * @hide 2798 */ 2799 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2800 2801 /** 2802 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2803 * @hide 2804 */ 2805 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2806 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2807 2808 /* 2809 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2810 * flag value. 2811 * @hide 2812 */ 2813 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2814 LAYOUT_DIRECTION_LTR, 2815 LAYOUT_DIRECTION_RTL, 2816 LAYOUT_DIRECTION_INHERIT, 2817 LAYOUT_DIRECTION_LOCALE 2818 }; 2819 2820 /** 2821 * Default horizontal layout direction. 2822 */ 2823 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2824 2825 /** 2826 * Default horizontal layout direction. 2827 * @hide 2828 */ 2829 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2830 2831 /** 2832 * Text direction is inherited through {@link ViewGroup} 2833 */ 2834 public static final int TEXT_DIRECTION_INHERIT = 0; 2835 2836 /** 2837 * Text direction is using "first strong algorithm". The first strong directional character 2838 * determines the paragraph direction. If there is no strong directional character, the 2839 * paragraph direction is the view's resolved layout direction. 2840 */ 2841 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2842 2843 /** 2844 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2845 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2846 * If there are neither, the paragraph direction is the view's resolved layout direction. 2847 */ 2848 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2849 2850 /** 2851 * Text direction is forced to LTR. 2852 */ 2853 public static final int TEXT_DIRECTION_LTR = 3; 2854 2855 /** 2856 * Text direction is forced to RTL. 2857 */ 2858 public static final int TEXT_DIRECTION_RTL = 4; 2859 2860 /** 2861 * Text direction is coming from the system Locale. 2862 */ 2863 public static final int TEXT_DIRECTION_LOCALE = 5; 2864 2865 /** 2866 * Text direction is using "first strong algorithm". The first strong directional character 2867 * determines the paragraph direction. If there is no strong directional character, the 2868 * paragraph direction is LTR. 2869 */ 2870 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2871 2872 /** 2873 * Text direction is using "first strong algorithm". The first strong directional character 2874 * determines the paragraph direction. If there is no strong directional character, the 2875 * paragraph direction is RTL. 2876 */ 2877 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2878 2879 /** 2880 * Default text direction is inherited 2881 */ 2882 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2883 2884 /** 2885 * Default resolved text direction 2886 * @hide 2887 */ 2888 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2889 2890 /** 2891 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2892 * @hide 2893 */ 2894 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2895 2896 /** 2897 * Mask for use with private flags indicating bits used for text direction. 2898 * @hide 2899 */ 2900 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2901 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2902 2903 /** 2904 * Array of text direction flags for mapping attribute "textDirection" to correct 2905 * flag value. 2906 * @hide 2907 */ 2908 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2909 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2910 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2911 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2912 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2913 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2914 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2915 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2916 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2917 }; 2918 2919 /** 2920 * Indicates whether the view text direction has been resolved. 2921 * @hide 2922 */ 2923 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2924 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2925 2926 /** 2927 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2928 * @hide 2929 */ 2930 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2931 2932 /** 2933 * Mask for use with private flags indicating bits used for resolved text direction. 2934 * @hide 2935 */ 2936 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2937 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2938 2939 /** 2940 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2941 * @hide 2942 */ 2943 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2944 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2945 2946 /** @hide */ 2947 @IntDef(prefix = { "TEXT_ALIGNMENT_" }, value = { 2948 TEXT_ALIGNMENT_INHERIT, 2949 TEXT_ALIGNMENT_GRAVITY, 2950 TEXT_ALIGNMENT_CENTER, 2951 TEXT_ALIGNMENT_TEXT_START, 2952 TEXT_ALIGNMENT_TEXT_END, 2953 TEXT_ALIGNMENT_VIEW_START, 2954 TEXT_ALIGNMENT_VIEW_END 2955 }) 2956 @Retention(RetentionPolicy.SOURCE) 2957 public @interface TextAlignment {} 2958 2959 /** 2960 * Default text alignment. The text alignment of this View is inherited from its parent. 2961 * Use with {@link #setTextAlignment(int)} 2962 */ 2963 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2964 2965 /** 2966 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2967 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph's text direction. 2968 * 2969 * Use with {@link #setTextAlignment(int)} 2970 */ 2971 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2972 2973 /** 2974 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2975 * 2976 * Use with {@link #setTextAlignment(int)} 2977 */ 2978 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2979 2980 /** 2981 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2982 * 2983 * Use with {@link #setTextAlignment(int)} 2984 */ 2985 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2986 2987 /** 2988 * Center the paragraph, e.g. ALIGN_CENTER. 2989 * 2990 * Use with {@link #setTextAlignment(int)} 2991 */ 2992 public static final int TEXT_ALIGNMENT_CENTER = 4; 2993 2994 /** 2995 * Align to the start of the view, which is ALIGN_LEFT if the view's resolved 2996 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2997 * 2998 * Use with {@link #setTextAlignment(int)} 2999 */ 3000 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 3001 3002 /** 3003 * Align to the end of the view, which is ALIGN_RIGHT if the view's resolved 3004 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 3005 * 3006 * Use with {@link #setTextAlignment(int)} 3007 */ 3008 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 3009 3010 /** 3011 * Default text alignment is inherited 3012 */ 3013 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 3014 3015 /** 3016 * Default resolved text alignment 3017 * @hide 3018 */ 3019 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 3020 3021 /** 3022 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 3023 * @hide 3024 */ 3025 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 3026 3027 /** 3028 * Mask for use with private flags indicating bits used for text alignment. 3029 * @hide 3030 */ 3031 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 3032 3033 /** 3034 * Array of text direction flags for mapping attribute "textAlignment" to correct 3035 * flag value. 3036 * @hide 3037 */ 3038 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 3039 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3040 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3041 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3042 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3043 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3044 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 3045 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 3046 }; 3047 3048 /** 3049 * Indicates whether the view text alignment has been resolved. 3050 * @hide 3051 */ 3052 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 3053 3054 /** 3055 * Bit shift to get the resolved text alignment. 3056 * @hide 3057 */ 3058 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 3059 3060 /** 3061 * Mask for use with private flags indicating bits used for text alignment. 3062 * @hide 3063 */ 3064 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 3065 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 3066 3067 /** 3068 * Indicates whether if the view text alignment has been resolved to gravity 3069 */ 3070 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 3071 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 3072 3073 // Accessiblity constants for mPrivateFlags2 3074 3075 /** 3076 * Shift for the bits in {@link #mPrivateFlags2} related to the 3077 * "importantForAccessibility" attribute. 3078 */ 3079 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 3080 3081 /** 3082 * Automatically determine whether a view is important for accessibility. 3083 */ 3084 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 3085 3086 /** 3087 * The view is important for accessibility. 3088 */ 3089 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 3090 3091 /** 3092 * The view is not important for accessibility. 3093 */ 3094 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 3095 3096 /** 3097 * The view is not important for accessibility, nor are any of its 3098 * descendant views. 3099 */ 3100 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 3101 3102 /** 3103 * The default whether the view is important for accessibility. 3104 */ 3105 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 3106 3107 /** 3108 * Automatically determine whether the view should only allow interactions from 3109 * {@link android.accessibilityservice.AccessibilityService}s with the 3110 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property 3111 * set to true. 3112 * 3113 * <p> 3114 * Accessibility interactions from services without {@code isAccessibilityTool} set to true are 3115 * disallowed for any of the following conditions: 3116 * <li>this view sets {@link #getFilterTouchesWhenObscured()}.</li> 3117 * <li>any parent of this view returns true from {@link #isAccessibilityDataSensitive()}.</li> 3118 * </p> 3119 */ 3120 public static final int ACCESSIBILITY_DATA_SENSITIVE_AUTO = 0x00000000; 3121 3122 /** 3123 * Only allow interactions from {@link android.accessibilityservice.AccessibilityService}s 3124 * with the {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} 3125 * property set to true. 3126 */ 3127 public static final int ACCESSIBILITY_DATA_SENSITIVE_YES = 0x00000001; 3128 3129 /** 3130 * Allow interactions from all {@link android.accessibilityservice.AccessibilityService}s, 3131 * regardless of their 3132 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property. 3133 */ 3134 public static final int ACCESSIBILITY_DATA_SENSITIVE_NO = 0x00000002; 3135 3136 /** @hide */ 3137 @IntDef(prefix = { "ACCESSIBILITY_DATA_SENSITIVE_" }, value = { 3138 ACCESSIBILITY_DATA_SENSITIVE_AUTO, 3139 ACCESSIBILITY_DATA_SENSITIVE_YES, 3140 ACCESSIBILITY_DATA_SENSITIVE_NO, 3141 }) 3142 @Retention(RetentionPolicy.SOURCE) 3143 public @interface AccessibilityDataSensitive {} 3144 3145 /** 3146 * Mask for obtaining the bits which specify how to determine 3147 * whether a view is important for accessibility. 3148 */ 3149 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 3150 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 3151 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 3152 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 3153 3154 /** 3155 * Shift for the bits in {@link #mPrivateFlags2} related to the 3156 * "accessibilityLiveRegion" attribute. 3157 */ 3158 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 3159 3160 /** 3161 * Live region mode specifying that accessibility services should not 3162 * automatically announce changes to this view. This is the default live 3163 * region mode for most views. 3164 * <p> 3165 * Use with {@link #setAccessibilityLiveRegion(int)}. 3166 */ 3167 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 3168 3169 /** 3170 * Live region mode specifying that accessibility services should announce 3171 * changes to this view. 3172 * <p> 3173 * Use with {@link #setAccessibilityLiveRegion(int)}. 3174 */ 3175 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 3176 3177 /** 3178 * Live region mode specifying that accessibility services should interrupt 3179 * ongoing speech to immediately announce changes to this view. 3180 * <p> 3181 * Use with {@link #setAccessibilityLiveRegion(int)}. 3182 */ 3183 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 3184 3185 /** 3186 * The default whether the view is important for accessibility. 3187 */ 3188 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 3189 3190 /** 3191 * Mask for obtaining the bits which specify a view's accessibility live 3192 * region mode. 3193 */ 3194 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 3195 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 3196 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 3197 3198 /** 3199 * Flag indicating whether a view has accessibility focus. 3200 */ 3201 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 3202 3203 /** 3204 * Flag whether the accessibility state of the subtree rooted at this view changed. 3205 */ 3206 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 3207 3208 /** 3209 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 3210 * is used to check whether later changes to the view's transform should invalidate the 3211 * view to force the quickReject test to run again. 3212 */ 3213 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 3214 3215 /** 3216 * Flag indicating that start/end padding has been resolved into left/right padding 3217 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 3218 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 3219 * during measurement. In some special cases this is required such as when an adapter-based 3220 * view measures prospective children without attaching them to a window. 3221 */ 3222 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 3223 3224 /** 3225 * Flag indicating that the start/end drawables has been resolved into left/right ones. 3226 */ 3227 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 3228 3229 /** 3230 * Indicates that the view is tracking some sort of transient state 3231 * that the app should not need to be aware of, but that the framework 3232 * should take special care to preserve. 3233 */ 3234 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 3235 3236 /** 3237 * Group of bits indicating that RTL properties resolution is done. 3238 */ 3239 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 3240 PFLAG2_TEXT_DIRECTION_RESOLVED | 3241 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 3242 PFLAG2_PADDING_RESOLVED | 3243 PFLAG2_DRAWABLE_RESOLVED; 3244 3245 // There are a couple of flags left in mPrivateFlags2 3246 3247 /* End of masks for mPrivateFlags2 */ 3248 3249 /* 3250 * Masks for mPrivateFlags3, as generated by dumpFlags(): 3251 * 3252 * |-------|-------|-------|-------| 3253 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 3254 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 3255 * 1 PFLAG3_IS_LAID_OUT 3256 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 3257 * 1 PFLAG3_CALLED_SUPER 3258 * 1 PFLAG3_APPLYING_INSETS 3259 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 3260 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 3261 * 1 PFLAG3_SCROLL_INDICATOR_TOP 3262 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 3263 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 3264 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 3265 * 1 PFLAG3_SCROLL_INDICATOR_START 3266 * 1 PFLAG3_SCROLL_INDICATOR_END 3267 * 1 PFLAG3_ASSIST_BLOCKED 3268 * 1 PFLAG3_CLUSTER 3269 * 1 PFLAG3_IS_AUTOFILLED 3270 * 1 PFLAG3_FINGER_DOWN 3271 * 1 PFLAG3_FOCUSED_BY_DEFAULT 3272 * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL 3273 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 3274 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 3275 * 1 PFLAG3_TEMPORARY_DETACH 3276 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 3277 * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT 3278 * 1 PFLAG3_SCREEN_READER_FOCUSABLE 3279 * 1 PFLAG3_AGGREGATED_VISIBLE 3280 * 1 PFLAG3_AUTOFILLID_EXPLICITLY_SET 3281 * 1 PFLAG3_ACCESSIBILITY_HEADING 3282 * |-------|-------|-------|-------| 3283 */ 3284 3285 /** 3286 * Flag indicating that view has a transform animation set on it. This is used to track whether 3287 * an animation is cleared between successive frames, in order to tell the associated 3288 * DisplayList to clear its animation matrix. 3289 */ 3290 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 3291 3292 /** 3293 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 3294 * animation is cleared between successive frames, in order to tell the associated 3295 * DisplayList to restore its alpha value. 3296 */ 3297 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 3298 3299 /** 3300 * Flag indicating that the view has been through at least one layout since it 3301 * was last attached to a window. 3302 */ 3303 static final int PFLAG3_IS_LAID_OUT = 0x4; 3304 3305 /** 3306 * Flag indicating that a call to measure() was skipped and should be done 3307 * instead when layout() is invoked. 3308 */ 3309 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 3310 3311 /** 3312 * Flag indicating that an overridden method correctly called down to 3313 * the superclass implementation as required by the API spec. 3314 */ 3315 static final int PFLAG3_CALLED_SUPER = 0x10; 3316 3317 /** 3318 * Flag indicating that we're in the process of applying window insets. 3319 */ 3320 static final int PFLAG3_APPLYING_INSETS = 0x20; 3321 3322 /** 3323 * Flag indicating that we're in the process of fitting system windows using the old method. 3324 */ 3325 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 3326 3327 /** 3328 * Flag indicating that nested scrolling is enabled for this view. 3329 * The view will optionally cooperate with views up its parent chain to allow for 3330 * integrated nested scrolling along the same axis. 3331 */ 3332 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 3333 3334 /** 3335 * Flag indicating that the bottom scroll indicator should be displayed 3336 * when this view can scroll up. 3337 */ 3338 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 3339 3340 /** 3341 * Flag indicating that the bottom scroll indicator should be displayed 3342 * when this view can scroll down. 3343 */ 3344 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 3345 3346 /** 3347 * Flag indicating that the left scroll indicator should be displayed 3348 * when this view can scroll left. 3349 */ 3350 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 3351 3352 /** 3353 * Flag indicating that the right scroll indicator should be displayed 3354 * when this view can scroll right. 3355 */ 3356 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 3357 3358 /** 3359 * Flag indicating that the start scroll indicator should be displayed 3360 * when this view can scroll in the start direction. 3361 */ 3362 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 3363 3364 /** 3365 * Flag indicating that the end scroll indicator should be displayed 3366 * when this view can scroll in the end direction. 3367 */ 3368 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 3369 3370 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 3371 3372 static final int SCROLL_INDICATORS_NONE = 0x0000; 3373 3374 /** 3375 * Mask for use with setFlags indicating bits used for indicating which 3376 * scroll indicators are enabled. 3377 */ 3378 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 3379 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 3380 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 3381 | PFLAG3_SCROLL_INDICATOR_END; 3382 3383 /** 3384 * Left-shift required to translate between public scroll indicator flags 3385 * and internal PFLAGS3 flags. When used as a right-shift, translates 3386 * PFLAGS3 flags to public flags. 3387 */ 3388 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 3389 3390 /** @hide */ 3391 @Retention(RetentionPolicy.SOURCE) 3392 @IntDef(flag = true, prefix = { "SCROLL_INDICATOR_" }, value = { 3393 SCROLL_INDICATOR_TOP, 3394 SCROLL_INDICATOR_BOTTOM, 3395 SCROLL_INDICATOR_LEFT, 3396 SCROLL_INDICATOR_RIGHT, 3397 SCROLL_INDICATOR_START, 3398 SCROLL_INDICATOR_END, 3399 }) 3400 public @interface ScrollIndicators {} 3401 3402 /** 3403 * Scroll indicator direction for the top edge of the view. 3404 * 3405 * @see #setScrollIndicators(int) 3406 * @see #setScrollIndicators(int, int) 3407 * @see #getScrollIndicators() 3408 */ 3409 public static final int SCROLL_INDICATOR_TOP = 3410 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3411 3412 /** 3413 * Scroll indicator direction for the bottom edge of the view. 3414 * 3415 * @see #setScrollIndicators(int) 3416 * @see #setScrollIndicators(int, int) 3417 * @see #getScrollIndicators() 3418 */ 3419 public static final int SCROLL_INDICATOR_BOTTOM = 3420 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3421 3422 /** 3423 * Scroll indicator direction for the left edge of the view. 3424 * 3425 * @see #setScrollIndicators(int) 3426 * @see #setScrollIndicators(int, int) 3427 * @see #getScrollIndicators() 3428 */ 3429 public static final int SCROLL_INDICATOR_LEFT = 3430 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3431 3432 /** 3433 * Scroll indicator direction for the right edge of the view. 3434 * 3435 * @see #setScrollIndicators(int) 3436 * @see #setScrollIndicators(int, int) 3437 * @see #getScrollIndicators() 3438 */ 3439 public static final int SCROLL_INDICATOR_RIGHT = 3440 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3441 3442 /** 3443 * Scroll indicator direction for the starting edge of the view. 3444 * <p> 3445 * Resolved according to the view's layout direction, see 3446 * {@link #getLayoutDirection()} for more information. 3447 * 3448 * @see #setScrollIndicators(int) 3449 * @see #setScrollIndicators(int, int) 3450 * @see #getScrollIndicators() 3451 */ 3452 public static final int SCROLL_INDICATOR_START = 3453 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3454 3455 /** 3456 * Scroll indicator direction for the ending edge of the view. 3457 * <p> 3458 * Resolved according to the view's layout direction, see 3459 * {@link #getLayoutDirection()} for more information. 3460 * 3461 * @see #setScrollIndicators(int) 3462 * @see #setScrollIndicators(int, int) 3463 * @see #getScrollIndicators() 3464 */ 3465 public static final int SCROLL_INDICATOR_END = 3466 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3467 3468 /** 3469 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 3470 * into this view.<p> 3471 */ 3472 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 3473 3474 /** 3475 * Flag indicating that the view is a root of a keyboard navigation cluster. 3476 * 3477 * @see #isKeyboardNavigationCluster() 3478 * @see #setKeyboardNavigationCluster(boolean) 3479 */ 3480 private static final int PFLAG3_CLUSTER = 0x8000; 3481 3482 /** 3483 * Flag indicating that the view is autofilled 3484 * 3485 * @see #isAutofilled() 3486 * @see #setAutofilled(boolean, boolean) 3487 */ 3488 private static final int PFLAG3_IS_AUTOFILLED = 0x10000; 3489 3490 /** 3491 * Indicates that the user is currently touching the screen. 3492 * Currently used for the tooltip positioning only. 3493 */ 3494 private static final int PFLAG3_FINGER_DOWN = 0x20000; 3495 3496 /** 3497 * Flag indicating that this view is the default-focus view. 3498 * 3499 * @see #isFocusedByDefault() 3500 * @see #setFocusedByDefault(boolean) 3501 */ 3502 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 3503 3504 /** 3505 * Shift for the bits in {@link #mPrivateFlags3} related to the 3506 * "importantForAutofill" attribute. 3507 */ 3508 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19; 3509 3510 /** 3511 * Mask for obtaining the bits which specify how to determine 3512 * whether a view is important for autofill. 3513 */ 3514 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 3515 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO 3516 | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 3517 | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS) 3518 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 3519 3520 /** 3521 * Whether this view has rendered elements that overlap (see {@link 3522 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 3523 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 3524 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 3525 * determined by whatever {@link #hasOverlappingRendering()} returns. 3526 */ 3527 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 3528 3529 /** 3530 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 3531 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 3532 */ 3533 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 3534 3535 /** 3536 * Flag indicating that the view is temporarily detached from the parent view. 3537 * 3538 * @see #onStartTemporaryDetach() 3539 * @see #onFinishTemporaryDetach() 3540 */ 3541 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3542 3543 /** 3544 * Flag indicating that the view does not wish to be revealed within its parent 3545 * hierarchy when it gains focus. Expressed in the negative since the historical 3546 * default behavior is to reveal on focus; this flag suppresses that behavior. 3547 * 3548 * @see #setRevealOnFocusHint(boolean) 3549 * @see #getRevealOnFocusHint() 3550 */ 3551 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3552 3553 /** 3554 * Flag indicating that when layout is completed we should notify 3555 * that the view was entered for autofill purposes. To minimize 3556 * showing autofill for views not visible to the user we evaluate 3557 * user visibility which cannot be done until the view is laid out. 3558 */ 3559 static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000; 3560 3561 /** 3562 * Works like focusable for screen readers, but without the side effects on input focus. 3563 * @see #setScreenReaderFocusable(boolean) 3564 */ 3565 private static final int PFLAG3_SCREEN_READER_FOCUSABLE = 0x10000000; 3566 3567 /** 3568 * The last aggregated visibility. Used to detect when it truly changes. 3569 */ 3570 private static final int PFLAG3_AGGREGATED_VISIBLE = 0x20000000; 3571 3572 /** 3573 * Used to indicate that {@link #mAutofillId} was explicitly set through 3574 * {@link #setAutofillId(AutofillId)}. 3575 */ 3576 private static final int PFLAG3_AUTOFILLID_EXPLICITLY_SET = 0x40000000; 3577 3578 /** 3579 * Indicates if the View is a heading for accessibility purposes 3580 */ 3581 private static final int PFLAG3_ACCESSIBILITY_HEADING = 0x80000000; 3582 3583 /* End of masks for mPrivateFlags3 */ 3584 3585 /* 3586 * Masks for mPrivateFlags4, as generated by dumpFlags(): 3587 * 3588 * |-------|-------|-------|-------| 3589 * 1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK 3590 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED 3591 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED 3592 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3593 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE 3594 * 11 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK 3595 * 1 PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS 3596 * 1 PFLAG4_AUTOFILL_HIDE_HIGHLIGHT 3597 * 11 PFLAG4_SCROLL_CAPTURE_HINT_MASK 3598 * 1 PFLAG4_ALLOW_CLICK_WHEN_DISABLED 3599 * 1 PFLAG4_DETACHED 3600 * 1 PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE 3601 * 1 PFLAG4_DRAG_A11Y_STARTED 3602 * 1 PFLAG4_AUTO_HANDWRITING_INITIATION_ENABLED 3603 * 1 PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER 3604 * 1 PFLAG4_TRAVERSAL_TRACING_ENABLED 3605 * 1 PFLAG4_RELAYOUT_TRACING_ENABLED 3606 * |-------|-------|-------|-------| 3607 */ 3608 3609 /** 3610 * Mask for obtaining the bits which specify how to determine 3611 * whether a view is important for autofill. 3612 * 3613 * <p>NOTE: the important for content capture values were the first flags added and are set in 3614 * the rightmost position, so we don't need to shift them 3615 */ 3616 private static final int PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK = 3617 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO | IMPORTANT_FOR_CONTENT_CAPTURE_YES 3618 | IMPORTANT_FOR_CONTENT_CAPTURE_NO 3619 | IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 3620 | IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS; 3621 3622 /* 3623 * Variables used to control when the IntelligenceManager.notifyNodeAdded()/removed() methods 3624 * should be called. 3625 * 3626 * The idea is to call notifyAppeared() after the view is layout and visible, then call 3627 * notifyDisappeared() when it's gone (without known when it was removed from the parent). 3628 */ 3629 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10; 3630 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20; 3631 3632 /* 3633 * Flags used to cache the value returned by isImportantForContentCapture while the view 3634 * hierarchy is being traversed. 3635 */ 3636 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED = 0x40; 3637 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE = 0x80; 3638 3639 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK = 3640 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3641 | PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 3642 3643 /** 3644 * @see #OPTIONAL_FITS_SYSTEM_WINDOWS 3645 */ 3646 static final int PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS = 0x000000100; 3647 3648 /** 3649 * Flag indicating the field should not have yellow highlight when autofilled. 3650 */ 3651 private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x200; 3652 3653 /** 3654 * Shift for the bits in {@link #mPrivateFlags4} related to scroll capture. 3655 */ 3656 static final int PFLAG4_SCROLL_CAPTURE_HINT_SHIFT = 10; 3657 3658 static final int PFLAG4_SCROLL_CAPTURE_HINT_MASK = (SCROLL_CAPTURE_HINT_INCLUDE 3659 | SCROLL_CAPTURE_HINT_EXCLUDE | SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS) 3660 << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; 3661 3662 /** 3663 * Indicates if the view can receive click events when disabled. 3664 */ 3665 private static final int PFLAG4_ALLOW_CLICK_WHEN_DISABLED = 0x000001000; 3666 3667 /** 3668 * Indicates if the view is just detached. 3669 */ 3670 private static final int PFLAG4_DETACHED = 0x000002000; 3671 3672 /** 3673 * Indicates that the view has transient state because the system is translating it. 3674 */ 3675 private static final int PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE = 0x000004000; 3676 3677 /** 3678 * Indicates that the view has started a drag with {@link AccessibilityAction#ACTION_DRAG_START} 3679 */ 3680 private static final int PFLAG4_DRAG_A11Y_STARTED = 0x000008000; 3681 3682 /** 3683 * Indicates that the view enables auto handwriting initiation. 3684 */ 3685 private static final int PFLAG4_AUTO_HANDWRITING_ENABLED = 0x000010000; 3686 3687 /** 3688 * Indicates that the view is important for Credential Manager. 3689 */ 3690 private static final int PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER = 0x000020000; 3691 3692 /** 3693 * When set, measure and layout passes of this view will be logged with {@link Trace}, so we 3694 * can better debug jank due to complex view hierarchies. 3695 */ 3696 private static final int PFLAG4_TRAVERSAL_TRACING_ENABLED = 0x000040000; 3697 3698 /** 3699 * When set, emits a {@link Trace} instant event and stacktrace every time a requestLayout of 3700 * this class happens. 3701 */ 3702 private static final int PFLAG4_RELAYOUT_TRACING_ENABLED = 0x000080000; 3703 3704 /* End of masks for mPrivateFlags4 */ 3705 3706 /** @hide */ 3707 protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0; 3708 /** @hide */ 3709 protected static final int VIEW_STRUCTURE_FOR_AUTOFILL = 1; 3710 /** @hide */ 3711 protected static final int VIEW_STRUCTURE_FOR_CONTENT_CAPTURE = 2; 3712 3713 /** @hide */ 3714 @IntDef(flag = true, prefix = { "VIEW_STRUCTURE_FOR" }, value = { 3715 VIEW_STRUCTURE_FOR_ASSIST, 3716 VIEW_STRUCTURE_FOR_AUTOFILL, 3717 VIEW_STRUCTURE_FOR_CONTENT_CAPTURE 3718 }) 3719 @Retention(RetentionPolicy.SOURCE) 3720 public @interface ViewStructureType {} 3721 3722 /** 3723 * Always allow a user to over-scroll this view, provided it is a 3724 * view that can scroll. 3725 * 3726 * @see #getOverScrollMode() 3727 * @see #setOverScrollMode(int) 3728 */ 3729 public static final int OVER_SCROLL_ALWAYS = 0; 3730 3731 /** 3732 * Allow a user to over-scroll this view only if the content is large 3733 * enough to meaningfully scroll, provided it is a view that can scroll. 3734 * 3735 * @see #getOverScrollMode() 3736 * @see #setOverScrollMode(int) 3737 */ 3738 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 3739 3740 /** 3741 * Never allow a user to over-scroll this view. 3742 * 3743 * @see #getOverScrollMode() 3744 * @see #setOverScrollMode(int) 3745 */ 3746 public static final int OVER_SCROLL_NEVER = 2; 3747 3748 /** 3749 * Special constant for {@link #setSystemUiVisibility(int)}: View has 3750 * requested the system UI (status bar) to be visible (the default). 3751 * 3752 * @see #setSystemUiVisibility(int) 3753 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 3754 * instead. 3755 */ 3756 @Deprecated 3757 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 3758 3759 /** 3760 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 3761 * system UI to enter an unobtrusive "low profile" mode. 3762 * 3763 * <p>This is for use in games, book readers, video players, or any other 3764 * "immersive" application where the usual system chrome is deemed too distracting. 3765 * 3766 * <p>In low profile mode, the status bar and/or navigation icons may dim. 3767 * 3768 * @see #setSystemUiVisibility(int) 3769 * @deprecated Low profile mode is deprecated. Hide the system bars instead if the application 3770 * needs to be in a unobtrusive mode. Use {@link WindowInsetsController#hide(int)} with 3771 * {@link Type#systemBars()}. 3772 */ 3773 @Deprecated 3774 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 3775 3776 /** 3777 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 3778 * system navigation be temporarily hidden. 3779 * 3780 * <p>This is an even less obtrusive state than that called for by 3781 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 3782 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 3783 * those to disappear. This is useful (in conjunction with the 3784 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 3785 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 3786 * window flags) for displaying content using every last pixel on the display. 3787 * 3788 * <p>There is a limitation: because navigation controls are so important, the least user 3789 * interaction will cause them to reappear immediately. When this happens, both 3790 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 3791 * so that both elements reappear at the same time. 3792 * 3793 * @see #setSystemUiVisibility(int) 3794 * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#navigationBars()} 3795 * instead. 3796 */ 3797 @Deprecated 3798 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 3799 3800 /** 3801 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 3802 * into the normal fullscreen mode so that its content can take over the screen 3803 * while still allowing the user to interact with the application. 3804 * 3805 * <p>This has the same visual effect as 3806 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 3807 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 3808 * meaning that non-critical screen decorations (such as the status bar) will be 3809 * hidden while the user is in the View's window, focusing the experience on 3810 * that content. Unlike the window flag, if you are using ActionBar in 3811 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3812 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 3813 * hide the action bar. 3814 * 3815 * <p>This approach to going fullscreen is best used over the window flag when 3816 * it is a transient state -- that is, the application does this at certain 3817 * points in its user interaction where it wants to allow the user to focus 3818 * on content, but not as a continuous state. For situations where the application 3819 * would like to simply stay full screen the entire time (such as a game that 3820 * wants to take over the screen), the 3821 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 3822 * is usually a better approach. The state set here will be removed by the system 3823 * in various situations (such as the user moving to another application) like 3824 * the other system UI states. 3825 * 3826 * <p>When using this flag, the application should provide some easy facility 3827 * for the user to go out of it. A common example would be in an e-book 3828 * reader, where tapping on the screen brings back whatever screen and UI 3829 * decorations that had been hidden while the user was immersed in reading 3830 * the book. 3831 * 3832 * @see #setSystemUiVisibility(int) 3833 * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#statusBars()} 3834 * instead. 3835 */ 3836 @Deprecated 3837 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 3838 3839 /** 3840 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 3841 * flags, we would like a stable view of the content insets given to 3842 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 3843 * will always represent the worst case that the application can expect 3844 * as a continuous state. In the stock Android UI this is the space for 3845 * the system bar, nav bar, and status bar, but not more transient elements 3846 * such as an input method. 3847 * 3848 * The stable layout your UI sees is based on the system UI modes you can 3849 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 3850 * then you will get a stable layout for changes of the 3851 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 3852 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 3853 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 3854 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 3855 * with a stable layout. (Note that you should avoid using 3856 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 3857 * 3858 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 3859 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 3860 * then a hidden status bar will be considered a "stable" state for purposes 3861 * here. This allows your UI to continually hide the status bar, while still 3862 * using the system UI flags to hide the action bar while still retaining 3863 * a stable layout. Note that changing the window fullscreen flag will never 3864 * provide a stable layout for a clean transition. 3865 * 3866 * <p>If you are using ActionBar in 3867 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3868 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 3869 * insets it adds to those given to the application. 3870 * 3871 * @deprecated Use {@link WindowInsets#getInsetsIgnoringVisibility(int)} instead to retrieve 3872 * insets that don't change when system bars change visibility state. 3873 */ 3874 @Deprecated 3875 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 3876 3877 /** 3878 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3879 * to be laid out as if it has requested 3880 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 3881 * allows it to avoid artifacts when switching in and out of that mode, at 3882 * the expense that some of its user interface may be covered by screen 3883 * decorations when they are shown. You can perform layout of your inner 3884 * UI elements to account for the navigation system UI through the 3885 * {@link #fitSystemWindows(Rect)} method. 3886 * 3887 * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with 3888 * {@link Type#navigationBars()}. For non-floating windows that fill the screen, call 3889 * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. 3890 */ 3891 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 3892 3893 /** 3894 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3895 * to be laid out as if it has requested 3896 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 3897 * allows it to avoid artifacts when switching in and out of that mode, at 3898 * the expense that some of its user interface may be covered by screen 3899 * decorations when they are shown. You can perform layout of your inner 3900 * UI elements to account for non-fullscreen system UI through the 3901 * {@link #fitSystemWindows(Rect)} method. 3902 * 3903 * <p>Note: on displays that have a {@link DisplayCutout}, the window may still be placed 3904 * differently than if {@link #SYSTEM_UI_FLAG_FULLSCREEN} was set, if the 3905 * window's {@link WindowManager.LayoutParams#layoutInDisplayCutoutMode 3906 * layoutInDisplayCutoutMode} is 3907 * {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3908 * LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT}. To avoid this, use either of the other modes. 3909 * 3910 * @see WindowManager.LayoutParams#layoutInDisplayCutoutMode 3911 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3912 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 3913 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 3914 * 3915 * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with 3916 * {@link Type#statusBars()} ()}. For non-floating windows that fill the screen, call 3917 * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. 3918 */ 3919 @Deprecated 3920 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 3921 3922 /** 3923 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3924 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 3925 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 3926 * user interaction. 3927 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 3928 * has an effect when used in combination with that flag.</p> 3929 * 3930 * @deprecated Use {@link WindowInsetsController#BEHAVIOR_DEFAULT} instead. 3931 */ 3932 @Deprecated 3933 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 3934 3935 /** 3936 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3937 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 3938 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 3939 * experience while also hiding the system bars. If this flag is not set, 3940 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 3941 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 3942 * if the user swipes from the top of the screen. 3943 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 3944 * system gestures, such as swiping from the top of the screen. These transient system bars 3945 * will overlay app's content, may have some degree of transparency, and will automatically 3946 * hide after a short timeout. 3947 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 3948 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 3949 * with one or both of those flags.</p> 3950 * 3951 * @deprecated Use {@link WindowInsetsController#BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE} instead. 3952 */ 3953 @Deprecated 3954 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 3955 3956 /** 3957 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 3958 * is compatible with light status bar backgrounds. 3959 * 3960 * <p>For this to take effect, the window must request 3961 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3962 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3963 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 3964 * FLAG_TRANSLUCENT_STATUS}. 3965 * 3966 * @see android.R.attr#windowLightStatusBar 3967 * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_STATUS_BARS} instead. 3968 */ 3969 @Deprecated 3970 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 3971 3972 /** 3973 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3974 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3975 */ 3976 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 3977 3978 /** 3979 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3980 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3981 */ 3982 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 3983 3984 /** 3985 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 3986 * that is compatible with light navigation bar backgrounds. 3987 * 3988 * <p>For this to take effect, the window must request 3989 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3990 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3991 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 3992 * FLAG_TRANSLUCENT_NAVIGATION}. 3993 * 3994 * @see android.R.attr#windowLightNavigationBar 3995 * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_NAVIGATION_BARS} instead. 3996 */ 3997 @Deprecated 3998 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 3999 4000 /** 4001 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 4002 */ 4003 @Deprecated 4004 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 4005 4006 /** 4007 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 4008 */ 4009 @Deprecated 4010 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 4011 4012 /** 4013 * @hide 4014 * 4015 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4016 * out of the public fields to keep the undefined bits out of the developer's way. 4017 * 4018 * Flag to make the status bar not expandable. Unless you also 4019 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 4020 */ 4021 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4022 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 4023 4024 /** 4025 * @hide 4026 * 4027 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4028 * out of the public fields to keep the undefined bits out of the developer's way. 4029 * 4030 * Flag to hide notification icons and scrolling ticker text. 4031 */ 4032 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 4033 4034 /** 4035 * @hide 4036 * 4037 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4038 * out of the public fields to keep the undefined bits out of the developer's way. 4039 * 4040 * Flag to disable incoming notification alerts. This will not block 4041 * icons, but it will block sound, vibrating and other visual or aural notifications. 4042 */ 4043 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 4044 4045 /** 4046 * @hide 4047 * 4048 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4049 * out of the public fields to keep the undefined bits out of the developer's way. 4050 * 4051 * Flag to hide only the scrolling ticker. Note that 4052 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 4053 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 4054 */ 4055 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 4056 4057 /** 4058 * @hide 4059 * 4060 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4061 * out of the public fields to keep the undefined bits out of the developer's way. 4062 * 4063 * Flag to hide the center system info area. 4064 */ 4065 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 4066 4067 /** 4068 * @hide 4069 * 4070 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4071 * out of the public fields to keep the undefined bits out of the developer's way. 4072 * 4073 * Flag to hide only the home button. Don't use this 4074 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4075 */ 4076 @UnsupportedAppUsage 4077 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 4078 4079 /** 4080 * @hide 4081 * 4082 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4083 * out of the public fields to keep the undefined bits out of the developer's way. 4084 * 4085 * Flag to hide only the back button. Don't use this 4086 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4087 */ 4088 @UnsupportedAppUsage 4089 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 4090 4091 /** 4092 * @hide 4093 * 4094 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4095 * out of the public fields to keep the undefined bits out of the developer's way. 4096 * 4097 * Flag to hide only the clock. You might use this if your activity has 4098 * its own clock making the status bar's clock redundant. 4099 */ 4100 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 4101 4102 /** 4103 * @hide 4104 * 4105 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4106 * out of the public fields to keep the undefined bits out of the developer's way. 4107 * 4108 * Flag to hide only the recent apps button. Don't use this 4109 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4110 */ 4111 @UnsupportedAppUsage 4112 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 4113 4114 /** 4115 * @hide 4116 * 4117 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4118 * out of the public fields to keep the undefined bits out of the developer's way. 4119 * 4120 * Flag to disable the global search gesture. Don't use this 4121 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 4122 */ 4123 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 4124 4125 /** 4126 * @hide 4127 * 4128 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4129 * out of the public fields to keep the undefined bits out of the developer's way. 4130 * 4131 * Flag to disable the ongoing call chip. 4132 */ 4133 public static final int STATUS_BAR_DISABLE_ONGOING_CALL_CHIP = 0x04000000; 4134 4135 /** 4136 * @hide 4137 */ 4138 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 4139 4140 /** 4141 * These are the system UI flags that can be cleared by events outside 4142 * of an application. Currently this is just the ability to tap on the 4143 * screen while hiding the navigation bar to have it return. 4144 * @hide 4145 */ 4146 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 4147 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 4148 | SYSTEM_UI_FLAG_FULLSCREEN; 4149 4150 /** 4151 * Flags that can impact the layout in relation to system UI. 4152 * 4153 * @deprecated System UI layout flags are deprecated. 4154 */ 4155 @Deprecated 4156 public static final int SYSTEM_UI_LAYOUT_FLAGS = 4157 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 4158 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 4159 4160 /** @hide */ 4161 @IntDef(flag = true, prefix = { "FIND_VIEWS_" }, value = { 4162 FIND_VIEWS_WITH_TEXT, 4163 FIND_VIEWS_WITH_CONTENT_DESCRIPTION 4164 }) 4165 @Retention(RetentionPolicy.SOURCE) 4166 public @interface FindViewFlags {} 4167 4168 /** 4169 * Find views that render the specified text. 4170 * 4171 * @see #findViewsWithText(ArrayList, CharSequence, int) 4172 */ 4173 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 4174 4175 /** 4176 * Find find views that contain the specified content description. 4177 * 4178 * @see #findViewsWithText(ArrayList, CharSequence, int) 4179 */ 4180 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 4181 4182 /** 4183 * Find views that contain {@link AccessibilityNodeProvider}. Such 4184 * a View is a root of virtual view hierarchy and may contain the searched 4185 * text. If this flag is set Views with providers are automatically 4186 * added and it is a responsibility of the client to call the APIs of 4187 * the provider to determine whether the virtual tree rooted at this View 4188 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 4189 * representing the virtual views with this text. 4190 * 4191 * @see #findViewsWithText(ArrayList, CharSequence, int) 4192 * 4193 * @hide 4194 */ 4195 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 4196 4197 /** 4198 * The undefined cursor position. 4199 * 4200 * @hide 4201 */ 4202 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 4203 4204 /** 4205 * Indicates that the screen has changed state and is now off. 4206 * 4207 * @see #onScreenStateChanged(int) 4208 */ 4209 public static final int SCREEN_STATE_OFF = 0x0; 4210 4211 /** 4212 * Indicates that the screen has changed state and is now on. 4213 * 4214 * @see #onScreenStateChanged(int) 4215 */ 4216 public static final int SCREEN_STATE_ON = 0x1; 4217 4218 /** 4219 * Indicates no axis of view scrolling. 4220 */ 4221 public static final int SCROLL_AXIS_NONE = 0; 4222 4223 /** 4224 * Indicates scrolling along the horizontal axis. 4225 */ 4226 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 4227 4228 /** 4229 * Indicates scrolling along the vertical axis. 4230 */ 4231 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 4232 4233 /** 4234 * Controls the over-scroll mode for this view. 4235 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 4236 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 4237 * and {@link #OVER_SCROLL_NEVER}. 4238 */ 4239 private int mOverScrollMode; 4240 4241 /** 4242 * The parent this view is attached to. 4243 * {@hide} 4244 * 4245 * @see #getParent() 4246 */ 4247 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4248 protected ViewParent mParent; 4249 4250 /** 4251 * {@hide} 4252 * 4253 * Not available for general use. If you need help, hang up and then dial one of the following 4254 * public APIs: 4255 * 4256 * @see #isAttachedToWindow() for current attach state 4257 * @see #onAttachedToWindow() for subclasses performing work when becoming attached 4258 * @see #onDetachedFromWindow() for subclasses performing work when becoming detached 4259 * @see OnAttachStateChangeListener for other code performing work on attach/detach 4260 * @see #getHandler() for posting messages to this view's UI thread/looper 4261 * @see #getParent() for interacting with the parent chain 4262 * @see #getWindowToken() for the current window token 4263 * @see #getRootView() for the view at the root of the attached hierarchy 4264 * @see #getDisplay() for the Display this view is presented on 4265 * @see #getRootWindowInsets() for the current insets applied to the whole attached window 4266 * @see #hasWindowFocus() for whether the attached window is currently focused 4267 * @see #getWindowVisibility() for checking the visibility of the attached window 4268 */ 4269 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4270 AttachInfo mAttachInfo; 4271 4272 /** 4273 * {@hide} 4274 */ 4275 @ViewDebug.ExportedProperty(flagMapping = { 4276 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 4277 name = "FORCE_LAYOUT"), 4278 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 4279 name = "LAYOUT_REQUIRED"), 4280 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 4281 name = "DRAWING_CACHE_INVALID", outputIf = false), 4282 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 4283 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 4284 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 4285 }, formatToHexString = true) 4286 4287 /* @hide */ 4288 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769414) 4289 public int mPrivateFlags; 4290 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768943) 4291 int mPrivateFlags2; 4292 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 129147060) 4293 int mPrivateFlags3; 4294 4295 private int mPrivateFlags4; 4296 4297 /** 4298 * This view's request for the visibility of the status bar. 4299 * @hide 4300 */ 4301 @ViewDebug.ExportedProperty(flagMapping = { 4302 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 4303 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 4304 name = "LOW_PROFILE"), 4305 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4306 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4307 name = "HIDE_NAVIGATION"), 4308 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_FULLSCREEN, 4309 equals = SYSTEM_UI_FLAG_FULLSCREEN, 4310 name = "FULLSCREEN"), 4311 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4312 equals = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4313 name = "LAYOUT_STABLE"), 4314 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4315 equals = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4316 name = "LAYOUT_HIDE_NAVIGATION"), 4317 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4318 equals = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4319 name = "LAYOUT_FULLSCREEN"), 4320 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE, 4321 equals = SYSTEM_UI_FLAG_IMMERSIVE, 4322 name = "IMMERSIVE"), 4323 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4324 equals = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4325 name = "IMMERSIVE_STICKY"), 4326 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4327 equals = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4328 name = "LIGHT_STATUS_BAR"), 4329 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4330 equals = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4331 name = "LIGHT_NAVIGATION_BAR"), 4332 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_EXPAND, 4333 equals = STATUS_BAR_DISABLE_EXPAND, 4334 name = "STATUS_BAR_DISABLE_EXPAND"), 4335 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4336 equals = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4337 name = "STATUS_BAR_DISABLE_NOTIFICATION_ICONS"), 4338 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4339 equals = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4340 name = "STATUS_BAR_DISABLE_NOTIFICATION_ALERTS"), 4341 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4342 equals = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4343 name = "STATUS_BAR_DISABLE_NOTIFICATION_TICKER"), 4344 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SYSTEM_INFO, 4345 equals = STATUS_BAR_DISABLE_SYSTEM_INFO, 4346 name = "STATUS_BAR_DISABLE_SYSTEM_INFO"), 4347 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_HOME, 4348 equals = STATUS_BAR_DISABLE_HOME, 4349 name = "STATUS_BAR_DISABLE_HOME"), 4350 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_BACK, 4351 equals = STATUS_BAR_DISABLE_BACK, 4352 name = "STATUS_BAR_DISABLE_BACK"), 4353 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_CLOCK, 4354 equals = STATUS_BAR_DISABLE_CLOCK, 4355 name = "STATUS_BAR_DISABLE_CLOCK"), 4356 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_RECENT, 4357 equals = STATUS_BAR_DISABLE_RECENT, 4358 name = "STATUS_BAR_DISABLE_RECENT"), 4359 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH, 4360 equals = STATUS_BAR_DISABLE_SEARCH, 4361 name = "STATUS_BAR_DISABLE_SEARCH"), 4362 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4363 equals = STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4364 name = "STATUS_BAR_DISABLE_ONGOING_CALL_CHIP") 4365 }, formatToHexString = true) 4366 @SystemUiVisibility 4367 int mSystemUiVisibility; 4368 4369 /** 4370 * @hide 4371 */ 4372 @IntDef(flag = true, prefix = "", value = { 4373 SYSTEM_UI_FLAG_LOW_PROFILE, 4374 SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4375 SYSTEM_UI_FLAG_FULLSCREEN, 4376 SYSTEM_UI_FLAG_LAYOUT_STABLE, 4377 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4378 SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4379 SYSTEM_UI_FLAG_IMMERSIVE, 4380 SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4381 SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4382 SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4383 STATUS_BAR_DISABLE_EXPAND, 4384 STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4385 STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4386 STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4387 STATUS_BAR_DISABLE_SYSTEM_INFO, 4388 STATUS_BAR_DISABLE_HOME, 4389 STATUS_BAR_DISABLE_BACK, 4390 STATUS_BAR_DISABLE_CLOCK, 4391 STATUS_BAR_DISABLE_RECENT, 4392 STATUS_BAR_DISABLE_SEARCH, 4393 STATUS_BAR_DISABLE_ONGOING_CALL_CHIP, 4394 }) 4395 @Retention(RetentionPolicy.SOURCE) 4396 public @interface SystemUiVisibility {} 4397 4398 /** 4399 * Reference count for transient state. 4400 * @see #setHasTransientState(boolean) 4401 */ 4402 int mTransientStateCount = 0; 4403 4404 /** 4405 * Count of how many windows this view has been attached to. 4406 */ 4407 int mWindowAttachCount; 4408 4409 /** 4410 * The layout parameters associated with this view and used by the parent 4411 * {@link android.view.ViewGroup} to determine how this view should be 4412 * laid out. 4413 * 4414 * The field should not be used directly. Instead {@link #getLayoutParams()} and {@link 4415 * #setLayoutParams(ViewGroup.LayoutParams)} should be used. The setter guarantees internal 4416 * state correctness of the class. 4417 * {@hide} 4418 */ 4419 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4420 protected ViewGroup.LayoutParams mLayoutParams; 4421 4422 /** 4423 * The view flags hold various views states. 4424 * 4425 * Use {@link #setTransitionVisibility(int)} to change the visibility of this view without 4426 * triggering updates. 4427 * {@hide} 4428 */ 4429 @ViewDebug.ExportedProperty(formatToHexString = true) 4430 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4431 int mViewFlags; 4432 4433 static class TransformationInfo { 4434 /** 4435 * The transform matrix for the View. This transform is calculated internally 4436 * based on the translation, rotation, and scale properties. 4437 * 4438 * Do *not* use this variable directly; instead call getMatrix(), which will 4439 * load the value from the View's RenderNode. 4440 */ 4441 private final Matrix mMatrix = new Matrix(); 4442 4443 /** 4444 * The inverse transform matrix for the View. This transform is calculated 4445 * internally based on the translation, rotation, and scale properties. 4446 * 4447 * Do *not* use this variable directly; instead call getInverseMatrix(), 4448 * which will load the value from the View's RenderNode. 4449 */ 4450 private Matrix mInverseMatrix; 4451 4452 /** 4453 * The opacity of the View. This is a value from 0 to 1, where 0 means 4454 * completely transparent and 1 means completely opaque. 4455 */ 4456 @ViewDebug.ExportedProperty 4457 private float mAlpha = 1f; 4458 4459 /** 4460 * The opacity of the view as manipulated by the Fade transition. This is a 4461 * property only used by transitions, which is composited with the other alpha 4462 * values to calculate the final visual alpha value. 4463 */ 4464 float mTransitionAlpha = 1f; 4465 } 4466 4467 /** @hide */ 4468 @UnsupportedAppUsage 4469 public TransformationInfo mTransformationInfo; 4470 4471 /** 4472 * Current clip bounds. to which all drawing of this view are constrained. 4473 */ 4474 @ViewDebug.ExportedProperty(category = "drawing") 4475 Rect mClipBounds = null; 4476 4477 private boolean mLastIsOpaque; 4478 4479 /** 4480 * The distance in pixels from the left edge of this view's parent 4481 * to the left edge of this view. 4482 * {@hide} 4483 */ 4484 @ViewDebug.ExportedProperty(category = "layout") 4485 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4486 protected int mLeft; 4487 /** 4488 * The distance in pixels from the left edge of this view's parent 4489 * to the right edge of this view. 4490 * {@hide} 4491 */ 4492 @ViewDebug.ExportedProperty(category = "layout") 4493 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4494 protected int mRight; 4495 /** 4496 * The distance in pixels from the top edge of this view's parent 4497 * to the top edge of this view. 4498 * {@hide} 4499 */ 4500 @ViewDebug.ExportedProperty(category = "layout") 4501 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4502 protected int mTop; 4503 /** 4504 * The distance in pixels from the top edge of this view's parent 4505 * to the bottom edge of this view. 4506 * {@hide} 4507 */ 4508 @ViewDebug.ExportedProperty(category = "layout") 4509 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4510 protected int mBottom; 4511 4512 /** 4513 * The offset, in pixels, by which the content of this view is scrolled 4514 * horizontally. 4515 * Please use {@link View#getScrollX()} and {@link View#setScrollX(int)} instead of 4516 * accessing these directly. 4517 * {@hide} 4518 */ 4519 @ViewDebug.ExportedProperty(category = "scrolling") 4520 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4521 protected int mScrollX; 4522 /** 4523 * The offset, in pixels, by which the content of this view is scrolled 4524 * vertically. 4525 * Please use {@link View#getScrollY()} and {@link View#setScrollY(int)} instead of 4526 * accessing these directly. 4527 * {@hide} 4528 */ 4529 @ViewDebug.ExportedProperty(category = "scrolling") 4530 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4531 protected int mScrollY; 4532 4533 /** 4534 * The final computed left padding in pixels that is used for drawing. This is the distance in 4535 * pixels between the left edge of this view and the left edge of its content. 4536 * {@hide} 4537 */ 4538 @ViewDebug.ExportedProperty(category = "padding") 4539 @UnsupportedAppUsage 4540 protected int mPaddingLeft = 0; 4541 /** 4542 * The final computed right padding in pixels that is used for drawing. This is the distance in 4543 * pixels between the right edge of this view and the right edge of its content. 4544 * {@hide} 4545 */ 4546 @ViewDebug.ExportedProperty(category = "padding") 4547 @UnsupportedAppUsage 4548 protected int mPaddingRight = 0; 4549 /** 4550 * The final computed top padding in pixels that is used for drawing. This is the distance in 4551 * pixels between the top edge of this view and the top edge of its content. 4552 * {@hide} 4553 */ 4554 @ViewDebug.ExportedProperty(category = "padding") 4555 @UnsupportedAppUsage 4556 protected int mPaddingTop; 4557 /** 4558 * The final computed bottom padding in pixels that is used for drawing. This is the distance in 4559 * pixels between the bottom edge of this view and the bottom edge of its content. 4560 * {@hide} 4561 */ 4562 @ViewDebug.ExportedProperty(category = "padding") 4563 @UnsupportedAppUsage 4564 protected int mPaddingBottom; 4565 4566 /** 4567 * The amount of pixel offset applied to the left edge of this view's handwriting bounds. 4568 */ 4569 private float mHandwritingBoundsOffsetLeft; 4570 4571 /** 4572 * The amount of pixel offset applied to the top edge of this view's handwriting bounds. 4573 */ 4574 private float mHandwritingBoundsOffsetTop; 4575 4576 /** 4577 * The amount of pixel offset applied to the right edge of this view's handwriting bounds. 4578 */ 4579 private float mHandwritingBoundsOffsetRight; 4580 4581 /** 4582 * The amount of pixel offset applied to the bottom edge of this view's handwriting bounds. 4583 */ 4584 private float mHandwritingBoundsOffsetBottom; 4585 4586 /** 4587 * The layout insets in pixels, that is the distance in pixels between the 4588 * visible edges of this view its bounds. 4589 */ 4590 private Insets mLayoutInsets; 4591 4592 /** 4593 * Briefly describes the state of the view and is primarily used for accessibility support. 4594 */ 4595 private CharSequence mStateDescription; 4596 4597 /** 4598 * Briefly describes the view and is primarily used for accessibility support. 4599 */ 4600 private CharSequence mContentDescription; 4601 4602 /** 4603 * If this view represents a distinct part of the window, it can have a title that labels the 4604 * area. 4605 */ 4606 private CharSequence mAccessibilityPaneTitle; 4607 4608 /** 4609 * Describes whether this view should only allow interactions from 4610 * {@link android.accessibilityservice.AccessibilityService}s with the 4611 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property 4612 * set to true. 4613 */ 4614 private int mExplicitAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_AUTO; 4615 /** Used to calculate and cache {@link #isAccessibilityDataSensitive()}. */ 4616 private int mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_AUTO; 4617 4618 /** 4619 * Specifies the id of a view for which this view serves as a label for 4620 * accessibility purposes. 4621 */ 4622 private int mLabelForId = View.NO_ID; 4623 4624 /** 4625 * Predicate for matching labeled view id with its label for 4626 * accessibility purposes. 4627 */ 4628 private MatchLabelForPredicate mMatchLabelForPredicate; 4629 4630 /** 4631 * Specifies a view before which this one is visited in accessibility traversal. 4632 */ 4633 private int mAccessibilityTraversalBeforeId = NO_ID; 4634 4635 /** 4636 * Specifies a view after which this one is visited in accessibility traversal. 4637 */ 4638 private int mAccessibilityTraversalAfterId = NO_ID; 4639 4640 /** 4641 * Predicate for matching a view by its id. 4642 */ 4643 private MatchIdPredicate mMatchIdPredicate; 4644 4645 /** 4646 * The right padding after RTL resolution, but before taking account of scroll bars. 4647 * 4648 * @hide 4649 */ 4650 @ViewDebug.ExportedProperty(category = "padding") 4651 protected int mUserPaddingRight; 4652 4653 /** 4654 * The resolved bottom padding before taking account of scroll bars. 4655 * 4656 * @hide 4657 */ 4658 @ViewDebug.ExportedProperty(category = "padding") 4659 protected int mUserPaddingBottom; 4660 4661 /** 4662 * The left padding after RTL resolution, but before taking account of scroll bars. 4663 * 4664 * @hide 4665 */ 4666 @ViewDebug.ExportedProperty(category = "padding") 4667 protected int mUserPaddingLeft; 4668 4669 /** 4670 * Cache the paddingStart set by the user to append to the scrollbar's size. 4671 * 4672 */ 4673 @ViewDebug.ExportedProperty(category = "padding") 4674 int mUserPaddingStart; 4675 4676 /** 4677 * Cache the paddingEnd set by the user to append to the scrollbar's size. 4678 * 4679 */ 4680 @ViewDebug.ExportedProperty(category = "padding") 4681 int mUserPaddingEnd; 4682 4683 /** 4684 * The left padding as set by a setter method, a background's padding, or via XML property 4685 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4686 * 4687 * @hide 4688 */ 4689 int mUserPaddingLeftInitial; 4690 4691 /** 4692 * The right padding as set by a setter method, a background's padding, or via XML property 4693 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4694 * 4695 * @hide 4696 */ 4697 int mUserPaddingRightInitial; 4698 4699 /** 4700 * Default undefined padding 4701 */ 4702 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 4703 4704 /** 4705 * Cache if a left padding has been defined explicitly via padding, horizontal padding, 4706 * or leftPadding in XML, or by setPadding(...) or setRelativePadding(...) 4707 */ 4708 private boolean mLeftPaddingDefined = false; 4709 4710 /** 4711 * Cache if a right padding has been defined explicitly via padding, horizontal padding, 4712 * or rightPadding in XML, or by setPadding(...) or setRelativePadding(...) 4713 */ 4714 private boolean mRightPaddingDefined = false; 4715 4716 /** 4717 * @hide 4718 */ 4719 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 4720 /** 4721 * @hide 4722 */ 4723 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 4724 4725 private LongSparseLongArray mMeasureCache; 4726 4727 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 4728 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4729 private Drawable mBackground; 4730 private TintInfo mBackgroundTint; 4731 4732 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 4733 private ForegroundInfo mForegroundInfo; 4734 4735 private Drawable mScrollIndicatorDrawable; 4736 4737 /** 4738 * RenderNode used for backgrounds. 4739 * <p> 4740 * When non-null and valid, this is expected to contain an up-to-date copy 4741 * of the background drawable. It is cleared on temporary detach, and reset 4742 * on cleanup. 4743 * @hide 4744 */ 4745 RenderNode mBackgroundRenderNode; 4746 4747 @UnsupportedAppUsage 4748 private int mBackgroundResource; 4749 private boolean mBackgroundSizeChanged; 4750 4751 /** The default focus highlight. 4752 * @see #mDefaultFocusHighlightEnabled 4753 * @see Drawable#hasFocusStateSpecified() 4754 */ 4755 private Drawable mDefaultFocusHighlight; 4756 private Drawable mDefaultFocusHighlightCache; 4757 private boolean mDefaultFocusHighlightSizeChanged; 4758 /** 4759 * True if the default focus highlight is needed on the target device. 4760 */ 4761 private static boolean sUseDefaultFocusHighlight; 4762 4763 /** 4764 * True if zero-sized views can be focused. 4765 */ 4766 private static boolean sCanFocusZeroSized; 4767 4768 /** 4769 * Always assign focus if a focusable View is available. 4770 */ 4771 private static boolean sAlwaysAssignFocus; 4772 4773 private String mTransitionName; 4774 4775 static class TintInfo { 4776 ColorStateList mTintList; 4777 BlendMode mBlendMode; 4778 boolean mHasTintMode; 4779 boolean mHasTintList; 4780 } 4781 4782 private static class ForegroundInfo { 4783 private Drawable mDrawable; 4784 private TintInfo mTintInfo; 4785 private int mGravity = Gravity.FILL; 4786 private boolean mInsidePadding = true; 4787 private boolean mBoundsChanged = true; 4788 private final Rect mSelfBounds = new Rect(); 4789 private final Rect mOverlayBounds = new Rect(); 4790 } 4791 4792 static class ListenerInfo { 4793 4794 @UnsupportedAppUsage ListenerInfo()4795 ListenerInfo() { 4796 } 4797 4798 /** 4799 * Listener used to dispatch focus change events. 4800 * This field should be made private, so it is hidden from the SDK. 4801 * {@hide} 4802 */ 4803 @UnsupportedAppUsage 4804 protected OnFocusChangeListener mOnFocusChangeListener; 4805 4806 /** 4807 * Listeners for layout change events. 4808 */ 4809 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 4810 4811 protected OnScrollChangeListener mOnScrollChangeListener; 4812 4813 /** 4814 * Listeners for attach events. 4815 */ 4816 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 4817 4818 /** 4819 * Listener used to dispatch click events. 4820 * This field should be made private, so it is hidden from the SDK. 4821 * {@hide} 4822 */ 4823 @UnsupportedAppUsage 4824 public OnClickListener mOnClickListener; 4825 4826 /** 4827 * Listener used to dispatch long click events. 4828 * This field should be made private, so it is hidden from the SDK. 4829 * {@hide} 4830 */ 4831 @UnsupportedAppUsage 4832 protected OnLongClickListener mOnLongClickListener; 4833 4834 /** 4835 * Listener used to dispatch context click events. This field should be made private, so it 4836 * is hidden from the SDK. 4837 * {@hide} 4838 */ 4839 protected OnContextClickListener mOnContextClickListener; 4840 4841 /** 4842 * Listener used to build the context menu. 4843 * This field should be made private, so it is hidden from the SDK. 4844 * {@hide} 4845 */ 4846 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4847 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 4848 4849 @UnsupportedAppUsage 4850 private OnKeyListener mOnKeyListener; 4851 4852 @UnsupportedAppUsage 4853 private OnTouchListener mOnTouchListener; 4854 4855 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4856 private OnHoverListener mOnHoverListener; 4857 4858 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4859 private OnGenericMotionListener mOnGenericMotionListener; 4860 4861 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 4862 private OnDragListener mOnDragListener; 4863 4864 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 4865 4866 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 4867 4868 OnCapturedPointerListener mOnCapturedPointerListener; 4869 4870 private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners; 4871 4872 WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback; 4873 4874 /** 4875 * This lives here since it's only valid for interactive views. This list is null 4876 * until its first use. 4877 */ 4878 private List<Rect> mSystemGestureExclusionRects = null; 4879 private List<Rect> mKeepClearRects = null; 4880 private List<Rect> mUnrestrictedKeepClearRects = null; 4881 private boolean mPreferKeepClear = false; 4882 private Rect mHandwritingArea = null; 4883 4884 /** 4885 * Used to track {@link #mSystemGestureExclusionRects}, {@link #mKeepClearRects} and 4886 * {@link #mHandwritingArea}. 4887 */ 4888 public RenderNode.PositionUpdateListener mPositionUpdateListener; 4889 private Runnable mPositionChangedUpdate; 4890 4891 /** 4892 * Allows the application to implement custom scroll capture support. 4893 */ 4894 ScrollCaptureCallback mScrollCaptureCallback; 4895 4896 @Nullable 4897 private OnReceiveContentListener mOnReceiveContentListener; 4898 } 4899 4900 @UnsupportedAppUsage 4901 ListenerInfo mListenerInfo; 4902 4903 private static class TooltipInfo { 4904 /** 4905 * Text to be displayed in a tooltip popup. 4906 */ 4907 @Nullable 4908 CharSequence mTooltipText; 4909 4910 /** 4911 * View-relative position of the tooltip anchor point. 4912 */ 4913 int mAnchorX; 4914 int mAnchorY; 4915 4916 /** 4917 * The tooltip popup. 4918 */ 4919 @Nullable 4920 TooltipPopup mTooltipPopup; 4921 4922 /** 4923 * Set to true if the tooltip was shown as a result of a long click. 4924 */ 4925 boolean mTooltipFromLongClick; 4926 4927 /** 4928 * Keep these Runnables so that they can be used to reschedule. 4929 */ 4930 Runnable mShowTooltipRunnable; 4931 Runnable mHideTooltipRunnable; 4932 4933 /** 4934 * Hover move is ignored if it is within this distance in pixels from the previous one. 4935 */ 4936 int mHoverSlop; 4937 4938 /** 4939 * Update the anchor position if it significantly (that is by at least mHoverSlop) 4940 * different from the previously stored position. Ignoring insignificant changes 4941 * filters out the jitter which is typical for such input sources as stylus. 4942 * 4943 * @return True if the position has been updated. 4944 */ updateAnchorPos(MotionEvent event)4945 private boolean updateAnchorPos(MotionEvent event) { 4946 final int newAnchorX = (int) event.getX(); 4947 final int newAnchorY = (int) event.getY(); 4948 if (Math.abs(newAnchorX - mAnchorX) <= mHoverSlop 4949 && Math.abs(newAnchorY - mAnchorY) <= mHoverSlop) { 4950 return false; 4951 } 4952 mAnchorX = newAnchorX; 4953 mAnchorY = newAnchorY; 4954 return true; 4955 } 4956 4957 /** 4958 * Clear the anchor position to ensure that the next change is considered significant. 4959 */ clearAnchorPos()4960 private void clearAnchorPos() { 4961 mAnchorX = Integer.MAX_VALUE; 4962 mAnchorY = Integer.MAX_VALUE; 4963 } 4964 } 4965 4966 TooltipInfo mTooltipInfo; 4967 4968 // Temporary values used to hold (x,y) coordinates when delegating from the 4969 // two-arg performLongClick() method to the legacy no-arg version. 4970 private float mLongClickX = Float.NaN; 4971 private float mLongClickY = Float.NaN; 4972 4973 /** 4974 * The application environment this view lives in. 4975 * This field should be made private, so it is hidden from the SDK. 4976 * {@hide} 4977 */ 4978 @ViewDebug.ExportedProperty(deepExport = true) 4979 @UnsupportedAppUsage 4980 @UiContext 4981 protected Context mContext; 4982 4983 @UnsupportedAppUsage 4984 private final Resources mResources; 4985 4986 @UnsupportedAppUsage 4987 private ScrollabilityCache mScrollCache; 4988 4989 private int[] mDrawableState = null; 4990 4991 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 4992 4993 /** 4994 * Animator that automatically runs based on state changes. 4995 */ 4996 private StateListAnimator mStateListAnimator; 4997 4998 /** 4999 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 5000 * the user may specify which view to go to next. 5001 */ 5002 private int mNextFocusLeftId = View.NO_ID; 5003 5004 /** 5005 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 5006 * the user may specify which view to go to next. 5007 */ 5008 private int mNextFocusRightId = View.NO_ID; 5009 5010 /** 5011 * When this view has focus and the next focus is {@link #FOCUS_UP}, 5012 * the user may specify which view to go to next. 5013 */ 5014 private int mNextFocusUpId = View.NO_ID; 5015 5016 /** 5017 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 5018 * the user may specify which view to go to next. 5019 */ 5020 private int mNextFocusDownId = View.NO_ID; 5021 5022 /** 5023 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 5024 * the user may specify which view to go to next. 5025 */ 5026 int mNextFocusForwardId = View.NO_ID; 5027 5028 /** 5029 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction. 5030 * 5031 * @see #findUserSetNextKeyboardNavigationCluster(View, int) 5032 */ 5033 int mNextClusterForwardId = View.NO_ID; 5034 5035 /** 5036 * Whether this View should use a default focus highlight when it gets focused but doesn't 5037 * have {@link android.R.attr#state_focused} defined in its background. 5038 */ 5039 boolean mDefaultFocusHighlightEnabled = true; 5040 5041 private CheckForLongPress mPendingCheckForLongPress; 5042 @UnsupportedAppUsage 5043 private CheckForTap mPendingCheckForTap = null; 5044 private PerformClick mPerformClick; 5045 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 5046 private SendAccessibilityEventThrottle mSendStateChangedAccessibilityEvent; 5047 private UnsetPressedState mUnsetPressedState; 5048 5049 /** 5050 * Whether the long press's action has been invoked. The tap's action is invoked on the 5051 * up event while a long press is invoked as soon as the long press duration is reached, so 5052 * a long press could be performed before the tap is checked, in which case the tap's action 5053 * should not be invoked. 5054 */ 5055 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 5056 private boolean mHasPerformedLongPress; 5057 5058 /** 5059 * Whether a context click button is currently pressed down. This is true when the stylus is 5060 * touching the screen and the primary button has been pressed, or if a mouse's right button is 5061 * pressed. This is false once the button is released or if the stylus has been lifted. 5062 */ 5063 private boolean mInContextButtonPress; 5064 5065 /** 5066 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 5067 * true after a stylus button press has occured, when the next up event should not be recognized 5068 * as a tap. 5069 */ 5070 private boolean mIgnoreNextUpEvent; 5071 5072 /** 5073 * The minimum height of the view. We'll try our best to have the height 5074 * of this view to at least this amount. 5075 */ 5076 @ViewDebug.ExportedProperty(category = "measurement") 5077 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 5078 private int mMinHeight; 5079 5080 /** 5081 * The minimum width of the view. We'll try our best to have the width 5082 * of this view to at least this amount. 5083 */ 5084 @ViewDebug.ExportedProperty(category = "measurement") 5085 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 5086 private int mMinWidth; 5087 5088 /** 5089 * The delegate to handle touch events that are physically in this view 5090 * but should be handled by another view. 5091 */ 5092 private TouchDelegate mTouchDelegate = null; 5093 5094 /** 5095 * While touch exploration is in use, set to true when hovering across boundaries and 5096 * inside the touch area of the delegate at receiving {@link MotionEvent#ACTION_HOVER_ENTER} 5097 * or {@link MotionEvent#ACTION_HOVER_MOVE}. False when leaving boundaries or receiving a 5098 * {@link MotionEvent#ACTION_HOVER_EXIT}. 5099 * Note that children of view group are excluded in the touch area. 5100 * @see #dispatchTouchExplorationHoverEvent 5101 */ 5102 private boolean mHoveringTouchDelegate = false; 5103 5104 // These two fields are set if the view is a handwriting delegator. 5105 private Runnable mHandwritingDelegatorCallback; 5106 private String mAllowedHandwritingDelegatePackageName; 5107 5108 // These two fields are set if the view is a handwriting delegate. 5109 private boolean mIsHandwritingDelegate; 5110 private String mAllowedHandwritingDelegatorPackageName; 5111 5112 /** 5113 * Solid color to use as a background when creating the drawing cache. Enables 5114 * the cache to use 16 bit bitmaps instead of 32 bit. 5115 */ 5116 private int mDrawingCacheBackgroundColor = 0; 5117 5118 /** 5119 * Special tree observer used when mAttachInfo is null. 5120 */ 5121 private ViewTreeObserver mFloatingTreeObserver; 5122 5123 /** 5124 * Cache the touch slop from the context that created the view. 5125 */ 5126 private int mTouchSlop; 5127 5128 /** 5129 * Cache the ambiguous gesture multiplier from the context that created the view. 5130 */ 5131 private float mAmbiguousGestureMultiplier; 5132 5133 /** 5134 * Object that handles automatic animation of view properties. 5135 */ 5136 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 5137 private ViewPropertyAnimator mAnimator = null; 5138 5139 /** 5140 * List of registered FrameMetricsObservers. 5141 */ 5142 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 5143 5144 /** 5145 * Flag indicating that a drag can cross window boundaries. When 5146 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 5147 * with this flag set, all visible applications with targetSdkVersion >= 5148 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 5149 * in the drag operation and receive the dragged content. 5150 * 5151 * <p>If this is the only flag set, then the drag recipient will only have access to text data 5152 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 5153 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 5154 */ 5155 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 5156 5157 /** 5158 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 5159 * request read access to the content URI(s) contained in the {@link ClipData} object. 5160 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION 5161 */ 5162 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 5163 5164 /** 5165 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 5166 * request write access to the content URI(s) contained in the {@link ClipData} object. 5167 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION 5168 */ 5169 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 5170 5171 /** 5172 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 5173 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 5174 * reboots until explicitly revoked with 5175 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}. 5176 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION 5177 */ 5178 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 5179 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 5180 5181 /** 5182 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 5183 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 5184 * match against the original granted URI. 5185 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION 5186 */ 5187 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 5188 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 5189 5190 /** 5191 * Flag indicating that the drag shadow will be opaque. When 5192 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 5193 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 5194 */ 5195 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 5196 5197 /** 5198 * Flag indicating that the drag was initiated with 5199 * {@link AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_START}. When 5200 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called, this 5201 * is used by the system to perform a drag without animations. 5202 */ 5203 public static final int DRAG_FLAG_ACCESSIBILITY_ACTION = 1 << 10; 5204 5205 /** 5206 * Flag indicating that the caller desires to take ownership of the drag surface for handling 5207 * the animation associated with an unhandled drag. It is mainly useful if the view starting 5208 * a global drag changes visibility during the gesture and the default animation of animating 5209 * the surface back to the origin is not sufficient. 5210 * 5211 * The calling app must hold the {@link android.Manifest.permission#START_TASKS_FROM_RECENTS} 5212 * permission and will receive the drag surface as a part of 5213 * {@link action.view.DragEvent#ACTION_DRAG_ENDED} only if the drag event's 5214 * {@link action.view.DragEvent#getDragResult()} is {@code false}. The caller is responsible 5215 * for removing the surface after its animation. 5216 * 5217 * This flag has no effect if the system decides that a cancel-drag animation does not need to 5218 * occur. 5219 * @hide 5220 */ 5221 public static final int DRAG_FLAG_REQUEST_SURFACE_FOR_RETURN_ANIMATION = 1 << 11; 5222 5223 /** 5224 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 5225 */ 5226 private float mVerticalScrollFactor; 5227 5228 /** 5229 * Position of the vertical scroll bar. 5230 */ 5231 @UnsupportedAppUsage 5232 private int mVerticalScrollbarPosition; 5233 5234 /** 5235 * Position the scroll bar at the default position as determined by the system. 5236 */ 5237 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 5238 5239 /** 5240 * Position the scroll bar along the left edge. 5241 */ 5242 public static final int SCROLLBAR_POSITION_LEFT = 1; 5243 5244 /** 5245 * Position the scroll bar along the right edge. 5246 */ 5247 public static final int SCROLLBAR_POSITION_RIGHT = 2; 5248 5249 /** 5250 * Indicates that the view does not have a layer. 5251 * 5252 * @see #getLayerType() 5253 * @see #setLayerType(int, android.graphics.Paint) 5254 * @see #LAYER_TYPE_SOFTWARE 5255 * @see #LAYER_TYPE_HARDWARE 5256 */ 5257 public static final int LAYER_TYPE_NONE = 0; 5258 5259 /** 5260 * <p>Indicates that the view has a software layer. A software layer is backed 5261 * by a bitmap and causes the view to be rendered using Android's software 5262 * rendering pipeline, even if hardware acceleration is enabled.</p> 5263 * 5264 * <p>Software layers have various usages:</p> 5265 * <p>When the application is not using hardware acceleration, a software layer 5266 * is useful to apply a specific color filter and/or blending mode and/or 5267 * translucency to a view and all its children.</p> 5268 * <p>When the application is using hardware acceleration, a software layer 5269 * is useful to render drawing primitives not supported by the hardware 5270 * accelerated pipeline. It can also be used to cache a complex view tree 5271 * into a texture and reduce the complexity of drawing operations. For instance, 5272 * when animating a complex view tree with a translation, a software layer can 5273 * be used to render the view tree only once.</p> 5274 * <p>Software layers should be avoided when the affected view tree updates 5275 * often. Every update will require to re-render the software layer, which can 5276 * potentially be slow (particularly when hardware acceleration is turned on 5277 * since the layer will have to be uploaded into a hardware texture after every 5278 * update.)</p> 5279 * 5280 * @see #getLayerType() 5281 * @see #setLayerType(int, android.graphics.Paint) 5282 * @see #LAYER_TYPE_NONE 5283 * @see #LAYER_TYPE_HARDWARE 5284 */ 5285 public static final int LAYER_TYPE_SOFTWARE = 1; 5286 5287 /** 5288 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 5289 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 5290 * OpenGL hardware) and causes the view to be rendered using Android's hardware 5291 * rendering pipeline, but only if hardware acceleration is turned on for the 5292 * view hierarchy. When hardware acceleration is turned off, hardware layers 5293 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 5294 * 5295 * <p>A hardware layer is useful to apply a specific color filter and/or 5296 * blending mode and/or translucency to a view and all its children.</p> 5297 * <p>A hardware layer can be used to cache a complex view tree into a 5298 * texture and reduce the complexity of drawing operations. For instance, 5299 * when animating a complex view tree with a translation, a hardware layer can 5300 * be used to render the view tree only once.</p> 5301 * <p>A hardware layer can also be used to increase the rendering quality when 5302 * rotation transformations are applied on a view. It can also be used to 5303 * prevent potential clipping issues when applying 3D transforms on a view.</p> 5304 * 5305 * @see #getLayerType() 5306 * @see #setLayerType(int, android.graphics.Paint) 5307 * @see #LAYER_TYPE_NONE 5308 * @see #LAYER_TYPE_SOFTWARE 5309 */ 5310 public static final int LAYER_TYPE_HARDWARE = 2; 5311 5312 /** @hide */ 5313 @IntDef(prefix = { "LAYER_TYPE_" }, value = { 5314 LAYER_TYPE_NONE, 5315 LAYER_TYPE_SOFTWARE, 5316 LAYER_TYPE_HARDWARE 5317 }) 5318 @Retention(RetentionPolicy.SOURCE) 5319 public @interface LayerType {} 5320 5321 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 5322 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 5323 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 5324 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 5325 }) 5326 int mLayerType = LAYER_TYPE_NONE; 5327 Paint mLayerPaint; 5328 5329 /** 5330 * Set to true when drawing cache is enabled and cannot be created. 5331 * 5332 * @hide 5333 */ 5334 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 5335 public boolean mCachingFailed; 5336 @UnsupportedAppUsage 5337 private Bitmap mDrawingCache; 5338 @UnsupportedAppUsage 5339 private Bitmap mUnscaledDrawingCache; 5340 5341 /** 5342 * RenderNode holding View properties, potentially holding a DisplayList of View content. 5343 * <p> 5344 * When non-null and valid, this is expected to contain an up-to-date copy 5345 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 5346 * cleanup. 5347 */ 5348 @UnsupportedAppUsage 5349 final RenderNode mRenderNode; 5350 5351 /** 5352 * Set to true when the view is sending hover accessibility events because it 5353 * is the innermost hovered view. 5354 */ 5355 private boolean mSendingHoverAccessibilityEvents; 5356 5357 /** 5358 * Delegate for injecting accessibility functionality. 5359 */ 5360 @UnsupportedAppUsage 5361 AccessibilityDelegate mAccessibilityDelegate; 5362 5363 /** 5364 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 5365 * and add/remove objects to/from the overlay directly through the Overlay methods. 5366 */ 5367 ViewOverlay mOverlay; 5368 5369 /** 5370 * The currently active parent view for receiving delegated nested scrolling events. 5371 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 5372 * by {@link #stopNestedScroll()} at the same point where we clear 5373 * requestDisallowInterceptTouchEvent. 5374 */ 5375 private ViewParent mNestedScrollingParent; 5376 5377 /** 5378 * Consistency verifier for debugging purposes. 5379 * @hide 5380 */ 5381 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 5382 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 5383 new InputEventConsistencyVerifier(this, 0) : null; 5384 5385 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 5386 5387 private int[] mTempNestedScrollConsumed; 5388 5389 /** 5390 * An overlay is going to draw this View instead of being drawn as part of this 5391 * View's parent. mGhostView is the View in the Overlay that must be invalidated 5392 * when this view is invalidated. 5393 */ 5394 GhostView mGhostView; 5395 5396 /** 5397 * Holds pairs of adjacent attribute data: attribute name followed by its value. 5398 * @hide 5399 */ 5400 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 5401 public String[] mAttributes; 5402 5403 /** 5404 * Maps a Resource id to its name. 5405 */ 5406 private static SparseArray<String> mAttributeMap; 5407 5408 /** 5409 * Queue of pending runnables. Used to postpone calls to post() until this 5410 * view is attached and has a handler. 5411 */ 5412 private HandlerActionQueue mRunQueue; 5413 5414 /** 5415 * The pointer icon when the mouse hovers on this view. The default is null. 5416 */ 5417 private PointerIcon mMousePointerIcon; 5418 5419 /** 5420 * @hide 5421 */ 5422 @UnsupportedAppUsage 5423 String mStartActivityRequestWho; 5424 5425 @Nullable 5426 private RoundScrollbarRenderer mRoundScrollbarRenderer; 5427 5428 /** Used to delay visibility updates sent to the autofill manager */ 5429 private Handler mVisibilityChangeForAutofillHandler; 5430 5431 /** 5432 * Used when app developers explicitly set the {@link ContentCaptureSession} associated with the 5433 * view (through {@link #setContentCaptureSession(ContentCaptureSession)}. 5434 */ 5435 @Nullable 5436 private ContentCaptureSession mContentCaptureSession; 5437 5438 /** 5439 * Whether {@link ContentCaptureSession} is cached, resets on {@link #invalidate()}. 5440 */ 5441 private boolean mContentCaptureSessionCached; 5442 5443 @LayoutRes 5444 private int mSourceLayoutId = ID_NULL; 5445 5446 @Nullable 5447 private SparseIntArray mAttributeSourceResId; 5448 5449 @Nullable 5450 private SparseArray<int[]> mAttributeResolutionStacks; 5451 5452 @StyleRes 5453 private int mExplicitStyle; 5454 5455 /** 5456 * Specifies which input source classes should provide unbuffered input events to this view 5457 * 5458 * @see View#requestUnbufferedDispatch(int) 5459 */ 5460 @InputSourceClass 5461 int mUnbufferedInputSource = InputDevice.SOURCE_CLASS_NONE; 5462 5463 @Nullable 5464 private String[] mReceiveContentMimeTypes; 5465 5466 @Nullable 5467 private ViewTranslationCallback mViewTranslationCallback; 5468 5469 @Nullable 5470 5471 private ViewTranslationResponse mViewTranslationResponse; 5472 5473 /** 5474 * Simple constructor to use when creating a view from code. 5475 * 5476 * @param context The Context the view is running in, through which it can 5477 * access the current theme, resources, etc. 5478 */ View(Context context)5479 public View(Context context) { 5480 mContext = context; 5481 mResources = context != null ? context.getResources() : null; 5482 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 5483 // Set some flags defaults 5484 mPrivateFlags2 = 5485 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 5486 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 5487 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 5488 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 5489 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 5490 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 5491 5492 final ViewConfiguration configuration = ViewConfiguration.get(context); 5493 mTouchSlop = configuration.getScaledTouchSlop(); 5494 mAmbiguousGestureMultiplier = configuration.getScaledAmbiguousGestureMultiplier(); 5495 5496 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 5497 mUserPaddingStart = UNDEFINED_PADDING; 5498 mUserPaddingEnd = UNDEFINED_PADDING; 5499 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 5500 5501 if (!sCompatibilityDone && context != null) { 5502 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5503 5504 // Older apps may need this compatibility hack for measurement. 5505 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; 5506 5507 // Older apps expect onMeasure() to always be called on a layout pass, regardless 5508 // of whether a layout was requested on that View. 5509 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; 5510 5511 // In M and newer, our widgets can pass a "hint" value in the size 5512 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 5513 // know what the expected parent size is going to be, so e.g. list items can size 5514 // themselves at 1/3 the size of their container. It breaks older apps though, 5515 // specifically apps that use some popular open source libraries. 5516 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M; 5517 5518 // Old versions of the platform would give different results from 5519 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 5520 // modes, so we always need to run an additional EXACTLY pass. 5521 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 5522 5523 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 5524 // On N+, we throw, but that breaks compatibility with apps that use these methods. 5525 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 5526 5527 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 5528 // in apps so we target check it to avoid breaking existing apps. 5529 sPreserveMarginParamsInLayoutParamConversion = 5530 targetSdkVersion >= Build.VERSION_CODES.N; 5531 5532 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 5533 5534 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 5535 5536 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 5537 5538 sUseDefaultFocusHighlight = context.getResources().getBoolean( 5539 com.android.internal.R.bool.config_useDefaultFocusHighlight); 5540 5541 sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P; 5542 5543 sCanFocusZeroSized = targetSdkVersion < Build.VERSION_CODES.P; 5544 5545 sAlwaysAssignFocus = targetSdkVersion < Build.VERSION_CODES.P; 5546 5547 sAcceptZeroSizeDragShadow = targetSdkVersion < Build.VERSION_CODES.P; 5548 5549 sBrokenInsetsDispatch = targetSdkVersion < Build.VERSION_CODES.R; 5550 5551 sBrokenWindowBackground = targetSdkVersion < Build.VERSION_CODES.Q; 5552 5553 GradientDrawable.sWrapNegativeAngleMeasurements = 5554 targetSdkVersion >= Build.VERSION_CODES.Q; 5555 5556 sForceLayoutWhenInsetsChanged = targetSdkVersion < Build.VERSION_CODES.R; 5557 5558 sCompatibilityDone = true; 5559 } 5560 } 5561 5562 /** 5563 * Constructor that is called when inflating a view from XML. This is called 5564 * when a view is being constructed from an XML file, supplying attributes 5565 * that were specified in the XML file. This version uses a default style of 5566 * 0, so the only attribute values applied are those in the Context's Theme 5567 * and the given AttributeSet. 5568 * 5569 * <p> 5570 * The method onFinishInflate() will be called after all children have been 5571 * added. 5572 * 5573 * @param context The Context the view is running in, through which it can 5574 * access the current theme, resources, etc. 5575 * @param attrs The attributes of the XML tag that is inflating the view. 5576 * @see #View(Context, AttributeSet, int) 5577 */ 5578 public View(Context context, @Nullable AttributeSet attrs) { 5579 this(context, attrs, 0); 5580 } 5581 5582 /** 5583 * Perform inflation from XML and apply a class-specific base style from a 5584 * theme attribute. This constructor of View allows subclasses to use their 5585 * own base style when they are inflating. For example, a Button class's 5586 * constructor would call this version of the super class constructor and 5587 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 5588 * allows the theme's button style to modify all of the base view attributes 5589 * (in particular its background) as well as the Button class's attributes. 5590 * 5591 * @param context The Context the view is running in, through which it can 5592 * access the current theme, resources, etc. 5593 * @param attrs The attributes of the XML tag that is inflating the view. 5594 * @param defStyleAttr An attribute in the current theme that contains a 5595 * reference to a style resource that supplies default values for 5596 * the view. Can be 0 to not look for defaults. 5597 * @see #View(Context, AttributeSet) 5598 */ 5599 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 5600 this(context, attrs, defStyleAttr, 0); 5601 } 5602 5603 /** 5604 * Perform inflation from XML and apply a class-specific base style from a 5605 * theme attribute or style resource. This constructor of View allows 5606 * subclasses to use their own base style when they are inflating. 5607 * <p> 5608 * When determining the final value of a particular attribute, there are 5609 * four inputs that come into play: 5610 * <ol> 5611 * <li>Any attribute values in the given AttributeSet. 5612 * <li>The style resource specified in the AttributeSet (named "style"). 5613 * <li>The default style specified by <var>defStyleAttr</var>. 5614 * <li>The default style specified by <var>defStyleRes</var>. 5615 * <li>The base values in this theme. 5616 * </ol> 5617 * <p> 5618 * Each of these inputs is considered in-order, with the first listed taking 5619 * precedence over the following ones. In other words, if in the 5620 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 5621 * , then the button's text will <em>always</em> be black, regardless of 5622 * what is specified in any of the styles. 5623 * 5624 * @param context The Context the view is running in, through which it can 5625 * access the current theme, resources, etc. 5626 * @param attrs The attributes of the XML tag that is inflating the view. 5627 * @param defStyleAttr An attribute in the current theme that contains a 5628 * reference to a style resource that supplies default values for 5629 * the view. Can be 0 to not look for defaults. 5630 * @param defStyleRes A resource identifier of a style resource that 5631 * supplies default values for the view, used only if 5632 * defStyleAttr is 0 or can not be found in the theme. Can be 0 5633 * to not look for defaults. 5634 * @see #View(Context, AttributeSet, int) 5635 */ 5636 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 5637 this(context); 5638 5639 mSourceLayoutId = Resources.getAttributeSetSourceResId(attrs); 5640 5641 final TypedArray a = context.obtainStyledAttributes( 5642 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 5643 5644 retrieveExplicitStyle(context.getTheme(), attrs); 5645 saveAttributeDataForStyleable(context, com.android.internal.R.styleable.View, attrs, a, 5646 defStyleAttr, defStyleRes); 5647 5648 if (sDebugViewAttributes) { 5649 saveAttributeData(attrs, a); 5650 } 5651 5652 Drawable background = null; 5653 5654 int leftPadding = -1; 5655 int topPadding = -1; 5656 int rightPadding = -1; 5657 int bottomPadding = -1; 5658 int startPadding = UNDEFINED_PADDING; 5659 int endPadding = UNDEFINED_PADDING; 5660 5661 int padding = -1; 5662 int paddingHorizontal = -1; 5663 int paddingVertical = -1; 5664 5665 int viewFlagValues = 0; 5666 int viewFlagMasks = 0; 5667 5668 boolean setScrollContainer = false; 5669 5670 int x = 0; 5671 int y = 0; 5672 5673 float tx = 0; 5674 float ty = 0; 5675 float tz = 0; 5676 float elevation = 0; 5677 float rotation = 0; 5678 float rotationX = 0; 5679 float rotationY = 0; 5680 float sx = 1f; 5681 float sy = 1f; 5682 boolean transformSet = false; 5683 5684 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 5685 int overScrollMode = mOverScrollMode; 5686 boolean initializeScrollbars = false; 5687 boolean initializeScrollIndicators = false; 5688 5689 boolean startPaddingDefined = false; 5690 boolean endPaddingDefined = false; 5691 boolean leftPaddingDefined = false; 5692 boolean rightPaddingDefined = false; 5693 5694 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5695 5696 // Set default values. 5697 viewFlagValues |= FOCUSABLE_AUTO; 5698 viewFlagMasks |= FOCUSABLE_AUTO; 5699 5700 final int N = a.getIndexCount(); 5701 for (int i = 0; i < N; i++) { 5702 int attr = a.getIndex(i); 5703 switch (attr) { 5704 case com.android.internal.R.styleable.View_background: 5705 background = a.getDrawable(attr); 5706 break; 5707 case com.android.internal.R.styleable.View_padding: 5708 padding = a.getDimensionPixelSize(attr, -1); 5709 mUserPaddingLeftInitial = padding; 5710 mUserPaddingRightInitial = padding; 5711 leftPaddingDefined = true; 5712 rightPaddingDefined = true; 5713 break; 5714 case com.android.internal.R.styleable.View_paddingHorizontal: 5715 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 5716 mUserPaddingLeftInitial = paddingHorizontal; 5717 mUserPaddingRightInitial = paddingHorizontal; 5718 leftPaddingDefined = true; 5719 rightPaddingDefined = true; 5720 break; 5721 case com.android.internal.R.styleable.View_paddingVertical: 5722 paddingVertical = a.getDimensionPixelSize(attr, -1); 5723 break; 5724 case com.android.internal.R.styleable.View_paddingLeft: 5725 leftPadding = a.getDimensionPixelSize(attr, -1); 5726 mUserPaddingLeftInitial = leftPadding; 5727 leftPaddingDefined = true; 5728 break; 5729 case com.android.internal.R.styleable.View_paddingTop: 5730 topPadding = a.getDimensionPixelSize(attr, -1); 5731 break; 5732 case com.android.internal.R.styleable.View_paddingRight: 5733 rightPadding = a.getDimensionPixelSize(attr, -1); 5734 mUserPaddingRightInitial = rightPadding; 5735 rightPaddingDefined = true; 5736 break; 5737 case com.android.internal.R.styleable.View_paddingBottom: 5738 bottomPadding = a.getDimensionPixelSize(attr, -1); 5739 break; 5740 case com.android.internal.R.styleable.View_paddingStart: 5741 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5742 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 5743 break; 5744 case com.android.internal.R.styleable.View_paddingEnd: 5745 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5746 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 5747 break; 5748 case com.android.internal.R.styleable.View_scrollX: 5749 x = a.getDimensionPixelOffset(attr, 0); 5750 break; 5751 case com.android.internal.R.styleable.View_scrollY: 5752 y = a.getDimensionPixelOffset(attr, 0); 5753 break; 5754 case com.android.internal.R.styleable.View_alpha: 5755 setAlpha(a.getFloat(attr, 1f)); 5756 break; 5757 case com.android.internal.R.styleable.View_transformPivotX: 5758 setPivotX(a.getDimension(attr, 0)); 5759 break; 5760 case com.android.internal.R.styleable.View_transformPivotY: 5761 setPivotY(a.getDimension(attr, 0)); 5762 break; 5763 case com.android.internal.R.styleable.View_translationX: 5764 tx = a.getDimension(attr, 0); 5765 transformSet = true; 5766 break; 5767 case com.android.internal.R.styleable.View_translationY: 5768 ty = a.getDimension(attr, 0); 5769 transformSet = true; 5770 break; 5771 case com.android.internal.R.styleable.View_translationZ: 5772 tz = a.getDimension(attr, 0); 5773 transformSet = true; 5774 break; 5775 case com.android.internal.R.styleable.View_elevation: 5776 elevation = a.getDimension(attr, 0); 5777 transformSet = true; 5778 break; 5779 case com.android.internal.R.styleable.View_rotation: 5780 rotation = a.getFloat(attr, 0); 5781 transformSet = true; 5782 break; 5783 case com.android.internal.R.styleable.View_rotationX: 5784 rotationX = a.getFloat(attr, 0); 5785 transformSet = true; 5786 break; 5787 case com.android.internal.R.styleable.View_rotationY: 5788 rotationY = a.getFloat(attr, 0); 5789 transformSet = true; 5790 break; 5791 case com.android.internal.R.styleable.View_scaleX: 5792 sx = a.getFloat(attr, 1f); 5793 transformSet = true; 5794 break; 5795 case com.android.internal.R.styleable.View_scaleY: 5796 sy = a.getFloat(attr, 1f); 5797 transformSet = true; 5798 break; 5799 case com.android.internal.R.styleable.View_id: 5800 mID = a.getResourceId(attr, NO_ID); 5801 break; 5802 case com.android.internal.R.styleable.View_tag: 5803 mTag = a.getText(attr); 5804 break; 5805 case com.android.internal.R.styleable.View_fitsSystemWindows: 5806 if (a.getBoolean(attr, false)) { 5807 viewFlagValues |= FITS_SYSTEM_WINDOWS; 5808 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 5809 } 5810 break; 5811 case com.android.internal.R.styleable.View_focusable: 5812 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 5813 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 5814 viewFlagMasks |= FOCUSABLE_MASK; 5815 } 5816 break; 5817 case com.android.internal.R.styleable.View_focusableInTouchMode: 5818 if (a.getBoolean(attr, false)) { 5819 // unset auto focus since focusableInTouchMode implies explicit focusable 5820 viewFlagValues &= ~FOCUSABLE_AUTO; 5821 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 5822 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 5823 } 5824 break; 5825 case com.android.internal.R.styleable.View_clickable: 5826 if (a.getBoolean(attr, false)) { 5827 viewFlagValues |= CLICKABLE; 5828 viewFlagMasks |= CLICKABLE; 5829 } 5830 break; 5831 case com.android.internal.R.styleable.View_allowClickWhenDisabled: 5832 setAllowClickWhenDisabled(a.getBoolean(attr, false)); 5833 break; 5834 case com.android.internal.R.styleable.View_longClickable: 5835 if (a.getBoolean(attr, false)) { 5836 viewFlagValues |= LONG_CLICKABLE; 5837 viewFlagMasks |= LONG_CLICKABLE; 5838 } 5839 break; 5840 case com.android.internal.R.styleable.View_contextClickable: 5841 if (a.getBoolean(attr, false)) { 5842 viewFlagValues |= CONTEXT_CLICKABLE; 5843 viewFlagMasks |= CONTEXT_CLICKABLE; 5844 } 5845 break; 5846 case com.android.internal.R.styleable.View_saveEnabled: 5847 if (!a.getBoolean(attr, true)) { 5848 viewFlagValues |= SAVE_DISABLED; 5849 viewFlagMasks |= SAVE_DISABLED_MASK; 5850 } 5851 break; 5852 case com.android.internal.R.styleable.View_duplicateParentState: 5853 if (a.getBoolean(attr, false)) { 5854 viewFlagValues |= DUPLICATE_PARENT_STATE; 5855 viewFlagMasks |= DUPLICATE_PARENT_STATE; 5856 } 5857 break; 5858 case com.android.internal.R.styleable.View_visibility: 5859 final int visibility = a.getInt(attr, 0); 5860 if (visibility != 0) { 5861 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 5862 viewFlagMasks |= VISIBILITY_MASK; 5863 } 5864 break; 5865 case com.android.internal.R.styleable.View_layoutDirection: 5866 // Clear any layout direction flags (included resolved bits) already set 5867 mPrivateFlags2 &= 5868 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 5869 // Set the layout direction flags depending on the value of the attribute 5870 final int layoutDirection = a.getInt(attr, -1); 5871 final int value = (layoutDirection != -1) ? 5872 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 5873 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 5874 break; 5875 case com.android.internal.R.styleable.View_drawingCacheQuality: 5876 final int cacheQuality = a.getInt(attr, 0); 5877 if (cacheQuality != 0) { 5878 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 5879 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 5880 } 5881 break; 5882 case com.android.internal.R.styleable.View_contentDescription: 5883 setContentDescription(a.getString(attr)); 5884 break; 5885 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 5886 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 5887 break; 5888 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 5889 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 5890 break; 5891 case com.android.internal.R.styleable.View_labelFor: 5892 setLabelFor(a.getResourceId(attr, NO_ID)); 5893 break; 5894 case com.android.internal.R.styleable.View_soundEffectsEnabled: 5895 if (!a.getBoolean(attr, true)) { 5896 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 5897 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 5898 } 5899 break; 5900 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 5901 if (!a.getBoolean(attr, true)) { 5902 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 5903 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 5904 } 5905 break; 5906 case R.styleable.View_scrollbars: 5907 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 5908 if (scrollbars != SCROLLBARS_NONE) { 5909 viewFlagValues |= scrollbars; 5910 viewFlagMasks |= SCROLLBARS_MASK; 5911 initializeScrollbars = true; 5912 } 5913 break; 5914 //noinspection deprecation 5915 case R.styleable.View_fadingEdge: 5916 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 5917 // Ignore the attribute starting with ICS 5918 break; 5919 } 5920 // With builds < ICS, fall through and apply fading edges 5921 case R.styleable.View_requiresFadingEdge: 5922 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 5923 if (fadingEdge != FADING_EDGE_NONE) { 5924 viewFlagValues |= fadingEdge; 5925 viewFlagMasks |= FADING_EDGE_MASK; 5926 initializeFadingEdgeInternal(a); 5927 } 5928 break; 5929 case R.styleable.View_scrollbarStyle: 5930 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 5931 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5932 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 5933 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 5934 } 5935 break; 5936 case R.styleable.View_isScrollContainer: 5937 setScrollContainer = true; 5938 if (a.getBoolean(attr, false)) { 5939 setScrollContainer(true); 5940 } 5941 break; 5942 case com.android.internal.R.styleable.View_keepScreenOn: 5943 if (a.getBoolean(attr, false)) { 5944 viewFlagValues |= KEEP_SCREEN_ON; 5945 viewFlagMasks |= KEEP_SCREEN_ON; 5946 } 5947 break; 5948 case R.styleable.View_filterTouchesWhenObscured: 5949 if (a.getBoolean(attr, false)) { 5950 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 5951 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 5952 } 5953 break; 5954 case R.styleable.View_nextFocusLeft: 5955 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 5956 break; 5957 case R.styleable.View_nextFocusRight: 5958 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 5959 break; 5960 case R.styleable.View_nextFocusUp: 5961 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 5962 break; 5963 case R.styleable.View_nextFocusDown: 5964 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 5965 break; 5966 case R.styleable.View_nextFocusForward: 5967 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 5968 break; 5969 case R.styleable.View_nextClusterForward: 5970 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 5971 break; 5972 case R.styleable.View_minWidth: 5973 mMinWidth = a.getDimensionPixelSize(attr, 0); 5974 break; 5975 case R.styleable.View_minHeight: 5976 mMinHeight = a.getDimensionPixelSize(attr, 0); 5977 break; 5978 case R.styleable.View_onClick: 5979 if (context.isRestricted()) { 5980 throw new IllegalStateException("The android:onClick attribute cannot " 5981 + "be used within a restricted context"); 5982 } 5983 5984 final String handlerName = a.getString(attr); 5985 if (handlerName != null) { 5986 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 5987 } 5988 break; 5989 case R.styleable.View_overScrollMode: 5990 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 5991 break; 5992 case R.styleable.View_verticalScrollbarPosition: 5993 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 5994 break; 5995 case R.styleable.View_layerType: 5996 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 5997 break; 5998 case R.styleable.View_textDirection: 5999 // Clear any text direction flag already set 6000 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 6001 // Set the text direction flags depending on the value of the attribute 6002 final int textDirection = a.getInt(attr, -1); 6003 if (textDirection != -1) { 6004 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 6005 } 6006 break; 6007 case R.styleable.View_textAlignment: 6008 // Clear any text alignment flag already set 6009 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 6010 // Set the text alignment flag depending on the value of the attribute 6011 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 6012 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 6013 break; 6014 case R.styleable.View_importantForAccessibility: 6015 setImportantForAccessibility(a.getInt(attr, 6016 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 6017 break; 6018 case R.styleable.View_accessibilityDataSensitive: 6019 setAccessibilityDataSensitive(a.getInt(attr, 6020 ACCESSIBILITY_DATA_SENSITIVE_AUTO)); 6021 break; 6022 case R.styleable.View_accessibilityLiveRegion: 6023 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 6024 break; 6025 case R.styleable.View_transitionName: 6026 setTransitionName(a.getString(attr)); 6027 break; 6028 case R.styleable.View_nestedScrollingEnabled: 6029 setNestedScrollingEnabled(a.getBoolean(attr, false)); 6030 break; 6031 case R.styleable.View_stateListAnimator: 6032 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 6033 a.getResourceId(attr, 0))); 6034 break; 6035 case R.styleable.View_backgroundTint: 6036 // This will get applied later during setBackground(). 6037 if (mBackgroundTint == null) { 6038 mBackgroundTint = new TintInfo(); 6039 } 6040 mBackgroundTint.mTintList = a.getColorStateList( 6041 R.styleable.View_backgroundTint); 6042 mBackgroundTint.mHasTintList = true; 6043 break; 6044 case R.styleable.View_backgroundTintMode: 6045 // This will get applied later during setBackground(). 6046 if (mBackgroundTint == null) { 6047 mBackgroundTint = new TintInfo(); 6048 } 6049 mBackgroundTint.mBlendMode = Drawable.parseBlendMode(a.getInt( 6050 R.styleable.View_backgroundTintMode, -1), null); 6051 mBackgroundTint.mHasTintMode = true; 6052 break; 6053 case R.styleable.View_outlineProvider: 6054 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 6055 PROVIDER_BACKGROUND)); 6056 break; 6057 case R.styleable.View_foreground: 6058 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 6059 setForeground(a.getDrawable(attr)); 6060 } 6061 break; 6062 case R.styleable.View_foregroundGravity: 6063 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 6064 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 6065 } 6066 break; 6067 case R.styleable.View_foregroundTintMode: 6068 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 6069 setForegroundTintBlendMode( 6070 Drawable.parseBlendMode(a.getInt(attr, -1), 6071 null)); 6072 } 6073 break; 6074 case R.styleable.View_foregroundTint: 6075 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 6076 setForegroundTintList(a.getColorStateList(attr)); 6077 } 6078 break; 6079 case R.styleable.View_foregroundInsidePadding: 6080 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 6081 if (mForegroundInfo == null) { 6082 mForegroundInfo = new ForegroundInfo(); 6083 } 6084 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 6085 mForegroundInfo.mInsidePadding); 6086 } 6087 break; 6088 case R.styleable.View_scrollIndicators: 6089 final int scrollIndicators = 6090 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 6091 & SCROLL_INDICATORS_PFLAG3_MASK; 6092 if (scrollIndicators != 0) { 6093 mPrivateFlags3 |= scrollIndicators; 6094 initializeScrollIndicators = true; 6095 } 6096 break; 6097 case R.styleable.View_pointerIcon: 6098 final int resourceId = a.getResourceId(attr, 0); 6099 if (resourceId != 0) { 6100 setPointerIcon(PointerIcon.load( 6101 context.getResources(), resourceId)); 6102 } else { 6103 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 6104 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 6105 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 6106 } 6107 } 6108 break; 6109 case R.styleable.View_forceHasOverlappingRendering: 6110 if (a.peekValue(attr) != null) { 6111 forceHasOverlappingRendering(a.getBoolean(attr, true)); 6112 } 6113 break; 6114 case R.styleable.View_tooltipText: 6115 setTooltipText(a.getText(attr)); 6116 break; 6117 case R.styleable.View_keyboardNavigationCluster: 6118 if (a.peekValue(attr) != null) { 6119 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 6120 } 6121 break; 6122 case R.styleable.View_focusedByDefault: 6123 if (a.peekValue(attr) != null) { 6124 setFocusedByDefault(a.getBoolean(attr, true)); 6125 } 6126 break; 6127 case R.styleable.View_autofillHints: 6128 if (a.peekValue(attr) != null) { 6129 CharSequence[] rawHints = null; 6130 String rawString = null; 6131 6132 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 6133 int resId = a.getResourceId(attr, 0); 6134 6135 try { 6136 rawHints = a.getTextArray(attr); 6137 } catch (Resources.NotFoundException e) { 6138 rawString = getResources().getString(resId); 6139 } 6140 } else { 6141 rawString = a.getString(attr); 6142 } 6143 6144 if (rawHints == null) { 6145 if (rawString == null) { 6146 throw new IllegalArgumentException( 6147 "Could not resolve autofillHints"); 6148 } else { 6149 rawHints = rawString.split(","); 6150 } 6151 } 6152 6153 String[] hints = new String[rawHints.length]; 6154 6155 int numHints = rawHints.length; 6156 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 6157 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 6158 } 6159 setAutofillHints(hints); 6160 } 6161 break; 6162 case R.styleable.View_importantForAutofill: 6163 if (a.peekValue(attr) != null) { 6164 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 6165 } 6166 break; 6167 case R.styleable.View_importantForContentCapture: 6168 if (a.peekValue(attr) != null) { 6169 setImportantForContentCapture(a.getInt(attr, 6170 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO)); 6171 } 6172 break; 6173 case R.styleable.View_isCredential: 6174 if (a.peekValue(attr) != null) { 6175 setIsCredential(a.getBoolean(attr, false)); 6176 } 6177 break; 6178 case R.styleable.View_defaultFocusHighlightEnabled: 6179 if (a.peekValue(attr) != null) { 6180 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); 6181 } 6182 break; 6183 case R.styleable.View_screenReaderFocusable: 6184 if (a.peekValue(attr) != null) { 6185 setScreenReaderFocusable(a.getBoolean(attr, false)); 6186 } 6187 break; 6188 case R.styleable.View_accessibilityPaneTitle: 6189 if (a.peekValue(attr) != null) { 6190 setAccessibilityPaneTitle(a.getString(attr)); 6191 } 6192 break; 6193 case R.styleable.View_outlineSpotShadowColor: 6194 setOutlineSpotShadowColor(a.getColor(attr, Color.BLACK)); 6195 break; 6196 case R.styleable.View_outlineAmbientShadowColor: 6197 setOutlineAmbientShadowColor(a.getColor(attr, Color.BLACK)); 6198 break; 6199 case com.android.internal.R.styleable.View_accessibilityHeading: 6200 setAccessibilityHeading(a.getBoolean(attr, false)); 6201 break; 6202 case R.styleable.View_forceDarkAllowed: 6203 mRenderNode.setForceDarkAllowed(a.getBoolean(attr, true)); 6204 break; 6205 case R.styleable.View_scrollCaptureHint: 6206 setScrollCaptureHint((a.getInt(attr, SCROLL_CAPTURE_HINT_AUTO))); 6207 break; 6208 case R.styleable.View_clipToOutline: 6209 setClipToOutline(a.getBoolean(attr, false)); 6210 break; 6211 case R.styleable.View_preferKeepClear: 6212 setPreferKeepClear(a.getBoolean(attr, false)); 6213 break; 6214 case R.styleable.View_autoHandwritingEnabled: 6215 setAutoHandwritingEnabled(a.getBoolean(attr, false)); 6216 break; 6217 case R.styleable.View_handwritingBoundsOffsetLeft: 6218 mHandwritingBoundsOffsetLeft = a.getDimension(attr, 0); 6219 break; 6220 case R.styleable.View_handwritingBoundsOffsetTop: 6221 mHandwritingBoundsOffsetTop = a.getDimension(attr, 0); 6222 break; 6223 case R.styleable.View_handwritingBoundsOffsetRight: 6224 mHandwritingBoundsOffsetRight = a.getDimension(attr, 0); 6225 break; 6226 case R.styleable.View_handwritingBoundsOffsetBottom: 6227 mHandwritingBoundsOffsetBottom = a.getDimension(attr, 0); 6228 break; 6229 } 6230 } 6231 6232 setOverScrollMode(overScrollMode); 6233 6234 // Cache start/end user padding as we cannot fully resolve padding here (we don't have yet 6235 // the resolved layout direction). Those cached values will be used later during padding 6236 // resolution. 6237 mUserPaddingStart = startPadding; 6238 mUserPaddingEnd = endPadding; 6239 6240 if (background != null) { 6241 setBackground(background); 6242 } 6243 6244 // setBackground above will record that padding is currently provided by the background. 6245 // If we have padding specified via xml, record that here instead and use it. 6246 mLeftPaddingDefined = leftPaddingDefined; 6247 mRightPaddingDefined = rightPaddingDefined; 6248 6249 // Valid paddingHorizontal/paddingVertical beats leftPadding, rightPadding, topPadding, 6250 // bottomPadding, and padding set by background. Valid padding beats everything. 6251 if (padding >= 0) { 6252 leftPadding = padding; 6253 topPadding = padding; 6254 rightPadding = padding; 6255 bottomPadding = padding; 6256 mUserPaddingLeftInitial = padding; 6257 mUserPaddingRightInitial = padding; 6258 } else { 6259 if (paddingHorizontal >= 0) { 6260 leftPadding = paddingHorizontal; 6261 rightPadding = paddingHorizontal; 6262 mUserPaddingLeftInitial = paddingHorizontal; 6263 mUserPaddingRightInitial = paddingHorizontal; 6264 } 6265 if (paddingVertical >= 0) { 6266 topPadding = paddingVertical; 6267 bottomPadding = paddingVertical; 6268 } 6269 } 6270 6271 if (isRtlCompatibilityMode()) { 6272 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 6273 // left / right padding are used if defined (meaning here nothing to do). If they are not 6274 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 6275 // start / end and resolve them as left / right (layout direction is not taken into account). 6276 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 6277 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 6278 // defined. 6279 if (!mLeftPaddingDefined && startPaddingDefined) { 6280 leftPadding = startPadding; 6281 } 6282 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 6283 if (!mRightPaddingDefined && endPaddingDefined) { 6284 rightPadding = endPadding; 6285 } 6286 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 6287 } else { 6288 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 6289 // values defined. Otherwise, left /right values are used. 6290 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 6291 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 6292 // defined. 6293 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 6294 6295 if (mLeftPaddingDefined && !hasRelativePadding) { 6296 mUserPaddingLeftInitial = leftPadding; 6297 } 6298 if (mRightPaddingDefined && !hasRelativePadding) { 6299 mUserPaddingRightInitial = rightPadding; 6300 } 6301 } 6302 6303 // mPaddingTop and mPaddingBottom may have been set by setBackground(Drawable) so must pass 6304 // them on if topPadding or bottomPadding are not valid. 6305 internalSetPadding( 6306 mUserPaddingLeftInitial, 6307 topPadding >= 0 ? topPadding : mPaddingTop, 6308 mUserPaddingRightInitial, 6309 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 6310 6311 if (viewFlagMasks != 0) { 6312 setFlags(viewFlagValues, viewFlagMasks); 6313 } 6314 6315 if (initializeScrollbars) { 6316 initializeScrollbarsInternal(a); 6317 } 6318 6319 if (initializeScrollIndicators) { 6320 initializeScrollIndicatorsInternal(); 6321 } 6322 6323 a.recycle(); 6324 6325 // Needs to be called after mViewFlags is set 6326 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 6327 recomputePadding(); 6328 } 6329 6330 if (x != 0 || y != 0) { 6331 scrollTo(x, y); 6332 } 6333 6334 if (transformSet) { 6335 setTranslationX(tx); 6336 setTranslationY(ty); 6337 setTranslationZ(tz); 6338 setElevation(elevation); 6339 setRotation(rotation); 6340 setRotationX(rotationX); 6341 setRotationY(rotationY); 6342 setScaleX(sx); 6343 setScaleY(sy); 6344 } 6345 6346 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 6347 setScrollContainer(true); 6348 } 6349 6350 computeOpaqueFlags(); 6351 } 6352 6353 /** 6354 * Returns the ordered list of resource ID that are considered when resolving attribute values 6355 * for this {@link View}. The list will include layout resource ID if the View is inflated from 6356 * XML. It will also include a set of explicit styles if specified in XML using 6357 * {@code style="..."}. Finally, it will include the default styles resolved from the theme. 6358 * 6359 * <p> 6360 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6361 * is enabled in Android developer options. 6362 * 6363 * @param attribute Attribute resource ID for which the resolution stack should be returned. 6364 * @return ordered list of resource ID that are considered when resolving attribute values for 6365 * this {@link View}. 6366 */ 6367 @NonNull 6368 public int[] getAttributeResolutionStack(@AttrRes int attribute) { 6369 if (!sDebugViewAttributes 6370 || mAttributeResolutionStacks == null 6371 || mAttributeResolutionStacks.get(attribute) == null) { 6372 return new int[0]; 6373 } 6374 int[] attributeResolutionStack = mAttributeResolutionStacks.get(attribute); 6375 int stackSize = attributeResolutionStack.length; 6376 if (mSourceLayoutId != ID_NULL) { 6377 stackSize++; 6378 } 6379 6380 int currentIndex = 0; 6381 int[] stack = new int[stackSize]; 6382 6383 if (mSourceLayoutId != ID_NULL) { 6384 stack[currentIndex] = mSourceLayoutId; 6385 currentIndex++; 6386 } 6387 for (int i = 0; i < attributeResolutionStack.length; i++) { 6388 stack[currentIndex] = attributeResolutionStack[i]; 6389 currentIndex++; 6390 } 6391 return stack; 6392 } 6393 6394 /** 6395 * Returns the mapping of attribute resource ID to source resource ID where the attribute value 6396 * was set. Source resource ID can either be a layout resource ID, if the value was set in XML 6397 * within the View tag, or a style resource ID, if the attribute was set in a style. The source 6398 * resource value will be one of the resource IDs from {@link #getAttributeSourceResourceMap()}. 6399 * 6400 * <p> 6401 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6402 * is enabled in Android developer options. 6403 * 6404 * @return mapping of attribute resource ID to source resource ID where the attribute value 6405 * was set. 6406 */ 6407 @NonNull 6408 @SuppressWarnings("AndroidFrameworkEfficientCollections") 6409 public Map<Integer, Integer> getAttributeSourceResourceMap() { 6410 HashMap<Integer, Integer> map = new HashMap<>(); 6411 if (!sDebugViewAttributes || mAttributeSourceResId == null) { 6412 return map; 6413 } 6414 for (int i = 0; i < mAttributeSourceResId.size(); i++) { 6415 map.put(mAttributeSourceResId.keyAt(i), mAttributeSourceResId.valueAt(i)); 6416 } 6417 return map; 6418 } 6419 6420 /** 6421 * Returns the resource ID for the style specified using {@code style="..."} in the 6422 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise if not 6423 * specified or otherwise not applicable. 6424 * <p> 6425 * Each {@link View} can have an explicit style specified in the layout file. 6426 * This style is used first during the {@link View} attribute resolution, then if an attribute 6427 * is not defined there the resource system looks at default style and theme as fallbacks. 6428 * 6429 * <p> 6430 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6431 * is enabled in Android developer options. 6432 * 6433 * @return The resource ID for the style specified using {@code style="..."} in the 6434 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise 6435 * if not specified or otherwise not applicable. 6436 */ 6437 @StyleRes 6438 public int getExplicitStyle() { 6439 if (!sDebugViewAttributes) { 6440 return ID_NULL; 6441 } 6442 return mExplicitStyle; 6443 } 6444 6445 /** 6446 * An implementation of OnClickListener that attempts to lazily load a 6447 * named click handling method from a parent or ancestor context. 6448 */ 6449 private static class DeclaredOnClickListener implements OnClickListener { 6450 private final View mHostView; 6451 private final String mMethodName; 6452 6453 private Method mResolvedMethod; 6454 private Context mResolvedContext; 6455 6456 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 6457 mHostView = hostView; 6458 mMethodName = methodName; 6459 } 6460 6461 @Override 6462 public void onClick(@NonNull View v) { 6463 if (mResolvedMethod == null) { 6464 resolveMethod(mHostView.getContext(), mMethodName); 6465 } 6466 6467 try { 6468 mResolvedMethod.invoke(mResolvedContext, v); 6469 } catch (IllegalAccessException e) { 6470 throw new IllegalStateException( 6471 "Could not execute non-public method for android:onClick", e); 6472 } catch (InvocationTargetException e) { 6473 throw new IllegalStateException( 6474 "Could not execute method for android:onClick", e); 6475 } 6476 } 6477 6478 @NonNull 6479 private void resolveMethod(@Nullable Context context, @NonNull String name) { 6480 while (context != null) { 6481 try { 6482 if (!context.isRestricted()) { 6483 final Method method = context.getClass().getMethod(mMethodName, View.class); 6484 if (method != null) { 6485 mResolvedMethod = method; 6486 mResolvedContext = context; 6487 return; 6488 } 6489 } 6490 } catch (NoSuchMethodException e) { 6491 // Failed to find method, keep searching up the hierarchy. 6492 } 6493 6494 if (context instanceof ContextWrapper) { 6495 context = ((ContextWrapper) context).getBaseContext(); 6496 } else { 6497 // Can't search up the hierarchy, null out and fail. 6498 context = null; 6499 } 6500 } 6501 6502 final int id = mHostView.getId(); 6503 final String idText = id == NO_ID ? "" : " with id '" 6504 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 6505 throw new IllegalStateException("Could not find method " + mMethodName 6506 + "(View) in a parent or ancestor Context for android:onClick " 6507 + "attribute defined on view " + mHostView.getClass() + idText); 6508 } 6509 } 6510 6511 /** 6512 * Non-public constructor for use in testing 6513 */ 6514 @UnsupportedAppUsage 6515 View() { 6516 mResources = null; 6517 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 6518 } 6519 6520 /** 6521 * Returns {@code true} when the View is attached and the system developer setting to show 6522 * the layout bounds is enabled or {@code false} otherwise. 6523 */ 6524 public final boolean isShowingLayoutBounds() { 6525 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 6526 } 6527 6528 /** 6529 * Used to test isShowingLayoutBounds(). This sets the local value used 6530 * by that function. This method does nothing if the layout isn't attached. 6531 * 6532 * @hide 6533 */ 6534 @TestApi 6535 public final void setShowingLayoutBounds(boolean debugLayout) { 6536 if (mAttachInfo != null) { 6537 mAttachInfo.mDebugLayout = debugLayout; 6538 } 6539 } 6540 6541 private static SparseArray<String> getAttributeMap() { 6542 if (mAttributeMap == null) { 6543 mAttributeMap = new SparseArray<>(); 6544 } 6545 return mAttributeMap; 6546 } 6547 6548 private void retrieveExplicitStyle(@NonNull Resources.Theme theme, 6549 @Nullable AttributeSet attrs) { 6550 if (!sDebugViewAttributes) { 6551 return; 6552 } 6553 mExplicitStyle = theme.getExplicitStyle(attrs); 6554 } 6555 6556 /** 6557 * Stores debugging information about attributes. This should be called in a constructor by 6558 * every custom {@link View} that uses a custom styleable. If the custom view does not call it, 6559 * then the custom attributes used by this view will not be visible in layout inspection tools. 6560 * 6561 * @param context Context under which this view is created. 6562 * @param styleable A reference to styleable array R.styleable.Foo 6563 * @param attrs AttributeSet used to construct this view. 6564 * @param t Resolved {@link TypedArray} returned by a call to 6565 * {@link Resources#obtainAttributes(AttributeSet, int[])}. 6566 * @param defStyleAttr Default style attribute passed into the view constructor. 6567 * @param defStyleRes Default style resource passed into the view constructor. 6568 */ 6569 public final void saveAttributeDataForStyleable(@NonNull Context context, 6570 @NonNull int[] styleable, @Nullable AttributeSet attrs, @NonNull TypedArray t, 6571 int defStyleAttr, int defStyleRes) { 6572 if (!sDebugViewAttributes) { 6573 return; 6574 } 6575 6576 int[] attributeResolutionStack = context.getTheme().getAttributeResolutionStack( 6577 defStyleAttr, defStyleRes, mExplicitStyle); 6578 6579 if (mAttributeResolutionStacks == null) { 6580 mAttributeResolutionStacks = new SparseArray<>(); 6581 } 6582 6583 if (mAttributeSourceResId == null) { 6584 mAttributeSourceResId = new SparseIntArray(); 6585 } 6586 6587 final int indexCount = t.getIndexCount(); 6588 for (int j = 0; j < indexCount; ++j) { 6589 final int index = t.getIndex(j); 6590 mAttributeSourceResId.append(styleable[index], t.getSourceResourceId(index, 0)); 6591 mAttributeResolutionStacks.append(styleable[index], attributeResolutionStack); 6592 } 6593 } 6594 6595 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 6596 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 6597 final int indexCount = t.getIndexCount(); 6598 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 6599 6600 int i = 0; 6601 6602 // Store raw XML attributes. 6603 for (int j = 0; j < attrsCount; ++j) { 6604 attributes[i] = attrs.getAttributeName(j); 6605 attributes[i + 1] = attrs.getAttributeValue(j); 6606 i += 2; 6607 } 6608 6609 // Store resolved styleable attributes. 6610 final Resources res = t.getResources(); 6611 final SparseArray<String> attributeMap = getAttributeMap(); 6612 for (int j = 0; j < indexCount; ++j) { 6613 final int index = t.getIndex(j); 6614 if (!t.hasValueOrEmpty(index)) { 6615 // Value is undefined. Skip it. 6616 continue; 6617 } 6618 6619 final int resourceId = t.getResourceId(index, 0); 6620 if (resourceId == 0) { 6621 // Value is not a reference. Skip it. 6622 continue; 6623 } 6624 6625 String resourceName = attributeMap.get(resourceId); 6626 if (resourceName == null) { 6627 try { 6628 resourceName = res.getResourceName(resourceId); 6629 } catch (Resources.NotFoundException e) { 6630 resourceName = "0x" + Integer.toHexString(resourceId); 6631 } 6632 attributeMap.put(resourceId, resourceName); 6633 } 6634 6635 attributes[i] = resourceName; 6636 attributes[i + 1] = t.getString(index); 6637 i += 2; 6638 } 6639 6640 // Trim to fit contents. 6641 final String[] trimmed = new String[i]; 6642 System.arraycopy(attributes, 0, trimmed, 0, i); 6643 mAttributes = trimmed; 6644 } 6645 6646 @Override 6647 public String toString() { 6648 StringBuilder out = new StringBuilder(256); 6649 out.append(getClass().getName()); 6650 out.append('{'); 6651 out.append(Integer.toHexString(System.identityHashCode(this))); 6652 out.append(' '); 6653 switch (mViewFlags&VISIBILITY_MASK) { 6654 case VISIBLE: out.append('V'); break; 6655 case INVISIBLE: out.append('I'); break; 6656 case GONE: out.append('G'); break; 6657 default: out.append('.'); break; 6658 } 6659 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 6660 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 6661 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 6662 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 6663 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 6664 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 6665 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 6666 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 6667 out.append(' '); 6668 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 6669 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 6670 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 6671 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 6672 out.append('p'); 6673 } else { 6674 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 6675 } 6676 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 6677 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 6678 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 6679 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 6680 out.append(' '); 6681 out.append(mLeft); 6682 out.append(','); 6683 out.append(mTop); 6684 out.append('-'); 6685 out.append(mRight); 6686 out.append(','); 6687 out.append(mBottom); 6688 appendId(out); 6689 if (mAutofillId != null) { 6690 out.append(" aid="); out.append(mAutofillId); 6691 } 6692 out.append("}"); 6693 return out.toString(); 6694 } 6695 6696 void appendId(StringBuilder out) { 6697 final int id = getId(); 6698 if (id != NO_ID) { 6699 out.append(" #"); 6700 out.append(Integer.toHexString(id)); 6701 final Resources r = mResources; 6702 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 6703 try { 6704 String pkgname; 6705 switch (id&0xff000000) { 6706 case 0x7f000000: 6707 pkgname="app"; 6708 break; 6709 case 0x01000000: 6710 pkgname="android"; 6711 break; 6712 default: 6713 pkgname = r.getResourcePackageName(id); 6714 break; 6715 } 6716 String typename = r.getResourceTypeName(id); 6717 String entryname = r.getResourceEntryName(id); 6718 out.append(" "); 6719 out.append(pkgname); 6720 out.append(":"); 6721 out.append(typename); 6722 out.append("/"); 6723 out.append(entryname); 6724 } catch (Resources.NotFoundException e) { 6725 } 6726 } 6727 } 6728 } 6729 6730 /** 6731 * <p> 6732 * Initializes the fading edges from a given set of styled attributes. This 6733 * method should be called by subclasses that need fading edges and when an 6734 * instance of these subclasses is created programmatically rather than 6735 * being inflated from XML. This method is automatically called when the XML 6736 * is inflated. 6737 * </p> 6738 * 6739 * @param a the styled attributes set to initialize the fading edges from 6740 * 6741 * @removed 6742 */ 6743 protected void initializeFadingEdge(TypedArray a) { 6744 // This method probably shouldn't have been included in the SDK to begin with. 6745 // It relies on 'a' having been initialized using an attribute filter array that is 6746 // not publicly available to the SDK. The old method has been renamed 6747 // to initializeFadingEdgeInternal and hidden for framework use only; 6748 // this one initializes using defaults to make it safe to call for apps. 6749 6750 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 6751 6752 initializeFadingEdgeInternal(arr); 6753 6754 arr.recycle(); 6755 } 6756 6757 /** 6758 * <p> 6759 * Initializes the fading edges from a given set of styled attributes. This 6760 * method should be called by subclasses that need fading edges and when an 6761 * instance of these subclasses is created programmatically rather than 6762 * being inflated from XML. This method is automatically called when the XML 6763 * is inflated. 6764 * </p> 6765 * 6766 * @param a the styled attributes set to initialize the fading edges from 6767 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 6768 */ 6769 protected void initializeFadingEdgeInternal(TypedArray a) { 6770 initScrollCache(); 6771 6772 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 6773 R.styleable.View_fadingEdgeLength, 6774 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 6775 } 6776 6777 /** 6778 * Returns the size of the vertical faded edges used to indicate that more 6779 * content in this view is visible. 6780 * 6781 * @return The size in pixels of the vertical faded edge or 0 if vertical 6782 * faded edges are not enabled for this view. 6783 * @attr ref android.R.styleable#View_fadingEdgeLength 6784 */ 6785 public int getVerticalFadingEdgeLength() { 6786 if (isVerticalFadingEdgeEnabled()) { 6787 ScrollabilityCache cache = mScrollCache; 6788 if (cache != null) { 6789 return cache.fadingEdgeLength; 6790 } 6791 } 6792 return 0; 6793 } 6794 6795 /** 6796 * Set the size of the faded edge used to indicate that more content in this 6797 * view is available. Will not change whether the fading edge is enabled; use 6798 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 6799 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 6800 * for the vertical or horizontal fading edges. 6801 * 6802 * @param length The size in pixels of the faded edge used to indicate that more 6803 * content in this view is visible. 6804 */ 6805 public void setFadingEdgeLength(int length) { 6806 initScrollCache(); 6807 mScrollCache.fadingEdgeLength = length; 6808 } 6809 6810 /** 6811 * Returns the size of the horizontal faded edges used to indicate that more 6812 * content in this view is visible. 6813 * 6814 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 6815 * faded edges are not enabled for this view. 6816 * @attr ref android.R.styleable#View_fadingEdgeLength 6817 */ 6818 public int getHorizontalFadingEdgeLength() { 6819 if (isHorizontalFadingEdgeEnabled()) { 6820 ScrollabilityCache cache = mScrollCache; 6821 if (cache != null) { 6822 return cache.fadingEdgeLength; 6823 } 6824 } 6825 return 0; 6826 } 6827 6828 /** 6829 * Returns the width of the vertical scrollbar. 6830 * 6831 * @return The width in pixels of the vertical scrollbar or 0 if there 6832 * is no vertical scrollbar. 6833 */ 6834 public int getVerticalScrollbarWidth() { 6835 ScrollabilityCache cache = mScrollCache; 6836 if (cache != null) { 6837 ScrollBarDrawable scrollBar = cache.scrollBar; 6838 if (scrollBar != null) { 6839 int size = scrollBar.getSize(true); 6840 if (size <= 0) { 6841 size = cache.scrollBarSize; 6842 } 6843 return size; 6844 } 6845 return 0; 6846 } 6847 return 0; 6848 } 6849 6850 /** 6851 * Returns the height of the horizontal scrollbar. 6852 * 6853 * @return The height in pixels of the horizontal scrollbar or 0 if 6854 * there is no horizontal scrollbar. 6855 */ 6856 protected int getHorizontalScrollbarHeight() { 6857 ScrollabilityCache cache = mScrollCache; 6858 if (cache != null) { 6859 ScrollBarDrawable scrollBar = cache.scrollBar; 6860 if (scrollBar != null) { 6861 int size = scrollBar.getSize(false); 6862 if (size <= 0) { 6863 size = cache.scrollBarSize; 6864 } 6865 return size; 6866 } 6867 return 0; 6868 } 6869 return 0; 6870 } 6871 6872 /** 6873 * <p> 6874 * Initializes the scrollbars from a given set of styled attributes. This 6875 * method should be called by subclasses that need scrollbars and when an 6876 * instance of these subclasses is created programmatically rather than 6877 * being inflated from XML. This method is automatically called when the XML 6878 * is inflated. 6879 * </p> 6880 * 6881 * @param a the styled attributes set to initialize the scrollbars from 6882 * 6883 * @removed 6884 */ 6885 protected void initializeScrollbars(TypedArray a) { 6886 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 6887 // using the View filter array which is not available to the SDK. As such, internal 6888 // framework usage now uses initializeScrollbarsInternal and we grab a default 6889 // TypedArray with the right filter instead here. 6890 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 6891 6892 initializeScrollbarsInternal(arr); 6893 6894 // We ignored the method parameter. Recycle the one we actually did use. 6895 arr.recycle(); 6896 } 6897 6898 private void initializeScrollBarDrawable() { 6899 initScrollCache(); 6900 6901 if (mScrollCache.scrollBar == null) { 6902 mScrollCache.scrollBar = new ScrollBarDrawable(); 6903 mScrollCache.scrollBar.setState(getDrawableState()); 6904 mScrollCache.scrollBar.setCallback(this); 6905 } 6906 } 6907 6908 /** 6909 * <p> 6910 * Initializes the scrollbars from a given set of styled attributes. This 6911 * method should be called by subclasses that need scrollbars and when an 6912 * instance of these subclasses is created programmatically rather than 6913 * being inflated from XML. This method is automatically called when the XML 6914 * is inflated. 6915 * </p> 6916 * 6917 * @param a the styled attributes set to initialize the scrollbars from 6918 * @hide 6919 */ 6920 @UnsupportedAppUsage 6921 protected void initializeScrollbarsInternal(TypedArray a) { 6922 initScrollCache(); 6923 6924 final ScrollabilityCache scrollabilityCache = mScrollCache; 6925 6926 if (scrollabilityCache.scrollBar == null) { 6927 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 6928 scrollabilityCache.scrollBar.setState(getDrawableState()); 6929 scrollabilityCache.scrollBar.setCallback(this); 6930 } 6931 6932 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 6933 6934 if (!fadeScrollbars) { 6935 scrollabilityCache.state = ScrollabilityCache.ON; 6936 } 6937 scrollabilityCache.fadeScrollBars = fadeScrollbars; 6938 6939 6940 scrollabilityCache.scrollBarFadeDuration = a.getInt( 6941 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 6942 .getScrollBarFadeDuration()); 6943 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 6944 R.styleable.View_scrollbarDefaultDelayBeforeFade, 6945 ViewConfiguration.getScrollDefaultDelay()); 6946 6947 6948 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 6949 com.android.internal.R.styleable.View_scrollbarSize, 6950 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 6951 6952 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 6953 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 6954 6955 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 6956 if (thumb != null) { 6957 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 6958 } 6959 6960 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 6961 false); 6962 if (alwaysDraw) { 6963 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 6964 } 6965 6966 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 6967 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 6968 6969 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 6970 if (thumb != null) { 6971 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 6972 } 6973 6974 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 6975 false); 6976 if (alwaysDraw) { 6977 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 6978 } 6979 6980 // Apply layout direction to the new Drawables if needed 6981 final int layoutDirection = getLayoutDirection(); 6982 if (track != null) { 6983 track.setLayoutDirection(layoutDirection); 6984 } 6985 if (thumb != null) { 6986 thumb.setLayoutDirection(layoutDirection); 6987 } 6988 6989 // Re-apply user/background padding so that scrollbar(s) get added 6990 resolvePadding(); 6991 } 6992 6993 /** 6994 * Defines the vertical scrollbar thumb drawable 6995 * @attr ref android.R.styleable#View_scrollbarThumbVertical 6996 * 6997 * @see #awakenScrollBars(int) 6998 * @see #isVerticalScrollBarEnabled() 6999 * @see #setVerticalScrollBarEnabled(boolean) 7000 */ 7001 public void setVerticalScrollbarThumbDrawable(@Nullable Drawable drawable) { 7002 initializeScrollBarDrawable(); 7003 mScrollCache.scrollBar.setVerticalThumbDrawable(drawable); 7004 } 7005 7006 /** 7007 * Defines the vertical scrollbar track drawable 7008 * @attr ref android.R.styleable#View_scrollbarTrackVertical 7009 * 7010 * @see #awakenScrollBars(int) 7011 * @see #isVerticalScrollBarEnabled() 7012 * @see #setVerticalScrollBarEnabled(boolean) 7013 */ 7014 public void setVerticalScrollbarTrackDrawable(@Nullable Drawable drawable) { 7015 initializeScrollBarDrawable(); 7016 mScrollCache.scrollBar.setVerticalTrackDrawable(drawable); 7017 } 7018 7019 /** 7020 * Defines the horizontal thumb drawable 7021 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 7022 * 7023 * @see #awakenScrollBars(int) 7024 * @see #isHorizontalScrollBarEnabled() 7025 * @see #setHorizontalScrollBarEnabled(boolean) 7026 */ 7027 public void setHorizontalScrollbarThumbDrawable(@Nullable Drawable drawable) { 7028 initializeScrollBarDrawable(); 7029 mScrollCache.scrollBar.setHorizontalThumbDrawable(drawable); 7030 } 7031 7032 /** 7033 * Defines the horizontal track drawable 7034 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 7035 * 7036 * @see #awakenScrollBars(int) 7037 * @see #isHorizontalScrollBarEnabled() 7038 * @see #setHorizontalScrollBarEnabled(boolean) 7039 */ 7040 public void setHorizontalScrollbarTrackDrawable(@Nullable Drawable drawable) { 7041 initializeScrollBarDrawable(); 7042 mScrollCache.scrollBar.setHorizontalTrackDrawable(drawable); 7043 } 7044 7045 /** 7046 * Returns the currently configured Drawable for the thumb of the vertical scroll bar if it 7047 * exists, null otherwise. 7048 * 7049 * @see #awakenScrollBars(int) 7050 * @see #isVerticalScrollBarEnabled() 7051 * @see #setVerticalScrollBarEnabled(boolean) 7052 */ 7053 public @Nullable Drawable getVerticalScrollbarThumbDrawable() { 7054 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalThumbDrawable() : null; 7055 } 7056 7057 /** 7058 * Returns the currently configured Drawable for the track of the vertical scroll bar if it 7059 * exists, null otherwise. 7060 * 7061 * @see #awakenScrollBars(int) 7062 * @see #isVerticalScrollBarEnabled() 7063 * @see #setVerticalScrollBarEnabled(boolean) 7064 */ 7065 public @Nullable Drawable getVerticalScrollbarTrackDrawable() { 7066 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalTrackDrawable() : null; 7067 } 7068 7069 /** 7070 * Returns the currently configured Drawable for the thumb of the horizontal scroll bar if it 7071 * exists, null otherwise. 7072 * 7073 * @see #awakenScrollBars(int) 7074 * @see #isHorizontalScrollBarEnabled() 7075 * @see #setHorizontalScrollBarEnabled(boolean) 7076 */ 7077 public @Nullable Drawable getHorizontalScrollbarThumbDrawable() { 7078 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalThumbDrawable() : null; 7079 } 7080 7081 /** 7082 * Returns the currently configured Drawable for the track of the horizontal scroll bar if it 7083 * exists, null otherwise. 7084 * 7085 * @see #awakenScrollBars(int) 7086 * @see #isHorizontalScrollBarEnabled() 7087 * @see #setHorizontalScrollBarEnabled(boolean) 7088 */ 7089 public @Nullable Drawable getHorizontalScrollbarTrackDrawable() { 7090 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalTrackDrawable() : null; 7091 } 7092 7093 private void initializeScrollIndicatorsInternal() { 7094 // Some day maybe we'll break this into top/left/start/etc. and let the 7095 // client control it. Until then, you can have any scroll indicator you 7096 // want as long as it's a 1dp foreground-colored rectangle. 7097 if (mScrollIndicatorDrawable == null) { 7098 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 7099 } 7100 } 7101 7102 /** 7103 * <p> 7104 * Initalizes the scrollability cache if necessary. 7105 * </p> 7106 */ 7107 private void initScrollCache() { 7108 if (mScrollCache == null) { 7109 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 7110 } 7111 } 7112 7113 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 7114 private ScrollabilityCache getScrollCache() { 7115 initScrollCache(); 7116 return mScrollCache; 7117 } 7118 7119 /** 7120 * Set the position of the vertical scroll bar. Should be one of 7121 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 7122 * {@link #SCROLLBAR_POSITION_RIGHT}. 7123 * 7124 * @param position Where the vertical scroll bar should be positioned. 7125 */ 7126 public void setVerticalScrollbarPosition(int position) { 7127 if (mVerticalScrollbarPosition != position) { 7128 mVerticalScrollbarPosition = position; 7129 computeOpaqueFlags(); 7130 resolvePadding(); 7131 } 7132 } 7133 7134 /** 7135 * @return The position where the vertical scroll bar will show, if applicable. 7136 * @see #setVerticalScrollbarPosition(int) 7137 */ 7138 public int getVerticalScrollbarPosition() { 7139 return mVerticalScrollbarPosition; 7140 } 7141 7142 boolean isOnScrollbar(float x, float y) { 7143 if (mScrollCache == null) { 7144 return false; 7145 } 7146 x += getScrollX(); 7147 y += getScrollY(); 7148 final boolean canScrollVertically = 7149 computeVerticalScrollRange() > computeVerticalScrollExtent(); 7150 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden() && canScrollVertically) { 7151 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7152 getVerticalScrollBarBounds(null, touchBounds); 7153 if (touchBounds.contains((int) x, (int) y)) { 7154 return true; 7155 } 7156 } 7157 final boolean canScrollHorizontally = 7158 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 7159 if (isHorizontalScrollBarEnabled() && canScrollHorizontally) { 7160 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7161 getHorizontalScrollBarBounds(null, touchBounds); 7162 if (touchBounds.contains((int) x, (int) y)) { 7163 return true; 7164 } 7165 } 7166 return false; 7167 } 7168 7169 @UnsupportedAppUsage 7170 boolean isOnScrollbarThumb(float x, float y) { 7171 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 7172 } 7173 7174 private boolean isOnVerticalScrollbarThumb(float x, float y) { 7175 if (mScrollCache == null || !isVerticalScrollBarEnabled() || isVerticalScrollBarHidden()) { 7176 return false; 7177 } 7178 final int range = computeVerticalScrollRange(); 7179 final int extent = computeVerticalScrollExtent(); 7180 if (range > extent) { 7181 x += getScrollX(); 7182 y += getScrollY(); 7183 final Rect bounds = mScrollCache.mScrollBarBounds; 7184 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7185 getVerticalScrollBarBounds(bounds, touchBounds); 7186 final int offset = computeVerticalScrollOffset(); 7187 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 7188 extent, range); 7189 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 7190 extent, range, offset); 7191 final int thumbTop = bounds.top + thumbOffset; 7192 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 7193 if (x >= touchBounds.left && x <= touchBounds.right 7194 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 7195 return true; 7196 } 7197 } 7198 return false; 7199 } 7200 7201 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 7202 if (mScrollCache == null || !isHorizontalScrollBarEnabled()) { 7203 return false; 7204 } 7205 final int range = computeHorizontalScrollRange(); 7206 final int extent = computeHorizontalScrollExtent(); 7207 if (range > extent) { 7208 x += getScrollX(); 7209 y += getScrollY(); 7210 final Rect bounds = mScrollCache.mScrollBarBounds; 7211 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7212 getHorizontalScrollBarBounds(bounds, touchBounds); 7213 final int offset = computeHorizontalScrollOffset(); 7214 7215 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 7216 extent, range); 7217 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 7218 extent, range, offset); 7219 final int thumbLeft = bounds.left + thumbOffset; 7220 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 7221 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 7222 && y >= touchBounds.top && y <= touchBounds.bottom) { 7223 return true; 7224 } 7225 } 7226 return false; 7227 } 7228 7229 @UnsupportedAppUsage 7230 boolean isDraggingScrollBar() { 7231 return mScrollCache != null 7232 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 7233 } 7234 7235 /** 7236 * Sets the state of all scroll indicators. 7237 * <p> 7238 * See {@link #setScrollIndicators(int, int)} for usage information. 7239 * 7240 * @param indicators a bitmask of indicators that should be enabled, or 7241 * {@code 0} to disable all indicators 7242 * @see #setScrollIndicators(int, int) 7243 * @see #getScrollIndicators() 7244 * @attr ref android.R.styleable#View_scrollIndicators 7245 */ 7246 @RemotableViewMethod 7247 public void setScrollIndicators(@ScrollIndicators int indicators) { 7248 setScrollIndicators(indicators, 7249 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 7250 } 7251 7252 /** 7253 * Sets the state of the scroll indicators specified by the mask. To change 7254 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 7255 * <p> 7256 * When a scroll indicator is enabled, it will be displayed if the view 7257 * can scroll in the direction of the indicator. 7258 * <p> 7259 * Multiple indicator types may be enabled or disabled by passing the 7260 * logical OR of the desired types. If multiple types are specified, they 7261 * will all be set to the same enabled state. 7262 * <p> 7263 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 7264 * 7265 * @param indicators the indicator direction, or the logical OR of multiple 7266 * indicator directions. One or more of: 7267 * <ul> 7268 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 7269 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 7270 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 7271 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 7272 * <li>{@link #SCROLL_INDICATOR_START}</li> 7273 * <li>{@link #SCROLL_INDICATOR_END}</li> 7274 * </ul> 7275 * @see #setScrollIndicators(int) 7276 * @see #getScrollIndicators() 7277 * @attr ref android.R.styleable#View_scrollIndicators 7278 */ 7279 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 7280 // Shift and sanitize mask. 7281 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7282 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 7283 7284 // Shift and mask indicators. 7285 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7286 indicators &= mask; 7287 7288 // Merge with non-masked flags. 7289 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 7290 7291 if (mPrivateFlags3 != updatedFlags) { 7292 mPrivateFlags3 = updatedFlags; 7293 7294 if (indicators != 0) { 7295 initializeScrollIndicatorsInternal(); 7296 } 7297 invalidate(); 7298 } 7299 } 7300 7301 /** 7302 * Returns a bitmask representing the enabled scroll indicators. 7303 * <p> 7304 * For example, if the top and left scroll indicators are enabled and all 7305 * other indicators are disabled, the return value will be 7306 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 7307 * <p> 7308 * To check whether the bottom scroll indicator is enabled, use the value 7309 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 7310 * 7311 * @return a bitmask representing the enabled scroll indicators 7312 */ 7313 @InspectableProperty(flagMapping = { 7314 @FlagEntry(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"), 7315 @FlagEntry(target = SCROLL_INDICATOR_TOP, name = "top"), 7316 @FlagEntry(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"), 7317 @FlagEntry(target = SCROLL_INDICATOR_LEFT, name = "left"), 7318 @FlagEntry(target = SCROLL_INDICATOR_RIGHT, name = "right"), 7319 @FlagEntry(target = SCROLL_INDICATOR_START, name = "start"), 7320 @FlagEntry(target = SCROLL_INDICATOR_END, name = "end") 7321 }) 7322 @ScrollIndicators 7323 public int getScrollIndicators() { 7324 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 7325 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7326 } 7327 7328 @UnsupportedAppUsage 7329 ListenerInfo getListenerInfo() { 7330 if (mListenerInfo != null) { 7331 return mListenerInfo; 7332 } 7333 mListenerInfo = new ListenerInfo(); 7334 return mListenerInfo; 7335 } 7336 7337 /** 7338 * Register a callback to be invoked when the scroll X or Y positions of 7339 * this view change. 7340 * <p> 7341 * <b>Note:</b> Some views handle scrolling independently from View and may 7342 * have their own separate listeners for scroll-type events. For example, 7343 * {@link android.widget.ListView ListView} allows clients to register an 7344 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 7345 * to listen for changes in list scroll position. 7346 * 7347 * @param l The listener to notify when the scroll X or Y position changes. 7348 * @see android.view.View#getScrollX() 7349 * @see android.view.View#getScrollY() 7350 */ 7351 public void setOnScrollChangeListener(OnScrollChangeListener l) { 7352 getListenerInfo().mOnScrollChangeListener = l; 7353 } 7354 7355 /** 7356 * Register a callback to be invoked when focus of this view changed. 7357 * 7358 * @param l The callback that will run. 7359 */ 7360 public void setOnFocusChangeListener(OnFocusChangeListener l) { 7361 getListenerInfo().mOnFocusChangeListener = l; 7362 } 7363 7364 /** 7365 * Add a listener that will be called when the bounds of the view change due to 7366 * layout processing. 7367 * 7368 * @param listener The listener that will be called when layout bounds change. 7369 */ 7370 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 7371 ListenerInfo li = getListenerInfo(); 7372 if (li.mOnLayoutChangeListeners == null) { 7373 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 7374 } 7375 if (!li.mOnLayoutChangeListeners.contains(listener)) { 7376 li.mOnLayoutChangeListeners.add(listener); 7377 } 7378 } 7379 7380 /** 7381 * Remove a listener for layout changes. 7382 * 7383 * @param listener The listener for layout bounds change. 7384 */ 7385 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 7386 ListenerInfo li = mListenerInfo; 7387 if (li == null || li.mOnLayoutChangeListeners == null) { 7388 return; 7389 } 7390 li.mOnLayoutChangeListeners.remove(listener); 7391 } 7392 7393 /** 7394 * Add a listener for attach state changes. 7395 * 7396 * This listener will be called whenever this view is attached or detached 7397 * from a window. Remove the listener using 7398 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 7399 * 7400 * @param listener Listener to attach 7401 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 7402 */ 7403 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7404 ListenerInfo li = getListenerInfo(); 7405 if (li.mOnAttachStateChangeListeners == null) { 7406 li.mOnAttachStateChangeListeners 7407 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 7408 } 7409 li.mOnAttachStateChangeListeners.add(listener); 7410 } 7411 7412 /** 7413 * Remove a listener for attach state changes. The listener will receive no further 7414 * notification of window attach/detach events. 7415 * 7416 * @param listener Listener to remove 7417 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 7418 */ 7419 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7420 ListenerInfo li = mListenerInfo; 7421 if (li == null || li.mOnAttachStateChangeListeners == null) { 7422 return; 7423 } 7424 li.mOnAttachStateChangeListeners.remove(listener); 7425 } 7426 7427 /** 7428 * Returns the focus-change callback registered for this view. 7429 * 7430 * @return The callback, or null if one is not registered. 7431 */ 7432 public OnFocusChangeListener getOnFocusChangeListener() { 7433 ListenerInfo li = mListenerInfo; 7434 return li != null ? li.mOnFocusChangeListener : null; 7435 } 7436 7437 /** 7438 * Register a callback to be invoked when this view is clicked. If this view is not 7439 * clickable, it becomes clickable. 7440 * 7441 * @param l The callback that will run 7442 * 7443 * @see #setClickable(boolean) 7444 */ 7445 public void setOnClickListener(@Nullable OnClickListener l) { 7446 if (!isClickable()) { 7447 setClickable(true); 7448 } 7449 getListenerInfo().mOnClickListener = l; 7450 } 7451 7452 /** 7453 * Return whether this view has an attached OnClickListener. Returns 7454 * true if there is a listener, false if there is none. 7455 */ 7456 public boolean hasOnClickListeners() { 7457 ListenerInfo li = mListenerInfo; 7458 return (li != null && li.mOnClickListener != null); 7459 } 7460 7461 /** 7462 * Register a callback to be invoked when this view is clicked and held. If this view is not 7463 * long clickable, it becomes long clickable. 7464 * 7465 * @param l The callback that will run 7466 * 7467 * @see #setLongClickable(boolean) 7468 */ 7469 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 7470 if (!isLongClickable()) { 7471 setLongClickable(true); 7472 } 7473 getListenerInfo().mOnLongClickListener = l; 7474 } 7475 7476 /** 7477 * Return whether this view has an attached OnLongClickListener. Returns 7478 * true if there is a listener, false if there is none. 7479 */ 7480 public boolean hasOnLongClickListeners() { 7481 ListenerInfo li = mListenerInfo; 7482 return (li != null && li.mOnLongClickListener != null); 7483 } 7484 7485 /** 7486 * @return the registered {@link OnLongClickListener} if there is one, {@code null} otherwise. 7487 * @hide 7488 */ 7489 @Nullable 7490 public OnLongClickListener getOnLongClickListener() { 7491 ListenerInfo li = mListenerInfo; 7492 return (li != null) ? li.mOnLongClickListener : null; 7493 } 7494 7495 /** 7496 * Register a callback to be invoked when this view is context clicked. If the view is not 7497 * context clickable, it becomes context clickable. 7498 * 7499 * @param l The callback that will run 7500 * @see #setContextClickable(boolean) 7501 */ 7502 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 7503 if (!isContextClickable()) { 7504 setContextClickable(true); 7505 } 7506 getListenerInfo().mOnContextClickListener = l; 7507 } 7508 7509 /** 7510 * Register a callback to be invoked when the context menu for this view is 7511 * being built. If this view is not long clickable, it becomes long clickable. 7512 * 7513 * @param l The callback that will run 7514 * 7515 */ 7516 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 7517 if (!isLongClickable()) { 7518 setLongClickable(true); 7519 } 7520 getListenerInfo().mOnCreateContextMenuListener = l; 7521 } 7522 7523 /** 7524 * Set an observer to collect stats for each frame rendered for this view. 7525 * 7526 * @hide 7527 */ 7528 public void addFrameMetricsListener(Window window, 7529 Window.OnFrameMetricsAvailableListener listener, 7530 Handler handler) { 7531 if (mAttachInfo != null) { 7532 if (mAttachInfo.mThreadedRenderer != null) { 7533 if (mFrameMetricsObservers == null) { 7534 mFrameMetricsObservers = new ArrayList<>(); 7535 } 7536 7537 FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); 7538 mFrameMetricsObservers.add(fmo); 7539 mAttachInfo.mThreadedRenderer.addObserver(fmo.getRendererObserver()); 7540 } else { 7541 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7542 } 7543 } else { 7544 if (mFrameMetricsObservers == null) { 7545 mFrameMetricsObservers = new ArrayList<>(); 7546 } 7547 7548 FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); 7549 mFrameMetricsObservers.add(fmo); 7550 } 7551 } 7552 7553 /** 7554 * Remove observer configured to collect frame stats for this view. 7555 * 7556 * @hide 7557 */ 7558 public void removeFrameMetricsListener( 7559 Window.OnFrameMetricsAvailableListener listener) { 7560 ThreadedRenderer renderer = getThreadedRenderer(); 7561 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 7562 if (fmo == null) { 7563 throw new IllegalArgumentException( 7564 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 7565 } 7566 7567 if (mFrameMetricsObservers != null) { 7568 mFrameMetricsObservers.remove(fmo); 7569 if (renderer != null) { 7570 renderer.removeObserver(fmo.getRendererObserver()); 7571 } 7572 } 7573 } 7574 7575 private void registerPendingFrameMetricsObservers() { 7576 if (mFrameMetricsObservers != null) { 7577 ThreadedRenderer renderer = getThreadedRenderer(); 7578 if (renderer != null) { 7579 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 7580 renderer.addObserver(fmo.getRendererObserver()); 7581 } 7582 } else { 7583 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7584 } 7585 } 7586 } 7587 7588 private FrameMetricsObserver findFrameMetricsObserver( 7589 Window.OnFrameMetricsAvailableListener listener) { 7590 if (mFrameMetricsObservers != null) { 7591 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 7592 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 7593 if (observer.mListener == listener) { 7594 return observer; 7595 } 7596 } 7597 } 7598 7599 return null; 7600 } 7601 7602 /** @hide */ 7603 public void setNotifyAutofillManagerOnClick(boolean notify) { 7604 if (notify) { 7605 mPrivateFlags |= PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7606 } else { 7607 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7608 } 7609 } 7610 7611 private void notifyAutofillManagerOnClick() { 7612 if ((mPrivateFlags & PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK) != 0) { 7613 try { 7614 getAutofillManager().notifyViewClicked(this); 7615 } finally { 7616 // Set it to already called so it's not called twice when called by 7617 // performClickInternal() 7618 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7619 } 7620 } 7621 } 7622 7623 /** 7624 * Entry point for {@link #performClick()} - other methods on View should call it instead of 7625 * {@code performClick()} directly to make sure the autofill manager is notified when 7626 * necessary (as subclasses could extend {@code performClick()} without calling the parent's 7627 * method). 7628 */ 7629 private boolean performClickInternal() { 7630 // Must notify autofill manager before performing the click actions to avoid scenarios where 7631 // the app has a click listener that changes the state of views the autofill service might 7632 // be interested on. 7633 notifyAutofillManagerOnClick(); 7634 7635 return performClick(); 7636 } 7637 7638 /** 7639 * Call this view's OnClickListener, if it is defined. Performs all normal 7640 * actions associated with clicking: reporting accessibility event, playing 7641 * a sound, etc. 7642 * 7643 * @return True there was an assigned OnClickListener that was called, false 7644 * otherwise is returned. 7645 */ 7646 // NOTE: other methods on View should not call this method directly, but performClickInternal() 7647 // instead, to guarantee that the autofill manager is notified when necessary (as subclasses 7648 // could extend this method without calling super.performClick()). 7649 public boolean performClick() { 7650 // We still need to call this method to handle the cases where performClick() was called 7651 // externally, instead of through performClickInternal() 7652 notifyAutofillManagerOnClick(); 7653 7654 final boolean result; 7655 final ListenerInfo li = mListenerInfo; 7656 if (li != null && li.mOnClickListener != null) { 7657 playSoundEffect(SoundEffectConstants.CLICK); 7658 li.mOnClickListener.onClick(this); 7659 result = true; 7660 } else { 7661 result = false; 7662 } 7663 7664 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 7665 7666 notifyEnterOrExitForAutoFillIfNeeded(true); 7667 7668 return result; 7669 } 7670 7671 /** 7672 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 7673 * this only calls the listener, and does not do any associated clicking 7674 * actions like reporting an accessibility event. 7675 * 7676 * @return True there was an assigned OnClickListener that was called, false 7677 * otherwise is returned. 7678 */ 7679 public boolean callOnClick() { 7680 ListenerInfo li = mListenerInfo; 7681 if (li != null && li.mOnClickListener != null) { 7682 li.mOnClickListener.onClick(this); 7683 return true; 7684 } 7685 return false; 7686 } 7687 7688 /** 7689 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7690 * context menu if the OnLongClickListener did not consume the event. 7691 * 7692 * @return {@code true} if one of the above receivers consumed the event, 7693 * {@code false} otherwise 7694 */ 7695 public boolean performLongClick() { 7696 return performLongClickInternal(mLongClickX, mLongClickY); 7697 } 7698 7699 /** 7700 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7701 * context menu if the OnLongClickListener did not consume the event, 7702 * anchoring it to an (x,y) coordinate. 7703 * 7704 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 7705 * to disable anchoring 7706 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 7707 * to disable anchoring 7708 * @return {@code true} if one of the above receivers consumed the event, 7709 * {@code false} otherwise 7710 */ 7711 public boolean performLongClick(float x, float y) { 7712 mLongClickX = x; 7713 mLongClickY = y; 7714 final boolean handled = performLongClick(); 7715 mLongClickX = Float.NaN; 7716 mLongClickY = Float.NaN; 7717 return handled; 7718 } 7719 7720 /** 7721 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7722 * context menu if the OnLongClickListener did not consume the event, 7723 * optionally anchoring it to an (x,y) coordinate. 7724 * 7725 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 7726 * to disable anchoring 7727 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 7728 * to disable anchoring 7729 * @return {@code true} if one of the above receivers consumed the event, 7730 * {@code false} otherwise 7731 */ 7732 private boolean performLongClickInternal(float x, float y) { 7733 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 7734 7735 boolean handled = false; 7736 final OnLongClickListener listener = 7737 mListenerInfo == null ? null : mListenerInfo.mOnLongClickListener; 7738 boolean shouldPerformHapticFeedback = true; 7739 if (listener != null) { 7740 handled = listener.onLongClick(View.this); 7741 if (handled) { 7742 shouldPerformHapticFeedback = listener.onLongClickUseDefaultHapticFeedback( 7743 View.this); 7744 } 7745 } 7746 if (!handled) { 7747 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 7748 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 7749 } 7750 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 7751 if (!handled) { 7752 handled = showLongClickTooltip((int) x, (int) y); 7753 } 7754 } 7755 if (handled && shouldPerformHapticFeedback) { 7756 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 7757 } 7758 return handled; 7759 } 7760 7761 /** 7762 * Call this view's OnContextClickListener, if it is defined. 7763 * 7764 * @param x the x coordinate of the context click 7765 * @param y the y coordinate of the context click 7766 * @return True if there was an assigned OnContextClickListener that consumed the event, false 7767 * otherwise. 7768 */ 7769 public boolean performContextClick(float x, float y) { 7770 return performContextClick(); 7771 } 7772 7773 /** 7774 * Call this view's OnContextClickListener, if it is defined. 7775 * 7776 * @return True if there was an assigned OnContextClickListener that consumed the event, false 7777 * otherwise. 7778 */ 7779 public boolean performContextClick() { 7780 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 7781 7782 boolean handled = false; 7783 ListenerInfo li = mListenerInfo; 7784 if (li != null && li.mOnContextClickListener != null) { 7785 handled = li.mOnContextClickListener.onContextClick(View.this); 7786 } 7787 if (handled) { 7788 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 7789 } 7790 return handled; 7791 } 7792 7793 /** 7794 * Performs button-related actions during a touch down event. 7795 * 7796 * @param event The event. 7797 * @return True if the down was consumed. 7798 * 7799 * @hide 7800 */ 7801 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 7802 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 7803 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 7804 showContextMenu(event.getX(), event.getY()); 7805 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 7806 return true; 7807 } 7808 return false; 7809 } 7810 7811 /** 7812 * Shows the context menu for this view. 7813 * 7814 * @return {@code true} if the context menu was shown, {@code false} 7815 * otherwise 7816 * @see #showContextMenu(float, float) 7817 */ 7818 public boolean showContextMenu() { 7819 return getParent().showContextMenuForChild(this); 7820 } 7821 7822 /** 7823 * Shows the context menu for this view anchored to the specified 7824 * view-relative coordinate. 7825 * 7826 * @param x the X coordinate in pixels relative to the view to which the 7827 * menu should be anchored, or {@link Float#NaN} to disable anchoring 7828 * @param y the Y coordinate in pixels relative to the view to which the 7829 * menu should be anchored, or {@link Float#NaN} to disable anchoring 7830 * @return {@code true} if the context menu was shown, {@code false} 7831 * otherwise 7832 */ 7833 public boolean showContextMenu(float x, float y) { 7834 return getParent().showContextMenuForChild(this, x, y); 7835 } 7836 7837 /** 7838 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 7839 * 7840 * @param callback Callback that will control the lifecycle of the action mode 7841 * @return The new action mode if it is started, null otherwise 7842 * 7843 * @see ActionMode 7844 * @see #startActionMode(android.view.ActionMode.Callback, int) 7845 */ 7846 public ActionMode startActionMode(ActionMode.Callback callback) { 7847 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 7848 } 7849 7850 /** 7851 * Start an action mode with the given type. 7852 * 7853 * @param callback Callback that will control the lifecycle of the action mode 7854 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 7855 * @return The new action mode if it is started, null otherwise 7856 * 7857 * @see ActionMode 7858 */ 7859 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 7860 ViewParent parent = getParent(); 7861 if (parent == null) return null; 7862 try { 7863 return parent.startActionModeForChild(this, callback, type); 7864 } catch (AbstractMethodError ame) { 7865 // Older implementations of custom views might not implement this. 7866 return parent.startActionModeForChild(this, callback); 7867 } 7868 } 7869 7870 /** 7871 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 7872 * Context, creating a unique View identifier to retrieve the result. 7873 * 7874 * @param intent The Intent to be started. 7875 * @param requestCode The request code to use. 7876 * @hide 7877 */ 7878 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 7879 public void startActivityForResult(Intent intent, int requestCode) { 7880 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 7881 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 7882 } 7883 7884 /** 7885 * If this View corresponds to the calling who, dispatches the activity result. 7886 * @param who The identifier for the targeted View to receive the result. 7887 * @param requestCode The integer request code originally supplied to 7888 * startActivityForResult(), allowing you to identify who this 7889 * result came from. 7890 * @param resultCode The integer result code returned by the child activity 7891 * through its setResult(). 7892 * @param data An Intent, which can return result data to the caller 7893 * (various data can be attached to Intent "extras"). 7894 * @return {@code true} if the activity result was dispatched. 7895 * @hide 7896 */ 7897 public boolean dispatchActivityResult( 7898 String who, int requestCode, int resultCode, Intent data) { 7899 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 7900 onActivityResult(requestCode, resultCode, data); 7901 mStartActivityRequestWho = null; 7902 return true; 7903 } 7904 return false; 7905 } 7906 7907 /** 7908 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 7909 * 7910 * @param requestCode The integer request code originally supplied to 7911 * startActivityForResult(), allowing you to identify who this 7912 * result came from. 7913 * @param resultCode The integer result code returned by the child activity 7914 * through its setResult(). 7915 * @param data An Intent, which can return result data to the caller 7916 * (various data can be attached to Intent "extras"). 7917 * @hide 7918 */ 7919 public void onActivityResult(int requestCode, int resultCode, Intent data) { 7920 // Do nothing. 7921 } 7922 7923 /** 7924 * Register a callback to be invoked when a hardware key is pressed in this view. 7925 * Key presses in software input methods will generally not trigger the methods of 7926 * this listener. 7927 * @param l the key listener to attach to this view 7928 */ 7929 public void setOnKeyListener(OnKeyListener l) { 7930 getListenerInfo().mOnKeyListener = l; 7931 } 7932 7933 /** 7934 * Register a callback to be invoked when a touch event is sent to this view. 7935 * @param l the touch listener to attach to this view 7936 */ 7937 public void setOnTouchListener(OnTouchListener l) { 7938 getListenerInfo().mOnTouchListener = l; 7939 } 7940 7941 /** 7942 * Register a callback to be invoked when a generic motion event is sent to this view. 7943 * @param l the generic motion listener to attach to this view 7944 */ 7945 public void setOnGenericMotionListener(OnGenericMotionListener l) { 7946 getListenerInfo().mOnGenericMotionListener = l; 7947 } 7948 7949 /** 7950 * Register a callback to be invoked when a hover event is sent to this view. 7951 * @param l the hover listener to attach to this view 7952 */ 7953 public void setOnHoverListener(OnHoverListener l) { 7954 getListenerInfo().mOnHoverListener = l; 7955 } 7956 7957 /** 7958 * Register a drag event listener callback object for this View. The parameter is 7959 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 7960 * View, the system calls the 7961 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 7962 * @param l An implementation of {@link android.view.View.OnDragListener}. 7963 */ 7964 public void setOnDragListener(OnDragListener l) { 7965 getListenerInfo().mOnDragListener = l; 7966 } 7967 7968 /** 7969 * Give this view focus. This will cause 7970 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 7971 * 7972 * Note: this does not check whether this {@link View} should get focus, it just 7973 * gives it focus no matter what. It should only be called internally by framework 7974 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 7975 * 7976 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 7977 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 7978 * focus moved when requestFocus() is called. It may not always 7979 * apply, in which case use the default View.FOCUS_DOWN. 7980 * @param previouslyFocusedRect The rectangle of the view that had focus 7981 * prior in this View's coordinate system. 7982 */ 7983 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 7984 if (DBG) { 7985 System.out.println(this + " requestFocus()"); 7986 } 7987 7988 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 7989 mPrivateFlags |= PFLAG_FOCUSED; 7990 7991 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 7992 7993 if (mParent != null) { 7994 mParent.requestChildFocus(this, this); 7995 updateFocusedInCluster(oldFocus, direction); 7996 } 7997 7998 if (mAttachInfo != null) { 7999 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 8000 } 8001 8002 onFocusChanged(true, direction, previouslyFocusedRect); 8003 refreshDrawableState(); 8004 } 8005 } 8006 8007 /** 8008 * Sets this view's preference for reveal behavior when it gains focus. 8009 * 8010 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 8011 * this view would prefer to be brought fully into view when it gains focus. 8012 * For example, a text field that a user is meant to type into. Other views such 8013 * as scrolling containers may prefer to opt-out of this behavior.</p> 8014 * 8015 * <p>The default value for views is true, though subclasses may change this 8016 * based on their preferred behavior.</p> 8017 * 8018 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 8019 * 8020 * @see #getRevealOnFocusHint() 8021 */ 8022 public final void setRevealOnFocusHint(boolean revealOnFocus) { 8023 if (revealOnFocus) { 8024 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 8025 } else { 8026 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 8027 } 8028 } 8029 8030 /** 8031 * Returns this view's preference for reveal behavior when it gains focus. 8032 * 8033 * <p>When this method returns true for a child view requesting focus, ancestor 8034 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 8035 * should make a best effort to make the newly focused child fully visible to the user. 8036 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 8037 * other properties affecting visibility to the user as part of the focus change.</p> 8038 * 8039 * @return true if this view would prefer to become fully visible when it gains focus, 8040 * false if it would prefer not to disrupt scroll positioning 8041 * 8042 * @see #setRevealOnFocusHint(boolean) 8043 */ 8044 public final boolean getRevealOnFocusHint() { 8045 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 8046 } 8047 8048 /** 8049 * Populates <code>outRect</code> with the hotspot bounds. By default, 8050 * the hotspot bounds are identical to the screen bounds. 8051 * 8052 * @param outRect rect to populate with hotspot bounds 8053 * @hide Only for internal use by views and widgets. 8054 */ 8055 public void getHotspotBounds(Rect outRect) { 8056 final Drawable background = getBackground(); 8057 if (background != null) { 8058 background.getHotspotBounds(outRect); 8059 } else { 8060 getBoundsOnScreen(outRect); 8061 } 8062 } 8063 8064 /** 8065 * Request that a rectangle of this view be visible on the screen, 8066 * scrolling if necessary just enough. 8067 * 8068 * <p>A View should call this if it maintains some notion of which part 8069 * of its content is interesting. For example, a text editing view 8070 * should call this when its cursor moves. 8071 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 8072 * It should not be affected by which part of the View is currently visible or its scroll 8073 * position. 8074 * 8075 * @param rectangle The rectangle in the View's content coordinate space 8076 * @return Whether any parent scrolled. 8077 */ 8078 public boolean requestRectangleOnScreen(Rect rectangle) { 8079 return requestRectangleOnScreen(rectangle, false); 8080 } 8081 8082 /** 8083 * Request that a rectangle of this view be visible on the screen, 8084 * scrolling if necessary just enough. 8085 * 8086 * <p>A View should call this if it maintains some notion of which part 8087 * of its content is interesting. For example, a text editing view 8088 * should call this when its cursor moves. 8089 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 8090 * It should not be affected by which part of the View is currently visible or its scroll 8091 * position. 8092 * <p>When <code>immediate</code> is set to true, scrolling will not be 8093 * animated. 8094 * 8095 * @param rectangle The rectangle in the View's content coordinate space 8096 * @param immediate True to forbid animated scrolling, false otherwise 8097 * @return Whether any parent scrolled. 8098 */ 8099 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 8100 if (mParent == null) { 8101 return false; 8102 } 8103 8104 View child = this; 8105 8106 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 8107 position.set(rectangle); 8108 8109 ViewParent parent = mParent; 8110 boolean scrolled = false; 8111 while (parent != null) { 8112 rectangle.set((int) position.left, (int) position.top, 8113 (int) position.right, (int) position.bottom); 8114 8115 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 8116 8117 if (!(parent instanceof View)) { 8118 break; 8119 } 8120 8121 // move it from child's content coordinate space to parent's content coordinate space 8122 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 8123 8124 child = (View) parent; 8125 parent = child.getParent(); 8126 } 8127 8128 return scrolled; 8129 } 8130 8131 /** 8132 * Called when this view wants to give up focus. If focus is cleared 8133 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 8134 * <p> 8135 * <strong>Note:</strong> When not in touch-mode, the framework will try to give focus 8136 * to the first focusable View from the top after focus is cleared. Hence, if this 8137 * View is the first from the top that can take focus, then all callbacks 8138 * related to clearing focus will be invoked after which the framework will 8139 * give focus to this view. 8140 * </p> 8141 */ 8142 public void clearFocus() { 8143 if (DBG) { 8144 System.out.println(this + " clearFocus()"); 8145 } 8146 8147 final boolean refocus = sAlwaysAssignFocus || !isInTouchMode(); 8148 clearFocusInternal(null, true, refocus); 8149 } 8150 8151 /** 8152 * Clears focus from the view, optionally propagating the change up through 8153 * the parent hierarchy and requesting that the root view place new focus. 8154 * 8155 * @param propagate whether to propagate the change up through the parent 8156 * hierarchy 8157 * @param refocus when propagate is true, specifies whether to request the 8158 * root view place new focus 8159 */ 8160 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 8161 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 8162 mPrivateFlags &= ~PFLAG_FOCUSED; 8163 clearParentsWantFocus(); 8164 8165 if (propagate && mParent != null) { 8166 mParent.clearChildFocus(this); 8167 } 8168 8169 onFocusChanged(false, 0, null); 8170 refreshDrawableState(); 8171 8172 if (propagate && (!refocus || !rootViewRequestFocus())) { 8173 notifyGlobalFocusCleared(this); 8174 } 8175 } 8176 } 8177 8178 void notifyGlobalFocusCleared(View oldFocus) { 8179 if (oldFocus != null && mAttachInfo != null) { 8180 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 8181 } 8182 } 8183 8184 boolean rootViewRequestFocus() { 8185 final View root = getRootView(); 8186 return root != null && root.requestFocus(); 8187 } 8188 8189 /** 8190 * Called internally by the view system when a new view is getting focus. 8191 * This is what clears the old focus. 8192 * <p> 8193 * <b>NOTE:</b> The parent view's focused child must be updated manually 8194 * after calling this method. Otherwise, the view hierarchy may be left in 8195 * an inconstent state. 8196 */ 8197 void unFocus(View focused) { 8198 if (DBG) { 8199 System.out.println(this + " unFocus()"); 8200 } 8201 8202 clearFocusInternal(focused, false, false); 8203 } 8204 8205 /** 8206 * Returns true if this view has focus itself, or is the ancestor of the 8207 * view that has focus. 8208 * 8209 * @return True if this view has or contains focus, false otherwise. 8210 */ 8211 @ViewDebug.ExportedProperty(category = "focus") 8212 public boolean hasFocus() { 8213 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 8214 } 8215 8216 /** 8217 * Returns true if this view is focusable or if it contains a reachable View 8218 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 8219 * is a view whose parents do not block descendants focus. 8220 * Only {@link #VISIBLE} views are considered focusable. 8221 * 8222 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 8223 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 8224 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 8225 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 8226 * {@code false} for views not explicitly marked as focusable. 8227 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 8228 * behavior.</p> 8229 * 8230 * @return {@code true} if the view is focusable or if the view contains a focusable 8231 * view, {@code false} otherwise 8232 * 8233 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 8234 * @see ViewGroup#getTouchscreenBlocksFocus() 8235 * @see #hasExplicitFocusable() 8236 */ 8237 public boolean hasFocusable() { 8238 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 8239 } 8240 8241 /** 8242 * Returns true if this view is focusable or if it contains a reachable View 8243 * for which {@link #hasExplicitFocusable()} returns {@code true}. 8244 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 8245 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 8246 * {@link #FOCUSABLE} are considered focusable. 8247 * 8248 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 8249 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 8250 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 8251 * to focusable will not.</p> 8252 * 8253 * @return {@code true} if the view is focusable or if the view contains a focusable 8254 * view, {@code false} otherwise 8255 * 8256 * @see #hasFocusable() 8257 */ 8258 public boolean hasExplicitFocusable() { 8259 return hasFocusable(false, true); 8260 } 8261 8262 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 8263 if (!isFocusableInTouchMode()) { 8264 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 8265 final ViewGroup g = (ViewGroup) p; 8266 if (g.shouldBlockFocusForTouchscreen()) { 8267 return false; 8268 } 8269 } 8270 } 8271 8272 // Invisible, gone, or disabled views are never focusable. 8273 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE 8274 || (mViewFlags & ENABLED_MASK) != ENABLED) { 8275 return false; 8276 } 8277 8278 // Only use effective focusable value when allowed. 8279 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 8280 return true; 8281 } 8282 8283 return false; 8284 } 8285 8286 /** 8287 * Called by the view system when the focus state of this view changes. 8288 * When the focus change event is caused by directional navigation, direction 8289 * and previouslyFocusedRect provide insight into where the focus is coming from. 8290 * When overriding, be sure to call up through to the super class so that 8291 * the standard focus handling will occur. 8292 * 8293 * @param gainFocus True if the View has focus; false otherwise. 8294 * @param direction The direction focus has moved when requestFocus() 8295 * is called to give this view focus. Values are 8296 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 8297 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 8298 * It may not always apply, in which case use the default. 8299 * @param previouslyFocusedRect The rectangle, in this view's coordinate 8300 * system, of the previously focused view. If applicable, this will be 8301 * passed in as finer grained information about where the focus is coming 8302 * from (in addition to direction). Will be <code>null</code> otherwise. 8303 */ 8304 @CallSuper 8305 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 8306 @Nullable Rect previouslyFocusedRect) { 8307 if (gainFocus) { 8308 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 8309 } else { 8310 notifyViewAccessibilityStateChangedIfNeeded( 8311 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8312 } 8313 8314 // Here we check whether we still need the default focus highlight, and switch it on/off. 8315 switchDefaultFocusHighlight(); 8316 8317 if (!gainFocus) { 8318 if (isPressed()) { 8319 setPressed(false); 8320 } 8321 if (hasWindowFocus()) { 8322 notifyFocusChangeToImeFocusController(false /* hasFocus */); 8323 } 8324 onFocusLost(); 8325 } else if (hasWindowFocus()) { 8326 notifyFocusChangeToImeFocusController(true /* hasFocus */); 8327 8328 if (mIsHandwritingDelegate) { 8329 ViewRootImpl viewRoot = getViewRootImpl(); 8330 if (viewRoot != null) { 8331 viewRoot.getHandwritingInitiator().onDelegateViewFocused(this); 8332 } 8333 } 8334 } 8335 8336 invalidate(true); 8337 ListenerInfo li = mListenerInfo; 8338 if (li != null && li.mOnFocusChangeListener != null) { 8339 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 8340 } 8341 8342 if (mAttachInfo != null) { 8343 mAttachInfo.mKeyDispatchState.reset(this); 8344 } 8345 8346 if (mParent != null) { 8347 mParent.onDescendantUnbufferedRequested(); 8348 } 8349 8350 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 8351 updatePreferKeepClearForFocus(); 8352 } 8353 8354 /** 8355 * Notify {@link ImeFocusController} about the focus change of the {@link View}. 8356 * 8357 * @param hasFocus {@code true} when the {@link View} is being focused. 8358 */ 8359 private void notifyFocusChangeToImeFocusController(boolean hasFocus) { 8360 if (mAttachInfo == null) { 8361 return; 8362 } 8363 mAttachInfo.mViewRootImpl.getImeFocusController().onViewFocusChanged(this, hasFocus); 8364 } 8365 8366 /** @hide */ 8367 public void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 8368 if (canNotifyAutofillEnterExitEvent()) { 8369 AutofillManager afm = getAutofillManager(); 8370 if (afm != null) { 8371 if (enter) { 8372 // We have not been laid out yet, hence cannot evaluate 8373 // whether this view is visible to the user, we will do 8374 // the evaluation once layout is complete. 8375 // Sometimes, views are already laid out, but it's still 8376 // not visible to the user, we also do the evaluation once 8377 // the view is visible. ex: There is a fade-in animation 8378 // for the activity, the view will be laid out when the 8379 // animation beginning. On the time, the view is not visible 8380 // to the user. And then as the animation progresses, the view 8381 // becomes visible to the user. 8382 if (!isLaidOut() || !isVisibleToUser()) { 8383 mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 8384 } else if (isVisibleToUser()) { 8385 if (isFocused()) { 8386 // TODO This is a potential problem that View gets focus before it's 8387 // visible to User. Ideally View should handle the event when 8388 // isVisibleToUser() becomes true where it should issue 8389 // notifyViewEntered(). 8390 afm.notifyViewEntered(this); 8391 } else { 8392 afm.notifyViewEnteredForFillDialog(this); 8393 } 8394 } 8395 } else if (!isFocused()) { 8396 afm.notifyViewExited(this); 8397 } 8398 } 8399 } 8400 } 8401 8402 /** 8403 * Visually distinct portion of a window with window-like semantics are considered panes for 8404 * accessibility purposes. One example is the content view of a large fragment that is replaced. 8405 * In order for accessibility services to understand a pane's window-like behavior, panes 8406 * should have descriptive titles. Views with pane titles produce 8407 * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}s when they appear, disappear, or change 8408 * title. 8409 * 8410 * <p> 8411 * When transitioning from one Activity to another, instead of using 8412 * setAccessibilityPaneTitle(), set a descriptive title for its window by using android:label 8413 * for the matching <activity> entry in your application’s manifest or updating the title at 8414 * runtime with{@link android.app.Activity#setTitle(CharSequence)}. 8415 * 8416 * @param accessibilityPaneTitle The pane's title. Setting to {@code null} indicates that this 8417 * View is not a pane. 8418 * 8419 * {@see AccessibilityNodeInfo#setPaneTitle(CharSequence)} 8420 * 8421 * @attr ref android.R.styleable#View_accessibilityPaneTitle 8422 */ 8423 public void setAccessibilityPaneTitle(@Nullable CharSequence accessibilityPaneTitle) { 8424 if (!TextUtils.equals(accessibilityPaneTitle, mAccessibilityPaneTitle)) { 8425 boolean currentPaneTitleEmpty = mAccessibilityPaneTitle == null; 8426 boolean newPaneTitleEmpty = accessibilityPaneTitle == null; 8427 mAccessibilityPaneTitle = accessibilityPaneTitle; 8428 // Make explicitly important as nulled titles need to be important for DISAPPEARED 8429 // events. 8430 if (mAccessibilityPaneTitle != null 8431 && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 8432 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 8433 } 8434 if (currentPaneTitleEmpty) { 8435 notifyViewAccessibilityStateChangedIfNeeded( 8436 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED); 8437 } else if (newPaneTitleEmpty) { 8438 notifyViewAccessibilityStateChangedIfNeeded( 8439 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); 8440 } else { 8441 notifyViewAccessibilityStateChangedIfNeeded( 8442 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE); 8443 } 8444 } 8445 } 8446 8447 /** 8448 * Get the title of the pane for purposes of accessibility. 8449 * 8450 * @return The current pane title. 8451 * 8452 * {@see #setAccessibilityPaneTitle}. 8453 * 8454 * @attr ref android.R.styleable#View_accessibilityPaneTitle 8455 */ 8456 @InspectableProperty 8457 @Nullable 8458 public CharSequence getAccessibilityPaneTitle() { 8459 return mAccessibilityPaneTitle; 8460 } 8461 8462 private boolean isAccessibilityPane() { 8463 return mAccessibilityPaneTitle != null; 8464 } 8465 8466 /** 8467 * Sends an accessibility event of the given type. If accessibility is 8468 * not enabled this method has no effect. The default implementation calls 8469 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 8470 * to populate information about the event source (this View), then calls 8471 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 8472 * populate the text content of the event source including its descendants, 8473 * then for events type {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} 8474 * and {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} with 8475 * subtype {@link AccessibilityEvent#CONTENT_CHANGE_TYPE_STATE_DESCRIPTION}, 8476 * throttle the events, and last calls 8477 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 8478 * on its parent to request sending of the event to interested parties. 8479 * <p> 8480 * If an {@link AccessibilityDelegate} has been specified via calling 8481 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8482 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 8483 * responsible for handling this call. 8484 * </p> 8485 * <p> 8486 * If this view uses {@link AccessibilityNodeProvider} to provide virtual view hierarchy rooted 8487 * at this view, this method should not be called to send events from virtual children because 8488 * it will populate the events with wrong information and the events should be throttled per 8489 * child instead at the virtual root level. To send events from virtual children, call 8490 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} on the view's 8491 * parent to request sending of the event to interested parties. 8492 * </p> 8493 * 8494 * @param eventType The type of the event to send, as defined by several types from 8495 * {@link AccessibilityEvent}, such as 8496 * {@link AccessibilityEvent#TYPE_VIEW_CLICKED} or 8497 * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 8498 * 8499 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 8500 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8501 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 8502 * @see AccessibilityDelegate 8503 */ 8504 public void sendAccessibilityEvent(int eventType) { 8505 if (mAccessibilityDelegate != null) { 8506 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 8507 } else { 8508 sendAccessibilityEventInternal(eventType); 8509 } 8510 } 8511 8512 /** 8513 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 8514 * {@link AccessibilityEvent} to suggest that an accessibility service announce the 8515 * specified text to its users. 8516 * <p> 8517 * Note: The event generated with this API carries no semantic meaning, and is appropriate only 8518 * in exceptional situations. Apps can generally achieve correct behavior for accessibility by 8519 * accurately supplying the semantics of their UI. 8520 * They should not need to specify what exactly is announced to users. 8521 * 8522 * <p> 8523 * In general, only announce transitions and don’t generate a confirmation message for simple 8524 * actions like a button press. Label your controls concisely and precisely instead, and for 8525 * significant UI changes like window changes, use 8526 * {@link android.app.Activity#setTitle(CharSequence)} and 8527 * {@link View#setAccessibilityPaneTitle(CharSequence)}. 8528 * 8529 * <p> 8530 * Use {@link View#setAccessibilityLiveRegion(int)} to inform the user of changes to critical 8531 * views within the user interface. These should still be used sparingly as they may generate 8532 * announcements every time a View is updated. 8533 * 8534 * @param text The announcement text. 8535 */ 8536 public void announceForAccessibility(CharSequence text) { 8537 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 8538 AccessibilityEvent event = AccessibilityEvent.obtain( 8539 AccessibilityEvent.TYPE_ANNOUNCEMENT); 8540 onInitializeAccessibilityEvent(event); 8541 event.getText().add(text); 8542 event.setContentDescription(null); 8543 mParent.requestSendAccessibilityEvent(this, event); 8544 } 8545 } 8546 8547 /** 8548 * @see #sendAccessibilityEvent(int) 8549 * 8550 * Note: Called from the default {@link AccessibilityDelegate}. 8551 * 8552 * @hide 8553 */ 8554 public void sendAccessibilityEventInternal(int eventType) { 8555 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 8556 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 8557 } 8558 } 8559 8560 /** 8561 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 8562 * takes as an argument an empty {@link AccessibilityEvent} and does not 8563 * perform a check whether accessibility is enabled. 8564 * <p> 8565 * If an {@link AccessibilityDelegate} has been specified via calling 8566 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8567 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 8568 * is responsible for handling this call. 8569 * </p> 8570 * 8571 * @param event The event to send. 8572 * 8573 * @see #sendAccessibilityEvent(int) 8574 */ 8575 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 8576 if (mAccessibilityDelegate != null) { 8577 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 8578 } else { 8579 sendAccessibilityEventUncheckedInternal(event); 8580 } 8581 } 8582 8583 /** 8584 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 8585 * 8586 * Note: Called from the default {@link AccessibilityDelegate}. 8587 * 8588 * @hide 8589 */ 8590 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 8591 // Panes disappearing are relevant even if though the view is no longer visible. 8592 boolean isWindowStateChanged = 8593 (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 8594 boolean isWindowDisappearedEvent = isWindowStateChanged && ((event.getContentChangeTypes() 8595 & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) != 0); 8596 boolean detached = detached(); 8597 if (!isShown() && !isWindowDisappearedEvent && !detached) { 8598 return; 8599 } 8600 onInitializeAccessibilityEvent(event); 8601 // Only a subset of accessibility events populates text content. 8602 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 8603 dispatchPopulateAccessibilityEvent(event); 8604 } 8605 SendAccessibilityEventThrottle throttle = getThrottleForAccessibilityEvent(event); 8606 if (throttle != null) { 8607 throttle.post(event); 8608 } else if (!isWindowDisappearedEvent && detached) { 8609 // Views could be attached soon later. Accessibility events during this temporarily 8610 // detached period should be sent too. 8611 postDelayed(() -> { 8612 if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) { 8613 requestParentSendAccessibilityEvent(event); 8614 } 8615 }, ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 8616 } else { 8617 requestParentSendAccessibilityEvent(event); 8618 } 8619 } 8620 8621 private void requestParentSendAccessibilityEvent(AccessibilityEvent event) { 8622 ViewParent parent = getParent(); 8623 if (parent != null) { 8624 getParent().requestSendAccessibilityEvent(this, event); 8625 } 8626 } 8627 8628 private SendAccessibilityEventThrottle getThrottleForAccessibilityEvent( 8629 AccessibilityEvent event) { 8630 if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { 8631 if (mSendViewScrolledAccessibilityEvent == null) { 8632 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 8633 } 8634 return mSendViewScrolledAccessibilityEvent; 8635 } 8636 boolean isStateContentChanged = (event.getContentChangeTypes() 8637 & AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION) != 0; 8638 if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 8639 && isStateContentChanged) { 8640 if (mSendStateChangedAccessibilityEvent == null) { 8641 mSendStateChangedAccessibilityEvent = new SendAccessibilityEventThrottle(); 8642 } 8643 return mSendStateChangedAccessibilityEvent; 8644 } 8645 return null; 8646 } 8647 8648 private void clearAccessibilityThrottles() { 8649 cancel(mSendViewScrolledAccessibilityEvent); 8650 cancel(mSendStateChangedAccessibilityEvent); 8651 } 8652 8653 /** 8654 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 8655 * to its children for adding their text content to the event. Note that the 8656 * event text is populated in a separate dispatch path since we add to the 8657 * event not only the text of the source but also the text of all its descendants. 8658 * A typical implementation will call 8659 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 8660 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 8661 * on each child. Override this method if custom population of the event text 8662 * content is required. 8663 * <p> 8664 * If an {@link AccessibilityDelegate} has been specified via calling 8665 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8666 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 8667 * is responsible for handling this call. 8668 * </p> 8669 * <p> 8670 * If this view sets {@link #isAccessibilityDataSensitive()} then this view should only append 8671 * sensitive information to an event that also sets 8672 * {@link AccessibilityEvent#isAccessibilityDataSensitive()}. 8673 * </p> 8674 * <p> 8675 * <em>Note:</em> Accessibility events of certain types are not dispatched for 8676 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 8677 * </p> 8678 * 8679 * @param event The event. 8680 * 8681 * @return True if the event population was completed. 8682 */ 8683 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 8684 if (mAccessibilityDelegate != null) { 8685 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 8686 } else { 8687 return dispatchPopulateAccessibilityEventInternal(event); 8688 } 8689 } 8690 8691 /** 8692 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8693 * 8694 * Note: Called from the default {@link AccessibilityDelegate}. 8695 * 8696 * @hide 8697 */ 8698 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 8699 onPopulateAccessibilityEvent(event); 8700 return false; 8701 } 8702 8703 /** 8704 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 8705 * giving a chance to this View to populate the accessibility event with its 8706 * text content. While this method is free to modify event 8707 * attributes other than text content, doing so should normally be performed in 8708 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 8709 * <p> 8710 * Example: Adding formatted date string to an accessibility event in addition 8711 * to the text added by the super implementation: 8712 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 8713 * super.onPopulateAccessibilityEvent(event); 8714 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 8715 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 8716 * mCurrentDate.getTimeInMillis(), flags); 8717 * event.getText().add(selectedDateUtterance); 8718 * }</pre> 8719 * <p> 8720 * If an {@link AccessibilityDelegate} has been specified via calling 8721 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8722 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 8723 * is responsible for handling this call. 8724 * </p> 8725 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 8726 * information to the event, in case the default implementation has basic information to add. 8727 * </p> 8728 * 8729 * @param event The accessibility event which to populate. 8730 * 8731 * @see #sendAccessibilityEvent(int) 8732 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8733 */ 8734 @CallSuper 8735 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 8736 if (mAccessibilityDelegate != null) { 8737 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 8738 } else { 8739 onPopulateAccessibilityEventInternal(event); 8740 } 8741 } 8742 8743 /** 8744 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 8745 * 8746 * Note: Called from the default {@link AccessibilityDelegate}. 8747 * 8748 * @hide 8749 */ 8750 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 8751 if ((event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) 8752 && isAccessibilityPane()) { 8753 event.getText().add(getAccessibilityPaneTitle()); 8754 } 8755 } 8756 8757 /** 8758 * Initializes an {@link AccessibilityEvent} with information about 8759 * this View which is the event source. In other words, the source of 8760 * an accessibility event is the view whose state change triggered firing 8761 * the event. 8762 * <p> 8763 * Example: Setting the password property of an event in addition 8764 * to properties set by the super implementation: 8765 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 8766 * super.onInitializeAccessibilityEvent(event); 8767 * event.setPassword(true); 8768 * }</pre> 8769 * <p> 8770 * If an {@link AccessibilityDelegate} has been specified via calling 8771 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8772 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 8773 * is responsible for handling this call. 8774 * </p> 8775 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 8776 * information to the event, in case the default implementation has basic information to add. 8777 * </p> 8778 * @param event The event to initialize. 8779 * 8780 * @see #sendAccessibilityEvent(int) 8781 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8782 */ 8783 @CallSuper 8784 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 8785 if (mAccessibilityDelegate != null) { 8786 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 8787 } else { 8788 onInitializeAccessibilityEventInternal(event); 8789 } 8790 } 8791 8792 /** 8793 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 8794 * 8795 * Note: Called from the default {@link AccessibilityDelegate}. 8796 * 8797 * @hide 8798 */ 8799 @UnsupportedAppUsage 8800 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 8801 event.setSource(this); 8802 event.setClassName(getAccessibilityClassName()); 8803 event.setPackageName(getContext().getPackageName()); 8804 event.setEnabled(isEnabled()); 8805 event.setContentDescription(mContentDescription); 8806 event.setScrollX(getScrollX()); 8807 event.setScrollY(getScrollY()); 8808 8809 switch (event.getEventType()) { 8810 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 8811 ArrayList<View> focusablesTempList = (mAttachInfo != null) 8812 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 8813 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 8814 event.setItemCount(focusablesTempList.size()); 8815 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 8816 if (mAttachInfo != null) { 8817 focusablesTempList.clear(); 8818 } 8819 } break; 8820 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 8821 CharSequence text = getIterableTextForAccessibility(); 8822 if (text != null && text.length() > 0) { 8823 event.setFromIndex(getAccessibilitySelectionStart()); 8824 event.setToIndex(getAccessibilitySelectionEnd()); 8825 event.setItemCount(text.length()); 8826 } 8827 } break; 8828 } 8829 } 8830 8831 /** 8832 * Returns an {@link AccessibilityNodeInfo} representing this view from the 8833 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 8834 * This method is responsible for obtaining an accessibility node info from a 8835 * pool of reusable instances and calling 8836 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 8837 * initialize the former. 8838 * <p> 8839 * Note: The client is responsible for recycling the obtained instance by calling 8840 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 8841 * </p> 8842 * 8843 * @return A populated {@link AccessibilityNodeInfo}. 8844 * 8845 * @see AccessibilityNodeInfo 8846 */ 8847 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 8848 if (mAccessibilityDelegate != null) { 8849 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 8850 } else { 8851 return createAccessibilityNodeInfoInternal(); 8852 } 8853 } 8854 8855 /** 8856 * @see #createAccessibilityNodeInfo() 8857 * 8858 * @hide 8859 */ 8860 public @Nullable AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 8861 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8862 if (provider != null) { 8863 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 8864 } else { 8865 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 8866 onInitializeAccessibilityNodeInfo(info); 8867 return info; 8868 } 8869 } 8870 8871 /** 8872 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 8873 * The base implementation sets: 8874 * <ul> 8875 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 8876 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 8877 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 8878 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 8879 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 8880 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 8881 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 8882 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 8883 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 8884 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 8885 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 8886 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 8887 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 8888 * </ul> 8889 * <p> 8890 * Subclasses should override this method, call the super implementation, 8891 * and set additional attributes. 8892 * </p> 8893 * <p> 8894 * If an {@link AccessibilityDelegate} has been specified via calling 8895 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8896 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 8897 * is responsible for handling this call. 8898 * </p> 8899 * 8900 * @param info The instance to initialize. 8901 */ 8902 @CallSuper 8903 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 8904 if (mAccessibilityDelegate != null) { 8905 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 8906 } else { 8907 onInitializeAccessibilityNodeInfoInternal(info); 8908 } 8909 } 8910 8911 /** 8912 * Gets the location of this view in screen coordinates. 8913 * 8914 * @param outRect The output location 8915 * @hide 8916 */ 8917 @UnsupportedAppUsage 8918 public void getBoundsOnScreen(Rect outRect) { 8919 getBoundsOnScreen(outRect, false); 8920 } 8921 8922 /** 8923 * Gets the location of this view in screen coordinates. 8924 * 8925 * @param outRect The output location 8926 * @param clipToParent Whether to clip child bounds to the parent ones. 8927 * @hide 8928 */ 8929 @UnsupportedAppUsage 8930 @TestApi 8931 public void getBoundsOnScreen(@NonNull Rect outRect, boolean clipToParent) { 8932 if (mAttachInfo == null) { 8933 return; 8934 } 8935 RectF position = mAttachInfo.mTmpTransformRect; 8936 getBoundsToScreenInternal(position, clipToParent); 8937 outRect.set(Math.round(position.left), Math.round(position.top), 8938 Math.round(position.right), Math.round(position.bottom)); 8939 // If "Sandboxing View Bounds APIs" override is enabled, applyViewBoundsSandboxingIfNeeded 8940 // will sandbox outRect within window bounds. 8941 mAttachInfo.mViewRootImpl.applyViewBoundsSandboxingIfNeeded(outRect); 8942 } 8943 8944 /** 8945 * Gets the location of this view in screen coordinates. 8946 * 8947 * @param outRect The output location 8948 * @param clipToParent Whether to clip child bounds to the parent ones. 8949 * @hide 8950 */ 8951 public void getBoundsOnScreen(RectF outRect, boolean clipToParent) { 8952 if (mAttachInfo == null) { 8953 return; 8954 } 8955 RectF position = mAttachInfo.mTmpTransformRect; 8956 getBoundsToScreenInternal(position, clipToParent); 8957 outRect.set(position.left, position.top, position.right, position.bottom); 8958 } 8959 8960 /** 8961 * Gets the location of this view in window coordinates. 8962 * 8963 * @param outRect The output location 8964 * @param clipToParent Whether to clip child bounds to the parent ones. 8965 * @hide 8966 */ 8967 public void getBoundsInWindow(Rect outRect, boolean clipToParent) { 8968 if (mAttachInfo == null) { 8969 return; 8970 } 8971 RectF position = mAttachInfo.mTmpTransformRect; 8972 getBoundsToWindowInternal(position, clipToParent); 8973 outRect.set(Math.round(position.left), Math.round(position.top), 8974 Math.round(position.right), Math.round(position.bottom)); 8975 } 8976 8977 private void getBoundsToScreenInternal(RectF position, boolean clipToParent) { 8978 position.set(0, 0, mRight - mLeft, mBottom - mTop); 8979 mapRectFromViewToScreenCoords(position, clipToParent); 8980 } 8981 8982 private void getBoundsToWindowInternal(RectF position, boolean clipToParent) { 8983 position.set(0, 0, mRight - mLeft, mBottom - mTop); 8984 mapRectFromViewToWindowCoords(position, clipToParent); 8985 } 8986 8987 /** 8988 * Map a rectangle from view-relative coordinates to screen-relative coordinates 8989 * 8990 * @param rect The rectangle to be mapped 8991 * @param clipToParent Whether to clip child bounds to the parent ones. 8992 * @hide 8993 */ 8994 public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { 8995 mapRectFromViewToWindowCoords(rect, clipToParent); 8996 rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 8997 } 8998 8999 /** 9000 * Map a rectangle from view-relative coordinates to window-relative coordinates 9001 * 9002 * @param rect The rectangle to be mapped 9003 * @param clipToParent Whether to clip child bounds to the parent ones. 9004 * @hide 9005 */ 9006 public void mapRectFromViewToWindowCoords(RectF rect, boolean clipToParent) { 9007 if (!hasIdentityMatrix()) { 9008 getMatrix().mapRect(rect); 9009 } 9010 9011 rect.offset(mLeft, mTop); 9012 9013 ViewParent parent = mParent; 9014 while (parent instanceof View) { 9015 View parentView = (View) parent; 9016 9017 rect.offset(-parentView.mScrollX, -parentView.mScrollY); 9018 9019 if (clipToParent) { 9020 rect.left = Math.max(rect.left, 0); 9021 rect.top = Math.max(rect.top, 0); 9022 rect.right = Math.min(rect.right, parentView.getWidth()); 9023 rect.bottom = Math.min(rect.bottom, parentView.getHeight()); 9024 } 9025 9026 if (!parentView.hasIdentityMatrix()) { 9027 parentView.getMatrix().mapRect(rect); 9028 } 9029 9030 rect.offset(parentView.mLeft, parentView.mTop); 9031 9032 parent = parentView.mParent; 9033 } 9034 9035 if (parent instanceof ViewRootImpl) { 9036 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 9037 rect.offset(0, -viewRootImpl.mCurScrollY); 9038 } 9039 } 9040 9041 /** 9042 * Return the class name of this object to be used for accessibility purposes. 9043 * Subclasses should only override this if they are implementing something that 9044 * should be seen as a completely new class of view when used by accessibility, 9045 * unrelated to the class it is deriving from. This is used to fill in 9046 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 9047 */ 9048 public CharSequence getAccessibilityClassName() { 9049 return View.class.getName(); 9050 } 9051 9052 /** 9053 * Called when assist structure is being retrieved from a view as part of 9054 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 9055 * @param structure Fill in with structured view data. The default implementation 9056 * fills in all data that can be inferred from the view itself. 9057 */ 9058 public void onProvideStructure(ViewStructure structure) { 9059 onProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 9060 } 9061 9062 /** 9063 * Populates a {@link ViewStructure} to fullfil an autofill request. 9064 * 9065 * <p>The structure should contain at least the following properties: 9066 * <ul> 9067 * <li>Autofill id ({@link ViewStructure#setAutofillId(AutofillId, int)}). 9068 * <li>Autofill type ({@link ViewStructure#setAutofillType(int)}). 9069 * <li>Autofill value ({@link ViewStructure#setAutofillValue(AutofillValue)}). 9070 * <li>Whether the data is sensitive ({@link ViewStructure#setDataIsSensitive(boolean)}). 9071 * </ul> 9072 * 9073 * <p>It's also recommended to set the following properties - the more properties the structure 9074 * has, the higher the chances of an {@link android.service.autofill.AutofillService} properly 9075 * using the structure: 9076 * 9077 * <ul> 9078 * <li>Autofill hints ({@link ViewStructure#setAutofillHints(String[])}). 9079 * <li>Autofill options ({@link ViewStructure#setAutofillOptions(CharSequence[])}) when the 9080 * view can only be filled with predefined values (typically used when the autofill type 9081 * is {@link #AUTOFILL_TYPE_LIST}). 9082 * <li>Resource id ({@link ViewStructure#setId(int, String, String, String)}). 9083 * <li>Class name ({@link ViewStructure#setClassName(String)}). 9084 * <li>Content description ({@link ViewStructure#setContentDescription(CharSequence)}). 9085 * <li>Visual properties such as visibility ({@link ViewStructure#setVisibility(int)}), 9086 * dimensions ({@link ViewStructure#setDimens(int, int, int, int, int, int)}), and 9087 * opacity ({@link ViewStructure#setOpaque(boolean)}). 9088 * <li>For views representing text fields, text properties such as the text itself 9089 * ({@link ViewStructure#setText(CharSequence)}), text hints 9090 * ({@link ViewStructure#setHint(CharSequence)}, input type 9091 * ({@link ViewStructure#setInputType(int)}), 9092 * <li>For views representing HTML nodes, its web domain 9093 * ({@link ViewStructure#setWebDomain(String)}) and HTML properties 9094 * (({@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}). 9095 * </ul> 9096 * 9097 * <p>The default implementation of this method already sets most of these properties based on 9098 * related {@link View} methods (for example, the autofill id is set using 9099 * {@link #getAutofillId()}, the autofill type set using {@link #getAutofillType()}, etc.), 9100 * and views in the standard Android widgets library also override it to set their 9101 * relevant properties (for example, {@link android.widget.TextView} already sets the text 9102 * properties), so it's recommended to only override this method 9103 * (and call {@code super.onProvideAutofillStructure()}) when: 9104 * 9105 * <ul> 9106 * <li>The view contents does not include PII (Personally Identifiable Information), so it 9107 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 9108 * <li>The view can only be autofilled with predefined options, so it can call 9109 * {@link ViewStructure#setAutofillOptions(CharSequence[])}. 9110 * </ul> 9111 * 9112 * <p><b>Note:</b> The {@code left} and {@code top} values set in 9113 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the next 9114 * {@link ViewGroup#isImportantForAutofill()} predecessor view included in the structure. 9115 * 9116 * <p>Views support the Autofill Framework mainly by: 9117 * <ul> 9118 * <li>Providing the metadata defining what the view means and how it can be autofilled. 9119 * <li>Notifying the Android System when the view value changed by calling 9120 * {@link AutofillManager#notifyValueChanged(View)}. 9121 * <li>Implementing the methods that autofill the view. 9122 * </ul> 9123 * <p>This method is responsible for the former; {@link #autofill(AutofillValue)} is responsible 9124 * for the latter. 9125 * 9126 * @param structure fill in with structured view data for autofill purposes. 9127 * @param flags optional flags. 9128 * 9129 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 9130 */ 9131 public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) { 9132 onProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 9133 } 9134 9135 /** 9136 * Populates a {@link ViewStructure} for content capture. 9137 * 9138 * <p>This method is called after a view that is eligible for content capture 9139 * (for example, if it {@link #isImportantForContentCapture()}, an intelligence service is 9140 * enabled for the user, and the activity rendering the view is enabled for content capture) 9141 * is laid out and is visible. The populated structure is then passed to the service through 9142 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}. 9143 * 9144 * <p>The default implementation of this method sets the most relevant properties based on 9145 * related {@link View} methods, and views in the standard Android widgets library also 9146 * override it to set their relevant properties. Therefore, if overriding this method, it 9147 * is recommended to call {@code super.onProvideContentCaptureStructure()}. 9148 * 9149 * <p><b>Note: </b>views that manage a virtual structure under this view must populate just 9150 * the node representing this view and return right away, then asynchronously report (not 9151 * necessarily in the UI thread) when the children nodes appear, disappear or have their text 9152 * changed by calling 9153 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}, 9154 * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and 9155 * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence)} 9156 * respectively. The structure for a child must be created using 9157 * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, long)}, and the 9158 * {@code autofillId} for a child can be obtained either through 9159 * {@code childStructure.getAutofillId()} or 9160 * {@link ContentCaptureSession#newAutofillId(AutofillId, long)}. 9161 * 9162 * <p>When the virtual view hierarchy represents a web page, you should also: 9163 * 9164 * <ul> 9165 * <li>Call {@link ContentCaptureManager#getContentCaptureConditions()} to infer content 9166 * capture events should be generate for that URL. 9167 * <li>Create a new {@link ContentCaptureSession} child for every HTML element that 9168 * renders a new URL (like an {@code IFRAME}) and use that session to notify events from 9169 * that subtree. 9170 * </ul> 9171 * 9172 * <p><b>Note: </b>the following methods of the {@code structure} will be ignored: 9173 * <ul> 9174 * <li>{@link ViewStructure#setChildCount(int)} 9175 * <li>{@link ViewStructure#addChildCount(int)} 9176 * <li>{@link ViewStructure#getChildCount()} 9177 * <li>{@link ViewStructure#newChild(int)} 9178 * <li>{@link ViewStructure#asyncNewChild(int)} 9179 * <li>{@link ViewStructure#asyncCommit()} 9180 * <li>{@link ViewStructure#setWebDomain(String)} 9181 * <li>{@link ViewStructure#newHtmlInfoBuilder(String)} 9182 * <li>{@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)} 9183 * <li>{@link ViewStructure#setDataIsSensitive(boolean)} 9184 * <li>{@link ViewStructure#setAlpha(float)} 9185 * <li>{@link ViewStructure#setElevation(float)} 9186 * <li>{@link ViewStructure#setTransformation(Matrix)} 9187 * 9188 * </ul> 9189 */ 9190 public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) { 9191 onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags); 9192 } 9193 9194 /** @hide */ 9195 protected void onProvideStructure(@NonNull ViewStructure structure, 9196 @ViewStructureType int viewFor, int flags) { 9197 final int id = mID; 9198 if (id != NO_ID && !isViewIdGenerated(id)) { 9199 String pkg, type, entry; 9200 try { 9201 final Resources res = getResources(); 9202 entry = res.getResourceEntryName(id); 9203 type = res.getResourceTypeName(id); 9204 pkg = res.getResourcePackageName(id); 9205 } catch (Resources.NotFoundException e) { 9206 entry = type = pkg = null; 9207 } 9208 structure.setId(id, pkg, type, entry); 9209 } else { 9210 structure.setId(id, null, null, null); 9211 } 9212 9213 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 9214 || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { 9215 final @AutofillType int autofillType = getAutofillType(); 9216 // Don't need to fill autofill info if view does not support it. 9217 // For example, only TextViews that are editable support autofill 9218 if (autofillType != AUTOFILL_TYPE_NONE) { 9219 structure.setAutofillType(autofillType); 9220 structure.setAutofillHints(getAutofillHints()); 9221 structure.setAutofillValue(getAutofillValue()); 9222 } 9223 structure.setImportantForAutofill(getImportantForAutofill()); 9224 structure.setReceiveContentMimeTypes(getReceiveContentMimeTypes()); 9225 } 9226 9227 int ignoredParentLeft = 0; 9228 int ignoredParentTop = 0; 9229 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 9230 && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 9231 View parentGroup = null; 9232 9233 ViewParent viewParent = getParent(); 9234 if (viewParent instanceof View) { 9235 parentGroup = (View) viewParent; 9236 } 9237 9238 while (parentGroup != null && !parentGroup.isImportantForAutofill()) { 9239 ignoredParentLeft += parentGroup.mLeft - parentGroup.mScrollX; 9240 ignoredParentTop += parentGroup.mTop - parentGroup.mScrollY; 9241 9242 viewParent = parentGroup.getParent(); 9243 if (viewParent instanceof View) { 9244 parentGroup = (View) viewParent; 9245 } else { 9246 break; 9247 } 9248 } 9249 } 9250 9251 structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY, 9252 mRight - mLeft, mBottom - mTop); 9253 if (viewFor == VIEW_STRUCTURE_FOR_ASSIST) { 9254 if (!hasIdentityMatrix()) { 9255 structure.setTransformation(getMatrix()); 9256 } 9257 structure.setElevation(getZ()); 9258 } 9259 structure.setVisibility(getVisibility()); 9260 structure.setEnabled(isEnabled()); 9261 if (isClickable()) { 9262 structure.setClickable(true); 9263 } 9264 if (isFocusable()) { 9265 structure.setFocusable(true); 9266 } 9267 if (isFocused()) { 9268 structure.setFocused(true); 9269 } 9270 if (isAccessibilityFocused()) { 9271 structure.setAccessibilityFocused(true); 9272 } 9273 if (isSelected()) { 9274 structure.setSelected(true); 9275 } 9276 if (isActivated()) { 9277 structure.setActivated(true); 9278 } 9279 if (isLongClickable()) { 9280 structure.setLongClickable(true); 9281 } 9282 if (this instanceof Checkable) { 9283 structure.setCheckable(true); 9284 if (((Checkable)this).isChecked()) { 9285 structure.setChecked(true); 9286 } 9287 } 9288 if (isOpaque()) { 9289 structure.setOpaque(true); 9290 } 9291 if (isContextClickable()) { 9292 structure.setContextClickable(true); 9293 } 9294 structure.setClassName(getAccessibilityClassName().toString()); 9295 structure.setContentDescription(getContentDescription()); 9296 } 9297 9298 /** 9299 * Called when assist structure is being retrieved from a view as part of 9300 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 9301 * generate additional virtual structure under this view. The default implementation 9302 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 9303 * view's virtual accessibility nodes, if any. You can override this for a more 9304 * optimal implementation providing this data. 9305 */ 9306 public void onProvideVirtualStructure(ViewStructure structure) { 9307 onProvideVirtualStructureCompat(structure, false); 9308 } 9309 9310 /** 9311 * Fallback implementation to populate a ViewStructure from accessibility state. 9312 * 9313 * @param structure The structure to populate. 9314 * @param forAutofill Whether the structure is needed for autofill. 9315 */ 9316 private void onProvideVirtualStructureCompat(ViewStructure structure, boolean forAutofill) { 9317 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 9318 if (provider != null) { 9319 if (forAutofill && Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9320 Log.v(AUTOFILL_LOG_TAG, "onProvideVirtualStructureCompat() for " + this); 9321 } 9322 final AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 9323 structure.setChildCount(1); 9324 final ViewStructure root = structure.newChild(0); 9325 populateVirtualStructure(root, provider, info, forAutofill); 9326 info.recycle(); 9327 } 9328 } 9329 9330 /** 9331 * Populates a {@link ViewStructure} containing virtual children to fullfil an autofill 9332 * request. 9333 * 9334 * <p>This method should be used when the view manages a virtual structure under this view. For 9335 * example, a view that draws input fields using {@link #draw(Canvas)}. 9336 * 9337 * <p>When implementing this method, subclasses must follow the rules below: 9338 * 9339 * <ul> 9340 * <li>Add virtual children by calling the {@link ViewStructure#newChild(int)} or 9341 * {@link ViewStructure#asyncNewChild(int)} methods, where the {@code id} is an unique id 9342 * identifying the children in the virtual structure. 9343 * <li>The children hierarchy can have multiple levels if necessary, but ideally it should 9344 * exclude intermediate levels that are irrelevant for autofill; that would improve the 9345 * autofill performance. 9346 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual 9347 * children. 9348 * <li>Set the autofill properties of the child structure as defined by 9349 * {@link #onProvideAutofillStructure(ViewStructure, int)}, using 9350 * {@link ViewStructure#setAutofillId(AutofillId, int)} to set its autofill id. 9351 * <li>Call {@link android.view.autofill.AutofillManager#notifyViewEntered(View, int, Rect)} 9352 * and/or {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} 9353 * when the focused virtual child changed. 9354 * <li>Override {@link #isVisibleToUserForAutofill(int)} to allow the platform to query 9355 * whether a given virtual view is visible to the user in order to support triggering 9356 * save when all views of interest go away. 9357 * <li>Call 9358 * {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, AutofillValue)} 9359 * when the value of a virtual child changed. 9360 * <li>Call {@link 9361 * android.view.autofill.AutofillManager#notifyViewVisibilityChanged(View, int, boolean)} 9362 * when the visibility of a virtual child changed. 9363 * <li>Call 9364 * {@link android.view.autofill.AutofillManager#notifyViewClicked(View, int)} when a virtual 9365 * child is clicked. 9366 * <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure 9367 * changed and the current context should be committed (for example, when the user tapped 9368 * a {@code SUBMIT} button in an HTML page). 9369 * <li>Call {@link AutofillManager#cancel()} when the autofill context of the view structure 9370 * changed and the current context should be canceled (for example, when the user tapped 9371 * a {@code CANCEL} button in an HTML page). 9372 * <li>Provide ways for users to manually request autofill by calling 9373 * {@link AutofillManager#requestAutofill(View, int, Rect)}. 9374 * <li>The {@code left} and {@code top} values set in 9375 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the 9376 * next {@link ViewGroup#isImportantForAutofill()} predecessor view included in the 9377 * structure. 9378 * </ul> 9379 * 9380 * <p>Views with virtual children support the Autofill Framework mainly by: 9381 * <ul> 9382 * <li>Providing the metadata defining what the virtual children mean and how they can be 9383 * autofilled. 9384 * <li>Implementing the methods that autofill the virtual children. 9385 * </ul> 9386 * <p>This method is responsible for the former; {@link #autofill(SparseArray)} is responsible 9387 * for the latter. 9388 * 9389 * @param structure fill in with virtual children data for autofill purposes. 9390 * @param flags optional flags. 9391 * 9392 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 9393 */ 9394 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 9395 if (mContext.isAutofillCompatibilityEnabled()) { 9396 onProvideVirtualStructureCompat(structure, true); 9397 } 9398 } 9399 9400 /** 9401 * Sets the listener to be {@link #performReceiveContent used} to handle insertion of 9402 * content into this view. 9403 * 9404 * <p>Depending on the type of view, this listener may be invoked for different scenarios. For 9405 * example, for an editable {@link android.widget.TextView}, this listener will be invoked for 9406 * the following scenarios: 9407 * <ol> 9408 * <li>Paste from the clipboard (e.g. "Paste" or "Paste as plain text" action in the 9409 * insertion/selection menu) 9410 * <li>Content insertion from the keyboard (from {@link InputConnection#commitContent}) 9411 * <li>Drag and drop (drop events from {@link #onDragEvent}) 9412 * <li>Autofill 9413 * <li>Selection replacement via {@link Intent#ACTION_PROCESS_TEXT} 9414 * </ol> 9415 * 9416 * <p>When setting a listener, clients must also declare the accepted MIME types. 9417 * The listener will still be invoked even if the MIME type of the content is not one of the 9418 * declared MIME types (e.g. if the user pastes content whose type is not one of the declared 9419 * MIME types). 9420 * In that case, the listener may reject the content (defer to the default platform behavior) 9421 * or execute some other fallback logic (e.g. show an appropriate message to the user). 9422 * The declared MIME types serve as a hint to allow different features to optionally alter 9423 * their behavior. For example, a soft keyboard may optionally choose to hide its UI for 9424 * inserting GIFs for a particular input field if the MIME types set here for that field 9425 * don't include "image/gif" or "image/*". 9426 * 9427 * <p>Note: MIME type matching in the Android framework is case-sensitive, unlike formal RFC 9428 * MIME types. As a result, you should always write your MIME types with lowercase letters, 9429 * or use {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to 9430 * lowercase. 9431 * 9432 * @param mimeTypes The MIME types accepted by the given listener. These may use patterns 9433 * such as "image/*", but may not start with a wildcard. This argument must 9434 * not be null or empty if a non-null listener is passed in. 9435 * @param listener The listener to use. This can be null to reset to the default behavior. 9436 */ 9437 public void setOnReceiveContentListener( 9438 @SuppressLint("NullableCollection") @Nullable String[] mimeTypes, 9439 @Nullable OnReceiveContentListener listener) { 9440 if (listener != null) { 9441 Preconditions.checkArgument(mimeTypes != null && mimeTypes.length > 0, 9442 "When the listener is set, MIME types must also be set"); 9443 } 9444 if (mimeTypes != null) { 9445 Preconditions.checkArgument(Arrays.stream(mimeTypes).noneMatch(t -> t.startsWith("*")), 9446 "A MIME type set here must not start with *: " + Arrays.toString(mimeTypes)); 9447 } 9448 mReceiveContentMimeTypes = ArrayUtils.isEmpty(mimeTypes) ? null : mimeTypes; 9449 getListenerInfo().mOnReceiveContentListener = listener; 9450 } 9451 9452 /** 9453 * Receives the given content. If no listener is set, invokes {@link #onReceiveContent}. If a 9454 * listener is {@link #setOnReceiveContentListener set}, invokes the listener instead; if the 9455 * listener returns a non-null result, invokes {@link #onReceiveContent} to handle it. 9456 * 9457 * @param payload The content to insert and related metadata. 9458 * 9459 * @return The portion of the passed-in content that was not accepted (may be all, some, or none 9460 * of the passed-in content). 9461 */ 9462 @Nullable performReceiveContent(@onNull ContentInfo payload)9463 public ContentInfo performReceiveContent(@NonNull ContentInfo payload) { 9464 final OnReceiveContentListener listener = (mListenerInfo == null) ? null 9465 : getListenerInfo().mOnReceiveContentListener; 9466 if (listener != null) { 9467 final ContentInfo remaining = listener.onReceiveContent(this, payload); 9468 return (remaining == null) ? null : onReceiveContent(remaining); 9469 } 9470 return onReceiveContent(payload); 9471 } 9472 9473 /** 9474 * Implements the default behavior for receiving content for this type of view. The default 9475 * view implementation is a no-op (returns the passed-in content without acting on it). 9476 * 9477 * <p>Widgets should override this method to define their default behavior for receiving 9478 * content. Apps should {@link #setOnReceiveContentListener set a listener} to provide 9479 * app-specific handling for receiving content. 9480 * 9481 * <p>See {@link #setOnReceiveContentListener} and {@link #performReceiveContent} for more info. 9482 * 9483 * @param payload The content to insert and related metadata. 9484 * 9485 * @return The portion of the passed-in content that was not handled (may be all, some, or none 9486 * of the passed-in content). 9487 */ 9488 @Nullable onReceiveContent(@onNull ContentInfo payload)9489 public ContentInfo onReceiveContent(@NonNull ContentInfo payload) { 9490 return payload; 9491 } 9492 9493 /** 9494 * Returns the MIME types accepted by {@link #performReceiveContent} for this view, as 9495 * configured via {@link #setOnReceiveContentListener}. By default returns null. 9496 * 9497 * <p>Different features (e.g. pasting from the clipboard, inserting stickers from the soft 9498 * keyboard, etc) may optionally use this metadata to conditionally alter their behavior. For 9499 * example, a soft keyboard may choose to hide its UI for inserting GIFs for a particular 9500 * input field if the MIME types returned here for that field don't include "image/gif" or 9501 * "image/*". 9502 * 9503 * <p>Note: Comparisons of MIME types should be performed using utilities such as 9504 * {@link ClipDescription#compareMimeTypes} rather than simple string equality, in order to 9505 * correctly handle patterns such as "text/*", "image/*", etc. Note that MIME type matching 9506 * in the Android framework is case-sensitive, unlike formal RFC MIME types. As a result, 9507 * you should always write your MIME types with lowercase letters, or use 9508 * {@link android.content.Intent#normalizeMimeType} to ensure that it is converted to 9509 * lowercase. 9510 * 9511 * @return The MIME types accepted by {@link #performReceiveContent} for this view (may 9512 * include patterns such as "image/*"). 9513 */ 9514 @SuppressLint("NullableCollection") 9515 @Nullable getReceiveContentMimeTypes()9516 public String[] getReceiveContentMimeTypes() { 9517 return mReceiveContentMimeTypes; 9518 } 9519 9520 /** 9521 * Automatically fills the content of this view with the {@code value}. 9522 * 9523 * <p>Views support the Autofill Framework mainly by: 9524 * <ul> 9525 * <li>Providing the metadata defining what the view means and how it can be autofilled. 9526 * <li>Implementing the methods that autofill the view. 9527 * </ul> 9528 * <p>{@link #onProvideAutofillStructure(ViewStructure, int)} is responsible for the former, 9529 * this method is responsible for latter. 9530 * 9531 * <p>This method does nothing by default, but when overridden it typically: 9532 * <ol> 9533 * <li>Checks if the provided value matches the expected type (which is defined by 9534 * {@link #getAutofillType()}). 9535 * <li>Checks if the view is editable - if it isn't, it should return right away. 9536 * <li>Call the proper getter method on {@link AutofillValue} to fetch the actual value. 9537 * <li>Pass the actual value to the equivalent setter in the view. 9538 * </ol> 9539 * 9540 * <p>For example, a text-field view could implement the method this way: 9541 * 9542 * <pre class="prettyprint"> 9543 * @Override 9544 * public void autofill(AutofillValue value) { 9545 * if (!value.isText() || !this.isEditable()) { 9546 * return; 9547 * } 9548 * CharSequence text = value.getTextValue(); 9549 * if (text != null) { 9550 * this.setText(text); 9551 * } 9552 * } 9553 * </pre> 9554 * 9555 * <p>If the value is updated asynchronously, the next call to 9556 * {@link AutofillManager#notifyValueChanged(View)} must happen <b>after</b> the value was 9557 * changed to the autofilled value. If not, the view will not be considered autofilled. 9558 * 9559 * <p><b>Note:</b> After this method is called, the value returned by 9560 * {@link #getAutofillValue()} must be equal to the {@code value} passed to it, otherwise the 9561 * view will not be highlighted as autofilled. 9562 * 9563 * @param value value to be autofilled. 9564 */ autofill(@uppressWarningsR) AutofillValue value)9565 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 9566 } 9567 9568 /** 9569 * Automatically fills the content of the virtual children within this view. 9570 * 9571 * <p>Views with virtual children support the Autofill Framework mainly by: 9572 * <ul> 9573 * <li>Providing the metadata defining what the virtual children mean and how they can be 9574 * autofilled. 9575 * <li>Implementing the methods that autofill the virtual children. 9576 * </ul> 9577 * <p>{@link #onProvideAutofillVirtualStructure(ViewStructure, int)} is responsible for the 9578 * former, this method is responsible for the latter - see {@link #autofill(AutofillValue)} and 9579 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info about autofill. 9580 * 9581 * <p>If a child value is updated asynchronously, the next call to 9582 * {@link AutofillManager#notifyValueChanged(View, int, AutofillValue)} must happen 9583 * <b>after</b> the value was changed to the autofilled value. If not, the child will not be 9584 * considered autofilled. 9585 * 9586 * <p><b>Note:</b> To indicate that a virtual view was autofilled, 9587 * <code>?android:attr/autofilledHighlight</code> should be drawn over it until the data 9588 * changes. 9589 * 9590 * @param values map of values to be autofilled, keyed by virtual child id. 9591 * 9592 * @attr ref android.R.styleable#Theme_autofilledHighlight 9593 */ autofill(@onNull @uppressWarningsR) SparseArray<AutofillValue> values)9594 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { 9595 if (!mContext.isAutofillCompatibilityEnabled()) { 9596 return; 9597 } 9598 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 9599 if (provider == null) { 9600 return; 9601 } 9602 final int valueCount = values.size(); 9603 for (int i = 0; i < valueCount; i++) { 9604 final AutofillValue value = values.valueAt(i); 9605 if (value.isText()) { 9606 final int virtualId = values.keyAt(i); 9607 final CharSequence text = value.getTextValue(); 9608 final Bundle arguments = new Bundle(); 9609 arguments.putCharSequence( 9610 AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text); 9611 provider.performAction(virtualId, AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); 9612 } 9613 } 9614 } 9615 9616 /** 9617 * Gets the unique, logical identifier of this view in the activity, for autofill purposes. 9618 * 9619 * <p>The autofill id is created on demand, unless it is explicitly set by 9620 * {@link #setAutofillId(AutofillId)}. 9621 * 9622 * <p>See {@link #setAutofillId(AutofillId)} for more info. 9623 * 9624 * @return The View's autofill id. 9625 */ getAutofillId()9626 public final AutofillId getAutofillId() { 9627 if (mAutofillId == null) { 9628 // The autofill id needs to be unique, but its value doesn't matter, 9629 // so it's better to reuse the accessibility id to save space. 9630 mAutofillId = new AutofillId(getAutofillViewId()); 9631 } 9632 return mAutofillId; 9633 } 9634 9635 /** 9636 * Sets the unique, logical identifier of this view in the activity, for autofill purposes. 9637 * 9638 * <p>The autofill id is created on demand, and this method should only be called when a view is 9639 * reused after {@link #dispatchProvideAutofillStructure(ViewStructure, int)} is called, as 9640 * that method creates a snapshot of the view that is passed along to the autofill service. 9641 * 9642 * <p>This method is typically used when view subtrees are recycled to represent different 9643 * content* —in this case, the autofill id can be saved before the view content is swapped 9644 * out, and restored later when it's swapped back in. For example: 9645 * 9646 * <pre> 9647 * EditText reusableView = ...; 9648 * ViewGroup parentView = ...; 9649 * AutofillManager afm = ...; 9650 * 9651 * // Swap out the view and change its contents 9652 * AutofillId oldId = reusableView.getAutofillId(); 9653 * CharSequence oldText = reusableView.getText(); 9654 * parentView.removeView(reusableView); 9655 * AutofillId newId = afm.getNextAutofillId(); 9656 * reusableView.setText("New I am"); 9657 * reusableView.setAutofillId(newId); 9658 * parentView.addView(reusableView); 9659 * 9660 * // Later, swap the old content back in 9661 * parentView.removeView(reusableView); 9662 * reusableView.setAutofillId(oldId); 9663 * reusableView.setText(oldText); 9664 * parentView.addView(reusableView); 9665 * </pre> 9666 * 9667 * <p>NOTE: If this view is a descendant of an {@link android.widget.AdapterView}, the system 9668 * may reset its autofill id when this view is recycled. If the autofill ids need to be stable, 9669 * they should be set again in 9670 * {@link android.widget.Adapter#getView(int, android.view.View, android.view.ViewGroup)}. 9671 * 9672 * @param id an autofill ID that is unique in the {@link android.app.Activity} hosting the view, 9673 * or {@code null} to reset it. Usually it's an id previously allocated to another view (and 9674 * obtained through {@link #getAutofillId()}), or a new value obtained through 9675 * {@link AutofillManager#getNextAutofillId()}. 9676 * 9677 * @throws IllegalStateException if the view is already {@link #isAttachedToWindow() attached to 9678 * a window}. 9679 * 9680 * @throws IllegalArgumentException if the id is an autofill id associated with a virtual view. 9681 */ setAutofillId(@ullable AutofillId id)9682 public void setAutofillId(@Nullable AutofillId id) { 9683 // TODO(b/37566627): add unit / CTS test for all possible combinations below 9684 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9685 Log.v(AUTOFILL_LOG_TAG, "setAutofill(): from " + mAutofillId + " to " + id); 9686 } 9687 if (isAttachedToWindow()) { 9688 throw new IllegalStateException("Cannot set autofill id when view is attached"); 9689 } 9690 if (id != null && !id.isNonVirtual()) { 9691 throw new IllegalStateException("Cannot set autofill id assigned to virtual views"); 9692 } 9693 if (id == null && (mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) == 0) { 9694 // Ignore reset because it was never explicitly set before. 9695 return; 9696 } 9697 mAutofillId = id; 9698 if (id != null) { 9699 mAutofillViewId = id.getViewId(); 9700 mPrivateFlags3 |= PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9701 } else { 9702 mAutofillViewId = NO_ID; 9703 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9704 } 9705 } 9706 9707 /** 9708 * Forces a reset of the autofill ids of the subtree rooted at this view. Like calling 9709 * {@link #setAutofillId(AutofillId) setAutofillId(null)} for each view, but works even if the 9710 * views are attached to a window. 9711 * 9712 * <p>This is useful if the views are being recycled, since an autofill id should uniquely 9713 * identify a particular piece of content. 9714 * 9715 * @hide 9716 */ resetSubtreeAutofillIds()9717 public void resetSubtreeAutofillIds() { 9718 if (mAutofillViewId == NO_ID) { 9719 return; 9720 } 9721 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 9722 Log.v(CONTENT_CAPTURE_LOG_TAG, "resetAutofillId() for " + mAutofillViewId); 9723 } else if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9724 Log.v(AUTOFILL_LOG_TAG, "resetAutofillId() for " + mAutofillViewId); 9725 } 9726 mAutofillId = null; 9727 mAutofillViewId = NO_ID; 9728 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9729 } 9730 9731 /** 9732 * Describes the autofill type of this view, so an 9733 * {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue} 9734 * when autofilling the view. 9735 * 9736 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it to properly 9737 * support the Autofill Framework. 9738 * 9739 * @return either {@link #AUTOFILL_TYPE_NONE}, {@link #AUTOFILL_TYPE_TEXT}, 9740 * {@link #AUTOFILL_TYPE_LIST}, {@link #AUTOFILL_TYPE_DATE}, or {@link #AUTOFILL_TYPE_TOGGLE}. 9741 * 9742 * @see #onProvideAutofillStructure(ViewStructure, int) 9743 * @see #autofill(AutofillValue) 9744 */ getAutofillType()9745 public @AutofillType int getAutofillType() { 9746 return AUTOFILL_TYPE_NONE; 9747 } 9748 9749 /** 9750 * Gets the hints that help an {@link android.service.autofill.AutofillService} determine how 9751 * to autofill the view with the user's data. 9752 * 9753 * <p>See {@link #setAutofillHints(String...)} for more info about these hints. 9754 * 9755 * @return The hints set via the attribute or {@link #setAutofillHints(String...)}, or 9756 * {@code null} if no hints were set. 9757 * 9758 * @attr ref android.R.styleable#View_autofillHints 9759 */ 9760 @ViewDebug.ExportedProperty() 9761 @InspectableProperty getAutofillHints()9762 @Nullable public String[] getAutofillHints() { 9763 return mAutofillHints; 9764 } 9765 9766 /** 9767 * @hide 9768 */ 9769 @TestApi isAutofilled()9770 public boolean isAutofilled() { 9771 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; 9772 } 9773 9774 /** 9775 * @hide 9776 */ hideAutofillHighlight()9777 public boolean hideAutofillHighlight() { 9778 return (mPrivateFlags4 & PFLAG4_AUTOFILL_HIDE_HIGHLIGHT) != 0; 9779 } 9780 9781 /** 9782 * Gets the {@link View}'s current autofill value. 9783 * 9784 * <p>By default returns {@code null}, but subclasses should override it and return an 9785 * appropriate value to properly support the Autofill Framework. 9786 * 9787 * @see #onProvideAutofillStructure(ViewStructure, int) 9788 * @see #autofill(AutofillValue) 9789 */ 9790 @Nullable getAutofillValue()9791 public AutofillValue getAutofillValue() { 9792 return null; 9793 } 9794 9795 /** 9796 * Gets the mode for determining whether this view is important for autofill. 9797 * 9798 * <p>See {@link #setImportantForAutofill(int)} and {@link #isImportantForAutofill()} for more 9799 * info about this mode. 9800 * 9801 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 9802 * {@link #setImportantForAutofill(int)}. 9803 * 9804 * @attr ref android.R.styleable#View_importantForAutofill 9805 */ 9806 @ViewDebug.ExportedProperty(mapping = { 9807 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 9808 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 9809 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), 9810 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 9811 to = "yesExcludeDescendants"), 9812 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 9813 to = "noExcludeDescendants")}) 9814 @InspectableProperty(enumMapping = { 9815 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"), 9816 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"), 9817 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"), 9818 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 9819 name = "yesExcludeDescendants"), 9820 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 9821 name = "noExcludeDescendants"), 9822 }) getImportantForAutofill()9823 public @AutofillImportance int getImportantForAutofill() { 9824 return (mPrivateFlags3 9825 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 9826 } 9827 9828 /** 9829 * Sets the mode for determining whether this view is considered important for autofill. 9830 * 9831 * <p>The platform determines the importance for autofill automatically but you 9832 * can use this method to customize the behavior. For example: 9833 * 9834 * <ol> 9835 * <li>When the view contents is irrelevant for autofill (for example, a text field used in a 9836 * "Captcha" challenge), it should be {@link #IMPORTANT_FOR_AUTOFILL_NO}. 9837 * <li>When both the view and its children are irrelevant for autofill (for example, the root 9838 * view of an activity containing a spreadhseet editor), it should be 9839 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 9840 * <li>When the view content is relevant for autofill but its children aren't (for example, 9841 * a credit card expiration date represented by a custom view that overrides the proper 9842 * autofill methods and has 2 children representing the month and year), it should 9843 * be {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}. 9844 * </ol> 9845 * 9846 * <p><b>Note:</b> Setting the mode as {@link #IMPORTANT_FOR_AUTOFILL_NO} or 9847 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and its 9848 * children) will not be used for autofill purpose; for example, when the user explicitly 9849 * makes an autofill request, all views are included in the ViewStructure, and starting in 9850 * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} the system uses other factors along 9851 * with importance to determine the autofill behavior. See {@link #isImportantForAutofill()} 9852 * for more details about how the View's importance for autofill is used. 9853 * 9854 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 9855 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, 9856 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 9857 * 9858 * @attr ref android.R.styleable#View_importantForAutofill 9859 */ setImportantForAutofill(@utofillImportance int mode)9860 public void setImportantForAutofill(@AutofillImportance int mode) { 9861 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 9862 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 9863 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 9864 } 9865 9866 /** 9867 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 9868 * associated with this view is considered important for autofill purposes. 9869 * 9870 * <p>Generally speaking, a view is important for autofill if: 9871 * <ol> 9872 * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}. 9873 * <li>The view contents can help an {@link android.service.autofill.AutofillService} 9874 * determine how other views can be autofilled. 9875 * <ol> 9876 * 9877 * <p>For example, view containers should typically return {@code false} for performance reasons 9878 * (since the important info is provided by their children), but if its properties have relevant 9879 * information (for example, a resource id called {@code credentials}, it should return 9880 * {@code true}. On the other hand, views representing labels or editable fields should 9881 * typically return {@code true}, but in some cases they could return {@code false} 9882 * (for example, if they're part of a "Captcha" mechanism). 9883 * 9884 * <p>The value returned by this method depends on the value returned by 9885 * {@link #getImportantForAutofill()}: 9886 * 9887 * <ol> 9888 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_YES} or 9889 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, then it returns {@code true} 9890 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_NO} or 9891 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}, then it returns {@code false} 9892 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, then it uses some simple heuristics 9893 * that can return {@code true} in some cases (like a container with a resource id), 9894 * but {@code false} in most. 9895 * <li>otherwise, it returns {@code false}. 9896 * </ol> 9897 * 9898 * <p> The behavior of importances depends on Android version: 9899 * <ol> 9900 * <li>For {@link android.os.Build.VERSION_CODES#TIRAMISU} and below: 9901 * <ol> 9902 * <li>When a view is considered important for autofill: 9903 * <ol> 9904 * <li>The view might automatically trigger an autofill request when focused on. 9905 * <li>The contents of the view are included in the {@link ViewStructure} used in an 9906 * autofill request. 9907 * </ol> 9908 * <li>On the other hand, when a view is considered not important for autofill: 9909 * <ol> 9910 * <li>The view never automatically triggers autofill requests, but it can trigger a 9911 * manual request through {@link AutofillManager#requestAutofill(View)}. 9912 * <li>The contents of the view are not included in the {@link ViewStructure} used in 9913 * an autofill request, unless the request has the 9914 * {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag. 9915 * </ol> 9916 * </ol> 9917 * <li>For {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and above: 9918 * <ol> 9919 * <li>The system uses importance, along with other view properties and other optimization 9920 * factors, to determine if a view should trigger autofill on focus. 9921 * <li>The contents of {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, 9922 * {@link #IMPORTANT_FOR_AUTOFILL_YES}, {@link #IMPORTANT_FOR_AUTOFILL_NO}, 9923 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, and 9924 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} views will be included in the 9925 * {@link ViewStructure} used in an autofill request. 9926 * </ol> 9927 * </ol> 9928 * 9929 * @return whether the view is considered important for autofill. 9930 * 9931 * @see #setImportantForAutofill(int) 9932 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 9933 * @see #IMPORTANT_FOR_AUTOFILL_YES 9934 * @see #IMPORTANT_FOR_AUTOFILL_NO 9935 * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 9936 * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9937 * @see AutofillManager#requestAutofill(View) 9938 */ isImportantForAutofill()9939 public final boolean isImportantForAutofill() { 9940 // Check parent mode to ensure we're not hidden. 9941 ViewParent parent = mParent; 9942 while (parent instanceof View) { 9943 final int parentImportance = ((View) parent).getImportantForAutofill(); 9944 if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9945 || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) { 9946 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9947 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 9948 + "because parent " + parent + "'s importance is " + parentImportance); 9949 } 9950 return false; 9951 } 9952 parent = parent.getParent(); 9953 } 9954 9955 final int importance = getImportantForAutofill(); 9956 9957 // First, check the explicit states. 9958 if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 9959 || importance == IMPORTANT_FOR_AUTOFILL_YES) { 9960 return true; 9961 } 9962 if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9963 || importance == IMPORTANT_FOR_AUTOFILL_NO) { 9964 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9965 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 9966 + "because its importance is " + importance); 9967 } 9968 return false; 9969 } 9970 9971 // Then use some heuristics to handle AUTO. 9972 if (importance != IMPORTANT_FOR_AUTOFILL_AUTO) { 9973 Log.w(AUTOFILL_LOG_TAG, "invalid autofill importance (" + importance + " on view " 9974 + this); 9975 return false; 9976 } 9977 9978 // Always include views that have an explicit resource id. 9979 final int id = mID; 9980 if (id != NO_ID && !isViewIdGenerated(id)) { 9981 final Resources res = getResources(); 9982 String entry = null; 9983 String pkg = null; 9984 try { 9985 entry = res.getResourceEntryName(id); 9986 pkg = res.getResourcePackageName(id); 9987 } catch (Resources.NotFoundException e) { 9988 // ignore 9989 } 9990 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 9991 return true; 9992 } 9993 } 9994 9995 // If the app developer explicitly set hints for it, it's important. 9996 if (getAutofillHints() != null) { 9997 return true; 9998 } 9999 10000 // Otherwise, assume it's not important... 10001 return false; 10002 } 10003 10004 /** 10005 * Gets the mode for determining whether this view is important for content capture. 10006 * 10007 * <p>See {@link #setImportantForContentCapture(int)} and 10008 * {@link #isImportantForContentCapture()} for more info about this mode. 10009 * 10010 * @return {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO} by default, or value passed to 10011 * {@link #setImportantForContentCapture(int)}. 10012 * 10013 * @attr ref android.R.styleable#View_importantForContentCapture 10014 */ 10015 @ViewDebug.ExportedProperty(mapping = { 10016 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to = "auto"), 10017 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES, to = "yes"), 10018 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO, to = "no"), 10019 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 10020 to = "yesExcludeDescendants"), 10021 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 10022 to = "noExcludeDescendants")}) 10023 @InspectableProperty(enumMapping = { 10024 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"), 10025 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"), 10026 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"), 10027 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 10028 name = "yesExcludeDescendants"), 10029 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 10030 name = "noExcludeDescendants"), 10031 }) getImportantForContentCapture()10032 public @ContentCaptureImportance int getImportantForContentCapture() { 10033 // NOTE: the important for content capture values were the first flags added and are set in 10034 // the rightmost position, so we don't need to shift them 10035 return mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 10036 } 10037 10038 /** 10039 * Sets the mode for determining whether this view is considered important for content capture. 10040 * 10041 * <p>The platform determines the importance for autofill automatically but you 10042 * can use this method to customize the behavior. Typically, a view that provides text should 10043 * be marked as {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}. 10044 * 10045 * @param mode {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}, 10046 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}, {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO}, 10047 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS}, 10048 * or {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS}. 10049 * 10050 * @attr ref android.R.styleable#View_importantForContentCapture 10051 */ setImportantForContentCapture(@ontentCaptureImportance int mode)10052 public void setImportantForContentCapture(@ContentCaptureImportance int mode) { 10053 // Reset first 10054 mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 10055 // Then set again 10056 // NOTE: the important for content capture values were the first flags added and are set in 10057 // the rightmost position, so we don't need to shift them 10058 mPrivateFlags4 |= (mode & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK); 10059 } 10060 10061 /** 10062 * Hints the Android System whether this view is considered important for content capture, based 10063 * on the value explicitly set by {@link #setImportantForContentCapture(int)} and heuristics 10064 * when it's {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}. 10065 * 10066 * <p>See {@link ContentCaptureManager} for more info about content capture. 10067 * 10068 * @return whether the view is considered important for content capture. 10069 * 10070 * @see #setImportantForContentCapture(int) 10071 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO 10072 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES 10073 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO 10074 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 10075 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 10076 */ isImportantForContentCapture()10077 public final boolean isImportantForContentCapture() { 10078 boolean isImportant; 10079 if ((mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED) != 0) { 10080 isImportant = (mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE) != 0; 10081 return isImportant; 10082 } 10083 10084 isImportant = calculateIsImportantForContentCapture(); 10085 10086 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 10087 if (isImportant) { 10088 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 10089 } 10090 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED; 10091 return isImportant; 10092 } 10093 10094 /** 10095 * Calculates whether the flag is important for content capture so it can be used by 10096 * {@link #isImportantForContentCapture()} while the tree is traversed. 10097 */ calculateIsImportantForContentCapture()10098 private boolean calculateIsImportantForContentCapture() { 10099 // Check parent mode to ensure we're important 10100 ViewParent parent = mParent; 10101 while (parent instanceof View) { 10102 final int parentImportance = ((View) parent).getImportantForContentCapture(); 10103 if (parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 10104 || parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS) { 10105 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 10106 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for " 10107 + "content capture because parent " + parent + "'s importance is " 10108 + parentImportance); 10109 } 10110 return false; 10111 } 10112 parent = parent.getParent(); 10113 } 10114 10115 final int importance = getImportantForContentCapture(); 10116 10117 // First, check the explicit states. 10118 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 10119 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES) { 10120 return true; 10121 } 10122 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 10123 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO) { 10124 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 10125 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for content " 10126 + "capture because its importance is " + importance); 10127 } 10128 return false; 10129 } 10130 10131 // Then use some heuristics to handle AUTO. 10132 if (importance != IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { 10133 Log.w(CONTENT_CAPTURE_LOG_TAG, "invalid content capture importance (" + importance 10134 + " on view " + this); 10135 return false; 10136 } 10137 10138 // View group is important if at least one children also is 10139 if (this instanceof ViewGroup) { 10140 final ViewGroup group = (ViewGroup) this; 10141 for (int i = 0; i < group.getChildCount(); i++) { 10142 final View child = group.getChildAt(i); 10143 if (child.isImportantForContentCapture()) { 10144 return true; 10145 } 10146 } 10147 } 10148 10149 // If the app developer explicitly set hints or autofill hintsfor it, it's important. 10150 if (getAutofillHints() != null) { 10151 return true; 10152 } 10153 10154 // Otherwise, assume it's not important... 10155 return false; 10156 } 10157 10158 /** 10159 * Helper used to notify the {@link ContentCaptureManager} when the view is removed or 10160 * added, based on whether it's laid out and visible, and without knowing if the parent removed 10161 * it from the view hierarchy. 10162 * 10163 * <p>This method is called from many places (visibility changed, view laid out, view attached 10164 * or detached to/from window, etc...) and hence must contain the logic to call the manager, as 10165 * described below: 10166 * 10167 * <ol> 10168 * <li>It should only be called when content capture is enabled for the view. 10169 * <li>It must call viewAppeared() before viewDisappeared() 10170 * <li>viewAppeared() can only be called when the view is visible and laid out 10171 * <li>It should not call the same event twice. 10172 * </ol> 10173 */ notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared)10174 private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) { 10175 AttachInfo ai = mAttachInfo; 10176 // Skip it while the view is being laid out for the first time 10177 if (ai != null && !ai.mReadyForContentCaptureUpdates) return; 10178 10179 // First check if context has client, so it saves a service lookup when it doesn't 10180 if (mContext.getContentCaptureOptions() == null) return; 10181 10182 if (appeared) { 10183 // The appeared event stops sending to AiAi. 10184 // 1. The view is hidden. 10185 // 2. The same event was sent. 10186 // 3. The view is not laid out, and it will be laid out in the future. 10187 // Some recycled views cached its layout and a relayout is unnecessary. In this case, 10188 // system still needs to notify content capture the view appeared. When a view is 10189 // recycled, it will set the flag PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED. 10190 final boolean isRecycledWithoutRelayout = getNotifiedContentCaptureDisappeared() 10191 && getVisibility() == VISIBLE 10192 && !isLayoutRequested(); 10193 if (getVisibility() != VISIBLE || getNotifiedContentCaptureAppeared() 10194 || !(isLaidOut() || isRecycledWithoutRelayout)) { 10195 if (DEBUG_CONTENT_CAPTURE) { 10196 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid=" 10197 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 10198 + ", visible=" + (getVisibility() == VISIBLE) 10199 + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared() 10200 + ", alreadyNotifiedDisappeared=" 10201 + getNotifiedContentCaptureDisappeared()); 10202 } 10203 return; 10204 } 10205 } else { 10206 if (!getNotifiedContentCaptureAppeared() || getNotifiedContentCaptureDisappeared()) { 10207 if (DEBUG_CONTENT_CAPTURE) { 10208 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": laid=" 10209 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 10210 + ", visible=" + (getVisibility() == VISIBLE) 10211 + ": alreadyNotifiedAppeared=" + getNotifiedContentCaptureAppeared() 10212 + ", alreadyNotifiedDisappeared=" 10213 + getNotifiedContentCaptureDisappeared()); 10214 } 10215 return; 10216 } 10217 } 10218 10219 ContentCaptureSession session = getContentCaptureSession(); 10220 if (session == null) return; 10221 10222 // ... and finally at the view level 10223 // NOTE: isImportantForContentCapture() is more expensive than cm.isContentCaptureEnabled() 10224 if (!isImportantForContentCapture()) return; 10225 10226 if (appeared) { 10227 setNotifiedContentCaptureAppeared(); 10228 10229 if (ai != null) { 10230 makeParentImportantAndNotifyAppearedEventIfNeed(); 10231 ai.delayNotifyContentCaptureEvent(session, this, appeared); 10232 } else { 10233 if (DEBUG_CONTENT_CAPTURE) { 10234 Log.w(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on appeared for " + this); 10235 } 10236 } 10237 } else { 10238 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 10239 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 10240 10241 if (ai != null) { 10242 ai.delayNotifyContentCaptureEvent(session, this, appeared); 10243 } else { 10244 if (DEBUG_CONTENT_CAPTURE) { 10245 Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on disappeared for " + this); 10246 } 10247 } 10248 10249 // We reset any translation state as views may be re-used (e.g., as in ListView and 10250 // RecyclerView). We only need to do this for views important for content capture since 10251 // views unimportant for content capture won't be translated anyway. 10252 if (!isTemporarilyDetached()) { 10253 clearTranslationState(); 10254 } 10255 } 10256 } 10257 makeParentImportantAndNotifyAppearedEventIfNeed()10258 private void makeParentImportantAndNotifyAppearedEventIfNeed() { 10259 // If view sent the appeared event to Content Capture, Content Capture also 10260 // would like to receive its parents' appeared events. So checks its parents 10261 // whether the appeared event is sent or not. If not, send the appeared event. 10262 final ViewParent parent = getParent(); 10263 if (parent instanceof View) { 10264 View p = ((View) parent); 10265 if (p.getNotifiedContentCaptureAppeared()) { 10266 return; 10267 } 10268 // Set important for content capture in the cache. 10269 p.mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; 10270 p.notifyAppearedOrDisappearedForContentCaptureIfNeeded(/* appeared */ true); 10271 } 10272 } 10273 setNotifiedContentCaptureAppeared()10274 private void setNotifiedContentCaptureAppeared() { 10275 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 10276 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 10277 } 10278 10279 /** @hide */ getNotifiedContentCaptureAppeared()10280 protected boolean getNotifiedContentCaptureAppeared() { 10281 return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0; 10282 } 10283 10284 getNotifiedContentCaptureDisappeared()10285 private boolean getNotifiedContentCaptureDisappeared() { 10286 return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0; 10287 } 10288 10289 /** 10290 * Sets the (optional) {@link ContentCaptureSession} associated with this view. 10291 * 10292 * <p>This method should be called when you need to associate a {@link ContentCaptureContext} to 10293 * the content capture events associated with this view or its view hierarchy (if it's a 10294 * {@link ViewGroup}). 10295 * 10296 * <p>For example, if your activity is associated with a web domain, first you would need to 10297 * set the context for the main DOM: 10298 * 10299 * <pre> 10300 * ContentCaptureSession mainSession = rootView.getContentCaptureSession(); 10301 * mainSession.setContentCaptureContext(ContentCaptureContext.forLocusId(Uri.parse(myUrl)); 10302 * </pre> 10303 * 10304 * <p>Then if the page had an {@code IFRAME}, you would create a new session for it: 10305 * 10306 * <pre> 10307 * ContentCaptureSession iframeSession = mainSession.createContentCaptureSession( 10308 * ContentCaptureContext.forLocusId(Uri.parse(iframeUrl))); 10309 * iframeView.setContentCaptureSession(iframeSession); 10310 * </pre> 10311 * 10312 * @param contentCaptureSession a session created by 10313 * {@link ContentCaptureSession#createContentCaptureSession( 10314 * android.view.contentcapture.ContentCaptureContext)}. 10315 */ setContentCaptureSession(@ullable ContentCaptureSession contentCaptureSession)10316 public void setContentCaptureSession(@Nullable ContentCaptureSession contentCaptureSession) { 10317 mContentCaptureSession = contentCaptureSession; 10318 } 10319 10320 /** 10321 * Gets the session used to notify content capture events. 10322 * 10323 * @return session explicitly set by {@link #setContentCaptureSession(ContentCaptureSession)}, 10324 * inherited by ancestors, default session or {@code null} if content capture is disabled for 10325 * this view. 10326 */ 10327 @Nullable getContentCaptureSession()10328 public final ContentCaptureSession getContentCaptureSession() { 10329 if (mContentCaptureSessionCached) { 10330 return mContentCaptureSession; 10331 } 10332 10333 mContentCaptureSession = getAndCacheContentCaptureSession(); 10334 mContentCaptureSessionCached = true; 10335 return mContentCaptureSession; 10336 } 10337 10338 @Nullable getAndCacheContentCaptureSession()10339 private ContentCaptureSession getAndCacheContentCaptureSession() { 10340 // First try the session explicitly set by setContentCaptureSession() 10341 if (mContentCaptureSession != null) { 10342 return mContentCaptureSession; 10343 } 10344 10345 // Then the session explicitly set in an ancestor 10346 ContentCaptureSession session = null; 10347 if (mParent instanceof View) { 10348 session = ((View) mParent).getContentCaptureSession(); 10349 } 10350 10351 // Finally, if no session was explicitly set, use the context's default session. 10352 if (session == null) { 10353 final ContentCaptureManager ccm = mContext 10354 .getSystemService(ContentCaptureManager.class); 10355 return ccm == null ? null : ccm.getMainContentCaptureSession(); 10356 } 10357 return session; 10358 } 10359 10360 @Nullable getAutofillManager()10361 private AutofillManager getAutofillManager() { 10362 return mContext.getSystemService(AutofillManager.class); 10363 } 10364 10365 /** 10366 * Check whether current activity / package is in autofill denylist. 10367 * 10368 * Called by viewGroup#populateChildrenForAutofill() to determine whether to include view in 10369 * assist structure 10370 */ isActivityDeniedForAutofillForUnimportantView()10371 final boolean isActivityDeniedForAutofillForUnimportantView() { 10372 final AutofillManager afm = getAutofillManager(); 10373 if (afm == null) return false; 10374 return afm.isActivityDeniedForAutofill(); 10375 } 10376 10377 /** 10378 * Check whether current view matches autofillable heuristics 10379 * 10380 * Called by viewGroup#populateChildrenForAutofill() to determine whether to include view in 10381 * assist structure 10382 */ isMatchingAutofillableHeuristics()10383 final boolean isMatchingAutofillableHeuristics() { 10384 final AutofillManager afm = getAutofillManager(); 10385 if (afm == null) return false; 10386 // check the flag to see if trigger fill request on not important views is enabled 10387 return afm.isTriggerFillRequestOnUnimportantViewEnabled() 10388 ? afm.isAutofillable(this) : false; 10389 } 10390 isAutofillable()10391 private boolean isAutofillable() { 10392 if (getAutofillType() == AUTOFILL_TYPE_NONE) return false; 10393 10394 final AutofillManager afm = getAutofillManager(); 10395 if (afm == null) { 10396 return false; 10397 } 10398 10399 // Check whether view is not part of an activity. If it's not, return false. 10400 if (getAutofillViewId() <= LAST_APP_AUTOFILL_ID) { 10401 return false; 10402 } 10403 10404 // If view is important and filter important view flag is turned on, or view is not 10405 // important and trigger fill request on not important view flag is turned on, then use 10406 // AutofillManager.isAutofillable() to decide whether view is autofillable instead. 10407 if ((isImportantForAutofill() && afm.isTriggerFillRequestOnFilteredImportantViewsEnabled()) 10408 || (!isImportantForAutofill() 10409 && afm.isTriggerFillRequestOnUnimportantViewEnabled())) { 10410 return afm.isAutofillable(this) ? true : notifyAugmentedAutofillIfNeeded(afm); 10411 } 10412 10413 // If the previous condition is not met, fall back to the previous way to trigger fill 10414 // request based on autofill importance instead. 10415 return isImportantForAutofill() ? true : notifyAugmentedAutofillIfNeeded(afm); 10416 } 10417 notifyAugmentedAutofillIfNeeded(AutofillManager afm)10418 private boolean notifyAugmentedAutofillIfNeeded(AutofillManager afm) { 10419 final AutofillOptions options = mContext.getAutofillOptions(); 10420 if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { 10421 return false; 10422 } 10423 afm.notifyViewEnteredForAugmentedAutofill(this); 10424 return true; 10425 } 10426 10427 /** @hide */ canNotifyAutofillEnterExitEvent()10428 public boolean canNotifyAutofillEnterExitEvent() { 10429 return isAutofillable() && isAttachedToWindow(); 10430 } 10431 populateVirtualStructure(ViewStructure structure, AccessibilityNodeProvider provider, AccessibilityNodeInfo info, boolean forAutofill)10432 private void populateVirtualStructure(ViewStructure structure, 10433 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, 10434 boolean forAutofill) { 10435 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 10436 null, null, info.getViewIdResourceName()); 10437 Rect rect = structure.getTempRect(); 10438 info.getBoundsInParent(rect); 10439 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 10440 structure.setVisibility(VISIBLE); 10441 structure.setEnabled(info.isEnabled()); 10442 if (info.isClickable()) { 10443 structure.setClickable(true); 10444 } 10445 if (info.isFocusable()) { 10446 structure.setFocusable(true); 10447 } 10448 if (info.isFocused()) { 10449 structure.setFocused(true); 10450 } 10451 if (info.isAccessibilityFocused()) { 10452 structure.setAccessibilityFocused(true); 10453 } 10454 if (info.isSelected()) { 10455 structure.setSelected(true); 10456 } 10457 if (info.isLongClickable()) { 10458 structure.setLongClickable(true); 10459 } 10460 if (info.isCheckable()) { 10461 structure.setCheckable(true); 10462 if (info.isChecked()) { 10463 structure.setChecked(true); 10464 } 10465 } 10466 if (info.isContextClickable()) { 10467 structure.setContextClickable(true); 10468 } 10469 if (forAutofill) { 10470 structure.setAutofillId(new AutofillId(getAutofillId(), 10471 AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()))); 10472 } 10473 CharSequence cname = info.getClassName(); 10474 structure.setClassName(cname != null ? cname.toString() : null); 10475 structure.setContentDescription(info.getContentDescription()); 10476 if (forAutofill) { 10477 final int maxTextLength = info.getMaxTextLength(); 10478 if (maxTextLength != -1) { 10479 structure.setMaxTextLength(maxTextLength); 10480 } 10481 structure.setHint(info.getHintText()); 10482 } 10483 CharSequence text = info.getText(); 10484 boolean hasText = text != null || info.getError() != null; 10485 if (hasText) { 10486 structure.setText(text, info.getTextSelectionStart(), info.getTextSelectionEnd()); 10487 } 10488 if (forAutofill) { 10489 if (info.isEditable()) { 10490 structure.setDataIsSensitive(true); 10491 if (hasText) { 10492 structure.setAutofillType(AUTOFILL_TYPE_TEXT); 10493 structure.setAutofillValue(AutofillValue.forText(text)); 10494 } 10495 int inputType = info.getInputType(); 10496 if (inputType == 0 && info.isPassword()) { 10497 inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD; 10498 } 10499 structure.setInputType(inputType); 10500 } else { 10501 structure.setDataIsSensitive(false); 10502 } 10503 } 10504 final int NCHILDREN = info.getChildCount(); 10505 if (NCHILDREN > 0) { 10506 structure.setChildCount(NCHILDREN); 10507 for (int i=0; i<NCHILDREN; i++) { 10508 if (AccessibilityNodeInfo.getVirtualDescendantId(info.getChildNodeIds().get(i)) 10509 == AccessibilityNodeProvider.HOST_VIEW_ID) { 10510 Log.e(VIEW_LOG_TAG, "Virtual view pointing to its host. Ignoring"); 10511 continue; 10512 } 10513 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 10514 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 10515 if (cinfo != null) { 10516 ViewStructure child = structure.newChild(i); 10517 populateVirtualStructure(child, provider, cinfo, forAutofill); 10518 cinfo.recycle(); 10519 } 10520 } 10521 } 10522 } 10523 10524 /** 10525 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 10526 * implementation calls {@link #onProvideStructure} and 10527 * {@link #onProvideVirtualStructure}. 10528 */ dispatchProvideStructure(ViewStructure structure)10529 public void dispatchProvideStructure(ViewStructure structure) { 10530 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 10531 } 10532 10533 /** 10534 * Dispatches creation of a {@link ViewStructure}s for autofill purposes down the hierarchy, 10535 * when an Assist structure is being created as part of an autofill request. 10536 * 10537 * <p>The default implementation does the following: 10538 * <ul> 10539 * <li>Sets the {@link AutofillId} in the structure. 10540 * <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}. 10541 * <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 10542 * </ul> 10543 * 10544 * <p>Typically, this method should only be overridden by subclasses that provide a view 10545 * hierarchy (such as {@link ViewGroup}) - other classes should override 10546 * {@link #onProvideAutofillStructure(ViewStructure, int)} or 10547 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} instead. 10548 * 10549 * <p>When overridden, it must: 10550 * 10551 * <ul> 10552 * <li>Either call 10553 * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly 10554 * set the {@link AutofillId} in the structure (for example, by calling 10555 * {@code structure.setAutofillId(getAutofillId())}). 10556 * <li>Decide how to handle the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag - when 10557 * set, all views in the structure should be considered important for autofill, 10558 * regardless of what {@link #isImportantForAutofill()} returns. We encourage you to 10559 * respect this flag to provide a better user experience - this flag is typically used 10560 * when an user explicitly requested autofill. If the flag is not set, 10561 * then only views marked as important for autofill should be included in the 10562 * structure - skipping non-important views optimizes the overall autofill performance. 10563 * </ul> 10564 * 10565 * @param structure fill in with structured view data for autofill purposes. 10566 * @param flags optional flags. 10567 * 10568 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 10569 */ dispatchProvideAutofillStructure(@onNull ViewStructure structure, @AutofillFlags int flags)10570 public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, 10571 @AutofillFlags int flags) { 10572 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 10573 } 10574 dispatchProvideStructure(@onNull ViewStructure structure, @ViewStructureType int viewFor, @AutofillFlags int flags)10575 private void dispatchProvideStructure(@NonNull ViewStructure structure, 10576 @ViewStructureType int viewFor, @AutofillFlags int flags) { 10577 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { 10578 structure.setAutofillId(getAutofillId()); 10579 onProvideAutofillStructure(structure, flags); 10580 onProvideAutofillVirtualStructure(structure, flags); 10581 } else if (!isAssistBlocked()) { 10582 onProvideStructure(structure); 10583 onProvideVirtualStructure(structure); 10584 } else { 10585 structure.setClassName(getAccessibilityClassName().toString()); 10586 structure.setAssistBlocked(true); 10587 } 10588 } 10589 10590 /** 10591 * Dispatches the initial content capture events for a view structure. 10592 * 10593 * @hide 10594 */ dispatchInitialProvideContentCaptureStructure()10595 public void dispatchInitialProvideContentCaptureStructure() { 10596 AttachInfo ai = mAttachInfo; 10597 if (ai == null) { 10598 Log.w(CONTENT_CAPTURE_LOG_TAG, 10599 "dispatchProvideContentCaptureStructure(): no AttachInfo for " + this); 10600 return; 10601 } 10602 ContentCaptureManager ccm = ai.mContentCaptureManager; 10603 if (ccm == null) { 10604 Log.w(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): " 10605 + "no ContentCaptureManager for " + this); 10606 return; 10607 } 10608 10609 // We must set it before checkign if the view itself is important, because it might 10610 // initially not be (for example, if it's empty), although that might change later (for 10611 // example, if important views are added) 10612 ai.mReadyForContentCaptureUpdates = true; 10613 10614 if (!isImportantForContentCapture()) { 10615 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 10616 Log.d(CONTENT_CAPTURE_LOG_TAG, 10617 "dispatchProvideContentCaptureStructure(): decorView is not important"); 10618 } 10619 return; 10620 } 10621 10622 ai.mContentCaptureManager = ccm; 10623 10624 ContentCaptureSession session = getContentCaptureSession(); 10625 if (session == null) { 10626 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 10627 Log.d(CONTENT_CAPTURE_LOG_TAG, 10628 "dispatchProvideContentCaptureStructure(): no session for " + this); 10629 } 10630 return; 10631 } 10632 10633 session.internalNotifyViewTreeEvent(/* started= */ true); 10634 try { 10635 dispatchProvideContentCaptureStructure(); 10636 } finally { 10637 session.internalNotifyViewTreeEvent(/* started= */ false); 10638 } 10639 } 10640 10641 /** @hide */ dispatchProvideContentCaptureStructure()10642 void dispatchProvideContentCaptureStructure() { 10643 ContentCaptureSession session = getContentCaptureSession(); 10644 if (session != null) { 10645 ViewStructure structure = session.newViewStructure(this); 10646 onProvideContentCaptureStructure(structure, /* flags= */ 0); 10647 setNotifiedContentCaptureAppeared(); 10648 session.notifyViewAppeared(structure); 10649 } 10650 } 10651 10652 /** 10653 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 10654 * 10655 * Note: Called from the default {@link AccessibilityDelegate}. 10656 * 10657 * @hide 10658 */ onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info)10659 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 10660 if (mAttachInfo == null) { 10661 return; 10662 } 10663 10664 Rect bounds = mAttachInfo.mTmpInvalRect; 10665 10666 getDrawingRect(bounds); 10667 info.setBoundsInParent(bounds); 10668 10669 getBoundsOnScreen(bounds, true); 10670 info.setBoundsInScreen(bounds); 10671 getBoundsInWindow(bounds, true); 10672 info.setBoundsInWindow(bounds); 10673 10674 ViewParent parent = getParentForAccessibility(); 10675 if (parent instanceof View) { 10676 info.setParent((View) parent); 10677 } 10678 10679 if (mID != View.NO_ID) { 10680 View rootView = getRootView(); 10681 if (rootView == null) { 10682 rootView = this; 10683 } 10684 10685 View label = rootView.findLabelForView(this, mID); 10686 if (label != null) { 10687 info.setLabeledBy(label); 10688 } 10689 10690 if ((mAttachInfo.mAccessibilityFetchFlags 10691 & AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS) != 0 10692 && Resources.resourceHasPackage(mID)) { 10693 try { 10694 String viewId = getResources().getResourceName(mID); 10695 info.setViewIdResourceName(viewId); 10696 } catch (Resources.NotFoundException nfe) { 10697 /* ignore */ 10698 } 10699 } 10700 } 10701 10702 if (mLabelForId != View.NO_ID) { 10703 View rootView = getRootView(); 10704 if (rootView == null) { 10705 rootView = this; 10706 } 10707 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 10708 if (labeled != null) { 10709 info.setLabelFor(labeled); 10710 } 10711 } 10712 10713 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 10714 View rootView = getRootView(); 10715 if (rootView == null) { 10716 rootView = this; 10717 } 10718 View next = rootView.findViewInsideOutShouldExist(this, 10719 mAccessibilityTraversalBeforeId); 10720 if (next != null && next.includeForAccessibility()) { 10721 info.setTraversalBefore(next); 10722 } 10723 } 10724 10725 if (mAccessibilityTraversalAfterId != View.NO_ID) { 10726 View rootView = getRootView(); 10727 if (rootView == null) { 10728 rootView = this; 10729 } 10730 View next = rootView.findViewInsideOutShouldExist(this, 10731 mAccessibilityTraversalAfterId); 10732 if (next != null && next.includeForAccessibility()) { 10733 info.setTraversalAfter(next); 10734 } 10735 } 10736 10737 info.setVisibleToUser(isVisibleToUser()); 10738 10739 info.setImportantForAccessibility(isImportantForAccessibility()); 10740 info.setAccessibilityDataSensitive(isAccessibilityDataSensitive()); 10741 info.setPackageName(mContext.getPackageName()); 10742 info.setClassName(getAccessibilityClassName()); 10743 info.setStateDescription(getStateDescription()); 10744 info.setContentDescription(getContentDescription()); 10745 10746 info.setEnabled(isEnabled()); 10747 info.setClickable(isClickable()); 10748 info.setFocusable(isFocusable()); 10749 info.setScreenReaderFocusable(isScreenReaderFocusable()); 10750 info.setFocused(isFocused()); 10751 info.setAccessibilityFocused(isAccessibilityFocused()); 10752 info.setSelected(isSelected()); 10753 info.setLongClickable(isLongClickable()); 10754 info.setContextClickable(isContextClickable()); 10755 info.setLiveRegion(getAccessibilityLiveRegion()); 10756 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipText != null)) { 10757 info.setTooltipText(mTooltipInfo.mTooltipText); 10758 info.addAction((mTooltipInfo.mTooltipPopup == null) 10759 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP 10760 : AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP); 10761 } 10762 10763 // TODO: These make sense only if we are in an AdapterView but all 10764 // views can be selected. Maybe from accessibility perspective 10765 // we should report as selectable view in an AdapterView. 10766 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 10767 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 10768 10769 if (isFocusable()) { 10770 if (isFocused()) { 10771 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 10772 } else { 10773 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 10774 } 10775 } 10776 10777 if (!isAccessibilityFocused()) { 10778 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 10779 } else { 10780 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 10781 } 10782 10783 if (isClickable() && isEnabled()) { 10784 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 10785 } 10786 10787 if (isLongClickable() && isEnabled()) { 10788 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 10789 } 10790 10791 if (isContextClickable() && isEnabled()) { 10792 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 10793 } 10794 10795 CharSequence text = getIterableTextForAccessibility(); 10796 if (text != null && text.length() > 0) { 10797 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 10798 10799 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 10800 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 10801 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 10802 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 10803 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 10804 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 10805 } 10806 10807 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 10808 populateAccessibilityNodeInfoDrawingOrderInParent(info); 10809 info.setPaneTitle(mAccessibilityPaneTitle); 10810 info.setHeading(isAccessibilityHeading()); 10811 10812 if (mTouchDelegate != null) { 10813 info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo()); 10814 } 10815 10816 if (startedSystemDragForAccessibility()) { 10817 info.addAction(AccessibilityAction.ACTION_DRAG_CANCEL); 10818 } 10819 10820 if (canAcceptAccessibilityDrop()) { 10821 info.addAction(AccessibilityAction.ACTION_DRAG_DROP); 10822 } 10823 } 10824 10825 10826 /** 10827 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 10828 * additional data. 10829 * <p> 10830 * This method only needs overloading if the node is marked as having extra data available. 10831 * </p> 10832 * 10833 * @param info The info to which to add the extra data. Never {@code null}. 10834 * @param extraDataKey A key specifying the type of extra data to add to the info. The 10835 * extra data should be added to the {@link Bundle} returned by 10836 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 10837 * {@code null}. 10838 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 10839 * {@code null} if the service provided no arguments. 10840 * 10841 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 10842 */ addExtraDataToAccessibilityNodeInfo( @onNull AccessibilityNodeInfo info, @NonNull String extraDataKey, @Nullable Bundle arguments)10843 public void addExtraDataToAccessibilityNodeInfo( 10844 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 10845 @Nullable Bundle arguments) { 10846 } 10847 10848 /** 10849 * Determine the order in which this view will be drawn relative to its siblings for a11y 10850 * 10851 * @param info The info whose drawing order should be populated 10852 */ populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info)10853 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 10854 /* 10855 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 10856 * drawing order may not be well-defined, and some Views with custom drawing order may 10857 * not be initialized sufficiently to respond properly getChildDrawingOrder. 10858 */ 10859 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 10860 info.setDrawingOrder(0); 10861 return; 10862 } 10863 int drawingOrderInParent = 1; 10864 // Iterate up the hierarchy if parents are not important for a11y 10865 View viewAtDrawingLevel = this; 10866 final ViewParent parent = getParentForAccessibility(); 10867 while (viewAtDrawingLevel != parent) { 10868 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 10869 if (!(currentParent instanceof ViewGroup)) { 10870 // Should only happen for the Decor 10871 drawingOrderInParent = 0; 10872 break; 10873 } else { 10874 final ViewGroup parentGroup = (ViewGroup) currentParent; 10875 final int childCount = parentGroup.getChildCount(); 10876 if (childCount > 1) { 10877 List<View> preorderedList = parentGroup.buildOrderedChildList(); 10878 if (preorderedList != null) { 10879 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 10880 for (int i = 0; i < childDrawIndex; i++) { 10881 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 10882 } 10883 preorderedList.clear(); 10884 } else { 10885 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 10886 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 10887 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 10888 .getChildDrawingOrder(childCount, childIndex) : childIndex; 10889 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 10890 if (childDrawIndex != 0) { 10891 for (int i = 0; i < numChildrenToIterate; i++) { 10892 final int otherDrawIndex = (customOrder ? 10893 parentGroup.getChildDrawingOrder(childCount, i) : i); 10894 if (otherDrawIndex < childDrawIndex) { 10895 drawingOrderInParent += 10896 numViewsForAccessibility(parentGroup.getChildAt(i)); 10897 } 10898 } 10899 } 10900 } 10901 } 10902 } 10903 viewAtDrawingLevel = (View) currentParent; 10904 } 10905 info.setDrawingOrder(drawingOrderInParent); 10906 } 10907 numViewsForAccessibility(View view)10908 private static int numViewsForAccessibility(View view) { 10909 if (view != null) { 10910 if (view.includeForAccessibility()) { 10911 return 1; 10912 } else if (view instanceof ViewGroup) { 10913 return ((ViewGroup) view).getNumChildrenForAccessibility(); 10914 } 10915 } 10916 return 0; 10917 } 10918 findLabelForView(View view, int labeledId)10919 private View findLabelForView(View view, int labeledId) { 10920 if (mMatchLabelForPredicate == null) { 10921 mMatchLabelForPredicate = new MatchLabelForPredicate(); 10922 } 10923 mMatchLabelForPredicate.mLabeledId = labeledId; 10924 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 10925 } 10926 10927 /** 10928 * Computes whether this virtual autofill view is visible to the user. 10929 * 10930 * <p><b>Note: </b>By default it returns {@code true}, but views providing a virtual hierarchy 10931 * view must override it. 10932 * 10933 * @return Whether the view is visible on the screen. 10934 */ isVisibleToUserForAutofill(int virtualId)10935 public boolean isVisibleToUserForAutofill(int virtualId) { 10936 if (mContext.isAutofillCompatibilityEnabled()) { 10937 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 10938 if (provider != null) { 10939 final AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(virtualId); 10940 if (node != null) { 10941 return node.isVisibleToUser(); 10942 } 10943 // if node is null, assume it's not visible anymore 10944 } else { 10945 Log.w(VIEW_LOG_TAG, "isVisibleToUserForAutofill(" + virtualId + "): no provider"); 10946 } 10947 return false; 10948 } 10949 return true; 10950 } 10951 10952 /** 10953 * Computes whether this view is visible to the user. Such a view is 10954 * attached, visible, all its predecessors are visible, it is not clipped 10955 * entirely by its predecessors, and has an alpha greater than zero. 10956 * 10957 * @return Whether the view is visible on the screen. 10958 * 10959 * @hide 10960 */ 10961 @UnsupportedAppUsage isVisibleToUser()10962 public boolean isVisibleToUser() { 10963 return isVisibleToUser(null); 10964 } 10965 10966 /** 10967 * Computes whether the given portion of this view is visible to the user. 10968 * Such a view is attached, visible, all its predecessors are visible, 10969 * has an alpha greater than zero, and the specified portion is not 10970 * clipped entirely by its predecessors. 10971 * 10972 * @param boundInView the portion of the view to test; coordinates should be relative; may be 10973 * <code>null</code>, and the entire view will be tested in this case. 10974 * When <code>true</code> is returned by the function, the actual visible 10975 * region will be stored in this parameter; that is, if boundInView is fully 10976 * contained within the view, no modification will be made, otherwise regions 10977 * outside of the visible area of the view will be clipped. 10978 * 10979 * @return Whether the specified portion of the view is visible on the screen. 10980 * 10981 * @hide 10982 */ 10983 @UnsupportedAppUsage(trackingBug = 171933273) isVisibleToUser(Rect boundInView)10984 protected boolean isVisibleToUser(Rect boundInView) { 10985 if (mAttachInfo != null) { 10986 // Attached to invisible window means this view is not visible. 10987 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 10988 return false; 10989 } 10990 // An invisible predecessor or one with alpha zero means 10991 // that this view is not visible to the user. 10992 Object current = this; 10993 while (current instanceof View) { 10994 View view = (View) current; 10995 // We have attach info so this view is attached and there is no 10996 // need to check whether we reach to ViewRootImpl on the way up. 10997 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 10998 view.getVisibility() != VISIBLE) { 10999 return false; 11000 } 11001 current = view.mParent; 11002 } 11003 // Check if the view is entirely covered by its predecessors. 11004 Rect visibleRect = mAttachInfo.mTmpInvalRect; 11005 Point offset = mAttachInfo.mPoint; 11006 if (!getGlobalVisibleRect(visibleRect, offset)) { 11007 return false; 11008 } 11009 // Check if the visible portion intersects the rectangle of interest. 11010 if (boundInView != null) { 11011 visibleRect.offset(-offset.x, -offset.y); 11012 return boundInView.intersect(visibleRect); 11013 } 11014 return true; 11015 } 11016 return false; 11017 } 11018 11019 /** 11020 * Returns the delegate for implementing accessibility support via 11021 * composition. For more details see {@link AccessibilityDelegate}. 11022 * 11023 * @return The delegate, or null if none set. 11024 */ getAccessibilityDelegate()11025 public AccessibilityDelegate getAccessibilityDelegate() { 11026 return mAccessibilityDelegate; 11027 } 11028 11029 /** 11030 * Sets a delegate for implementing accessibility support via composition 11031 * (as opposed to inheritance). For more details, see 11032 * {@link AccessibilityDelegate}. 11033 * <p> 11034 * <strong>Note:</strong> On platform versions prior to 11035 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 11036 * views in the {@code android.widget.*} package are called <i>before</i> 11037 * host methods. This prevents certain properties such as class name from 11038 * being modified by overriding 11039 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 11040 * as any changes will be overwritten by the host class. 11041 * <p> 11042 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 11043 * methods are called <i>after</i> host methods, which all properties to be 11044 * modified without being overwritten by the host class. 11045 * 11046 * @param delegate the object to which accessibility method calls should be 11047 * delegated 11048 * @see AccessibilityDelegate 11049 */ setAccessibilityDelegate(@ullable AccessibilityDelegate delegate)11050 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 11051 mAccessibilityDelegate = delegate; 11052 } 11053 11054 /** 11055 * Gets the provider for managing a virtual view hierarchy rooted at this View 11056 * and reported to {@link android.accessibilityservice.AccessibilityService}s 11057 * that explore the window content. 11058 * <p> 11059 * If this method returns an instance, this instance is responsible for managing 11060 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 11061 * View including the one representing the View itself. Similarly the returned 11062 * instance is responsible for performing accessibility actions on any virtual 11063 * view or the root view itself. 11064 * </p> 11065 * <p> 11066 * If an {@link AccessibilityDelegate} has been specified via calling 11067 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 11068 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 11069 * is responsible for handling this call. 11070 * </p> 11071 * 11072 * @return The provider. 11073 * 11074 * @see AccessibilityNodeProvider 11075 */ getAccessibilityNodeProvider()11076 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 11077 if (mAccessibilityDelegate != null) { 11078 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 11079 } else { 11080 return null; 11081 } 11082 } 11083 11084 /** 11085 * Gets the unique identifier of this view on the screen for accessibility purposes. 11086 * 11087 * @return The view accessibility id. 11088 * 11089 * @hide 11090 */ 11091 @UnsupportedAppUsage getAccessibilityViewId()11092 public int getAccessibilityViewId() { 11093 if (mAccessibilityViewId == NO_ID) { 11094 mAccessibilityViewId = sNextAccessibilityViewId++; 11095 } 11096 return mAccessibilityViewId; 11097 } 11098 11099 /** 11100 * Gets the unique identifier of this view on the screen for autofill purposes. 11101 * 11102 * @return The view autofill id. 11103 * 11104 * @hide 11105 */ getAutofillViewId()11106 public int getAutofillViewId() { 11107 if (mAutofillViewId == NO_ID) { 11108 mAutofillViewId = mContext.getNextAutofillId(); 11109 } 11110 return mAutofillViewId; 11111 } 11112 11113 /** 11114 * Gets the unique identifier of the window in which this View resides. 11115 * 11116 * @return The window accessibility id. 11117 * 11118 * @hide 11119 */ getAccessibilityWindowId()11120 public int getAccessibilityWindowId() { 11121 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 11122 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 11123 } 11124 11125 /** 11126 * Returns the {@link View}'s state description. 11127 * <p> 11128 * <strong>Note:</strong> Do not override this method, as it will have no 11129 * effect on the state description presented to accessibility services. 11130 * You must call {@link #setStateDescription(CharSequence)} to modify the 11131 * state description. 11132 * 11133 * @return the state description 11134 * @see #setStateDescription(CharSequence) 11135 */ 11136 @ViewDebug.ExportedProperty(category = "accessibility") getStateDescription()11137 public final @Nullable CharSequence getStateDescription() { 11138 return mStateDescription; 11139 } 11140 11141 /** 11142 * Returns the {@link View}'s content description. 11143 * <p> 11144 * <strong>Note:</strong> Do not override this method, as it will have no 11145 * effect on the content description presented to accessibility services. 11146 * You must call {@link #setContentDescription(CharSequence)} to modify the 11147 * content description. 11148 * 11149 * @return the content description 11150 * @see #setContentDescription(CharSequence) 11151 * @attr ref android.R.styleable#View_contentDescription 11152 */ 11153 @ViewDebug.ExportedProperty(category = "accessibility") 11154 @InspectableProperty getContentDescription()11155 public CharSequence getContentDescription() { 11156 return mContentDescription; 11157 } 11158 11159 /** 11160 * Sets the {@link View}'s state description. 11161 * <p> 11162 * A state description briefly describes the states of the view and is primarily used 11163 * for accessibility support to determine how the states of a view should be presented to 11164 * the user. It is a supplement to the boolean states (for example, checked/unchecked) and 11165 * it is used for customized state description (for example, "wifi, connected, three bars"). 11166 * State description changes frequently while content description should change less often. 11167 * State description should be localized. For android widgets which have default state 11168 * descriptions, app developers can call this method to override the state descriptions. 11169 * Setting state description to null restores the default behavior. 11170 * 11171 * @param stateDescription The state description. 11172 * @see #getStateDescription() 11173 */ 11174 @RemotableViewMethod setStateDescription(@ullable CharSequence stateDescription)11175 public void setStateDescription(@Nullable CharSequence stateDescription) { 11176 if (mStateDescription == null) { 11177 if (stateDescription == null) { 11178 return; 11179 } 11180 } else if (mStateDescription.equals(stateDescription)) { 11181 return; 11182 } 11183 mStateDescription = stateDescription; 11184 if (!TextUtils.isEmpty(stateDescription) 11185 && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 11186 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 11187 } 11188 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 11189 AccessibilityEvent event = AccessibilityEvent.obtain(); 11190 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 11191 event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION); 11192 sendAccessibilityEventUnchecked(event); 11193 } 11194 } 11195 11196 /** 11197 * Sets the {@link View}'s content description. 11198 * <p> 11199 * A content description briefly describes the view and is primarily used 11200 * for accessibility support to determine how a view should be presented to 11201 * the user. In the case of a view with no textual representation, such as 11202 * {@link android.widget.ImageButton}, a useful content description 11203 * explains what the view does. For example, an image button with a phone 11204 * icon that is used to place a call may use "Call" as its content 11205 * description. An image of a floppy disk that is used to save a file may 11206 * use "Save". 11207 * 11208 * <p> 11209 * This should omit role or state. Role refers to the kind of user-interface element the View 11210 * is, such as a Button or Checkbox. State refers to a frequently changing property of the View, 11211 * such as an On/Off state of a button or the audio level of a volume slider. 11212 * 11213 * <p> 11214 * Content description updates are not frequent, and are used when the semantic content - not 11215 * the state - of the element changes. For example, a Play button might change to a Pause 11216 * button during music playback. 11217 * 11218 * @param contentDescription The content description. 11219 * @see #getContentDescription() 11220 * @see #setStateDescription(CharSequence)} for state changes. 11221 * @attr ref android.R.styleable#View_contentDescription 11222 */ 11223 @RemotableViewMethod setContentDescription(CharSequence contentDescription)11224 public void setContentDescription(CharSequence contentDescription) { 11225 if (mContentDescription == null) { 11226 if (contentDescription == null) { 11227 return; 11228 } 11229 } else if (mContentDescription.equals(contentDescription)) { 11230 return; 11231 } 11232 mContentDescription = contentDescription; 11233 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 11234 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 11235 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 11236 notifySubtreeAccessibilityStateChangedIfNeeded(); 11237 } else { 11238 notifyViewAccessibilityStateChangedIfNeeded( 11239 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 11240 } 11241 } 11242 11243 /** 11244 * Sets the id of a view before which this one is visited in accessibility traversal. 11245 * A screen-reader must visit the content of this view before the content of the one 11246 * it precedes. For example, if view B is set to be before view A, then a screen-reader 11247 * will traverse the entire content of B before traversing the entire content of A, 11248 * regardles of what traversal strategy it is using. 11249 * <p> 11250 * Views that do not have specified before/after relationships are traversed in order 11251 * determined by the screen-reader. 11252 * </p> 11253 * <p> 11254 * Setting that this view is before a view that is not important for accessibility 11255 * or if this view is not important for accessibility will have no effect as the 11256 * screen-reader is not aware of unimportant views. 11257 * </p> 11258 * 11259 * @param beforeId The id of a view this one precedes in accessibility traversal. 11260 * 11261 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 11262 * 11263 * @see #setImportantForAccessibility(int) 11264 */ 11265 @RemotableViewMethod setAccessibilityTraversalBefore(@dRes int beforeId)11266 public void setAccessibilityTraversalBefore(@IdRes int beforeId) { 11267 if (mAccessibilityTraversalBeforeId == beforeId) { 11268 return; 11269 } 11270 mAccessibilityTraversalBeforeId = beforeId; 11271 notifyViewAccessibilityStateChangedIfNeeded( 11272 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11273 } 11274 11275 /** 11276 * Gets the id of a view before which this one is visited in accessibility traversal. 11277 * 11278 * @return The id of a view this one precedes in accessibility traversal if 11279 * specified, otherwise {@link #NO_ID}. 11280 * 11281 * @see #setAccessibilityTraversalBefore(int) 11282 */ 11283 @IdRes 11284 @InspectableProperty getAccessibilityTraversalBefore()11285 public int getAccessibilityTraversalBefore() { 11286 return mAccessibilityTraversalBeforeId; 11287 } 11288 11289 /** 11290 * Sets the id of a view after which this one is visited in accessibility traversal. 11291 * A screen-reader must visit the content of the other view before the content of this 11292 * one. For example, if view B is set to be after view A, then a screen-reader 11293 * will traverse the entire content of A before traversing the entire content of B, 11294 * regardles of what traversal strategy it is using. 11295 * <p> 11296 * Views that do not have specified before/after relationships are traversed in order 11297 * determined by the screen-reader. 11298 * </p> 11299 * <p> 11300 * Setting that this view is after a view that is not important for accessibility 11301 * or if this view is not important for accessibility will have no effect as the 11302 * screen-reader is not aware of unimportant views. 11303 * </p> 11304 * 11305 * @param afterId The id of a view this one succedees in accessibility traversal. 11306 * 11307 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 11308 * 11309 * @see #setImportantForAccessibility(int) 11310 */ 11311 @RemotableViewMethod setAccessibilityTraversalAfter(@dRes int afterId)11312 public void setAccessibilityTraversalAfter(@IdRes int afterId) { 11313 if (mAccessibilityTraversalAfterId == afterId) { 11314 return; 11315 } 11316 mAccessibilityTraversalAfterId = afterId; 11317 notifyViewAccessibilityStateChangedIfNeeded( 11318 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11319 } 11320 11321 /** 11322 * Gets the id of a view after which this one is visited in accessibility traversal. 11323 * 11324 * @return The id of a view this one succeedes in accessibility traversal if 11325 * specified, otherwise {@link #NO_ID}. 11326 * 11327 * @see #setAccessibilityTraversalAfter(int) 11328 */ 11329 @IdRes 11330 @InspectableProperty getAccessibilityTraversalAfter()11331 public int getAccessibilityTraversalAfter() { 11332 return mAccessibilityTraversalAfterId; 11333 } 11334 11335 /** 11336 * Gets the id of a view for which this view serves as a label for 11337 * accessibility purposes. 11338 * 11339 * @return The labeled view id. 11340 */ 11341 @IdRes 11342 @ViewDebug.ExportedProperty(category = "accessibility") 11343 @InspectableProperty getLabelFor()11344 public int getLabelFor() { 11345 return mLabelForId; 11346 } 11347 11348 /** 11349 * Sets the id of a view for which this view serves as a label for 11350 * accessibility purposes. 11351 * 11352 * @param id The labeled view id. 11353 */ 11354 @RemotableViewMethod setLabelFor(@dRes int id)11355 public void setLabelFor(@IdRes int id) { 11356 if (mLabelForId == id) { 11357 return; 11358 } 11359 mLabelForId = id; 11360 if (mLabelForId != View.NO_ID 11361 && mID == View.NO_ID) { 11362 mID = generateViewId(); 11363 } 11364 notifyViewAccessibilityStateChangedIfNeeded( 11365 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11366 } 11367 11368 /** 11369 * Invoked whenever this view loses focus, either by losing window focus or by losing 11370 * focus within its window. This method can be used to clear any state tied to the 11371 * focus. For instance, if a button is held pressed with the trackball and the window 11372 * loses focus, this method can be used to cancel the press. 11373 * 11374 * Subclasses of View overriding this method should always call super.onFocusLost(). 11375 * 11376 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 11377 * @see #onWindowFocusChanged(boolean) 11378 * 11379 * @hide pending API council approval 11380 */ 11381 @CallSuper 11382 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onFocusLost()11383 protected void onFocusLost() { 11384 resetPressedState(); 11385 } 11386 resetPressedState()11387 private void resetPressedState() { 11388 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 11389 return; 11390 } 11391 11392 if (isPressed()) { 11393 setPressed(false); 11394 11395 if (!mHasPerformedLongPress) { 11396 removeLongPressCallback(); 11397 } 11398 } 11399 } 11400 11401 /** 11402 * Returns true if this view has focus 11403 * 11404 * @return True if this view has focus, false otherwise. 11405 */ 11406 @ViewDebug.ExportedProperty(category = "focus") 11407 @InspectableProperty(hasAttributeId = false) isFocused()11408 public boolean isFocused() { 11409 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 11410 } 11411 11412 /** 11413 * Find the view in the hierarchy rooted at this view that currently has 11414 * focus. 11415 * 11416 * @return The view that currently has focus, or null if no focused view can 11417 * be found. 11418 */ findFocus()11419 public View findFocus() { 11420 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 11421 } 11422 11423 /** 11424 * Indicates whether this view is one of the set of scrollable containers in 11425 * its window. 11426 * 11427 * @return whether this view is one of the set of scrollable containers in 11428 * its window 11429 * 11430 * @attr ref android.R.styleable#View_isScrollContainer 11431 */ 11432 @InspectableProperty(name = "isScrollContainer") isScrollContainer()11433 public boolean isScrollContainer() { 11434 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 11435 } 11436 11437 /** 11438 * Change whether this view is one of the set of scrollable containers in 11439 * its window. This will be used to determine whether the window can 11440 * resize or must pan when a soft input area is open -- scrollable 11441 * containers allow the window to use resize mode since the container 11442 * will appropriately shrink. 11443 * 11444 * @attr ref android.R.styleable#View_isScrollContainer 11445 */ setScrollContainer(boolean isScrollContainer)11446 public void setScrollContainer(boolean isScrollContainer) { 11447 if (isScrollContainer) { 11448 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 11449 mAttachInfo.mScrollContainers.add(this); 11450 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 11451 } 11452 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 11453 } else { 11454 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 11455 mAttachInfo.mScrollContainers.remove(this); 11456 } 11457 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 11458 } 11459 } 11460 11461 /** 11462 * Returns the quality of the drawing cache. 11463 * 11464 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 11465 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 11466 * 11467 * @see #setDrawingCacheQuality(int) 11468 * @see #setDrawingCacheEnabled(boolean) 11469 * @see #isDrawingCacheEnabled() 11470 * 11471 * @attr ref android.R.styleable#View_drawingCacheQuality 11472 * 11473 * @deprecated The view drawing cache was largely made obsolete with the introduction of 11474 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 11475 * layers are largely unnecessary and can easily result in a net loss in performance due to the 11476 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 11477 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 11478 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 11479 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 11480 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 11481 * software-rendered usages are discouraged and have compatibility issues with hardware-only 11482 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 11483 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 11484 * reports or unit testing the {@link PixelCopy} API is recommended. 11485 */ 11486 @Deprecated 11487 @DrawingCacheQuality 11488 @InspectableProperty(enumMapping = { 11489 @EnumEntry(value = DRAWING_CACHE_QUALITY_LOW, name = "low"), 11490 @EnumEntry(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"), 11491 @EnumEntry(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto") 11492 }) getDrawingCacheQuality()11493 public int getDrawingCacheQuality() { 11494 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 11495 } 11496 11497 /** 11498 * Set the drawing cache quality of this view. This value is used only when the 11499 * drawing cache is enabled 11500 * 11501 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 11502 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 11503 * 11504 * @see #getDrawingCacheQuality() 11505 * @see #setDrawingCacheEnabled(boolean) 11506 * @see #isDrawingCacheEnabled() 11507 * 11508 * @attr ref android.R.styleable#View_drawingCacheQuality 11509 * 11510 * @deprecated The view drawing cache was largely made obsolete with the introduction of 11511 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 11512 * layers are largely unnecessary and can easily result in a net loss in performance due to the 11513 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 11514 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 11515 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 11516 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 11517 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 11518 * software-rendered usages are discouraged and have compatibility issues with hardware-only 11519 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 11520 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 11521 * reports or unit testing the {@link PixelCopy} API is recommended. 11522 */ 11523 @Deprecated setDrawingCacheQuality(@rawingCacheQuality int quality)11524 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 11525 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 11526 } 11527 11528 /** 11529 * Returns whether the screen should remain on, corresponding to the current 11530 * value of {@link #KEEP_SCREEN_ON}. 11531 * 11532 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 11533 * 11534 * @see #setKeepScreenOn(boolean) 11535 * 11536 * @attr ref android.R.styleable#View_keepScreenOn 11537 */ 11538 @InspectableProperty getKeepScreenOn()11539 public boolean getKeepScreenOn() { 11540 return (mViewFlags & KEEP_SCREEN_ON) != 0; 11541 } 11542 11543 /** 11544 * Controls whether the screen should remain on, modifying the 11545 * value of {@link #KEEP_SCREEN_ON}. 11546 * 11547 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 11548 * 11549 * @see #getKeepScreenOn() 11550 * 11551 * @attr ref android.R.styleable#View_keepScreenOn 11552 */ setKeepScreenOn(boolean keepScreenOn)11553 public void setKeepScreenOn(boolean keepScreenOn) { 11554 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 11555 } 11556 11557 /** 11558 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 11559 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11560 * 11561 * @attr ref android.R.styleable#View_nextFocusLeft 11562 */ 11563 @IdRes 11564 @InspectableProperty(name = "nextFocusLeft") getNextFocusLeftId()11565 public int getNextFocusLeftId() { 11566 return mNextFocusLeftId; 11567 } 11568 11569 /** 11570 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 11571 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 11572 * decide automatically. 11573 * 11574 * @attr ref android.R.styleable#View_nextFocusLeft 11575 */ setNextFocusLeftId(@dRes int nextFocusLeftId)11576 public void setNextFocusLeftId(@IdRes int nextFocusLeftId) { 11577 mNextFocusLeftId = nextFocusLeftId; 11578 } 11579 11580 /** 11581 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 11582 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11583 * 11584 * @attr ref android.R.styleable#View_nextFocusRight 11585 */ 11586 @IdRes 11587 @InspectableProperty(name = "nextFocusRight") getNextFocusRightId()11588 public int getNextFocusRightId() { 11589 return mNextFocusRightId; 11590 } 11591 11592 /** 11593 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 11594 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 11595 * decide automatically. 11596 * 11597 * @attr ref android.R.styleable#View_nextFocusRight 11598 */ setNextFocusRightId(@dRes int nextFocusRightId)11599 public void setNextFocusRightId(@IdRes int nextFocusRightId) { 11600 mNextFocusRightId = nextFocusRightId; 11601 } 11602 11603 /** 11604 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 11605 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11606 * 11607 * @attr ref android.R.styleable#View_nextFocusUp 11608 */ 11609 @IdRes 11610 @InspectableProperty(name = "nextFocusUp") getNextFocusUpId()11611 public int getNextFocusUpId() { 11612 return mNextFocusUpId; 11613 } 11614 11615 /** 11616 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 11617 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 11618 * decide automatically. 11619 * 11620 * @attr ref android.R.styleable#View_nextFocusUp 11621 */ setNextFocusUpId(@dRes int nextFocusUpId)11622 public void setNextFocusUpId(@IdRes int nextFocusUpId) { 11623 mNextFocusUpId = nextFocusUpId; 11624 } 11625 11626 /** 11627 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 11628 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11629 * 11630 * @attr ref android.R.styleable#View_nextFocusDown 11631 */ 11632 @IdRes 11633 @InspectableProperty(name = "nextFocusDown") getNextFocusDownId()11634 public int getNextFocusDownId() { 11635 return mNextFocusDownId; 11636 } 11637 11638 /** 11639 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 11640 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 11641 * decide automatically. 11642 * 11643 * @attr ref android.R.styleable#View_nextFocusDown 11644 */ setNextFocusDownId(@dRes int nextFocusDownId)11645 public void setNextFocusDownId(@IdRes int nextFocusDownId) { 11646 mNextFocusDownId = nextFocusDownId; 11647 } 11648 11649 /** 11650 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 11651 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11652 * 11653 * @attr ref android.R.styleable#View_nextFocusForward 11654 */ 11655 @IdRes 11656 @InspectableProperty(name = "nextFocusForward") getNextFocusForwardId()11657 public int getNextFocusForwardId() { 11658 return mNextFocusForwardId; 11659 } 11660 11661 /** 11662 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 11663 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 11664 * decide automatically. 11665 * 11666 * @attr ref android.R.styleable#View_nextFocusForward 11667 */ setNextFocusForwardId(@dRes int nextFocusForwardId)11668 public void setNextFocusForwardId(@IdRes int nextFocusForwardId) { 11669 mNextFocusForwardId = nextFocusForwardId; 11670 } 11671 11672 /** 11673 * Gets the id of the root of the next keyboard navigation cluster. 11674 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 11675 * decide automatically. 11676 * 11677 * @attr ref android.R.styleable#View_nextClusterForward 11678 */ 11679 @IdRes 11680 @InspectableProperty(name = "nextClusterForward") getNextClusterForwardId()11681 public int getNextClusterForwardId() { 11682 return mNextClusterForwardId; 11683 } 11684 11685 /** 11686 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 11687 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 11688 * decide automatically. 11689 * 11690 * @attr ref android.R.styleable#View_nextClusterForward 11691 */ setNextClusterForwardId(@dRes int nextClusterForwardId)11692 public void setNextClusterForwardId(@IdRes int nextClusterForwardId) { 11693 mNextClusterForwardId = nextClusterForwardId; 11694 } 11695 11696 /** 11697 * Returns the visibility of this view and all of its ancestors 11698 * 11699 * @return True if this view and all of its ancestors are {@link #VISIBLE} 11700 */ isShown()11701 public boolean isShown() { 11702 View current = this; 11703 //noinspection ConstantConditions 11704 do { 11705 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 11706 return false; 11707 } 11708 ViewParent parent = current.mParent; 11709 if (parent == null) { 11710 return false; // We are not attached to the view root 11711 } 11712 if (!(parent instanceof View)) { 11713 return true; 11714 } 11715 current = (View) parent; 11716 } while (current != null); 11717 11718 return false; 11719 } 11720 detached()11721 private boolean detached() { 11722 View current = this; 11723 //noinspection ConstantConditions 11724 do { 11725 if ((current.mPrivateFlags4 & PFLAG4_DETACHED) != 0) { 11726 return true; 11727 } 11728 ViewParent parent = current.mParent; 11729 if (parent == null) { 11730 return false; 11731 } 11732 if (!(parent instanceof View)) { 11733 return false; 11734 } 11735 current = (View) parent; 11736 } while (current != null); 11737 11738 return false; 11739 } 11740 11741 /** 11742 * Called by the view hierarchy when the content insets for a window have 11743 * changed, to allow it to adjust its content to fit within those windows. 11744 * The content insets tell you the space that the status bar, input method, 11745 * and other system windows infringe on the application's window. 11746 * 11747 * <p>You do not normally need to deal with this function, since the default 11748 * window decoration given to applications takes care of applying it to the 11749 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 11750 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 11751 * and your content can be placed under those system elements. You can then 11752 * use this method within your view hierarchy if you have parts of your UI 11753 * which you would like to ensure are not being covered. 11754 * 11755 * <p>The default implementation of this method simply applies the content 11756 * insets to the view's padding, consuming that content (modifying the 11757 * insets to be 0), and returning true. This behavior is off by default, but can 11758 * be enabled through {@link #setFitsSystemWindows(boolean)}. 11759 * 11760 * <p>This function's traversal down the hierarchy is depth-first. The same content 11761 * insets object is propagated down the hierarchy, so any changes made to it will 11762 * be seen by all following views (including potentially ones above in 11763 * the hierarchy since this is a depth-first traversal). The first view 11764 * that returns true will abort the entire traversal. 11765 * 11766 * <p>The default implementation works well for a situation where it is 11767 * used with a container that covers the entire window, allowing it to 11768 * apply the appropriate insets to its content on all edges. If you need 11769 * a more complicated layout (such as two different views fitting system 11770 * windows, one on the top of the window, and one on the bottom), 11771 * you can override the method and handle the insets however you would like. 11772 * Note that the insets provided by the framework are always relative to the 11773 * far edges of the window, not accounting for the location of the called view 11774 * within that window. (In fact when this method is called you do not yet know 11775 * where the layout will place the view, as it is done before layout happens.) 11776 * 11777 * <p>Note: unlike many View methods, there is no dispatch phase to this 11778 * call. If you are overriding it in a ViewGroup and want to allow the 11779 * call to continue to your children, you must be sure to call the super 11780 * implementation. 11781 * 11782 * <p>Here is a sample layout that makes use of fitting system windows 11783 * to have controls for a video view placed inside of the window decorations 11784 * that it hides and shows. This can be used with code like the second 11785 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 11786 * 11787 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 11788 * 11789 * @param insets Current content insets of the window. Prior to 11790 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 11791 * the insets or else you and Android will be unhappy. 11792 * 11793 * @return {@code true} if this view applied the insets and it should not 11794 * continue propagating further down the hierarchy, {@code false} otherwise. 11795 * @see #getFitsSystemWindows() 11796 * @see #setFitsSystemWindows(boolean) 11797 * @see #setSystemUiVisibility(int) 11798 * 11799 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 11800 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 11801 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 11802 * to implement handling their own insets. 11803 */ 11804 @Deprecated fitSystemWindows(Rect insets)11805 protected boolean fitSystemWindows(Rect insets) { 11806 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 11807 if (insets == null) { 11808 // Null insets by definition have already been consumed. 11809 // This call cannot apply insets since there are none to apply, 11810 // so return false. 11811 return false; 11812 } 11813 // If we're not in the process of dispatching the newer apply insets call, 11814 // that means we're not in the compatibility path. Dispatch into the newer 11815 // apply insets path and take things from there. 11816 try { 11817 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 11818 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 11819 } finally { 11820 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 11821 } 11822 } else { 11823 // We're being called from the newer apply insets path. 11824 // Perform the standard fallback behavior. 11825 return fitSystemWindowsInt(insets); 11826 } 11827 } 11828 fitSystemWindowsInt(Rect insets)11829 private boolean fitSystemWindowsInt(Rect insets) { 11830 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 11831 Rect localInsets = sThreadLocal.get(); 11832 boolean res = computeFitSystemWindows(insets, localInsets); 11833 applyInsets(localInsets); 11834 return res; 11835 } 11836 return false; 11837 } 11838 applyInsets(Rect insets)11839 private void applyInsets(Rect insets) { 11840 mUserPaddingStart = UNDEFINED_PADDING; 11841 mUserPaddingEnd = UNDEFINED_PADDING; 11842 mUserPaddingLeftInitial = insets.left; 11843 mUserPaddingRightInitial = insets.right; 11844 internalSetPadding(insets.left, insets.top, insets.right, insets.bottom); 11845 } 11846 11847 /** 11848 * Called when the view should apply {@link WindowInsets} according to its internal policy. 11849 * 11850 * <p>This method should be overridden by views that wish to apply a policy different from or 11851 * in addition to the default behavior. Clients that wish to force a view subtree 11852 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 11853 * 11854 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 11855 * it will be called during dispatch instead of this method. The listener may optionally 11856 * call this method from its own implementation if it wishes to apply the view's default 11857 * insets policy in addition to its own.</p> 11858 * 11859 * <p>Implementations of this method should either return the insets parameter unchanged 11860 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 11861 * that this view applied itself. This allows new inset types added in future platform 11862 * versions to pass through existing implementations unchanged without being erroneously 11863 * consumed.</p> 11864 * 11865 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 11866 * property is set then the view will consume the system window insets and apply them 11867 * as padding for the view.</p> 11868 * 11869 * @param insets Insets to apply 11870 * @return The supplied insets with any applied insets consumed 11871 */ onApplyWindowInsets(WindowInsets insets)11872 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 11873 if ((mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 11874 && (mViewFlags & FITS_SYSTEM_WINDOWS) != 0) { 11875 return onApplyFrameworkOptionalFitSystemWindows(insets); 11876 } 11877 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 11878 // We weren't called from within a direct call to fitSystemWindows, 11879 // call into it as a fallback in case we're in a class that overrides it 11880 // and has logic to perform. 11881 if (fitSystemWindows(insets.getSystemWindowInsetsAsRect())) { 11882 return insets.consumeSystemWindowInsets(); 11883 } 11884 } else { 11885 // We were called from within a direct call to fitSystemWindows. 11886 if (fitSystemWindowsInt(insets.getSystemWindowInsetsAsRect())) { 11887 return insets.consumeSystemWindowInsets(); 11888 } 11889 } 11890 return insets; 11891 } 11892 onApplyFrameworkOptionalFitSystemWindows(WindowInsets insets)11893 private WindowInsets onApplyFrameworkOptionalFitSystemWindows(WindowInsets insets) { 11894 Rect localInsets = sThreadLocal.get(); 11895 WindowInsets result = computeSystemWindowInsets(insets, localInsets); 11896 applyInsets(localInsets); 11897 return result; 11898 } 11899 11900 /** 11901 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 11902 * window insets to this view. The listener's 11903 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 11904 * method will be called instead of the view's 11905 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 11906 * 11907 * @param listener Listener to set 11908 * 11909 * @see #onApplyWindowInsets(WindowInsets) 11910 */ setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener)11911 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 11912 getListenerInfo().mOnApplyWindowInsetsListener = listener; 11913 } 11914 11915 /** 11916 * Request to apply the given window insets to this view or another view in its subtree. 11917 * 11918 * <p>This method should be called by clients wishing to apply insets corresponding to areas 11919 * obscured by window decorations or overlays. This can include the status and navigation bars, 11920 * action bars, input methods and more. New inset categories may be added in the future. 11921 * The method returns the insets provided minus any that were applied by this view or its 11922 * children.</p> 11923 * 11924 * <p>Clients wishing to provide custom behavior should override the 11925 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 11926 * {@link OnApplyWindowInsetsListener} via the 11927 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 11928 * method.</p> 11929 * 11930 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 11931 * </p> 11932 * 11933 * @param insets Insets to apply 11934 * @return The provided insets minus the insets that were consumed 11935 */ dispatchApplyWindowInsets(WindowInsets insets)11936 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 11937 try { 11938 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 11939 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 11940 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 11941 } else { 11942 return onApplyWindowInsets(insets); 11943 } 11944 } finally { 11945 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 11946 } 11947 } 11948 11949 /** 11950 * Sets a {@link WindowInsetsAnimation.Callback} to be notified about animations of windows that 11951 * cause insets. 11952 * <p> 11953 * The callback's {@link WindowInsetsAnimation.Callback#getDispatchMode() 11954 * dispatch mode} will affect whether animation callbacks are dispatched to the children of 11955 * this view. 11956 * </p> 11957 * @param callback The callback to set. 11958 */ setWindowInsetsAnimationCallback( @ullable WindowInsetsAnimation.Callback callback)11959 public void setWindowInsetsAnimationCallback( 11960 @Nullable WindowInsetsAnimation.Callback callback) { 11961 getListenerInfo().mWindowInsetsAnimationCallback = callback; 11962 } 11963 11964 /** 11965 * @return {@code true} if any {@link WindowInsetsAnimation.Callback} is registered on the view 11966 * or view tree of the sub-hierarchy {@code false} otherwise. 11967 * @hide 11968 */ hasWindowInsetsAnimationCallback()11969 public boolean hasWindowInsetsAnimationCallback() { 11970 return getListenerInfo().mWindowInsetsAnimationCallback != null; 11971 } 11972 11973 /** 11974 * Dispatches {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)} 11975 * when Window Insets animation is being prepared. 11976 * @param animation current animation 11977 * 11978 * @see WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation) 11979 */ dispatchWindowInsetsAnimationPrepare( @onNull WindowInsetsAnimation animation)11980 public void dispatchWindowInsetsAnimationPrepare( 11981 @NonNull WindowInsetsAnimation animation) { 11982 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11983 mListenerInfo.mWindowInsetsAnimationCallback.onPrepare(animation); 11984 } 11985 } 11986 11987 /** 11988 * Dispatches {@link WindowInsetsAnimation.Callback#onStart(WindowInsetsAnimation, Bounds)} 11989 * when Window Insets animation is started. 11990 * @param animation current animation 11991 * @param bounds the upper and lower {@link Bounds} that provides range of 11992 * {@link WindowInsetsAnimation}. 11993 * @return the upper and lower {@link Bounds}. 11994 */ 11995 @NonNull dispatchWindowInsetsAnimationStart( @onNull WindowInsetsAnimation animation, @NonNull Bounds bounds)11996 public Bounds dispatchWindowInsetsAnimationStart( 11997 @NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds) { 11998 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11999 return mListenerInfo.mWindowInsetsAnimationCallback.onStart(animation, bounds); 12000 } 12001 return bounds; 12002 } 12003 12004 /** 12005 * Dispatches {@link WindowInsetsAnimation.Callback#onProgress(WindowInsets, List)} 12006 * when Window Insets animation makes progress. 12007 * @param insets The current {@link WindowInsets}. 12008 * @param runningAnimations The currently running {@link WindowInsetsAnimation}s. 12009 * @return current {@link WindowInsets}. 12010 */ 12011 @NonNull dispatchWindowInsetsAnimationProgress(@onNull WindowInsets insets, @NonNull List<WindowInsetsAnimation> runningAnimations)12012 public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets, 12013 @NonNull List<WindowInsetsAnimation> runningAnimations) { 12014 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 12015 return mListenerInfo.mWindowInsetsAnimationCallback.onProgress(insets, 12016 runningAnimations); 12017 } else { 12018 return insets; 12019 } 12020 } 12021 12022 /** 12023 * Dispatches {@link WindowInsetsAnimation.Callback#onEnd(WindowInsetsAnimation)} 12024 * when Window Insets animation ends. 12025 * @param animation The current ongoing {@link WindowInsetsAnimation}. 12026 */ dispatchWindowInsetsAnimationEnd(@onNull WindowInsetsAnimation animation)12027 public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) { 12028 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 12029 mListenerInfo.mWindowInsetsAnimationCallback.onEnd(animation); 12030 } 12031 } 12032 12033 /** 12034 * Sets a list of areas within this view's post-layout coordinate space where the system 12035 * should not intercept touch or other pointing device gestures. <em>This method should 12036 * be called by {@link #onLayout(boolean, int, int, int, int)} or {@link #onDraw(Canvas)}.</em> 12037 * 12038 * <p>Use this to tell the system which specific sub-areas of a view need to receive gesture 12039 * input in order to function correctly in the presence of global system gestures that may 12040 * conflict. For example, if the system wishes to capture swipe-in-from-screen-edge gestures 12041 * to provide system-level navigation functionality, a view such as a navigation drawer 12042 * container can mark the left (or starting) edge of itself as requiring gesture capture 12043 * priority using this API. The system may then choose to relax its own gesture recognition 12044 * to allow the app to consume the user's gesture. It is not necessary for an app to register 12045 * exclusion rects for broadly spanning regions such as the entirety of a 12046 * <code>ScrollView</code> or for simple press and release click targets such as 12047 * <code>Button</code>. Mark an exclusion rect when interacting with a view requires 12048 * a precision touch gesture in a small area in either the X or Y dimension, such as 12049 * an edge swipe or dragging a <code>SeekBar</code> thumb.</p> 12050 * 12051 * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the 12052 * exclusions it takes into account. The limit does not apply while the navigation 12053 * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the 12054 * {@link android.inputmethodservice.InputMethodService input method} and 12055 * {@link Intent#CATEGORY_HOME home activity}. 12056 * </p> 12057 * 12058 * @param rects A list of precision gesture regions that this view needs to function correctly 12059 */ setSystemGestureExclusionRects(@onNull List<Rect> rects)12060 public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) { 12061 if (rects.isEmpty() && mListenerInfo == null) return; 12062 12063 final ListenerInfo info = getListenerInfo(); 12064 if (info.mSystemGestureExclusionRects != null) { 12065 info.mSystemGestureExclusionRects.clear(); 12066 info.mSystemGestureExclusionRects.addAll(rects); 12067 } else { 12068 info.mSystemGestureExclusionRects = new ArrayList<>(rects); 12069 } 12070 12071 updatePositionUpdateListener(); 12072 postUpdate(this::updateSystemGestureExclusionRects); 12073 } 12074 updatePositionUpdateListener()12075 private void updatePositionUpdateListener() { 12076 final ListenerInfo info = getListenerInfo(); 12077 if (getSystemGestureExclusionRects().isEmpty() 12078 && collectPreferKeepClearRects().isEmpty() 12079 && collectUnrestrictedPreferKeepClearRects().isEmpty() 12080 && (info.mHandwritingArea == null || !shouldInitiateHandwriting())) { 12081 if (info.mPositionUpdateListener != null) { 12082 mRenderNode.removePositionUpdateListener(info.mPositionUpdateListener); 12083 info.mPositionUpdateListener = null; 12084 info.mPositionChangedUpdate = null; 12085 } 12086 } else { 12087 if (info.mPositionUpdateListener == null) { 12088 info.mPositionChangedUpdate = () -> { 12089 updateSystemGestureExclusionRects(); 12090 updateKeepClearRects(); 12091 updateHandwritingArea(); 12092 }; 12093 info.mPositionUpdateListener = new RenderNode.PositionUpdateListener() { 12094 @Override 12095 public void positionChanged(long n, int l, int t, int r, int b) { 12096 postUpdate(info.mPositionChangedUpdate); 12097 } 12098 12099 @Override 12100 public void positionLost(long frameNumber) { 12101 postUpdate(info.mPositionChangedUpdate); 12102 } 12103 }; 12104 mRenderNode.addPositionUpdateListener(info.mPositionUpdateListener); 12105 } 12106 } 12107 } 12108 12109 /** 12110 * WARNING: this can be called by a hwui worker thread, not just the UI thread! 12111 */ postUpdate(Runnable r)12112 private void postUpdate(Runnable r) { 12113 // Potentially racey from a background thread. It's ok if it's not perfect. 12114 final Handler h = getHandler(); 12115 if (h != null) { 12116 h.postAtFrontOfQueue(r); 12117 } 12118 } 12119 updateSystemGestureExclusionRects()12120 void updateSystemGestureExclusionRects() { 12121 final AttachInfo ai = mAttachInfo; 12122 if (ai != null) { 12123 ai.mViewRootImpl.updateSystemGestureExclusionRectsForView(this); 12124 } 12125 } 12126 12127 /** 12128 * Retrieve the list of areas within this view's post-layout coordinate space where the system 12129 * should not intercept touch or other pointing device gestures. 12130 * 12131 * <p>Do not modify the returned list.</p> 12132 * 12133 * @return the list set by {@link #setSystemGestureExclusionRects(List)} 12134 */ 12135 @NonNull getSystemGestureExclusionRects()12136 public List<Rect> getSystemGestureExclusionRects() { 12137 final ListenerInfo info = mListenerInfo; 12138 if (info != null) { 12139 final List<Rect> list = info.mSystemGestureExclusionRects; 12140 if (list != null) { 12141 return list; 12142 } 12143 } 12144 return Collections.emptyList(); 12145 } 12146 12147 /** 12148 * Set a preference to keep the bounds of this view clear from floating windows above this 12149 * view's window. This informs the system that the view is considered a vital area for the 12150 * user and that ideally it should not be covered. Setting this is only appropriate for UI 12151 * where the user would likely take action to uncover it. 12152 * <p> 12153 * The system will try to respect this preference, but when not possible will ignore it. 12154 * <p> 12155 * Note: This is independent from {@link #setPreferKeepClearRects}. If both are set, both will 12156 * be taken into account. 12157 * <p> 12158 * @see #setPreferKeepClearRects 12159 * @see #isPreferKeepClear 12160 * @attr ref android.R.styleable#View_preferKeepClear 12161 */ setPreferKeepClear(boolean preferKeepClear)12162 public final void setPreferKeepClear(boolean preferKeepClear) { 12163 getListenerInfo().mPreferKeepClear = preferKeepClear; 12164 updatePositionUpdateListener(); 12165 postUpdate(this::updateKeepClearRects); 12166 } 12167 12168 /** 12169 * Retrieve the preference for this view to be kept clear. This is set either by 12170 * {@link #setPreferKeepClear} or via the attribute android.R.styleable#View_preferKeepClear. 12171 * <p> 12172 * If this is {@code true}, the system will ignore the Rects set by 12173 * {@link #setPreferKeepClearRects} and try to keep the whole view clear. 12174 * <p> 12175 * @see #setPreferKeepClear 12176 * @attr ref android.R.styleable#View_preferKeepClear 12177 */ isPreferKeepClear()12178 public final boolean isPreferKeepClear() { 12179 return mListenerInfo != null && mListenerInfo.mPreferKeepClear; 12180 } 12181 12182 /** 12183 * Set a preference to keep the provided rects clear from floating windows above this 12184 * view's window. This informs the system that these rects are considered vital areas for the 12185 * user and that ideally they should not be covered. Setting this is only appropriate for UI 12186 * where the user would likely take action to uncover it. 12187 * <p> 12188 * The system will try to respect this preference, but when not possible will ignore it. 12189 * <p> 12190 * Note: This is independent from {@link #setPreferKeepClear}. If both are set, both will be 12191 * taken into account. 12192 * <p> 12193 * @see #setPreferKeepClear 12194 * @see #getPreferKeepClearRects 12195 * 12196 * @param rects A list of rects in this view's local coordinate system 12197 */ setPreferKeepClearRects(@onNull List<Rect> rects)12198 public final void setPreferKeepClearRects(@NonNull List<Rect> rects) { 12199 final ListenerInfo info = getListenerInfo(); 12200 if (info.mKeepClearRects != null) { 12201 info.mKeepClearRects.clear(); 12202 info.mKeepClearRects.addAll(rects); 12203 } else { 12204 info.mKeepClearRects = new ArrayList<>(rects); 12205 } 12206 updatePositionUpdateListener(); 12207 postUpdate(this::updateKeepClearRects); 12208 } 12209 12210 /** 12211 * @return the list of rects, set by {@link #setPreferKeepClearRects}. 12212 * 12213 * @see #setPreferKeepClearRects 12214 */ 12215 @NonNull getPreferKeepClearRects()12216 public final List<Rect> getPreferKeepClearRects() { 12217 final ListenerInfo info = mListenerInfo; 12218 if (info != null && info.mKeepClearRects != null) { 12219 return new ArrayList(info.mKeepClearRects); 12220 } 12221 12222 return Collections.emptyList(); 12223 } 12224 12225 /** 12226 * Set a preference to keep the provided rects clear from floating windows above this 12227 * view's window. This informs the system that these rects are considered vital areas for the 12228 * user and that ideally they should not be covered. Setting this is only appropriate for UI 12229 * where the user would likely take action to uncover it. 12230 * <p> 12231 * Note: The difference with {@link #setPreferKeepClearRects} is that the system won't apply 12232 * restrictions to the rects set here. 12233 * <p> 12234 * @see #setPreferKeepClear 12235 * @see #getPreferKeepClearRects 12236 * 12237 * @param rects A list of rects in this view's local coordinate system 12238 * 12239 * @hide 12240 */ 12241 @SystemApi 12242 @RequiresPermission(android.Manifest.permission.SET_UNRESTRICTED_KEEP_CLEAR_AREAS) setUnrestrictedPreferKeepClearRects(@onNull List<Rect> rects)12243 public final void setUnrestrictedPreferKeepClearRects(@NonNull List<Rect> rects) { 12244 final ListenerInfo info = getListenerInfo(); 12245 if (info.mUnrestrictedKeepClearRects != null) { 12246 info.mUnrestrictedKeepClearRects.clear(); 12247 info.mUnrestrictedKeepClearRects.addAll(rects); 12248 } else { 12249 info.mUnrestrictedKeepClearRects = new ArrayList<>(rects); 12250 } 12251 updatePositionUpdateListener(); 12252 postUpdate(this::updateKeepClearRects); 12253 } 12254 12255 /** 12256 * @return the list of rects, set by {@link #setPreferKeepClearRects}. 12257 * 12258 * @see #setPreferKeepClearRects 12259 * 12260 * @hide 12261 */ 12262 @SystemApi 12263 @NonNull getUnrestrictedPreferKeepClearRects()12264 public final List<Rect> getUnrestrictedPreferKeepClearRects() { 12265 final ListenerInfo info = mListenerInfo; 12266 if (info != null && info.mUnrestrictedKeepClearRects != null) { 12267 return new ArrayList(info.mUnrestrictedKeepClearRects); 12268 } 12269 12270 return Collections.emptyList(); 12271 } 12272 updateKeepClearRects()12273 void updateKeepClearRects() { 12274 final AttachInfo ai = mAttachInfo; 12275 if (ai != null) { 12276 ai.mViewRootImpl.updateKeepClearRectsForView(this); 12277 } 12278 } 12279 12280 /** 12281 * Retrieve the list of areas within this view's post-layout coordinate space which the 12282 * system will try to not cover with other floating elements, like the pip window. 12283 */ 12284 @NonNull collectPreferKeepClearRects()12285 List<Rect> collectPreferKeepClearRects() { 12286 ListenerInfo info = mListenerInfo; 12287 boolean keepClearForFocus = isFocused() 12288 && ViewConfiguration.get(mContext).isPreferKeepClearForFocusEnabled(); 12289 boolean keepBoundsClear = (info != null && info.mPreferKeepClear) || keepClearForFocus; 12290 boolean hasCustomKeepClearRects = info != null && info.mKeepClearRects != null; 12291 12292 if (!keepBoundsClear && !hasCustomKeepClearRects) { 12293 return Collections.emptyList(); 12294 } else if (keepBoundsClear && !hasCustomKeepClearRects) { 12295 return Collections.singletonList(new Rect(0, 0, getWidth(), getHeight())); 12296 } 12297 12298 final List<Rect> list = new ArrayList<>(); 12299 if (keepBoundsClear) { 12300 list.add(new Rect(0, 0, getWidth(), getHeight())); 12301 } 12302 12303 if (hasCustomKeepClearRects) { 12304 list.addAll(info.mKeepClearRects); 12305 } 12306 12307 return list; 12308 } 12309 updatePreferKeepClearForFocus()12310 private void updatePreferKeepClearForFocus() { 12311 if (ViewConfiguration.get(mContext).isPreferKeepClearForFocusEnabled()) { 12312 updatePositionUpdateListener(); 12313 post(this::updateKeepClearRects); 12314 } 12315 } 12316 12317 /** 12318 * Retrieve the list of unrestricted areas within this view's post-layout coordinate space 12319 * which the system will try to not cover with other floating elements, like the pip window. 12320 */ 12321 @NonNull collectUnrestrictedPreferKeepClearRects()12322 List<Rect> collectUnrestrictedPreferKeepClearRects() { 12323 final ListenerInfo info = mListenerInfo; 12324 if (info != null && info.mUnrestrictedKeepClearRects != null) { 12325 return info.mUnrestrictedKeepClearRects; 12326 } 12327 12328 return Collections.emptyList(); 12329 } 12330 12331 /** 12332 * Set the amount of offset applied to this view's stylus handwriting bounds. A positive offset 12333 * will offset the edge outwards.The base handwriting bounds of a view is its visible bounds. 12334 * The handwriting bounds offsets are applied to the base handwriting bounds to determine the 12335 * final handwriting bounds. 12336 * <p> This method is mainly used to enlarge the view's handwriting bounds for a better user 12337 * experience. 12338 * <p> Note that when the view is clipped (e.g. the view is in a 12339 * {@link android.widget.ScrollView}), the offsets are applied after the view's handwriting 12340 * bounds is clipped. 12341 * 12342 * @param offsetLeft the amount of pixel offset applied to the left edge outwards of the view's 12343 * handwriting bounds. 12344 * @param offsetTop the amount of pixel offset applied to the top edge outwards of the view's 12345 * handwriting bounds. 12346 * @param offsetRight the amount of pixel offset applied to the right edge outwards of the 12347 * view's handwriting bounds. 12348 * @param offsetBottom the amount of pixel offset applied to the bottom edge outwards of the 12349 * view's handwriting bounds. 12350 * 12351 * @see #setAutoHandwritingEnabled(boolean) 12352 * @see #getHandwritingBoundsOffsetLeft() 12353 * @see #getHandwritingBoundsOffsetTop() 12354 * @see #getHandwritingBoundsOffsetRight() 12355 * @see #getHandwritingBoundsOffsetBottom() 12356 */ setHandwritingBoundsOffsets(float offsetLeft, float offsetTop, float offsetRight, float offsetBottom)12357 public void setHandwritingBoundsOffsets(float offsetLeft, float offsetTop, 12358 float offsetRight, float offsetBottom) { 12359 mHandwritingBoundsOffsetLeft = offsetLeft; 12360 mHandwritingBoundsOffsetTop = offsetTop; 12361 mHandwritingBoundsOffsetRight = offsetRight; 12362 mHandwritingBoundsOffsetBottom = offsetBottom; 12363 } 12364 12365 /** 12366 * Return the amount of offset applied to the left edge of this view's handwriting bounds, 12367 * in the unit of pixel. 12368 * 12369 * @see #setAutoHandwritingEnabled(boolean) 12370 * @see #setHandwritingBoundsOffsets(float, float, float, float) 12371 */ getHandwritingBoundsOffsetLeft()12372 public float getHandwritingBoundsOffsetLeft() { 12373 return mHandwritingBoundsOffsetLeft; 12374 } 12375 12376 /** 12377 * Return the amount of offset applied to the top edge of this view's handwriting bounds, 12378 * in the unit of pixel. 12379 * 12380 * @see #setAutoHandwritingEnabled(boolean) 12381 * @see #setHandwritingBoundsOffsets(float, float, float, float) 12382 */ getHandwritingBoundsOffsetTop()12383 public float getHandwritingBoundsOffsetTop() { 12384 return mHandwritingBoundsOffsetTop; 12385 } 12386 12387 /** 12388 * Return the amount of offset applied to the right edge of this view's handwriting bounds, in 12389 * the unit of pixel. 12390 * 12391 * @see #setAutoHandwritingEnabled(boolean) 12392 * @see #setHandwritingBoundsOffsets(float, float, float, float) 12393 */ getHandwritingBoundsOffsetRight()12394 public float getHandwritingBoundsOffsetRight() { 12395 return mHandwritingBoundsOffsetRight; 12396 } 12397 12398 /** 12399 * Return the amount of offset applied to the bottom edge of this view's handwriting bounds, in 12400 * the unit of pixel. 12401 * 12402 * @see #setAutoHandwritingEnabled(boolean) 12403 * @see #setHandwritingBoundsOffsets(float, float, float, float) 12404 */ getHandwritingBoundsOffsetBottom()12405 public float getHandwritingBoundsOffsetBottom() { 12406 return mHandwritingBoundsOffsetBottom; 12407 } 12408 12409 12410 /** 12411 * Set a handwriting area in this view. If there is any stylus {@link MotionEvent} 12412 * occurs within this area, it will trigger stylus handwriting mode. This can be disabled by 12413 * disabling the auto handwriting initiation by calling 12414 * {@link #setAutoHandwritingEnabled(boolean)} with false. 12415 * 12416 * @attr rect the handwriting area in the view's local coordiniates. 12417 * 12418 * @see android.view.inputmethod.InputMethodManager#startStylusHandwriting(View) 12419 * @see #setAutoHandwritingEnabled(boolean) 12420 * 12421 * @hide 12422 */ setHandwritingArea(@ullable Rect rect)12423 public void setHandwritingArea(@Nullable Rect rect) { 12424 final ListenerInfo info = getListenerInfo(); 12425 info.mHandwritingArea = rect; 12426 updatePositionUpdateListener(); 12427 postUpdate(this::updateHandwritingArea); 12428 } 12429 12430 /** 12431 * Return the handwriting areas set on this view, in its local coordinates. 12432 * @see #setHandwritingArea(Rect) 12433 * 12434 * @hide 12435 */ 12436 @Nullable getHandwritingArea()12437 public Rect getHandwritingArea() { 12438 final ListenerInfo info = mListenerInfo; 12439 if (info != null && info.mHandwritingArea != null) { 12440 return new Rect(info.mHandwritingArea); 12441 } 12442 return null; 12443 } 12444 updateHandwritingArea()12445 void updateHandwritingArea() { 12446 // If autoHandwritingArea is not enabled, do nothing. 12447 if (!shouldInitiateHandwriting()) return; 12448 final AttachInfo ai = mAttachInfo; 12449 if (ai != null) { 12450 ai.mViewRootImpl.getHandwritingInitiator().updateHandwritingAreasForView(this); 12451 } 12452 } 12453 12454 /** 12455 * Returns true if a stylus {@link MotionEvent} within this view's bounds should initiate 12456 * handwriting mode, either for this view ({@link #isAutoHandwritingEnabled()} is {@code true}) 12457 * or for a handwriting delegate view ({@link #getHandwritingDelegatorCallback()} is not {@code 12458 * null}). 12459 */ shouldInitiateHandwriting()12460 boolean shouldInitiateHandwriting() { 12461 return isAutoHandwritingEnabled() || getHandwritingDelegatorCallback() != null; 12462 } 12463 12464 /** 12465 * Sets a callback which should be called when a stylus {@link MotionEvent} occurs within this 12466 * view's bounds. The callback will be called from the UI thread. 12467 * 12468 * <p>Setting a callback allows this view to act as a handwriting delegator, so that handwriting 12469 * mode for a delegate editor view can be initiated by stylus movement on this delegator view. 12470 * The callback implementation is expected to show and focus the delegate editor view. If a view 12471 * which returns {@code true} for {@link #isHandwritingDelegate()} creates an input connection 12472 * while the same stylus {@link MotionEvent} sequence is ongoing, handwriting mode will be 12473 * initiated for that view. 12474 * 12475 * <p>A common use case is a custom view which looks like a text editor but does not actually 12476 * support text editing itself, and clicking on the custom view causes an EditText to be shown. 12477 * To support handwriting initiation in this case, this method can be called on the custom view 12478 * to configure it as a delegator. The EditText should call {@link #setIsHandwritingDelegate} to 12479 * set it as a delegate. The {@code callback} implementation is typically the same as the click 12480 * listener implementation which shows the EditText. 12481 * 12482 * <p>If {@code null} is passed, this view will no longer act as a handwriting initiation 12483 * delegator. 12484 * 12485 * @param callback a callback which should be called when a stylus {@link MotionEvent} occurs 12486 * within this view's bounds 12487 */ setHandwritingDelegatorCallback(@ullable Runnable callback)12488 public void setHandwritingDelegatorCallback(@Nullable Runnable callback) { 12489 mHandwritingDelegatorCallback = callback; 12490 if (callback != null) { 12491 setHandwritingArea(new Rect(0, 0, getWidth(), getHeight())); 12492 } 12493 } 12494 12495 /** 12496 * Returns the callback set by {@link #setHandwritingDelegatorCallback} which should be called 12497 * when a stylus {@link MotionEvent} occurs within this view's bounds. The callback should only 12498 * be called from the UI thread. 12499 */ 12500 @Nullable getHandwritingDelegatorCallback()12501 public Runnable getHandwritingDelegatorCallback() { 12502 return mHandwritingDelegatorCallback; 12503 } 12504 12505 /** 12506 * Specifies that this view may act as a handwriting initiation delegator for a delegate editor 12507 * view from the specified package. If this method is not called, delegators may only be used to 12508 * initiate handwriting mode for a delegate editor view from the same package as the delegator 12509 * view. This method allows specifying a different trusted package which may contain a delegate 12510 * editor view linked to this delegator view. 12511 * 12512 * <p>This method has no effect unless {@link #setHandwritingDelegatorCallback} is also called 12513 * to configure this view to act as a handwriting delegator. 12514 * 12515 * <p>If this method is called on the delegator view, then {@link 12516 * #setAllowedHandwritingDelegatorPackage} should also be called on the delegate editor view. 12517 * 12518 * <p>For example, to configure a delegator view in package 1: 12519 * 12520 * <pre> 12521 * delegatorView.setHandwritingDelegatorCallback(callback); 12522 * delegatorView.setAllowedHandwritingDelegatePackage(package2);</pre> 12523 * 12524 * Then to configure the corresponding delegate editor view in package 2: 12525 * 12526 * <pre> 12527 * delegateEditorView.setIsHandwritingDelegate(true); 12528 * delegateEditorView.setAllowedHandwritingDelegatorPackage(package1);</pre> 12529 * 12530 * @param allowedPackageName the package name of a delegate editor view linked to this delegator 12531 * view, or {@code null} to restore the default behavior of only allowing delegate editor 12532 * views from the same package as this delegator view 12533 */ setAllowedHandwritingDelegatePackage(@ullable String allowedPackageName)12534 public void setAllowedHandwritingDelegatePackage(@Nullable String allowedPackageName) { 12535 mAllowedHandwritingDelegatePackageName = allowedPackageName; 12536 } 12537 12538 /** 12539 * Returns the allowed package for delegate editor views for which this view may act as a 12540 * handwriting delegator, as set by {@link #setAllowedHandwritingDelegatePackage}. If {@link 12541 * #setAllowedHandwritingDelegatePackage} has not been called, or called with {@code null} 12542 * argument, this will return {@code null}, meaning that this delegator view may only be used to 12543 * initiate handwriting mode for a delegate editor view from the same package as this delegator 12544 * view. 12545 */ 12546 @Nullable getAllowedHandwritingDelegatePackageName()12547 public String getAllowedHandwritingDelegatePackageName() { 12548 return mAllowedHandwritingDelegatePackageName; 12549 } 12550 12551 /** 12552 * Sets this view to be a handwriting delegate. If a delegate view creates an input connection 12553 * while a stylus {@link MotionEvent} sequence from a delegator view is ongoing, handwriting 12554 * mode will be initiated for the delegate view. 12555 * 12556 * @param isHandwritingDelegate whether this view is a handwriting initiation delegate 12557 * @see #setHandwritingDelegatorCallback(Runnable) 12558 */ setIsHandwritingDelegate(boolean isHandwritingDelegate)12559 public void setIsHandwritingDelegate(boolean isHandwritingDelegate) { 12560 mIsHandwritingDelegate = isHandwritingDelegate; 12561 } 12562 12563 /** 12564 * Returns whether this view has been set as a handwriting delegate by {@link 12565 * #setIsHandwritingDelegate}. 12566 */ isHandwritingDelegate()12567 public boolean isHandwritingDelegate() { 12568 return mIsHandwritingDelegate; 12569 } 12570 12571 /** 12572 * Specifies that a view from the specified package may act as a handwriting delegator for this 12573 * delegate editor view. If this method is not called, only views from the same package as this 12574 * delegate editor view may act as a handwriting delegator. This method allows specifying a 12575 * different trusted package which may contain a delegator view linked to this delegate editor 12576 * view. 12577 * 12578 * <p>This method has no effect unless {@link #setIsHandwritingDelegate} is also called to 12579 * configure this view to act as a handwriting delegate. 12580 * 12581 * <p>If this method is called on the delegate editor view, then {@link 12582 * #setAllowedHandwritingDelegatePackage} should also be called on the delegator view. 12583 * 12584 * @param allowedPackageName the package name of a delegator view linked to this delegate editor 12585 * view, or {@code null} to restore the default behavior of only allowing delegator views 12586 * from the same package as this delegate editor view 12587 */ setAllowedHandwritingDelegatorPackage(@ullable String allowedPackageName)12588 public void setAllowedHandwritingDelegatorPackage(@Nullable String allowedPackageName) { 12589 mAllowedHandwritingDelegatorPackageName = allowedPackageName; 12590 } 12591 12592 /** 12593 * Returns the allowed package for views which may act as a handwriting delegator for this 12594 * delegate editor view, as set by {@link #setAllowedHandwritingDelegatorPackage}. If {@link 12595 * #setAllowedHandwritingDelegatorPackage} has not been called, or called with {@code null} 12596 * argument, this will return {@code null}, meaning that only views from the same package as 12597 * this delegator editor view may act as a handwriting delegator. 12598 */ 12599 @Nullable getAllowedHandwritingDelegatorPackageName()12600 public String getAllowedHandwritingDelegatorPackageName() { 12601 return mAllowedHandwritingDelegatorPackageName; 12602 } 12603 12604 /** 12605 * Gets the coordinates of this view in the coordinate space of the 12606 * {@link Surface} that contains the view. 12607 * 12608 * <p>In multiple-screen scenarios, if the surface spans multiple screens, 12609 * the coordinate space of the surface also spans multiple screens. 12610 * 12611 * <p>After the method returns, the argument array contains the x and y 12612 * coordinates of the view relative to the view's left and top edges, 12613 * respectively. 12614 * 12615 * @param location A two-element integer array in which the view coordinates 12616 * are stored. The x-coordinate is at index 0; the y-coordinate, at 12617 * index 1. 12618 */ getLocationInSurface(@onNull @ize2) int[] location)12619 public void getLocationInSurface(@NonNull @Size(2) int[] location) { 12620 getLocationInWindow(location); 12621 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 12622 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 12623 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 12624 } 12625 } 12626 12627 /** 12628 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 12629 * only available if the view is attached. 12630 * 12631 * @return WindowInsets from the top of the view hierarchy or null if View is detached 12632 */ getRootWindowInsets()12633 public WindowInsets getRootWindowInsets() { 12634 if (mAttachInfo != null) { 12635 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 12636 } 12637 return null; 12638 } 12639 12640 /** 12641 * Retrieves the single {@link WindowInsetsController} of the window this view is attached to. 12642 * 12643 * @return The {@link WindowInsetsController} or {@code null} if the view is neither attached to 12644 * a window nor a view tree with a decor. 12645 * @see Window#getInsetsController() 12646 */ getWindowInsetsController()12647 public @Nullable WindowInsetsController getWindowInsetsController() { 12648 if (mAttachInfo != null) { 12649 return mAttachInfo.mViewRootImpl.getInsetsController(); 12650 } 12651 ViewParent parent = getParent(); 12652 if (parent instanceof View) { 12653 return ((View) parent).getWindowInsetsController(); 12654 } else if (parent instanceof ViewRootImpl) { 12655 // Between WindowManager.addView() and the first traversal AttachInfo isn't set yet. 12656 return ((ViewRootImpl) parent).getInsetsController(); 12657 } 12658 return null; 12659 } 12660 12661 12662 /** 12663 * Walk up the View hierarchy to find the nearest {@link OnBackInvokedDispatcher}. 12664 * 12665 * @return The {@link OnBackInvokedDispatcher} from this or the nearest 12666 * ancestor, or null if this view is both not attached and have no ancestor providing an 12667 * {@link OnBackInvokedDispatcher}. 12668 */ 12669 @Nullable findOnBackInvokedDispatcher()12670 public final OnBackInvokedDispatcher findOnBackInvokedDispatcher() { 12671 ViewParent parent = getParent(); 12672 if (parent != null) { 12673 return parent.findOnBackInvokedDispatcherForChild(this, this); 12674 } 12675 return null; 12676 } 12677 12678 /** 12679 * @hide Compute the insets that should be consumed by this view and the ones 12680 * that should propagate to those under it. 12681 * 12682 * Note: This is used by appcompat's ActionBarOverlayLayout through reflection. 12683 * 12684 * @param inoutInsets the insets given to this view 12685 * @param outLocalInsets the insets that should be applied to this view 12686 * @deprecated use {@link #computeSystemWindowInsets} 12687 * @return 12688 */ 12689 @Deprecated 12690 @UnsupportedAppUsage computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets)12691 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 12692 WindowInsets innerInsets = computeSystemWindowInsets(new WindowInsets(inoutInsets), 12693 outLocalInsets); 12694 inoutInsets.set(innerInsets.getSystemWindowInsetsAsRect()); 12695 return innerInsets.isSystemWindowInsetsConsumed(); 12696 } 12697 12698 /** 12699 * Compute insets that should be consumed by this view and the ones that should propagate 12700 * to those under it. 12701 * 12702 * @param in Insets currently being processed by this View, likely received as a parameter 12703 * to {@link #onApplyWindowInsets(WindowInsets)}. 12704 * @param outLocalInsets A Rect that will receive the insets that should be consumed 12705 * by this view 12706 * @return Insets that should be passed along to views under this one 12707 */ computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets)12708 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 12709 boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 12710 || (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; 12711 if (isOptionalFitSystemWindows && mAttachInfo != null) { 12712 OnContentApplyWindowInsetsListener listener = 12713 mAttachInfo.mContentOnApplyWindowInsetsListener; 12714 if (listener == null) { 12715 // The application wants to take care of fitting system window for 12716 // the content. 12717 outLocalInsets.setEmpty(); 12718 return in; 12719 } 12720 Pair<Insets, WindowInsets> result = listener.onContentApplyWindowInsets(this, in); 12721 outLocalInsets.set(result.first.toRect()); 12722 return result.second; 12723 } else { 12724 outLocalInsets.set(in.getSystemWindowInsetsAsRect()); 12725 return in.consumeSystemWindowInsets().inset(outLocalInsets); 12726 } 12727 } 12728 12729 /** 12730 * Sets whether or not this view should account for system screen decorations 12731 * such as the status bar and inset its content; that is, controlling whether 12732 * the default implementation of {@link #fitSystemWindows(Rect)} will be 12733 * executed. See that method for more details. 12734 * 12735 * <p>Note that if you are providing your own implementation of 12736 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 12737 * flag to true -- your implementation will be overriding the default 12738 * implementation that checks this flag. 12739 * 12740 * @param fitSystemWindows If true, then the default implementation of 12741 * {@link #fitSystemWindows(Rect)} will be executed. 12742 * 12743 * @attr ref android.R.styleable#View_fitsSystemWindows 12744 * @see #getFitsSystemWindows() 12745 * @see #fitSystemWindows(Rect) 12746 * @see #setSystemUiVisibility(int) 12747 */ setFitsSystemWindows(boolean fitSystemWindows)12748 public void setFitsSystemWindows(boolean fitSystemWindows) { 12749 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 12750 } 12751 12752 /** 12753 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 12754 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 12755 * will be executed. 12756 * 12757 * @return {@code true} if the default implementation of 12758 * {@link #fitSystemWindows(Rect)} will be executed. 12759 * 12760 * @attr ref android.R.styleable#View_fitsSystemWindows 12761 * @see #setFitsSystemWindows(boolean) 12762 * @see #fitSystemWindows(Rect) 12763 * @see #setSystemUiVisibility(int) 12764 */ 12765 @ViewDebug.ExportedProperty 12766 @InspectableProperty getFitsSystemWindows()12767 public boolean getFitsSystemWindows() { 12768 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 12769 } 12770 12771 /** @hide */ 12772 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) fitsSystemWindows()12773 public boolean fitsSystemWindows() { 12774 return getFitsSystemWindows(); 12775 } 12776 12777 /** 12778 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 12779 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 12780 */ 12781 @Deprecated requestFitSystemWindows()12782 public void requestFitSystemWindows() { 12783 if (mParent != null) { 12784 mParent.requestFitSystemWindows(); 12785 } 12786 } 12787 12788 /** 12789 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 12790 */ requestApplyInsets()12791 public void requestApplyInsets() { 12792 requestFitSystemWindows(); 12793 } 12794 12795 /** 12796 * @see #OPTIONAL_FITS_SYSTEM_WINDOWS 12797 * @hide 12798 */ 12799 @UnsupportedAppUsage makeOptionalFitsSystemWindows()12800 public void makeOptionalFitsSystemWindows() { 12801 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 12802 } 12803 12804 /** 12805 * @see #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS 12806 * @hide 12807 */ makeFrameworkOptionalFitsSystemWindows()12808 public void makeFrameworkOptionalFitsSystemWindows() { 12809 mPrivateFlags4 |= PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS; 12810 } 12811 12812 /** 12813 * @hide 12814 */ isFrameworkOptionalFitsSystemWindows()12815 public boolean isFrameworkOptionalFitsSystemWindows() { 12816 return (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; 12817 } 12818 12819 /** 12820 * Returns the visibility status for this view. 12821 * 12822 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 12823 * @attr ref android.R.styleable#View_visibility 12824 */ 12825 @ViewDebug.ExportedProperty(mapping = { 12826 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 12827 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 12828 @ViewDebug.IntToString(from = GONE, to = "GONE") 12829 }) 12830 @InspectableProperty(enumMapping = { 12831 @EnumEntry(value = VISIBLE, name = "visible"), 12832 @EnumEntry(value = INVISIBLE, name = "invisible"), 12833 @EnumEntry(value = GONE, name = "gone") 12834 }) 12835 @Visibility getVisibility()12836 public int getVisibility() { 12837 return mViewFlags & VISIBILITY_MASK; 12838 } 12839 12840 /** 12841 * Set the visibility state of this view. 12842 * 12843 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 12844 * @attr ref android.R.styleable#View_visibility 12845 */ 12846 @RemotableViewMethod setVisibility(@isibility int visibility)12847 public void setVisibility(@Visibility int visibility) { 12848 setFlags(visibility, VISIBILITY_MASK); 12849 } 12850 12851 /** 12852 * Returns the enabled status for this view. The interpretation of the 12853 * enabled state varies by subclass. 12854 * 12855 * @return True if this view is enabled, false otherwise. 12856 */ 12857 @ViewDebug.ExportedProperty 12858 @InspectableProperty isEnabled()12859 public boolean isEnabled() { 12860 return (mViewFlags & ENABLED_MASK) == ENABLED; 12861 } 12862 12863 /** 12864 * Set the enabled state of this view. The interpretation of the enabled 12865 * state varies by subclass. 12866 * 12867 * @param enabled True if this view is enabled, false otherwise. 12868 */ 12869 @RemotableViewMethod setEnabled(boolean enabled)12870 public void setEnabled(boolean enabled) { 12871 if (enabled == isEnabled()) return; 12872 12873 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 12874 12875 /* 12876 * The View most likely has to change its appearance, so refresh 12877 * the drawable state. 12878 */ 12879 refreshDrawableState(); 12880 12881 // Invalidate too, since the default behavior for views is to be 12882 // be drawn at 50% alpha rather than to change the drawable. 12883 invalidate(true); 12884 12885 if (!enabled) { 12886 cancelPendingInputEvents(); 12887 } 12888 notifyViewAccessibilityStateChangedIfNeeded( 12889 AccessibilityEvent.CONTENT_CHANGE_TYPE_ENABLED); 12890 } 12891 12892 /** 12893 * Set whether this view can receive the focus. 12894 * <p> 12895 * Setting this to false will also ensure that this view is not focusable 12896 * in touch mode. 12897 * 12898 * @param focusable If true, this view can receive the focus. 12899 * 12900 * @see #setFocusableInTouchMode(boolean) 12901 * @see #setFocusable(int) 12902 * @attr ref android.R.styleable#View_focusable 12903 */ 12904 @RemotableViewMethod setFocusable(boolean focusable)12905 public void setFocusable(boolean focusable) { 12906 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 12907 } 12908 12909 /** 12910 * Sets whether this view can receive focus. 12911 * <p> 12912 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 12913 * automatically based on the view's interactivity. This is the default. 12914 * <p> 12915 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 12916 * in touch mode. 12917 * 12918 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 12919 * or {@link #FOCUSABLE_AUTO}. 12920 * @see #setFocusableInTouchMode(boolean) 12921 * @attr ref android.R.styleable#View_focusable 12922 */ 12923 @RemotableViewMethod setFocusable(@ocusable int focusable)12924 public void setFocusable(@Focusable int focusable) { 12925 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 12926 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 12927 } 12928 setFlags(focusable, FOCUSABLE_MASK); 12929 } 12930 12931 /** 12932 * Set whether this view can receive focus while in touch mode. 12933 * 12934 * Setting this to true will also ensure that this view is focusable. 12935 * 12936 * @param focusableInTouchMode If true, this view can receive the focus while 12937 * in touch mode. 12938 * 12939 * @see #setFocusable(boolean) 12940 * @attr ref android.R.styleable#View_focusableInTouchMode 12941 */ 12942 @RemotableViewMethod setFocusableInTouchMode(boolean focusableInTouchMode)12943 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 12944 // Focusable in touch mode should always be set before the focusable flag 12945 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 12946 // which, in touch mode, will not successfully request focus on this view 12947 // because the focusable in touch mode flag is not set 12948 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 12949 12950 // Clear FOCUSABLE_AUTO if set. 12951 if (focusableInTouchMode) { 12952 // Clears FOCUSABLE_AUTO if set. 12953 setFlags(FOCUSABLE, FOCUSABLE_MASK); 12954 } 12955 } 12956 12957 /** 12958 * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how 12959 * to autofill the view with the user's data. 12960 * 12961 * <p>Typically, there is only one way to autofill a view, but there could be more than one. 12962 * For example, if the application accepts either an username or email address to identify 12963 * an user. 12964 * 12965 * <p>These hints are not validated by the Android System, but passed "as is" to the service. 12966 * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_} 12967 * constants such as: 12968 * {@link #AUTOFILL_HINT_USERNAME}, {@link #AUTOFILL_HINT_PASSWORD}, 12969 * {@link #AUTOFILL_HINT_EMAIL_ADDRESS}, 12970 * {@link #AUTOFILL_HINT_NAME}, 12971 * {@link #AUTOFILL_HINT_PHONE}, 12972 * {@link #AUTOFILL_HINT_POSTAL_ADDRESS}, {@link #AUTOFILL_HINT_POSTAL_CODE}, 12973 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 12974 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 12975 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 12976 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or 12977 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}. 12978 * 12979 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set. 12980 * @attr ref android.R.styleable#View_autofillHints 12981 */ setAutofillHints(@ullable String... autofillHints)12982 public void setAutofillHints(@Nullable String... autofillHints) { 12983 if (autofillHints == null || autofillHints.length == 0) { 12984 mAutofillHints = null; 12985 } else { 12986 mAutofillHints = autofillHints; 12987 } 12988 } 12989 12990 /** 12991 * @hide 12992 */ 12993 @TestApi setAutofilled(boolean isAutofilled, boolean hideHighlight)12994 public void setAutofilled(boolean isAutofilled, boolean hideHighlight) { 12995 boolean wasChanged = isAutofilled != isAutofilled(); 12996 12997 if (wasChanged) { 12998 if (isAutofilled) { 12999 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; 13000 } else { 13001 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; 13002 } 13003 13004 if (hideHighlight) { 13005 mPrivateFlags4 |= PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; 13006 } else { 13007 mPrivateFlags4 &= ~PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; 13008 } 13009 13010 invalidate(); 13011 } 13012 } 13013 13014 /** 13015 * Set whether this view should have sound effects enabled for events such as 13016 * clicking and touching. 13017 * 13018 * <p>You may wish to disable sound effects for a view if you already play sounds, 13019 * for instance, a dial key that plays dtmf tones. 13020 * 13021 * @param soundEffectsEnabled whether sound effects are enabled for this view. 13022 * @see #isSoundEffectsEnabled() 13023 * @see #playSoundEffect(int) 13024 * @attr ref android.R.styleable#View_soundEffectsEnabled 13025 */ setSoundEffectsEnabled(boolean soundEffectsEnabled)13026 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 13027 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 13028 } 13029 13030 /** 13031 * @return whether this view should have sound effects enabled for events such as 13032 * clicking and touching. 13033 * 13034 * @see #setSoundEffectsEnabled(boolean) 13035 * @see #playSoundEffect(int) 13036 * @attr ref android.R.styleable#View_soundEffectsEnabled 13037 */ 13038 @ViewDebug.ExportedProperty 13039 @InspectableProperty isSoundEffectsEnabled()13040 public boolean isSoundEffectsEnabled() { 13041 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 13042 } 13043 13044 /** 13045 * Set whether this view should have haptic feedback for events such as 13046 * long presses. 13047 * 13048 * <p>You may wish to disable haptic feedback if your view already controls 13049 * its own haptic feedback. 13050 * 13051 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 13052 * @see #isHapticFeedbackEnabled() 13053 * @see #performHapticFeedback(int) 13054 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 13055 */ setHapticFeedbackEnabled(boolean hapticFeedbackEnabled)13056 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 13057 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 13058 } 13059 13060 /** 13061 * @return whether this view should have haptic feedback enabled for events 13062 * such as long presses. 13063 * 13064 * @see #setHapticFeedbackEnabled(boolean) 13065 * @see #performHapticFeedback(int) 13066 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 13067 */ 13068 @ViewDebug.ExportedProperty 13069 @InspectableProperty isHapticFeedbackEnabled()13070 public boolean isHapticFeedbackEnabled() { 13071 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 13072 } 13073 13074 /** 13075 * Returns the layout direction for this view. 13076 * 13077 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 13078 * {@link #LAYOUT_DIRECTION_RTL}, 13079 * {@link #LAYOUT_DIRECTION_INHERIT} or 13080 * {@link #LAYOUT_DIRECTION_LOCALE}. 13081 * 13082 * @attr ref android.R.styleable#View_layoutDirection 13083 * 13084 * @hide 13085 */ 13086 @ViewDebug.ExportedProperty(category = "layout", mapping = { 13087 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 13088 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 13089 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 13090 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 13091 }) 13092 @InspectableProperty(hasAttributeId = false, enumMapping = { 13093 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 13094 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl"), 13095 @EnumEntry(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"), 13096 @EnumEntry(value = LAYOUT_DIRECTION_LOCALE, name = "locale") 13097 }) 13098 @LayoutDir getRawLayoutDirection()13099 public int getRawLayoutDirection() { 13100 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 13101 } 13102 13103 /** 13104 * Set the layout direction for this view. This will propagate a reset of layout direction 13105 * resolution to the view's children and resolve layout direction for this view. 13106 * 13107 * @param layoutDirection the layout direction to set. Should be one of: 13108 * 13109 * {@link #LAYOUT_DIRECTION_LTR}, 13110 * {@link #LAYOUT_DIRECTION_RTL}, 13111 * {@link #LAYOUT_DIRECTION_INHERIT}, 13112 * {@link #LAYOUT_DIRECTION_LOCALE}. 13113 * 13114 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 13115 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 13116 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 13117 * 13118 * @attr ref android.R.styleable#View_layoutDirection 13119 */ 13120 @RemotableViewMethod setLayoutDirection(@ayoutDir int layoutDirection)13121 public void setLayoutDirection(@LayoutDir int layoutDirection) { 13122 if (getRawLayoutDirection() != layoutDirection) { 13123 // Reset the current layout direction and the resolved one 13124 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 13125 resetRtlProperties(); 13126 // Set the new layout direction (filtered) 13127 mPrivateFlags2 |= 13128 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 13129 // We need to resolve all RTL properties as they all depend on layout direction 13130 resolveRtlPropertiesIfNeeded(); 13131 requestLayout(); 13132 invalidate(true); 13133 } 13134 } 13135 13136 /** 13137 * Returns the resolved layout direction for this view. 13138 * 13139 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 13140 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 13141 * 13142 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 13143 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 13144 * 13145 * @attr ref android.R.styleable#View_layoutDirection 13146 */ 13147 @ViewDebug.ExportedProperty(category = "layout", mapping = { 13148 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 13149 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 13150 }) 13151 @InspectableProperty(enumMapping = { 13152 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 13153 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl") 13154 }) 13155 @ResolvedLayoutDir getLayoutDirection()13156 public int getLayoutDirection() { 13157 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 13158 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 13159 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 13160 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 13161 } 13162 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 13163 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 13164 } 13165 13166 /** 13167 * Indicates whether or not this view's layout is right-to-left. This is resolved from 13168 * layout attribute and/or the inherited value from the parent 13169 * 13170 * @return true if the layout is right-to-left. 13171 * 13172 * @hide 13173 */ 13174 @ViewDebug.ExportedProperty(category = "layout") 13175 @UnsupportedAppUsage isLayoutRtl()13176 public boolean isLayoutRtl() { 13177 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 13178 } 13179 13180 /** 13181 * Indicates whether the view is currently tracking transient state that the 13182 * app should not need to concern itself with saving and restoring, but that 13183 * the framework should take special note to preserve when possible. 13184 * 13185 * <p>A view with transient state cannot be trivially rebound from an external 13186 * data source, such as an adapter binding item views in a list. This may be 13187 * because the view is performing an animation, tracking user selection 13188 * of content, or similar.</p> 13189 * 13190 * @return true if the view has transient state 13191 */ 13192 @ViewDebug.ExportedProperty(category = "layout") hasTransientState()13193 public boolean hasTransientState() { 13194 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 13195 } 13196 13197 /** 13198 * Set whether this view is currently tracking transient state that the 13199 * framework should attempt to preserve when possible. This flag is reference counted, 13200 * so every call to setHasTransientState(true) should be paired with a later call 13201 * to setHasTransientState(false). 13202 * 13203 * <p>A view with transient state cannot be trivially rebound from an external 13204 * data source, such as an adapter binding item views in a list. This may be 13205 * because the view is performing an animation, tracking user selection 13206 * of content, or similar.</p> 13207 * 13208 * @param hasTransientState true if this view has transient state 13209 */ setHasTransientState(boolean hasTransientState)13210 public void setHasTransientState(boolean hasTransientState) { 13211 final boolean oldHasTransientState = hasTransientState(); 13212 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 13213 mTransientStateCount - 1; 13214 if (mTransientStateCount < 0) { 13215 mTransientStateCount = 0; 13216 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 13217 "unmatched pair of setHasTransientState calls"); 13218 } else if ((hasTransientState && mTransientStateCount == 1) || 13219 (!hasTransientState && mTransientStateCount == 0)) { 13220 // update flag if we've just incremented up from 0 or decremented down to 0 13221 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 13222 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 13223 final boolean newHasTransientState = hasTransientState(); 13224 if (mParent != null && newHasTransientState != oldHasTransientState) { 13225 try { 13226 mParent.childHasTransientStateChanged(this, newHasTransientState); 13227 } catch (AbstractMethodError e) { 13228 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 13229 " does not fully implement ViewParent", e); 13230 } 13231 } 13232 } 13233 } 13234 13235 /** 13236 * Set the view is tracking translation transient state. This flag is used to check if the view 13237 * need to call setHasTransientState(false) to reset transient state that set when starting 13238 * translation. 13239 * 13240 * @param hasTranslationTransientState true if this view has translation transient state 13241 * @hide 13242 */ setHasTranslationTransientState(boolean hasTranslationTransientState)13243 public void setHasTranslationTransientState(boolean hasTranslationTransientState) { 13244 if (hasTranslationTransientState) { 13245 mPrivateFlags4 |= PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 13246 } else { 13247 mPrivateFlags4 &= ~PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 13248 } 13249 } 13250 13251 /** 13252 * @hide 13253 */ hasTranslationTransientState()13254 public boolean hasTranslationTransientState() { 13255 return (mPrivateFlags4 & PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE) 13256 == PFLAG4_HAS_TRANSLATION_TRANSIENT_STATE; 13257 } 13258 13259 /** 13260 * @hide 13261 */ clearTranslationState()13262 public void clearTranslationState() { 13263 if (mViewTranslationCallback != null) { 13264 mViewTranslationCallback.onClearTranslation(this); 13265 } 13266 clearViewTranslationResponse(); 13267 if (hasTranslationTransientState()) { 13268 setHasTransientState(false); 13269 setHasTranslationTransientState(false); 13270 } 13271 } 13272 13273 /** 13274 * Returns true if this view is currently attached to a window. 13275 */ isAttachedToWindow()13276 public boolean isAttachedToWindow() { 13277 return mAttachInfo != null; 13278 } 13279 13280 /** 13281 * Returns true if this view has been through at least one layout since it 13282 * was last attached to or detached from a window. 13283 */ isLaidOut()13284 public boolean isLaidOut() { 13285 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 13286 } 13287 13288 /** 13289 * @return {@code true} if laid-out and not about to do another layout. 13290 */ isLayoutValid()13291 boolean isLayoutValid() { 13292 return isLaidOut() && ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == 0); 13293 } 13294 13295 /** 13296 * If this view doesn't do any drawing on its own, set this flag to 13297 * allow further optimizations. By default, this flag is not set on 13298 * View, but could be set on some View subclasses such as ViewGroup. 13299 * 13300 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 13301 * you should clear this flag. 13302 * 13303 * @param willNotDraw whether or not this View draw on its own 13304 */ setWillNotDraw(boolean willNotDraw)13305 public void setWillNotDraw(boolean willNotDraw) { 13306 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 13307 } 13308 13309 /** 13310 * Returns whether or not this View draws on its own. 13311 * 13312 * @return true if this view has nothing to draw, false otherwise 13313 */ 13314 @ViewDebug.ExportedProperty(category = "drawing") willNotDraw()13315 public boolean willNotDraw() { 13316 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 13317 } 13318 13319 /** 13320 * When a View's drawing cache is enabled, drawing is redirected to an 13321 * offscreen bitmap. Some views, like an ImageView, must be able to 13322 * bypass this mechanism if they already draw a single bitmap, to avoid 13323 * unnecessary usage of the memory. 13324 * 13325 * @param willNotCacheDrawing true if this view does not cache its 13326 * drawing, false otherwise 13327 * 13328 * @deprecated The view drawing cache was largely made obsolete with the introduction of 13329 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 13330 * layers are largely unnecessary and can easily result in a net loss in performance due to the 13331 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 13332 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 13333 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 13334 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 13335 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 13336 * software-rendered usages are discouraged and have compatibility issues with hardware-only 13337 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 13338 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 13339 * reports or unit testing the {@link PixelCopy} API is recommended. 13340 */ 13341 @Deprecated setWillNotCacheDrawing(boolean willNotCacheDrawing)13342 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 13343 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 13344 } 13345 13346 /** 13347 * Returns whether or not this View can cache its drawing or not. 13348 * 13349 * @return true if this view does not cache its drawing, false otherwise 13350 * 13351 * @deprecated The view drawing cache was largely made obsolete with the introduction of 13352 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 13353 * layers are largely unnecessary and can easily result in a net loss in performance due to the 13354 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 13355 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 13356 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 13357 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 13358 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 13359 * software-rendered usages are discouraged and have compatibility issues with hardware-only 13360 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 13361 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 13362 * reports or unit testing the {@link PixelCopy} API is recommended. 13363 */ 13364 @ViewDebug.ExportedProperty(category = "drawing") 13365 @Deprecated willNotCacheDrawing()13366 public boolean willNotCacheDrawing() { 13367 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 13368 } 13369 13370 /** 13371 * Indicates whether this view reacts to click events or not. 13372 * 13373 * @return true if the view is clickable, false otherwise 13374 * 13375 * @see #setClickable(boolean) 13376 * @attr ref android.R.styleable#View_clickable 13377 */ 13378 @ViewDebug.ExportedProperty 13379 @InspectableProperty isClickable()13380 public boolean isClickable() { 13381 return (mViewFlags & CLICKABLE) == CLICKABLE; 13382 } 13383 13384 /** 13385 * Enables or disables click events for this view. When a view 13386 * is clickable it will change its state to "pressed" on every click. 13387 * Subclasses should set the view clickable to visually react to 13388 * user's clicks. 13389 * 13390 * @param clickable true to make the view clickable, false otherwise 13391 * 13392 * @see #isClickable() 13393 * @attr ref android.R.styleable#View_clickable 13394 */ setClickable(boolean clickable)13395 public void setClickable(boolean clickable) { 13396 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 13397 } 13398 13399 /** 13400 * Enables or disables click events for this view when disabled. 13401 * 13402 * @param clickableWhenDisabled true to make the view clickable, false otherwise 13403 * 13404 * @attr ref android.R.styleable#View_allowClickWhenDisabled 13405 */ setAllowClickWhenDisabled(boolean clickableWhenDisabled)13406 public void setAllowClickWhenDisabled(boolean clickableWhenDisabled) { 13407 if (clickableWhenDisabled) { 13408 mPrivateFlags4 |= PFLAG4_ALLOW_CLICK_WHEN_DISABLED; 13409 } else { 13410 mPrivateFlags4 &= ~PFLAG4_ALLOW_CLICK_WHEN_DISABLED; 13411 } 13412 } 13413 13414 /** 13415 * Indicates whether this view reacts to long click events or not. 13416 * 13417 * @return true if the view is long clickable, false otherwise 13418 * 13419 * @see #setLongClickable(boolean) 13420 * @attr ref android.R.styleable#View_longClickable 13421 */ 13422 @InspectableProperty isLongClickable()13423 public boolean isLongClickable() { 13424 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 13425 } 13426 13427 /** 13428 * Enables or disables long click events for this view. When a view is long 13429 * clickable it reacts to the user holding down the button for a longer 13430 * duration than a tap. This event can either launch the listener or a 13431 * context menu. 13432 * 13433 * @param longClickable true to make the view long clickable, false otherwise 13434 * @see #isLongClickable() 13435 * @attr ref android.R.styleable#View_longClickable 13436 */ setLongClickable(boolean longClickable)13437 public void setLongClickable(boolean longClickable) { 13438 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 13439 } 13440 13441 /** 13442 * Indicates whether this view reacts to context clicks or not. 13443 * 13444 * @return true if the view is context clickable, false otherwise 13445 * @see #setContextClickable(boolean) 13446 * @attr ref android.R.styleable#View_contextClickable 13447 */ 13448 @InspectableProperty isContextClickable()13449 public boolean isContextClickable() { 13450 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 13451 } 13452 13453 /** 13454 * Enables or disables context clicking for this view. This event can launch the listener. 13455 * 13456 * @param contextClickable true to make the view react to a context click, false otherwise 13457 * @see #isContextClickable() 13458 * @attr ref android.R.styleable#View_contextClickable 13459 */ setContextClickable(boolean contextClickable)13460 public void setContextClickable(boolean contextClickable) { 13461 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 13462 } 13463 13464 /** 13465 * Sets the pressed state for this view and provides a touch coordinate for 13466 * animation hinting. 13467 * 13468 * @param pressed Pass true to set the View's internal state to "pressed", 13469 * or false to reverts the View's internal state from a 13470 * previously set "pressed" state. 13471 * @param x The x coordinate of the touch that caused the press 13472 * @param y The y coordinate of the touch that caused the press 13473 */ setPressed(boolean pressed, float x, float y)13474 private void setPressed(boolean pressed, float x, float y) { 13475 if (pressed) { 13476 drawableHotspotChanged(x, y); 13477 } 13478 13479 setPressed(pressed); 13480 } 13481 13482 /** 13483 * Sets the pressed state for this view. 13484 * 13485 * @see #isClickable() 13486 * @see #setClickable(boolean) 13487 * 13488 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 13489 * the View's internal state from a previously set "pressed" state. 13490 */ setPressed(boolean pressed)13491 public void setPressed(boolean pressed) { 13492 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 13493 13494 if (pressed) { 13495 mPrivateFlags |= PFLAG_PRESSED; 13496 } else { 13497 mPrivateFlags &= ~PFLAG_PRESSED; 13498 } 13499 13500 if (needsRefresh) { 13501 refreshDrawableState(); 13502 } 13503 dispatchSetPressed(pressed); 13504 } 13505 13506 /** 13507 * Dispatch setPressed to all of this View's children. 13508 * 13509 * @see #setPressed(boolean) 13510 * 13511 * @param pressed The new pressed state 13512 */ dispatchSetPressed(boolean pressed)13513 protected void dispatchSetPressed(boolean pressed) { 13514 } 13515 13516 /** 13517 * Indicates whether the view is currently in pressed state. Unless 13518 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 13519 * the pressed state. 13520 * 13521 * @see #setPressed(boolean) 13522 * @see #isClickable() 13523 * @see #setClickable(boolean) 13524 * 13525 * @return true if the view is currently pressed, false otherwise 13526 */ 13527 @ViewDebug.ExportedProperty 13528 @InspectableProperty(hasAttributeId = false) isPressed()13529 public boolean isPressed() { 13530 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 13531 } 13532 13533 /** 13534 * @hide 13535 * Indicates whether this view will participate in data collection through 13536 * {@link ViewStructure}. If true, it will not provide any data 13537 * for itself or its children. If false, the normal data collection will be allowed. 13538 * 13539 * @return Returns false if assist data collection is not blocked, else true. 13540 * 13541 * @see #setAssistBlocked(boolean) 13542 * @attr ref android.R.styleable#View_assistBlocked 13543 */ isAssistBlocked()13544 public boolean isAssistBlocked() { 13545 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 13546 } 13547 13548 /** 13549 * @hide 13550 * Controls whether assist data collection from this view and its children is enabled 13551 * (that is, whether {@link #onProvideStructure} and 13552 * {@link #onProvideVirtualStructure} will be called). The default value is false, 13553 * allowing normal assist collection. Setting this to false will disable assist collection. 13554 * 13555 * @param enabled Set to true to <em>disable</em> assist data collection, or false 13556 * (the default) to allow it. 13557 * 13558 * @see #isAssistBlocked() 13559 * @see #onProvideStructure 13560 * @see #onProvideVirtualStructure 13561 * @attr ref android.R.styleable#View_assistBlocked 13562 */ 13563 @UnsupportedAppUsage setAssistBlocked(boolean enabled)13564 public void setAssistBlocked(boolean enabled) { 13565 if (enabled) { 13566 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 13567 } else { 13568 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 13569 } 13570 } 13571 13572 /** 13573 * Indicates whether this view will save its state (that is, 13574 * whether its {@link #onSaveInstanceState} method will be called). 13575 * 13576 * @return Returns true if the view state saving is enabled, else false. 13577 * 13578 * @see #setSaveEnabled(boolean) 13579 * @attr ref android.R.styleable#View_saveEnabled 13580 */ 13581 @InspectableProperty isSaveEnabled()13582 public boolean isSaveEnabled() { 13583 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 13584 } 13585 13586 /** 13587 * Controls whether the saving of this view's state is 13588 * enabled (that is, whether its {@link #onSaveInstanceState} method 13589 * will be called). Note that even if freezing is enabled, the 13590 * view still must have an id assigned to it (via {@link #setId(int)}) 13591 * for its state to be saved. This flag can only disable the 13592 * saving of this view; any child views may still have their state saved. 13593 * 13594 * @param enabled Set to false to <em>disable</em> state saving, or true 13595 * (the default) to allow it. 13596 * 13597 * @see #isSaveEnabled() 13598 * @see #setId(int) 13599 * @see #onSaveInstanceState() 13600 * @attr ref android.R.styleable#View_saveEnabled 13601 */ setSaveEnabled(boolean enabled)13602 public void setSaveEnabled(boolean enabled) { 13603 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 13604 } 13605 13606 /** 13607 * Gets whether the framework should discard touches when the view's 13608 * window is obscured by another visible window at the touched location. 13609 * Refer to the {@link View} security documentation for more details. 13610 * 13611 * @return True if touch filtering is enabled. 13612 * 13613 * @see #setFilterTouchesWhenObscured(boolean) 13614 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 13615 */ 13616 @ViewDebug.ExportedProperty 13617 @InspectableProperty getFilterTouchesWhenObscured()13618 public boolean getFilterTouchesWhenObscured() { 13619 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 13620 } 13621 13622 /** 13623 * Sets whether the framework should discard touches when the view's 13624 * window is obscured by another visible window at the touched location. 13625 * Refer to the {@link View} security documentation for more details. 13626 * 13627 * @param enabled True if touch filtering should be enabled. 13628 * 13629 * @see #getFilterTouchesWhenObscured 13630 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 13631 */ setFilterTouchesWhenObscured(boolean enabled)13632 public void setFilterTouchesWhenObscured(boolean enabled) { 13633 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 13634 FILTER_TOUCHES_WHEN_OBSCURED); 13635 calculateAccessibilityDataSensitive(); 13636 } 13637 13638 /** 13639 * Indicates whether the entire hierarchy under this view will save its 13640 * state when a state saving traversal occurs from its parent. The default 13641 * is true; if false, these views will not be saved unless 13642 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 13643 * 13644 * @return Returns true if the view state saving from parent is enabled, else false. 13645 * 13646 * @see #setSaveFromParentEnabled(boolean) 13647 */ isSaveFromParentEnabled()13648 public boolean isSaveFromParentEnabled() { 13649 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 13650 } 13651 13652 /** 13653 * Controls whether the entire hierarchy under this view will save its 13654 * state when a state saving traversal occurs from its parent. The default 13655 * is true; if false, these views will not be saved unless 13656 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 13657 * 13658 * @param enabled Set to false to <em>disable</em> state saving, or true 13659 * (the default) to allow it. 13660 * 13661 * @see #isSaveFromParentEnabled() 13662 * @see #setId(int) 13663 * @see #onSaveInstanceState() 13664 */ setSaveFromParentEnabled(boolean enabled)13665 public void setSaveFromParentEnabled(boolean enabled) { 13666 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 13667 } 13668 13669 13670 /** 13671 * Returns whether this View is currently able to take focus. 13672 * 13673 * @return True if this view can take focus, or false otherwise. 13674 */ 13675 @ViewDebug.ExportedProperty(category = "focus") isFocusable()13676 public final boolean isFocusable() { 13677 return FOCUSABLE == (mViewFlags & FOCUSABLE); 13678 } 13679 13680 /** 13681 * Returns the focusable setting for this view. 13682 * 13683 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 13684 * @attr ref android.R.styleable#View_focusable 13685 */ 13686 @ViewDebug.ExportedProperty(mapping = { 13687 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 13688 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 13689 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 13690 }, category = "focus") 13691 @InspectableProperty(enumMapping = { 13692 @EnumEntry(value = NOT_FOCUSABLE, name = "false"), 13693 @EnumEntry(value = FOCUSABLE, name = "true"), 13694 @EnumEntry(value = FOCUSABLE_AUTO, name = "auto") 13695 }) 13696 @Focusable getFocusable()13697 public int getFocusable() { 13698 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 13699 } 13700 13701 /** 13702 * When a view is focusable, it may not want to take focus when in touch mode. 13703 * For example, a button would like focus when the user is navigating via a D-pad 13704 * so that the user can click on it, but once the user starts touching the screen, 13705 * the button shouldn't take focus 13706 * @return Whether the view is focusable in touch mode. 13707 * @attr ref android.R.styleable#View_focusableInTouchMode 13708 */ 13709 @ViewDebug.ExportedProperty(category = "focus") 13710 @InspectableProperty isFocusableInTouchMode()13711 public final boolean isFocusableInTouchMode() { 13712 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 13713 } 13714 13715 /** 13716 * Returns whether the view should be treated as a focusable unit by screen reader 13717 * accessibility tools. 13718 * @see #setScreenReaderFocusable(boolean) 13719 * 13720 * @return Whether the view should be treated as a focusable unit by screen reader. 13721 * 13722 * @attr ref android.R.styleable#View_screenReaderFocusable 13723 */ 13724 @InspectableProperty isScreenReaderFocusable()13725 public boolean isScreenReaderFocusable() { 13726 return (mPrivateFlags3 & PFLAG3_SCREEN_READER_FOCUSABLE) != 0; 13727 } 13728 13729 /** 13730 * Sets whether this View should be a focusable element for screen readers 13731 * and include non-focusable Views from its subtree when providing feedback. 13732 * <p> 13733 * Note: this is similar to using <a href="#attr_android:focusable">{@code android:focusable}, 13734 * but does not impact input focus behavior. 13735 * 13736 * @param screenReaderFocusable Whether the view should be treated as a unit by screen reader 13737 * accessibility tools. 13738 * 13739 * @attr ref android.R.styleable#View_screenReaderFocusable 13740 */ setScreenReaderFocusable(boolean screenReaderFocusable)13741 public void setScreenReaderFocusable(boolean screenReaderFocusable) { 13742 updatePflags3AndNotifyA11yIfChanged(PFLAG3_SCREEN_READER_FOCUSABLE, screenReaderFocusable); 13743 } 13744 13745 /** 13746 * Gets whether this view is a heading for accessibility purposes. 13747 * 13748 * @return {@code true} if the view is a heading, {@code false} otherwise. 13749 * 13750 * @attr ref android.R.styleable#View_accessibilityHeading 13751 */ 13752 @InspectableProperty isAccessibilityHeading()13753 public boolean isAccessibilityHeading() { 13754 return (mPrivateFlags3 & PFLAG3_ACCESSIBILITY_HEADING) != 0; 13755 } 13756 13757 /** 13758 * Set if view is a heading for a section of content for accessibility purposes. 13759 * <p> 13760 * Users of some accessibility services can choose to navigate between headings 13761 * instead of between paragraphs, words, etc. Apps that provide headings on 13762 * sections of text can help the text navigation experience. 13763 * 13764 * @param isHeading {@code true} if the view is a heading, {@code false} otherwise. 13765 * 13766 * @attr ref android.R.styleable#View_accessibilityHeading 13767 */ setAccessibilityHeading(boolean isHeading)13768 public void setAccessibilityHeading(boolean isHeading) { 13769 updatePflags3AndNotifyA11yIfChanged(PFLAG3_ACCESSIBILITY_HEADING, isHeading); 13770 } 13771 updatePflags3AndNotifyA11yIfChanged(int mask, boolean newValue)13772 private void updatePflags3AndNotifyA11yIfChanged(int mask, boolean newValue) { 13773 int pflags3 = mPrivateFlags3; 13774 if (newValue) { 13775 pflags3 |= mask; 13776 } else { 13777 pflags3 &= ~mask; 13778 } 13779 13780 if (pflags3 != mPrivateFlags3) { 13781 mPrivateFlags3 = pflags3; 13782 notifyViewAccessibilityStateChangedIfNeeded( 13783 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13784 } 13785 } 13786 13787 /** 13788 * Find the nearest view in the specified direction that can take focus. 13789 * This does not actually give focus to that view. 13790 * 13791 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 13792 * 13793 * @return The nearest focusable in the specified direction, or null if none 13794 * can be found. 13795 */ focusSearch(@ocusRealDirection int direction)13796 public View focusSearch(@FocusRealDirection int direction) { 13797 if (mParent != null) { 13798 return mParent.focusSearch(this, direction); 13799 } else { 13800 return null; 13801 } 13802 } 13803 13804 /** 13805 * Returns whether this View is a root of a keyboard navigation cluster. 13806 * 13807 * @return True if this view is a root of a cluster, or false otherwise. 13808 * @attr ref android.R.styleable#View_keyboardNavigationCluster 13809 */ 13810 @ViewDebug.ExportedProperty(category = "focus") 13811 @InspectableProperty isKeyboardNavigationCluster()13812 public final boolean isKeyboardNavigationCluster() { 13813 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 13814 } 13815 13816 /** 13817 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters 13818 * will be ignored. 13819 * 13820 * @return the keyboard navigation cluster that this view is in (can be this view) 13821 * or {@code null} if not in one 13822 */ findKeyboardNavigationCluster()13823 View findKeyboardNavigationCluster() { 13824 if (mParent instanceof View) { 13825 View cluster = ((View) mParent).findKeyboardNavigationCluster(); 13826 if (cluster != null) { 13827 return cluster; 13828 } else if (isKeyboardNavigationCluster()) { 13829 return this; 13830 } 13831 } 13832 return null; 13833 } 13834 13835 /** 13836 * Set whether this view is a root of a keyboard navigation cluster. 13837 * 13838 * @param isCluster If true, this view is a root of a cluster. 13839 * 13840 * @attr ref android.R.styleable#View_keyboardNavigationCluster 13841 */ setKeyboardNavigationCluster(boolean isCluster)13842 public void setKeyboardNavigationCluster(boolean isCluster) { 13843 if (isCluster) { 13844 mPrivateFlags3 |= PFLAG3_CLUSTER; 13845 } else { 13846 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 13847 } 13848 } 13849 13850 /** 13851 * Sets this View as the one which receives focus the next time cluster navigation jumps 13852 * to the cluster containing this View. This does NOT change focus even if the cluster 13853 * containing this view is current. 13854 * 13855 * @hide 13856 */ 13857 @TestApi setFocusedInCluster()13858 public final void setFocusedInCluster() { 13859 setFocusedInCluster(findKeyboardNavigationCluster()); 13860 } 13861 setFocusedInCluster(View cluster)13862 private void setFocusedInCluster(View cluster) { 13863 if (this instanceof ViewGroup) { 13864 ((ViewGroup) this).mFocusedInCluster = null; 13865 } 13866 if (cluster == this) { 13867 return; 13868 } 13869 ViewParent parent = mParent; 13870 View child = this; 13871 while (parent instanceof ViewGroup) { 13872 ((ViewGroup) parent).mFocusedInCluster = child; 13873 if (parent == cluster) { 13874 break; 13875 } 13876 child = (View) parent; 13877 parent = parent.getParent(); 13878 } 13879 } 13880 updateFocusedInCluster(View oldFocus, @FocusDirection int direction)13881 private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) { 13882 if (oldFocus != null) { 13883 View oldCluster = oldFocus.findKeyboardNavigationCluster(); 13884 View cluster = findKeyboardNavigationCluster(); 13885 if (oldCluster != cluster) { 13886 // Going from one cluster to another, so save last-focused. 13887 // This covers cluster jumps because they are always FOCUS_DOWN 13888 oldFocus.setFocusedInCluster(oldCluster); 13889 if (!(oldFocus.mParent instanceof ViewGroup)) { 13890 return; 13891 } 13892 if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) { 13893 // This is a result of ordered navigation so consider navigation through 13894 // the previous cluster "complete" and clear its last-focused memory. 13895 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 13896 } else if (oldFocus instanceof ViewGroup 13897 && ((ViewGroup) oldFocus).getDescendantFocusability() 13898 == ViewGroup.FOCUS_AFTER_DESCENDANTS 13899 && ViewRootImpl.isViewDescendantOf(this, oldFocus)) { 13900 // This means oldFocus is not focusable since it obviously has a focusable 13901 // child (this). Don't restore focus to it in the future. 13902 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 13903 } 13904 } 13905 } 13906 } 13907 13908 /** 13909 * Returns whether this View should receive focus when the focus is restored for the view 13910 * hierarchy containing this view. 13911 * <p> 13912 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 13913 * window or serves as a target of cluster navigation. 13914 * 13915 * @see #restoreDefaultFocus() 13916 * 13917 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 13918 * @attr ref android.R.styleable#View_focusedByDefault 13919 */ 13920 @ViewDebug.ExportedProperty(category = "focus") 13921 @InspectableProperty isFocusedByDefault()13922 public final boolean isFocusedByDefault() { 13923 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 13924 } 13925 13926 /** 13927 * Sets whether this View should receive focus when the focus is restored for the view 13928 * hierarchy containing this view. 13929 * <p> 13930 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 13931 * window or serves as a target of cluster navigation. 13932 * 13933 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 13934 * {@code false} otherwise. 13935 * 13936 * @see #restoreDefaultFocus() 13937 * 13938 * @attr ref android.R.styleable#View_focusedByDefault 13939 */ 13940 @RemotableViewMethod setFocusedByDefault(boolean isFocusedByDefault)13941 public void setFocusedByDefault(boolean isFocusedByDefault) { 13942 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 13943 return; 13944 } 13945 13946 if (isFocusedByDefault) { 13947 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 13948 } else { 13949 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 13950 } 13951 13952 if (mParent instanceof ViewGroup) { 13953 if (isFocusedByDefault) { 13954 ((ViewGroup) mParent).setDefaultFocus(this); 13955 } else { 13956 ((ViewGroup) mParent).clearDefaultFocus(this); 13957 } 13958 } 13959 } 13960 13961 /** 13962 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 13963 * 13964 * @return {@code true} if this view has default focus, {@code false} otherwise 13965 */ hasDefaultFocus()13966 boolean hasDefaultFocus() { 13967 return isFocusedByDefault(); 13968 } 13969 13970 /** 13971 * Find the nearest keyboard navigation cluster in the specified direction. 13972 * This does not actually give focus to that cluster. 13973 * 13974 * @param currentCluster The starting point of the search. Null means the current cluster is not 13975 * found yet 13976 * @param direction Direction to look 13977 * 13978 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 13979 * can be found 13980 */ keyboardNavigationClusterSearch(View currentCluster, @FocusDirection int direction)13981 public View keyboardNavigationClusterSearch(View currentCluster, 13982 @FocusDirection int direction) { 13983 if (isKeyboardNavigationCluster()) { 13984 currentCluster = this; 13985 } 13986 if (isRootNamespace()) { 13987 // Root namespace means we should consider ourselves the top of the 13988 // tree for group searching; otherwise we could be group searching 13989 // into other tabs. see LocalActivityManager and TabHost for more info. 13990 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 13991 this, currentCluster, direction); 13992 } else if (mParent != null) { 13993 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 13994 } 13995 return null; 13996 } 13997 13998 /** 13999 * This method is the last chance for the focused view and its ancestors to 14000 * respond to an arrow key. This is called when the focused view did not 14001 * consume the key internally, nor could the view system find a new view in 14002 * the requested direction to give focus to. 14003 * 14004 * @param focused The currently focused view. 14005 * @param direction The direction focus wants to move. One of FOCUS_UP, 14006 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 14007 * @return True if the this view consumed this unhandled move. 14008 */ dispatchUnhandledMove(View focused, @FocusRealDirection int direction)14009 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 14010 return false; 14011 } 14012 14013 /** 14014 * Sets whether this View should use a default focus highlight when it gets focused but doesn't 14015 * have {@link android.R.attr#state_focused} defined in its background. 14016 * 14017 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus 14018 * highlight, {@code false} otherwise. 14019 * 14020 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 14021 */ setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled)14022 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { 14023 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; 14024 } 14025 14026 /** 14027 * Returns whether this View should use a default focus highlight when it gets focused but 14028 * doesn't have {@link android.R.attr#state_focused} defined in its background. 14029 * 14030 * @return True if this View should use a default focus highlight. 14031 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 14032 */ 14033 @ViewDebug.ExportedProperty(category = "focus") 14034 @InspectableProperty getDefaultFocusHighlightEnabled()14035 public final boolean getDefaultFocusHighlightEnabled() { 14036 return mDefaultFocusHighlightEnabled; 14037 } 14038 14039 /** 14040 * If a user manually specified the next view id for a particular direction, 14041 * use the root to look up the view. 14042 * @param root The root view of the hierarchy containing this view. 14043 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 14044 * or FOCUS_BACKWARD. 14045 * @return The user specified next view, or null if there is none. 14046 */ findUserSetNextFocus(View root, @FocusDirection int direction)14047 View findUserSetNextFocus(View root, @FocusDirection int direction) { 14048 switch (direction) { 14049 case FOCUS_LEFT: 14050 if (mNextFocusLeftId == View.NO_ID) return null; 14051 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 14052 case FOCUS_RIGHT: 14053 if (mNextFocusRightId == View.NO_ID) return null; 14054 return findViewInsideOutShouldExist(root, mNextFocusRightId); 14055 case FOCUS_UP: 14056 if (mNextFocusUpId == View.NO_ID) return null; 14057 return findViewInsideOutShouldExist(root, mNextFocusUpId); 14058 case FOCUS_DOWN: 14059 if (mNextFocusDownId == View.NO_ID) return null; 14060 return findViewInsideOutShouldExist(root, mNextFocusDownId); 14061 case FOCUS_FORWARD: 14062 if (mNextFocusForwardId == View.NO_ID) return null; 14063 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 14064 case FOCUS_BACKWARD: { 14065 if (mID == View.NO_ID) return null; 14066 final View rootView = root; 14067 final View startView = this; 14068 // Since we have forward links but no backward links, we need to find the view that 14069 // forward links to this view. We can't just find the view with the specified ID 14070 // because view IDs need not be unique throughout the tree. 14071 return root.findViewByPredicateInsideOut(startView, 14072 t -> findViewInsideOutShouldExist(rootView, t, t.mNextFocusForwardId) 14073 == startView); 14074 } 14075 } 14076 return null; 14077 } 14078 14079 /** 14080 * If a user manually specified the next keyboard-navigation cluster for a particular direction, 14081 * use the root to look up the view. 14082 * 14083 * @param root the root view of the hierarchy containing this view 14084 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD} 14085 * @return the user-specified next cluster, or {@code null} if there is none 14086 */ findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction)14087 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { 14088 switch (direction) { 14089 case FOCUS_FORWARD: 14090 if (mNextClusterForwardId == View.NO_ID) return null; 14091 return findViewInsideOutShouldExist(root, mNextClusterForwardId); 14092 case FOCUS_BACKWARD: { 14093 if (mID == View.NO_ID) return null; 14094 final int id = mID; 14095 return root.findViewByPredicateInsideOut(this, 14096 (Predicate<View>) t -> t.mNextClusterForwardId == id); 14097 } 14098 } 14099 return null; 14100 } 14101 findViewInsideOutShouldExist(View root, int id)14102 private View findViewInsideOutShouldExist(View root, int id) { 14103 return findViewInsideOutShouldExist(root, this, id); 14104 } 14105 findViewInsideOutShouldExist(View root, View start, int id)14106 private View findViewInsideOutShouldExist(View root, View start, int id) { 14107 if (mMatchIdPredicate == null) { 14108 mMatchIdPredicate = new MatchIdPredicate(); 14109 } 14110 mMatchIdPredicate.mId = id; 14111 View result = root.findViewByPredicateInsideOut(start, mMatchIdPredicate); 14112 if (result == null) { 14113 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 14114 } 14115 return result; 14116 } 14117 14118 /** 14119 * Find and return all focusable views that are descendants of this view, 14120 * possibly including this view if it is focusable itself. 14121 * 14122 * @param direction The direction of the focus 14123 * @return A list of focusable views 14124 */ getFocusables(@ocusDirection int direction)14125 public ArrayList<View> getFocusables(@FocusDirection int direction) { 14126 ArrayList<View> result = new ArrayList<View>(24); 14127 addFocusables(result, direction); 14128 return result; 14129 } 14130 14131 /** 14132 * Add any focusable views that are descendants of this view (possibly 14133 * including this view if it is focusable itself) to views. If we are in touch mode, 14134 * only add views that are also focusable in touch mode. 14135 * 14136 * @param views Focusable views found so far 14137 * @param direction The direction of the focus 14138 */ addFocusables(ArrayList<View> views, @FocusDirection int direction)14139 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 14140 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 14141 } 14142 14143 /** 14144 * Adds any focusable views that are descendants of this view (possibly 14145 * including this view if it is focusable itself) to views. This method 14146 * adds all focusable views regardless if we are in touch mode or 14147 * only views focusable in touch mode if we are in touch mode or 14148 * only views that can take accessibility focus if accessibility is enabled 14149 * depending on the focusable mode parameter. 14150 * 14151 * @param views Focusable views found so far or null if all we are interested is 14152 * the number of focusables. 14153 * @param direction The direction of the focus. 14154 * @param focusableMode The type of focusables to be added. 14155 * 14156 * @see #FOCUSABLES_ALL 14157 * @see #FOCUSABLES_TOUCH_MODE 14158 */ addFocusables(ArrayList<View> views, @FocusDirection int direction, @FocusableMode int focusableMode)14159 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 14160 @FocusableMode int focusableMode) { 14161 if (views == null) { 14162 return; 14163 } 14164 if (!canTakeFocus()) { 14165 return; 14166 } 14167 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 14168 && !isFocusableInTouchMode()) { 14169 return; 14170 } 14171 views.add(this); 14172 } 14173 14174 /** 14175 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 14176 * including this view if it is a cluster root itself) to views. 14177 * 14178 * @param views Keyboard navigation cluster roots found so far 14179 * @param direction Direction to look 14180 */ addKeyboardNavigationClusters( @onNull Collection<View> views, int direction)14181 public void addKeyboardNavigationClusters( 14182 @NonNull Collection<View> views, 14183 int direction) { 14184 if (!isKeyboardNavigationCluster()) { 14185 return; 14186 } 14187 if (!hasFocusable()) { 14188 return; 14189 } 14190 views.add(this); 14191 } 14192 14193 /** 14194 * Finds the Views that contain given text. The containment is case insensitive. 14195 * The search is performed by either the text that the View renders or the content 14196 * description that describes the view for accessibility purposes and the view does 14197 * not render or both. Clients can specify how the search is to be performed via 14198 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 14199 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 14200 * 14201 * @param outViews The output list of matching Views. 14202 * @param searched The text to match against. 14203 * 14204 * @see #FIND_VIEWS_WITH_TEXT 14205 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 14206 * @see #setContentDescription(CharSequence) 14207 */ findViewsWithText(ArrayList<View> outViews, CharSequence searched, @FindViewFlags int flags)14208 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 14209 @FindViewFlags int flags) { 14210 if (getAccessibilityNodeProvider() != null) { 14211 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 14212 outViews.add(this); 14213 } 14214 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 14215 && (searched != null && searched.length() > 0) 14216 && (mContentDescription != null && mContentDescription.length() > 0)) { 14217 String searchedLowerCase = searched.toString().toLowerCase(); 14218 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 14219 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 14220 outViews.add(this); 14221 } 14222 } 14223 } 14224 14225 /** 14226 * Find and return all touchable views that are descendants of this view, 14227 * possibly including this view if it is touchable itself. 14228 * 14229 * @return A list of touchable views 14230 */ getTouchables()14231 public ArrayList<View> getTouchables() { 14232 ArrayList<View> result = new ArrayList<View>(); 14233 addTouchables(result); 14234 return result; 14235 } 14236 14237 /** 14238 * Add any touchable views that are descendants of this view (possibly 14239 * including this view if it is touchable itself) to views. 14240 * 14241 * @param views Touchable views found so far 14242 */ addTouchables(ArrayList<View> views)14243 public void addTouchables(ArrayList<View> views) { 14244 final int viewFlags = mViewFlags; 14245 14246 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 14247 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 14248 && (viewFlags & ENABLED_MASK) == ENABLED) { 14249 views.add(this); 14250 } 14251 } 14252 14253 /** 14254 * Returns whether this View is accessibility focused. 14255 * 14256 * @return True if this View is accessibility focused. 14257 */ 14258 @InspectableProperty(hasAttributeId = false) isAccessibilityFocused()14259 public boolean isAccessibilityFocused() { 14260 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 14261 } 14262 14263 /** 14264 * Call this to try to give accessibility focus to this view. 14265 * 14266 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 14267 * returns false or the view is no visible or the view already has accessibility 14268 * focus. 14269 * 14270 * See also {@link #focusSearch(int)}, which is what you call to say that you 14271 * have focus, and you want your parent to look for the next one. 14272 * 14273 * <p> 14274 * <b>Note:</b> Avoid setting accessibility focus. This is intended to be controlled by screen 14275 * readers. Apps changing focus can confuse screen readers, so the resulting behavior can vary 14276 * by device and screen reader version. 14277 * 14278 * @return Whether this view actually took accessibility focus. 14279 * 14280 * @hide 14281 */ 14282 @UnsupportedAppUsage requestAccessibilityFocus()14283 public boolean requestAccessibilityFocus() { 14284 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 14285 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 14286 return false; 14287 } 14288 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 14289 return false; 14290 } 14291 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 14292 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 14293 ViewRootImpl viewRootImpl = getViewRootImpl(); 14294 if (viewRootImpl != null) { 14295 viewRootImpl.setAccessibilityFocus(this, null); 14296 } 14297 invalidate(); 14298 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 14299 return true; 14300 } 14301 return false; 14302 } 14303 14304 /** 14305 * Call this to try to clear accessibility focus of this view. 14306 * 14307 * See also {@link #focusSearch(int)}, which is what you call to say that you 14308 * have focus, and you want your parent to look for the next one. 14309 * 14310 * @hide 14311 */ 14312 @UnsupportedAppUsage clearAccessibilityFocus()14313 public void clearAccessibilityFocus() { 14314 clearAccessibilityFocusNoCallbacks(0); 14315 14316 // Clear the global reference of accessibility focus if this view or 14317 // any of its descendants had accessibility focus. This will NOT send 14318 // an event or update internal state if focus is cleared from a 14319 // descendant view, which may leave views in inconsistent states. 14320 final ViewRootImpl viewRootImpl = getViewRootImpl(); 14321 if (viewRootImpl != null) { 14322 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 14323 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 14324 viewRootImpl.setAccessibilityFocus(null, null); 14325 } 14326 } 14327 } 14328 sendAccessibilityHoverEvent(int eventType)14329 private void sendAccessibilityHoverEvent(int eventType) { 14330 // Since we are not delivering to a client accessibility events from not 14331 // important views (unless the clinet request that) we need to fire the 14332 // event from the deepest view exposed to the client. As a consequence if 14333 // the user crosses a not exposed view the client will see enter and exit 14334 // of the exposed predecessor followed by and enter and exit of that same 14335 // predecessor when entering and exiting the not exposed descendant. This 14336 // is fine since the client has a clear idea which view is hovered at the 14337 // price of a couple more events being sent. This is a simple and 14338 // working solution. 14339 View source = this; 14340 while (true) { 14341 if (source.includeForAccessibility(false)) { 14342 source.sendAccessibilityEvent(eventType); 14343 return; 14344 } 14345 ViewParent parent = source.getParent(); 14346 if (parent instanceof View) { 14347 source = (View) parent; 14348 } else { 14349 return; 14350 } 14351 } 14352 } 14353 14354 /** 14355 * Clears accessibility focus without calling any callback methods 14356 * normally invoked in {@link #clearAccessibilityFocus()}. This method 14357 * is used separately from that one for clearing accessibility focus when 14358 * giving this focus to another view. 14359 * 14360 * @param action The action, if any, that led to focus being cleared. Set to 14361 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 14362 * the window. 14363 */ clearAccessibilityFocusNoCallbacks(int action)14364 void clearAccessibilityFocusNoCallbacks(int action) { 14365 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 14366 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 14367 invalidate(); 14368 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 14369 AccessibilityEvent event = AccessibilityEvent.obtain( 14370 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 14371 event.setAction(action); 14372 if (mAccessibilityDelegate != null) { 14373 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 14374 } else { 14375 sendAccessibilityEventUnchecked(event); 14376 } 14377 } 14378 14379 updatePreferKeepClearForFocus(); 14380 } 14381 } 14382 14383 /** 14384 * Call this to try to give focus to a specific view or to one of its 14385 * descendants. 14386 * 14387 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 14388 * false), or if it can't be focused due to other conditions (not focusable in touch mode 14389 * ({@link #isFocusableInTouchMode}) while the device is in touch mode, not visible, not 14390 * enabled, or has no size). 14391 * 14392 * See also {@link #focusSearch(int)}, which is what you call to say that you 14393 * have focus, and you want your parent to look for the next one. 14394 * 14395 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 14396 * {@link #FOCUS_DOWN} and <code>null</code>. 14397 * 14398 * @return Whether this view or one of its descendants actually took focus. 14399 */ requestFocus()14400 public final boolean requestFocus() { 14401 return requestFocus(View.FOCUS_DOWN); 14402 } 14403 14404 /** 14405 * This will request focus for whichever View was last focused within this 14406 * cluster before a focus-jump out of it. 14407 * 14408 * @hide 14409 */ 14410 @TestApi restoreFocusInCluster(@ocusRealDirection int direction)14411 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 14412 // Prioritize focusableByDefault over algorithmic focus selection. 14413 if (restoreDefaultFocus()) { 14414 return true; 14415 } 14416 return requestFocus(direction); 14417 } 14418 14419 /** 14420 * This will request focus for whichever View not in a cluster was last focused before a 14421 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 14422 * the "first" focusable view it finds. 14423 * 14424 * @hide 14425 */ 14426 @TestApi restoreFocusNotInCluster()14427 public boolean restoreFocusNotInCluster() { 14428 return requestFocus(View.FOCUS_DOWN); 14429 } 14430 14431 /** 14432 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 14433 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 14434 * 14435 * @return Whether this view or one of its descendants actually took focus 14436 */ restoreDefaultFocus()14437 public boolean restoreDefaultFocus() { 14438 return requestFocus(View.FOCUS_DOWN); 14439 } 14440 14441 /** 14442 * Call this to try to give focus to a specific view or to one of its 14443 * descendants and give it a hint about what direction focus is heading. 14444 * 14445 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 14446 * false), or if it is focusable and it is not focusable in touch mode 14447 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 14448 * 14449 * See also {@link #focusSearch(int)}, which is what you call to say that you 14450 * have focus, and you want your parent to look for the next one. 14451 * 14452 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 14453 * <code>null</code> set for the previously focused rectangle. 14454 * 14455 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 14456 * @return Whether this view or one of its descendants actually took focus. 14457 */ requestFocus(int direction)14458 public final boolean requestFocus(int direction) { 14459 return requestFocus(direction, null); 14460 } 14461 14462 /** 14463 * Call this to try to give focus to a specific view or to one of its descendants 14464 * and give it hints about the direction and a specific rectangle that the focus 14465 * is coming from. The rectangle can help give larger views a finer grained hint 14466 * about where focus is coming from, and therefore, where to show selection, or 14467 * forward focus change internally. 14468 * 14469 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 14470 * false), or if it is focusable and it is not focusable in touch mode 14471 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 14472 * 14473 * A View will not take focus if it is not visible. 14474 * 14475 * A View will not take focus if one of its parents has 14476 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 14477 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 14478 * 14479 * See also {@link #focusSearch(int)}, which is what you call to say that you 14480 * have focus, and you want your parent to look for the next one. 14481 * 14482 * You may wish to override this method if your custom {@link View} has an internal 14483 * {@link View} that it wishes to forward the request to. 14484 * 14485 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 14486 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 14487 * to give a finer grained hint about where focus is coming from. May be null 14488 * if there is no hint. 14489 * @return Whether this view or one of its descendants actually took focus. 14490 */ requestFocus(int direction, Rect previouslyFocusedRect)14491 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 14492 return requestFocusNoSearch(direction, previouslyFocusedRect); 14493 } 14494 requestFocusNoSearch(int direction, Rect previouslyFocusedRect)14495 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 14496 // need to be focusable 14497 if (!canTakeFocus()) { 14498 return false; 14499 } 14500 14501 // need to be focusable in touch mode if in touch mode 14502 if (isInTouchMode() && 14503 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 14504 return false; 14505 } 14506 14507 // need to not have any parents blocking us 14508 if (hasAncestorThatBlocksDescendantFocus()) { 14509 return false; 14510 } 14511 14512 if (!isLayoutValid()) { 14513 mPrivateFlags |= PFLAG_WANTS_FOCUS; 14514 } else { 14515 clearParentsWantFocus(); 14516 } 14517 14518 handleFocusGainInternal(direction, previouslyFocusedRect); 14519 return true; 14520 } 14521 clearParentsWantFocus()14522 void clearParentsWantFocus() { 14523 if (mParent instanceof View) { 14524 ((View) mParent).mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 14525 ((View) mParent).clearParentsWantFocus(); 14526 } 14527 } 14528 14529 /** 14530 * Call this to try to give focus to a specific view or to one of its descendants. This is a 14531 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 14532 * touch mode to request focus when they are touched. 14533 * 14534 * @return Whether this view or one of its descendants actually took focus. 14535 * 14536 * @see #isInTouchMode() 14537 * 14538 */ requestFocusFromTouch()14539 public final boolean requestFocusFromTouch() { 14540 // Leave touch mode if we need to 14541 if (isInTouchMode()) { 14542 ViewRootImpl viewRoot = getViewRootImpl(); 14543 if (viewRoot != null) { 14544 viewRoot.ensureTouchMode(false); 14545 } 14546 } 14547 return requestFocus(View.FOCUS_DOWN); 14548 } 14549 14550 /** 14551 * @return Whether any ancestor of this view blocks descendant focus. 14552 */ hasAncestorThatBlocksDescendantFocus()14553 private boolean hasAncestorThatBlocksDescendantFocus() { 14554 final boolean focusableInTouchMode = isFocusableInTouchMode(); 14555 ViewParent ancestor = mParent; 14556 while (ancestor instanceof ViewGroup) { 14557 final ViewGroup vgAncestor = (ViewGroup) ancestor; 14558 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 14559 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 14560 return true; 14561 } else { 14562 ancestor = vgAncestor.getParent(); 14563 } 14564 } 14565 return false; 14566 } 14567 14568 /** 14569 * Gets the mode for determining whether this View is important for accessibility. 14570 * A view is important for accessibility if it fires accessibility events and if it 14571 * is reported to accessibility services that query the screen. 14572 * 14573 * @return The mode for determining whether a view is important for accessibility, one 14574 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 14575 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 14576 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 14577 * 14578 * @attr ref android.R.styleable#View_importantForAccessibility 14579 * 14580 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 14581 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 14582 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 14583 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 14584 */ 14585 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 14586 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 14587 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 14588 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 14589 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 14590 to = "noHideDescendants") 14591 }) 14592 @InspectableProperty(enumMapping = { 14593 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"), 14594 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"), 14595 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"), 14596 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 14597 name = "noHideDescendants"), 14598 }) getImportantForAccessibility()14599 public int getImportantForAccessibility() { 14600 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 14601 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 14602 } 14603 14604 /** 14605 * Sets the live region mode for this view. This indicates to accessibility 14606 * services whether they should automatically notify the user about changes 14607 * to the view's content description or text, or to the content descriptions 14608 * or text of the view's children (where applicable). 14609 * <p> 14610 * For example, in a login screen with a TextView that displays an "incorrect 14611 * password" notification, that view should be marked as a live region with 14612 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 14613 * <p> 14614 * To disable change notifications for this view, use 14615 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 14616 * mode for most views. 14617 * <p> 14618 * To indicate that the user should be notified of changes, use 14619 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 14620 * <p> 14621 * If the view's changes should interrupt ongoing speech and notify the user 14622 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 14623 * 14624 * @param mode The live region mode for this view, one of: 14625 * <ul> 14626 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 14627 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 14628 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 14629 * </ul> 14630 * @attr ref android.R.styleable#View_accessibilityLiveRegion 14631 */ setAccessibilityLiveRegion(int mode)14632 public void setAccessibilityLiveRegion(int mode) { 14633 if (mode != getAccessibilityLiveRegion()) { 14634 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 14635 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 14636 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 14637 notifyViewAccessibilityStateChangedIfNeeded( 14638 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 14639 } 14640 } 14641 14642 /** 14643 * Gets the live region mode for this View. 14644 * 14645 * @return The live region mode for the view. 14646 * 14647 * @attr ref android.R.styleable#View_accessibilityLiveRegion 14648 * 14649 * @see #setAccessibilityLiveRegion(int) 14650 */ 14651 @InspectableProperty(enumMapping = { 14652 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"), 14653 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"), 14654 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive") 14655 }) getAccessibilityLiveRegion()14656 public int getAccessibilityLiveRegion() { 14657 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 14658 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 14659 } 14660 14661 /** 14662 * Sets how to determine whether this view is important for accessibility 14663 * which is if it fires accessibility events and if it is reported to 14664 * accessibility services that query the screen. 14665 * 14666 * @param mode How to determine whether this view is important for accessibility. 14667 * 14668 * @attr ref android.R.styleable#View_importantForAccessibility 14669 * 14670 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 14671 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 14672 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 14673 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 14674 */ setImportantForAccessibility(int mode)14675 public void setImportantForAccessibility(int mode) { 14676 final int oldMode = getImportantForAccessibility(); 14677 if (mode != oldMode) { 14678 final boolean hideDescendants = 14679 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 14680 14681 // If this node or its descendants are no longer important, try to 14682 // clear accessibility focus. 14683 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 14684 final View focusHost = findAccessibilityFocusHost(hideDescendants); 14685 if (focusHost != null) { 14686 focusHost.clearAccessibilityFocus(); 14687 } 14688 } 14689 14690 // If we're moving between AUTO and another state, we might not need 14691 // to send a subtree changed notification. We'll store the computed 14692 // importance, since we'll need to check it later to make sure. 14693 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 14694 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 14695 final boolean oldIncludeForAccessibility = 14696 maySkipNotify && includeForAccessibility(false); 14697 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 14698 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 14699 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 14700 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility(false)) { 14701 notifySubtreeAccessibilityStateChangedIfNeeded(); 14702 } else { 14703 notifyViewAccessibilityStateChangedIfNeeded( 14704 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 14705 } 14706 } 14707 } 14708 14709 /** 14710 * Returns the view within this view's hierarchy that is hosting 14711 * accessibility focus. 14712 * 14713 * @param searchDescendants whether to search for focus in descendant views 14714 * @return the view hosting accessibility focus, or {@code null} 14715 */ findAccessibilityFocusHost(boolean searchDescendants)14716 private View findAccessibilityFocusHost(boolean searchDescendants) { 14717 if (isAccessibilityFocusedViewOrHost()) { 14718 return this; 14719 } 14720 14721 if (searchDescendants) { 14722 final ViewRootImpl viewRoot = getViewRootImpl(); 14723 if (viewRoot != null) { 14724 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 14725 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 14726 return focusHost; 14727 } 14728 } 14729 } 14730 14731 return null; 14732 } 14733 14734 /** 14735 * Computes whether this view should be exposed for accessibility. In 14736 * general, views that are interactive or provide information are exposed 14737 * while views that serve only as containers are hidden. 14738 * <p> 14739 * If an ancestor of this view has importance 14740 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 14741 * returns <code>false</code>. 14742 * <p> 14743 * Otherwise, the value is computed according to the view's 14744 * {@link #getImportantForAccessibility()} value: 14745 * <ol> 14746 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 14747 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 14748 * </code> 14749 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 14750 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 14751 * view satisfies any of the following: 14752 * <ul> 14753 * <li>Is actionable, e.g. {@link #isClickable()}, 14754 * {@link #isLongClickable()}, or {@link #isFocusable()} 14755 * <li>Has an {@link AccessibilityDelegate} 14756 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 14757 * {@link OnKeyListener}, etc. 14758 * <li>Is an accessibility live region, e.g. 14759 * {@link #getAccessibilityLiveRegion()} is not 14760 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 14761 * </ul> 14762 * <li>Has an accessibility pane title, see {@link #setAccessibilityPaneTitle}</li> 14763 * </ol> 14764 * 14765 * @return Whether the view is exposed for accessibility. 14766 * @see #setImportantForAccessibility(int) 14767 * @see #getImportantForAccessibility() 14768 */ isImportantForAccessibility()14769 public boolean isImportantForAccessibility() { 14770 final int mode = getImportantForAccessibility(); 14771 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 14772 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 14773 return false; 14774 } 14775 14776 // Check parent mode to ensure we're not hidden. 14777 ViewParent parent = mParent; 14778 while (parent instanceof View) { 14779 if (((View) parent).getImportantForAccessibility() 14780 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 14781 return false; 14782 } 14783 parent = parent.getParent(); 14784 } 14785 14786 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 14787 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 14788 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE 14789 || isAccessibilityPane(); 14790 } 14791 14792 /** 14793 * Gets the parent for accessibility purposes. Note that the parent for 14794 * accessibility is not necessary the immediate parent. It is the first 14795 * predecessor that is important for accessibility. 14796 * 14797 * @return The parent for accessibility purposes. 14798 */ getParentForAccessibility()14799 public ViewParent getParentForAccessibility() { 14800 if (mParent instanceof View) { 14801 View parentView = (View) mParent; 14802 if (parentView.includeForAccessibility()) { 14803 return mParent; 14804 } else { 14805 return mParent.getParentForAccessibility(); 14806 } 14807 } 14808 return null; 14809 } 14810 14811 /** @hide */ getSelfOrParentImportantForA11y()14812 View getSelfOrParentImportantForA11y() { 14813 if (isImportantForAccessibility()) return this; 14814 ViewParent parent = getParentForAccessibility(); 14815 if (parent instanceof View) return (View) parent; 14816 return null; 14817 } 14818 14819 /** 14820 * Adds the children of this View relevant for accessibility to the given list 14821 * as output. Since some Views are not important for accessibility the added 14822 * child views are not necessarily direct children of this view, rather they are 14823 * the first level of descendants important for accessibility. 14824 * 14825 * @param outChildren The output list that will receive children for accessibility. 14826 */ addChildrenForAccessibility(ArrayList<View> outChildren)14827 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 14828 14829 } 14830 14831 /** 14832 * @see #includeForAccessibility(boolean) 14833 * @hide 14834 */ 14835 @UnsupportedAppUsage includeForAccessibility()14836 public boolean includeForAccessibility() { 14837 return includeForAccessibility(true); 14838 } 14839 14840 /** 14841 * Whether to regard this view for accessibility. 14842 * 14843 * <p> 14844 * If this decision is used for generating the accessibility node tree then this returns false 14845 * for {@link #isAccessibilityDataPrivate()} views queried by non-accessibility tools. 14846 * </p> 14847 * <p> 14848 * Otherwise, a view is regarded for accessibility if: 14849 * <li>the view returns true for {@link #isImportantForAccessibility()}, or</li> 14850 * <li>the querying accessibility service has explicitly requested that views not important for 14851 * accessibility are regarded by setting 14852 * {@link android.accessibilityservice.AccessibilityServiceInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS}</li> 14853 * </p> 14854 * 14855 * @param forNodeTree True if the result of this function will be used for generating a node 14856 * tree, otherwise false (like when sending {@link AccessibilityEvent}s). 14857 * @return Whether to regard the view for accessibility. 14858 * @hide 14859 */ includeForAccessibility(boolean forNodeTree)14860 public boolean includeForAccessibility(boolean forNodeTree) { 14861 if (mAttachInfo == null) { 14862 return false; 14863 } 14864 14865 if (forNodeTree) { 14866 // The AccessibilityDataPrivate property should not effect whether this View is 14867 // included for consideration when sending AccessibilityEvents. Events copy their 14868 // source View's AccessibilityDataPrivate value, and then filtering is done when 14869 // AccessibilityManagerService propagates events to each recipient AccessibilityService. 14870 if (!AccessibilityManager.getInstance(mContext).isRequestFromAccessibilityTool() 14871 && isAccessibilityDataSensitive()) { 14872 return false; 14873 } 14874 } 14875 14876 return (mAttachInfo.mAccessibilityFetchFlags 14877 & AccessibilityNodeInfo.FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 14878 || isImportantForAccessibility(); 14879 } 14880 14881 /** 14882 * Whether this view should restrict accessibility service access only to services that have the 14883 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property 14884 * set to true. 14885 * 14886 * <p> 14887 * See default behavior provided by {@link #ACCESSIBILITY_DATA_SENSITIVE_AUTO}. Otherwise, 14888 * returns true for {@link #ACCESSIBILITY_DATA_SENSITIVE_YES} or false for {@link 14889 * #ACCESSIBILITY_DATA_SENSITIVE_NO}. 14890 * </p> 14891 * 14892 * @return True if this view should restrict accessibility service access to services that have 14893 * the isAccessibilityTool property. 14894 */ 14895 @ViewDebug.ExportedProperty(category = "accessibility") isAccessibilityDataSensitive()14896 public boolean isAccessibilityDataSensitive() { 14897 if (mInferredAccessibilityDataSensitive == ACCESSIBILITY_DATA_SENSITIVE_AUTO) { 14898 calculateAccessibilityDataSensitive(); 14899 } 14900 return mInferredAccessibilityDataSensitive == ACCESSIBILITY_DATA_SENSITIVE_YES; 14901 } 14902 14903 /** 14904 * Calculate and cache the inferred value for {@link #isAccessibilityDataSensitive()}. 14905 * 14906 * <p> 14907 * <strong>Note:</strong> This method needs to be called any time one of the below conditions 14908 * changes, to recalculate the new value. 14909 * </p> 14910 */ calculateAccessibilityDataSensitive()14911 void calculateAccessibilityDataSensitive() { 14912 // Use the explicit value if set. 14913 if (mExplicitAccessibilityDataSensitive != ACCESSIBILITY_DATA_SENSITIVE_AUTO) { 14914 mInferredAccessibilityDataSensitive = mExplicitAccessibilityDataSensitive; 14915 } else if (getFilterTouchesWhenObscured()) { 14916 // Views that set filterTouchesWhenObscured default to accessibilityDataSensitive. 14917 mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_YES; 14918 } else if (mParent instanceof View && ((View) mParent).isAccessibilityDataSensitive()) { 14919 // Descendants of accessibilityDataSensitive Views are also accessibilityDataSensitive. 14920 mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_YES; 14921 } else { 14922 // Otherwise, default to not accessibilityDataSensitive. 14923 mInferredAccessibilityDataSensitive = ACCESSIBILITY_DATA_SENSITIVE_NO; 14924 } 14925 } 14926 14927 /** 14928 * Specifies whether this view should only allow interactions from 14929 * {@link android.accessibilityservice.AccessibilityService}s with the 14930 * {@link android.accessibilityservice.AccessibilityServiceInfo#isAccessibilityTool} property 14931 * set to true. 14932 */ setAccessibilityDataSensitive( @ccessibilityDataSensitive int accessibilityDataSensitive)14933 public void setAccessibilityDataSensitive( 14934 @AccessibilityDataSensitive int accessibilityDataSensitive) { 14935 mExplicitAccessibilityDataSensitive = accessibilityDataSensitive; 14936 calculateAccessibilityDataSensitive(); 14937 } 14938 14939 /** 14940 * Returns whether the View is considered actionable from 14941 * accessibility perspective. Such view are important for 14942 * accessibility. 14943 * 14944 * @return True if the view is actionable for accessibility. 14945 * 14946 * @hide 14947 */ isActionableForAccessibility()14948 public boolean isActionableForAccessibility() { 14949 return (isClickable() || isLongClickable() || isFocusable()); 14950 } 14951 14952 /** 14953 * Returns whether the View has registered callbacks which makes it 14954 * important for accessibility. 14955 * 14956 * @return True if the view is actionable for accessibility. 14957 */ hasListenersForAccessibility()14958 private boolean hasListenersForAccessibility() { 14959 ListenerInfo info = getListenerInfo(); 14960 return mTouchDelegate != null || info.mOnKeyListener != null 14961 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 14962 || info.mOnHoverListener != null || info.mOnDragListener != null; 14963 } 14964 14965 /** 14966 * Notifies that the accessibility state of this view changed. The change 14967 * is local to this view and does not represent structural changes such 14968 * as children and parent. For example, the view became focusable. The 14969 * notification is at at most once every 14970 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 14971 * to avoid unnecessary load to the system. Also once a view has a pending 14972 * notification this method is a NOP until the notification has been sent. 14973 * 14974 * @hide 14975 */ 14976 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) notifyViewAccessibilityStateChangedIfNeeded(int changeType)14977 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 14978 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 14979 return; 14980 } 14981 14982 // Changes to views with a pane title count as window state changes, as the pane title 14983 // marks them as significant parts of the UI. A visible view with a nulled title may send 14984 // a disappeared event. 14985 if ((changeType != AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) 14986 && (isAccessibilityPane() 14987 || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) 14988 && isAggregatedVisible())) { 14989 // If the pane isn't visible, content changed events are sufficient unless we're 14990 // reporting that the view just disappeared 14991 if ((isAggregatedVisible()) 14992 || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)) { 14993 final AccessibilityEvent event = AccessibilityEvent.obtain(); 14994 onInitializeAccessibilityEvent(event); 14995 event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 14996 event.setContentChangeTypes(changeType); 14997 event.setSource(this); 14998 onPopulateAccessibilityEvent(event); 14999 if (mParent != null) { 15000 try { 15001 mParent.requestSendAccessibilityEvent(this, event); 15002 } catch (AbstractMethodError e) { 15003 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() 15004 + " does not fully implement ViewParent", e); 15005 } 15006 } 15007 return; 15008 } 15009 } 15010 15011 // If this is a live region, we should send a subtree change event 15012 // from this view immediately. Otherwise, we can let it propagate up. 15013 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) { 15014 final AccessibilityEvent event = AccessibilityEvent.obtain(); 15015 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 15016 event.setContentChangeTypes(changeType); 15017 sendAccessibilityEventUnchecked(event); 15018 } else if (mParent != null) { 15019 try { 15020 mParent.notifySubtreeAccessibilityStateChanged(this, this, changeType); 15021 } catch (AbstractMethodError e) { 15022 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15023 " does not fully implement ViewParent", e); 15024 } 15025 } 15026 } 15027 15028 /** 15029 * Notifies that the accessibility state of this view changed. The change 15030 * is *not* local to this view and does represent structural changes such 15031 * as children and parent. For example, the view size changed. The 15032 * notification is at at most once every 15033 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 15034 * to avoid unnecessary load to the system. Also once a view has a pending 15035 * notification this method is a NOP until the notification has been sent. 15036 * 15037 * @hide 15038 */ 15039 @UnsupportedAppUsage notifySubtreeAccessibilityStateChangedIfNeeded()15040 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 15041 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 15042 return; 15043 } 15044 15045 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 15046 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 15047 if (mParent != null) { 15048 try { 15049 mParent.notifySubtreeAccessibilityStateChanged( 15050 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 15051 } catch (AbstractMethodError e) { 15052 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 15053 " does not fully implement ViewParent", e); 15054 } 15055 } 15056 } 15057 } 15058 notifySubtreeAccessibilityStateChangedByParentIfNeeded()15059 private void notifySubtreeAccessibilityStateChangedByParentIfNeeded() { 15060 if (!AccessibilityManager.getInstance(mContext).isEnabled()) { 15061 return; 15062 } 15063 15064 final View sendA11yEventView = (View) getParentForAccessibility(); 15065 if (sendA11yEventView != null && sendA11yEventView.isShown()) { 15066 sendA11yEventView.notifySubtreeAccessibilityStateChangedIfNeeded(); 15067 } 15068 } 15069 15070 /** 15071 * Changes the visibility of this View without triggering any other changes. This should only 15072 * be used by animation frameworks, such as {@link android.transition.Transition}, where 15073 * visibility changes should not adjust focus or trigger a new layout. Application developers 15074 * should use {@link #setVisibility} instead to ensure that the hierarchy is correctly updated. 15075 * 15076 * <p>Only call this method when a temporary visibility must be applied during an 15077 * animation and the original visibility value is guaranteed to be reset after the 15078 * animation completes. Use {@link #setVisibility} in all other cases.</p> 15079 * 15080 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 15081 * @see #setVisibility(int) 15082 */ setTransitionVisibility(@isibility int visibility)15083 public void setTransitionVisibility(@Visibility int visibility) { 15084 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 15085 } 15086 15087 /** 15088 * Reset the flag indicating the accessibility state of the subtree rooted 15089 * at this view changed. 15090 */ resetSubtreeAccessibilityStateChanged()15091 void resetSubtreeAccessibilityStateChanged() { 15092 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 15093 } 15094 15095 /** 15096 * Report an accessibility action to this view's parents for delegated processing. 15097 * 15098 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 15099 * call this method to delegate an accessibility action to a supporting parent. If the parent 15100 * returns true from its 15101 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 15102 * method this method will return true to signify that the action was consumed.</p> 15103 * 15104 * <p>This method is useful for implementing nested scrolling child views. If 15105 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 15106 * a custom view implementation may invoke this method to allow a parent to consume the 15107 * scroll first. If this method returns true the custom view should skip its own scrolling 15108 * behavior.</p> 15109 * 15110 * @param action Accessibility action to delegate 15111 * @param arguments Optional action arguments 15112 * @return true if the action was consumed by a parent 15113 */ dispatchNestedPrePerformAccessibilityAction(int action, @Nullable Bundle arguments)15114 public boolean dispatchNestedPrePerformAccessibilityAction(int action, 15115 @Nullable Bundle arguments) { 15116 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 15117 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 15118 return true; 15119 } 15120 } 15121 return false; 15122 } 15123 15124 /** 15125 * Performs the specified accessibility action on the view. For 15126 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 15127 * <p> 15128 * If an {@link AccessibilityDelegate} has been specified via calling 15129 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 15130 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 15131 * is responsible for handling this call. 15132 * </p> 15133 * 15134 * <p>The default implementation will delegate 15135 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 15136 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 15137 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 15138 * 15139 * <p> 15140 * <b>Note:</b> Avoid setting accessibility focus with 15141 * {@link AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS}. This is intended to be controlled 15142 * by screen readers. Apps changing focus can confuse screen readers, so the resulting behavior 15143 * can vary by device and screen reader version. 15144 * 15145 * @param action The action to perform. 15146 * @param arguments Optional action arguments. 15147 * @return Whether the action was performed. 15148 */ performAccessibilityAction(int action, @Nullable Bundle arguments)15149 public boolean performAccessibilityAction(int action, @Nullable Bundle arguments) { 15150 if (mAccessibilityDelegate != null) { 15151 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 15152 } else { 15153 return performAccessibilityActionInternal(action, arguments); 15154 } 15155 } 15156 15157 /** 15158 * @see #performAccessibilityAction(int, Bundle) 15159 * 15160 * Note: Called from the default {@link AccessibilityDelegate}. 15161 * 15162 * @hide 15163 */ 15164 @UnsupportedAppUsage performAccessibilityActionInternal(int action, @Nullable Bundle arguments)15165 public boolean performAccessibilityActionInternal(int action, @Nullable Bundle arguments) { 15166 if (isNestedScrollingEnabled() 15167 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 15168 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 15169 || action == R.id.accessibilityActionScrollUp 15170 || action == R.id.accessibilityActionScrollLeft 15171 || action == R.id.accessibilityActionScrollDown 15172 || action == R.id.accessibilityActionScrollRight)) { 15173 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 15174 return true; 15175 } 15176 } 15177 15178 switch (action) { 15179 case AccessibilityNodeInfo.ACTION_CLICK: { 15180 if (isClickable()) { 15181 performClickInternal(); 15182 return true; 15183 } 15184 } break; 15185 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 15186 if (isLongClickable()) { 15187 performLongClick(); 15188 return true; 15189 } 15190 } break; 15191 case AccessibilityNodeInfo.ACTION_FOCUS: { 15192 if (!hasFocus()) { 15193 // Get out of touch mode since accessibility 15194 // wants to move focus around. 15195 getViewRootImpl().ensureTouchMode(false); 15196 return requestFocus(); 15197 } 15198 } break; 15199 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 15200 if (hasFocus()) { 15201 clearFocus(); 15202 return !isFocused(); 15203 } 15204 } break; 15205 case AccessibilityNodeInfo.ACTION_SELECT: { 15206 if (!isSelected()) { 15207 setSelected(true); 15208 return isSelected(); 15209 } 15210 } break; 15211 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 15212 if (isSelected()) { 15213 setSelected(false); 15214 return !isSelected(); 15215 } 15216 } break; 15217 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 15218 if (!isAccessibilityFocused()) { 15219 return requestAccessibilityFocus(); 15220 } 15221 } break; 15222 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 15223 if (isAccessibilityFocused()) { 15224 clearAccessibilityFocus(); 15225 return true; 15226 } 15227 } break; 15228 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 15229 if (arguments != null) { 15230 final int granularity = arguments.getInt( 15231 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 15232 final boolean extendSelection = arguments.getBoolean( 15233 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 15234 return traverseAtGranularity(granularity, true, extendSelection); 15235 } 15236 } break; 15237 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 15238 if (arguments != null) { 15239 final int granularity = arguments.getInt( 15240 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 15241 final boolean extendSelection = arguments.getBoolean( 15242 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 15243 return traverseAtGranularity(granularity, false, extendSelection); 15244 } 15245 } break; 15246 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 15247 CharSequence text = getIterableTextForAccessibility(); 15248 if (text == null) { 15249 return false; 15250 } 15251 final int start = (arguments != null) ? arguments.getInt( 15252 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 15253 final int end = (arguments != null) ? arguments.getInt( 15254 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 15255 // Only cursor position can be specified (selection length == 0) 15256 if ((getAccessibilitySelectionStart() != start 15257 || getAccessibilitySelectionEnd() != end) 15258 && (start == end)) { 15259 setAccessibilitySelection(start, end); 15260 notifyViewAccessibilityStateChangedIfNeeded( 15261 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 15262 return true; 15263 } 15264 } break; 15265 case R.id.accessibilityActionShowOnScreen: { 15266 if (mAttachInfo != null) { 15267 final Rect r = mAttachInfo.mTmpInvalRect; 15268 getDrawingRect(r); 15269 return requestRectangleOnScreen(r, true); 15270 } 15271 } break; 15272 case R.id.accessibilityActionContextClick: { 15273 if (isContextClickable()) { 15274 performContextClick(); 15275 return true; 15276 } 15277 } break; 15278 case R.id.accessibilityActionShowTooltip: { 15279 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipPopup != null)) { 15280 // Tooltip already showing 15281 return false; 15282 } 15283 return showLongClickTooltip(0, 0); 15284 } 15285 case R.id.accessibilityActionHideTooltip: { 15286 if ((mTooltipInfo == null) || (mTooltipInfo.mTooltipPopup == null)) { 15287 // No tooltip showing 15288 return false; 15289 } 15290 hideTooltip(); 15291 return true; 15292 } 15293 case R.id.accessibilityActionDragDrop: { 15294 if (!canAcceptAccessibilityDrop()) { 15295 return false; 15296 } 15297 try { 15298 if (mAttachInfo != null && mAttachInfo.mSession != null) { 15299 final int[] location = new int[2]; 15300 getLocationInWindow(location); 15301 final int centerX = location[0] + getWidth() / 2; 15302 final int centerY = location[1] + getHeight() / 2; 15303 return mAttachInfo.mSession.dropForAccessibility(mAttachInfo.mWindow, 15304 centerX, centerY); 15305 } 15306 } catch (RemoteException e) { 15307 Log.e(VIEW_LOG_TAG, "Unable to drop for accessibility", e); 15308 } 15309 return false; 15310 } 15311 case R.id.accessibilityActionDragCancel: { 15312 if (!startedSystemDragForAccessibility()) { 15313 return false; 15314 } 15315 if (mAttachInfo != null && mAttachInfo.mDragToken != null) { 15316 cancelDragAndDrop(); 15317 return true; 15318 } 15319 return false; 15320 } 15321 } 15322 return false; 15323 } 15324 canAcceptAccessibilityDrop()15325 private boolean canAcceptAccessibilityDrop() { 15326 if (!canAcceptDrag()) { 15327 return false; 15328 } 15329 ListenerInfo li = mListenerInfo; 15330 return (li != null) && (li.mOnDragListener != null || li.mOnReceiveContentListener != null); 15331 } 15332 traverseAtGranularity(int granularity, boolean forward, boolean extendSelection)15333 private boolean traverseAtGranularity(int granularity, boolean forward, 15334 boolean extendSelection) { 15335 CharSequence text = getIterableTextForAccessibility(); 15336 if (text == null || text.length() == 0) { 15337 return false; 15338 } 15339 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 15340 if (iterator == null) { 15341 return false; 15342 } 15343 int current = getAccessibilitySelectionEnd(); 15344 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 15345 current = forward ? 0 : text.length(); 15346 } 15347 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 15348 if (range == null) { 15349 return false; 15350 } 15351 final int segmentStart = range[0]; 15352 final int segmentEnd = range[1]; 15353 int selectionStart; 15354 int selectionEnd; 15355 if (extendSelection && isAccessibilitySelectionExtendable()) { 15356 prepareForExtendedAccessibilitySelection(); 15357 selectionStart = getAccessibilitySelectionStart(); 15358 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 15359 selectionStart = forward ? segmentStart : segmentEnd; 15360 } 15361 selectionEnd = forward ? segmentEnd : segmentStart; 15362 } else { 15363 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 15364 } 15365 setAccessibilitySelection(selectionStart, selectionEnd); 15366 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 15367 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 15368 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 15369 return true; 15370 } 15371 15372 /** 15373 * Gets the text reported for accessibility purposes. 15374 * 15375 * @return The accessibility text. 15376 * 15377 * @hide 15378 */ 15379 @UnsupportedAppUsage getIterableTextForAccessibility()15380 public CharSequence getIterableTextForAccessibility() { 15381 return getContentDescription(); 15382 } 15383 15384 /** 15385 * Gets whether accessibility selection can be extended. 15386 * 15387 * @return If selection is extensible. 15388 * 15389 * @hide 15390 */ isAccessibilitySelectionExtendable()15391 public boolean isAccessibilitySelectionExtendable() { 15392 return false; 15393 } 15394 15395 /** 15396 * Prepare for extended selection. 15397 * @hide 15398 */ prepareForExtendedAccessibilitySelection()15399 public void prepareForExtendedAccessibilitySelection() { 15400 return; 15401 } 15402 15403 /** 15404 * @hide 15405 */ getAccessibilitySelectionStart()15406 public int getAccessibilitySelectionStart() { 15407 return mAccessibilityCursorPosition; 15408 } 15409 15410 /** 15411 * @hide 15412 */ getAccessibilitySelectionEnd()15413 public int getAccessibilitySelectionEnd() { 15414 return getAccessibilitySelectionStart(); 15415 } 15416 15417 /** 15418 * @hide 15419 */ setAccessibilitySelection(int start, int end)15420 public void setAccessibilitySelection(int start, int end) { 15421 if (start == end && end == mAccessibilityCursorPosition) { 15422 return; 15423 } 15424 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 15425 mAccessibilityCursorPosition = start; 15426 } else { 15427 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 15428 } 15429 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 15430 } 15431 sendViewTextTraversedAtGranularityEvent(int action, int granularity, int fromIndex, int toIndex)15432 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 15433 int fromIndex, int toIndex) { 15434 if (mParent == null) { 15435 return; 15436 } 15437 AccessibilityEvent event = AccessibilityEvent.obtain( 15438 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 15439 onInitializeAccessibilityEvent(event); 15440 onPopulateAccessibilityEvent(event); 15441 event.setFromIndex(fromIndex); 15442 event.setToIndex(toIndex); 15443 event.setAction(action); 15444 event.setMovementGranularity(granularity); 15445 mParent.requestSendAccessibilityEvent(this, event); 15446 } 15447 15448 /** 15449 * @hide 15450 */ 15451 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getIteratorForGranularity(int granularity)15452 public TextSegmentIterator getIteratorForGranularity(int granularity) { 15453 switch (granularity) { 15454 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 15455 CharSequence text = getIterableTextForAccessibility(); 15456 if (text != null && text.length() > 0) { 15457 CharacterTextSegmentIterator iterator = 15458 CharacterTextSegmentIterator.getInstance( 15459 mContext.getResources().getConfiguration().locale); 15460 iterator.initialize(text.toString()); 15461 return iterator; 15462 } 15463 } break; 15464 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 15465 CharSequence text = getIterableTextForAccessibility(); 15466 if (text != null && text.length() > 0) { 15467 WordTextSegmentIterator iterator = 15468 WordTextSegmentIterator.getInstance( 15469 mContext.getResources().getConfiguration().locale); 15470 iterator.initialize(text.toString()); 15471 return iterator; 15472 } 15473 } break; 15474 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 15475 CharSequence text = getIterableTextForAccessibility(); 15476 if (text != null && text.length() > 0) { 15477 ParagraphTextSegmentIterator iterator = 15478 ParagraphTextSegmentIterator.getInstance(); 15479 iterator.initialize(text.toString()); 15480 return iterator; 15481 } 15482 } break; 15483 } 15484 return null; 15485 } 15486 15487 /** 15488 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 15489 * and {@link #onFinishTemporaryDetach()}. 15490 * 15491 * <p>This method always returns {@code true} when called directly or indirectly from 15492 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 15493 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 15494 * <ul> 15495 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 15496 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 15497 * </ul> 15498 * </p> 15499 * 15500 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 15501 * and {@link #onFinishTemporaryDetach()}. 15502 */ isTemporarilyDetached()15503 public final boolean isTemporarilyDetached() { 15504 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 15505 } 15506 15507 /** 15508 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 15509 * a container View. 15510 */ 15511 @CallSuper dispatchStartTemporaryDetach()15512 public void dispatchStartTemporaryDetach() { 15513 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 15514 notifyEnterOrExitForAutoFillIfNeeded(false); 15515 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 15516 onStartTemporaryDetach(); 15517 } 15518 15519 /** 15520 * This is called when a container is going to temporarily detach a child, with 15521 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 15522 * It will either be followed by {@link #onFinishTemporaryDetach()} or 15523 * {@link #onDetachedFromWindow()} when the container is done. 15524 */ onStartTemporaryDetach()15525 public void onStartTemporaryDetach() { 15526 removeUnsetPressCallback(); 15527 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 15528 } 15529 15530 /** 15531 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 15532 * a container View. 15533 */ 15534 @CallSuper dispatchFinishTemporaryDetach()15535 public void dispatchFinishTemporaryDetach() { 15536 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 15537 onFinishTemporaryDetach(); 15538 if (hasWindowFocus() && hasFocus()) { 15539 notifyFocusChangeToImeFocusController(true /* hasFocus */); 15540 } 15541 notifyEnterOrExitForAutoFillIfNeeded(true); 15542 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 15543 } 15544 15545 /** 15546 * Called after {@link #onStartTemporaryDetach} when the container is done 15547 * changing the view. 15548 */ onFinishTemporaryDetach()15549 public void onFinishTemporaryDetach() { 15550 } 15551 15552 /** 15553 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 15554 * for this view's window. Returns null if the view is not currently attached 15555 * to the window. Normally you will not need to use this directly, but 15556 * just use the standard high-level event callbacks like 15557 * {@link #onKeyDown(int, KeyEvent)}. 15558 */ getKeyDispatcherState()15559 public KeyEvent.DispatcherState getKeyDispatcherState() { 15560 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 15561 } 15562 15563 /** 15564 * Dispatch a key event before it is processed by any input method 15565 * associated with the view hierarchy. This can be used to intercept 15566 * key events in special situations before the IME consumes them; a 15567 * typical example would be handling the BACK key to update the application's 15568 * UI instead of allowing the IME to see it and close itself. 15569 * 15570 * @param event The key event to be dispatched. 15571 * @return True if the event was handled, false otherwise. 15572 */ dispatchKeyEventPreIme(KeyEvent event)15573 public boolean dispatchKeyEventPreIme(KeyEvent event) { 15574 return onKeyPreIme(event.getKeyCode(), event); 15575 } 15576 15577 /** 15578 * Dispatch a key event to the next view on the focus path. This path runs 15579 * from the top of the view tree down to the currently focused view. If this 15580 * view has focus, it will dispatch to itself. Otherwise it will dispatch 15581 * the next node down the focus path. This method also fires any key 15582 * listeners. 15583 * 15584 * @param event The key event to be dispatched. 15585 * @return True if the event was handled, false otherwise. 15586 */ dispatchKeyEvent(KeyEvent event)15587 public boolean dispatchKeyEvent(KeyEvent event) { 15588 if (mInputEventConsistencyVerifier != null) { 15589 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 15590 } 15591 15592 // Give any attached key listener a first crack at the event. 15593 //noinspection SimplifiableIfStatement 15594 ListenerInfo li = mListenerInfo; 15595 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 15596 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 15597 return true; 15598 } 15599 15600 if (event.dispatch(this, mAttachInfo != null 15601 ? mAttachInfo.mKeyDispatchState : null, this)) { 15602 return true; 15603 } 15604 15605 if (mInputEventConsistencyVerifier != null) { 15606 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 15607 } 15608 return false; 15609 } 15610 15611 /** 15612 * Dispatches a key shortcut event. 15613 * 15614 * @param event The key event to be dispatched. 15615 * @return True if the event was handled by the view, false otherwise. 15616 */ dispatchKeyShortcutEvent(KeyEvent event)15617 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 15618 return onKeyShortcut(event.getKeyCode(), event); 15619 } 15620 15621 /** 15622 * Pass the touch screen motion event down to the target view, or this 15623 * view if it is the target. 15624 * 15625 * @param event The motion event to be dispatched. 15626 * @return True if the event was handled by the view, false otherwise. 15627 * 15628 * @see #onTouchEvent(MotionEvent) 15629 */ dispatchTouchEvent(MotionEvent event)15630 public boolean dispatchTouchEvent(MotionEvent event) { 15631 // If the event should be handled by accessibility focus first. 15632 if (event.isTargetAccessibilityFocus()) { 15633 // We don't have focus or no virtual descendant has it, do not handle the event. 15634 if (!isAccessibilityFocusedViewOrHost()) { 15635 return false; 15636 } 15637 // We have focus and got the event, then use normal event dispatch. 15638 event.setTargetAccessibilityFocus(false); 15639 } 15640 boolean result = false; 15641 15642 if (mInputEventConsistencyVerifier != null) { 15643 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 15644 } 15645 15646 final int actionMasked = event.getActionMasked(); 15647 if (actionMasked == MotionEvent.ACTION_DOWN) { 15648 // Defensive cleanup for new gesture 15649 stopNestedScroll(); 15650 } 15651 15652 if (onFilterTouchEventForSecurity(event)) { 15653 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 15654 result = true; 15655 } 15656 //noinspection SimplifiableIfStatement 15657 ListenerInfo li = mListenerInfo; 15658 if (li != null && li.mOnTouchListener != null 15659 && (mViewFlags & ENABLED_MASK) == ENABLED 15660 && li.mOnTouchListener.onTouch(this, event)) { 15661 result = true; 15662 } 15663 15664 if (!result && onTouchEvent(event)) { 15665 result = true; 15666 } 15667 } 15668 15669 if (!result && mInputEventConsistencyVerifier != null) { 15670 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 15671 } 15672 15673 // Clean up after nested scrolls if this is the end of a gesture; 15674 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 15675 // of the gesture. 15676 if (actionMasked == MotionEvent.ACTION_UP || 15677 actionMasked == MotionEvent.ACTION_CANCEL || 15678 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 15679 stopNestedScroll(); 15680 } 15681 15682 return result; 15683 } 15684 isAccessibilityFocusedViewOrHost()15685 boolean isAccessibilityFocusedViewOrHost() { 15686 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 15687 .getAccessibilityFocusedHost() == this); 15688 } 15689 15690 /** 15691 * Returns whether this view can receive pointer events. 15692 * 15693 * @return {@code true} if this view can receive pointer events. 15694 * @hide 15695 */ canReceivePointerEvents()15696 protected boolean canReceivePointerEvents() { 15697 return (mViewFlags & VISIBILITY_MASK) == VISIBLE || getAnimation() != null; 15698 } 15699 15700 /** 15701 * Filter the touch event to apply security policies. 15702 * 15703 * @param event The motion event to be filtered. 15704 * @return True if the event should be dispatched, false if the event should be dropped. 15705 * 15706 * @see #getFilterTouchesWhenObscured 15707 */ onFilterTouchEventForSecurity(MotionEvent event)15708 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 15709 //noinspection RedundantIfStatement 15710 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 15711 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 15712 // Window is obscured, drop this touch. 15713 return false; 15714 } 15715 return true; 15716 } 15717 15718 /** 15719 * Pass a trackball motion event down to the focused view. 15720 * 15721 * @param event The motion event to be dispatched. 15722 * @return True if the event was handled by the view, false otherwise. 15723 * 15724 * @see #onTrackballEvent(MotionEvent) 15725 */ dispatchTrackballEvent(MotionEvent event)15726 public boolean dispatchTrackballEvent(MotionEvent event) { 15727 if (mInputEventConsistencyVerifier != null) { 15728 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 15729 } 15730 15731 return onTrackballEvent(event); 15732 } 15733 15734 /** 15735 * Pass a captured pointer event down to the focused view. 15736 * 15737 * @param event The motion event to be dispatched. 15738 * @return True if the event was handled by the view, false otherwise. 15739 */ dispatchCapturedPointerEvent(MotionEvent event)15740 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 15741 if (!hasPointerCapture()) { 15742 return false; 15743 } 15744 //noinspection SimplifiableIfStatement 15745 ListenerInfo li = mListenerInfo; 15746 if (li != null && li.mOnCapturedPointerListener != null 15747 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 15748 return true; 15749 } 15750 return onCapturedPointerEvent(event); 15751 } 15752 15753 /** 15754 * Dispatch a generic motion event. 15755 * <p> 15756 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 15757 * are delivered to the view under the pointer. All other generic motion events are 15758 * delivered to the focused view. Hover events are handled specially and are delivered 15759 * to {@link #onHoverEvent(MotionEvent)} first. 15760 * </p> 15761 * 15762 * @param event The motion event to be dispatched. 15763 * @return True if the event was handled by the view, false otherwise. 15764 * 15765 * @see #onHoverEvent(MotionEvent) 15766 * @see #onGenericMotionEvent(MotionEvent) 15767 */ dispatchGenericMotionEvent(MotionEvent event)15768 public boolean dispatchGenericMotionEvent(MotionEvent event) { 15769 if (mInputEventConsistencyVerifier != null) { 15770 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 15771 } 15772 15773 final int source = event.getSource(); 15774 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 15775 final int action = event.getAction(); 15776 if (action == MotionEvent.ACTION_HOVER_ENTER 15777 || action == MotionEvent.ACTION_HOVER_MOVE 15778 || action == MotionEvent.ACTION_HOVER_EXIT) { 15779 if (dispatchHoverEvent(event)) { 15780 return true; 15781 } 15782 } else if (dispatchGenericPointerEvent(event)) { 15783 return true; 15784 } 15785 } else if (dispatchGenericFocusedEvent(event)) { 15786 return true; 15787 } 15788 15789 if (dispatchGenericMotionEventInternal(event)) { 15790 return true; 15791 } 15792 15793 if (mInputEventConsistencyVerifier != null) { 15794 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 15795 } 15796 return false; 15797 } 15798 dispatchGenericMotionEventInternal(MotionEvent event)15799 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 15800 //noinspection SimplifiableIfStatement 15801 ListenerInfo li = mListenerInfo; 15802 if (li != null && li.mOnGenericMotionListener != null 15803 && (mViewFlags & ENABLED_MASK) == ENABLED 15804 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 15805 return true; 15806 } 15807 15808 if (onGenericMotionEvent(event)) { 15809 return true; 15810 } 15811 15812 final int actionButton = event.getActionButton(); 15813 switch (event.getActionMasked()) { 15814 case MotionEvent.ACTION_BUTTON_PRESS: 15815 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 15816 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 15817 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 15818 if (performContextClick(event.getX(), event.getY())) { 15819 mInContextButtonPress = true; 15820 setPressed(true, event.getX(), event.getY()); 15821 removeTapCallback(); 15822 removeLongPressCallback(); 15823 return true; 15824 } 15825 } 15826 break; 15827 15828 case MotionEvent.ACTION_BUTTON_RELEASE: 15829 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 15830 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 15831 mInContextButtonPress = false; 15832 mIgnoreNextUpEvent = true; 15833 } 15834 break; 15835 } 15836 15837 if (mInputEventConsistencyVerifier != null) { 15838 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 15839 } 15840 return false; 15841 } 15842 15843 /** 15844 * Dispatch a hover event. 15845 * <p> 15846 * Do not call this method directly. 15847 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 15848 * </p> 15849 * 15850 * @param event The motion event to be dispatched. 15851 * @return True if the event was handled by the view, false otherwise. 15852 */ dispatchHoverEvent(MotionEvent event)15853 protected boolean dispatchHoverEvent(MotionEvent event) { 15854 ListenerInfo li = mListenerInfo; 15855 //noinspection SimplifiableIfStatement 15856 if (li != null && li.mOnHoverListener != null 15857 && (mViewFlags & ENABLED_MASK) == ENABLED 15858 && li.mOnHoverListener.onHover(this, event)) { 15859 return true; 15860 } 15861 15862 return onHoverEvent(event); 15863 } 15864 15865 /** 15866 * Returns true if the view has a child to which it has recently sent 15867 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 15868 * it does not have a hovered child, then it must be the innermost hovered view. 15869 * @hide 15870 */ hasHoveredChild()15871 protected boolean hasHoveredChild() { 15872 return false; 15873 } 15874 15875 /** 15876 * Returns true if the given point, in local coordinates, is inside the hovered child. 15877 * 15878 * @hide 15879 */ pointInHoveredChild(MotionEvent event)15880 protected boolean pointInHoveredChild(MotionEvent event) { 15881 return false; 15882 } 15883 15884 /** 15885 * Dispatch a generic motion event to the view under the first pointer. 15886 * <p> 15887 * Do not call this method directly. 15888 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 15889 * </p> 15890 * 15891 * @param event The motion event to be dispatched. 15892 * @return True if the event was handled by the view, false otherwise. 15893 */ dispatchGenericPointerEvent(MotionEvent event)15894 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 15895 return false; 15896 } 15897 15898 /** 15899 * Dispatch a generic motion event to the currently focused view. 15900 * <p> 15901 * Do not call this method directly. 15902 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 15903 * </p> 15904 * 15905 * @param event The motion event to be dispatched. 15906 * @return True if the event was handled by the view, false otherwise. 15907 */ dispatchGenericFocusedEvent(MotionEvent event)15908 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 15909 return false; 15910 } 15911 15912 /** 15913 * Dispatch a pointer event. 15914 * <p> 15915 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 15916 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 15917 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 15918 * and should not be expected to handle other pointing device features. 15919 * </p> 15920 * 15921 * @param event The motion event to be dispatched. 15922 * @return True if the event was handled by the view, false otherwise. 15923 * @hide 15924 */ 15925 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) dispatchPointerEvent(MotionEvent event)15926 public final boolean dispatchPointerEvent(MotionEvent event) { 15927 if (event.isTouchEvent()) { 15928 return dispatchTouchEvent(event); 15929 } else { 15930 return dispatchGenericMotionEvent(event); 15931 } 15932 } 15933 15934 /** 15935 * Called when the window containing this view gains or loses window focus. 15936 * ViewGroups should override to route to their children. 15937 * 15938 * @param hasFocus True if the window containing this view now has focus, 15939 * false otherwise. 15940 */ dispatchWindowFocusChanged(boolean hasFocus)15941 public void dispatchWindowFocusChanged(boolean hasFocus) { 15942 onWindowFocusChanged(hasFocus); 15943 } 15944 15945 /** 15946 * Called when the window containing this view gains or loses focus. Note 15947 * that this is separate from view focus: to receive key events, both 15948 * your view and its window must have focus. If a window is displayed 15949 * on top of yours that takes input focus, then your own window will lose 15950 * focus but the view focus will remain unchanged. 15951 * 15952 * @param hasWindowFocus True if the window containing this view now has 15953 * focus, false otherwise. 15954 */ onWindowFocusChanged(boolean hasWindowFocus)15955 public void onWindowFocusChanged(boolean hasWindowFocus) { 15956 if (!hasWindowFocus) { 15957 if (isPressed()) { 15958 setPressed(false); 15959 } 15960 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 15961 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 15962 notifyFocusChangeToImeFocusController(false /* hasFocus */); 15963 } 15964 removeLongPressCallback(); 15965 removeTapCallback(); 15966 onFocusLost(); 15967 } else if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 15968 notifyFocusChangeToImeFocusController(true /* hasFocus */); 15969 } 15970 15971 refreshDrawableState(); 15972 } 15973 15974 /** 15975 * Returns true if this view is in a window that currently has window focus. 15976 * Note that this is not the same as the view itself having focus. 15977 * 15978 * @return True if this view is in a window that currently has window focus. 15979 */ hasWindowFocus()15980 public boolean hasWindowFocus() { 15981 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 15982 } 15983 15984 /** 15985 * @return {@code true} if this view is in a window that currently has IME focusable state. 15986 * @hide 15987 */ hasImeFocus()15988 public boolean hasImeFocus() { 15989 return getViewRootImpl() != null && getViewRootImpl().getImeFocusController().hasImeFocus(); 15990 } 15991 15992 /** 15993 * Dispatch a view visibility change down the view hierarchy. 15994 * ViewGroups should override to route to their children. 15995 * @param changedView The view whose visibility changed. Could be 'this' or 15996 * an ancestor view. 15997 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 15998 * {@link #INVISIBLE} or {@link #GONE}. 15999 */ dispatchVisibilityChanged(@onNull View changedView, @Visibility int visibility)16000 protected void dispatchVisibilityChanged(@NonNull View changedView, 16001 @Visibility int visibility) { 16002 onVisibilityChanged(changedView, visibility); 16003 } 16004 16005 /** 16006 * Called when the visibility of the view or an ancestor of the view has 16007 * changed. 16008 * 16009 * @param changedView The view whose visibility changed. May be 16010 * {@code this} or an ancestor view. 16011 * @param visibility The new visibility, one of {@link #VISIBLE}, 16012 * {@link #INVISIBLE} or {@link #GONE}. 16013 */ onVisibilityChanged(@onNull View changedView, @Visibility int visibility)16014 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 16015 } 16016 16017 /** 16018 * Dispatch a hint about whether this view is displayed. For instance, when 16019 * a View moves out of the screen, it might receives a display hint indicating 16020 * the view is not displayed. Applications should not <em>rely</em> on this hint 16021 * as there is no guarantee that they will receive one. 16022 * 16023 * @param hint A hint about whether or not this view is displayed: 16024 * {@link #VISIBLE} or {@link #INVISIBLE}. 16025 */ dispatchDisplayHint(@isibility int hint)16026 public void dispatchDisplayHint(@Visibility int hint) { 16027 onDisplayHint(hint); 16028 } 16029 16030 /** 16031 * Gives this view a hint about whether is displayed or not. For instance, when 16032 * a View moves out of the screen, it might receives a display hint indicating 16033 * the view is not displayed. Applications should not <em>rely</em> on this hint 16034 * as there is no guarantee that they will receive one. 16035 * 16036 * @param hint A hint about whether or not this view is displayed: 16037 * {@link #VISIBLE} or {@link #INVISIBLE}. 16038 */ onDisplayHint(@isibility int hint)16039 protected void onDisplayHint(@Visibility int hint) { 16040 } 16041 16042 /** 16043 * Dispatch a window visibility change down the view hierarchy. 16044 * ViewGroups should override to route to their children. 16045 * 16046 * @param visibility The new visibility of the window. 16047 * 16048 * @see #onWindowVisibilityChanged(int) 16049 */ dispatchWindowVisibilityChanged(@isibility int visibility)16050 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 16051 onWindowVisibilityChanged(visibility); 16052 } 16053 16054 /** 16055 * Called when the window containing has change its visibility 16056 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 16057 * that this tells you whether or not your window is being made visible 16058 * to the window manager; this does <em>not</em> tell you whether or not 16059 * your window is obscured by other windows on the screen, even if it 16060 * is itself visible. 16061 * 16062 * @param visibility The new visibility of the window. 16063 */ onWindowVisibilityChanged(@isibility int visibility)16064 protected void onWindowVisibilityChanged(@Visibility int visibility) { 16065 if (visibility == VISIBLE) { 16066 initialAwakenScrollBars(); 16067 } 16068 } 16069 16070 /** 16071 * @return true if this view and all ancestors are visible as of the last 16072 * {@link #onVisibilityAggregated(boolean)} call. 16073 * 16074 * @hide 16075 */ isAggregatedVisible()16076 public boolean isAggregatedVisible() { 16077 return (mPrivateFlags3 & PFLAG3_AGGREGATED_VISIBLE) != 0; 16078 } 16079 16080 /** 16081 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 16082 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 16083 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 16084 * 16085 * @param isVisible true if this view's visibility to the user is uninterrupted by its 16086 * ancestors or by window visibility 16087 * @return true if this view is visible to the user, not counting clipping or overlapping 16088 */ dispatchVisibilityAggregated(boolean isVisible)16089 boolean dispatchVisibilityAggregated(boolean isVisible) { 16090 final boolean thisVisible = getVisibility() == VISIBLE; 16091 // If we're not visible but something is telling us we are, ignore it. 16092 if (thisVisible || !isVisible) { 16093 onVisibilityAggregated(isVisible); 16094 } 16095 return thisVisible && isVisible; 16096 } 16097 16098 /** 16099 * Called when the user-visibility of this View is potentially affected by a change 16100 * to this view itself, an ancestor view or the window this view is attached to. 16101 * 16102 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 16103 * and this view's window is also visible 16104 */ 16105 @CallSuper onVisibilityAggregated(boolean isVisible)16106 public void onVisibilityAggregated(boolean isVisible) { 16107 // Update our internal visibility tracking so we can detect changes 16108 boolean oldVisible = isAggregatedVisible(); 16109 mPrivateFlags3 = isVisible ? (mPrivateFlags3 | PFLAG3_AGGREGATED_VISIBLE) 16110 : (mPrivateFlags3 & ~PFLAG3_AGGREGATED_VISIBLE); 16111 if (isVisible && mAttachInfo != null) { 16112 initialAwakenScrollBars(); 16113 } 16114 16115 final Drawable dr = mBackground; 16116 if (dr != null && isVisible != dr.isVisible()) { 16117 dr.setVisible(isVisible, false); 16118 } 16119 final Drawable hl = mDefaultFocusHighlight; 16120 if (hl != null && isVisible != hl.isVisible()) { 16121 hl.setVisible(isVisible, false); 16122 } 16123 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 16124 if (fg != null && isVisible != fg.isVisible()) { 16125 fg.setVisible(isVisible, false); 16126 } 16127 16128 if (isAutofillable()) { 16129 AutofillManager afm = getAutofillManager(); 16130 16131 if (afm != null && getAutofillViewId() > LAST_APP_AUTOFILL_ID) { 16132 if (mVisibilityChangeForAutofillHandler != null) { 16133 mVisibilityChangeForAutofillHandler.removeMessages(0); 16134 } 16135 16136 // If the view is in the background but still part of the hierarchy this is called 16137 // with isVisible=false. Hence visibility==false requires further checks 16138 if (isVisible) { 16139 afm.notifyViewVisibilityChanged(this, true); 16140 } else { 16141 if (mVisibilityChangeForAutofillHandler == null) { 16142 mVisibilityChangeForAutofillHandler = 16143 new VisibilityChangeForAutofillHandler(afm, this); 16144 } 16145 // Let current operation (e.g. removal of the view from the hierarchy) 16146 // finish before checking state 16147 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); 16148 } 16149 } 16150 } 16151 16152 if (isVisible != oldVisible) { 16153 if (isAccessibilityPane()) { 16154 notifyViewAccessibilityStateChangedIfNeeded(isVisible 16155 ? AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED 16156 : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); 16157 } 16158 16159 notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); 16160 16161 if (!getSystemGestureExclusionRects().isEmpty()) { 16162 postUpdate(this::updateSystemGestureExclusionRects); 16163 } 16164 16165 if (!collectPreferKeepClearRects().isEmpty()) { 16166 postUpdate(this::updateKeepClearRects); 16167 } 16168 } 16169 } 16170 16171 /** 16172 * Returns the current visibility of the window this view is attached to 16173 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 16174 * 16175 * @return Returns the current visibility of the view's window. 16176 */ 16177 @Visibility getWindowVisibility()16178 public int getWindowVisibility() { 16179 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 16180 } 16181 16182 /** 16183 * Retrieve the overall visible display size in which the window this view is 16184 * attached to has been positioned in. This takes into account screen 16185 * decorations above the window, for both cases where the window itself 16186 * is being position inside of them or the window is being placed under 16187 * then and covered insets are used for the window to position its content 16188 * inside. In effect, this tells you the available area where content can 16189 * be placed and remain visible to users. 16190 * 16191 * @param outRect Filled in with the visible display frame. If the view 16192 * is not attached to a window, this is simply the raw display size. 16193 */ getWindowVisibleDisplayFrame(Rect outRect)16194 public void getWindowVisibleDisplayFrame(Rect outRect) { 16195 if (mAttachInfo != null) { 16196 mAttachInfo.mViewRootImpl.getWindowVisibleDisplayFrame(outRect); 16197 return; 16198 } 16199 // The view is not attached to a display so we don't have a context. 16200 // Make a best guess about the display size. 16201 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 16202 d.getRectSize(outRect); 16203 } 16204 16205 /** 16206 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 16207 * is currently in without any insets. 16208 * 16209 * @hide 16210 */ 16211 @UnsupportedAppUsage 16212 @TestApi getWindowDisplayFrame(@onNull Rect outRect)16213 public void getWindowDisplayFrame(@NonNull Rect outRect) { 16214 if (mAttachInfo != null) { 16215 mAttachInfo.mViewRootImpl.getDisplayFrame(outRect); 16216 return; 16217 } 16218 // The view is not attached to a display so we don't have a context. 16219 // Make a best guess about the display size. 16220 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 16221 d.getRectSize(outRect); 16222 } 16223 16224 /** 16225 * Dispatch a notification about a resource configuration change down 16226 * the view hierarchy. 16227 * ViewGroups should override to route to their children. 16228 * 16229 * @param newConfig The new resource configuration. 16230 * 16231 * @see #onConfigurationChanged(android.content.res.Configuration) 16232 */ dispatchConfigurationChanged(Configuration newConfig)16233 public void dispatchConfigurationChanged(Configuration newConfig) { 16234 onConfigurationChanged(newConfig); 16235 } 16236 16237 /** 16238 * Called when the current configuration of the resources being used 16239 * by the application have changed. You can use this to decide when 16240 * to reload resources that can changed based on orientation and other 16241 * configuration characteristics. You only need to use this if you are 16242 * not relying on the normal {@link android.app.Activity} mechanism of 16243 * recreating the activity instance upon a configuration change. 16244 * 16245 * @param newConfig The new resource configuration. 16246 */ onConfigurationChanged(Configuration newConfig)16247 protected void onConfigurationChanged(Configuration newConfig) { 16248 } 16249 16250 /** 16251 * Private function to aggregate all per-view attributes in to the view 16252 * root. 16253 */ dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility)16254 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 16255 performCollectViewAttributes(attachInfo, visibility); 16256 } 16257 performCollectViewAttributes(AttachInfo attachInfo, int visibility)16258 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 16259 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 16260 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 16261 attachInfo.mKeepScreenOn = true; 16262 } 16263 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 16264 ListenerInfo li = mListenerInfo; 16265 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 16266 attachInfo.mHasSystemUiListeners = true; 16267 } 16268 } 16269 } 16270 needGlobalAttributesUpdate(boolean force)16271 void needGlobalAttributesUpdate(boolean force) { 16272 final AttachInfo ai = mAttachInfo; 16273 if (ai != null && !ai.mRecomputeGlobalAttributes) { 16274 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 16275 || ai.mHasSystemUiListeners) { 16276 ai.mRecomputeGlobalAttributes = true; 16277 } 16278 } 16279 } 16280 16281 /** 16282 * Returns the touch mode state associated with this view. 16283 * 16284 * Attached views return the touch mode state from the associated window's display. 16285 * Detached views just return the default touch mode value defined in 16286 * {@code com.android.internal.R.bool.config_defaultInTouchMode}. 16287 * 16288 * Touch mode is entered once the user begins interacting with the device by touch, and 16289 * affects various things like whether focus highlight is always visible to the user. 16290 * 16291 * @return the touch mode state associated with this view 16292 */ 16293 @ViewDebug.ExportedProperty isInTouchMode()16294 public boolean isInTouchMode() { 16295 if (mAttachInfo != null) { 16296 return mAttachInfo.mInTouchMode; 16297 } 16298 return mResources.getBoolean(com.android.internal.R.bool.config_defaultInTouchMode); 16299 } 16300 16301 /** 16302 * Returns the context the view is running in, through which it can 16303 * access the current theme, resources, etc. 16304 * 16305 * @return The view's Context. 16306 */ 16307 @ViewDebug.CapturedViewProperty 16308 @UiContext getContext()16309 public final Context getContext() { 16310 return mContext; 16311 } 16312 16313 /** 16314 * Handle a key event before it is processed by any input method 16315 * associated with the view hierarchy. This can be used to intercept 16316 * key events in special situations before the IME consumes them; a 16317 * typical example would be handling the BACK key to update the application's 16318 * UI instead of allowing the IME to see it and close itself. 16319 * 16320 * @param keyCode The value in event.getKeyCode(). 16321 * @param event Description of the key event. 16322 * @return If you handled the event, return true. If you want to allow the 16323 * event to be handled by the next receiver, return false. 16324 */ onKeyPreIme(int keyCode, KeyEvent event)16325 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 16326 return false; 16327 } 16328 16329 /** 16330 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 16331 * KeyEvent.Callback.onKeyDown()}: perform press of the view 16332 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 16333 * is released, if the view is enabled and clickable. 16334 * <p> 16335 * Key presses in software keyboards will generally NOT trigger this 16336 * listener, although some may elect to do so in some situations. Do not 16337 * rely on this to catch software key presses. 16338 * 16339 * @param keyCode a key code that represents the button pressed, from 16340 * {@link android.view.KeyEvent} 16341 * @param event the KeyEvent object that defines the button action 16342 */ onKeyDown(int keyCode, KeyEvent event)16343 public boolean onKeyDown(int keyCode, KeyEvent event) { 16344 if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) { 16345 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 16346 return true; 16347 } 16348 16349 if (event.getRepeatCount() == 0) { 16350 // Long clickable items don't necessarily have to be clickable. 16351 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 16352 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 16353 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 16354 // For the purposes of menu anchoring and drawable hotspots, 16355 // key events are considered to be at the center of the view. 16356 final float x = getWidth() / 2f; 16357 final float y = getHeight() / 2f; 16358 if (clickable) { 16359 setPressed(true, x, y); 16360 } 16361 checkForLongClick( 16362 ViewConfiguration.getLongPressTimeout(), 16363 x, 16364 y, 16365 // This is not a touch gesture -- do not classify it as one. 16366 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION); 16367 return true; 16368 } 16369 } 16370 } 16371 16372 return false; 16373 } 16374 16375 /** 16376 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 16377 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 16378 * the event). 16379 * <p>Key presses in software keyboards will generally NOT trigger this listener, 16380 * although some may elect to do so in some situations. Do not rely on this to 16381 * catch software key presses. 16382 */ onKeyLongPress(int keyCode, KeyEvent event)16383 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 16384 return false; 16385 } 16386 16387 /** 16388 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 16389 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 16390 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 16391 * or {@link KeyEvent#KEYCODE_SPACE} is released. 16392 * <p>Key presses in software keyboards will generally NOT trigger this listener, 16393 * although some may elect to do so in some situations. Do not rely on this to 16394 * catch software key presses. 16395 * 16396 * @param keyCode A key code that represents the button pressed, from 16397 * {@link android.view.KeyEvent}. 16398 * @param event The KeyEvent object that defines the button action. 16399 */ onKeyUp(int keyCode, KeyEvent event)16400 public boolean onKeyUp(int keyCode, KeyEvent event) { 16401 if (KeyEvent.isConfirmKey(keyCode) && event.hasNoModifiers()) { 16402 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 16403 return true; 16404 } 16405 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 16406 setPressed(false); 16407 16408 if (!mHasPerformedLongPress) { 16409 // This is a tap, so remove the longpress check 16410 removeLongPressCallback(); 16411 if (!event.isCanceled()) { 16412 return performClickInternal(); 16413 } 16414 } 16415 } 16416 } 16417 return false; 16418 } 16419 16420 /** 16421 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 16422 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 16423 * the event). 16424 * <p>Key presses in software keyboards will generally NOT trigger this listener, 16425 * although some may elect to do so in some situations. Do not rely on this to 16426 * catch software key presses. 16427 * 16428 * @param keyCode A key code that represents the button pressed, from 16429 * {@link android.view.KeyEvent}. 16430 * @param repeatCount The number of times the action was made. 16431 * @param event The KeyEvent object that defines the button action. 16432 */ onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)16433 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 16434 return false; 16435 } 16436 16437 /** 16438 * Called on the focused view when a key shortcut event is not handled. 16439 * Override this method to implement local key shortcuts for the View. 16440 * Key shortcuts can also be implemented by setting the 16441 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 16442 * 16443 * @param keyCode The value in event.getKeyCode(). 16444 * @param event Description of the key event. 16445 * @return If you handled the event, return true. If you want to allow the 16446 * event to be handled by the next receiver, return false. 16447 */ onKeyShortcut(int keyCode, KeyEvent event)16448 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 16449 return false; 16450 } 16451 16452 /** 16453 * Check whether the called view is a text editor, in which case it 16454 * would make sense to automatically display a soft input window for 16455 * it. Subclasses should override this if they implement 16456 * {@link #onCreateInputConnection(EditorInfo)} to return true if 16457 * a call on that method would return a non-null InputConnection, and 16458 * they are really a first-class editor that the user would normally 16459 * start typing on when the go into a window containing your view. 16460 * 16461 * <p>The default implementation always returns false. This does 16462 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 16463 * will not be called or the user can not otherwise perform edits on your 16464 * view; it is just a hint to the system that this is not the primary 16465 * purpose of this view. 16466 * 16467 * @return Returns true if this view is a text editor, else false. 16468 */ onCheckIsTextEditor()16469 public boolean onCheckIsTextEditor() { 16470 return false; 16471 } 16472 16473 /** 16474 * Create a new InputConnection for an InputMethod to interact 16475 * with the view. The default implementation returns null, since it doesn't 16476 * support input methods. You can override this to implement such support. 16477 * This is only needed for views that take focus and text input. 16478 * 16479 * <p>When implementing this, you probably also want to implement 16480 * {@link #onCheckIsTextEditor()} to indicate you will return a 16481 * non-null InputConnection.</p> 16482 * 16483 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 16484 * object correctly and in its entirety, so that the connected IME can rely 16485 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 16486 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 16487 * must be filled in with the correct cursor position for IMEs to work correctly 16488 * with your application.</p> 16489 * 16490 * @param outAttrs Fill in with attribute information about the connection. 16491 */ onCreateInputConnection(EditorInfo outAttrs)16492 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 16493 return null; 16494 } 16495 16496 /** 16497 * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application 16498 * that the system has successfully initialized an {@link InputConnection} and it is ready for 16499 * use. 16500 * 16501 * <p>The default implementation does nothing, since a view doesn't support input methods by 16502 * default (see {@link #onCreateInputConnection}). 16503 * 16504 * @param inputConnection The {@link InputConnection} from {@link #onCreateInputConnection}, 16505 * after it's been fully initialized by the system. 16506 * @param editorInfo The {@link EditorInfo} that was used to create the {@link InputConnection}. 16507 * @param handler The dedicated {@link Handler} on which IPC method calls from input methods 16508 * will be dispatched. This is the handler returned by {@link InputConnection#getHandler()}. If 16509 * that method returns null, this parameter will be null also. 16510 * 16511 * @hide 16512 */ onInputConnectionOpenedInternal(@onNull InputConnection inputConnection, @NonNull EditorInfo editorInfo, @Nullable Handler handler)16513 public void onInputConnectionOpenedInternal(@NonNull InputConnection inputConnection, 16514 @NonNull EditorInfo editorInfo, @Nullable Handler handler) {} 16515 16516 /** 16517 * Called by the {@link android.view.inputmethod.InputMethodManager} to notify the application 16518 * that the {@link InputConnection} has been closed. 16519 * 16520 * <p>The default implementation does nothing, since a view doesn't support input methods by 16521 * default (see {@link #onCreateInputConnection}). 16522 * 16523 * <p><strong>Note:</strong> This callback is not invoked if the view is already detached when 16524 * the {@link InputConnection} is closed or the connection is not valid and managed by 16525 * {@link com.android.server.inputmethod.InputMethodManagerService}. 16526 * TODO(b/170645312): Before un-hiding this API, handle the detached view scenario. 16527 * 16528 * @hide 16529 */ onInputConnectionClosedInternal()16530 public void onInputConnectionClosedInternal() {} 16531 16532 /** 16533 * Called by the {@link android.view.inputmethod.InputMethodManager} 16534 * when a view who is not the current 16535 * input connection target is trying to make a call on the manager. The 16536 * default implementation returns false; you can override this to return 16537 * true for certain views if you are performing InputConnection proxying 16538 * to them. 16539 * @param view The View that is making the InputMethodManager call. 16540 * @return Return true to allow the call, false to reject. 16541 */ checkInputConnectionProxy(View view)16542 public boolean checkInputConnectionProxy(View view) { 16543 return false; 16544 } 16545 16546 /** 16547 * Show the context menu for this view. It is not safe to hold on to the 16548 * menu after returning from this method. 16549 * 16550 * You should normally not overload this method. Overload 16551 * {@link #onCreateContextMenu(ContextMenu)} or define an 16552 * {@link OnCreateContextMenuListener} to add items to the context menu. 16553 * 16554 * @param menu The context menu to populate 16555 */ createContextMenu(ContextMenu menu)16556 public void createContextMenu(ContextMenu menu) { 16557 ContextMenuInfo menuInfo = getContextMenuInfo(); 16558 16559 // Sets the current menu info so all items added to menu will have 16560 // my extra info set. 16561 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 16562 16563 onCreateContextMenu(menu); 16564 ListenerInfo li = mListenerInfo; 16565 if (li != null && li.mOnCreateContextMenuListener != null) { 16566 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 16567 } 16568 16569 // Clear the extra information so subsequent items that aren't mine don't 16570 // have my extra info. 16571 ((MenuBuilder)menu).setCurrentMenuInfo(null); 16572 16573 if (mParent != null) { 16574 mParent.createContextMenu(menu); 16575 } 16576 } 16577 16578 /** 16579 * Views should implement this if they have extra information to associate 16580 * with the context menu. The return result is supplied as a parameter to 16581 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 16582 * callback. 16583 * 16584 * @return Extra information about the item for which the context menu 16585 * should be shown. This information will vary across different 16586 * subclasses of View. 16587 */ getContextMenuInfo()16588 protected ContextMenuInfo getContextMenuInfo() { 16589 return null; 16590 } 16591 16592 /** 16593 * Views should implement this if the view itself is going to add items to 16594 * the context menu. 16595 * 16596 * @param menu the context menu to populate 16597 */ onCreateContextMenu(ContextMenu menu)16598 protected void onCreateContextMenu(ContextMenu menu) { 16599 } 16600 16601 /** 16602 * Implement this method to handle trackball motion events. 16603 * <p> 16604 * The <em>relative</em> movement of the trackball since the last event 16605 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 16606 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 16607 * that a movement of 1 corresponds to the user pressing one DPAD key (so 16608 * they will often be fractional values, representing the more fine-grained 16609 * movement information available from a trackball). 16610 * </p> 16611 * 16612 * @param event The motion event. 16613 * @return True if the event was handled, false otherwise. 16614 */ onTrackballEvent(MotionEvent event)16615 public boolean onTrackballEvent(MotionEvent event) { 16616 return false; 16617 } 16618 16619 /** 16620 * Implement this method to handle generic motion events. 16621 * <p> 16622 * Generic motion events describe joystick movements, hover events from mouse or stylus 16623 * devices, trackpad touches, scroll wheel movements and other motion events not handled 16624 * by {@link #onTouchEvent(MotionEvent)} or {@link #onTrackballEvent(MotionEvent)}. 16625 * The {@link MotionEvent#getSource() source} of the motion event specifies 16626 * the class of input that was received. Implementations of this method 16627 * must examine the bits in the source before processing the event. 16628 * The following code example shows how this is done. 16629 * </p><p> 16630 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 16631 * are delivered to the view under the pointer. All other generic motion events are 16632 * delivered to the focused view. 16633 * </p> 16634 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 16635 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 16636 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 16637 * // process the joystick movement... 16638 * return true; 16639 * } 16640 * } 16641 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 16642 * switch (event.getAction()) { 16643 * case MotionEvent.ACTION_HOVER_MOVE: 16644 * // process the hover movement... 16645 * return true; 16646 * case MotionEvent.ACTION_SCROLL: 16647 * // process the scroll wheel movement... 16648 * return true; 16649 * } 16650 * } 16651 * return super.onGenericMotionEvent(event); 16652 * }</pre> 16653 * 16654 * @param event The generic motion event being processed. 16655 * @return True if the event was handled, false otherwise. 16656 */ onGenericMotionEvent(MotionEvent event)16657 public boolean onGenericMotionEvent(MotionEvent event) { 16658 return false; 16659 } 16660 16661 /** 16662 * Dispatching hover events to {@link TouchDelegate} to improve accessibility. 16663 * <p> 16664 * This method is dispatching hover events to the delegate target to support explore by touch. 16665 * Similar to {@link ViewGroup#dispatchTouchEvent}, this method send proper hover events to 16666 * the delegate target according to the pointer and the touch area of the delegate while touch 16667 * exploration enabled. 16668 * </p> 16669 * 16670 * @param event The motion event dispatch to the delegate target. 16671 * @return True if the event was handled, false otherwise. 16672 * 16673 * @see #onHoverEvent 16674 */ dispatchTouchExplorationHoverEvent(MotionEvent event)16675 private boolean dispatchTouchExplorationHoverEvent(MotionEvent event) { 16676 final AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 16677 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 16678 return false; 16679 } 16680 16681 final boolean oldHoveringTouchDelegate = mHoveringTouchDelegate; 16682 final int action = event.getActionMasked(); 16683 boolean pointInDelegateRegion = false; 16684 boolean handled = false; 16685 16686 final AccessibilityNodeInfo.TouchDelegateInfo info = mTouchDelegate.getTouchDelegateInfo(); 16687 for (int i = 0; i < info.getRegionCount(); i++) { 16688 Region r = info.getRegionAt(i); 16689 if (r.contains((int) event.getX(), (int) event.getY())) { 16690 pointInDelegateRegion = true; 16691 } 16692 } 16693 16694 // Explore by touch should dispatch events to children under the pointer first if any 16695 // before dispatching to TouchDelegate. For non-hoverable views that do not consume 16696 // hover events but receive accessibility focus, it should also not delegate to these 16697 // views when hovered. 16698 if (!oldHoveringTouchDelegate) { 16699 if ((action == MotionEvent.ACTION_HOVER_ENTER 16700 || action == MotionEvent.ACTION_HOVER_MOVE) 16701 && !pointInHoveredChild(event) 16702 && pointInDelegateRegion) { 16703 mHoveringTouchDelegate = true; 16704 } 16705 } else { 16706 if (action == MotionEvent.ACTION_HOVER_EXIT 16707 || (action == MotionEvent.ACTION_HOVER_MOVE 16708 && (pointInHoveredChild(event) || !pointInDelegateRegion))) { 16709 mHoveringTouchDelegate = false; 16710 } 16711 } 16712 switch (action) { 16713 case MotionEvent.ACTION_HOVER_MOVE: 16714 if (oldHoveringTouchDelegate && mHoveringTouchDelegate) { 16715 // Inside bounds, dispatch as is. 16716 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 16717 } else if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 16718 // Moving inbound, synthesize hover enter. 16719 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 16720 ? event : MotionEvent.obtainNoHistory(event); 16721 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER); 16722 handled = mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 16723 eventNoHistory.setAction(action); 16724 handled |= mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 16725 } else if (oldHoveringTouchDelegate && !mHoveringTouchDelegate) { 16726 // Moving outbound, synthesize hover exit. 16727 final boolean hoverExitPending = event.isHoverExitPending(); 16728 event.setHoverExitPending(true); 16729 mTouchDelegate.onTouchExplorationHoverEvent(event); 16730 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 16731 ? event : MotionEvent.obtainNoHistory(event); 16732 eventNoHistory.setHoverExitPending(hoverExitPending); 16733 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); 16734 mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 16735 } // else: outside bounds, do nothing. 16736 break; 16737 case MotionEvent.ACTION_HOVER_ENTER: 16738 if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 16739 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 16740 } 16741 break; 16742 case MotionEvent.ACTION_HOVER_EXIT: 16743 if (oldHoveringTouchDelegate) { 16744 mTouchDelegate.onTouchExplorationHoverEvent(event); 16745 } 16746 break; 16747 } 16748 return handled; 16749 } 16750 16751 /** 16752 * Implement this method to handle hover events. 16753 * <p> 16754 * This method is called whenever a pointer is hovering into, over, or out of the 16755 * bounds of a view and the view is not currently being touched. 16756 * Hover events are represented as pointer events with action 16757 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 16758 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 16759 * </p> 16760 * <ul> 16761 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 16762 * when the pointer enters the bounds of the view.</li> 16763 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 16764 * when the pointer has already entered the bounds of the view and has moved.</li> 16765 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 16766 * when the pointer has exited the bounds of the view or when the pointer is 16767 * about to go down due to a button click, tap, or similar user action that 16768 * causes the view to be touched.</li> 16769 * </ul> 16770 * <p> 16771 * The view should implement this method to return true to indicate that it is 16772 * handling the hover event, such as by changing its drawable state. 16773 * </p><p> 16774 * The default implementation calls {@link #setHovered} to update the hovered state 16775 * of the view when a hover enter or hover exit event is received, if the view 16776 * is enabled and is clickable. The default implementation also sends hover 16777 * accessibility events. 16778 * </p> 16779 * 16780 * @param event The motion event that describes the hover. 16781 * @return True if the view handled the hover event. 16782 * 16783 * @see #isHovered 16784 * @see #setHovered 16785 * @see #onHoverChanged 16786 */ onHoverEvent(MotionEvent event)16787 public boolean onHoverEvent(MotionEvent event) { 16788 if (mTouchDelegate != null && dispatchTouchExplorationHoverEvent(event)) { 16789 return true; 16790 } 16791 16792 // The root view may receive hover (or touch) events that are outside the bounds of 16793 // the window. This code ensures that we only send accessibility events for 16794 // hovers that are actually within the bounds of the root view. 16795 final int action = event.getActionMasked(); 16796 if (!mSendingHoverAccessibilityEvents) { 16797 if ((action == MotionEvent.ACTION_HOVER_ENTER 16798 || action == MotionEvent.ACTION_HOVER_MOVE) 16799 && !hasHoveredChild() 16800 && pointInView(event.getX(), event.getY())) { 16801 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 16802 mSendingHoverAccessibilityEvents = true; 16803 } 16804 } else { 16805 if (action == MotionEvent.ACTION_HOVER_EXIT 16806 || (action == MotionEvent.ACTION_HOVER_MOVE 16807 && !pointInView(event.getX(), event.getY()))) { 16808 mSendingHoverAccessibilityEvents = false; 16809 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 16810 } 16811 } 16812 16813 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 16814 && event.isFromSource(InputDevice.SOURCE_MOUSE) 16815 && isOnScrollbar(event.getX(), event.getY())) { 16816 awakenScrollBars(); 16817 } 16818 16819 // If we consider ourself hoverable, or if we we're already hovered, 16820 // handle changing state in response to ENTER and EXIT events. 16821 if (isHoverable() || isHovered()) { 16822 switch (action) { 16823 case MotionEvent.ACTION_HOVER_ENTER: 16824 setHovered(true); 16825 break; 16826 case MotionEvent.ACTION_HOVER_EXIT: 16827 setHovered(false); 16828 break; 16829 } 16830 16831 // Dispatch the event to onGenericMotionEvent before returning true. 16832 // This is to provide compatibility with existing applications that 16833 // handled HOVER_MOVE events in onGenericMotionEvent and that would 16834 // break because of the new default handling for hoverable views 16835 // in onHoverEvent. 16836 // Note that onGenericMotionEvent will be called by default when 16837 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 16838 dispatchGenericMotionEventInternal(event); 16839 // The event was already handled by calling setHovered(), so always 16840 // return true. 16841 return true; 16842 } 16843 16844 return false; 16845 } 16846 16847 /** 16848 * Returns true if the view should handle {@link #onHoverEvent} 16849 * by calling {@link #setHovered} to change its hovered state. 16850 * 16851 * @return True if the view is hoverable. 16852 */ isHoverable()16853 private boolean isHoverable() { 16854 final int viewFlags = mViewFlags; 16855 if ((viewFlags & ENABLED_MASK) == DISABLED) { 16856 return false; 16857 } 16858 16859 return (viewFlags & CLICKABLE) == CLICKABLE 16860 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 16861 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 16862 } 16863 16864 /** 16865 * Returns true if the view is currently hovered. 16866 * 16867 * @return True if the view is currently hovered. 16868 * 16869 * @see #setHovered 16870 * @see #onHoverChanged 16871 */ 16872 @ViewDebug.ExportedProperty isHovered()16873 public boolean isHovered() { 16874 return (mPrivateFlags & PFLAG_HOVERED) != 0; 16875 } 16876 16877 /** 16878 * Sets whether the view is currently hovered. 16879 * <p> 16880 * Calling this method also changes the drawable state of the view. This 16881 * enables the view to react to hover by using different drawable resources 16882 * to change its appearance. 16883 * </p><p> 16884 * The {@link #onHoverChanged} method is called when the hovered state changes. 16885 * </p> 16886 * 16887 * @param hovered True if the view is hovered. 16888 * 16889 * @see #isHovered 16890 * @see #onHoverChanged 16891 */ setHovered(boolean hovered)16892 public void setHovered(boolean hovered) { 16893 if (hovered) { 16894 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 16895 mPrivateFlags |= PFLAG_HOVERED; 16896 refreshDrawableState(); 16897 onHoverChanged(true); 16898 } 16899 } else { 16900 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 16901 mPrivateFlags &= ~PFLAG_HOVERED; 16902 refreshDrawableState(); 16903 onHoverChanged(false); 16904 } 16905 } 16906 } 16907 16908 /** 16909 * Implement this method to handle hover state changes. 16910 * <p> 16911 * This method is called whenever the hover state changes as a result of a 16912 * call to {@link #setHovered}. 16913 * </p> 16914 * 16915 * @param hovered The current hover state, as returned by {@link #isHovered}. 16916 * 16917 * @see #isHovered 16918 * @see #setHovered 16919 */ onHoverChanged(boolean hovered)16920 public void onHoverChanged(boolean hovered) { 16921 } 16922 16923 /** 16924 * Handles scroll bar dragging by mouse input. 16925 * 16926 * @hide 16927 * @param event The motion event. 16928 * 16929 * @return true if the event was handled as a scroll bar dragging, false otherwise. 16930 */ handleScrollBarDragging(MotionEvent event)16931 protected boolean handleScrollBarDragging(MotionEvent event) { 16932 if (mScrollCache == null) { 16933 return false; 16934 } 16935 final float x = event.getX(); 16936 final float y = event.getY(); 16937 final int action = event.getAction(); 16938 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 16939 && action != MotionEvent.ACTION_DOWN) 16940 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 16941 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 16942 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 16943 return false; 16944 } 16945 16946 switch (action) { 16947 case MotionEvent.ACTION_MOVE: 16948 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 16949 return false; 16950 } 16951 if (mScrollCache.mScrollBarDraggingState 16952 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 16953 final Rect bounds = mScrollCache.mScrollBarBounds; 16954 getVerticalScrollBarBounds(bounds, null); 16955 final int range = computeVerticalScrollRange(); 16956 final int offset = computeVerticalScrollOffset(); 16957 final int extent = computeVerticalScrollExtent(); 16958 16959 final int thumbLength = ScrollBarUtils.getThumbLength( 16960 bounds.height(), bounds.width(), extent, range); 16961 final int thumbOffset = ScrollBarUtils.getThumbOffset( 16962 bounds.height(), thumbLength, extent, range, offset); 16963 16964 final float diff = y - mScrollCache.mScrollBarDraggingPos; 16965 final float maxThumbOffset = bounds.height() - thumbLength; 16966 final float newThumbOffset = 16967 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 16968 final int height = getHeight(); 16969 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 16970 && height > 0 && extent > 0) { 16971 final int newY = Math.round((range - extent) 16972 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 16973 if (newY != getScrollY()) { 16974 mScrollCache.mScrollBarDraggingPos = y; 16975 setScrollY(newY); 16976 } 16977 } 16978 return true; 16979 } 16980 if (mScrollCache.mScrollBarDraggingState 16981 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 16982 final Rect bounds = mScrollCache.mScrollBarBounds; 16983 getHorizontalScrollBarBounds(bounds, null); 16984 final int range = computeHorizontalScrollRange(); 16985 final int offset = computeHorizontalScrollOffset(); 16986 final int extent = computeHorizontalScrollExtent(); 16987 16988 final int thumbLength = ScrollBarUtils.getThumbLength( 16989 bounds.width(), bounds.height(), extent, range); 16990 final int thumbOffset = ScrollBarUtils.getThumbOffset( 16991 bounds.width(), thumbLength, extent, range, offset); 16992 16993 final float diff = x - mScrollCache.mScrollBarDraggingPos; 16994 final float maxThumbOffset = bounds.width() - thumbLength; 16995 final float newThumbOffset = 16996 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 16997 final int width = getWidth(); 16998 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 16999 && width > 0 && extent > 0) { 17000 final int newX = Math.round((range - extent) 17001 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 17002 if (newX != getScrollX()) { 17003 mScrollCache.mScrollBarDraggingPos = x; 17004 setScrollX(newX); 17005 } 17006 } 17007 return true; 17008 } 17009 case MotionEvent.ACTION_DOWN: 17010 if (mScrollCache.state == ScrollabilityCache.OFF) { 17011 return false; 17012 } 17013 if (isOnVerticalScrollbarThumb(x, y)) { 17014 mScrollCache.mScrollBarDraggingState = 17015 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 17016 mScrollCache.mScrollBarDraggingPos = y; 17017 return true; 17018 } 17019 if (isOnHorizontalScrollbarThumb(x, y)) { 17020 mScrollCache.mScrollBarDraggingState = 17021 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 17022 mScrollCache.mScrollBarDraggingPos = x; 17023 return true; 17024 } 17025 } 17026 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 17027 return false; 17028 } 17029 17030 /** 17031 * Implement this method to handle touch screen motion events. 17032 * <p> 17033 * If this method is used to detect click actions, it is recommended that 17034 * the actions be performed by implementing and calling 17035 * {@link #performClick()}. This will ensure consistent system behavior, 17036 * including: 17037 * <ul> 17038 * <li>obeying click sound preferences 17039 * <li>dispatching OnClickListener calls 17040 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 17041 * accessibility features are enabled 17042 * </ul> 17043 * 17044 * @param event The motion event. 17045 * @return True if the event was handled, false otherwise. 17046 */ onTouchEvent(MotionEvent event)17047 public boolean onTouchEvent(MotionEvent event) { 17048 final float x = event.getX(); 17049 final float y = event.getY(); 17050 final int viewFlags = mViewFlags; 17051 final int action = event.getAction(); 17052 17053 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 17054 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 17055 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 17056 17057 if ((viewFlags & ENABLED_MASK) == DISABLED 17058 && (mPrivateFlags4 & PFLAG4_ALLOW_CLICK_WHEN_DISABLED) == 0) { 17059 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 17060 setPressed(false); 17061 } 17062 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 17063 // A disabled view that is clickable still consumes the touch 17064 // events, it just doesn't respond to them. 17065 return clickable; 17066 } 17067 if (mTouchDelegate != null) { 17068 if (mTouchDelegate.onTouchEvent(event)) { 17069 return true; 17070 } 17071 } 17072 17073 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 17074 switch (action) { 17075 case MotionEvent.ACTION_UP: 17076 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 17077 if ((viewFlags & TOOLTIP) == TOOLTIP) { 17078 handleTooltipUp(); 17079 } 17080 if (!clickable) { 17081 removeTapCallback(); 17082 removeLongPressCallback(); 17083 mInContextButtonPress = false; 17084 mHasPerformedLongPress = false; 17085 mIgnoreNextUpEvent = false; 17086 break; 17087 } 17088 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 17089 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 17090 // take focus if we don't have it already and we should in 17091 // touch mode. 17092 boolean focusTaken = false; 17093 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 17094 focusTaken = requestFocus(); 17095 } 17096 17097 if (prepressed) { 17098 // The button is being released before we actually 17099 // showed it as pressed. Make it show the pressed 17100 // state now (before scheduling the click) to ensure 17101 // the user sees it. 17102 setPressed(true, x, y); 17103 } 17104 17105 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 17106 // This is a tap, so remove the longpress check 17107 removeLongPressCallback(); 17108 17109 // Only perform take click actions if we were in the pressed state 17110 if (!focusTaken) { 17111 // Use a Runnable and post this rather than calling 17112 // performClick directly. This lets other visual state 17113 // of the view update before click actions start. 17114 if (mPerformClick == null) { 17115 mPerformClick = new PerformClick(); 17116 } 17117 if (!post(mPerformClick)) { 17118 performClickInternal(); 17119 } 17120 } 17121 } 17122 17123 if (mUnsetPressedState == null) { 17124 mUnsetPressedState = new UnsetPressedState(); 17125 } 17126 17127 if (prepressed) { 17128 postDelayed(mUnsetPressedState, 17129 ViewConfiguration.getPressedStateDuration()); 17130 } else if (!post(mUnsetPressedState)) { 17131 // If the post failed, unpress right now 17132 mUnsetPressedState.run(); 17133 } 17134 17135 removeTapCallback(); 17136 } 17137 mIgnoreNextUpEvent = false; 17138 break; 17139 17140 case MotionEvent.ACTION_DOWN: 17141 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 17142 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 17143 } 17144 mHasPerformedLongPress = false; 17145 17146 if (!clickable) { 17147 checkForLongClick( 17148 ViewConfiguration.getLongPressTimeout(), 17149 x, 17150 y, 17151 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 17152 break; 17153 } 17154 17155 if (performButtonActionOnTouchDown(event)) { 17156 break; 17157 } 17158 17159 // Walk up the hierarchy to determine if we're inside a scrolling container. 17160 boolean isInScrollingContainer = isInScrollingContainer(); 17161 17162 // For views inside a scrolling container, delay the pressed feedback for 17163 // a short period in case this is a scroll. 17164 if (isInScrollingContainer) { 17165 mPrivateFlags |= PFLAG_PREPRESSED; 17166 if (mPendingCheckForTap == null) { 17167 mPendingCheckForTap = new CheckForTap(); 17168 } 17169 mPendingCheckForTap.x = event.getX(); 17170 mPendingCheckForTap.y = event.getY(); 17171 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 17172 } else { 17173 // Not inside a scrolling container, so show the feedback right away 17174 setPressed(true, x, y); 17175 checkForLongClick( 17176 ViewConfiguration.getLongPressTimeout(), 17177 x, 17178 y, 17179 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 17180 } 17181 break; 17182 17183 case MotionEvent.ACTION_CANCEL: 17184 if (clickable) { 17185 setPressed(false); 17186 } 17187 removeTapCallback(); 17188 removeLongPressCallback(); 17189 mInContextButtonPress = false; 17190 mHasPerformedLongPress = false; 17191 mIgnoreNextUpEvent = false; 17192 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 17193 break; 17194 17195 case MotionEvent.ACTION_MOVE: 17196 if (clickable) { 17197 drawableHotspotChanged(x, y); 17198 } 17199 17200 final int motionClassification = event.getClassification(); 17201 final boolean ambiguousGesture = 17202 motionClassification == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE; 17203 int touchSlop = mTouchSlop; 17204 if (ambiguousGesture && hasPendingLongPressCallback()) { 17205 if (!pointInView(x, y, touchSlop)) { 17206 // The default action here is to cancel long press. But instead, we 17207 // just extend the timeout here, in case the classification 17208 // stays ambiguous. 17209 removeLongPressCallback(); 17210 long delay = (long) (ViewConfiguration.getLongPressTimeout() 17211 * mAmbiguousGestureMultiplier); 17212 // Subtract the time already spent 17213 delay -= event.getEventTime() - event.getDownTime(); 17214 checkForLongClick( 17215 delay, 17216 x, 17217 y, 17218 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 17219 } 17220 touchSlop *= mAmbiguousGestureMultiplier; 17221 } 17222 17223 // Be lenient about moving outside of buttons 17224 if (!pointInView(x, y, touchSlop)) { 17225 // Outside button 17226 // Remove any future long press/tap checks 17227 removeTapCallback(); 17228 removeLongPressCallback(); 17229 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 17230 setPressed(false); 17231 } 17232 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 17233 } 17234 17235 final boolean deepPress = 17236 motionClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS; 17237 if (deepPress && hasPendingLongPressCallback()) { 17238 // process the long click action immediately 17239 removeLongPressCallback(); 17240 checkForLongClick( 17241 0 /* send immediately */, 17242 x, 17243 y, 17244 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS); 17245 } 17246 17247 break; 17248 } 17249 17250 return true; 17251 } 17252 17253 return false; 17254 } 17255 17256 /** 17257 * @hide 17258 */ 17259 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) isInScrollingContainer()17260 public boolean isInScrollingContainer() { 17261 ViewParent p = getParent(); 17262 while (p != null && p instanceof ViewGroup) { 17263 if (((ViewGroup) p).shouldDelayChildPressedState()) { 17264 return true; 17265 } 17266 p = p.getParent(); 17267 } 17268 return false; 17269 } 17270 17271 /** 17272 * Remove the longpress detection timer. 17273 */ removeLongPressCallback()17274 private void removeLongPressCallback() { 17275 if (mPendingCheckForLongPress != null) { 17276 removeCallbacks(mPendingCheckForLongPress); 17277 } 17278 } 17279 17280 /** 17281 * Return true if the long press callback is scheduled to run sometime in the future. 17282 * Return false if there is no scheduled long press callback at the moment. 17283 */ hasPendingLongPressCallback()17284 private boolean hasPendingLongPressCallback() { 17285 if (mPendingCheckForLongPress == null) { 17286 return false; 17287 } 17288 final AttachInfo attachInfo = mAttachInfo; 17289 if (attachInfo == null) { 17290 return false; 17291 } 17292 return attachInfo.mHandler.hasCallbacks(mPendingCheckForLongPress); 17293 } 17294 17295 /** 17296 * Remove the pending click action 17297 */ 17298 @UnsupportedAppUsage removePerformClickCallback()17299 private void removePerformClickCallback() { 17300 if (mPerformClick != null) { 17301 removeCallbacks(mPerformClick); 17302 } 17303 } 17304 17305 /** 17306 * Remove the prepress detection timer. 17307 */ removeUnsetPressCallback()17308 private void removeUnsetPressCallback() { 17309 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 17310 setPressed(false); 17311 removeCallbacks(mUnsetPressedState); 17312 } 17313 } 17314 17315 /** 17316 * Remove the tap detection timer. 17317 */ removeTapCallback()17318 private void removeTapCallback() { 17319 if (mPendingCheckForTap != null) { 17320 mPrivateFlags &= ~PFLAG_PREPRESSED; 17321 removeCallbacks(mPendingCheckForTap); 17322 } 17323 } 17324 17325 /** 17326 * Cancels a pending long press. Your subclass can use this if you 17327 * want the context menu to come up if the user presses and holds 17328 * at the same place, but you don't want it to come up if they press 17329 * and then move around enough to cause scrolling. 17330 */ cancelLongPress()17331 public void cancelLongPress() { 17332 removeLongPressCallback(); 17333 17334 /* 17335 * The prepressed state handled by the tap callback is a display 17336 * construct, but the tap callback will post a long press callback 17337 * less its own timeout. Remove it here. 17338 */ 17339 removeTapCallback(); 17340 } 17341 17342 /** 17343 * Sets the TouchDelegate for this View. 17344 */ setTouchDelegate(TouchDelegate delegate)17345 public void setTouchDelegate(TouchDelegate delegate) { 17346 mTouchDelegate = delegate; 17347 } 17348 17349 /** 17350 * Gets the TouchDelegate for this View. 17351 */ getTouchDelegate()17352 public TouchDelegate getTouchDelegate() { 17353 return mTouchDelegate; 17354 } 17355 17356 /** 17357 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 17358 * 17359 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 17360 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 17361 * available. This method should only be called for touch events. 17362 * 17363 * <p class="note">This API is not intended for most applications. Buffered dispatch 17364 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 17365 * streams will not improve your input latency. Side effects include: increased latency, 17366 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 17367 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 17368 * you.</p> 17369 * 17370 * To receive unbuffered events for arbitrary input device source classes, use 17371 * {@link #requestUnbufferedDispatch(int)}, 17372 * 17373 * @see View#requestUnbufferedDispatch(int) 17374 */ requestUnbufferedDispatch(MotionEvent event)17375 public final void requestUnbufferedDispatch(MotionEvent event) { 17376 final int action = event.getAction(); 17377 if (mAttachInfo == null 17378 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 17379 || !event.isTouchEvent()) { 17380 return; 17381 } 17382 mAttachInfo.mUnbufferedDispatchRequested = true; 17383 } 17384 17385 /** 17386 * Request unbuffered dispatch of the given event source class to this view. 17387 * This is similar to {@link View#requestUnbufferedDispatch(MotionEvent)}, but does not 17388 * automatically terminate, and allows the specification of arbitrary input source classes. 17389 * 17390 * <p>Prior to {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}, calling this method 17391 * will not result in any behavioral changes when this View is not attached to a window. 17392 * 17393 * @param source The combined input source class to request unbuffered dispatch for. All 17394 * events coming from these source classes will not be buffered. Set to 17395 * {@link InputDevice#SOURCE_CLASS_NONE} in order to return to default behaviour. 17396 * 17397 * @see View#requestUnbufferedDispatch(MotionEvent) 17398 */ requestUnbufferedDispatch(@nputSourceClass int source)17399 public final void requestUnbufferedDispatch(@InputSourceClass int source) { 17400 if (mUnbufferedInputSource == source) { 17401 return; 17402 } 17403 mUnbufferedInputSource = source; 17404 if (mParent != null) { 17405 mParent.onDescendantUnbufferedRequested(); 17406 } 17407 } 17408 hasSize()17409 private boolean hasSize() { 17410 return (mBottom > mTop) && (mRight > mLeft); 17411 } 17412 canTakeFocus()17413 private boolean canTakeFocus() { 17414 return ((mViewFlags & VISIBILITY_MASK) == VISIBLE) 17415 && ((mViewFlags & FOCUSABLE) == FOCUSABLE) 17416 && ((mViewFlags & ENABLED_MASK) == ENABLED) 17417 && (sCanFocusZeroSized || !isLayoutValid() || hasSize()); 17418 } 17419 17420 /** 17421 * Set flags controlling behavior of this view. 17422 * 17423 * @param flags Constant indicating the value which should be set 17424 * @param mask Constant indicating the bit range that should be changed 17425 */ 17426 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) setFlags(int flags, int mask)17427 void setFlags(int flags, int mask) { 17428 final boolean accessibilityEnabled = 17429 AccessibilityManager.getInstance(mContext).isEnabled(); 17430 final boolean oldIncludeForAccessibility = 17431 accessibilityEnabled && includeForAccessibility(false); 17432 17433 int old = mViewFlags; 17434 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 17435 17436 int changed = mViewFlags ^ old; 17437 if (changed == 0) { 17438 return; 17439 } 17440 int privateFlags = mPrivateFlags; 17441 boolean shouldNotifyFocusableAvailable = false; 17442 17443 // If focusable is auto, update the FOCUSABLE bit. 17444 int focusableChangedByAuto = 0; 17445 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 17446 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 17447 // Heuristic only takes into account whether view is clickable. 17448 final int newFocus; 17449 if ((mViewFlags & CLICKABLE) != 0) { 17450 newFocus = FOCUSABLE; 17451 } else { 17452 newFocus = NOT_FOCUSABLE; 17453 } 17454 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 17455 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 17456 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 17457 } 17458 17459 /* Check if the FOCUSABLE bit has changed */ 17460 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 17461 if (((old & FOCUSABLE) == FOCUSABLE) 17462 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 17463 /* Give up focus if we are no longer focusable */ 17464 clearFocus(); 17465 if (mParent instanceof ViewGroup) { 17466 ((ViewGroup) mParent).clearFocusedInCluster(); 17467 } 17468 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 17469 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 17470 /* 17471 * Tell the view system that we are now available to take focus 17472 * if no one else already has it. 17473 */ 17474 if (mParent != null) { 17475 ViewRootImpl viewRootImpl = getViewRootImpl(); 17476 if (!sAutoFocusableOffUIThreadWontNotifyParents 17477 || focusableChangedByAuto == 0 17478 || viewRootImpl == null 17479 || viewRootImpl.mThread == Thread.currentThread()) { 17480 shouldNotifyFocusableAvailable = canTakeFocus(); 17481 } 17482 } 17483 } 17484 } 17485 17486 final int newVisibility = flags & VISIBILITY_MASK; 17487 if (newVisibility == VISIBLE) { 17488 if ((changed & VISIBILITY_MASK) != 0) { 17489 /* 17490 * If this view is becoming visible, invalidate it in case it changed while 17491 * it was not visible. Marking it drawn ensures that the invalidation will 17492 * go through. 17493 */ 17494 mPrivateFlags |= PFLAG_DRAWN; 17495 invalidate(true); 17496 17497 needGlobalAttributesUpdate(true); 17498 17499 // a view becoming visible is worth notifying the parent about in case nothing has 17500 // focus. Even if this specific view isn't focusable, it may contain something that 17501 // is, so let the root view try to give this focus if nothing else does. 17502 shouldNotifyFocusableAvailable = hasSize(); 17503 } 17504 } 17505 17506 if ((changed & ENABLED_MASK) != 0) { 17507 if ((mViewFlags & ENABLED_MASK) == ENABLED) { 17508 // a view becoming enabled should notify the parent as long as the view is also 17509 // visible and the parent wasn't already notified by becoming visible during this 17510 // setFlags invocation. 17511 shouldNotifyFocusableAvailable = canTakeFocus(); 17512 } else { 17513 if (isFocused()) clearFocus(); 17514 } 17515 } 17516 17517 if (shouldNotifyFocusableAvailable && mParent != null) { 17518 mParent.focusableViewAvailable(this); 17519 } 17520 17521 /* Check if the GONE bit has changed */ 17522 if ((changed & GONE) != 0) { 17523 needGlobalAttributesUpdate(false); 17524 requestLayout(); 17525 17526 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 17527 if (hasFocus()) { 17528 clearFocus(); 17529 if (mParent instanceof ViewGroup) { 17530 ((ViewGroup) mParent).clearFocusedInCluster(); 17531 } 17532 } 17533 clearAccessibilityFocus(); 17534 destroyDrawingCache(); 17535 if (mParent instanceof View) { 17536 // GONE views noop invalidation, so invalidate the parent 17537 ((View) mParent).invalidate(true); 17538 } 17539 // Mark the view drawn to ensure that it gets invalidated properly the next 17540 // time it is visible and gets invalidated 17541 mPrivateFlags |= PFLAG_DRAWN; 17542 } 17543 if (mAttachInfo != null) { 17544 mAttachInfo.mViewVisibilityChanged = true; 17545 } 17546 } 17547 17548 /* Check if the VISIBLE bit has changed */ 17549 if ((changed & INVISIBLE) != 0) { 17550 needGlobalAttributesUpdate(false); 17551 /* 17552 * If this view is becoming invisible, set the DRAWN flag so that 17553 * the next invalidate() will not be skipped. 17554 */ 17555 mPrivateFlags |= PFLAG_DRAWN; 17556 17557 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 17558 // root view becoming invisible shouldn't clear focus and accessibility focus 17559 if (getRootView() != this) { 17560 if (hasFocus()) { 17561 clearFocus(); 17562 if (mParent instanceof ViewGroup) { 17563 ((ViewGroup) mParent).clearFocusedInCluster(); 17564 } 17565 } 17566 clearAccessibilityFocus(); 17567 } 17568 } 17569 if (mAttachInfo != null) { 17570 mAttachInfo.mViewVisibilityChanged = true; 17571 } 17572 } 17573 17574 if ((changed & VISIBILITY_MASK) != 0) { 17575 // If the view is invisible, cleanup its display list to free up resources 17576 if (newVisibility != VISIBLE && mAttachInfo != null) { 17577 cleanupDraw(); 17578 } 17579 17580 if (mParent instanceof ViewGroup) { 17581 ViewGroup parent = (ViewGroup) mParent; 17582 parent.onChildVisibilityChanged(this, (changed & VISIBILITY_MASK), 17583 newVisibility); 17584 parent.invalidate(true); 17585 } else if (mParent != null) { 17586 mParent.invalidateChild(this, null); 17587 } 17588 17589 if (mAttachInfo != null) { 17590 dispatchVisibilityChanged(this, newVisibility); 17591 17592 // Aggregated visibility changes are dispatched to attached views 17593 // in visible windows where the parent is currently shown/drawn 17594 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 17595 // discounting clipping or overlapping. This makes it a good place 17596 // to change animation states. 17597 if (mParent != null && getWindowVisibility() == VISIBLE && 17598 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 17599 dispatchVisibilityAggregated(newVisibility == VISIBLE); 17600 } 17601 // If this view is invisible from visible, then sending the A11y event by its 17602 // parent which is shown and has the accessibility important. 17603 if ((old & VISIBILITY_MASK) == VISIBLE) { 17604 notifySubtreeAccessibilityStateChangedByParentIfNeeded(); 17605 } else { 17606 notifySubtreeAccessibilityStateChangedIfNeeded(); 17607 } 17608 } 17609 } 17610 17611 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 17612 destroyDrawingCache(); 17613 } 17614 17615 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 17616 destroyDrawingCache(); 17617 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 17618 invalidateParentCaches(); 17619 } 17620 17621 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 17622 destroyDrawingCache(); 17623 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 17624 } 17625 17626 if ((changed & DRAW_MASK) != 0) { 17627 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 17628 if (mBackground != null 17629 || mDefaultFocusHighlight != null 17630 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 17631 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 17632 } else { 17633 mPrivateFlags |= PFLAG_SKIP_DRAW; 17634 } 17635 } else { 17636 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 17637 } 17638 requestLayout(); 17639 invalidate(true); 17640 } 17641 17642 if ((changed & KEEP_SCREEN_ON) != 0) { 17643 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 17644 mParent.recomputeViewAttributes(this); 17645 } 17646 } 17647 17648 if (accessibilityEnabled) { 17649 // If we're an accessibility pane and the visibility changed, we already have sent 17650 // a state change, so we really don't need to report other changes. 17651 if (isAccessibilityPane()) { 17652 changed &= ~VISIBILITY_MASK; 17653 } 17654 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 17655 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 17656 || (changed & CONTEXT_CLICKABLE) != 0) { 17657 if (oldIncludeForAccessibility != includeForAccessibility(false)) { 17658 notifySubtreeAccessibilityStateChangedIfNeeded(); 17659 } else { 17660 notifyViewAccessibilityStateChangedIfNeeded( 17661 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 17662 } 17663 } else if ((changed & ENABLED_MASK) != 0) { 17664 notifyViewAccessibilityStateChangedIfNeeded( 17665 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 17666 } 17667 } 17668 } 17669 17670 /** 17671 * Change the view's z order in the tree, so it's on top of other sibling 17672 * views. This ordering change may affect layout, if the parent container 17673 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 17674 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 17675 * method should be followed by calls to {@link #requestLayout()} and 17676 * {@link View#invalidate()} on the view's parent to force the parent to redraw 17677 * with the new child ordering. 17678 * 17679 * @see ViewGroup#bringChildToFront(View) 17680 */ bringToFront()17681 public void bringToFront() { 17682 if (mParent != null) { 17683 mParent.bringChildToFront(this); 17684 } 17685 } 17686 17687 /** 17688 * This is called in response to an internal scroll in this view (i.e., the 17689 * view scrolled its own contents). This is typically as a result of 17690 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 17691 * called. 17692 * 17693 * @param l Current horizontal scroll origin. 17694 * @param t Current vertical scroll origin. 17695 * @param oldl Previous horizontal scroll origin. 17696 * @param oldt Previous vertical scroll origin. 17697 */ onScrollChanged(int l, int t, int oldl, int oldt)17698 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 17699 notifySubtreeAccessibilityStateChangedIfNeeded(); 17700 postSendViewScrolledAccessibilityEventCallback(l - oldl, t - oldt); 17701 17702 mBackgroundSizeChanged = true; 17703 mDefaultFocusHighlightSizeChanged = true; 17704 if (mForegroundInfo != null) { 17705 mForegroundInfo.mBoundsChanged = true; 17706 } 17707 17708 final AttachInfo ai = mAttachInfo; 17709 if (ai != null) { 17710 ai.mViewScrollChanged = true; 17711 } 17712 17713 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 17714 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 17715 } 17716 } 17717 17718 /** 17719 * Interface definition for a callback to be invoked when the scroll 17720 * X or Y positions of a view change. 17721 * <p> 17722 * <b>Note:</b> Some views handle scrolling independently from View and may 17723 * have their own separate listeners for scroll-type events. For example, 17724 * {@link android.widget.ListView ListView} allows clients to register an 17725 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 17726 * to listen for changes in list scroll position. 17727 * 17728 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 17729 */ 17730 public interface OnScrollChangeListener { 17731 /** 17732 * Called when the scroll position of a view changes. 17733 * 17734 * @param v The view whose scroll position has changed. 17735 * @param scrollX Current horizontal scroll origin. 17736 * @param scrollY Current vertical scroll origin. 17737 * @param oldScrollX Previous horizontal scroll origin. 17738 * @param oldScrollY Previous vertical scroll origin. 17739 */ onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY)17740 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 17741 } 17742 17743 /** 17744 * Interface definition for a callback to be invoked when the layout bounds of a view 17745 * changes due to layout processing. 17746 */ 17747 public interface OnLayoutChangeListener { 17748 /** 17749 * Called when the layout bounds of a view changes due to layout processing. 17750 * 17751 * @param v The view whose bounds have changed. 17752 * @param left The new value of the view's left property. 17753 * @param top The new value of the view's top property. 17754 * @param right The new value of the view's right property. 17755 * @param bottom The new value of the view's bottom property. 17756 * @param oldLeft The previous value of the view's left property. 17757 * @param oldTop The previous value of the view's top property. 17758 * @param oldRight The previous value of the view's right property. 17759 * @param oldBottom The previous value of the view's bottom property. 17760 */ onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)17761 void onLayoutChange(View v, int left, int top, int right, int bottom, 17762 int oldLeft, int oldTop, int oldRight, int oldBottom); 17763 } 17764 17765 /** 17766 * This is called during layout when the size of this view has changed. If 17767 * you were just added to the view hierarchy, you're called with the old 17768 * values of 0. 17769 * 17770 * @param w Current width of this view. 17771 * @param h Current height of this view. 17772 * @param oldw Old width of this view. 17773 * @param oldh Old height of this view. 17774 */ onSizeChanged(int w, int h, int oldw, int oldh)17775 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 17776 } 17777 17778 /** 17779 * Called by draw to draw the child views. This may be overridden 17780 * by derived classes to gain control just before its children are drawn 17781 * (but after its own view has been drawn). 17782 * @param canvas the canvas on which to draw the view 17783 */ dispatchDraw(@onNull Canvas canvas)17784 protected void dispatchDraw(@NonNull Canvas canvas) { 17785 17786 } 17787 17788 /** 17789 * Gets the parent of this view. Note that the parent is a 17790 * ViewParent and not necessarily a View. 17791 * 17792 * @return Parent of this view. 17793 */ getParent()17794 public final ViewParent getParent() { 17795 return mParent; 17796 } 17797 17798 /** 17799 * Set the horizontal scrolled position of your view. This will cause a call to 17800 * {@link #onScrollChanged(int, int, int, int)} and the view will be 17801 * invalidated. 17802 * @param value the x position to scroll to 17803 */ setScrollX(int value)17804 public void setScrollX(int value) { 17805 scrollTo(value, mScrollY); 17806 } 17807 17808 /** 17809 * Set the vertical scrolled position of your view. This will cause a call to 17810 * {@link #onScrollChanged(int, int, int, int)} and the view will be 17811 * invalidated. 17812 * @param value the y position to scroll to 17813 */ setScrollY(int value)17814 public void setScrollY(int value) { 17815 scrollTo(mScrollX, value); 17816 } 17817 17818 /** 17819 * Return the scrolled left position of this view. This is the left edge of 17820 * the displayed part of your view. You do not need to draw any pixels 17821 * farther left, since those are outside of the frame of your view on 17822 * screen. 17823 * 17824 * @return The left edge of the displayed part of your view, in pixels. 17825 */ 17826 @InspectableProperty getScrollX()17827 public final int getScrollX() { 17828 return mScrollX; 17829 } 17830 17831 /** 17832 * Return the scrolled top position of this view. This is the top edge of 17833 * the displayed part of your view. You do not need to draw any pixels above 17834 * it, since those are outside of the frame of your view on screen. 17835 * 17836 * @return The top edge of the displayed part of your view, in pixels. 17837 */ 17838 @InspectableProperty getScrollY()17839 public final int getScrollY() { 17840 return mScrollY; 17841 } 17842 17843 /** 17844 * Return the width of your view. 17845 * 17846 * @return The width of your view, in pixels. 17847 */ 17848 @ViewDebug.ExportedProperty(category = "layout") getWidth()17849 public final int getWidth() { 17850 return mRight - mLeft; 17851 } 17852 17853 /** 17854 * Return the height of your view. 17855 * 17856 * @return The height of your view, in pixels. 17857 */ 17858 @ViewDebug.ExportedProperty(category = "layout") getHeight()17859 public final int getHeight() { 17860 return mBottom - mTop; 17861 } 17862 17863 /** 17864 * Return the visible drawing bounds of your view. Fills in the output 17865 * rectangle with the values from getScrollX(), getScrollY(), 17866 * getWidth(), and getHeight(). These bounds do not account for any 17867 * transformation properties currently set on the view, such as 17868 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 17869 * 17870 * @param outRect The (scrolled) drawing bounds of the view. 17871 */ getDrawingRect(Rect outRect)17872 public void getDrawingRect(Rect outRect) { 17873 outRect.left = mScrollX; 17874 outRect.top = mScrollY; 17875 outRect.right = mScrollX + (mRight - mLeft); 17876 outRect.bottom = mScrollY + (mBottom - mTop); 17877 } 17878 17879 /** 17880 * Like {@link #getMeasuredWidthAndState()}, but only returns the 17881 * raw width component (that is the result is masked by 17882 * {@link #MEASURED_SIZE_MASK}). 17883 * 17884 * @return The raw measured width of this view. 17885 */ getMeasuredWidth()17886 public final int getMeasuredWidth() { 17887 return mMeasuredWidth & MEASURED_SIZE_MASK; 17888 } 17889 17890 /** 17891 * Return the full width measurement information for this view as computed 17892 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 17893 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 17894 * This should be used during measurement and layout calculations only. Use 17895 * {@link #getWidth()} to see how wide a view is after layout. 17896 * 17897 * @return The measured width of this view as a bit mask. 17898 */ 17899 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 17900 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 17901 name = "MEASURED_STATE_TOO_SMALL"), 17902 }) getMeasuredWidthAndState()17903 public final int getMeasuredWidthAndState() { 17904 return mMeasuredWidth; 17905 } 17906 17907 /** 17908 * Like {@link #getMeasuredHeightAndState()}, but only returns the 17909 * raw height component (that is the result is masked by 17910 * {@link #MEASURED_SIZE_MASK}). 17911 * 17912 * @return The raw measured height of this view. 17913 */ getMeasuredHeight()17914 public final int getMeasuredHeight() { 17915 return mMeasuredHeight & MEASURED_SIZE_MASK; 17916 } 17917 17918 /** 17919 * Return the full height measurement information for this view as computed 17920 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 17921 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 17922 * This should be used during measurement and layout calculations only. Use 17923 * {@link #getHeight()} to see how high a view is after layout. 17924 * 17925 * @return The measured height of this view as a bit mask. 17926 */ 17927 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 17928 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 17929 name = "MEASURED_STATE_TOO_SMALL"), 17930 }) getMeasuredHeightAndState()17931 public final int getMeasuredHeightAndState() { 17932 return mMeasuredHeight; 17933 } 17934 17935 /** 17936 * Return only the state bits of {@link #getMeasuredWidthAndState()} 17937 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 17938 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 17939 * and the height component is at the shifted bits 17940 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 17941 */ getMeasuredState()17942 public final int getMeasuredState() { 17943 return (mMeasuredWidth&MEASURED_STATE_MASK) 17944 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 17945 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 17946 } 17947 17948 /** 17949 * The transform matrix of this view, which is calculated based on the current 17950 * rotation, scale, and pivot properties. 17951 * 17952 * @see #getRotation() 17953 * @see #getScaleX() 17954 * @see #getScaleY() 17955 * @see #getPivotX() 17956 * @see #getPivotY() 17957 * @return The current transform matrix for the view 17958 */ getMatrix()17959 public Matrix getMatrix() { 17960 ensureTransformationInfo(); 17961 final Matrix matrix = mTransformationInfo.mMatrix; 17962 mRenderNode.getMatrix(matrix); 17963 return matrix; 17964 } 17965 17966 /** 17967 * Returns true if the transform matrix is the identity matrix. 17968 * Recomputes the matrix if necessary. 17969 * 17970 * @return True if the transform matrix is the identity matrix, false otherwise. 17971 * @hide 17972 */ 17973 @UnsupportedAppUsage hasIdentityMatrix()17974 public final boolean hasIdentityMatrix() { 17975 return mRenderNode.hasIdentityMatrix(); 17976 } 17977 17978 @UnsupportedAppUsage ensureTransformationInfo()17979 void ensureTransformationInfo() { 17980 if (mTransformationInfo == null) { 17981 mTransformationInfo = new TransformationInfo(); 17982 } 17983 } 17984 17985 /** 17986 * Utility method to retrieve the inverse of the current mMatrix property. 17987 * We cache the matrix to avoid recalculating it when transform properties 17988 * have not changed. 17989 * 17990 * @return The inverse of the current matrix of this view. 17991 * @hide 17992 */ 17993 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getInverseMatrix()17994 public final Matrix getInverseMatrix() { 17995 ensureTransformationInfo(); 17996 if (mTransformationInfo.mInverseMatrix == null) { 17997 mTransformationInfo.mInverseMatrix = new Matrix(); 17998 } 17999 final Matrix matrix = mTransformationInfo.mInverseMatrix; 18000 mRenderNode.getInverseMatrix(matrix); 18001 return matrix; 18002 } 18003 18004 /** 18005 * Gets the distance along the Z axis from the camera to this view. 18006 * 18007 * @see #setCameraDistance(float) 18008 * 18009 * @return The distance along the Z axis. 18010 */ getCameraDistance()18011 public float getCameraDistance() { 18012 final float dpi = mResources.getDisplayMetrics().densityDpi; 18013 return mRenderNode.getCameraDistance() * dpi; 18014 } 18015 18016 /** 18017 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 18018 * views are drawn) from the camera to this view. The camera's distance 18019 * affects 3D transformations, for instance rotations around the X and Y 18020 * axis. If the rotationX or rotationY properties are changed and this view is 18021 * large (more than half the size of the screen), it is recommended to always 18022 * use a camera distance that's greater than the height (X axis rotation) or 18023 * the width (Y axis rotation) of this view.</p> 18024 * 18025 * <p>The distance of the camera from the view plane can have an affect on the 18026 * perspective distortion of the view when it is rotated around the x or y axis. 18027 * For example, a large distance will result in a large viewing angle, and there 18028 * will not be much perspective distortion of the view as it rotates. A short 18029 * distance may cause much more perspective distortion upon rotation, and can 18030 * also result in some drawing artifacts if the rotated view ends up partially 18031 * behind the camera (which is why the recommendation is to use a distance at 18032 * least as far as the size of the view, if the view is to be rotated.)</p> 18033 * 18034 * <p>The distance is expressed in "depth pixels." The default distance depends 18035 * on the screen density. For instance, on a medium density display, the 18036 * default distance is 1280. On a high density display, the default distance 18037 * is 1920.</p> 18038 * 18039 * <p>If you want to specify a distance that leads to visually consistent 18040 * results across various densities, use the following formula:</p> 18041 * <pre> 18042 * float scale = context.getResources().getDisplayMetrics().density; 18043 * view.setCameraDistance(distance * scale); 18044 * </pre> 18045 * 18046 * <p>The density scale factor of a high density display is 1.5, 18047 * and 1920 = 1280 * 1.5.</p> 18048 * 18049 * @param distance The distance in "depth pixels", if negative the opposite 18050 * value is used 18051 * 18052 * @see #setRotationX(float) 18053 * @see #setRotationY(float) 18054 */ setCameraDistance(float distance)18055 public void setCameraDistance(float distance) { 18056 final float dpi = mResources.getDisplayMetrics().densityDpi; 18057 18058 invalidateViewProperty(true, false); 18059 mRenderNode.setCameraDistance(Math.abs(distance) / dpi); 18060 invalidateViewProperty(false, false); 18061 18062 invalidateParentIfNeededAndWasQuickRejected(); 18063 } 18064 18065 /** 18066 * The degrees that the view is rotated around the pivot point. 18067 * 18068 * @see #setRotation(float) 18069 * @see #getPivotX() 18070 * @see #getPivotY() 18071 * 18072 * @return The degrees of rotation. 18073 */ 18074 @ViewDebug.ExportedProperty(category = "drawing") 18075 @InspectableProperty getRotation()18076 public float getRotation() { 18077 return mRenderNode.getRotationZ(); 18078 } 18079 18080 /** 18081 * Sets the degrees that the view is rotated around the pivot point. Increasing values 18082 * result in clockwise rotation. 18083 * 18084 * @param rotation The degrees of rotation. 18085 * 18086 * @see #getRotation() 18087 * @see #getPivotX() 18088 * @see #getPivotY() 18089 * @see #setRotationX(float) 18090 * @see #setRotationY(float) 18091 * 18092 * @attr ref android.R.styleable#View_rotation 18093 */ 18094 @RemotableViewMethod setRotation(float rotation)18095 public void setRotation(float rotation) { 18096 if (rotation != getRotation()) { 18097 // Double-invalidation is necessary to capture view's old and new areas 18098 invalidateViewProperty(true, false); 18099 mRenderNode.setRotationZ(rotation); 18100 invalidateViewProperty(false, true); 18101 18102 invalidateParentIfNeededAndWasQuickRejected(); 18103 notifySubtreeAccessibilityStateChangedIfNeeded(); 18104 } 18105 } 18106 18107 /** 18108 * The degrees that the view is rotated around the vertical axis through the pivot point. 18109 * 18110 * @see #getPivotX() 18111 * @see #getPivotY() 18112 * @see #setRotationY(float) 18113 * 18114 * @return The degrees of Y rotation. 18115 */ 18116 @ViewDebug.ExportedProperty(category = "drawing") 18117 @InspectableProperty getRotationY()18118 public float getRotationY() { 18119 return mRenderNode.getRotationY(); 18120 } 18121 18122 /** 18123 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 18124 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 18125 * down the y axis. 18126 * 18127 * When rotating large views, it is recommended to adjust the camera distance 18128 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 18129 * 18130 * @param rotationY The degrees of Y rotation. 18131 * 18132 * @see #getRotationY() 18133 * @see #getPivotX() 18134 * @see #getPivotY() 18135 * @see #setRotation(float) 18136 * @see #setRotationX(float) 18137 * @see #setCameraDistance(float) 18138 * 18139 * @attr ref android.R.styleable#View_rotationY 18140 */ 18141 @RemotableViewMethod setRotationY(float rotationY)18142 public void setRotationY(float rotationY) { 18143 if (rotationY != getRotationY()) { 18144 invalidateViewProperty(true, false); 18145 mRenderNode.setRotationY(rotationY); 18146 invalidateViewProperty(false, true); 18147 18148 invalidateParentIfNeededAndWasQuickRejected(); 18149 notifySubtreeAccessibilityStateChangedIfNeeded(); 18150 } 18151 } 18152 18153 /** 18154 * The degrees that the view is rotated around the horizontal axis through the pivot point. 18155 * 18156 * @see #getPivotX() 18157 * @see #getPivotY() 18158 * @see #setRotationX(float) 18159 * 18160 * @return The degrees of X rotation. 18161 */ 18162 @ViewDebug.ExportedProperty(category = "drawing") 18163 @InspectableProperty getRotationX()18164 public float getRotationX() { 18165 return mRenderNode.getRotationX(); 18166 } 18167 18168 /** 18169 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 18170 * Increasing values result in clockwise rotation from the viewpoint of looking down the 18171 * x axis. 18172 * 18173 * When rotating large views, it is recommended to adjust the camera distance 18174 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 18175 * 18176 * @param rotationX The degrees of X rotation. 18177 * 18178 * @see #getRotationX() 18179 * @see #getPivotX() 18180 * @see #getPivotY() 18181 * @see #setRotation(float) 18182 * @see #setRotationY(float) 18183 * @see #setCameraDistance(float) 18184 * 18185 * @attr ref android.R.styleable#View_rotationX 18186 */ 18187 @RemotableViewMethod setRotationX(float rotationX)18188 public void setRotationX(float rotationX) { 18189 if (rotationX != getRotationX()) { 18190 invalidateViewProperty(true, false); 18191 mRenderNode.setRotationX(rotationX); 18192 invalidateViewProperty(false, true); 18193 18194 invalidateParentIfNeededAndWasQuickRejected(); 18195 notifySubtreeAccessibilityStateChangedIfNeeded(); 18196 } 18197 } 18198 18199 /** 18200 * The amount that the view is scaled in x around the pivot point, as a proportion of 18201 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 18202 * 18203 * <p>By default, this is 1.0f. 18204 * 18205 * @see #getPivotX() 18206 * @see #getPivotY() 18207 * @return The scaling factor. 18208 */ 18209 @ViewDebug.ExportedProperty(category = "drawing") 18210 @InspectableProperty getScaleX()18211 public float getScaleX() { 18212 return mRenderNode.getScaleX(); 18213 } 18214 18215 /** 18216 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 18217 * the view's unscaled width. A value of 1 means that no scaling is applied. 18218 * 18219 * @param scaleX The scaling factor. 18220 * @see #getPivotX() 18221 * @see #getPivotY() 18222 * 18223 * @attr ref android.R.styleable#View_scaleX 18224 */ 18225 @RemotableViewMethod setScaleX(float scaleX)18226 public void setScaleX(float scaleX) { 18227 if (scaleX != getScaleX()) { 18228 scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX"); 18229 invalidateViewProperty(true, false); 18230 mRenderNode.setScaleX(scaleX); 18231 invalidateViewProperty(false, true); 18232 18233 invalidateParentIfNeededAndWasQuickRejected(); 18234 notifySubtreeAccessibilityStateChangedIfNeeded(); 18235 } 18236 } 18237 18238 /** 18239 * The amount that the view is scaled in y around the pivot point, as a proportion of 18240 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 18241 * 18242 * <p>By default, this is 1.0f. 18243 * 18244 * @see #getPivotX() 18245 * @see #getPivotY() 18246 * @return The scaling factor. 18247 */ 18248 @ViewDebug.ExportedProperty(category = "drawing") 18249 @InspectableProperty getScaleY()18250 public float getScaleY() { 18251 return mRenderNode.getScaleY(); 18252 } 18253 18254 /** 18255 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 18256 * the view's unscaled width. A value of 1 means that no scaling is applied. 18257 * 18258 * @param scaleY The scaling factor. 18259 * @see #getPivotX() 18260 * @see #getPivotY() 18261 * 18262 * @attr ref android.R.styleable#View_scaleY 18263 */ 18264 @RemotableViewMethod setScaleY(float scaleY)18265 public void setScaleY(float scaleY) { 18266 if (scaleY != getScaleY()) { 18267 scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY"); 18268 invalidateViewProperty(true, false); 18269 mRenderNode.setScaleY(scaleY); 18270 invalidateViewProperty(false, true); 18271 18272 invalidateParentIfNeededAndWasQuickRejected(); 18273 notifySubtreeAccessibilityStateChangedIfNeeded(); 18274 } 18275 } 18276 18277 /** 18278 * The x location of the point around which the view is {@link #setRotation(float) rotated} 18279 * and {@link #setScaleX(float) scaled}. 18280 * 18281 * @see #getRotation() 18282 * @see #getScaleX() 18283 * @see #getScaleY() 18284 * @see #getPivotY() 18285 * @return The x location of the pivot point. 18286 * 18287 * @attr ref android.R.styleable#View_transformPivotX 18288 */ 18289 @ViewDebug.ExportedProperty(category = "drawing") 18290 @InspectableProperty(name = "transformPivotX") getPivotX()18291 public float getPivotX() { 18292 return mRenderNode.getPivotX(); 18293 } 18294 18295 /** 18296 * Sets the x location of the point around which the view is 18297 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 18298 * By default, the pivot point is centered on the object. 18299 * Setting this property disables this behavior and causes the view to use only the 18300 * explicitly set pivotX and pivotY values. 18301 * 18302 * @param pivotX The x location of the pivot point. 18303 * @see #getRotation() 18304 * @see #getScaleX() 18305 * @see #getScaleY() 18306 * @see #getPivotY() 18307 * 18308 * @attr ref android.R.styleable#View_transformPivotX 18309 */ 18310 @RemotableViewMethod setPivotX(float pivotX)18311 public void setPivotX(float pivotX) { 18312 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 18313 invalidateViewProperty(true, false); 18314 mRenderNode.setPivotX(pivotX); 18315 invalidateViewProperty(false, true); 18316 18317 invalidateParentIfNeededAndWasQuickRejected(); 18318 } 18319 } 18320 18321 /** 18322 * The y location of the point around which the view is {@link #setRotation(float) rotated} 18323 * and {@link #setScaleY(float) scaled}. 18324 * 18325 * @see #getRotation() 18326 * @see #getScaleX() 18327 * @see #getScaleY() 18328 * @see #getPivotY() 18329 * @return The y location of the pivot point. 18330 * 18331 * @attr ref android.R.styleable#View_transformPivotY 18332 */ 18333 @ViewDebug.ExportedProperty(category = "drawing") 18334 @InspectableProperty(name = "transformPivotY") getPivotY()18335 public float getPivotY() { 18336 return mRenderNode.getPivotY(); 18337 } 18338 18339 /** 18340 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 18341 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 18342 * Setting this property disables this behavior and causes the view to use only the 18343 * explicitly set pivotX and pivotY values. 18344 * 18345 * @param pivotY The y location of the pivot point. 18346 * @see #getRotation() 18347 * @see #getScaleX() 18348 * @see #getScaleY() 18349 * @see #getPivotY() 18350 * 18351 * @attr ref android.R.styleable#View_transformPivotY 18352 */ 18353 @RemotableViewMethod setPivotY(float pivotY)18354 public void setPivotY(float pivotY) { 18355 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 18356 invalidateViewProperty(true, false); 18357 mRenderNode.setPivotY(pivotY); 18358 invalidateViewProperty(false, true); 18359 18360 invalidateParentIfNeededAndWasQuickRejected(); 18361 } 18362 } 18363 18364 /** 18365 * Returns whether or not a pivot has been set by a call to {@link #setPivotX(float)} or 18366 * {@link #setPivotY(float)}. If no pivot has been set then the pivot will be the center 18367 * of the view. 18368 * 18369 * @return True if a pivot has been set, false if the default pivot is being used 18370 */ isPivotSet()18371 public boolean isPivotSet() { 18372 return mRenderNode.isPivotExplicitlySet(); 18373 } 18374 18375 /** 18376 * Clears any pivot previously set by a call to {@link #setPivotX(float)} or 18377 * {@link #setPivotY(float)}. After calling this {@link #isPivotSet()} will be false 18378 * and the pivot used for rotation will return to default of being centered on the view. 18379 */ resetPivot()18380 public void resetPivot() { 18381 if (mRenderNode.resetPivot()) { 18382 invalidateViewProperty(false, false); 18383 } 18384 } 18385 18386 /** 18387 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 18388 * completely transparent and 1 means the view is completely opaque. 18389 * 18390 * <p>By default this is 1.0f. 18391 * @return The opacity of the view. 18392 */ 18393 @ViewDebug.ExportedProperty(category = "drawing") 18394 @InspectableProperty getAlpha()18395 public float getAlpha() { 18396 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 18397 } 18398 18399 /** 18400 * Sets the behavior for overlapping rendering for this view (see {@link 18401 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 18402 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 18403 * providing the value which is then used internally. That is, when {@link 18404 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 18405 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 18406 * instead. 18407 * 18408 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 18409 * instead of that returned by {@link #hasOverlappingRendering()}. 18410 * 18411 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 18412 */ forceHasOverlappingRendering(boolean hasOverlappingRendering)18413 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 18414 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 18415 if (hasOverlappingRendering) { 18416 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 18417 } else { 18418 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 18419 } 18420 } 18421 18422 /** 18423 * Returns the value for overlapping rendering that is used internally. This is either 18424 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 18425 * the return value of {@link #hasOverlappingRendering()}, otherwise. 18426 * 18427 * @return The value for overlapping rendering being used internally. 18428 */ getHasOverlappingRendering()18429 public final boolean getHasOverlappingRendering() { 18430 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 18431 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 18432 hasOverlappingRendering(); 18433 } 18434 18435 /** 18436 * Returns whether this View has content which overlaps. 18437 * 18438 * <p>This function, intended to be overridden by specific View types, is an optimization when 18439 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 18440 * an offscreen buffer and then composited into place, which can be expensive. If the view has 18441 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 18442 * directly. An example of overlapping rendering is a TextView with a background image, such as 18443 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 18444 * ImageView with only the foreground image. The default implementation returns true; subclasses 18445 * should override if they have cases which can be optimized.</p> 18446 * 18447 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 18448 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 18449 * 18450 * @return true if the content in this view might overlap, false otherwise. 18451 */ 18452 @ViewDebug.ExportedProperty(category = "drawing") hasOverlappingRendering()18453 public boolean hasOverlappingRendering() { 18454 return true; 18455 } 18456 18457 /** 18458 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 18459 * completely transparent and 1 means the view is completely opaque. 18460 * 18461 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 18462 * can have significant performance implications, especially for large views. It is best to use 18463 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 18464 * 18465 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 18466 * strongly recommended for performance reasons to either override 18467 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 18468 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 18469 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 18470 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 18471 * of rendering cost, even for simple or small views. Starting with 18472 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 18473 * applied to the view at the rendering level.</p> 18474 * 18475 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 18476 * responsible for applying the opacity itself.</p> 18477 * 18478 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 18479 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 18480 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 18481 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 18482 * 18483 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 18484 * value will clip a View to its bounds, unless the View returns <code>false</code> from 18485 * {@link #hasOverlappingRendering}.</p> 18486 * 18487 * @param alpha The opacity of the view. 18488 * 18489 * @see #hasOverlappingRendering() 18490 * @see #setLayerType(int, android.graphics.Paint) 18491 * 18492 * @attr ref android.R.styleable#View_alpha 18493 */ 18494 @RemotableViewMethod setAlpha(@loatRangefrom=0.0, to=1.0) float alpha)18495 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 18496 ensureTransformationInfo(); 18497 if (mTransformationInfo.mAlpha != alpha) { 18498 setAlphaInternal(alpha); 18499 if (onSetAlpha((int) (alpha * 255))) { 18500 mPrivateFlags |= PFLAG_ALPHA_SET; 18501 // subclass is handling alpha - don't optimize rendering cache invalidation 18502 invalidateParentCaches(); 18503 invalidate(true); 18504 } else { 18505 mPrivateFlags &= ~PFLAG_ALPHA_SET; 18506 invalidateViewProperty(true, false); 18507 mRenderNode.setAlpha(getFinalAlpha()); 18508 } 18509 } 18510 } 18511 18512 /** 18513 * Faster version of setAlpha() which performs the same steps except there are 18514 * no calls to invalidate(). The caller of this function should perform proper invalidation 18515 * on the parent and this object. The return value indicates whether the subclass handles 18516 * alpha (the return value for onSetAlpha()). 18517 * 18518 * @param alpha The new value for the alpha property 18519 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 18520 * the new value for the alpha property is different from the old value 18521 */ 18522 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768435) setAlphaNoInvalidation(float alpha)18523 boolean setAlphaNoInvalidation(float alpha) { 18524 ensureTransformationInfo(); 18525 if (mTransformationInfo.mAlpha != alpha) { 18526 setAlphaInternal(alpha); 18527 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 18528 if (subclassHandlesAlpha) { 18529 mPrivateFlags |= PFLAG_ALPHA_SET; 18530 return true; 18531 } else { 18532 mPrivateFlags &= ~PFLAG_ALPHA_SET; 18533 mRenderNode.setAlpha(getFinalAlpha()); 18534 } 18535 } 18536 return false; 18537 } 18538 setAlphaInternal(float alpha)18539 void setAlphaInternal(float alpha) { 18540 float oldAlpha = mTransformationInfo.mAlpha; 18541 mTransformationInfo.mAlpha = alpha; 18542 // Report visibility changes, which can affect children, to accessibility 18543 if ((alpha == 0) ^ (oldAlpha == 0)) { 18544 notifySubtreeAccessibilityStateChangedIfNeeded(); 18545 } 18546 } 18547 18548 /** 18549 * This property is intended only for use by the Fade transition, which animates it 18550 * to produce a visual translucency that does not side-effect (or get affected by) 18551 * the real alpha property. This value is composited with the other alpha value 18552 * (and the AlphaAnimation value, when that is present) to produce a final visual 18553 * translucency result, which is what is passed into the DisplayList. 18554 */ setTransitionAlpha(float alpha)18555 public void setTransitionAlpha(float alpha) { 18556 ensureTransformationInfo(); 18557 if (mTransformationInfo.mTransitionAlpha != alpha) { 18558 mTransformationInfo.mTransitionAlpha = alpha; 18559 mPrivateFlags &= ~PFLAG_ALPHA_SET; 18560 invalidateViewProperty(true, false); 18561 mRenderNode.setAlpha(getFinalAlpha()); 18562 } 18563 } 18564 18565 /** 18566 * Calculates the visual alpha of this view, which is a combination of the actual 18567 * alpha value and the transitionAlpha value (if set). 18568 */ getFinalAlpha()18569 private float getFinalAlpha() { 18570 if (mTransformationInfo != null) { 18571 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 18572 } 18573 return 1; 18574 } 18575 18576 /** 18577 * This property is intended only for use by the Fade transition, which animates 18578 * it to produce a visual translucency that does not side-effect (or get affected 18579 * by) the real alpha property. This value is composited with the other alpha 18580 * value (and the AlphaAnimation value, when that is present) to produce a final 18581 * visual translucency result, which is what is passed into the DisplayList. 18582 */ 18583 @ViewDebug.ExportedProperty(category = "drawing") getTransitionAlpha()18584 public float getTransitionAlpha() { 18585 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 18586 } 18587 18588 /** 18589 * Sets whether or not to allow force dark to apply to this view. 18590 * 18591 * Setting this to false will disable the auto-dark feature on everything this view 18592 * draws, including any descendants. 18593 * 18594 * Setting this to true will allow this view to be automatically made dark, however 18595 * a value of 'true' will not override any 'false' value in its parent chain nor will 18596 * it prevent any 'false' in any of its children. 18597 * 18598 * The default behavior of force dark is also influenced by the Theme's 18599 * {@link android.R.styleable#Theme_isLightTheme isLightTheme} attribute. 18600 * If a theme is isLightTheme="false", then force dark is globally disabled for that theme. 18601 * 18602 * @param allow Whether or not to allow force dark. 18603 */ setForceDarkAllowed(boolean allow)18604 public void setForceDarkAllowed(boolean allow) { 18605 if (mRenderNode.setForceDarkAllowed(allow)) { 18606 // Currently toggling force-dark requires a new display list push to apply 18607 // TODO: Make it not clobber the display list so this is just a damageSelf() instead 18608 invalidate(); 18609 } 18610 } 18611 18612 /** 18613 * See {@link #setForceDarkAllowed(boolean)} 18614 * 18615 * @return true if force dark is allowed (default), false if it is disabled 18616 */ 18617 @ViewDebug.ExportedProperty(category = "drawing") 18618 @InspectableProperty isForceDarkAllowed()18619 public boolean isForceDarkAllowed() { 18620 return mRenderNode.isForceDarkAllowed(); 18621 } 18622 18623 /** 18624 * Top position of this view relative to its parent. 18625 * 18626 * @return The top of this view, in pixels. 18627 */ 18628 @ViewDebug.CapturedViewProperty getTop()18629 public final int getTop() { 18630 return mTop; 18631 } 18632 18633 /** 18634 * Sets the top position of this view relative to its parent. This method is meant to be called 18635 * by the layout system and should not generally be called otherwise, because the property 18636 * may be changed at any time by the layout. 18637 * 18638 * @param top The top of this view, in pixels. 18639 */ setTop(int top)18640 public final void setTop(int top) { 18641 if (top != mTop) { 18642 final boolean matrixIsIdentity = hasIdentityMatrix(); 18643 if (matrixIsIdentity) { 18644 if (mAttachInfo != null) { 18645 int minTop; 18646 int yLoc; 18647 if (top < mTop) { 18648 minTop = top; 18649 yLoc = top - mTop; 18650 } else { 18651 minTop = mTop; 18652 yLoc = 0; 18653 } 18654 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 18655 } 18656 } else { 18657 // Double-invalidation is necessary to capture view's old and new areas 18658 invalidate(true); 18659 } 18660 18661 int width = mRight - mLeft; 18662 int oldHeight = mBottom - mTop; 18663 18664 mTop = top; 18665 mRenderNode.setTop(mTop); 18666 18667 sizeChange(width, mBottom - mTop, width, oldHeight); 18668 18669 if (!matrixIsIdentity) { 18670 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 18671 invalidate(true); 18672 } 18673 mBackgroundSizeChanged = true; 18674 mDefaultFocusHighlightSizeChanged = true; 18675 if (mForegroundInfo != null) { 18676 mForegroundInfo.mBoundsChanged = true; 18677 } 18678 invalidateParentIfNeeded(); 18679 } 18680 } 18681 18682 /** 18683 * Bottom position of this view relative to its parent. 18684 * 18685 * @return The bottom of this view, in pixels. 18686 */ 18687 @ViewDebug.CapturedViewProperty getBottom()18688 public final int getBottom() { 18689 return mBottom; 18690 } 18691 18692 /** 18693 * True if this view has changed since the last time being drawn. 18694 * 18695 * @return The dirty state of this view. 18696 */ isDirty()18697 public boolean isDirty() { 18698 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 18699 } 18700 18701 /** 18702 * Sets the bottom position of this view relative to its parent. This method is meant to be 18703 * called by the layout system and should not generally be called otherwise, because the 18704 * property may be changed at any time by the layout. 18705 * 18706 * @param bottom The bottom of this view, in pixels. 18707 */ setBottom(int bottom)18708 public final void setBottom(int bottom) { 18709 if (bottom != mBottom) { 18710 final boolean matrixIsIdentity = hasIdentityMatrix(); 18711 if (matrixIsIdentity) { 18712 if (mAttachInfo != null) { 18713 int maxBottom; 18714 if (bottom < mBottom) { 18715 maxBottom = mBottom; 18716 } else { 18717 maxBottom = bottom; 18718 } 18719 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 18720 } 18721 } else { 18722 // Double-invalidation is necessary to capture view's old and new areas 18723 invalidate(true); 18724 } 18725 18726 int width = mRight - mLeft; 18727 int oldHeight = mBottom - mTop; 18728 18729 mBottom = bottom; 18730 mRenderNode.setBottom(mBottom); 18731 18732 sizeChange(width, mBottom - mTop, width, oldHeight); 18733 18734 if (!matrixIsIdentity) { 18735 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 18736 invalidate(true); 18737 } 18738 mBackgroundSizeChanged = true; 18739 mDefaultFocusHighlightSizeChanged = true; 18740 if (mForegroundInfo != null) { 18741 mForegroundInfo.mBoundsChanged = true; 18742 } 18743 invalidateParentIfNeeded(); 18744 } 18745 } 18746 18747 /** 18748 * Left position of this view relative to its parent. 18749 * 18750 * @return The left edge of this view, in pixels. 18751 */ 18752 @ViewDebug.CapturedViewProperty getLeft()18753 public final int getLeft() { 18754 return mLeft; 18755 } 18756 18757 /** 18758 * Sets the left position of this view relative to its parent. This method is meant to be called 18759 * by the layout system and should not generally be called otherwise, because the property 18760 * may be changed at any time by the layout. 18761 * 18762 * @param left The left of this view, in pixels. 18763 */ setLeft(int left)18764 public final void setLeft(int left) { 18765 if (left != mLeft) { 18766 final boolean matrixIsIdentity = hasIdentityMatrix(); 18767 if (matrixIsIdentity) { 18768 if (mAttachInfo != null) { 18769 int minLeft; 18770 int xLoc; 18771 if (left < mLeft) { 18772 minLeft = left; 18773 xLoc = left - mLeft; 18774 } else { 18775 minLeft = mLeft; 18776 xLoc = 0; 18777 } 18778 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 18779 } 18780 } else { 18781 // Double-invalidation is necessary to capture view's old and new areas 18782 invalidate(true); 18783 } 18784 18785 int oldWidth = mRight - mLeft; 18786 int height = mBottom - mTop; 18787 18788 mLeft = left; 18789 mRenderNode.setLeft(left); 18790 18791 sizeChange(mRight - mLeft, height, oldWidth, height); 18792 18793 if (!matrixIsIdentity) { 18794 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 18795 invalidate(true); 18796 } 18797 mBackgroundSizeChanged = true; 18798 mDefaultFocusHighlightSizeChanged = true; 18799 if (mForegroundInfo != null) { 18800 mForegroundInfo.mBoundsChanged = true; 18801 } 18802 invalidateParentIfNeeded(); 18803 } 18804 } 18805 18806 /** 18807 * Right position of this view relative to its parent. 18808 * 18809 * @return The right edge of this view, in pixels. 18810 */ 18811 @ViewDebug.CapturedViewProperty getRight()18812 public final int getRight() { 18813 return mRight; 18814 } 18815 18816 /** 18817 * Sets the right position of this view relative to its parent. This method is meant to be called 18818 * by the layout system and should not generally be called otherwise, because the property 18819 * may be changed at any time by the layout. 18820 * 18821 * @param right The right of this view, in pixels. 18822 */ setRight(int right)18823 public final void setRight(int right) { 18824 if (right != mRight) { 18825 final boolean matrixIsIdentity = hasIdentityMatrix(); 18826 if (matrixIsIdentity) { 18827 if (mAttachInfo != null) { 18828 int maxRight; 18829 if (right < mRight) { 18830 maxRight = mRight; 18831 } else { 18832 maxRight = right; 18833 } 18834 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 18835 } 18836 } else { 18837 // Double-invalidation is necessary to capture view's old and new areas 18838 invalidate(true); 18839 } 18840 18841 int oldWidth = mRight - mLeft; 18842 int height = mBottom - mTop; 18843 18844 mRight = right; 18845 mRenderNode.setRight(mRight); 18846 18847 sizeChange(mRight - mLeft, height, oldWidth, height); 18848 18849 if (!matrixIsIdentity) { 18850 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 18851 invalidate(true); 18852 } 18853 mBackgroundSizeChanged = true; 18854 mDefaultFocusHighlightSizeChanged = true; 18855 if (mForegroundInfo != null) { 18856 mForegroundInfo.mBoundsChanged = true; 18857 } 18858 invalidateParentIfNeeded(); 18859 } 18860 } 18861 sanitizeFloatPropertyValue(float value, String propertyName)18862 private static float sanitizeFloatPropertyValue(float value, String propertyName) { 18863 return sanitizeFloatPropertyValue(value, propertyName, -Float.MAX_VALUE, Float.MAX_VALUE); 18864 } 18865 sanitizeFloatPropertyValue(float value, String propertyName, float min, float max)18866 private static float sanitizeFloatPropertyValue(float value, String propertyName, 18867 float min, float max) { 18868 // The expected "nothing bad happened" path 18869 if (value >= min && value <= max) return value; 18870 18871 if (value < min || value == Float.NEGATIVE_INFINITY) { 18872 if (sThrowOnInvalidFloatProperties) { 18873 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 18874 + value + ", the value must be >= " + min); 18875 } 18876 return min; 18877 } 18878 18879 if (value > max || value == Float.POSITIVE_INFINITY) { 18880 if (sThrowOnInvalidFloatProperties) { 18881 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 18882 + value + ", the value must be <= " + max); 18883 } 18884 return max; 18885 } 18886 18887 if (Float.isNaN(value)) { 18888 if (sThrowOnInvalidFloatProperties) { 18889 throw new IllegalArgumentException( 18890 "Cannot set '" + propertyName + "' to Float.NaN"); 18891 } 18892 return 0; // Unclear which direction this NaN went so... 0? 18893 } 18894 18895 // Shouldn't be possible to reach this. 18896 throw new IllegalStateException("How do you get here?? " + value); 18897 } 18898 18899 /** 18900 * The visual x position of this view, in pixels. This is equivalent to the 18901 * {@link #setTranslationX(float) translationX} property plus the current 18902 * {@link #getLeft() left} property. 18903 * 18904 * @return The visual x position of this view, in pixels. 18905 */ 18906 @ViewDebug.ExportedProperty(category = "drawing") getX()18907 public float getX() { 18908 return mLeft + getTranslationX(); 18909 } 18910 18911 /** 18912 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 18913 * {@link #setTranslationX(float) translationX} property to be the difference between 18914 * the x value passed in and the current {@link #getLeft() left} property. 18915 * 18916 * @param x The visual x position of this view, in pixels. 18917 */ setX(float x)18918 public void setX(float x) { 18919 setTranslationX(x - mLeft); 18920 } 18921 18922 /** 18923 * The visual y position of this view, in pixels. This is equivalent to the 18924 * {@link #setTranslationY(float) translationY} property plus the current 18925 * {@link #getTop() top} property. 18926 * 18927 * @return The visual y position of this view, in pixels. 18928 */ 18929 @ViewDebug.ExportedProperty(category = "drawing") getY()18930 public float getY() { 18931 return mTop + getTranslationY(); 18932 } 18933 18934 /** 18935 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 18936 * {@link #setTranslationY(float) translationY} property to be the difference between 18937 * the y value passed in and the current {@link #getTop() top} property. 18938 * 18939 * @param y The visual y position of this view, in pixels. 18940 */ setY(float y)18941 public void setY(float y) { 18942 setTranslationY(y - mTop); 18943 } 18944 18945 /** 18946 * The visual z position of this view, in pixels. This is equivalent to the 18947 * {@link #setTranslationZ(float) translationZ} property plus the current 18948 * {@link #getElevation() elevation} property. 18949 * 18950 * @return The visual z position of this view, in pixels. 18951 */ 18952 @ViewDebug.ExportedProperty(category = "drawing") getZ()18953 public float getZ() { 18954 return getElevation() + getTranslationZ(); 18955 } 18956 18957 /** 18958 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 18959 * {@link #setTranslationZ(float) translationZ} property to be the difference between 18960 * the z value passed in and the current {@link #getElevation() elevation} property. 18961 * 18962 * @param z The visual z position of this view, in pixels. 18963 */ setZ(float z)18964 public void setZ(float z) { 18965 setTranslationZ(z - getElevation()); 18966 } 18967 18968 /** 18969 * The base elevation of this view relative to its parent, in pixels. 18970 * 18971 * @return The base depth position of the view, in pixels. 18972 */ 18973 @ViewDebug.ExportedProperty(category = "drawing") 18974 @InspectableProperty getElevation()18975 public float getElevation() { 18976 return mRenderNode.getElevation(); 18977 } 18978 18979 /** 18980 * Sets the base elevation of this view, in pixels. 18981 * 18982 * @attr ref android.R.styleable#View_elevation 18983 */ 18984 @RemotableViewMethod setElevation(float elevation)18985 public void setElevation(float elevation) { 18986 if (elevation != getElevation()) { 18987 elevation = sanitizeFloatPropertyValue(elevation, "elevation"); 18988 invalidateViewProperty(true, false); 18989 mRenderNode.setElevation(elevation); 18990 invalidateViewProperty(false, true); 18991 18992 invalidateParentIfNeededAndWasQuickRejected(); 18993 } 18994 } 18995 18996 /** 18997 * The horizontal location of this view relative to its {@link #getLeft() left} position. 18998 * This position is post-layout, in addition to wherever the object's 18999 * layout placed it. 19000 * 19001 * @return The horizontal position of this view relative to its left position, in pixels. 19002 */ 19003 @ViewDebug.ExportedProperty(category = "drawing") 19004 @InspectableProperty getTranslationX()19005 public float getTranslationX() { 19006 return mRenderNode.getTranslationX(); 19007 } 19008 19009 /** 19010 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 19011 * This effectively positions the object post-layout, in addition to wherever the object's 19012 * layout placed it. 19013 * 19014 * @param translationX The horizontal position of this view relative to its left position, 19015 * in pixels. 19016 * 19017 * @attr ref android.R.styleable#View_translationX 19018 */ 19019 @RemotableViewMethod setTranslationX(float translationX)19020 public void setTranslationX(float translationX) { 19021 if (translationX != getTranslationX()) { 19022 invalidateViewProperty(true, false); 19023 mRenderNode.setTranslationX(translationX); 19024 invalidateViewProperty(false, true); 19025 19026 invalidateParentIfNeededAndWasQuickRejected(); 19027 notifySubtreeAccessibilityStateChangedIfNeeded(); 19028 } 19029 } 19030 19031 /** 19032 * The vertical location of this view relative to its {@link #getTop() top} position. 19033 * This position is post-layout, in addition to wherever the object's 19034 * layout placed it. 19035 * 19036 * @return The vertical position of this view relative to its top position, 19037 * in pixels. 19038 */ 19039 @ViewDebug.ExportedProperty(category = "drawing") 19040 @InspectableProperty getTranslationY()19041 public float getTranslationY() { 19042 return mRenderNode.getTranslationY(); 19043 } 19044 19045 /** 19046 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 19047 * This effectively positions the object post-layout, in addition to wherever the object's 19048 * layout placed it. 19049 * 19050 * @param translationY The vertical position of this view relative to its top position, 19051 * in pixels. 19052 * 19053 * @attr ref android.R.styleable#View_translationY 19054 */ 19055 @RemotableViewMethod setTranslationY(float translationY)19056 public void setTranslationY(float translationY) { 19057 if (translationY != getTranslationY()) { 19058 invalidateViewProperty(true, false); 19059 mRenderNode.setTranslationY(translationY); 19060 invalidateViewProperty(false, true); 19061 19062 invalidateParentIfNeededAndWasQuickRejected(); 19063 notifySubtreeAccessibilityStateChangedIfNeeded(); 19064 } 19065 } 19066 19067 /** 19068 * The depth location of this view relative to its {@link #getElevation() elevation}. 19069 * 19070 * @return The depth of this view relative to its elevation. 19071 */ 19072 @ViewDebug.ExportedProperty(category = "drawing") 19073 @InspectableProperty getTranslationZ()19074 public float getTranslationZ() { 19075 return mRenderNode.getTranslationZ(); 19076 } 19077 19078 /** 19079 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 19080 * 19081 * @attr ref android.R.styleable#View_translationZ 19082 */ 19083 @RemotableViewMethod setTranslationZ(float translationZ)19084 public void setTranslationZ(float translationZ) { 19085 if (translationZ != getTranslationZ()) { 19086 translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ"); 19087 invalidateViewProperty(true, false); 19088 mRenderNode.setTranslationZ(translationZ); 19089 invalidateViewProperty(false, true); 19090 19091 invalidateParentIfNeededAndWasQuickRejected(); 19092 } 19093 } 19094 19095 /** 19096 * Changes the transformation matrix on the view. This is used in animation frameworks, 19097 * such as {@link android.transition.Transition}. When the animation finishes, the matrix 19098 * should be cleared by calling this method with <code>null</code> as the matrix parameter. 19099 * Application developers should use transformation methods like {@link #setRotation(float)}, 19100 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 19101 * and {@link #setTranslationY(float)} (float)}} instead. 19102 * 19103 * @param matrix The matrix, null indicates that the matrix should be cleared. 19104 * @see #getAnimationMatrix() 19105 */ setAnimationMatrix(@ullable Matrix matrix)19106 public void setAnimationMatrix(@Nullable Matrix matrix) { 19107 invalidateViewProperty(true, false); 19108 mRenderNode.setAnimationMatrix(matrix); 19109 invalidateViewProperty(false, true); 19110 19111 invalidateParentIfNeededAndWasQuickRejected(); 19112 } 19113 19114 /** 19115 * Return the current transformation matrix of the view. This is used in animation frameworks, 19116 * such as {@link android.transition.Transition}. Returns <code>null</code> when there is no 19117 * transformation provided by {@link #setAnimationMatrix(Matrix)}. 19118 * Application developers should use transformation methods like {@link #setRotation(float)}, 19119 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 19120 * and {@link #setTranslationY(float)} (float)}} instead. 19121 * 19122 * @return the Matrix, null indicates there is no transformation 19123 * @see #setAnimationMatrix(Matrix) 19124 */ 19125 @Nullable getAnimationMatrix()19126 public Matrix getAnimationMatrix() { 19127 return mRenderNode.getAnimationMatrix(); 19128 } 19129 19130 /** 19131 * Returns the current StateListAnimator if exists. 19132 * 19133 * @return StateListAnimator or null if it does not exists 19134 * @see #setStateListAnimator(android.animation.StateListAnimator) 19135 */ 19136 @InspectableProperty getStateListAnimator()19137 public StateListAnimator getStateListAnimator() { 19138 return mStateListAnimator; 19139 } 19140 19141 /** 19142 * Attaches the provided StateListAnimator to this View. 19143 * <p> 19144 * Any previously attached StateListAnimator will be detached. 19145 * 19146 * @param stateListAnimator The StateListAnimator to update the view 19147 * @see android.animation.StateListAnimator 19148 */ setStateListAnimator(StateListAnimator stateListAnimator)19149 public void setStateListAnimator(StateListAnimator stateListAnimator) { 19150 if (mStateListAnimator == stateListAnimator) { 19151 return; 19152 } 19153 if (mStateListAnimator != null) { 19154 mStateListAnimator.setTarget(null); 19155 } 19156 mStateListAnimator = stateListAnimator; 19157 if (stateListAnimator != null) { 19158 stateListAnimator.setTarget(this); 19159 if (isAttachedToWindow()) { 19160 stateListAnimator.setState(getDrawableState()); 19161 } 19162 } 19163 } 19164 19165 /** 19166 * Returns whether the Outline should be used to clip the contents of the View. 19167 * <p> 19168 * Note that this flag will only be respected if the View's Outline returns true from 19169 * {@link Outline#canClip()}. 19170 * 19171 * @see #setOutlineProvider(ViewOutlineProvider) 19172 * @see #setClipToOutline(boolean) 19173 */ getClipToOutline()19174 public final boolean getClipToOutline() { 19175 return mRenderNode.getClipToOutline(); 19176 } 19177 19178 /** 19179 * Sets whether the View's Outline should be used to clip the contents of the View. 19180 * <p> 19181 * Only a single non-rectangular clip can be applied on a View at any time. 19182 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 19183 * circular reveal} animation take priority over Outline clipping, and 19184 * child Outline clipping takes priority over Outline clipping done by a 19185 * parent. 19186 * <p> 19187 * Note that this flag will only be respected if the View's Outline returns true from 19188 * {@link Outline#canClip()}. 19189 * 19190 * @see #setOutlineProvider(ViewOutlineProvider) 19191 * @see #getClipToOutline() 19192 * 19193 * @attr ref android.R.styleable#View_clipToOutline 19194 */ 19195 @RemotableViewMethod setClipToOutline(boolean clipToOutline)19196 public void setClipToOutline(boolean clipToOutline) { 19197 damageInParent(); 19198 if (getClipToOutline() != clipToOutline) { 19199 mRenderNode.setClipToOutline(clipToOutline); 19200 } 19201 } 19202 19203 // correspond to the enum values of View_outlineProvider 19204 private static final int PROVIDER_BACKGROUND = 0; 19205 private static final int PROVIDER_NONE = 1; 19206 private static final int PROVIDER_BOUNDS = 2; 19207 private static final int PROVIDER_PADDED_BOUNDS = 3; setOutlineProviderFromAttribute(int providerInt)19208 private void setOutlineProviderFromAttribute(int providerInt) { 19209 switch (providerInt) { 19210 case PROVIDER_BACKGROUND: 19211 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 19212 break; 19213 case PROVIDER_NONE: 19214 setOutlineProvider(null); 19215 break; 19216 case PROVIDER_BOUNDS: 19217 setOutlineProvider(ViewOutlineProvider.BOUNDS); 19218 break; 19219 case PROVIDER_PADDED_BOUNDS: 19220 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 19221 break; 19222 } 19223 } 19224 19225 /** 19226 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 19227 * the shape of the shadow it casts, and enables outline clipping. 19228 * <p> 19229 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 19230 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 19231 * outline provider with this method allows this behavior to be overridden. 19232 * <p> 19233 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 19234 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 19235 * <p> 19236 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 19237 * 19238 * @see #setClipToOutline(boolean) 19239 * @see #getClipToOutline() 19240 * @see #getOutlineProvider() 19241 */ setOutlineProvider(ViewOutlineProvider provider)19242 public void setOutlineProvider(ViewOutlineProvider provider) { 19243 if (mOutlineProvider != provider) { 19244 mOutlineProvider = provider; 19245 invalidateOutline(); 19246 } 19247 } 19248 19249 /** 19250 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 19251 * that defines the shape of the shadow it casts, and enables outline clipping. 19252 * 19253 * @see #setOutlineProvider(ViewOutlineProvider) 19254 */ 19255 @InspectableProperty getOutlineProvider()19256 public ViewOutlineProvider getOutlineProvider() { 19257 return mOutlineProvider; 19258 } 19259 19260 /** 19261 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 19262 * 19263 * @see #setOutlineProvider(ViewOutlineProvider) 19264 */ invalidateOutline()19265 public void invalidateOutline() { 19266 rebuildOutline(); 19267 19268 notifySubtreeAccessibilityStateChangedIfNeeded(); 19269 invalidateViewProperty(false, false); 19270 } 19271 19272 /** 19273 * Internal version of {@link #invalidateOutline()} which invalidates the 19274 * outline without invalidating the view itself. This is intended to be called from 19275 * within methods in the View class itself which are the result of the view being 19276 * invalidated already. For example, when we are drawing the background of a View, 19277 * we invalidate the outline in case it changed in the meantime, but we do not 19278 * need to invalidate the view because we're already drawing the background as part 19279 * of drawing the view in response to an earlier invalidation of the view. 19280 */ rebuildOutline()19281 private void rebuildOutline() { 19282 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 19283 if (mAttachInfo == null) return; 19284 19285 if (mOutlineProvider == null) { 19286 // no provider, remove outline 19287 mRenderNode.setOutline(null); 19288 } else { 19289 final Outline outline = mAttachInfo.mTmpOutline; 19290 outline.setEmpty(); 19291 outline.setAlpha(1.0f); 19292 19293 mOutlineProvider.getOutline(this, outline); 19294 mRenderNode.setOutline(outline); 19295 } 19296 } 19297 19298 /** 19299 * HierarchyViewer only 19300 * 19301 * @hide 19302 */ 19303 @ViewDebug.ExportedProperty(category = "drawing") hasShadow()19304 public boolean hasShadow() { 19305 return mRenderNode.hasShadow(); 19306 } 19307 19308 /** 19309 * Sets the color of the spot shadow that is drawn when the view has a positive Z or 19310 * elevation value. 19311 * <p> 19312 * By default the shadow color is black. Generally, this color will be opaque so the intensity 19313 * of the shadow is consistent between different views with different colors. 19314 * <p> 19315 * The opacity of the final spot shadow is a function of the shadow caster height, the 19316 * alpha channel of the outlineSpotShadowColor (typically opaque), and the 19317 * {@link android.R.attr#spotShadowAlpha} theme attribute. 19318 * 19319 * @attr ref android.R.styleable#View_outlineSpotShadowColor 19320 * @param color The color this View will cast for its elevation spot shadow. 19321 */ setOutlineSpotShadowColor(@olorInt int color)19322 public void setOutlineSpotShadowColor(@ColorInt int color) { 19323 if (mRenderNode.setSpotShadowColor(color)) { 19324 invalidateViewProperty(true, true); 19325 } 19326 } 19327 19328 /** 19329 * @return The shadow color set by {@link #setOutlineSpotShadowColor(int)}, or black if nothing 19330 * was set 19331 */ 19332 @InspectableProperty getOutlineSpotShadowColor()19333 public @ColorInt int getOutlineSpotShadowColor() { 19334 return mRenderNode.getSpotShadowColor(); 19335 } 19336 19337 /** 19338 * Sets the color of the ambient shadow that is drawn when the view has a positive Z or 19339 * elevation value. 19340 * <p> 19341 * By default the shadow color is black. Generally, this color will be opaque so the intensity 19342 * of the shadow is consistent between different views with different colors. 19343 * <p> 19344 * The opacity of the final ambient shadow is a function of the shadow caster height, the 19345 * alpha channel of the outlineAmbientShadowColor (typically opaque), and the 19346 * {@link android.R.attr#ambientShadowAlpha} theme attribute. 19347 * 19348 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 19349 * @param color The color this View will cast for its elevation shadow. 19350 */ setOutlineAmbientShadowColor(@olorInt int color)19351 public void setOutlineAmbientShadowColor(@ColorInt int color) { 19352 if (mRenderNode.setAmbientShadowColor(color)) { 19353 invalidateViewProperty(true, true); 19354 } 19355 } 19356 19357 /** 19358 * @return The shadow color set by {@link #setOutlineAmbientShadowColor(int)}, or black if 19359 * nothing was set 19360 */ 19361 @InspectableProperty getOutlineAmbientShadowColor()19362 public @ColorInt int getOutlineAmbientShadowColor() { 19363 return mRenderNode.getAmbientShadowColor(); 19364 } 19365 19366 19367 /** @hide */ setRevealClip(boolean shouldClip, float x, float y, float radius)19368 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 19369 mRenderNode.setRevealClip(shouldClip, x, y, radius); 19370 invalidateViewProperty(false, false); 19371 } 19372 19373 /** 19374 * Hit rectangle in parent's coordinates 19375 * 19376 * @param outRect The hit rectangle of the view. 19377 */ getHitRect(Rect outRect)19378 public void getHitRect(Rect outRect) { 19379 if (hasIdentityMatrix() || mAttachInfo == null) { 19380 outRect.set(mLeft, mTop, mRight, mBottom); 19381 } else { 19382 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 19383 tmpRect.set(0, 0, getWidth(), getHeight()); 19384 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 19385 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 19386 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 19387 } 19388 } 19389 19390 /** 19391 * Determines whether the given point, in local coordinates is inside the view. 19392 */ pointInView(float localX, float localY)19393 /*package*/ final boolean pointInView(float localX, float localY) { 19394 return pointInView(localX, localY, 0); 19395 } 19396 19397 /** 19398 * Utility method to determine whether the given point, in local coordinates, 19399 * is inside the view, where the area of the view is expanded by the slop factor. 19400 * This method is called while processing touch-move events to determine if the event 19401 * is still within the view. 19402 * 19403 * @hide 19404 */ 19405 @UnsupportedAppUsage pointInView(float localX, float localY, float slop)19406 public boolean pointInView(float localX, float localY, float slop) { 19407 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 19408 localY < ((mBottom - mTop) + slop); 19409 } 19410 19411 /** 19412 * When a view has focus and the user navigates away from it, the next view is searched for 19413 * starting from the rectangle filled in by this method. 19414 * 19415 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 19416 * of the view. However, if your view maintains some idea of internal selection, 19417 * such as a cursor, or a selected row or column, you should override this method and 19418 * fill in a more specific rectangle. 19419 * 19420 * @param r The rectangle to fill in, in this view's coordinates. 19421 */ getFocusedRect(Rect r)19422 public void getFocusedRect(Rect r) { 19423 getDrawingRect(r); 19424 } 19425 19426 /** 19427 * Sets {@code r} to the coordinates of the non-clipped area of this view in 19428 * the coordinate space of the view's root view. Sets {@code globalOffset} 19429 * to the offset of the view's x and y coordinates from the coordinate space 19430 * origin, which is the top left corner of the root view irrespective of 19431 * screen decorations and system UI elements. 19432 * 19433 * <p>To convert {@code r} to coordinates relative to the top left corner of 19434 * this view (without taking view rotations into account), offset {@code r} 19435 * by the inverse values of 19436 * {@code globalOffset}—{@code r.offset(-globalOffset.x, 19437 * -globalOffset.y)}—which is equivalent to calling 19438 * {@link #getLocalVisibleRect(Rect) getLocalVisibleRect(Rect)}. 19439 * 19440 * <p><b>Note:</b> Do not use this method to determine the size of a window 19441 * in multi-window mode; use 19442 * {@link WindowManager#getCurrentWindowMetrics()}. 19443 * 19444 * @param r If the method returns true, contains the coordinates of the 19445 * visible portion of this view in the coordinate space of the view's 19446 * root view. If the method returns false, the contents of {@code r} 19447 * are undefined. 19448 * @param globalOffset If the method returns true, contains the offset of 19449 * the x and y coordinates of this view from the top left corner of the 19450 * view's root view. If the method returns false, the contents of 19451 * {@code globalOffset} are undefined. The argument can be null (see 19452 * {@link #getGlobalVisibleRect(Rect) getGlobalVisibleRect(Rect)}. 19453 * @return true if at least part of the view is visible within the root 19454 * view; false if the view is completely clipped or translated out of 19455 * the visible area of the root view. 19456 * 19457 * @see #getLocalVisibleRect(Rect) 19458 */ getGlobalVisibleRect(Rect r, Point globalOffset)19459 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 19460 int width = mRight - mLeft; 19461 int height = mBottom - mTop; 19462 if (width > 0 && height > 0) { 19463 r.set(0, 0, width, height); 19464 if (globalOffset != null) { 19465 globalOffset.set(-mScrollX, -mScrollY); 19466 } 19467 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 19468 } 19469 return false; 19470 } 19471 19472 /** 19473 * Sets {@code r} to the coordinates of the non-clipped area of this view in 19474 * the coordinate space of the view's root view. 19475 * 19476 * <p>See {@link #getGlobalVisibleRect(Rect, Point) 19477 * getGlobalVisibleRect(Rect, Point)} for more information. 19478 * 19479 * @param r If the method returns true, contains the coordinates of the 19480 * visible portion of this view in the coordinate space of the view's 19481 * root view. If the method returns false, the contents of {@code r} 19482 * are undefined. 19483 * @return true if at least part of the view is visible within the root 19484 * view; otherwise false. 19485 */ getGlobalVisibleRect(Rect r)19486 public final boolean getGlobalVisibleRect(Rect r) { 19487 return getGlobalVisibleRect(r, null); 19488 } 19489 19490 /** 19491 * Sets {@code r} to the coordinates of the non-clipped area of this view 19492 * relative to the top left corner of the view. 19493 * 19494 * <p>If the view is clipped on the left or top, the left and top 19495 * coordinates are offset from 0 by the clipped amount. For example, if the 19496 * view is off screen 50px on the left and 30px at the top, the left and top 19497 * coordinates are 50 and 30 respectively. 19498 * 19499 * <p>If the view is clipped on the right or bottom, the right and bottom 19500 * coordinates are reduced by the clipped amount. For example, if the view 19501 * is off screen 40px on the right and 20px at the bottom, the right 19502 * coordinate is the view width - 40, and the bottom coordinate is the view 19503 * height - 20. 19504 * 19505 * @param r If the method returns true, contains the coordinates of the 19506 * visible portion of this view relative to the top left corner of the 19507 * view. If the method returns false, the contents of {@code r} are 19508 * undefined. 19509 * @return true if at least part of the view is visible; false if the view 19510 * is completely clipped or translated out of the visible area. 19511 * 19512 * @see #getGlobalVisibleRect(Rect, Point) 19513 */ getLocalVisibleRect(Rect r)19514 public final boolean getLocalVisibleRect(Rect r) { 19515 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 19516 if (getGlobalVisibleRect(r, offset)) { 19517 r.offset(-offset.x, -offset.y); // make r local 19518 return true; 19519 } 19520 return false; 19521 } 19522 19523 /** 19524 * Offset this view's vertical location by the specified number of pixels. 19525 * 19526 * @param offset the number of pixels to offset the view by 19527 */ offsetTopAndBottom(int offset)19528 public void offsetTopAndBottom(int offset) { 19529 if (offset != 0) { 19530 final boolean matrixIsIdentity = hasIdentityMatrix(); 19531 if (matrixIsIdentity) { 19532 if (isHardwareAccelerated()) { 19533 invalidateViewProperty(false, false); 19534 } else { 19535 final ViewParent p = mParent; 19536 if (p != null && mAttachInfo != null) { 19537 final Rect r = mAttachInfo.mTmpInvalRect; 19538 int minTop; 19539 int maxBottom; 19540 int yLoc; 19541 if (offset < 0) { 19542 minTop = mTop + offset; 19543 maxBottom = mBottom; 19544 yLoc = offset; 19545 } else { 19546 minTop = mTop; 19547 maxBottom = mBottom + offset; 19548 yLoc = 0; 19549 } 19550 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 19551 p.invalidateChild(this, r); 19552 } 19553 } 19554 } else { 19555 invalidateViewProperty(false, false); 19556 } 19557 19558 mTop += offset; 19559 mBottom += offset; 19560 mRenderNode.offsetTopAndBottom(offset); 19561 if (isHardwareAccelerated()) { 19562 invalidateViewProperty(false, false); 19563 invalidateParentIfNeededAndWasQuickRejected(); 19564 } else { 19565 if (!matrixIsIdentity) { 19566 invalidateViewProperty(false, true); 19567 } 19568 invalidateParentIfNeeded(); 19569 } 19570 notifySubtreeAccessibilityStateChangedIfNeeded(); 19571 } 19572 } 19573 19574 /** 19575 * Offset this view's horizontal location by the specified amount of pixels. 19576 * 19577 * @param offset the number of pixels to offset the view by 19578 */ offsetLeftAndRight(int offset)19579 public void offsetLeftAndRight(int offset) { 19580 if (offset != 0) { 19581 final boolean matrixIsIdentity = hasIdentityMatrix(); 19582 if (matrixIsIdentity) { 19583 if (isHardwareAccelerated()) { 19584 invalidateViewProperty(false, false); 19585 } else { 19586 final ViewParent p = mParent; 19587 if (p != null && mAttachInfo != null) { 19588 final Rect r = mAttachInfo.mTmpInvalRect; 19589 int minLeft; 19590 int maxRight; 19591 if (offset < 0) { 19592 minLeft = mLeft + offset; 19593 maxRight = mRight; 19594 } else { 19595 minLeft = mLeft; 19596 maxRight = mRight + offset; 19597 } 19598 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 19599 p.invalidateChild(this, r); 19600 } 19601 } 19602 } else { 19603 invalidateViewProperty(false, false); 19604 } 19605 19606 mLeft += offset; 19607 mRight += offset; 19608 mRenderNode.offsetLeftAndRight(offset); 19609 if (isHardwareAccelerated()) { 19610 invalidateViewProperty(false, false); 19611 invalidateParentIfNeededAndWasQuickRejected(); 19612 } else { 19613 if (!matrixIsIdentity) { 19614 invalidateViewProperty(false, true); 19615 } 19616 invalidateParentIfNeeded(); 19617 } 19618 notifySubtreeAccessibilityStateChangedIfNeeded(); 19619 } 19620 } 19621 19622 /** 19623 * Get the LayoutParams associated with this view. All views should have 19624 * layout parameters. These supply parameters to the <i>parent</i> of this 19625 * view specifying how it should be arranged. There are many subclasses of 19626 * ViewGroup.LayoutParams, and these correspond to the different subclasses 19627 * of ViewGroup that are responsible for arranging their children. 19628 * 19629 * This method may return null if this View is not attached to a parent 19630 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 19631 * was not invoked successfully. When a View is attached to a parent 19632 * ViewGroup, this method must not return null. 19633 * 19634 * @return The LayoutParams associated with this view, or null if no 19635 * parameters have been set yet 19636 */ 19637 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") getLayoutParams()19638 public ViewGroup.LayoutParams getLayoutParams() { 19639 return mLayoutParams; 19640 } 19641 19642 /** 19643 * Set the layout parameters associated with this view. These supply 19644 * parameters to the <i>parent</i> of this view specifying how it should be 19645 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 19646 * correspond to the different subclasses of ViewGroup that are responsible 19647 * for arranging their children. 19648 * 19649 * @param params The layout parameters for this view, cannot be null 19650 */ setLayoutParams(ViewGroup.LayoutParams params)19651 public void setLayoutParams(ViewGroup.LayoutParams params) { 19652 if (params == null) { 19653 throw new NullPointerException("Layout parameters cannot be null"); 19654 } 19655 mLayoutParams = params; 19656 resolveLayoutParams(); 19657 if (mParent instanceof ViewGroup) { 19658 ((ViewGroup) mParent).onSetLayoutParams(this, params); 19659 } 19660 requestLayout(); 19661 } 19662 19663 /** 19664 * Resolve the layout parameters depending on the resolved layout direction 19665 * 19666 * @hide 19667 */ resolveLayoutParams()19668 public void resolveLayoutParams() { 19669 if (mLayoutParams != null) { 19670 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 19671 } 19672 } 19673 19674 /** 19675 * Set the scrolled position of your view. This will cause a call to 19676 * {@link #onScrollChanged(int, int, int, int)} and the view will be 19677 * invalidated. 19678 * @param x the x position to scroll to 19679 * @param y the y position to scroll to 19680 */ scrollTo(int x, int y)19681 public void scrollTo(int x, int y) { 19682 if (mScrollX != x || mScrollY != y) { 19683 int oldX = mScrollX; 19684 int oldY = mScrollY; 19685 mScrollX = x; 19686 mScrollY = y; 19687 invalidateParentCaches(); 19688 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 19689 if (!awakenScrollBars()) { 19690 postInvalidateOnAnimation(); 19691 } 19692 } 19693 } 19694 19695 /** 19696 * Move the scrolled position of your view. This will cause a call to 19697 * {@link #onScrollChanged(int, int, int, int)} and the view will be 19698 * invalidated. 19699 * @param x the amount of pixels to scroll by horizontally 19700 * @param y the amount of pixels to scroll by vertically 19701 */ scrollBy(int x, int y)19702 public void scrollBy(int x, int y) { 19703 scrollTo(mScrollX + x, mScrollY + y); 19704 } 19705 19706 /** 19707 * <p>Trigger the scrollbars to draw. When invoked this method starts an 19708 * animation to fade the scrollbars out after a default delay. If a subclass 19709 * provides animated scrolling, the start delay should equal the duration 19710 * of the scrolling animation.</p> 19711 * 19712 * <p>The animation starts only if at least one of the scrollbars is 19713 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 19714 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 19715 * this method returns true, and false otherwise. If the animation is 19716 * started, this method calls {@link #invalidate()}; in that case the 19717 * caller should not call {@link #invalidate()}.</p> 19718 * 19719 * <p>This method should be invoked every time a subclass directly updates 19720 * the scroll parameters.</p> 19721 * 19722 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 19723 * and {@link #scrollTo(int, int)}.</p> 19724 * 19725 * @return true if the animation is played, false otherwise 19726 * 19727 * @see #awakenScrollBars(int) 19728 * @see #scrollBy(int, int) 19729 * @see #scrollTo(int, int) 19730 * @see #isHorizontalScrollBarEnabled() 19731 * @see #isVerticalScrollBarEnabled() 19732 * @see #setHorizontalScrollBarEnabled(boolean) 19733 * @see #setVerticalScrollBarEnabled(boolean) 19734 */ awakenScrollBars()19735 protected boolean awakenScrollBars() { 19736 return mScrollCache != null && 19737 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 19738 } 19739 19740 /** 19741 * Trigger the scrollbars to draw. 19742 * This method differs from awakenScrollBars() only in its default duration. 19743 * initialAwakenScrollBars() will show the scroll bars for longer than 19744 * usual to give the user more of a chance to notice them. 19745 * 19746 * @return true if the animation is played, false otherwise. 19747 */ initialAwakenScrollBars()19748 private boolean initialAwakenScrollBars() { 19749 return mScrollCache != null && 19750 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 19751 } 19752 19753 /** 19754 * <p> 19755 * Trigger the scrollbars to draw. When invoked this method starts an 19756 * animation to fade the scrollbars out after a fixed delay. If a subclass 19757 * provides animated scrolling, the start delay should equal the duration of 19758 * the scrolling animation. 19759 * </p> 19760 * 19761 * <p> 19762 * The animation starts only if at least one of the scrollbars is enabled, 19763 * as specified by {@link #isHorizontalScrollBarEnabled()} and 19764 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 19765 * this method returns true, and false otherwise. If the animation is 19766 * started, this method calls {@link #invalidate()}; in that case the caller 19767 * should not call {@link #invalidate()}. 19768 * </p> 19769 * 19770 * <p> 19771 * This method should be invoked every time a subclass directly updates the 19772 * scroll parameters. 19773 * </p> 19774 * 19775 * @param startDelay the delay, in milliseconds, after which the animation 19776 * should start; when the delay is 0, the animation starts 19777 * immediately 19778 * @return true if the animation is played, false otherwise 19779 * 19780 * @see #scrollBy(int, int) 19781 * @see #scrollTo(int, int) 19782 * @see #isHorizontalScrollBarEnabled() 19783 * @see #isVerticalScrollBarEnabled() 19784 * @see #setHorizontalScrollBarEnabled(boolean) 19785 * @see #setVerticalScrollBarEnabled(boolean) 19786 */ awakenScrollBars(int startDelay)19787 protected boolean awakenScrollBars(int startDelay) { 19788 return awakenScrollBars(startDelay, true); 19789 } 19790 19791 /** 19792 * <p> 19793 * Trigger the scrollbars to draw. When invoked this method starts an 19794 * animation to fade the scrollbars out after a fixed delay. If a subclass 19795 * provides animated scrolling, the start delay should equal the duration of 19796 * the scrolling animation. 19797 * </p> 19798 * 19799 * <p> 19800 * The animation starts only if at least one of the scrollbars is enabled, 19801 * as specified by {@link #isHorizontalScrollBarEnabled()} and 19802 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 19803 * this method returns true, and false otherwise. If the animation is 19804 * started, this method calls {@link #invalidate()} if the invalidate parameter 19805 * is set to true; in that case the caller 19806 * should not call {@link #invalidate()}. 19807 * </p> 19808 * 19809 * <p> 19810 * This method should be invoked every time a subclass directly updates the 19811 * scroll parameters. 19812 * </p> 19813 * 19814 * @param startDelay the delay, in milliseconds, after which the animation 19815 * should start; when the delay is 0, the animation starts 19816 * immediately 19817 * 19818 * @param invalidate Whether this method should call invalidate 19819 * 19820 * @return true if the animation is played, false otherwise 19821 * 19822 * @see #scrollBy(int, int) 19823 * @see #scrollTo(int, int) 19824 * @see #isHorizontalScrollBarEnabled() 19825 * @see #isVerticalScrollBarEnabled() 19826 * @see #setHorizontalScrollBarEnabled(boolean) 19827 * @see #setVerticalScrollBarEnabled(boolean) 19828 */ awakenScrollBars(int startDelay, boolean invalidate)19829 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 19830 final ScrollabilityCache scrollCache = mScrollCache; 19831 19832 if (scrollCache == null || !scrollCache.fadeScrollBars) { 19833 return false; 19834 } 19835 19836 if (scrollCache.scrollBar == null) { 19837 scrollCache.scrollBar = new ScrollBarDrawable(); 19838 scrollCache.scrollBar.setState(getDrawableState()); 19839 scrollCache.scrollBar.setCallback(this); 19840 } 19841 19842 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 19843 19844 if (invalidate) { 19845 // Invalidate to show the scrollbars 19846 postInvalidateOnAnimation(); 19847 } 19848 19849 if (scrollCache.state == ScrollabilityCache.OFF) { 19850 // FIXME: this is copied from WindowManagerService. 19851 // We should get this value from the system when it 19852 // is possible to do so. 19853 final int KEY_REPEAT_FIRST_DELAY = 750; 19854 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 19855 } 19856 19857 // Tell mScrollCache when we should start fading. This may 19858 // extend the fade start time if one was already scheduled 19859 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 19860 scrollCache.fadeStartTime = fadeStartTime; 19861 scrollCache.state = ScrollabilityCache.ON; 19862 19863 // Schedule our fader to run, unscheduling any old ones first 19864 if (mAttachInfo != null) { 19865 mAttachInfo.mHandler.removeCallbacks(scrollCache); 19866 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 19867 } 19868 19869 return true; 19870 } 19871 19872 return false; 19873 } 19874 19875 /** 19876 * Do not invalidate views which are not visible and which are not running an animation. They 19877 * will not get drawn and they should not set dirty flags as if they will be drawn 19878 */ skipInvalidate()19879 private boolean skipInvalidate() { 19880 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 19881 (!(mParent instanceof ViewGroup) || 19882 !((ViewGroup) mParent).isViewTransitioning(this)); 19883 } 19884 19885 /** 19886 * Mark the area defined by dirty as needing to be drawn. If the view is 19887 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 19888 * point in the future. 19889 * <p> 19890 * This must be called from a UI thread. To call from a non-UI thread, call 19891 * {@link #postInvalidate()}. 19892 * <p> 19893 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 19894 * {@code dirty}. 19895 * 19896 * @param dirty the rectangle representing the bounds of the dirty region 19897 * 19898 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 19899 * the importance of the dirty rectangle. In API 21 the given rectangle is 19900 * ignored entirely in favor of an internally-calculated area instead. 19901 * Because of this, clients are encouraged to just call {@link #invalidate()}. 19902 */ 19903 @Deprecated invalidate(Rect dirty)19904 public void invalidate(Rect dirty) { 19905 final int scrollX = mScrollX; 19906 final int scrollY = mScrollY; 19907 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 19908 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 19909 } 19910 19911 /** 19912 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 19913 * coordinates of the dirty rect are relative to the view. If the view is 19914 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 19915 * point in the future. 19916 * <p> 19917 * This must be called from a UI thread. To call from a non-UI thread, call 19918 * {@link #postInvalidate()}. 19919 * 19920 * @param l the left position of the dirty region 19921 * @param t the top position of the dirty region 19922 * @param r the right position of the dirty region 19923 * @param b the bottom position of the dirty region 19924 * 19925 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 19926 * the importance of the dirty rectangle. In API 21 the given rectangle is 19927 * ignored entirely in favor of an internally-calculated area instead. 19928 * Because of this, clients are encouraged to just call {@link #invalidate()}. 19929 */ 19930 @Deprecated invalidate(int l, int t, int r, int b)19931 public void invalidate(int l, int t, int r, int b) { 19932 final int scrollX = mScrollX; 19933 final int scrollY = mScrollY; 19934 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 19935 } 19936 19937 /** 19938 * Invalidate the whole view. If the view is visible, 19939 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 19940 * the future. 19941 * <p> 19942 * This must be called from a UI thread. To call from a non-UI thread, call 19943 * {@link #postInvalidate()}. 19944 */ invalidate()19945 public void invalidate() { 19946 invalidate(true); 19947 } 19948 19949 /** 19950 * This is where the invalidate() work actually happens. A full invalidate() 19951 * causes the drawing cache to be invalidated, but this function can be 19952 * called with invalidateCache set to false to skip that invalidation step 19953 * for cases that do not need it (for example, a component that remains at 19954 * the same dimensions with the same content). 19955 * 19956 * @param invalidateCache Whether the drawing cache for this view should be 19957 * invalidated as well. This is usually true for a full 19958 * invalidate, but may be set to false if the View's contents or 19959 * dimensions have not changed. 19960 * @hide 19961 */ 19962 @UnsupportedAppUsage invalidate(boolean invalidateCache)19963 public void invalidate(boolean invalidateCache) { 19964 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 19965 } 19966 invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate)19967 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 19968 boolean fullInvalidate) { 19969 if (mGhostView != null) { 19970 mGhostView.invalidate(true); 19971 return; 19972 } 19973 19974 if (skipInvalidate()) { 19975 return; 19976 } 19977 19978 // Reset content capture caches 19979 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; 19980 mContentCaptureSessionCached = false; 19981 19982 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 19983 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 19984 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 19985 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 19986 if (fullInvalidate) { 19987 mLastIsOpaque = isOpaque(); 19988 mPrivateFlags &= ~PFLAG_DRAWN; 19989 } 19990 19991 mPrivateFlags |= PFLAG_DIRTY; 19992 19993 if (invalidateCache) { 19994 mPrivateFlags |= PFLAG_INVALIDATED; 19995 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 19996 } 19997 19998 // Propagate the damage rectangle to the parent view. 19999 final AttachInfo ai = mAttachInfo; 20000 final ViewParent p = mParent; 20001 if (p != null && ai != null && l < r && t < b) { 20002 final Rect damage = ai.mTmpInvalRect; 20003 damage.set(l, t, r, b); 20004 p.invalidateChild(this, damage); 20005 } 20006 20007 // Damage the entire projection receiver, if necessary. 20008 if (mBackground != null && mBackground.isProjected()) { 20009 final View receiver = getProjectionReceiver(); 20010 if (receiver != null) { 20011 receiver.damageInParent(); 20012 } 20013 } 20014 } 20015 } 20016 20017 /** 20018 * @return this view's projection receiver, or {@code null} if none exists 20019 */ getProjectionReceiver()20020 private View getProjectionReceiver() { 20021 ViewParent p = getParent(); 20022 while (p != null && p instanceof View) { 20023 final View v = (View) p; 20024 if (v.isProjectionReceiver()) { 20025 return v; 20026 } 20027 p = p.getParent(); 20028 } 20029 20030 return null; 20031 } 20032 20033 /** 20034 * @return whether the view is a projection receiver 20035 */ isProjectionReceiver()20036 private boolean isProjectionReceiver() { 20037 return mBackground != null; 20038 } 20039 20040 /** 20041 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 20042 * set any flags or handle all of the cases handled by the default invalidation methods. 20043 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 20044 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 20045 * walk up the hierarchy, transforming the dirty rect as necessary. 20046 * 20047 * The method also handles normal invalidation logic if display list properties are not 20048 * being used in this view. The invalidateParent and forceRedraw flags are used by that 20049 * backup approach, to handle these cases used in the various property-setting methods. 20050 * 20051 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 20052 * are not being used in this view 20053 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 20054 * list properties are not being used in this view 20055 */ 20056 @UnsupportedAppUsage invalidateViewProperty(boolean invalidateParent, boolean forceRedraw)20057 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 20058 if (!isHardwareAccelerated() 20059 || !mRenderNode.hasDisplayList() 20060 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 20061 if (invalidateParent) { 20062 invalidateParentCaches(); 20063 } 20064 if (forceRedraw) { 20065 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 20066 } 20067 invalidate(false); 20068 } else { 20069 damageInParent(); 20070 } 20071 } 20072 20073 /** 20074 * Tells the parent view to damage this view's bounds. 20075 * 20076 * @hide 20077 */ damageInParent()20078 protected void damageInParent() { 20079 if (mParent != null && mAttachInfo != null) { 20080 mParent.onDescendantInvalidated(this, this); 20081 } 20082 } 20083 20084 /** 20085 * Used to indicate that the parent of this view should clear its caches. This functionality 20086 * is used to force the parent to rebuild its display list (when hardware-accelerated), 20087 * which is necessary when various parent-managed properties of the view change, such as 20088 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 20089 * clears the parent caches and does not causes an invalidate event. 20090 * 20091 * @hide 20092 */ 20093 @UnsupportedAppUsage invalidateParentCaches()20094 protected void invalidateParentCaches() { 20095 if (mParent instanceof View) { 20096 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 20097 } 20098 } 20099 20100 /** 20101 * Used to indicate that the parent of this view should be invalidated. This functionality 20102 * is used to force the parent to rebuild its display list (when hardware-accelerated), 20103 * which is necessary when various parent-managed properties of the view change, such as 20104 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 20105 * an invalidation event to the parent. 20106 * 20107 * @hide 20108 */ 20109 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) invalidateParentIfNeeded()20110 protected void invalidateParentIfNeeded() { 20111 if (isHardwareAccelerated() && mParent instanceof View) { 20112 ((View) mParent).invalidate(true); 20113 } 20114 } 20115 20116 /** 20117 * @hide 20118 */ invalidateParentIfNeededAndWasQuickRejected()20119 protected void invalidateParentIfNeededAndWasQuickRejected() { 20120 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 20121 // View was rejected last time it was drawn by its parent; this may have changed 20122 invalidateParentIfNeeded(); 20123 } 20124 } 20125 20126 /** 20127 * Indicates whether this View is opaque. An opaque View guarantees that it will 20128 * draw all the pixels overlapping its bounds using a fully opaque color. 20129 * 20130 * Subclasses of View should override this method whenever possible to indicate 20131 * whether an instance is opaque. Opaque Views are treated in a special way by 20132 * the View hierarchy, possibly allowing it to perform optimizations during 20133 * invalidate/draw passes. 20134 * 20135 * @return True if this View is guaranteed to be fully opaque, false otherwise. 20136 */ 20137 @ViewDebug.ExportedProperty(category = "drawing") isOpaque()20138 public boolean isOpaque() { 20139 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 20140 getFinalAlpha() >= 1.0f; 20141 } 20142 20143 /** 20144 * @hide 20145 */ 20146 @UnsupportedAppUsage computeOpaqueFlags()20147 protected void computeOpaqueFlags() { 20148 // Opaque if: 20149 // - Has a background 20150 // - Background is opaque 20151 // - Doesn't have scrollbars or scrollbars overlay 20152 20153 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 20154 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 20155 } else { 20156 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 20157 } 20158 20159 final int flags = mViewFlags; 20160 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 20161 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 20162 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 20163 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 20164 } else { 20165 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 20166 } 20167 } 20168 20169 /** 20170 * @hide 20171 */ hasOpaqueScrollbars()20172 protected boolean hasOpaqueScrollbars() { 20173 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 20174 } 20175 20176 /** 20177 * @return A handler associated with the thread running the View. This 20178 * handler can be used to pump events in the UI events queue. 20179 */ getHandler()20180 public Handler getHandler() { 20181 final AttachInfo attachInfo = mAttachInfo; 20182 if (attachInfo != null) { 20183 return attachInfo.mHandler; 20184 } 20185 return null; 20186 } 20187 20188 /** 20189 * Returns the queue of runnable for this view. 20190 * 20191 * @return the queue of runnables for this view 20192 */ getRunQueue()20193 private HandlerActionQueue getRunQueue() { 20194 if (mRunQueue == null) { 20195 mRunQueue = new HandlerActionQueue(); 20196 } 20197 return mRunQueue; 20198 } 20199 20200 /** 20201 * Gets the view root associated with the View. 20202 * @return The view root, or null if none. 20203 * @hide 20204 */ 20205 @UnsupportedAppUsage getViewRootImpl()20206 public ViewRootImpl getViewRootImpl() { 20207 if (mAttachInfo != null) { 20208 return mAttachInfo.mViewRootImpl; 20209 } 20210 return null; 20211 } 20212 20213 /** 20214 * @hide 20215 */ 20216 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getThreadedRenderer()20217 public ThreadedRenderer getThreadedRenderer() { 20218 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 20219 } 20220 20221 /** 20222 * <p>Causes the Runnable to be added to the message queue. 20223 * The runnable will be run on the user interface thread.</p> 20224 * 20225 * @param action The Runnable that will be executed. 20226 * 20227 * @return Returns true if the Runnable was successfully placed in to the 20228 * message queue. Returns false on failure, usually because the 20229 * looper processing the message queue is exiting. 20230 * 20231 * @see #postDelayed 20232 * @see #removeCallbacks 20233 */ post(Runnable action)20234 public boolean post(Runnable action) { 20235 final AttachInfo attachInfo = mAttachInfo; 20236 if (attachInfo != null) { 20237 return attachInfo.mHandler.post(action); 20238 } 20239 20240 // Postpone the runnable until we know on which thread it needs to run. 20241 // Assume that the runnable will be successfully placed after attach. 20242 getRunQueue().post(action); 20243 return true; 20244 } 20245 20246 /** 20247 * <p>Causes the Runnable to be added to the message queue, to be run 20248 * after the specified amount of time elapses. 20249 * The runnable will be run on the user interface thread.</p> 20250 * 20251 * @param action The Runnable that will be executed. 20252 * @param delayMillis The delay (in milliseconds) until the Runnable 20253 * will be executed. 20254 * 20255 * @return true if the Runnable was successfully placed in to the 20256 * message queue. Returns false on failure, usually because the 20257 * looper processing the message queue is exiting. Note that a 20258 * result of true does not mean the Runnable will be processed -- 20259 * if the looper is quit before the delivery time of the message 20260 * occurs then the message will be dropped. 20261 * 20262 * @see #post 20263 * @see #removeCallbacks 20264 */ postDelayed(Runnable action, long delayMillis)20265 public boolean postDelayed(Runnable action, long delayMillis) { 20266 final AttachInfo attachInfo = mAttachInfo; 20267 if (attachInfo != null) { 20268 return attachInfo.mHandler.postDelayed(action, delayMillis); 20269 } 20270 20271 // Postpone the runnable until we know on which thread it needs to run. 20272 // Assume that the runnable will be successfully placed after attach. 20273 getRunQueue().postDelayed(action, delayMillis); 20274 return true; 20275 } 20276 20277 /** 20278 * <p>Causes the Runnable to execute on the next animation time step. 20279 * The runnable will be run on the user interface thread.</p> 20280 * 20281 * @param action The Runnable that will be executed. 20282 * 20283 * @see #postOnAnimationDelayed 20284 * @see #removeCallbacks 20285 */ postOnAnimation(Runnable action)20286 public void postOnAnimation(Runnable action) { 20287 final AttachInfo attachInfo = mAttachInfo; 20288 if (attachInfo != null) { 20289 attachInfo.mViewRootImpl.mChoreographer.postCallback( 20290 Choreographer.CALLBACK_ANIMATION, action, null); 20291 } else { 20292 // Postpone the runnable until we know 20293 // on which thread it needs to run. 20294 getRunQueue().post(action); 20295 } 20296 } 20297 20298 /** 20299 * <p>Causes the Runnable to execute on the next animation time step, 20300 * after the specified amount of time elapses. 20301 * The runnable will be run on the user interface thread.</p> 20302 * 20303 * @param action The Runnable that will be executed. 20304 * @param delayMillis The delay (in milliseconds) until the Runnable 20305 * will be executed. 20306 * 20307 * @see #postOnAnimation 20308 * @see #removeCallbacks 20309 */ postOnAnimationDelayed(Runnable action, long delayMillis)20310 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 20311 final AttachInfo attachInfo = mAttachInfo; 20312 if (attachInfo != null) { 20313 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 20314 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 20315 } else { 20316 // Postpone the runnable until we know 20317 // on which thread it needs to run. 20318 getRunQueue().postDelayed(action, delayMillis); 20319 } 20320 } 20321 20322 /** 20323 * <p>Removes the specified Runnable from the message queue.</p> 20324 * 20325 * @param action The Runnable to remove from the message handling queue 20326 * 20327 * @return true if this view could ask the Handler to remove the Runnable, 20328 * false otherwise. When the returned value is true, the Runnable 20329 * may or may not have been actually removed from the message queue 20330 * (for instance, if the Runnable was not in the queue already.) 20331 * 20332 * @see #post 20333 * @see #postDelayed 20334 * @see #postOnAnimation 20335 * @see #postOnAnimationDelayed 20336 */ removeCallbacks(Runnable action)20337 public boolean removeCallbacks(Runnable action) { 20338 if (action != null) { 20339 final AttachInfo attachInfo = mAttachInfo; 20340 if (attachInfo != null) { 20341 attachInfo.mHandler.removeCallbacks(action); 20342 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 20343 Choreographer.CALLBACK_ANIMATION, action, null); 20344 } 20345 getRunQueue().removeCallbacks(action); 20346 } 20347 return true; 20348 } 20349 20350 /** 20351 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 20352 * Use this to invalidate the View from a non-UI thread.</p> 20353 * 20354 * <p>This method can be invoked from outside of the UI thread 20355 * only when this View is attached to a window.</p> 20356 * 20357 * @see #invalidate() 20358 * @see #postInvalidateDelayed(long) 20359 */ postInvalidate()20360 public void postInvalidate() { 20361 postInvalidateDelayed(0); 20362 } 20363 20364 /** 20365 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 20366 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 20367 * 20368 * <p>This method can be invoked from outside of the UI thread 20369 * only when this View is attached to a window.</p> 20370 * 20371 * @param left The left coordinate of the rectangle to invalidate. 20372 * @param top The top coordinate of the rectangle to invalidate. 20373 * @param right The right coordinate of the rectangle to invalidate. 20374 * @param bottom The bottom coordinate of the rectangle to invalidate. 20375 * 20376 * @see #invalidate(int, int, int, int) 20377 * @see #invalidate(Rect) 20378 * @see #postInvalidateDelayed(long, int, int, int, int) 20379 */ postInvalidate(int left, int top, int right, int bottom)20380 public void postInvalidate(int left, int top, int right, int bottom) { 20381 postInvalidateDelayed(0, left, top, right, bottom); 20382 } 20383 20384 /** 20385 * <p>Cause an invalidate to happen on a subsequent cycle through the event 20386 * loop. Waits for the specified amount of time.</p> 20387 * 20388 * <p>This method can be invoked from outside of the UI thread 20389 * only when this View is attached to a window.</p> 20390 * 20391 * @param delayMilliseconds the duration in milliseconds to delay the 20392 * invalidation by 20393 * 20394 * @see #invalidate() 20395 * @see #postInvalidate() 20396 */ postInvalidateDelayed(long delayMilliseconds)20397 public void postInvalidateDelayed(long delayMilliseconds) { 20398 // We try only with the AttachInfo because there's no point in invalidating 20399 // if we are not attached to our window 20400 final AttachInfo attachInfo = mAttachInfo; 20401 if (attachInfo != null) { 20402 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 20403 } 20404 } 20405 20406 /** 20407 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 20408 * through the event loop. Waits for the specified amount of time.</p> 20409 * 20410 * <p>This method can be invoked from outside of the UI thread 20411 * only when this View is attached to a window.</p> 20412 * 20413 * @param delayMilliseconds the duration in milliseconds to delay the 20414 * invalidation by 20415 * @param left The left coordinate of the rectangle to invalidate. 20416 * @param top The top coordinate of the rectangle to invalidate. 20417 * @param right The right coordinate of the rectangle to invalidate. 20418 * @param bottom The bottom coordinate of the rectangle to invalidate. 20419 * 20420 * @see #invalidate(int, int, int, int) 20421 * @see #invalidate(Rect) 20422 * @see #postInvalidate(int, int, int, int) 20423 */ postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom)20424 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 20425 int right, int bottom) { 20426 20427 // We try only with the AttachInfo because there's no point in invalidating 20428 // if we are not attached to our window 20429 final AttachInfo attachInfo = mAttachInfo; 20430 if (attachInfo != null) { 20431 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 20432 info.target = this; 20433 info.left = left; 20434 info.top = top; 20435 info.right = right; 20436 info.bottom = bottom; 20437 20438 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 20439 } 20440 } 20441 20442 /** 20443 * <p>Cause an invalidate to happen on the next animation time step, typically the 20444 * next display frame.</p> 20445 * 20446 * <p>This method can be invoked from outside of the UI thread 20447 * only when this View is attached to a window.</p> 20448 * 20449 * @see #invalidate() 20450 */ postInvalidateOnAnimation()20451 public void postInvalidateOnAnimation() { 20452 // We try only with the AttachInfo because there's no point in invalidating 20453 // if we are not attached to our window 20454 final AttachInfo attachInfo = mAttachInfo; 20455 if (attachInfo != null) { 20456 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 20457 } 20458 } 20459 20460 /** 20461 * <p>Cause an invalidate of the specified area to happen on the next animation 20462 * time step, typically the next display frame.</p> 20463 * 20464 * <p>This method can be invoked from outside of the UI thread 20465 * only when this View is attached to a window.</p> 20466 * 20467 * @param left The left coordinate of the rectangle to invalidate. 20468 * @param top The top coordinate of the rectangle to invalidate. 20469 * @param right The right coordinate of the rectangle to invalidate. 20470 * @param bottom The bottom coordinate of the rectangle to invalidate. 20471 * 20472 * @see #invalidate(int, int, int, int) 20473 * @see #invalidate(Rect) 20474 */ postInvalidateOnAnimation(int left, int top, int right, int bottom)20475 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 20476 // We try only with the AttachInfo because there's no point in invalidating 20477 // if we are not attached to our window 20478 final AttachInfo attachInfo = mAttachInfo; 20479 if (attachInfo != null) { 20480 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 20481 info.target = this; 20482 info.left = left; 20483 info.top = top; 20484 info.right = right; 20485 info.bottom = bottom; 20486 20487 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 20488 } 20489 } 20490 20491 /** 20492 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 20493 * This event is sent at most once every 20494 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 20495 */ postSendViewScrolledAccessibilityEventCallback(int dx, int dy)20496 private void postSendViewScrolledAccessibilityEventCallback(int dx, int dy) { 20497 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 20498 AccessibilityEvent event = 20499 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED); 20500 event.setScrollDeltaX(dx); 20501 event.setScrollDeltaY(dy); 20502 sendAccessibilityEventUnchecked(event); 20503 } 20504 } 20505 20506 /** 20507 * Called by a parent to request that a child update its values for mScrollX 20508 * and mScrollY if necessary. This will typically be done if the child is 20509 * animating a scroll using a {@link android.widget.Scroller Scroller} 20510 * object. 20511 */ computeScroll()20512 public void computeScroll() { 20513 } 20514 20515 /** 20516 * <p>Indicate whether the horizontal edges are faded when the view is 20517 * scrolled horizontally.</p> 20518 * 20519 * @return true if the horizontal edges should are faded on scroll, false 20520 * otherwise 20521 * 20522 * @see #setHorizontalFadingEdgeEnabled(boolean) 20523 * 20524 * @attr ref android.R.styleable#View_requiresFadingEdge 20525 */ isHorizontalFadingEdgeEnabled()20526 public boolean isHorizontalFadingEdgeEnabled() { 20527 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 20528 } 20529 20530 /** 20531 * <p>Define whether the horizontal edges should be faded when this view 20532 * is scrolled horizontally.</p> 20533 * 20534 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 20535 * be faded when the view is scrolled 20536 * horizontally 20537 * 20538 * @see #isHorizontalFadingEdgeEnabled() 20539 * 20540 * @attr ref android.R.styleable#View_requiresFadingEdge 20541 */ setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled)20542 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 20543 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 20544 if (horizontalFadingEdgeEnabled) { 20545 initScrollCache(); 20546 } 20547 20548 mViewFlags ^= FADING_EDGE_HORIZONTAL; 20549 } 20550 } 20551 20552 /** 20553 * <p>Indicate whether the vertical edges are faded when the view is 20554 * scrolled horizontally.</p> 20555 * 20556 * @return true if the vertical edges should are faded on scroll, false 20557 * otherwise 20558 * 20559 * @see #setVerticalFadingEdgeEnabled(boolean) 20560 * 20561 * @attr ref android.R.styleable#View_requiresFadingEdge 20562 */ isVerticalFadingEdgeEnabled()20563 public boolean isVerticalFadingEdgeEnabled() { 20564 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 20565 } 20566 20567 /** 20568 * <p>Define whether the vertical edges should be faded when this view 20569 * is scrolled vertically.</p> 20570 * 20571 * @param verticalFadingEdgeEnabled true if the vertical edges should 20572 * be faded when the view is scrolled 20573 * vertically 20574 * 20575 * @see #isVerticalFadingEdgeEnabled() 20576 * 20577 * @attr ref android.R.styleable#View_requiresFadingEdge 20578 */ setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled)20579 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 20580 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 20581 if (verticalFadingEdgeEnabled) { 20582 initScrollCache(); 20583 } 20584 20585 mViewFlags ^= FADING_EDGE_VERTICAL; 20586 } 20587 } 20588 20589 /** 20590 * Get the fading edge flags, used for inspection. 20591 * 20592 * @return One of {@link #FADING_EDGE_NONE}, {@link #FADING_EDGE_VERTICAL}, 20593 * or {@link #FADING_EDGE_HORIZONTAL} 20594 * @hide 20595 */ 20596 @InspectableProperty(name = "requiresFadingEdge", flagMapping = { 20597 @FlagEntry(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"), 20598 @FlagEntry(target = FADING_EDGE_VERTICAL, name = "vertical"), 20599 @FlagEntry(target = FADING_EDGE_HORIZONTAL, name = "horizontal") 20600 }) getFadingEdge()20601 public int getFadingEdge() { 20602 return mViewFlags & FADING_EDGE_MASK; 20603 } 20604 20605 /** 20606 * Get the fading edge length, used for inspection 20607 * 20608 * @return The fading edge length or 0 20609 * @hide 20610 */ 20611 @InspectableProperty getFadingEdgeLength()20612 public int getFadingEdgeLength() { 20613 if (mScrollCache != null && (mViewFlags & FADING_EDGE_MASK) != FADING_EDGE_NONE) { 20614 return mScrollCache.fadingEdgeLength; 20615 } 20616 return 0; 20617 } 20618 20619 /** 20620 * Returns the strength, or intensity, of the top faded edge. The strength is 20621 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 20622 * returns 0.0 or 1.0 but no value in between. 20623 * 20624 * Subclasses should override this method to provide a smoother fade transition 20625 * when scrolling occurs. 20626 * 20627 * @return the intensity of the top fade as a float between 0.0f and 1.0f 20628 */ getTopFadingEdgeStrength()20629 protected float getTopFadingEdgeStrength() { 20630 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 20631 } 20632 20633 /** 20634 * Returns the strength, or intensity, of the bottom faded edge. The strength is 20635 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 20636 * returns 0.0 or 1.0 but no value in between. 20637 * 20638 * Subclasses should override this method to provide a smoother fade transition 20639 * when scrolling occurs. 20640 * 20641 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 20642 */ getBottomFadingEdgeStrength()20643 protected float getBottomFadingEdgeStrength() { 20644 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 20645 computeVerticalScrollRange() ? 1.0f : 0.0f; 20646 } 20647 20648 /** 20649 * Returns the strength, or intensity, of the left faded edge. The strength is 20650 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 20651 * returns 0.0 or 1.0 but no value in between. 20652 * 20653 * Subclasses should override this method to provide a smoother fade transition 20654 * when scrolling occurs. 20655 * 20656 * @return the intensity of the left fade as a float between 0.0f and 1.0f 20657 */ getLeftFadingEdgeStrength()20658 protected float getLeftFadingEdgeStrength() { 20659 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 20660 } 20661 20662 /** 20663 * Returns the strength, or intensity, of the right faded edge. The strength is 20664 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 20665 * returns 0.0 or 1.0 but no value in between. 20666 * 20667 * Subclasses should override this method to provide a smoother fade transition 20668 * when scrolling occurs. 20669 * 20670 * @return the intensity of the right fade as a float between 0.0f and 1.0f 20671 */ getRightFadingEdgeStrength()20672 protected float getRightFadingEdgeStrength() { 20673 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 20674 computeHorizontalScrollRange() ? 1.0f : 0.0f; 20675 } 20676 20677 /** 20678 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 20679 * scrollbar is not drawn by default.</p> 20680 * 20681 * @return true if the horizontal scrollbar should be painted, false 20682 * otherwise 20683 * 20684 * @see #setHorizontalScrollBarEnabled(boolean) 20685 */ isHorizontalScrollBarEnabled()20686 public boolean isHorizontalScrollBarEnabled() { 20687 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 20688 } 20689 20690 /** 20691 * <p>Define whether the horizontal scrollbar should be drawn or not. The 20692 * scrollbar is not drawn by default.</p> 20693 * 20694 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 20695 * be painted 20696 * 20697 * @see #isHorizontalScrollBarEnabled() 20698 */ setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled)20699 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 20700 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 20701 mViewFlags ^= SCROLLBARS_HORIZONTAL; 20702 computeOpaqueFlags(); 20703 resolvePadding(); 20704 } 20705 } 20706 20707 /** 20708 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 20709 * scrollbar is not drawn by default.</p> 20710 * 20711 * @return true if the vertical scrollbar should be painted, false 20712 * otherwise 20713 * 20714 * @see #setVerticalScrollBarEnabled(boolean) 20715 */ isVerticalScrollBarEnabled()20716 public boolean isVerticalScrollBarEnabled() { 20717 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 20718 } 20719 20720 /** 20721 * <p>Define whether the vertical scrollbar should be drawn or not. The 20722 * scrollbar is not drawn by default.</p> 20723 * 20724 * @param verticalScrollBarEnabled true if the vertical scrollbar should 20725 * be painted 20726 * 20727 * @see #isVerticalScrollBarEnabled() 20728 */ setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled)20729 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 20730 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 20731 mViewFlags ^= SCROLLBARS_VERTICAL; 20732 computeOpaqueFlags(); 20733 resolvePadding(); 20734 } 20735 } 20736 20737 /** 20738 * @hide 20739 */ 20740 @UnsupportedAppUsage recomputePadding()20741 protected void recomputePadding() { 20742 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 20743 } 20744 20745 /** 20746 * Define whether scrollbars will fade when the view is not scrolling. 20747 * 20748 * @param fadeScrollbars whether to enable fading 20749 * 20750 * @attr ref android.R.styleable#View_fadeScrollbars 20751 */ setScrollbarFadingEnabled(boolean fadeScrollbars)20752 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 20753 initScrollCache(); 20754 final ScrollabilityCache scrollabilityCache = mScrollCache; 20755 scrollabilityCache.fadeScrollBars = fadeScrollbars; 20756 if (fadeScrollbars) { 20757 scrollabilityCache.state = ScrollabilityCache.OFF; 20758 } else { 20759 scrollabilityCache.state = ScrollabilityCache.ON; 20760 } 20761 } 20762 20763 /** 20764 * 20765 * Returns true if scrollbars will fade when this view is not scrolling 20766 * 20767 * @return true if scrollbar fading is enabled 20768 * 20769 * @attr ref android.R.styleable#View_fadeScrollbars 20770 */ isScrollbarFadingEnabled()20771 public boolean isScrollbarFadingEnabled() { 20772 return mScrollCache != null && mScrollCache.fadeScrollBars; 20773 } 20774 20775 /** 20776 * 20777 * Returns the delay before scrollbars fade. 20778 * 20779 * @return the delay before scrollbars fade 20780 * 20781 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 20782 */ 20783 @InspectableProperty(name = "scrollbarDefaultDelayBeforeFade") getScrollBarDefaultDelayBeforeFade()20784 public int getScrollBarDefaultDelayBeforeFade() { 20785 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 20786 mScrollCache.scrollBarDefaultDelayBeforeFade; 20787 } 20788 20789 /** 20790 * Define the delay before scrollbars fade. 20791 * 20792 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 20793 * 20794 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 20795 */ setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade)20796 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 20797 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 20798 } 20799 20800 /** 20801 * 20802 * Returns the scrollbar fade duration. 20803 * 20804 * @return the scrollbar fade duration, in milliseconds 20805 * 20806 * @attr ref android.R.styleable#View_scrollbarFadeDuration 20807 */ 20808 @InspectableProperty(name = "scrollbarFadeDuration") getScrollBarFadeDuration()20809 public int getScrollBarFadeDuration() { 20810 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 20811 mScrollCache.scrollBarFadeDuration; 20812 } 20813 20814 /** 20815 * Define the scrollbar fade duration. 20816 * 20817 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 20818 * 20819 * @attr ref android.R.styleable#View_scrollbarFadeDuration 20820 */ setScrollBarFadeDuration(int scrollBarFadeDuration)20821 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 20822 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 20823 } 20824 20825 /** 20826 * 20827 * Returns the scrollbar size. 20828 * 20829 * @return the scrollbar size 20830 * 20831 * @attr ref android.R.styleable#View_scrollbarSize 20832 */ 20833 @InspectableProperty(name = "scrollbarSize") getScrollBarSize()20834 public int getScrollBarSize() { 20835 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 20836 mScrollCache.scrollBarSize; 20837 } 20838 20839 /** 20840 * Define the scrollbar size. 20841 * 20842 * @param scrollBarSize - the scrollbar size 20843 * 20844 * @attr ref android.R.styleable#View_scrollbarSize 20845 */ setScrollBarSize(int scrollBarSize)20846 public void setScrollBarSize(int scrollBarSize) { 20847 getScrollCache().scrollBarSize = scrollBarSize; 20848 } 20849 20850 /** 20851 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 20852 * inset. When inset, they add to the padding of the view. And the scrollbars 20853 * can be drawn inside the padding area or on the edge of the view. For example, 20854 * if a view has a background drawable and you want to draw the scrollbars 20855 * inside the padding specified by the drawable, you can use 20856 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 20857 * appear at the edge of the view, ignoring the padding, then you can use 20858 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 20859 * @param style the style of the scrollbars. Should be one of 20860 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 20861 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 20862 * @see #SCROLLBARS_INSIDE_OVERLAY 20863 * @see #SCROLLBARS_INSIDE_INSET 20864 * @see #SCROLLBARS_OUTSIDE_OVERLAY 20865 * @see #SCROLLBARS_OUTSIDE_INSET 20866 * 20867 * @attr ref android.R.styleable#View_scrollbarStyle 20868 */ setScrollBarStyle(@crollBarStyle int style)20869 public void setScrollBarStyle(@ScrollBarStyle int style) { 20870 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 20871 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 20872 computeOpaqueFlags(); 20873 resolvePadding(); 20874 } 20875 } 20876 20877 /** 20878 * <p>Returns the current scrollbar style.</p> 20879 * @return the current scrollbar style 20880 * @see #SCROLLBARS_INSIDE_OVERLAY 20881 * @see #SCROLLBARS_INSIDE_INSET 20882 * @see #SCROLLBARS_OUTSIDE_OVERLAY 20883 * @see #SCROLLBARS_OUTSIDE_INSET 20884 * 20885 * @attr ref android.R.styleable#View_scrollbarStyle 20886 */ 20887 @ViewDebug.ExportedProperty(mapping = { 20888 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 20889 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 20890 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 20891 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 20892 }) 20893 @InspectableProperty(name = "scrollbarStyle", enumMapping = { 20894 @EnumEntry(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"), 20895 @EnumEntry(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"), 20896 @EnumEntry(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"), 20897 @EnumEntry(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset") 20898 }) 20899 @ScrollBarStyle getScrollBarStyle()20900 public int getScrollBarStyle() { 20901 return mViewFlags & SCROLLBARS_STYLE_MASK; 20902 } 20903 20904 /** 20905 * <p>Compute the horizontal range that the horizontal scrollbar 20906 * represents.</p> 20907 * 20908 * <p>The range is expressed in arbitrary units that must be the same as the 20909 * units used by {@link #computeHorizontalScrollExtent()} and 20910 * {@link #computeHorizontalScrollOffset()}.</p> 20911 * 20912 * <p>The default range is the drawing width of this view.</p> 20913 * 20914 * @return the total horizontal range represented by the horizontal 20915 * scrollbar 20916 * 20917 * @see #computeHorizontalScrollExtent() 20918 * @see #computeHorizontalScrollOffset() 20919 */ computeHorizontalScrollRange()20920 protected int computeHorizontalScrollRange() { 20921 return getWidth(); 20922 } 20923 20924 /** 20925 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 20926 * within the horizontal range. This value is used to compute the position 20927 * of the thumb within the scrollbar's track.</p> 20928 * 20929 * <p>The range is expressed in arbitrary units that must be the same as the 20930 * units used by {@link #computeHorizontalScrollRange()} and 20931 * {@link #computeHorizontalScrollExtent()}.</p> 20932 * 20933 * <p>The default offset is the scroll offset of this view.</p> 20934 * 20935 * @return the horizontal offset of the scrollbar's thumb 20936 * 20937 * @see #computeHorizontalScrollRange() 20938 * @see #computeHorizontalScrollExtent() 20939 */ computeHorizontalScrollOffset()20940 protected int computeHorizontalScrollOffset() { 20941 return mScrollX; 20942 } 20943 20944 /** 20945 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 20946 * within the horizontal range. This value is used to compute the length 20947 * of the thumb within the scrollbar's track.</p> 20948 * 20949 * <p>The range is expressed in arbitrary units that must be the same as the 20950 * units used by {@link #computeHorizontalScrollRange()} and 20951 * {@link #computeHorizontalScrollOffset()}.</p> 20952 * 20953 * <p>The default extent is the drawing width of this view.</p> 20954 * 20955 * @return the horizontal extent of the scrollbar's thumb 20956 * 20957 * @see #computeHorizontalScrollRange() 20958 * @see #computeHorizontalScrollOffset() 20959 */ computeHorizontalScrollExtent()20960 protected int computeHorizontalScrollExtent() { 20961 return getWidth(); 20962 } 20963 20964 /** 20965 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 20966 * 20967 * <p>The range is expressed in arbitrary units that must be the same as the 20968 * units used by {@link #computeVerticalScrollExtent()} and 20969 * {@link #computeVerticalScrollOffset()}.</p> 20970 * 20971 * @return the total vertical range represented by the vertical scrollbar 20972 * 20973 * <p>The default range is the drawing height of this view.</p> 20974 * 20975 * @see #computeVerticalScrollExtent() 20976 * @see #computeVerticalScrollOffset() 20977 */ computeVerticalScrollRange()20978 protected int computeVerticalScrollRange() { 20979 return getHeight(); 20980 } 20981 20982 /** 20983 * <p>Compute the vertical offset of the vertical scrollbar's thumb 20984 * within the horizontal range. This value is used to compute the position 20985 * of the thumb within the scrollbar's track.</p> 20986 * 20987 * <p>The range is expressed in arbitrary units that must be the same as the 20988 * units used by {@link #computeVerticalScrollRange()} and 20989 * {@link #computeVerticalScrollExtent()}.</p> 20990 * 20991 * <p>The default offset is the scroll offset of this view.</p> 20992 * 20993 * @return the vertical offset of the scrollbar's thumb 20994 * 20995 * @see #computeVerticalScrollRange() 20996 * @see #computeVerticalScrollExtent() 20997 */ computeVerticalScrollOffset()20998 protected int computeVerticalScrollOffset() { 20999 return mScrollY; 21000 } 21001 21002 /** 21003 * <p>Compute the vertical extent of the vertical scrollbar's thumb 21004 * within the vertical range. This value is used to compute the length 21005 * of the thumb within the scrollbar's track.</p> 21006 * 21007 * <p>The range is expressed in arbitrary units that must be the same as the 21008 * units used by {@link #computeVerticalScrollRange()} and 21009 * {@link #computeVerticalScrollOffset()}.</p> 21010 * 21011 * <p>The default extent is the drawing height of this view.</p> 21012 * 21013 * @return the vertical extent of the scrollbar's thumb 21014 * 21015 * @see #computeVerticalScrollRange() 21016 * @see #computeVerticalScrollOffset() 21017 */ computeVerticalScrollExtent()21018 protected int computeVerticalScrollExtent() { 21019 return getHeight(); 21020 } 21021 21022 /** 21023 * Check if this view can be scrolled horizontally in a certain direction. 21024 * 21025 * <p>This is without regard to whether the view is enabled or not, or if it will scroll 21026 * in response to user input or not. 21027 * 21028 * @param direction Negative to check scrolling left, positive to check scrolling right. 21029 * @return true if this view can be scrolled in the specified direction, false otherwise. 21030 */ canScrollHorizontally(int direction)21031 public boolean canScrollHorizontally(int direction) { 21032 final int offset = computeHorizontalScrollOffset(); 21033 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 21034 if (range == 0) return false; 21035 if (direction < 0) { 21036 return offset > 0; 21037 } else { 21038 return offset < range - 1; 21039 } 21040 } 21041 21042 /** 21043 * Check if this view can be scrolled vertically in a certain direction. 21044 * 21045 * <p>This is without regard to whether the view is enabled or not, or if it will scroll 21046 * in response to user input or not. 21047 * 21048 * @param direction Negative to check scrolling up, positive to check scrolling down. 21049 * @return true if this view can be scrolled in the specified direction, false otherwise. 21050 */ canScrollVertically(int direction)21051 public boolean canScrollVertically(int direction) { 21052 final int offset = computeVerticalScrollOffset(); 21053 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 21054 if (range == 0) return false; 21055 if (direction < 0) { 21056 return offset > 0; 21057 } else { 21058 return offset < range - 1; 21059 } 21060 } 21061 getScrollIndicatorBounds(@onNull Rect out)21062 void getScrollIndicatorBounds(@NonNull Rect out) { 21063 out.left = mScrollX; 21064 out.right = mScrollX + mRight - mLeft; 21065 out.top = mScrollY; 21066 out.bottom = mScrollY + mBottom - mTop; 21067 } 21068 onDrawScrollIndicators(@onNull Canvas c)21069 private void onDrawScrollIndicators(@NonNull Canvas c) { 21070 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 21071 // No scroll indicators enabled. 21072 return; 21073 } 21074 21075 final Drawable dr = mScrollIndicatorDrawable; 21076 if (dr == null) { 21077 // Scroll indicators aren't supported here. 21078 return; 21079 } 21080 21081 if (mAttachInfo == null) { 21082 // View is not attached. 21083 return; 21084 } 21085 21086 final int h = dr.getIntrinsicHeight(); 21087 final int w = dr.getIntrinsicWidth(); 21088 final Rect rect = mAttachInfo.mTmpInvalRect; 21089 getScrollIndicatorBounds(rect); 21090 21091 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 21092 final boolean canScrollUp = canScrollVertically(-1); 21093 if (canScrollUp) { 21094 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 21095 dr.draw(c); 21096 } 21097 } 21098 21099 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 21100 final boolean canScrollDown = canScrollVertically(1); 21101 if (canScrollDown) { 21102 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 21103 dr.draw(c); 21104 } 21105 } 21106 21107 final int leftRtl; 21108 final int rightRtl; 21109 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 21110 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 21111 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 21112 } else { 21113 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 21114 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 21115 } 21116 21117 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 21118 if ((mPrivateFlags3 & leftMask) != 0) { 21119 final boolean canScrollLeft = canScrollHorizontally(-1); 21120 if (canScrollLeft) { 21121 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 21122 dr.draw(c); 21123 } 21124 } 21125 21126 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 21127 if ((mPrivateFlags3 & rightMask) != 0) { 21128 final boolean canScrollRight = canScrollHorizontally(1); 21129 if (canScrollRight) { 21130 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 21131 dr.draw(c); 21132 } 21133 } 21134 } 21135 getHorizontalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)21136 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 21137 @Nullable Rect touchBounds) { 21138 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 21139 if (bounds == null) { 21140 return; 21141 } 21142 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 21143 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 21144 && !isVerticalScrollBarHidden(); 21145 final int size = getHorizontalScrollbarHeight(); 21146 final int verticalScrollBarGap = drawVerticalScrollBar ? 21147 getVerticalScrollbarWidth() : 0; 21148 final int width = mRight - mLeft; 21149 final int height = mBottom - mTop; 21150 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 21151 bounds.left = mScrollX + (mPaddingLeft & inside); 21152 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 21153 bounds.bottom = bounds.top + size; 21154 21155 if (touchBounds == null) { 21156 return; 21157 } 21158 if (touchBounds != bounds) { 21159 touchBounds.set(bounds); 21160 } 21161 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 21162 if (touchBounds.height() < minTouchTarget) { 21163 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 21164 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 21165 touchBounds.top = touchBounds.bottom - minTouchTarget; 21166 } 21167 if (touchBounds.width() < minTouchTarget) { 21168 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 21169 touchBounds.left -= adjust; 21170 touchBounds.right = touchBounds.left + minTouchTarget; 21171 } 21172 } 21173 getVerticalScrollBarBounds(@ullable Rect bounds, @Nullable Rect touchBounds)21174 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 21175 if (mRoundScrollbarRenderer == null) { 21176 getStraightVerticalScrollBarBounds(bounds, touchBounds); 21177 } else { 21178 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds); 21179 } 21180 } 21181 getRoundVerticalScrollBarBounds(Rect bounds)21182 private void getRoundVerticalScrollBarBounds(Rect bounds) { 21183 final int width = mRight - mLeft; 21184 final int height = mBottom - mTop; 21185 // Do not take padding into account as we always want the scrollbars 21186 // to hug the screen for round wearable devices. 21187 bounds.left = mScrollX; 21188 bounds.top = mScrollY; 21189 bounds.right = bounds.left + width; 21190 bounds.bottom = mScrollY + height; 21191 } 21192 getStraightVerticalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)21193 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 21194 @Nullable Rect touchBounds) { 21195 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 21196 if (bounds == null) { 21197 return; 21198 } 21199 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 21200 final int size = getVerticalScrollbarWidth(); 21201 int verticalScrollbarPosition = mVerticalScrollbarPosition; 21202 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 21203 verticalScrollbarPosition = isLayoutRtl() ? 21204 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 21205 } 21206 final int width = mRight - mLeft; 21207 final int height = mBottom - mTop; 21208 switch (verticalScrollbarPosition) { 21209 default: 21210 case SCROLLBAR_POSITION_RIGHT: 21211 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 21212 break; 21213 case SCROLLBAR_POSITION_LEFT: 21214 bounds.left = mScrollX + (mUserPaddingLeft & inside); 21215 break; 21216 } 21217 bounds.top = mScrollY + (mPaddingTop & inside); 21218 bounds.right = bounds.left + size; 21219 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 21220 21221 if (touchBounds == null) { 21222 return; 21223 } 21224 if (touchBounds != bounds) { 21225 touchBounds.set(bounds); 21226 } 21227 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 21228 if (touchBounds.width() < minTouchTarget) { 21229 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 21230 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 21231 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 21232 touchBounds.left = touchBounds.right - minTouchTarget; 21233 } else { 21234 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 21235 touchBounds.right = touchBounds.left + minTouchTarget; 21236 } 21237 } 21238 if (touchBounds.height() < minTouchTarget) { 21239 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 21240 touchBounds.top -= adjust; 21241 touchBounds.bottom = touchBounds.top + minTouchTarget; 21242 } 21243 } 21244 21245 /** 21246 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 21247 * scrollbars are painted only if they have been awakened first.</p> 21248 * 21249 * @param canvas the canvas on which to draw the scrollbars 21250 * 21251 * @see #awakenScrollBars(int) 21252 */ onDrawScrollBars(@onNull Canvas canvas)21253 protected final void onDrawScrollBars(@NonNull Canvas canvas) { 21254 // scrollbars are drawn only when the animation is running 21255 final ScrollabilityCache cache = mScrollCache; 21256 21257 if (cache != null) { 21258 21259 int state = cache.state; 21260 21261 if (state == ScrollabilityCache.OFF) { 21262 return; 21263 } 21264 21265 boolean invalidate = false; 21266 21267 if (state == ScrollabilityCache.FADING) { 21268 // We're fading -- get our fade interpolation 21269 if (cache.interpolatorValues == null) { 21270 cache.interpolatorValues = new float[1]; 21271 } 21272 21273 float[] values = cache.interpolatorValues; 21274 21275 // Stops the animation if we're done 21276 if (cache.scrollBarInterpolator.timeToValues(values) == 21277 Interpolator.Result.FREEZE_END) { 21278 cache.state = ScrollabilityCache.OFF; 21279 } else { 21280 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 21281 } 21282 21283 // This will make the scroll bars inval themselves after 21284 // drawing. We only want this when we're fading so that 21285 // we prevent excessive redraws 21286 invalidate = true; 21287 } else { 21288 // We're just on -- but we may have been fading before so 21289 // reset alpha 21290 cache.scrollBar.mutate().setAlpha(255); 21291 } 21292 21293 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 21294 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 21295 && !isVerticalScrollBarHidden(); 21296 21297 // Fork out the scroll bar drawing for round wearable devices. 21298 if (mRoundScrollbarRenderer != null) { 21299 if (drawVerticalScrollBar) { 21300 final Rect bounds = cache.mScrollBarBounds; 21301 getVerticalScrollBarBounds(bounds, null); 21302 mRoundScrollbarRenderer.drawRoundScrollbars( 21303 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 21304 if (invalidate) { 21305 invalidate(); 21306 } 21307 } 21308 // Do not draw horizontal scroll bars for round wearable devices. 21309 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 21310 final ScrollBarDrawable scrollBar = cache.scrollBar; 21311 21312 if (drawHorizontalScrollBar) { 21313 scrollBar.setParameters(computeHorizontalScrollRange(), 21314 computeHorizontalScrollOffset(), 21315 computeHorizontalScrollExtent(), false); 21316 final Rect bounds = cache.mScrollBarBounds; 21317 getHorizontalScrollBarBounds(bounds, null); 21318 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 21319 bounds.right, bounds.bottom); 21320 if (invalidate) { 21321 invalidate(bounds); 21322 } 21323 } 21324 21325 if (drawVerticalScrollBar) { 21326 scrollBar.setParameters(computeVerticalScrollRange(), 21327 computeVerticalScrollOffset(), 21328 computeVerticalScrollExtent(), true); 21329 final Rect bounds = cache.mScrollBarBounds; 21330 getVerticalScrollBarBounds(bounds, null); 21331 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 21332 bounds.right, bounds.bottom); 21333 if (invalidate) { 21334 invalidate(bounds); 21335 } 21336 } 21337 } 21338 } 21339 } 21340 21341 /** 21342 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 21343 * FastScroller is visible. 21344 * @return whether to temporarily hide the vertical scrollbar 21345 * @hide 21346 */ isVerticalScrollBarHidden()21347 protected boolean isVerticalScrollBarHidden() { 21348 return false; 21349 } 21350 21351 /** 21352 * <p>Draw the horizontal scrollbar if 21353 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 21354 * 21355 * @param canvas the canvas on which to draw the scrollbar 21356 * @param scrollBar the scrollbar's drawable 21357 * 21358 * @see #isHorizontalScrollBarEnabled() 21359 * @see #computeHorizontalScrollRange() 21360 * @see #computeHorizontalScrollExtent() 21361 * @see #computeHorizontalScrollOffset() 21362 * @hide 21363 */ 21364 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onDrawHorizontalScrollBar(@onNull Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)21365 protected void onDrawHorizontalScrollBar(@NonNull Canvas canvas, Drawable scrollBar, 21366 int l, int t, int r, int b) { 21367 scrollBar.setBounds(l, t, r, b); 21368 scrollBar.draw(canvas); 21369 } 21370 21371 /** 21372 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 21373 * returns true.</p> 21374 * 21375 * @param canvas the canvas on which to draw the scrollbar 21376 * @param scrollBar the scrollbar's drawable 21377 * 21378 * @see #isVerticalScrollBarEnabled() 21379 * @see #computeVerticalScrollRange() 21380 * @see #computeVerticalScrollExtent() 21381 * @see #computeVerticalScrollOffset() 21382 * @hide 21383 */ 21384 @UnsupportedAppUsage onDrawVerticalScrollBar(@onNull Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)21385 protected void onDrawVerticalScrollBar(@NonNull Canvas canvas, Drawable scrollBar, 21386 int l, int t, int r, int b) { 21387 scrollBar.setBounds(l, t, r, b); 21388 scrollBar.draw(canvas); 21389 } 21390 21391 /** 21392 * Implement this to do your drawing. 21393 * 21394 * @param canvas the canvas on which the background will be drawn 21395 */ onDraw(@onNull Canvas canvas)21396 protected void onDraw(@NonNull Canvas canvas) { 21397 } 21398 21399 /* 21400 * Caller is responsible for calling requestLayout if necessary. 21401 * (This allows addViewInLayout to not request a new layout.) 21402 */ 21403 @UnsupportedAppUsage assignParent(ViewParent parent)21404 void assignParent(ViewParent parent) { 21405 if (mParent == null) { 21406 mParent = parent; 21407 } else if (parent == null) { 21408 mParent = null; 21409 } else { 21410 throw new RuntimeException("view " + this + " being added, but" 21411 + " it already has a parent"); 21412 } 21413 } 21414 21415 /** 21416 * This is called when the view is attached to a window. At this point it 21417 * has a Surface and will start drawing. Note that this function is 21418 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 21419 * however it may be called any time before the first onDraw -- including 21420 * before or after {@link #onMeasure(int, int)}. 21421 * 21422 * @see #onDetachedFromWindow() 21423 */ 21424 @CallSuper onAttachedToWindow()21425 protected void onAttachedToWindow() { 21426 if (mParent != null && (mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 21427 mParent.requestTransparentRegion(this); 21428 } 21429 21430 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 21431 21432 jumpDrawablesToCurrentState(); 21433 21434 AccessibilityNodeIdManager.getInstance().registerViewWithId(this, getAccessibilityViewId()); 21435 resetSubtreeAccessibilityStateChanged(); 21436 21437 // rebuild, since Outline not maintained while View is detached 21438 rebuildOutline(); 21439 21440 if (isFocused()) { 21441 notifyFocusChangeToImeFocusController(true /* hasFocus */); 21442 } 21443 21444 if (sTraceLayoutSteps) { 21445 setTraversalTracingEnabled(true); 21446 } 21447 if (sTraceRequestLayoutClass != null 21448 && sTraceRequestLayoutClass.equals(getClass().getSimpleName())) { 21449 setRelayoutTracingEnabled(true); 21450 } 21451 } 21452 21453 /** 21454 * Resolve all RTL related properties. 21455 * 21456 * @return true if resolution of RTL properties has been done 21457 * 21458 * @hide 21459 */ resolveRtlPropertiesIfNeeded()21460 public boolean resolveRtlPropertiesIfNeeded() { 21461 if (!needRtlPropertiesResolution()) return false; 21462 21463 // Order is important here: LayoutDirection MUST be resolved first 21464 if (!isLayoutDirectionResolved()) { 21465 resolveLayoutDirection(); 21466 resolveLayoutParams(); 21467 } 21468 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 21469 if (!isTextDirectionResolved()) { 21470 resolveTextDirection(); 21471 } 21472 if (!isTextAlignmentResolved()) { 21473 resolveTextAlignment(); 21474 } 21475 // Should resolve Drawables before Padding because we need the layout direction of the 21476 // Drawable to correctly resolve Padding. 21477 if (!areDrawablesResolved()) { 21478 resolveDrawables(); 21479 } 21480 if (!isPaddingResolved()) { 21481 resolvePadding(); 21482 } 21483 onRtlPropertiesChanged(getLayoutDirection()); 21484 return true; 21485 } 21486 21487 /** 21488 * Reset resolution of all RTL related properties. 21489 * 21490 * @hide 21491 */ 21492 @TestApi resetRtlProperties()21493 public void resetRtlProperties() { 21494 resetResolvedLayoutDirection(); 21495 resetResolvedTextDirection(); 21496 resetResolvedTextAlignment(); 21497 resetResolvedPadding(); 21498 resetResolvedDrawables(); 21499 } 21500 21501 /** 21502 * @see #onScreenStateChanged(int) 21503 */ dispatchScreenStateChanged(int screenState)21504 void dispatchScreenStateChanged(int screenState) { 21505 onScreenStateChanged(screenState); 21506 } 21507 21508 /** 21509 * This method is called whenever the state of the screen this view is 21510 * attached to changes. A state change will usually occurs when the screen 21511 * turns on or off (whether it happens automatically or the user does it 21512 * manually.) 21513 * 21514 * @param screenState The new state of the screen. Can be either 21515 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 21516 */ onScreenStateChanged(int screenState)21517 public void onScreenStateChanged(int screenState) { 21518 } 21519 21520 /** 21521 * @see #onMovedToDisplay(int, Configuration) 21522 */ dispatchMovedToDisplay(Display display, Configuration config)21523 void dispatchMovedToDisplay(Display display, Configuration config) { 21524 mAttachInfo.mDisplay = display; 21525 mAttachInfo.mDisplayState = display.getState(); 21526 onMovedToDisplay(display.getDisplayId(), config); 21527 } 21528 21529 /** 21530 * Called by the system when the hosting activity is moved from one display to another without 21531 * recreation. This means that the activity is declared to handle all changes to configuration 21532 * that happened when it was switched to another display, so it wasn't destroyed and created 21533 * again. 21534 * 21535 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 21536 * applied configuration actually changed. It is up to app developer to choose whether to handle 21537 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)} 21538 * call. 21539 * 21540 * <p>Use this callback to track changes to the displays if some functionality relies on an 21541 * association with some display properties. 21542 * 21543 * @param displayId The id of the display to which the view was moved. 21544 * @param config Configuration of the resources on new display after move. 21545 * 21546 * @see #onConfigurationChanged(Configuration) 21547 * @hide 21548 */ onMovedToDisplay(int displayId, Configuration config)21549 public void onMovedToDisplay(int displayId, Configuration config) { 21550 } 21551 21552 /** 21553 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 21554 */ 21555 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) hasRtlSupport()21556 private boolean hasRtlSupport() { 21557 return mContext.getApplicationInfo().hasRtlSupport(); 21558 } 21559 21560 /** 21561 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 21562 * RTL not supported) 21563 */ isRtlCompatibilityMode()21564 private boolean isRtlCompatibilityMode() { 21565 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 21566 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport(); 21567 } 21568 21569 /** 21570 * @return true if RTL properties need resolution. 21571 * 21572 */ needRtlPropertiesResolution()21573 private boolean needRtlPropertiesResolution() { 21574 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 21575 } 21576 21577 /** 21578 * Called when any RTL property (layout direction or text direction or text alignment) has 21579 * been changed. 21580 * 21581 * Subclasses need to override this method to take care of cached information that depends on the 21582 * resolved layout direction, or to inform child views that inherit their layout direction. 21583 * 21584 * The default implementation does nothing. 21585 * 21586 * @param layoutDirection the direction of the layout 21587 * 21588 * @see #LAYOUT_DIRECTION_LTR 21589 * @see #LAYOUT_DIRECTION_RTL 21590 */ onRtlPropertiesChanged(@esolvedLayoutDir int layoutDirection)21591 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 21592 } 21593 21594 /** 21595 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 21596 * that the parent directionality can and will be resolved before its children. 21597 * 21598 * @return true if resolution has been done, false otherwise. 21599 * 21600 * @hide 21601 */ resolveLayoutDirection()21602 public boolean resolveLayoutDirection() { 21603 // Clear any previous layout direction resolution 21604 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 21605 21606 if (hasRtlSupport()) { 21607 // Set resolved depending on layout direction 21608 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 21609 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 21610 case LAYOUT_DIRECTION_INHERIT: 21611 // We cannot resolve yet. LTR is by default and let the resolution happen again 21612 // later to get the correct resolved value 21613 if (!canResolveLayoutDirection()) return false; 21614 21615 // Parent has not yet resolved, LTR is still the default 21616 try { 21617 if (!mParent.isLayoutDirectionResolved()) return false; 21618 21619 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 21620 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 21621 } 21622 } catch (AbstractMethodError e) { 21623 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 21624 " does not fully implement ViewParent", e); 21625 } 21626 break; 21627 case LAYOUT_DIRECTION_RTL: 21628 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 21629 break; 21630 case LAYOUT_DIRECTION_LOCALE: 21631 if((LAYOUT_DIRECTION_RTL == 21632 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 21633 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 21634 } 21635 break; 21636 default: 21637 // Nothing to do, LTR by default 21638 } 21639 } 21640 21641 // Set to resolved 21642 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 21643 return true; 21644 } 21645 21646 /** 21647 * Check if layout direction resolution can be done. 21648 * 21649 * @return true if layout direction resolution can be done otherwise return false. 21650 */ canResolveLayoutDirection()21651 public boolean canResolveLayoutDirection() { 21652 switch (getRawLayoutDirection()) { 21653 case LAYOUT_DIRECTION_INHERIT: 21654 if (mParent != null) { 21655 try { 21656 return mParent.canResolveLayoutDirection(); 21657 } catch (AbstractMethodError e) { 21658 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 21659 " does not fully implement ViewParent", e); 21660 } 21661 } 21662 return false; 21663 21664 default: 21665 return true; 21666 } 21667 } 21668 21669 /** 21670 * Reset the resolved layout direction. Layout direction will be resolved during a call to 21671 * {@link #onMeasure(int, int)}. 21672 * 21673 * @hide 21674 */ 21675 @TestApi resetResolvedLayoutDirection()21676 public void resetResolvedLayoutDirection() { 21677 // Reset the current resolved bits 21678 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 21679 } 21680 21681 /** 21682 * @return true if the layout direction is inherited. 21683 * 21684 * @hide 21685 */ isLayoutDirectionInherited()21686 public boolean isLayoutDirectionInherited() { 21687 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 21688 } 21689 21690 /** 21691 * @return true if layout direction has been resolved. 21692 */ isLayoutDirectionResolved()21693 public boolean isLayoutDirectionResolved() { 21694 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 21695 } 21696 21697 /** 21698 * Return if padding has been resolved 21699 * 21700 * @hide 21701 */ 21702 @UnsupportedAppUsage isPaddingResolved()21703 boolean isPaddingResolved() { 21704 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 21705 } 21706 21707 /** 21708 * Resolves padding depending on layout direction, if applicable, and 21709 * recomputes internal padding values to adjust for scroll bars. 21710 * 21711 * @hide 21712 */ 21713 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resolvePadding()21714 public void resolvePadding() { 21715 final int resolvedLayoutDirection = getLayoutDirection(); 21716 21717 if (!isRtlCompatibilityMode()) { 21718 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 21719 // If start / end padding are defined, they will be resolved (hence overriding) to 21720 // left / right or right / left depending on the resolved layout direction. 21721 // If start / end padding are not defined, use the left / right ones. 21722 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 21723 Rect padding = sThreadLocal.get(); 21724 if (padding == null) { 21725 padding = new Rect(); 21726 sThreadLocal.set(padding); 21727 } 21728 mBackground.getPadding(padding); 21729 if (!mLeftPaddingDefined) { 21730 mUserPaddingLeftInitial = padding.left; 21731 } 21732 if (!mRightPaddingDefined) { 21733 mUserPaddingRightInitial = padding.right; 21734 } 21735 } 21736 switch (resolvedLayoutDirection) { 21737 case LAYOUT_DIRECTION_RTL: 21738 if (mUserPaddingStart != UNDEFINED_PADDING) { 21739 mUserPaddingRight = mUserPaddingStart; 21740 } else { 21741 mUserPaddingRight = mUserPaddingRightInitial; 21742 } 21743 if (mUserPaddingEnd != UNDEFINED_PADDING) { 21744 mUserPaddingLeft = mUserPaddingEnd; 21745 } else { 21746 mUserPaddingLeft = mUserPaddingLeftInitial; 21747 } 21748 break; 21749 case LAYOUT_DIRECTION_LTR: 21750 default: 21751 if (mUserPaddingStart != UNDEFINED_PADDING) { 21752 mUserPaddingLeft = mUserPaddingStart; 21753 } else { 21754 mUserPaddingLeft = mUserPaddingLeftInitial; 21755 } 21756 if (mUserPaddingEnd != UNDEFINED_PADDING) { 21757 mUserPaddingRight = mUserPaddingEnd; 21758 } else { 21759 mUserPaddingRight = mUserPaddingRightInitial; 21760 } 21761 } 21762 21763 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 21764 } 21765 21766 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 21767 onRtlPropertiesChanged(resolvedLayoutDirection); 21768 21769 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 21770 } 21771 21772 /** 21773 * Reset the resolved layout direction. 21774 * 21775 * @hide 21776 */ 21777 @TestApi resetResolvedPadding()21778 public void resetResolvedPadding() { 21779 resetResolvedPaddingInternal(); 21780 } 21781 21782 /** 21783 * Used when we only want to reset *this* view's padding and not trigger overrides 21784 * in ViewGroup that reset children too. 21785 */ resetResolvedPaddingInternal()21786 void resetResolvedPaddingInternal() { 21787 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 21788 } 21789 21790 /** 21791 * This is called when the view is detached from a window. At this point it 21792 * no longer has a surface for drawing. 21793 * 21794 * @see #onAttachedToWindow() 21795 */ 21796 @CallSuper onDetachedFromWindow()21797 protected void onDetachedFromWindow() { 21798 } 21799 21800 /** 21801 * This is a framework-internal mirror of onDetachedFromWindow() that's called 21802 * after onDetachedFromWindow(). 21803 * 21804 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 21805 * The super method should be called at the end of the overridden method to ensure 21806 * subclasses are destroyed first 21807 * 21808 * @hide 21809 */ 21810 @CallSuper 21811 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onDetachedFromWindowInternal()21812 protected void onDetachedFromWindowInternal() { 21813 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 21814 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 21815 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 21816 21817 removeUnsetPressCallback(); 21818 removeLongPressCallback(); 21819 removePerformClickCallback(); 21820 clearAccessibilityThrottles(); 21821 stopNestedScroll(); 21822 21823 // Anything that started animating right before detach should already 21824 // be in its final state when re-attached. 21825 jumpDrawablesToCurrentState(); 21826 21827 destroyDrawingCache(); 21828 21829 cleanupDraw(); 21830 mCurrentAnimation = null; 21831 21832 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 21833 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 21834 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 21835 hideTooltip(); 21836 } 21837 21838 AccessibilityNodeIdManager.getInstance().unregisterViewWithId(getAccessibilityViewId()); 21839 21840 if (mBackgroundRenderNode != null) { 21841 mBackgroundRenderNode.forceEndAnimators(); 21842 } 21843 mRenderNode.forceEndAnimators(); 21844 } 21845 cleanupDraw()21846 private void cleanupDraw() { 21847 resetDisplayList(); 21848 if (mAttachInfo != null) { 21849 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 21850 } 21851 } 21852 invalidateInheritedLayoutMode(int layoutModeOfRoot)21853 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 21854 } 21855 21856 /** 21857 * @return The number of times this view has been attached to a window 21858 */ getWindowAttachCount()21859 protected int getWindowAttachCount() { 21860 return mWindowAttachCount; 21861 } 21862 21863 /** 21864 * Retrieve a unique token identifying the window this view is attached to. 21865 * @return Return the window's token for use in 21866 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 21867 */ getWindowToken()21868 public IBinder getWindowToken() { 21869 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 21870 } 21871 21872 /** 21873 * Retrieve the {@link WindowId} for the window this view is 21874 * currently attached to. 21875 */ getWindowId()21876 public WindowId getWindowId() { 21877 AttachInfo ai = mAttachInfo; 21878 if (ai == null) { 21879 return null; 21880 } 21881 if (ai.mWindowId == null) { 21882 try { 21883 ai.mIWindowId = ai.mSession.getWindowId(ai.mWindowToken); 21884 if (ai.mIWindowId != null) { 21885 ai.mWindowId = new WindowId(ai.mIWindowId); 21886 } 21887 } catch (RemoteException e) { 21888 } 21889 } 21890 return ai.mWindowId; 21891 } 21892 21893 /** 21894 * Retrieve a unique token identifying the top-level "real" window of 21895 * the window that this view is attached to. That is, this is like 21896 * {@link #getWindowToken}, except if the window this view in is a panel 21897 * window (attached to another containing window), then the token of 21898 * the containing window is returned instead. 21899 * 21900 * @return Returns the associated window token, either 21901 * {@link #getWindowToken()} or the containing window's token. 21902 */ getApplicationWindowToken()21903 public IBinder getApplicationWindowToken() { 21904 AttachInfo ai = mAttachInfo; 21905 if (ai != null) { 21906 IBinder appWindowToken = ai.mPanelParentWindowToken; 21907 if (appWindowToken == null) { 21908 appWindowToken = ai.mWindowToken; 21909 } 21910 return appWindowToken; 21911 } 21912 return null; 21913 } 21914 21915 /** 21916 * Gets the logical display to which the view's window has been attached. 21917 * 21918 * @return The logical display, or null if the view is not currently attached to a window. 21919 */ getDisplay()21920 public Display getDisplay() { 21921 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 21922 } 21923 21924 /** 21925 * Retrieve private session object this view hierarchy is using to 21926 * communicate with the window manager. 21927 * @return the session object to communicate with the window manager 21928 */ 21929 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) getWindowSession()21930 /*package*/ IWindowSession getWindowSession() { 21931 return mAttachInfo != null ? mAttachInfo.mSession : null; 21932 } 21933 21934 /** 21935 * Return the window this view is currently attached to. 21936 * @hide 21937 */ getWindow()21938 protected IWindow getWindow() { 21939 return mAttachInfo != null ? mAttachInfo.mWindow : null; 21940 } 21941 21942 /** 21943 * Return the visibility value of the least visible component passed. 21944 */ combineVisibility(int vis1, int vis2)21945 int combineVisibility(int vis1, int vis2) { 21946 // This works because VISIBLE < INVISIBLE < GONE. 21947 return Math.max(vis1, vis2); 21948 } 21949 21950 private boolean mShouldFakeFocus = false; 21951 21952 /** 21953 * Fake send a focus event after attaching to window. 21954 * See {@link android.view.ViewRootImpl#dispatchCompatFakeFocus()} for details. 21955 * @hide 21956 */ fakeFocusAfterAttachingToWindow()21957 public void fakeFocusAfterAttachingToWindow() { 21958 mShouldFakeFocus = true; 21959 } 21960 21961 /** 21962 * @param info the {@link android.view.View.AttachInfo} to associated with 21963 * this view 21964 */ 21965 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchAttachedToWindow(AttachInfo info, int visibility)21966 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 21967 mAttachInfo = info; 21968 if (mOverlay != null) { 21969 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 21970 } 21971 mWindowAttachCount++; 21972 // We will need to evaluate the drawable state at least once. 21973 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 21974 if (mFloatingTreeObserver != null) { 21975 info.mTreeObserver.merge(mFloatingTreeObserver); 21976 mFloatingTreeObserver = null; 21977 } 21978 21979 registerPendingFrameMetricsObservers(); 21980 21981 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 21982 mAttachInfo.mScrollContainers.add(this); 21983 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 21984 } 21985 // Transfer all pending runnables. 21986 if (mRunQueue != null) { 21987 mRunQueue.executeActions(info.mHandler); 21988 mRunQueue = null; 21989 } 21990 performCollectViewAttributes(mAttachInfo, visibility); 21991 onAttachedToWindow(); 21992 21993 ListenerInfo li = mListenerInfo; 21994 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 21995 li != null ? li.mOnAttachStateChangeListeners : null; 21996 if (listeners != null && listeners.size() > 0) { 21997 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 21998 // perform the dispatching. The iterator is a safe guard against listeners that 21999 // could mutate the list by calling the various add/remove methods. This prevents 22000 // the array from being modified while we iterate it. 22001 for (OnAttachStateChangeListener listener : listeners) { 22002 listener.onViewAttachedToWindow(this); 22003 } 22004 } 22005 22006 int vis = info.mWindowVisibility; 22007 if (vis != GONE) { 22008 onWindowVisibilityChanged(vis); 22009 if (isShown()) { 22010 // Calling onVisibilityAggregated directly here since the subtree will also 22011 // receive dispatchAttachedToWindow and this same call 22012 onVisibilityAggregated(vis == VISIBLE); 22013 } 22014 } 22015 22016 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 22017 // As all views in the subtree will already receive dispatchAttachedToWindow 22018 // traversing the subtree again here is not desired. 22019 onVisibilityChanged(this, visibility); 22020 22021 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 22022 // If nobody has evaluated the drawable state yet, then do it now. 22023 refreshDrawableState(); 22024 } 22025 needGlobalAttributesUpdate(false); 22026 22027 notifyEnterOrExitForAutoFillIfNeeded(true); 22028 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 22029 22030 if (mShouldFakeFocus) { 22031 getViewRootImpl().dispatchCompatFakeFocus(); 22032 mShouldFakeFocus = false; 22033 } 22034 } 22035 22036 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchDetachedFromWindow()22037 void dispatchDetachedFromWindow() { 22038 AttachInfo info = mAttachInfo; 22039 if (info != null) { 22040 int vis = info.mWindowVisibility; 22041 if (vis != GONE) { 22042 onWindowVisibilityChanged(GONE); 22043 if (isShown()) { 22044 // Invoking onVisibilityAggregated directly here since the subtree 22045 // will also receive detached from window 22046 onVisibilityAggregated(false); 22047 } 22048 } 22049 } 22050 22051 onDetachedFromWindow(); 22052 onDetachedFromWindowInternal(); 22053 22054 if (info != null) { 22055 info.mViewRootImpl.getImeFocusController().onViewDetachedFromWindow(this); 22056 } 22057 22058 ListenerInfo li = mListenerInfo; 22059 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 22060 li != null ? li.mOnAttachStateChangeListeners : null; 22061 if (listeners != null && listeners.size() > 0) { 22062 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 22063 // perform the dispatching. The iterator is a safe guard against listeners that 22064 // could mutate the list by calling the various add/remove methods. This prevents 22065 // the array from being modified while we iterate it. 22066 for (OnAttachStateChangeListener listener : listeners) { 22067 listener.onViewDetachedFromWindow(this); 22068 } 22069 } 22070 22071 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 22072 mAttachInfo.mScrollContainers.remove(this); 22073 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 22074 } 22075 22076 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 22077 22078 mAttachInfo = null; 22079 if (mOverlay != null) { 22080 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 22081 } 22082 22083 notifyEnterOrExitForAutoFillIfNeeded(false); 22084 22085 if (info != null && !collectPreferKeepClearRects().isEmpty()) { 22086 info.mViewRootImpl.updateKeepClearRectsForView(this); 22087 } 22088 } 22089 22090 /** 22091 * Cancel any deferred high-level input events that were previously posted to the event queue. 22092 * 22093 * <p>Many views post high-level events such as click handlers to the event queue 22094 * to run deferred in order to preserve a desired user experience - clearing visible 22095 * pressed states before executing, etc. This method will abort any events of this nature 22096 * that are currently in flight.</p> 22097 * 22098 * <p>Custom views that generate their own high-level deferred input events should override 22099 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 22100 * 22101 * <p>This will also cancel pending input events for any child views.</p> 22102 * 22103 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 22104 * This will not impact newer events posted after this call that may occur as a result of 22105 * lower-level input events still waiting in the queue. If you are trying to prevent 22106 * double-submitted events for the duration of some sort of asynchronous transaction 22107 * you should also take other steps to protect against unexpected double inputs e.g. calling 22108 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 22109 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 22110 */ cancelPendingInputEvents()22111 public final void cancelPendingInputEvents() { 22112 dispatchCancelPendingInputEvents(); 22113 } 22114 22115 /** 22116 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 22117 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 22118 */ dispatchCancelPendingInputEvents()22119 void dispatchCancelPendingInputEvents() { 22120 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 22121 onCancelPendingInputEvents(); 22122 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 22123 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 22124 " did not call through to super.onCancelPendingInputEvents()"); 22125 } 22126 } 22127 22128 /** 22129 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 22130 * a parent view. 22131 * 22132 * <p>This method is responsible for removing any pending high-level input events that were 22133 * posted to the event queue to run later. Custom view classes that post their own deferred 22134 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 22135 * {@link android.os.Handler} should override this method, call 22136 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 22137 * </p> 22138 */ onCancelPendingInputEvents()22139 public void onCancelPendingInputEvents() { 22140 removePerformClickCallback(); 22141 cancelLongPress(); 22142 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 22143 } 22144 22145 /** 22146 * Store this view hierarchy's frozen state into the given container. 22147 * 22148 * @param container The SparseArray in which to save the view's state. 22149 * 22150 * @see #restoreHierarchyState(android.util.SparseArray) 22151 * @see #dispatchSaveInstanceState(android.util.SparseArray) 22152 * @see #onSaveInstanceState() 22153 */ saveHierarchyState(SparseArray<Parcelable> container)22154 public void saveHierarchyState(SparseArray<Parcelable> container) { 22155 dispatchSaveInstanceState(container); 22156 } 22157 22158 /** 22159 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 22160 * this view and its children. May be overridden to modify how freezing happens to a 22161 * view's children; for example, some views may want to not store state for their children. 22162 * 22163 * @param container The SparseArray in which to save the view's state. 22164 * 22165 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 22166 * @see #saveHierarchyState(android.util.SparseArray) 22167 * @see #onSaveInstanceState() 22168 */ dispatchSaveInstanceState(SparseArray<Parcelable> container)22169 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 22170 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 22171 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 22172 Parcelable state = onSaveInstanceState(); 22173 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 22174 throw new IllegalStateException( 22175 "Derived class did not call super.onSaveInstanceState()"); 22176 } 22177 if (state != null) { 22178 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 22179 // + ": " + state); 22180 container.put(mID, state); 22181 } 22182 } 22183 } 22184 22185 /** 22186 * Hook allowing a view to generate a representation of its internal state 22187 * that can later be used to create a new instance with that same state. 22188 * This state should only contain information that is not persistent or can 22189 * not be reconstructed later. For example, you will never store your 22190 * current position on screen because that will be computed again when a 22191 * new instance of the view is placed in its view hierarchy. 22192 * <p> 22193 * Some examples of things you may store here: the current cursor position 22194 * in a text view (but usually not the text itself since that is stored in a 22195 * content provider or other persistent storage), the currently selected 22196 * item in a list view. 22197 * 22198 * @return Returns a Parcelable object containing the view's current dynamic 22199 * state, or null if there is nothing interesting to save. 22200 * @see #onRestoreInstanceState(Parcelable) 22201 * @see #saveHierarchyState(SparseArray) 22202 * @see #dispatchSaveInstanceState(SparseArray) 22203 * @see #setSaveEnabled(boolean) 22204 */ 22205 @CallSuper onSaveInstanceState()22206 @Nullable protected Parcelable onSaveInstanceState() { 22207 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 22208 if (mStartActivityRequestWho != null || isAutofilled() 22209 || mAutofillViewId > LAST_APP_AUTOFILL_ID) { 22210 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 22211 22212 if (mStartActivityRequestWho != null) { 22213 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; 22214 } 22215 22216 if (isAutofilled()) { 22217 state.mSavedData |= BaseSavedState.IS_AUTOFILLED; 22218 } 22219 22220 if (mAutofillViewId > LAST_APP_AUTOFILL_ID) { 22221 state.mSavedData |= BaseSavedState.AUTOFILL_ID; 22222 } 22223 22224 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 22225 state.mIsAutofilled = isAutofilled(); 22226 state.mHideHighlight = hideAutofillHighlight(); 22227 state.mAutofillViewId = mAutofillViewId; 22228 return state; 22229 } 22230 return BaseSavedState.EMPTY_STATE; 22231 } 22232 22233 /** 22234 * Restore this view hierarchy's frozen state from the given container. 22235 * 22236 * @param container The SparseArray which holds previously frozen states. 22237 * 22238 * @see #saveHierarchyState(android.util.SparseArray) 22239 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 22240 * @see #onRestoreInstanceState(android.os.Parcelable) 22241 */ restoreHierarchyState(SparseArray<Parcelable> container)22242 public void restoreHierarchyState(SparseArray<Parcelable> container) { 22243 dispatchRestoreInstanceState(container); 22244 } 22245 22246 /** 22247 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 22248 * state for this view and its children. May be overridden to modify how restoring 22249 * happens to a view's children; for example, some views may want to not store state 22250 * for their children. 22251 * 22252 * @param container The SparseArray which holds previously saved state. 22253 * 22254 * @see #dispatchSaveInstanceState(android.util.SparseArray) 22255 * @see #restoreHierarchyState(android.util.SparseArray) 22256 * @see #onRestoreInstanceState(android.os.Parcelable) 22257 */ dispatchRestoreInstanceState(SparseArray<Parcelable> container)22258 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 22259 if (mID != NO_ID) { 22260 Parcelable state = container.get(mID); 22261 if (state != null) { 22262 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 22263 // + ": " + state); 22264 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 22265 onRestoreInstanceState(state); 22266 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 22267 throw new IllegalStateException( 22268 "Derived class did not call super.onRestoreInstanceState()"); 22269 } 22270 } 22271 } 22272 } 22273 22274 /** 22275 * Hook allowing a view to re-apply a representation of its internal state that had previously 22276 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 22277 * null state. 22278 * 22279 * @param state The frozen state that had previously been returned by 22280 * {@link #onSaveInstanceState}. 22281 * 22282 * @see #onSaveInstanceState() 22283 * @see #restoreHierarchyState(android.util.SparseArray) 22284 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 22285 */ 22286 @CallSuper onRestoreInstanceState(Parcelable state)22287 protected void onRestoreInstanceState(Parcelable state) { 22288 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 22289 if (state != null && !(state instanceof AbsSavedState)) { 22290 throw new IllegalArgumentException("Wrong state class, expecting View State but " 22291 + "received " + state.getClass().toString() + " instead. This usually happens " 22292 + "when two views of different type have the same id in the same hierarchy. " 22293 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 22294 + "other views do not use the same id."); 22295 } 22296 if (state != null && state instanceof BaseSavedState) { 22297 BaseSavedState baseState = (BaseSavedState) state; 22298 22299 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { 22300 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; 22301 } 22302 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { 22303 setAutofilled(baseState.mIsAutofilled, baseState.mHideHighlight); 22304 } 22305 if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) { 22306 // It can happen that views have the same view id and the restoration path will not 22307 // be able to distinguish between them. The autofill id needs to be unique though. 22308 // Hence prevent the same autofill view id from being restored multiple times. 22309 ((BaseSavedState) state).mSavedData &= ~BaseSavedState.AUTOFILL_ID; 22310 22311 if ((mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) != 0) { 22312 // Ignore when view already set it through setAutofillId(); 22313 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.DEBUG)) { 22314 Log.d(AUTOFILL_LOG_TAG, "onRestoreInstanceState(): not setting autofillId " 22315 + "to " + baseState.mAutofillViewId + " because view explicitly set" 22316 + " it to " + mAutofillId); 22317 } 22318 } else { 22319 mAutofillViewId = baseState.mAutofillViewId; 22320 mAutofillId = null; // will be set on demand by getAutofillId() 22321 } 22322 } 22323 } 22324 } 22325 22326 /** 22327 * <p>Return the time at which the drawing of the view hierarchy started.</p> 22328 * 22329 * @return the drawing start time in milliseconds 22330 */ getDrawingTime()22331 public long getDrawingTime() { 22332 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 22333 } 22334 22335 /** 22336 * <p>Enables or disables the duplication of the parent's state into this view. When 22337 * duplication is enabled, this view gets its drawable state from its parent rather 22338 * than from its own internal properties.</p> 22339 * 22340 * <p>Note: in the current implementation, setting this property to true after the 22341 * view was added to a ViewGroup might have no effect at all. This property should 22342 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 22343 * 22344 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 22345 * property is enabled, an exception will be thrown.</p> 22346 * 22347 * <p>Note: if the child view uses and updates additional states which are unknown to the 22348 * parent, these states should not be affected by this method.</p> 22349 * 22350 * @param enabled True to enable duplication of the parent's drawable state, false 22351 * to disable it. 22352 * 22353 * @see #getDrawableState() 22354 * @see #isDuplicateParentStateEnabled() 22355 */ setDuplicateParentStateEnabled(boolean enabled)22356 public void setDuplicateParentStateEnabled(boolean enabled) { 22357 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 22358 } 22359 22360 /** 22361 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 22362 * 22363 * @return True if this view's drawable state is duplicated from the parent, 22364 * false otherwise 22365 * 22366 * @see #getDrawableState() 22367 * @see #setDuplicateParentStateEnabled(boolean) 22368 */ 22369 @InspectableProperty(name = "duplicateParentState") isDuplicateParentStateEnabled()22370 public boolean isDuplicateParentStateEnabled() { 22371 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 22372 } 22373 22374 /** 22375 * <p>Specifies the type of layer backing this view. The layer can be 22376 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 22377 * {@link #LAYER_TYPE_HARDWARE}.</p> 22378 * 22379 * <p>A layer is associated with an optional {@link android.graphics.Paint} 22380 * instance that controls how the layer is composed on screen. The following 22381 * properties of the paint are taken into account when composing the layer:</p> 22382 * <ul> 22383 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 22384 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 22385 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 22386 * </ul> 22387 * 22388 * <p>If this view has an alpha value set to < 1.0 by calling 22389 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 22390 * by this view's alpha value.</p> 22391 * 22392 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 22393 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 22394 * for more information on when and how to use layers.</p> 22395 * 22396 * @param layerType The type of layer to use with this view, must be one of 22397 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 22398 * {@link #LAYER_TYPE_HARDWARE} 22399 * @param paint The paint used to compose the layer. This argument is optional 22400 * and can be null. It is ignored when the layer type is 22401 * {@link #LAYER_TYPE_NONE} 22402 * 22403 * @see #getLayerType() 22404 * @see #LAYER_TYPE_NONE 22405 * @see #LAYER_TYPE_SOFTWARE 22406 * @see #LAYER_TYPE_HARDWARE 22407 * @see #setAlpha(float) 22408 * 22409 * @attr ref android.R.styleable#View_layerType 22410 */ setLayerType(@ayerType int layerType, @Nullable Paint paint)22411 public void setLayerType(@LayerType int layerType, @Nullable Paint paint) { 22412 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 22413 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 22414 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 22415 } 22416 22417 boolean typeChanged = mRenderNode.setLayerType(layerType); 22418 22419 if (!typeChanged) { 22420 setLayerPaint(paint); 22421 return; 22422 } 22423 22424 if (layerType != LAYER_TYPE_SOFTWARE) { 22425 // Destroy any previous software drawing cache if present 22426 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 22427 // drawing cache created in View#draw when drawing to a SW canvas. 22428 destroyDrawingCache(); 22429 } 22430 22431 mLayerType = layerType; 22432 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 22433 mRenderNode.setLayerPaint(mLayerPaint); 22434 22435 // draw() behaves differently if we are on a layer, so we need to 22436 // invalidate() here 22437 invalidateParentCaches(); 22438 invalidate(true); 22439 } 22440 22441 /** 22442 * Configure the {@link android.graphics.RenderEffect} to apply to this View. 22443 * This will apply a visual effect to the results of the View before it is drawn. For example if 22444 * {@link RenderEffect#createBlurEffect(float, float, RenderEffect, Shader.TileMode)} 22445 * is provided, the contents will be drawn in a separate layer, then this layer will be blurred 22446 * when this View is drawn. 22447 * @param renderEffect to be applied to the View. Passing null clears the previously configured 22448 * {@link RenderEffect} 22449 */ setRenderEffect(@ullable RenderEffect renderEffect)22450 public void setRenderEffect(@Nullable RenderEffect renderEffect) { 22451 if (mRenderNode.setRenderEffect(renderEffect)) { 22452 invalidateViewProperty(true, true); 22453 } 22454 } 22455 22456 /** 22457 * Updates the {@link Paint} object used with the current layer (used only if the current 22458 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 22459 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 22460 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 22461 * ensure that the view gets redrawn immediately. 22462 * 22463 * <p>A layer is associated with an optional {@link android.graphics.Paint} 22464 * instance that controls how the layer is composed on screen. The following 22465 * properties of the paint are taken into account when composing the layer:</p> 22466 * <ul> 22467 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 22468 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 22469 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 22470 * </ul> 22471 * 22472 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 22473 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 22474 * 22475 * @param paint The paint used to compose the layer. This argument is optional 22476 * and can be null. It is ignored when the layer type is 22477 * {@link #LAYER_TYPE_NONE} 22478 * 22479 * @see #setLayerType(int, android.graphics.Paint) 22480 */ setLayerPaint(@ullable Paint paint)22481 public void setLayerPaint(@Nullable Paint paint) { 22482 int layerType = getLayerType(); 22483 if (layerType != LAYER_TYPE_NONE) { 22484 mLayerPaint = paint; 22485 if (layerType == LAYER_TYPE_HARDWARE) { 22486 if (mRenderNode.setLayerPaint(paint)) { 22487 invalidateViewProperty(false, false); 22488 } 22489 } else { 22490 invalidate(); 22491 } 22492 } 22493 } 22494 22495 /** 22496 * Indicates what type of layer is currently associated with this view. By default 22497 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 22498 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 22499 * for more information on the different types of layers. 22500 * 22501 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 22502 * {@link #LAYER_TYPE_HARDWARE} 22503 * 22504 * @see #setLayerType(int, android.graphics.Paint) 22505 * @see #buildLayer() 22506 * @see #LAYER_TYPE_NONE 22507 * @see #LAYER_TYPE_SOFTWARE 22508 * @see #LAYER_TYPE_HARDWARE 22509 */ 22510 @InspectableProperty(enumMapping = { 22511 @EnumEntry(value = LAYER_TYPE_NONE, name = "none"), 22512 @EnumEntry(value = LAYER_TYPE_SOFTWARE, name = "software"), 22513 @EnumEntry(value = LAYER_TYPE_HARDWARE, name = "hardware") 22514 }) 22515 @LayerType getLayerType()22516 public int getLayerType() { 22517 return mLayerType; 22518 } 22519 22520 /** 22521 * Forces this view's layer to be created and this view to be rendered 22522 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 22523 * invoking this method will have no effect. 22524 * 22525 * This method can for instance be used to render a view into its layer before 22526 * starting an animation. If this view is complex, rendering into the layer 22527 * before starting the animation will avoid skipping frames. 22528 * 22529 * @throws IllegalStateException If this view is not attached to a window 22530 * 22531 * @see #setLayerType(int, android.graphics.Paint) 22532 */ buildLayer()22533 public void buildLayer() { 22534 if (mLayerType == LAYER_TYPE_NONE) return; 22535 22536 final AttachInfo attachInfo = mAttachInfo; 22537 if (attachInfo == null) { 22538 throw new IllegalStateException("This view must be attached to a window first"); 22539 } 22540 22541 if (getWidth() == 0 || getHeight() == 0) { 22542 return; 22543 } 22544 22545 switch (mLayerType) { 22546 case LAYER_TYPE_HARDWARE: 22547 updateDisplayListIfDirty(); 22548 if (attachInfo.mThreadedRenderer != null && mRenderNode.hasDisplayList()) { 22549 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 22550 } 22551 break; 22552 case LAYER_TYPE_SOFTWARE: 22553 buildDrawingCache(true); 22554 break; 22555 } 22556 } 22557 22558 /** 22559 * Destroys all hardware rendering resources. This method is invoked 22560 * when the system needs to reclaim resources. Upon execution of this 22561 * method, you should free any OpenGL resources created by the view. 22562 * 22563 * Note: you <strong>must</strong> call 22564 * <code>super.destroyHardwareResources()</code> when overriding 22565 * this method. 22566 * 22567 * @hide 22568 */ 22569 @CallSuper 22570 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) destroyHardwareResources()22571 protected void destroyHardwareResources() { 22572 if (mOverlay != null) { 22573 mOverlay.getOverlayView().destroyHardwareResources(); 22574 } 22575 if (mGhostView != null) { 22576 mGhostView.destroyHardwareResources(); 22577 } 22578 } 22579 22580 /** 22581 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 22582 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 22583 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 22584 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 22585 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 22586 * null.</p> 22587 * 22588 * <p>Enabling the drawing cache is similar to 22589 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 22590 * acceleration is turned off. When hardware acceleration is turned on, enabling the 22591 * drawing cache has no effect on rendering because the system uses a different mechanism 22592 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 22593 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 22594 * for information on how to enable software and hardware layers.</p> 22595 * 22596 * <p>This API can be used to manually generate 22597 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 22598 * {@link #getDrawingCache()}.</p> 22599 * 22600 * @param enabled true to enable the drawing cache, false otherwise 22601 * 22602 * @see #isDrawingCacheEnabled() 22603 * @see #getDrawingCache() 22604 * @see #buildDrawingCache() 22605 * @see #setLayerType(int, android.graphics.Paint) 22606 * 22607 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22608 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22609 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22610 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22611 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22612 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22613 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22614 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22615 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22616 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22617 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22618 * reports or unit testing the {@link PixelCopy} API is recommended. 22619 */ 22620 @Deprecated setDrawingCacheEnabled(boolean enabled)22621 public void setDrawingCacheEnabled(boolean enabled) { 22622 mCachingFailed = false; 22623 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 22624 } 22625 22626 /** 22627 * <p>Indicates whether the drawing cache is enabled for this view.</p> 22628 * 22629 * @return true if the drawing cache is enabled 22630 * 22631 * @see #setDrawingCacheEnabled(boolean) 22632 * @see #getDrawingCache() 22633 * 22634 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22635 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22636 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22637 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22638 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22639 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22640 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22641 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22642 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22643 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22644 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22645 * reports or unit testing the {@link PixelCopy} API is recommended. 22646 */ 22647 @Deprecated 22648 @ViewDebug.ExportedProperty(category = "drawing") isDrawingCacheEnabled()22649 public boolean isDrawingCacheEnabled() { 22650 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 22651 } 22652 22653 /** 22654 * Debugging utility which recursively outputs the dirty state of a view and its 22655 * descendants. 22656 * 22657 * @hide 22658 */ 22659 @SuppressWarnings({"UnusedDeclaration"}) outputDirtyFlags(String indent, boolean clear, int clearMask)22660 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 22661 Log.d(VIEW_LOG_TAG, indent + this + " DIRTY(" 22662 + (mPrivateFlags & View.PFLAG_DIRTY_MASK) 22663 + ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" 22664 + (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) 22665 + ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 22666 if (clear) { 22667 mPrivateFlags &= clearMask; 22668 } 22669 if (this instanceof ViewGroup) { 22670 ViewGroup parent = (ViewGroup) this; 22671 final int count = parent.getChildCount(); 22672 for (int i = 0; i < count; i++) { 22673 final View child = parent.getChildAt(i); 22674 child.outputDirtyFlags(indent + " ", clear, clearMask); 22675 } 22676 } 22677 } 22678 22679 /** 22680 * This method is used by ViewGroup to cause its children to restore or recreate their 22681 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 22682 * to recreate its own display list, which would happen if it went through the normal 22683 * draw/dispatchDraw mechanisms. 22684 * 22685 * @hide 22686 */ dispatchGetDisplayList()22687 protected void dispatchGetDisplayList() {} 22688 22689 /** 22690 * A view that is not attached or hardware accelerated cannot create a display list. 22691 * This method checks these conditions and returns the appropriate result. 22692 * 22693 * @return true if view has the ability to create a display list, false otherwise. 22694 * 22695 * @hide 22696 */ canHaveDisplayList()22697 public boolean canHaveDisplayList() { 22698 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 22699 } 22700 22701 /** 22702 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 22703 * @hide 22704 */ 22705 @NonNull 22706 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) updateDisplayListIfDirty()22707 public RenderNode updateDisplayListIfDirty() { 22708 final RenderNode renderNode = mRenderNode; 22709 if (!canHaveDisplayList()) { 22710 // can't populate RenderNode, don't try 22711 return renderNode; 22712 } 22713 22714 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 22715 || !renderNode.hasDisplayList() 22716 || (mRecreateDisplayList)) { 22717 // Don't need to recreate the display list, just need to tell our 22718 // children to restore/recreate theirs 22719 if (renderNode.hasDisplayList() 22720 && !mRecreateDisplayList) { 22721 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 22722 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22723 dispatchGetDisplayList(); 22724 22725 return renderNode; // no work needed 22726 } 22727 22728 // If we got here, we're recreating it. Mark it as such to ensure that 22729 // we copy in child display lists into ours in drawChild() 22730 mRecreateDisplayList = true; 22731 22732 int width = mRight - mLeft; 22733 int height = mBottom - mTop; 22734 int layerType = getLayerType(); 22735 22736 // Hacky hack: Reset any stretch effects as those are applied during the draw pass 22737 // instead of being "stateful" like other RenderNode properties 22738 renderNode.clearStretch(); 22739 22740 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 22741 22742 try { 22743 if (layerType == LAYER_TYPE_SOFTWARE) { 22744 buildDrawingCache(true); 22745 Bitmap cache = getDrawingCache(true); 22746 if (cache != null) { 22747 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 22748 } 22749 } else { 22750 computeScroll(); 22751 22752 canvas.translate(-mScrollX, -mScrollY); 22753 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 22754 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22755 22756 // Fast path for layouts with no backgrounds 22757 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 22758 dispatchDraw(canvas); 22759 drawAutofilledHighlight(canvas); 22760 if (mOverlay != null && !mOverlay.isEmpty()) { 22761 mOverlay.getOverlayView().draw(canvas); 22762 } 22763 if (isShowingLayoutBounds()) { 22764 debugDrawFocus(canvas); 22765 } 22766 } else { 22767 draw(canvas); 22768 } 22769 } 22770 } finally { 22771 renderNode.endRecording(); 22772 setDisplayListProperties(renderNode); 22773 } 22774 } else { 22775 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 22776 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22777 } 22778 return renderNode; 22779 } 22780 22781 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) resetDisplayList()22782 private void resetDisplayList() { 22783 mRenderNode.discardDisplayList(); 22784 if (mBackgroundRenderNode != null) { 22785 mBackgroundRenderNode.discardDisplayList(); 22786 } 22787 } 22788 22789 /** 22790 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 22791 * 22792 * @return A non-scaled bitmap representing this view or null if cache is disabled. 22793 * 22794 * @see #getDrawingCache(boolean) 22795 * 22796 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22797 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22798 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22799 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22800 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22801 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22802 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22803 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22804 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22805 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22806 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22807 * reports or unit testing the {@link PixelCopy} API is recommended. 22808 */ 22809 @Deprecated getDrawingCache()22810 public Bitmap getDrawingCache() { 22811 return getDrawingCache(false); 22812 } 22813 22814 /** 22815 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 22816 * is null when caching is disabled. If caching is enabled and the cache is not ready, 22817 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 22818 * draw from the cache when the cache is enabled. To benefit from the cache, you must 22819 * request the drawing cache by calling this method and draw it on screen if the 22820 * returned bitmap is not null.</p> 22821 * 22822 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 22823 * this method will create a bitmap of the same size as this view. Because this bitmap 22824 * will be drawn scaled by the parent ViewGroup, the result on screen might show 22825 * scaling artifacts. To avoid such artifacts, you should call this method by setting 22826 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 22827 * size than the view. This implies that your application must be able to handle this 22828 * size.</p> 22829 * 22830 * @param autoScale Indicates whether the generated bitmap should be scaled based on 22831 * the current density of the screen when the application is in compatibility 22832 * mode. 22833 * 22834 * @return A bitmap representing this view or null if cache is disabled. 22835 * 22836 * @see #setDrawingCacheEnabled(boolean) 22837 * @see #isDrawingCacheEnabled() 22838 * @see #buildDrawingCache(boolean) 22839 * @see #destroyDrawingCache() 22840 * 22841 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22842 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22843 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22844 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22845 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22846 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22847 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22848 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22849 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22850 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22851 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22852 * reports or unit testing the {@link PixelCopy} API is recommended. 22853 */ 22854 @Deprecated getDrawingCache(boolean autoScale)22855 public Bitmap getDrawingCache(boolean autoScale) { 22856 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 22857 return null; 22858 } 22859 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 22860 buildDrawingCache(autoScale); 22861 } 22862 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 22863 } 22864 22865 /** 22866 * <p>Frees the resources used by the drawing cache. If you call 22867 * {@link #buildDrawingCache()} manually without calling 22868 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 22869 * should cleanup the cache with this method afterwards.</p> 22870 * 22871 * @see #setDrawingCacheEnabled(boolean) 22872 * @see #buildDrawingCache() 22873 * @see #getDrawingCache() 22874 * 22875 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22876 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22877 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22878 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22879 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22880 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22881 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22882 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22883 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22884 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22885 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22886 * reports or unit testing the {@link PixelCopy} API is recommended. 22887 */ 22888 @Deprecated destroyDrawingCache()22889 public void destroyDrawingCache() { 22890 if (mDrawingCache != null) { 22891 mDrawingCache.recycle(); 22892 mDrawingCache = null; 22893 } 22894 if (mUnscaledDrawingCache != null) { 22895 mUnscaledDrawingCache.recycle(); 22896 mUnscaledDrawingCache = null; 22897 } 22898 } 22899 22900 /** 22901 * Setting a solid background color for the drawing cache's bitmaps will improve 22902 * performance and memory usage. Note, though that this should only be used if this 22903 * view will always be drawn on top of a solid color. 22904 * 22905 * @param color The background color to use for the drawing cache's bitmap 22906 * 22907 * @see #setDrawingCacheEnabled(boolean) 22908 * @see #buildDrawingCache() 22909 * @see #getDrawingCache() 22910 * 22911 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22912 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22913 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22914 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22915 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22916 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22917 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22918 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22919 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22920 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22921 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22922 * reports or unit testing the {@link PixelCopy} API is recommended. 22923 */ 22924 @Deprecated setDrawingCacheBackgroundColor(@olorInt int color)22925 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 22926 if (color != mDrawingCacheBackgroundColor) { 22927 mDrawingCacheBackgroundColor = color; 22928 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 22929 } 22930 } 22931 22932 /** 22933 * @see #setDrawingCacheBackgroundColor(int) 22934 * 22935 * @return The background color to used for the drawing cache's bitmap 22936 * 22937 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22938 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22939 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22940 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22941 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22942 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22943 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22944 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22945 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22946 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22947 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22948 * reports or unit testing the {@link PixelCopy} API is recommended. 22949 */ 22950 @Deprecated 22951 @ColorInt getDrawingCacheBackgroundColor()22952 public int getDrawingCacheBackgroundColor() { 22953 return mDrawingCacheBackgroundColor; 22954 } 22955 22956 /** 22957 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 22958 * 22959 * @see #buildDrawingCache(boolean) 22960 * 22961 * @deprecated The view drawing cache was largely made obsolete with the introduction of 22962 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 22963 * layers are largely unnecessary and can easily result in a net loss in performance due to the 22964 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 22965 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 22966 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 22967 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 22968 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 22969 * software-rendered usages are discouraged and have compatibility issues with hardware-only 22970 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 22971 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 22972 * reports or unit testing the {@link PixelCopy} API is recommended. 22973 */ 22974 @Deprecated buildDrawingCache()22975 public void buildDrawingCache() { 22976 buildDrawingCache(false); 22977 } 22978 22979 /** 22980 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 22981 * 22982 * <p>If you call {@link #buildDrawingCache()} manually without calling 22983 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 22984 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 22985 * 22986 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 22987 * this method will create a bitmap of the same size as this view. Because this bitmap 22988 * will be drawn scaled by the parent ViewGroup, the result on screen might show 22989 * scaling artifacts. To avoid such artifacts, you should call this method by setting 22990 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 22991 * size than the view. This implies that your application must be able to handle this 22992 * size.</p> 22993 * 22994 * <p>You should avoid calling this method when hardware acceleration is enabled. If 22995 * you do not need the drawing cache bitmap, calling this method will increase memory 22996 * usage and cause the view to be rendered in software once, thus negatively impacting 22997 * performance.</p> 22998 * 22999 * @see #getDrawingCache() 23000 * @see #destroyDrawingCache() 23001 * 23002 * @deprecated The view drawing cache was largely made obsolete with the introduction of 23003 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 23004 * layers are largely unnecessary and can easily result in a net loss in performance due to the 23005 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 23006 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 23007 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 23008 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 23009 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 23010 * software-rendered usages are discouraged and have compatibility issues with hardware-only 23011 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 23012 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 23013 * reports or unit testing the {@link PixelCopy} API is recommended. 23014 */ 23015 @Deprecated buildDrawingCache(boolean autoScale)23016 public void buildDrawingCache(boolean autoScale) { 23017 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 23018 mDrawingCache == null : mUnscaledDrawingCache == null)) { 23019 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 23020 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 23021 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 23022 } 23023 try { 23024 buildDrawingCacheImpl(autoScale); 23025 } finally { 23026 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 23027 } 23028 } 23029 } 23030 23031 /** 23032 * private, internal implementation of buildDrawingCache, used to enable tracing 23033 */ buildDrawingCacheImpl(boolean autoScale)23034 private void buildDrawingCacheImpl(boolean autoScale) { 23035 mCachingFailed = false; 23036 23037 int width = mRight - mLeft; 23038 int height = mBottom - mTop; 23039 23040 final AttachInfo attachInfo = mAttachInfo; 23041 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 23042 23043 if (autoScale && scalingRequired) { 23044 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 23045 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 23046 } 23047 23048 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 23049 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 23050 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 23051 23052 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 23053 final long drawingCacheSize = 23054 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 23055 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 23056 if (width > 0 && height > 0) { 23057 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 23058 + " too large to fit into a software layer (or drawing cache), needs " 23059 + projectedBitmapSize + " bytes, only " 23060 + drawingCacheSize + " available"); 23061 } 23062 destroyDrawingCache(); 23063 mCachingFailed = true; 23064 return; 23065 } 23066 23067 boolean clear = true; 23068 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 23069 23070 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 23071 Bitmap.Config quality; 23072 if (!opaque) { 23073 // Never pick ARGB_4444 because it looks awful 23074 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 23075 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 23076 case DRAWING_CACHE_QUALITY_AUTO: 23077 case DRAWING_CACHE_QUALITY_LOW: 23078 case DRAWING_CACHE_QUALITY_HIGH: 23079 default: 23080 quality = Bitmap.Config.ARGB_8888; 23081 break; 23082 } 23083 } else { 23084 // Optimization for translucent windows 23085 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 23086 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 23087 } 23088 23089 // Try to cleanup memory 23090 if (bitmap != null) bitmap.recycle(); 23091 23092 try { 23093 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 23094 width, height, quality); 23095 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 23096 if (autoScale) { 23097 mDrawingCache = bitmap; 23098 } else { 23099 mUnscaledDrawingCache = bitmap; 23100 } 23101 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 23102 } catch (OutOfMemoryError e) { 23103 // If there is not enough memory to create the bitmap cache, just 23104 // ignore the issue as bitmap caches are not required to draw the 23105 // view hierarchy 23106 if (autoScale) { 23107 mDrawingCache = null; 23108 } else { 23109 mUnscaledDrawingCache = null; 23110 } 23111 mCachingFailed = true; 23112 return; 23113 } 23114 23115 clear = drawingCacheBackgroundColor != 0; 23116 } 23117 23118 Canvas canvas; 23119 if (attachInfo != null) { 23120 canvas = attachInfo.mCanvas; 23121 if (canvas == null) { 23122 canvas = new Canvas(); 23123 } 23124 canvas.setBitmap(bitmap); 23125 // Temporarily clobber the cached Canvas in case one of our children 23126 // is also using a drawing cache. Without this, the children would 23127 // steal the canvas by attaching their own bitmap to it and bad, bad 23128 // thing would happen (invisible views, corrupted drawings, etc.) 23129 attachInfo.mCanvas = null; 23130 } else { 23131 // This case should hopefully never or seldom happen 23132 canvas = new Canvas(bitmap); 23133 } 23134 23135 if (clear) { 23136 bitmap.eraseColor(drawingCacheBackgroundColor); 23137 } 23138 23139 computeScroll(); 23140 final int restoreCount = canvas.save(); 23141 23142 if (autoScale && scalingRequired) { 23143 final float scale = attachInfo.mApplicationScale; 23144 canvas.scale(scale, scale); 23145 } 23146 23147 canvas.translate(-mScrollX, -mScrollY); 23148 23149 mPrivateFlags |= PFLAG_DRAWN; 23150 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 23151 mLayerType != LAYER_TYPE_NONE) { 23152 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 23153 } 23154 23155 // Fast path for layouts with no backgrounds 23156 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 23157 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 23158 dispatchDraw(canvas); 23159 drawAutofilledHighlight(canvas); 23160 if (mOverlay != null && !mOverlay.isEmpty()) { 23161 mOverlay.getOverlayView().draw(canvas); 23162 } 23163 } else { 23164 draw(canvas); 23165 } 23166 23167 canvas.restoreToCount(restoreCount); 23168 canvas.setBitmap(null); 23169 23170 if (attachInfo != null) { 23171 // Restore the cached Canvas for our siblings 23172 attachInfo.mCanvas = canvas; 23173 } 23174 } 23175 23176 /** 23177 * Create a snapshot of the view into a bitmap. We should probably make 23178 * some form of this public, but should think about the API. 23179 * 23180 * @hide 23181 */ 23182 @UnsupportedAppUsage createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren)23183 public Bitmap createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren) { 23184 int width = mRight - mLeft; 23185 int height = mBottom - mTop; 23186 23187 final AttachInfo attachInfo = mAttachInfo; 23188 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 23189 width = (int) ((width * scale) + 0.5f); 23190 height = (int) ((height * scale) + 0.5f); 23191 23192 Canvas oldCanvas = null; 23193 try { 23194 Canvas canvas = canvasProvider.getCanvas(this, 23195 width > 0 ? width : 1, height > 0 ? height : 1); 23196 23197 if (attachInfo != null) { 23198 oldCanvas = attachInfo.mCanvas; 23199 // Temporarily clobber the cached Canvas in case one of our children 23200 // is also using a drawing cache. Without this, the children would 23201 // steal the canvas by attaching their own bitmap to it and bad, bad 23202 // things would happen (invisible views, corrupted drawings, etc.) 23203 attachInfo.mCanvas = null; 23204 } 23205 23206 computeScroll(); 23207 final int restoreCount = canvas.save(); 23208 canvas.scale(scale, scale); 23209 canvas.translate(-mScrollX, -mScrollY); 23210 23211 // Temporarily remove the dirty mask 23212 int flags = mPrivateFlags; 23213 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 23214 23215 // Fast path for layouts with no backgrounds 23216 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 23217 dispatchDraw(canvas); 23218 drawAutofilledHighlight(canvas); 23219 if (mOverlay != null && !mOverlay.isEmpty()) { 23220 mOverlay.getOverlayView().draw(canvas); 23221 } 23222 } else { 23223 draw(canvas); 23224 } 23225 23226 mPrivateFlags = flags; 23227 canvas.restoreToCount(restoreCount); 23228 return canvasProvider.createBitmap(); 23229 } finally { 23230 if (oldCanvas != null) { 23231 attachInfo.mCanvas = oldCanvas; 23232 } 23233 } 23234 } 23235 23236 /** 23237 * Indicates whether this View is currently in edit mode. A View is usually 23238 * in edit mode when displayed within a developer tool. For instance, if 23239 * this View is being drawn by a visual user interface builder, this method 23240 * should return true. 23241 * 23242 * Subclasses should check the return value of this method to provide 23243 * different behaviors if their normal behavior might interfere with the 23244 * host environment. For instance: the class spawns a thread in its 23245 * constructor, the drawing code relies on device-specific features, etc. 23246 * 23247 * This method is usually checked in the drawing code of custom widgets. 23248 * 23249 * @return True if this View is in edit mode, false otherwise. 23250 */ isInEditMode()23251 public boolean isInEditMode() { 23252 return false; 23253 } 23254 23255 /** 23256 * If the View draws content inside its padding and enables fading edges, 23257 * it needs to support padding offsets. Padding offsets are added to the 23258 * fading edges to extend the length of the fade so that it covers pixels 23259 * drawn inside the padding. 23260 * 23261 * Subclasses of this class should override this method if they need 23262 * to draw content inside the padding. 23263 * 23264 * @return True if padding offset must be applied, false otherwise. 23265 * 23266 * @see #getLeftPaddingOffset() 23267 * @see #getRightPaddingOffset() 23268 * @see #getTopPaddingOffset() 23269 * @see #getBottomPaddingOffset() 23270 * 23271 * @since CURRENT 23272 */ isPaddingOffsetRequired()23273 protected boolean isPaddingOffsetRequired() { 23274 return false; 23275 } 23276 23277 /** 23278 * Amount by which to extend the left fading region. Called only when 23279 * {@link #isPaddingOffsetRequired()} returns true. 23280 * 23281 * @return The left padding offset in pixels. 23282 * 23283 * @see #isPaddingOffsetRequired() 23284 * 23285 * @since CURRENT 23286 */ getLeftPaddingOffset()23287 protected int getLeftPaddingOffset() { 23288 return 0; 23289 } 23290 23291 /** 23292 * Amount by which to extend the right fading region. Called only when 23293 * {@link #isPaddingOffsetRequired()} returns true. 23294 * 23295 * @return The right padding offset in pixels. 23296 * 23297 * @see #isPaddingOffsetRequired() 23298 * 23299 * @since CURRENT 23300 */ getRightPaddingOffset()23301 protected int getRightPaddingOffset() { 23302 return 0; 23303 } 23304 23305 /** 23306 * Amount by which to extend the top fading region. Called only when 23307 * {@link #isPaddingOffsetRequired()} returns true. 23308 * 23309 * @return The top padding offset in pixels. 23310 * 23311 * @see #isPaddingOffsetRequired() 23312 * 23313 * @since CURRENT 23314 */ getTopPaddingOffset()23315 protected int getTopPaddingOffset() { 23316 return 0; 23317 } 23318 23319 /** 23320 * Amount by which to extend the bottom fading region. Called only when 23321 * {@link #isPaddingOffsetRequired()} returns true. 23322 * 23323 * @return The bottom padding offset in pixels. 23324 * 23325 * @see #isPaddingOffsetRequired() 23326 * 23327 * @since CURRENT 23328 */ getBottomPaddingOffset()23329 protected int getBottomPaddingOffset() { 23330 return 0; 23331 } 23332 23333 /** 23334 * @hide 23335 * @param offsetRequired 23336 */ getFadeTop(boolean offsetRequired)23337 protected int getFadeTop(boolean offsetRequired) { 23338 int top = mPaddingTop; 23339 if (offsetRequired) top += getTopPaddingOffset(); 23340 return top; 23341 } 23342 23343 /** 23344 * @hide 23345 * @param offsetRequired 23346 */ getFadeHeight(boolean offsetRequired)23347 protected int getFadeHeight(boolean offsetRequired) { 23348 int padding = mPaddingTop; 23349 if (offsetRequired) padding += getTopPaddingOffset(); 23350 return mBottom - mTop - mPaddingBottom - padding; 23351 } 23352 23353 /** 23354 * <p>Indicates whether this view is attached to a hardware accelerated 23355 * window or not.</p> 23356 * 23357 * <p>Even if this method returns true, it does not mean that every call 23358 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 23359 * accelerated {@link android.graphics.Canvas}. For instance, if this view 23360 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 23361 * window is hardware accelerated, 23362 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 23363 * return false, and this method will return true.</p> 23364 * 23365 * @return True if the view is attached to a window and the window is 23366 * hardware accelerated; false in any other case. 23367 */ 23368 @ViewDebug.ExportedProperty(category = "drawing") isHardwareAccelerated()23369 public boolean isHardwareAccelerated() { 23370 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 23371 } 23372 23373 /** 23374 * Sets a rectangular area on this view to which the view will be clipped 23375 * when it is drawn. Setting the value to null will remove the clip bounds 23376 * and the view will draw normally, using its full bounds. 23377 * 23378 * @param clipBounds The rectangular area, in the local coordinates of 23379 * this view, to which future drawing operations will be clipped. 23380 */ setClipBounds(Rect clipBounds)23381 public void setClipBounds(Rect clipBounds) { 23382 if (clipBounds == mClipBounds 23383 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 23384 return; 23385 } 23386 if (clipBounds != null) { 23387 if (mClipBounds == null) { 23388 mClipBounds = new Rect(clipBounds); 23389 } else { 23390 mClipBounds.set(clipBounds); 23391 } 23392 } else { 23393 mClipBounds = null; 23394 } 23395 mRenderNode.setClipRect(mClipBounds); 23396 invalidateViewProperty(false, false); 23397 } 23398 23399 /** 23400 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 23401 * 23402 * @return A copy of the current clip bounds if clip bounds are set, 23403 * otherwise null. 23404 */ getClipBounds()23405 public Rect getClipBounds() { 23406 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 23407 } 23408 23409 23410 /** 23411 * Populates an output rectangle with the clip bounds of the view, 23412 * returning {@code true} if successful or {@code false} if the view's 23413 * clip bounds are {@code null}. 23414 * 23415 * @param outRect rectangle in which to place the clip bounds of the view 23416 * @return {@code true} if successful or {@code false} if the view's 23417 * clip bounds are {@code null} 23418 */ getClipBounds(Rect outRect)23419 public boolean getClipBounds(Rect outRect) { 23420 if (mClipBounds != null) { 23421 outRect.set(mClipBounds); 23422 return true; 23423 } 23424 return false; 23425 } 23426 23427 /** 23428 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 23429 * case of an active Animation being run on the view. 23430 */ applyLegacyAnimation(ViewGroup parent, long drawingTime, Animation a, boolean scalingRequired)23431 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 23432 Animation a, boolean scalingRequired) { 23433 Transformation invalidationTransform; 23434 final int flags = parent.mGroupFlags; 23435 final boolean initialized = a.isInitialized(); 23436 if (!initialized) { 23437 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 23438 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 23439 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 23440 onAnimationStart(); 23441 } 23442 23443 final Transformation t = parent.getChildTransformation(); 23444 boolean more = a.getTransformation(drawingTime, t, 1f); 23445 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 23446 if (parent.mInvalidationTransformation == null) { 23447 parent.mInvalidationTransformation = new Transformation(); 23448 } 23449 invalidationTransform = parent.mInvalidationTransformation; 23450 a.getTransformation(drawingTime, invalidationTransform, 1f); 23451 } else { 23452 invalidationTransform = t; 23453 } 23454 23455 if (more) { 23456 if (!a.willChangeBounds()) { 23457 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 23458 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 23459 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 23460 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 23461 // The child need to draw an animation, potentially offscreen, so 23462 // make sure we do not cancel invalidate requests 23463 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 23464 parent.invalidate(mLeft, mTop, mRight, mBottom); 23465 } 23466 } else { 23467 if (parent.mInvalidateRegion == null) { 23468 parent.mInvalidateRegion = new RectF(); 23469 } 23470 final RectF region = parent.mInvalidateRegion; 23471 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 23472 invalidationTransform); 23473 23474 // The child need to draw an animation, potentially offscreen, so 23475 // make sure we do not cancel invalidate requests 23476 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 23477 23478 final int left = mLeft + (int) region.left; 23479 final int top = mTop + (int) region.top; 23480 parent.invalidate(left, top, left + (int) (region.width() + .5f), 23481 top + (int) (region.height() + .5f)); 23482 } 23483 } 23484 return more; 23485 } 23486 23487 /** 23488 * This method is called by getDisplayList() when a display list is recorded for a View. 23489 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 23490 */ setDisplayListProperties(RenderNode renderNode)23491 void setDisplayListProperties(RenderNode renderNode) { 23492 if (renderNode != null) { 23493 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 23494 renderNode.setClipToBounds(mParent instanceof ViewGroup 23495 && ((ViewGroup) mParent).getClipChildren()); 23496 23497 float alpha = 1; 23498 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 23499 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 23500 ViewGroup parentVG = (ViewGroup) mParent; 23501 final Transformation t = parentVG.getChildTransformation(); 23502 if (parentVG.getChildStaticTransformation(this, t)) { 23503 final int transformType = t.getTransformationType(); 23504 if (transformType != Transformation.TYPE_IDENTITY) { 23505 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 23506 alpha = t.getAlpha(); 23507 } 23508 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 23509 renderNode.setStaticMatrix(t.getMatrix()); 23510 } 23511 } 23512 } 23513 } 23514 if (mTransformationInfo != null) { 23515 alpha *= getFinalAlpha(); 23516 if (alpha < 1) { 23517 final int multipliedAlpha = (int) (255 * alpha); 23518 if (onSetAlpha(multipliedAlpha)) { 23519 alpha = 1; 23520 } 23521 } 23522 renderNode.setAlpha(alpha); 23523 } else if (alpha < 1) { 23524 renderNode.setAlpha(alpha); 23525 } 23526 } 23527 } 23528 23529 /** 23530 * If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 23531 * 23532 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 23533 * HW accelerated, it can't handle drawing RenderNodes. 23534 * 23535 * @hide 23536 */ drawsWithRenderNode(@onNull Canvas canvas)23537 protected final boolean drawsWithRenderNode(@NonNull Canvas canvas) { 23538 return mAttachInfo != null 23539 && mAttachInfo.mHardwareAccelerated 23540 && canvas.isHardwareAccelerated(); 23541 } 23542 23543 /** 23544 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 23545 * 23546 * This is where the View specializes rendering behavior based on layer type, 23547 * and hardware acceleration. 23548 */ draw(@onNull Canvas canvas, ViewGroup parent, long drawingTime)23549 boolean draw(@NonNull Canvas canvas, ViewGroup parent, long drawingTime) { 23550 23551 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 23552 23553 boolean drawingWithRenderNode = drawsWithRenderNode(canvas); 23554 23555 boolean more = false; 23556 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 23557 final int parentFlags = parent.mGroupFlags; 23558 23559 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 23560 parent.getChildTransformation().clear(); 23561 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 23562 } 23563 23564 Transformation transformToApply = null; 23565 boolean concatMatrix = false; 23566 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 23567 final Animation a = getAnimation(); 23568 if (a != null) { 23569 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 23570 concatMatrix = a.willChangeTransformationMatrix(); 23571 if (concatMatrix) { 23572 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 23573 } 23574 transformToApply = parent.getChildTransformation(); 23575 } else { 23576 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 23577 // No longer animating: clear out old animation matrix 23578 mRenderNode.setAnimationMatrix(null); 23579 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 23580 } 23581 if (!drawingWithRenderNode 23582 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 23583 final Transformation t = parent.getChildTransformation(); 23584 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 23585 if (hasTransform) { 23586 final int transformType = t.getTransformationType(); 23587 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 23588 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 23589 } 23590 } 23591 } 23592 23593 concatMatrix |= !childHasIdentityMatrix; 23594 23595 // Sets the flag as early as possible to allow draw() implementations 23596 // to call invalidate() successfully when doing animations 23597 mPrivateFlags |= PFLAG_DRAWN; 23598 23599 if (!concatMatrix && 23600 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 23601 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 23602 canvas.quickReject(mLeft, mTop, mRight, mBottom) && 23603 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 23604 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 23605 return more; 23606 } 23607 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 23608 23609 if (hardwareAcceleratedCanvas) { 23610 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 23611 // retain the flag's value temporarily in the mRecreateDisplayList flag 23612 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 23613 mPrivateFlags &= ~PFLAG_INVALIDATED; 23614 } 23615 23616 RenderNode renderNode = null; 23617 Bitmap cache = null; 23618 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 23619 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 23620 if (layerType != LAYER_TYPE_NONE) { 23621 // If not drawing with RenderNode, treat HW layers as SW 23622 layerType = LAYER_TYPE_SOFTWARE; 23623 buildDrawingCache(true); 23624 } 23625 cache = getDrawingCache(true); 23626 } 23627 23628 if (drawingWithRenderNode) { 23629 // Delay getting the display list until animation-driven alpha values are 23630 // set up and possibly passed on to the view 23631 renderNode = updateDisplayListIfDirty(); 23632 if (!renderNode.hasDisplayList()) { 23633 // Uncommon, but possible. If a view is removed from the hierarchy during the call 23634 // to getDisplayList(), the display list will be marked invalid and we should not 23635 // try to use it again. 23636 renderNode = null; 23637 drawingWithRenderNode = false; 23638 } 23639 } 23640 23641 int sx = 0; 23642 int sy = 0; 23643 if (!drawingWithRenderNode) { 23644 computeScroll(); 23645 sx = mScrollX; 23646 sy = mScrollY; 23647 } 23648 23649 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 23650 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 23651 23652 int restoreTo = -1; 23653 if (!drawingWithRenderNode || transformToApply != null) { 23654 restoreTo = canvas.save(); 23655 } 23656 if (offsetForScroll) { 23657 canvas.translate(mLeft - sx, mTop - sy); 23658 } else { 23659 if (!drawingWithRenderNode) { 23660 canvas.translate(mLeft, mTop); 23661 } 23662 if (scalingRequired) { 23663 if (drawingWithRenderNode) { 23664 // TODO: Might not need this if we put everything inside the DL 23665 restoreTo = canvas.save(); 23666 } 23667 // mAttachInfo cannot be null, otherwise scalingRequired == false 23668 final float scale = 1.0f / mAttachInfo.mApplicationScale; 23669 canvas.scale(scale, scale); 23670 } 23671 } 23672 23673 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 23674 if (transformToApply != null 23675 || alpha < 1 23676 || !hasIdentityMatrix() 23677 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 23678 if (transformToApply != null || !childHasIdentityMatrix) { 23679 int transX = 0; 23680 int transY = 0; 23681 23682 if (offsetForScroll) { 23683 transX = -sx; 23684 transY = -sy; 23685 } 23686 23687 if (transformToApply != null) { 23688 if (concatMatrix) { 23689 if (drawingWithRenderNode) { 23690 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 23691 } else { 23692 // Undo the scroll translation, apply the transformation matrix, 23693 // then redo the scroll translate to get the correct result. 23694 canvas.translate(-transX, -transY); 23695 canvas.concat(transformToApply.getMatrix()); 23696 canvas.translate(transX, transY); 23697 } 23698 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 23699 } 23700 23701 float transformAlpha = transformToApply.getAlpha(); 23702 if (transformAlpha < 1) { 23703 alpha *= transformAlpha; 23704 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 23705 } 23706 } 23707 23708 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 23709 canvas.translate(-transX, -transY); 23710 canvas.concat(getMatrix()); 23711 canvas.translate(transX, transY); 23712 } 23713 } 23714 23715 // Deal with alpha if it is or used to be <1 23716 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 23717 if (alpha < 1) { 23718 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 23719 } else { 23720 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 23721 } 23722 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 23723 if (!drawingWithDrawingCache) { 23724 final int multipliedAlpha = (int) (255 * alpha); 23725 if (!onSetAlpha(multipliedAlpha)) { 23726 if (drawingWithRenderNode) { 23727 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 23728 } else if (layerType == LAYER_TYPE_NONE) { 23729 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 23730 multipliedAlpha); 23731 } 23732 } else { 23733 // Alpha is handled by the child directly, clobber the layer's alpha 23734 mPrivateFlags |= PFLAG_ALPHA_SET; 23735 } 23736 } 23737 } 23738 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 23739 onSetAlpha(255); 23740 mPrivateFlags &= ~PFLAG_ALPHA_SET; 23741 } 23742 23743 if (!drawingWithRenderNode) { 23744 // apply clips directly, since RenderNode won't do it for this draw 23745 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 23746 if (offsetForScroll) { 23747 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 23748 } else { 23749 if (!scalingRequired || cache == null) { 23750 canvas.clipRect(0, 0, getWidth(), getHeight()); 23751 } else { 23752 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 23753 } 23754 } 23755 } 23756 23757 if (mClipBounds != null) { 23758 // clip bounds ignore scroll 23759 canvas.clipRect(mClipBounds); 23760 } 23761 } 23762 23763 if (!drawingWithDrawingCache) { 23764 if (drawingWithRenderNode) { 23765 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 23766 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 23767 } else { 23768 // Fast path for layouts with no backgrounds 23769 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 23770 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 23771 dispatchDraw(canvas); 23772 } else { 23773 draw(canvas); 23774 } 23775 } 23776 } else if (cache != null) { 23777 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 23778 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 23779 // no layer paint, use temporary paint to draw bitmap 23780 Paint cachePaint = parent.mCachePaint; 23781 if (cachePaint == null) { 23782 cachePaint = new Paint(); 23783 cachePaint.setDither(false); 23784 parent.mCachePaint = cachePaint; 23785 } 23786 cachePaint.setAlpha((int) (alpha * 255)); 23787 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 23788 } else { 23789 // use layer paint to draw the bitmap, merging the two alphas, but also restore 23790 int layerPaintAlpha = mLayerPaint.getAlpha(); 23791 if (alpha < 1) { 23792 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 23793 } 23794 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 23795 if (alpha < 1) { 23796 mLayerPaint.setAlpha(layerPaintAlpha); 23797 } 23798 } 23799 } 23800 23801 if (restoreTo >= 0) { 23802 canvas.restoreToCount(restoreTo); 23803 } 23804 23805 if (a != null && !more) { 23806 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 23807 onSetAlpha(255); 23808 } 23809 parent.finishAnimatingView(this, a); 23810 } 23811 23812 if (more && hardwareAcceleratedCanvas) { 23813 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 23814 // alpha animations should cause the child to recreate its display list 23815 invalidate(true); 23816 } 23817 } 23818 23819 mRecreateDisplayList = false; 23820 23821 return more; 23822 } 23823 getDebugPaint()23824 static Paint getDebugPaint() { 23825 if (sDebugPaint == null) { 23826 sDebugPaint = new Paint(); 23827 sDebugPaint.setAntiAlias(false); 23828 } 23829 return sDebugPaint; 23830 } 23831 dipsToPixels(int dips)23832 final int dipsToPixels(int dips) { 23833 float scale = getContext().getResources().getDisplayMetrics().density; 23834 return (int) (dips * scale + 0.5f); 23835 } 23836 debugDrawFocus(@onNull Canvas canvas)23837 private void debugDrawFocus(@NonNull Canvas canvas) { 23838 if (isFocused()) { 23839 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 23840 final int l = mScrollX; 23841 final int r = l + mRight - mLeft; 23842 final int t = mScrollY; 23843 final int b = t + mBottom - mTop; 23844 23845 final Paint paint = getDebugPaint(); 23846 paint.setColor(DEBUG_CORNERS_COLOR); 23847 23848 // Draw squares in corners. 23849 paint.setStyle(Paint.Style.FILL); 23850 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 23851 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 23852 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 23853 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 23854 23855 // Draw big X across the view. 23856 paint.setStyle(Paint.Style.STROKE); 23857 canvas.drawLine(l, t, r, b, paint); 23858 canvas.drawLine(l, b, r, t, paint); 23859 } 23860 } 23861 23862 /** 23863 * Manually render this view (and all of its children) to the given Canvas. 23864 * The view must have already done a full layout before this function is 23865 * called. When implementing a view, implement 23866 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 23867 * If you do need to override this method, call the superclass version. 23868 * 23869 * @param canvas The Canvas to which the View is rendered. 23870 */ 23871 @CallSuper draw(@onNull Canvas canvas)23872 public void draw(@NonNull Canvas canvas) { 23873 final int privateFlags = mPrivateFlags; 23874 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 23875 23876 /* 23877 * Draw traversal performs several drawing steps which must be executed 23878 * in the appropriate order: 23879 * 23880 * 1. Draw the background 23881 * 2. If necessary, save the canvas' layers to prepare for fading 23882 * 3. Draw view's content 23883 * 4. Draw children 23884 * 5. If necessary, draw the fading edges and restore layers 23885 * 6. Draw decorations (scrollbars for instance) 23886 * 7. If necessary, draw the default focus highlight 23887 */ 23888 23889 // Step 1, draw the background, if needed 23890 int saveCount; 23891 23892 drawBackground(canvas); 23893 23894 // skip step 2 & 5 if possible (common case) 23895 final int viewFlags = mViewFlags; 23896 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 23897 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 23898 if (!verticalEdges && !horizontalEdges) { 23899 // Step 3, draw the content 23900 onDraw(canvas); 23901 23902 // Step 4, draw the children 23903 dispatchDraw(canvas); 23904 23905 drawAutofilledHighlight(canvas); 23906 23907 // Overlay is part of the content and draws beneath Foreground 23908 if (mOverlay != null && !mOverlay.isEmpty()) { 23909 mOverlay.getOverlayView().dispatchDraw(canvas); 23910 } 23911 23912 // Step 6, draw decorations (foreground, scrollbars) 23913 onDrawForeground(canvas); 23914 23915 // Step 7, draw the default focus highlight 23916 drawDefaultFocusHighlight(canvas); 23917 23918 if (isShowingLayoutBounds()) { 23919 debugDrawFocus(canvas); 23920 } 23921 23922 // we're done... 23923 return; 23924 } 23925 23926 /* 23927 * Here we do the full fledged routine... 23928 * (this is an uncommon case where speed matters less, 23929 * this is why we repeat some of the tests that have been 23930 * done above) 23931 */ 23932 23933 boolean drawTop = false; 23934 boolean drawBottom = false; 23935 boolean drawLeft = false; 23936 boolean drawRight = false; 23937 23938 float topFadeStrength = 0.0f; 23939 float bottomFadeStrength = 0.0f; 23940 float leftFadeStrength = 0.0f; 23941 float rightFadeStrength = 0.0f; 23942 23943 // Step 2, save the canvas' layers 23944 int paddingLeft = mPaddingLeft; 23945 23946 final boolean offsetRequired = isPaddingOffsetRequired(); 23947 if (offsetRequired) { 23948 paddingLeft += getLeftPaddingOffset(); 23949 } 23950 23951 int left = mScrollX + paddingLeft; 23952 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 23953 int top = mScrollY + getFadeTop(offsetRequired); 23954 int bottom = top + getFadeHeight(offsetRequired); 23955 23956 if (offsetRequired) { 23957 right += getRightPaddingOffset(); 23958 bottom += getBottomPaddingOffset(); 23959 } 23960 23961 final ScrollabilityCache scrollabilityCache = mScrollCache; 23962 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 23963 int length = (int) fadeHeight; 23964 23965 // clip the fade length if top and bottom fades overlap 23966 // overlapping fades produce odd-looking artifacts 23967 if (verticalEdges && (top + length > bottom - length)) { 23968 length = (bottom - top) / 2; 23969 } 23970 23971 // also clip horizontal fades if necessary 23972 if (horizontalEdges && (left + length > right - length)) { 23973 length = (right - left) / 2; 23974 } 23975 23976 if (verticalEdges) { 23977 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 23978 drawTop = topFadeStrength * fadeHeight > 1.0f; 23979 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 23980 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 23981 } 23982 23983 if (horizontalEdges) { 23984 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 23985 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 23986 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 23987 drawRight = rightFadeStrength * fadeHeight > 1.0f; 23988 } 23989 23990 saveCount = canvas.getSaveCount(); 23991 int topSaveCount = -1; 23992 int bottomSaveCount = -1; 23993 int leftSaveCount = -1; 23994 int rightSaveCount = -1; 23995 23996 int solidColor = getSolidColor(); 23997 if (solidColor == 0) { 23998 if (drawTop) { 23999 topSaveCount = canvas.saveUnclippedLayer(left, top, right, top + length); 24000 } 24001 24002 if (drawBottom) { 24003 bottomSaveCount = canvas.saveUnclippedLayer(left, bottom - length, right, bottom); 24004 } 24005 24006 if (drawLeft) { 24007 leftSaveCount = canvas.saveUnclippedLayer(left, top, left + length, bottom); 24008 } 24009 24010 if (drawRight) { 24011 rightSaveCount = canvas.saveUnclippedLayer(right - length, top, right, bottom); 24012 } 24013 } else { 24014 scrollabilityCache.setFadeColor(solidColor); 24015 } 24016 24017 // Step 3, draw the content 24018 onDraw(canvas); 24019 24020 // Step 4, draw the children 24021 dispatchDraw(canvas); 24022 24023 // Step 5, draw the fade effect and restore layers 24024 final Paint p = scrollabilityCache.paint; 24025 final Matrix matrix = scrollabilityCache.matrix; 24026 final Shader fade = scrollabilityCache.shader; 24027 24028 // must be restored in the reverse order that they were saved 24029 if (drawRight) { 24030 matrix.setScale(1, fadeHeight * rightFadeStrength); 24031 matrix.postRotate(90); 24032 matrix.postTranslate(right, top); 24033 fade.setLocalMatrix(matrix); 24034 p.setShader(fade); 24035 if (solidColor == 0) { 24036 canvas.restoreUnclippedLayer(rightSaveCount, p); 24037 24038 } else { 24039 canvas.drawRect(right - length, top, right, bottom, p); 24040 } 24041 } 24042 24043 if (drawLeft) { 24044 matrix.setScale(1, fadeHeight * leftFadeStrength); 24045 matrix.postRotate(-90); 24046 matrix.postTranslate(left, top); 24047 fade.setLocalMatrix(matrix); 24048 p.setShader(fade); 24049 if (solidColor == 0) { 24050 canvas.restoreUnclippedLayer(leftSaveCount, p); 24051 } else { 24052 canvas.drawRect(left, top, left + length, bottom, p); 24053 } 24054 } 24055 24056 if (drawBottom) { 24057 matrix.setScale(1, fadeHeight * bottomFadeStrength); 24058 matrix.postRotate(180); 24059 matrix.postTranslate(left, bottom); 24060 fade.setLocalMatrix(matrix); 24061 p.setShader(fade); 24062 if (solidColor == 0) { 24063 canvas.restoreUnclippedLayer(bottomSaveCount, p); 24064 } else { 24065 canvas.drawRect(left, bottom - length, right, bottom, p); 24066 } 24067 } 24068 24069 if (drawTop) { 24070 matrix.setScale(1, fadeHeight * topFadeStrength); 24071 matrix.postTranslate(left, top); 24072 fade.setLocalMatrix(matrix); 24073 p.setShader(fade); 24074 if (solidColor == 0) { 24075 canvas.restoreUnclippedLayer(topSaveCount, p); 24076 } else { 24077 canvas.drawRect(left, top, right, top + length, p); 24078 } 24079 } 24080 24081 canvas.restoreToCount(saveCount); 24082 24083 drawAutofilledHighlight(canvas); 24084 24085 // Overlay is part of the content and draws beneath Foreground 24086 if (mOverlay != null && !mOverlay.isEmpty()) { 24087 mOverlay.getOverlayView().dispatchDraw(canvas); 24088 } 24089 24090 // Step 6, draw decorations (foreground, scrollbars) 24091 onDrawForeground(canvas); 24092 24093 // Step 7, draw the default focus highlight 24094 drawDefaultFocusHighlight(canvas); 24095 24096 if (isShowingLayoutBounds()) { 24097 debugDrawFocus(canvas); 24098 } 24099 } 24100 24101 /** 24102 * Draws the background onto the specified canvas. 24103 * 24104 * @param canvas Canvas on which to draw the background 24105 */ 24106 @UnsupportedAppUsage drawBackground(@onNull Canvas canvas)24107 private void drawBackground(@NonNull Canvas canvas) { 24108 final Drawable background = mBackground; 24109 if (background == null) { 24110 return; 24111 } 24112 24113 setBackgroundBounds(); 24114 24115 // Attempt to use a display list if requested. 24116 if (canvas.isHardwareAccelerated() && mAttachInfo != null 24117 && mAttachInfo.mThreadedRenderer != null) { 24118 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 24119 24120 final RenderNode renderNode = mBackgroundRenderNode; 24121 if (renderNode != null && renderNode.hasDisplayList()) { 24122 setBackgroundRenderNodeProperties(renderNode); 24123 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 24124 return; 24125 } 24126 } 24127 24128 final int scrollX = mScrollX; 24129 final int scrollY = mScrollY; 24130 if ((scrollX | scrollY) == 0) { 24131 background.draw(canvas); 24132 } else { 24133 canvas.translate(scrollX, scrollY); 24134 background.draw(canvas); 24135 canvas.translate(-scrollX, -scrollY); 24136 } 24137 } 24138 24139 /** 24140 * Sets the correct background bounds and rebuilds the outline, if needed. 24141 * <p/> 24142 * This is called by LayoutLib. 24143 */ setBackgroundBounds()24144 void setBackgroundBounds() { 24145 if (mBackgroundSizeChanged && mBackground != null) { 24146 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 24147 mBackgroundSizeChanged = false; 24148 rebuildOutline(); 24149 } 24150 } 24151 setBackgroundRenderNodeProperties(RenderNode renderNode)24152 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 24153 renderNode.setTranslationX(mScrollX); 24154 renderNode.setTranslationY(mScrollY); 24155 } 24156 24157 /** 24158 * Creates a new display list or updates the existing display list for the 24159 * specified Drawable. 24160 * 24161 * @param drawable Drawable for which to create a display list 24162 * @param renderNode Existing RenderNode, or {@code null} 24163 * @return A valid display list for the specified drawable 24164 */ getDrawableRenderNode(Drawable drawable, RenderNode renderNode)24165 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 24166 if (renderNode == null) { 24167 renderNode = RenderNode.create(drawable.getClass().getName(), 24168 new ViewAnimationHostBridge(this)); 24169 renderNode.setUsageHint(RenderNode.USAGE_BACKGROUND); 24170 } 24171 24172 final Rect bounds = drawable.getBounds(); 24173 final int width = bounds.width(); 24174 final int height = bounds.height(); 24175 24176 // Hacky hack: Reset any stretch effects as those are applied during the draw pass 24177 // instead of being "stateful" like other RenderNode properties 24178 renderNode.clearStretch(); 24179 24180 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 24181 24182 // Reverse left/top translation done by drawable canvas, which will 24183 // instead be applied by rendernode's LTRB bounds below. This way, the 24184 // drawable's bounds match with its rendernode bounds and its content 24185 // will lie within those bounds in the rendernode tree. 24186 canvas.translate(-bounds.left, -bounds.top); 24187 24188 try { 24189 drawable.draw(canvas); 24190 } finally { 24191 renderNode.endRecording(); 24192 } 24193 24194 // Set up drawable properties that are view-independent. 24195 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 24196 renderNode.setProjectBackwards(drawable.isProjected()); 24197 renderNode.setProjectionReceiver(true); 24198 renderNode.setClipToBounds(false); 24199 return renderNode; 24200 } 24201 24202 /** 24203 * Returns the overlay for this view, creating it if it does not yet exist. 24204 * Adding drawables to the overlay will cause them to be displayed whenever 24205 * the view itself is redrawn. Objects in the overlay should be actively 24206 * managed: remove them when they should not be displayed anymore. The 24207 * overlay will always have the same size as its host view. 24208 * 24209 * <p>Note: Overlays do not currently work correctly with {@link 24210 * SurfaceView} or {@link TextureView}; contents in overlays for these 24211 * types of views may not display correctly.</p> 24212 * 24213 * @return The ViewOverlay object for this view. 24214 * @see ViewOverlay 24215 */ getOverlay()24216 public ViewOverlay getOverlay() { 24217 if (mOverlay == null) { 24218 mOverlay = new ViewOverlay(mContext, this); 24219 } 24220 return mOverlay; 24221 } 24222 24223 /** 24224 * Override this if your view is known to always be drawn on top of a solid color background, 24225 * and needs to draw fading edges. Returning a non-zero color enables the view system to 24226 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 24227 * should be set to 0xFF. 24228 * 24229 * @see #setVerticalFadingEdgeEnabled(boolean) 24230 * @see #setHorizontalFadingEdgeEnabled(boolean) 24231 * 24232 * @return The known solid color background for this view, or 0 if the color may vary 24233 */ 24234 @ViewDebug.ExportedProperty(category = "drawing") 24235 @InspectableProperty 24236 @ColorInt getSolidColor()24237 public int getSolidColor() { 24238 return 0; 24239 } 24240 24241 /** 24242 * Build a human readable string representation of the specified view flags. 24243 * 24244 * @param flags the view flags to convert to a string 24245 * @return a String representing the supplied flags 24246 */ printFlags(int flags)24247 private static String printFlags(int flags) { 24248 String output = ""; 24249 int numFlags = 0; 24250 if ((flags & FOCUSABLE) == FOCUSABLE) { 24251 output += "TAKES_FOCUS"; 24252 numFlags++; 24253 } 24254 24255 switch (flags & VISIBILITY_MASK) { 24256 case INVISIBLE: 24257 if (numFlags > 0) { 24258 output += " "; 24259 } 24260 output += "INVISIBLE"; 24261 // USELESS HERE numFlags++; 24262 break; 24263 case GONE: 24264 if (numFlags > 0) { 24265 output += " "; 24266 } 24267 output += "GONE"; 24268 // USELESS HERE numFlags++; 24269 break; 24270 default: 24271 break; 24272 } 24273 return output; 24274 } 24275 24276 /** 24277 * Build a human readable string representation of the specified private 24278 * view flags. 24279 * 24280 * @param privateFlags the private view flags to convert to a string 24281 * @return a String representing the supplied flags 24282 */ printPrivateFlags(int privateFlags)24283 private static String printPrivateFlags(int privateFlags) { 24284 String output = ""; 24285 int numFlags = 0; 24286 24287 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 24288 output += "WANTS_FOCUS"; 24289 numFlags++; 24290 } 24291 24292 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 24293 if (numFlags > 0) { 24294 output += " "; 24295 } 24296 output += "FOCUSED"; 24297 numFlags++; 24298 } 24299 24300 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 24301 if (numFlags > 0) { 24302 output += " "; 24303 } 24304 output += "SELECTED"; 24305 numFlags++; 24306 } 24307 24308 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 24309 if (numFlags > 0) { 24310 output += " "; 24311 } 24312 output += "IS_ROOT_NAMESPACE"; 24313 numFlags++; 24314 } 24315 24316 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 24317 if (numFlags > 0) { 24318 output += " "; 24319 } 24320 output += "HAS_BOUNDS"; 24321 numFlags++; 24322 } 24323 24324 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 24325 if (numFlags > 0) { 24326 output += " "; 24327 } 24328 output += "DRAWN"; 24329 // USELESS HERE numFlags++; 24330 } 24331 return output; 24332 } 24333 24334 /** 24335 * <p>Indicates whether or not this view's layout will be requested during 24336 * the next hierarchy layout pass.</p> 24337 * 24338 * @return true if the layout will be forced during next layout pass 24339 */ isLayoutRequested()24340 public boolean isLayoutRequested() { 24341 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 24342 } 24343 24344 /** 24345 * Return true if o is a ViewGroup that is laying out using optical bounds. 24346 * @hide 24347 */ isLayoutModeOptical(Object o)24348 public static boolean isLayoutModeOptical(Object o) { 24349 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 24350 } 24351 24352 /** 24353 * Enable measure/layout debugging on traces. 24354 * 24355 * @see Trace 24356 * @hide 24357 */ setTraceLayoutSteps(boolean traceLayoutSteps)24358 public static void setTraceLayoutSteps(boolean traceLayoutSteps) { 24359 sTraceLayoutSteps = traceLayoutSteps; 24360 } 24361 24362 /** 24363 * Enable request layout tracing classes with {@code s} simple name. 24364 * <p> 24365 * When set, a {@link Trace} instant event and a log with the stacktrace is emitted every 24366 * time a requestLayout of a class matching {@code s} name happens. 24367 * This applies only to views attached from this point onwards. 24368 * 24369 * @see Trace#instant(long, String) 24370 * @hide 24371 */ setTracedRequestLayoutClassClass(String s)24372 public static void setTracedRequestLayoutClassClass(String s) { 24373 sTraceRequestLayoutClass = s; 24374 } 24375 setOpticalFrame(int left, int top, int right, int bottom)24376 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 24377 Insets parentInsets = mParent instanceof View ? 24378 ((View) mParent).getOpticalInsets() : Insets.NONE; 24379 Insets childInsets = getOpticalInsets(); 24380 return setFrame( 24381 left + parentInsets.left - childInsets.left, 24382 top + parentInsets.top - childInsets.top, 24383 right + parentInsets.left + childInsets.right, 24384 bottom + parentInsets.top + childInsets.bottom); 24385 } 24386 24387 /** 24388 * Assign a size and position to a view and all of its 24389 * descendants 24390 * 24391 * <p>This is the second phase of the layout mechanism. 24392 * (The first is measuring). In this phase, each parent calls 24393 * layout on all of its children to position them. 24394 * This is typically done using the child measurements 24395 * that were stored in the measure pass().</p> 24396 * 24397 * <p>Derived classes should not override this method. 24398 * Derived classes with children should override 24399 * onLayout. In that method, they should 24400 * call layout on each of their children.</p> 24401 * 24402 * @param l Left position, relative to parent 24403 * @param t Top position, relative to parent 24404 * @param r Right position, relative to parent 24405 * @param b Bottom position, relative to parent 24406 */ 24407 @SuppressWarnings({"unchecked"}) layout(int l, int t, int r, int b)24408 public void layout(int l, int t, int r, int b) { 24409 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 24410 if (isTraversalTracingEnabled()) { 24411 Trace.beginSection(mTracingStrings.onMeasureBeforeLayout); 24412 } 24413 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 24414 if (isTraversalTracingEnabled()) { 24415 Trace.endSection(); 24416 } 24417 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 24418 } 24419 24420 int oldL = mLeft; 24421 int oldT = mTop; 24422 int oldB = mBottom; 24423 int oldR = mRight; 24424 24425 boolean changed = isLayoutModeOptical(mParent) ? 24426 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 24427 24428 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 24429 if (isTraversalTracingEnabled()) { 24430 Trace.beginSection(mTracingStrings.onLayout); 24431 } 24432 onLayout(changed, l, t, r, b); 24433 if (isTraversalTracingEnabled()) { 24434 Trace.endSection(); 24435 } 24436 24437 if (shouldDrawRoundScrollbar()) { 24438 if(mRoundScrollbarRenderer == null) { 24439 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 24440 } 24441 } else { 24442 mRoundScrollbarRenderer = null; 24443 } 24444 24445 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 24446 24447 ListenerInfo li = mListenerInfo; 24448 if (li != null && li.mOnLayoutChangeListeners != null) { 24449 ArrayList<OnLayoutChangeListener> listenersCopy = 24450 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 24451 int numListeners = listenersCopy.size(); 24452 for (int i = 0; i < numListeners; ++i) { 24453 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 24454 } 24455 } 24456 } 24457 24458 final boolean wasLayoutValid = isLayoutValid(); 24459 24460 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 24461 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 24462 24463 if (!wasLayoutValid && isFocused()) { 24464 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 24465 if (canTakeFocus()) { 24466 // We have a robust focus, so parents should no longer be wanting focus. 24467 clearParentsWantFocus(); 24468 } else if (getViewRootImpl() == null || !getViewRootImpl().isInLayout()) { 24469 // This is a weird case. Most-likely the user, rather than ViewRootImpl, called 24470 // layout. In this case, there's no guarantee that parent layouts will be evaluated 24471 // and thus the safest action is to clear focus here. 24472 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 24473 clearParentsWantFocus(); 24474 } else if (!hasParentWantsFocus()) { 24475 // original requestFocus was likely on this view directly, so just clear focus 24476 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 24477 } 24478 // otherwise, we let parents handle re-assigning focus during their layout passes. 24479 } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 24480 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 24481 View focused = findFocus(); 24482 if (focused != null) { 24483 // Try to restore focus as close as possible to our starting focus. 24484 if (!restoreDefaultFocus() && !hasParentWantsFocus()) { 24485 // Give up and clear focus once we've reached the top-most parent which wants 24486 // focus. 24487 focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 24488 } 24489 } 24490 } 24491 24492 if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { 24493 mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 24494 notifyEnterOrExitForAutoFillIfNeeded(true); 24495 } 24496 24497 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 24498 } 24499 hasParentWantsFocus()24500 private boolean hasParentWantsFocus() { 24501 ViewParent parent = mParent; 24502 while (parent instanceof ViewGroup) { 24503 ViewGroup pv = (ViewGroup) parent; 24504 if ((pv.mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 24505 return true; 24506 } 24507 parent = pv.mParent; 24508 } 24509 return false; 24510 } 24511 24512 /** 24513 * Called from layout when this view should 24514 * assign a size and position to each of its children. 24515 * 24516 * Derived classes with children should override 24517 * this method and call layout on each of 24518 * their children. 24519 * @param changed This is a new size or position for this view 24520 * @param left Left position, relative to parent 24521 * @param top Top position, relative to parent 24522 * @param right Right position, relative to parent 24523 * @param bottom Bottom position, relative to parent 24524 */ onLayout(boolean changed, int left, int top, int right, int bottom)24525 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 24526 } 24527 24528 /** 24529 * Assign a size and position to this view. 24530 * 24531 * This is called from layout. 24532 * 24533 * @param left Left position, relative to parent 24534 * @param top Top position, relative to parent 24535 * @param right Right position, relative to parent 24536 * @param bottom Bottom position, relative to parent 24537 * @return true if the new size and position are different than the 24538 * previous ones 24539 * {@hide} 24540 */ 24541 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) setFrame(int left, int top, int right, int bottom)24542 protected boolean setFrame(int left, int top, int right, int bottom) { 24543 boolean changed = false; 24544 24545 if (DBG) { 24546 Log.d(VIEW_LOG_TAG, this + " View.setFrame(" + left + "," + top + "," 24547 + right + "," + bottom + ")"); 24548 } 24549 24550 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 24551 changed = true; 24552 24553 // Remember our drawn bit 24554 int drawn = mPrivateFlags & PFLAG_DRAWN; 24555 24556 int oldWidth = mRight - mLeft; 24557 int oldHeight = mBottom - mTop; 24558 int newWidth = right - left; 24559 int newHeight = bottom - top; 24560 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 24561 24562 // Invalidate our old position 24563 invalidate(sizeChanged); 24564 24565 mLeft = left; 24566 mTop = top; 24567 mRight = right; 24568 mBottom = bottom; 24569 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 24570 24571 mPrivateFlags |= PFLAG_HAS_BOUNDS; 24572 24573 24574 if (sizeChanged) { 24575 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 24576 } 24577 24578 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 24579 // If we are visible, force the DRAWN bit to on so that 24580 // this invalidate will go through (at least to our parent). 24581 // This is because someone may have invalidated this view 24582 // before this call to setFrame came in, thereby clearing 24583 // the DRAWN bit. 24584 mPrivateFlags |= PFLAG_DRAWN; 24585 invalidate(sizeChanged); 24586 // parent display list may need to be recreated based on a change in the bounds 24587 // of any child 24588 invalidateParentCaches(); 24589 } 24590 24591 // Reset drawn bit to original value (invalidate turns it off) 24592 mPrivateFlags |= drawn; 24593 24594 mBackgroundSizeChanged = true; 24595 mDefaultFocusHighlightSizeChanged = true; 24596 if (mForegroundInfo != null) { 24597 mForegroundInfo.mBoundsChanged = true; 24598 } 24599 24600 notifySubtreeAccessibilityStateChangedIfNeeded(); 24601 } 24602 return changed; 24603 } 24604 24605 /** 24606 * Assign a size and position to this view. 24607 * 24608 * This method is meant to be used in animations only as it applies this position and size 24609 * for the view only temporary and it can be changed back at any time by the layout. 24610 * 24611 * @param left Left position, relative to parent 24612 * @param top Top position, relative to parent 24613 * @param right Right position, relative to parent 24614 * @param bottom Bottom position, relative to parent 24615 * 24616 * @see #setLeft(int), #setRight(int), #setTop(int), #setBottom(int) 24617 */ setLeftTopRightBottom(int left, int top, int right, int bottom)24618 public final void setLeftTopRightBottom(int left, int top, int right, int bottom) { 24619 setFrame(left, top, right, bottom); 24620 } 24621 sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight)24622 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 24623 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 24624 if (mOverlay != null) { 24625 mOverlay.getOverlayView().setRight(newWidth); 24626 mOverlay.getOverlayView().setBottom(newHeight); 24627 } 24628 // If this isn't laid out yet, focus assignment will be handled during the "deferment/ 24629 // backtracking" of requestFocus during layout, so don't touch focus here. 24630 if (!sCanFocusZeroSized && isLayoutValid() 24631 // Don't touch focus if animating 24632 && !(mParent instanceof ViewGroup && ((ViewGroup) mParent).isLayoutSuppressed())) { 24633 if (newWidth <= 0 || newHeight <= 0) { 24634 if (hasFocus()) { 24635 clearFocus(); 24636 if (mParent instanceof ViewGroup) { 24637 ((ViewGroup) mParent).clearFocusedInCluster(); 24638 } 24639 } 24640 clearAccessibilityFocus(); 24641 } else if (oldWidth <= 0 || oldHeight <= 0) { 24642 if (mParent != null && canTakeFocus()) { 24643 mParent.focusableViewAvailable(this); 24644 } 24645 } 24646 } 24647 rebuildOutline(); 24648 if (onCheckIsTextEditor() || mHandwritingDelegatorCallback != null) { 24649 setHandwritingArea(new Rect(0, 0, newWidth, newHeight)); 24650 } 24651 } 24652 24653 /** 24654 * Finalize inflating a view from XML. This is called as the last phase 24655 * of inflation, after all child views have been added. 24656 * 24657 * <p>Even if the subclass overrides onFinishInflate, they should always be 24658 * sure to call the super method, so that we get called. 24659 */ 24660 @CallSuper onFinishInflate()24661 protected void onFinishInflate() { 24662 } 24663 24664 /** 24665 * Returns the resources associated with this view. 24666 * 24667 * @return Resources object. 24668 */ getResources()24669 public Resources getResources() { 24670 return mResources; 24671 } 24672 24673 /** 24674 * Invalidates the specified Drawable. 24675 * 24676 * @param drawable the drawable to invalidate 24677 */ 24678 @Override invalidateDrawable(@onNull Drawable drawable)24679 public void invalidateDrawable(@NonNull Drawable drawable) { 24680 if (verifyDrawable(drawable)) { 24681 final Rect dirty = drawable.getDirtyBounds(); 24682 final int scrollX = mScrollX; 24683 final int scrollY = mScrollY; 24684 24685 invalidate(dirty.left + scrollX, dirty.top + scrollY, 24686 dirty.right + scrollX, dirty.bottom + scrollY); 24687 rebuildOutline(); 24688 } 24689 } 24690 24691 /** 24692 * Schedules an action on a drawable to occur at a specified time. 24693 * 24694 * @param who the recipient of the action 24695 * @param what the action to run on the drawable 24696 * @param when the time at which the action must occur. Uses the 24697 * {@link SystemClock#uptimeMillis} timebase. 24698 */ 24699 @Override scheduleDrawable(@onNull Drawable who, @NonNull Runnable what, long when)24700 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 24701 if (verifyDrawable(who) && what != null) { 24702 final long delay = when - SystemClock.uptimeMillis(); 24703 if (mAttachInfo != null) { 24704 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 24705 Choreographer.CALLBACK_ANIMATION, what, who, 24706 Choreographer.subtractFrameDelay(delay)); 24707 } else { 24708 // Postpone the runnable until we know 24709 // on which thread it needs to run. 24710 getRunQueue().postDelayed(what, delay); 24711 } 24712 } 24713 } 24714 24715 /** 24716 * Cancels a scheduled action on a drawable. 24717 * 24718 * @param who the recipient of the action 24719 * @param what the action to cancel 24720 */ 24721 @Override unscheduleDrawable(@onNull Drawable who, @NonNull Runnable what)24722 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 24723 if (verifyDrawable(who) && what != null) { 24724 if (mAttachInfo != null) { 24725 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 24726 Choreographer.CALLBACK_ANIMATION, what, who); 24727 } 24728 getRunQueue().removeCallbacks(what); 24729 } 24730 } 24731 24732 /** 24733 * Unschedule any events associated with the given Drawable. This can be 24734 * used when selecting a new Drawable into a view, so that the previous 24735 * one is completely unscheduled. 24736 * 24737 * @param who The Drawable to unschedule. 24738 * 24739 * @see #drawableStateChanged 24740 */ unscheduleDrawable(Drawable who)24741 public void unscheduleDrawable(Drawable who) { 24742 if (mAttachInfo != null && who != null) { 24743 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 24744 Choreographer.CALLBACK_ANIMATION, null, who); 24745 } 24746 } 24747 24748 /** 24749 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 24750 * that the View directionality can and will be resolved before its Drawables. 24751 * 24752 * Will call {@link View#onResolveDrawables} when resolution is done. 24753 * 24754 * @hide 24755 */ resolveDrawables()24756 protected void resolveDrawables() { 24757 // Drawables resolution may need to happen before resolving the layout direction (which is 24758 // done only during the measure() call). 24759 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 24760 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 24761 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 24762 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 24763 // direction to be resolved as its resolved value will be the same as its raw value. 24764 if (!isLayoutDirectionResolved() && 24765 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 24766 return; 24767 } 24768 24769 final int layoutDirection = isLayoutDirectionResolved() ? 24770 getLayoutDirection() : getRawLayoutDirection(); 24771 24772 if (mBackground != null) { 24773 mBackground.setLayoutDirection(layoutDirection); 24774 } 24775 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 24776 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 24777 } 24778 if (mDefaultFocusHighlight != null) { 24779 mDefaultFocusHighlight.setLayoutDirection(layoutDirection); 24780 } 24781 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 24782 onResolveDrawables(layoutDirection); 24783 } 24784 areDrawablesResolved()24785 boolean areDrawablesResolved() { 24786 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 24787 } 24788 24789 /** 24790 * Called when layout direction has been resolved. 24791 * 24792 * The default implementation does nothing. 24793 * 24794 * @param layoutDirection The resolved layout direction. 24795 * 24796 * @see #LAYOUT_DIRECTION_LTR 24797 * @see #LAYOUT_DIRECTION_RTL 24798 * 24799 * @hide 24800 */ onResolveDrawables(@esolvedLayoutDir int layoutDirection)24801 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 24802 } 24803 24804 /** 24805 * @hide 24806 */ 24807 @TestApi resetResolvedDrawables()24808 protected void resetResolvedDrawables() { 24809 resetResolvedDrawablesInternal(); 24810 } 24811 resetResolvedDrawablesInternal()24812 void resetResolvedDrawablesInternal() { 24813 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 24814 } 24815 24816 /** 24817 * If your view subclass is displaying its own Drawable objects, it should 24818 * override this function and return true for any Drawable it is 24819 * displaying. This allows animations for those drawables to be 24820 * scheduled. 24821 * 24822 * <p>Be sure to call through to the super class when overriding this 24823 * function. 24824 * 24825 * @param who The Drawable to verify. Return true if it is one you are 24826 * displaying, else return the result of calling through to the 24827 * super class. 24828 * 24829 * @return boolean If true then the Drawable is being displayed in the 24830 * view; else false and it is not allowed to animate. 24831 * 24832 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 24833 * @see #drawableStateChanged() 24834 */ 24835 @CallSuper verifyDrawable(@onNull Drawable who)24836 protected boolean verifyDrawable(@NonNull Drawable who) { 24837 // Avoid verifying the scroll bar drawable so that we don't end up in 24838 // an invalidation loop. This effectively prevents the scroll bar 24839 // drawable from triggering invalidations and scheduling runnables. 24840 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) 24841 || (mDefaultFocusHighlight == who); 24842 } 24843 24844 /** 24845 * This function is called whenever the state of the view changes in such 24846 * a way that it impacts the state of drawables being shown. 24847 * <p> 24848 * If the View has a StateListAnimator, it will also be called to run necessary state 24849 * change animations. 24850 * <p> 24851 * Be sure to call through to the superclass when overriding this function. 24852 * 24853 * @see Drawable#setState(int[]) 24854 */ 24855 @CallSuper drawableStateChanged()24856 protected void drawableStateChanged() { 24857 final int[] state = getDrawableState(); 24858 boolean changed = false; 24859 24860 final Drawable bg = mBackground; 24861 if (bg != null && bg.isStateful()) { 24862 changed |= bg.setState(state); 24863 } 24864 24865 final Drawable hl = mDefaultFocusHighlight; 24866 if (hl != null && hl.isStateful()) { 24867 changed |= hl.setState(state); 24868 } 24869 24870 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 24871 if (fg != null && fg.isStateful()) { 24872 changed |= fg.setState(state); 24873 } 24874 24875 if (mScrollCache != null) { 24876 final Drawable scrollBar = mScrollCache.scrollBar; 24877 if (scrollBar != null && scrollBar.isStateful()) { 24878 changed |= scrollBar.setState(state) 24879 && mScrollCache.state != ScrollabilityCache.OFF; 24880 } 24881 } 24882 24883 if (mStateListAnimator != null) { 24884 mStateListAnimator.setState(state); 24885 } 24886 24887 if (!isAggregatedVisible()) { 24888 // If we're not visible, skip any animated changes 24889 jumpDrawablesToCurrentState(); 24890 } 24891 24892 if (changed) { 24893 invalidate(); 24894 } 24895 } 24896 24897 /** 24898 * This function is called whenever the view hotspot changes and needs to 24899 * be propagated to drawables or child views managed by the view. 24900 * <p> 24901 * Dispatching to child views is handled by 24902 * {@link #dispatchDrawableHotspotChanged(float, float)}. 24903 * <p> 24904 * Be sure to call through to the superclass when overriding this function. 24905 * 24906 * @param x hotspot x coordinate 24907 * @param y hotspot y coordinate 24908 */ 24909 @CallSuper drawableHotspotChanged(float x, float y)24910 public void drawableHotspotChanged(float x, float y) { 24911 if (mBackground != null) { 24912 mBackground.setHotspot(x, y); 24913 } 24914 if (mDefaultFocusHighlight != null) { 24915 mDefaultFocusHighlight.setHotspot(x, y); 24916 } 24917 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 24918 mForegroundInfo.mDrawable.setHotspot(x, y); 24919 } 24920 24921 dispatchDrawableHotspotChanged(x, y); 24922 } 24923 24924 /** 24925 * Dispatches drawableHotspotChanged to all of this View's children. 24926 * 24927 * @param x hotspot x coordinate 24928 * @param y hotspot y coordinate 24929 * @see #drawableHotspotChanged(float, float) 24930 */ dispatchDrawableHotspotChanged(float x, float y)24931 public void dispatchDrawableHotspotChanged(float x, float y) { 24932 } 24933 24934 /** 24935 * Call this to force a view to update its drawable state. This will cause 24936 * drawableStateChanged to be called on this view. Views that are interested 24937 * in the new state should call getDrawableState. 24938 * 24939 * @see #drawableStateChanged 24940 * @see #getDrawableState 24941 */ refreshDrawableState()24942 public void refreshDrawableState() { 24943 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 24944 drawableStateChanged(); 24945 24946 ViewParent parent = mParent; 24947 if (parent != null) { 24948 parent.childDrawableStateChanged(this); 24949 } 24950 } 24951 24952 /** 24953 * Create a default focus highlight if it doesn't exist. 24954 * @return a default focus highlight. 24955 */ getDefaultFocusHighlightDrawable()24956 private Drawable getDefaultFocusHighlightDrawable() { 24957 if (mDefaultFocusHighlightCache == null) { 24958 if (mContext != null) { 24959 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; 24960 final TypedArray ta = mContext.obtainStyledAttributes(attrs); 24961 mDefaultFocusHighlightCache = ta.getDrawable(0); 24962 ta.recycle(); 24963 } 24964 } 24965 return mDefaultFocusHighlightCache; 24966 } 24967 24968 /** 24969 * Set the current default focus highlight. 24970 * @param highlight the highlight drawable, or {@code null} if it's no longer needed. 24971 */ setDefaultFocusHighlight(Drawable highlight)24972 private void setDefaultFocusHighlight(Drawable highlight) { 24973 mDefaultFocusHighlight = highlight; 24974 mDefaultFocusHighlightSizeChanged = true; 24975 if (highlight != null) { 24976 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 24977 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 24978 } 24979 highlight.setLayoutDirection(getLayoutDirection()); 24980 if (highlight.isStateful()) { 24981 highlight.setState(getDrawableState()); 24982 } 24983 if (isAttachedToWindow()) { 24984 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 24985 } 24986 // Set callback last, since the view may still be initializing. 24987 highlight.setCallback(this); 24988 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 24989 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 24990 mPrivateFlags |= PFLAG_SKIP_DRAW; 24991 } 24992 invalidate(); 24993 } 24994 24995 /** 24996 * Check whether we need to draw a default focus highlight when this view gets focused, 24997 * which requires: 24998 * <ul> 24999 * <li>In both background and foreground, {@link android.R.attr#state_focused} 25000 * is not defined.</li> 25001 * <li>This view is not in touch mode.</li> 25002 * <li>This view doesn't opt out for a default focus highlight, via 25003 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li> 25004 * <li>This view is attached to window.</li> 25005 * </ul> 25006 * @return {@code true} if a default focus highlight is needed. 25007 * @hide 25008 */ 25009 @TestApi isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground)25010 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { 25011 final boolean lackFocusState = (background == null || !background.isStateful() 25012 || !background.hasFocusStateSpecified()) 25013 && (foreground == null || !foreground.isStateful() 25014 || !foreground.hasFocusStateSpecified()); 25015 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState 25016 && isAttachedToWindow() && sUseDefaultFocusHighlight; 25017 } 25018 25019 /** 25020 * When this view is focused, switches on/off the default focused highlight. 25021 * <p> 25022 * This always happens when this view is focused, and only at this moment the default focus 25023 * highlight can be visible. 25024 */ switchDefaultFocusHighlight()25025 private void switchDefaultFocusHighlight() { 25026 if (isFocused()) { 25027 final boolean needed = isDefaultFocusHighlightNeeded(mBackground, 25028 mForegroundInfo == null ? null : mForegroundInfo.mDrawable); 25029 final boolean active = mDefaultFocusHighlight != null; 25030 if (needed && !active) { 25031 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); 25032 } else if (!needed && active) { 25033 // The highlight is no longer needed, so tear it down. 25034 setDefaultFocusHighlight(null); 25035 } 25036 } 25037 } 25038 25039 /** 25040 * Draw the default focus highlight onto the canvas if there is one and this view is focused. 25041 * @param canvas the canvas where we're drawing the highlight. 25042 */ drawDefaultFocusHighlight(@onNull Canvas canvas)25043 private void drawDefaultFocusHighlight(@NonNull Canvas canvas) { 25044 if (mDefaultFocusHighlight != null && isFocused()) { 25045 if (mDefaultFocusHighlightSizeChanged) { 25046 mDefaultFocusHighlightSizeChanged = false; 25047 final int l = mScrollX; 25048 final int r = l + mRight - mLeft; 25049 final int t = mScrollY; 25050 final int b = t + mBottom - mTop; 25051 mDefaultFocusHighlight.setBounds(l, t, r, b); 25052 } 25053 mDefaultFocusHighlight.draw(canvas); 25054 } 25055 } 25056 25057 /** 25058 * Return an array of resource IDs of the drawable states representing the 25059 * current state of the view. 25060 * 25061 * @return The current drawable state 25062 * 25063 * @see Drawable#setState(int[]) 25064 * @see #drawableStateChanged() 25065 * @see #onCreateDrawableState(int) 25066 */ getDrawableState()25067 public final int[] getDrawableState() { 25068 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 25069 return mDrawableState; 25070 } else { 25071 mDrawableState = onCreateDrawableState(0); 25072 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 25073 return mDrawableState; 25074 } 25075 } 25076 25077 /** 25078 * Generate the new {@link android.graphics.drawable.Drawable} state for 25079 * this view. This is called by the view 25080 * system when the cached Drawable state is determined to be invalid. To 25081 * retrieve the current state, you should use {@link #getDrawableState}. 25082 * 25083 * @param extraSpace if non-zero, this is the number of extra entries you 25084 * would like in the returned array in which you can place your own 25085 * states. 25086 * 25087 * @return Returns an array holding the current {@link Drawable} state of 25088 * the view. 25089 * 25090 * @see #mergeDrawableStates(int[], int[]) 25091 */ onCreateDrawableState(int extraSpace)25092 protected int[] onCreateDrawableState(int extraSpace) { 25093 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 25094 mParent instanceof View) { 25095 return ((View) mParent).onCreateDrawableState(extraSpace); 25096 } 25097 25098 int[] drawableState; 25099 25100 int privateFlags = mPrivateFlags; 25101 25102 int viewStateIndex = 0; 25103 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 25104 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 25105 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 25106 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 25107 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 25108 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 25109 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested) { 25110 // This is set if HW acceleration is requested, even if the current 25111 // process doesn't allow it. This is just to allow app preview 25112 // windows to better match their app. 25113 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 25114 } 25115 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 25116 25117 final int privateFlags2 = mPrivateFlags2; 25118 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 25119 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 25120 } 25121 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 25122 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 25123 } 25124 25125 drawableState = StateSet.get(viewStateIndex); 25126 25127 //noinspection ConstantIfStatement 25128 if (false) { 25129 Log.i("View", "drawableStateIndex=" + viewStateIndex); 25130 Log.i("View", toString() 25131 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 25132 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 25133 + " fo=" + hasFocus() 25134 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 25135 + " wf=" + hasWindowFocus() 25136 + ": " + Arrays.toString(drawableState)); 25137 } 25138 25139 if (extraSpace == 0) { 25140 return drawableState; 25141 } 25142 25143 final int[] fullState; 25144 if (drawableState != null) { 25145 fullState = new int[drawableState.length + extraSpace]; 25146 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 25147 } else { 25148 fullState = new int[extraSpace]; 25149 } 25150 25151 return fullState; 25152 } 25153 25154 /** 25155 * Merge your own state values in <var>additionalState</var> into the base 25156 * state values <var>baseState</var> that were returned by 25157 * {@link #onCreateDrawableState(int)}. 25158 * 25159 * @param baseState The base state values returned by 25160 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 25161 * own additional state values. 25162 * 25163 * @param additionalState The additional state values you would like 25164 * added to <var>baseState</var>; this array is not modified. 25165 * 25166 * @return As a convenience, the <var>baseState</var> array you originally 25167 * passed into the function is returned. 25168 * 25169 * @see #onCreateDrawableState(int) 25170 */ mergeDrawableStates(int[] baseState, int[] additionalState)25171 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 25172 final int N = baseState.length; 25173 int i = N - 1; 25174 while (i >= 0 && baseState[i] == 0) { 25175 i--; 25176 } 25177 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 25178 return baseState; 25179 } 25180 25181 /** 25182 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 25183 * on all Drawable objects associated with this view. 25184 * <p> 25185 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 25186 * attached to this view. 25187 */ 25188 @CallSuper jumpDrawablesToCurrentState()25189 public void jumpDrawablesToCurrentState() { 25190 if (mBackground != null) { 25191 mBackground.jumpToCurrentState(); 25192 } 25193 if (mStateListAnimator != null) { 25194 mStateListAnimator.jumpToCurrentState(); 25195 } 25196 if (mDefaultFocusHighlight != null) { 25197 mDefaultFocusHighlight.jumpToCurrentState(); 25198 } 25199 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 25200 mForegroundInfo.mDrawable.jumpToCurrentState(); 25201 } 25202 } 25203 25204 /** 25205 * Sets the background color for this view. 25206 * @param color the color of the background 25207 */ 25208 @RemotableViewMethod setBackgroundColor(@olorInt int color)25209 public void setBackgroundColor(@ColorInt int color) { 25210 if (mBackground instanceof ColorDrawable) { 25211 ((ColorDrawable) mBackground.mutate()).setColor(color); 25212 computeOpaqueFlags(); 25213 mBackgroundResource = 0; 25214 } else { 25215 setBackground(new ColorDrawable(color)); 25216 } 25217 } 25218 25219 /** 25220 * Set the background to a given resource. The resource should refer to 25221 * a Drawable object or 0 to remove the background. 25222 * @param resid The identifier of the resource. 25223 * 25224 * @attr ref android.R.styleable#View_background 25225 */ 25226 @RemotableViewMethod setBackgroundResource(@rawableRes int resid)25227 public void setBackgroundResource(@DrawableRes int resid) { 25228 if (resid != 0 && resid == mBackgroundResource) { 25229 return; 25230 } 25231 25232 Drawable d = null; 25233 if (resid != 0) { 25234 d = mContext.getDrawable(resid); 25235 } 25236 setBackground(d); 25237 25238 mBackgroundResource = resid; 25239 } 25240 25241 /** 25242 * Set the background to a given Drawable, or remove the background. If the 25243 * background has padding, this View's padding is set to the background's 25244 * padding. However, when a background is removed, this View's padding isn't 25245 * touched. If setting the padding is desired, please use 25246 * {@link #setPadding(int, int, int, int)}. 25247 * 25248 * @param background The Drawable to use as the background, or null to remove the 25249 * background 25250 */ setBackground(Drawable background)25251 public void setBackground(Drawable background) { 25252 //noinspection deprecation 25253 setBackgroundDrawable(background); 25254 } 25255 25256 /** 25257 * @deprecated use {@link #setBackground(Drawable)} instead 25258 */ 25259 @Deprecated setBackgroundDrawable(Drawable background)25260 public void setBackgroundDrawable(Drawable background) { 25261 computeOpaqueFlags(); 25262 25263 if (background == mBackground) { 25264 return; 25265 } 25266 25267 boolean requestLayout = false; 25268 25269 mBackgroundResource = 0; 25270 25271 /* 25272 * Regardless of whether we're setting a new background or not, we want 25273 * to clear the previous drawable. setVisible first while we still have the callback set. 25274 */ 25275 if (mBackground != null) { 25276 if (isAttachedToWindow()) { 25277 mBackground.setVisible(false, false); 25278 } 25279 mBackground.setCallback(null); 25280 unscheduleDrawable(mBackground); 25281 } 25282 25283 if (background != null) { 25284 Rect padding = sThreadLocal.get(); 25285 if (padding == null) { 25286 padding = new Rect(); 25287 sThreadLocal.set(padding); 25288 } 25289 resetResolvedDrawablesInternal(); 25290 background.setLayoutDirection(getLayoutDirection()); 25291 if (background.getPadding(padding)) { 25292 resetResolvedPaddingInternal(); 25293 switch (background.getLayoutDirection()) { 25294 case LAYOUT_DIRECTION_RTL: 25295 mUserPaddingLeftInitial = padding.right; 25296 mUserPaddingRightInitial = padding.left; 25297 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 25298 break; 25299 case LAYOUT_DIRECTION_LTR: 25300 default: 25301 mUserPaddingLeftInitial = padding.left; 25302 mUserPaddingRightInitial = padding.right; 25303 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 25304 } 25305 mLeftPaddingDefined = false; 25306 mRightPaddingDefined = false; 25307 } 25308 25309 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 25310 // if it has a different minimum size, we should layout again 25311 if (mBackground == null 25312 || mBackground.getMinimumHeight() != background.getMinimumHeight() 25313 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 25314 requestLayout = true; 25315 } 25316 25317 // Set mBackground before we set this as the callback and start making other 25318 // background drawable state change calls. In particular, the setVisible call below 25319 // can result in drawables attempting to start animations or otherwise invalidate, 25320 // which requires the view set as the callback (us) to recognize the drawable as 25321 // belonging to it as per verifyDrawable. 25322 mBackground = background; 25323 if (background.isStateful()) { 25324 background.setState(getDrawableState()); 25325 } 25326 if (isAttachedToWindow()) { 25327 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 25328 } 25329 25330 applyBackgroundTint(); 25331 25332 // Set callback last, since the view may still be initializing. 25333 background.setCallback(this); 25334 25335 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 25336 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 25337 requestLayout = true; 25338 } 25339 } else { 25340 /* Remove the background */ 25341 mBackground = null; 25342 if ((mViewFlags & WILL_NOT_DRAW) != 0 25343 && (mDefaultFocusHighlight == null) 25344 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 25345 mPrivateFlags |= PFLAG_SKIP_DRAW; 25346 } 25347 25348 /* 25349 * When the background is set, we try to apply its padding to this 25350 * View. When the background is removed, we don't touch this View's 25351 * padding. This is noted in the Javadocs. Hence, we don't need to 25352 * requestLayout(), the invalidate() below is sufficient. 25353 */ 25354 25355 // The old background's minimum size could have affected this 25356 // View's layout, so let's requestLayout 25357 requestLayout = true; 25358 } 25359 25360 computeOpaqueFlags(); 25361 25362 if (requestLayout) { 25363 requestLayout(); 25364 } 25365 25366 mBackgroundSizeChanged = true; 25367 invalidate(true); 25368 invalidateOutline(); 25369 } 25370 25371 /** 25372 * Gets the background drawable 25373 * 25374 * @return The drawable used as the background for this view, if any. 25375 * 25376 * @see #setBackground(Drawable) 25377 * 25378 * @attr ref android.R.styleable#View_background 25379 */ 25380 @InspectableProperty getBackground()25381 public Drawable getBackground() { 25382 return mBackground; 25383 } 25384 25385 /** 25386 * Applies a tint to the background drawable. Does not modify the current tint 25387 * mode, which is {@link BlendMode#SRC_IN} by default. 25388 * <p> 25389 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 25390 * mutate the drawable and apply the specified tint and tint mode using 25391 * {@link Drawable#setTintList(ColorStateList)}. 25392 * 25393 * @param tint the tint to apply, may be {@code null} to clear tint 25394 * 25395 * @attr ref android.R.styleable#View_backgroundTint 25396 * @see #getBackgroundTintList() 25397 * @see Drawable#setTintList(ColorStateList) 25398 */ 25399 @RemotableViewMethod setBackgroundTintList(@ullable ColorStateList tint)25400 public void setBackgroundTintList(@Nullable ColorStateList tint) { 25401 if (mBackgroundTint == null) { 25402 mBackgroundTint = new TintInfo(); 25403 } 25404 mBackgroundTint.mTintList = tint; 25405 mBackgroundTint.mHasTintList = true; 25406 25407 applyBackgroundTint(); 25408 } 25409 25410 /** 25411 * Return the tint applied to the background drawable, if specified. 25412 * 25413 * @return the tint applied to the background drawable 25414 * @attr ref android.R.styleable#View_backgroundTint 25415 * @see #setBackgroundTintList(ColorStateList) 25416 */ 25417 @InspectableProperty(name = "backgroundTint") 25418 @Nullable getBackgroundTintList()25419 public ColorStateList getBackgroundTintList() { 25420 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 25421 } 25422 25423 /** 25424 * Specifies the blending mode used to apply the tint specified by 25425 * {@link #setBackgroundTintList(ColorStateList)}} to the background 25426 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 25427 * 25428 * @param tintMode the blending mode used to apply the tint, may be 25429 * {@code null} to clear tint 25430 * @attr ref android.R.styleable#View_backgroundTintMode 25431 * @see #getBackgroundTintMode() 25432 * @see Drawable#setTintMode(PorterDuff.Mode) 25433 */ setBackgroundTintMode(@ullable PorterDuff.Mode tintMode)25434 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 25435 BlendMode mode = null; 25436 if (tintMode != null) { 25437 mode = BlendMode.fromValue(tintMode.nativeInt); 25438 } 25439 25440 setBackgroundTintBlendMode(mode); 25441 } 25442 25443 /** 25444 * Specifies the blending mode used to apply the tint specified by 25445 * {@link #setBackgroundTintList(ColorStateList)}} to the background 25446 * drawable. The default mode is {@link BlendMode#SRC_IN}. 25447 * 25448 * @param blendMode the blending mode used to apply the tint, may be 25449 * {@code null} to clear tint 25450 * @attr ref android.R.styleable#View_backgroundTintMode 25451 * @see #getBackgroundTintMode() 25452 * @see Drawable#setTintBlendMode(BlendMode) 25453 */ 25454 @RemotableViewMethod setBackgroundTintBlendMode(@ullable BlendMode blendMode)25455 public void setBackgroundTintBlendMode(@Nullable BlendMode blendMode) { 25456 if (mBackgroundTint == null) { 25457 mBackgroundTint = new TintInfo(); 25458 } 25459 25460 mBackgroundTint.mBlendMode = blendMode; 25461 mBackgroundTint.mHasTintMode = true; 25462 25463 applyBackgroundTint(); 25464 } 25465 25466 /** 25467 * Return the blending mode used to apply the tint to the background 25468 * drawable, if specified. 25469 * 25470 * @return the blending mode used to apply the tint to the background 25471 * drawable 25472 * @attr ref android.R.styleable#View_backgroundTintMode 25473 * @see #setBackgroundTintBlendMode(BlendMode) 25474 * 25475 */ 25476 @Nullable 25477 @InspectableProperty getBackgroundTintMode()25478 public PorterDuff.Mode getBackgroundTintMode() { 25479 PorterDuff.Mode porterDuffMode; 25480 if (mBackgroundTint != null && mBackgroundTint.mBlendMode != null) { 25481 porterDuffMode = BlendMode.blendModeToPorterDuffMode(mBackgroundTint.mBlendMode); 25482 } else { 25483 porterDuffMode = null; 25484 } 25485 return porterDuffMode; 25486 } 25487 25488 /** 25489 * Return the blending mode used to apply the tint to the background 25490 * drawable, if specified. 25491 * 25492 * @return the blending mode used to apply the tint to the background 25493 * drawable, null if no blend has previously been configured 25494 * @attr ref android.R.styleable#View_backgroundTintMode 25495 * @see #setBackgroundTintBlendMode(BlendMode) 25496 */ getBackgroundTintBlendMode()25497 public @Nullable BlendMode getBackgroundTintBlendMode() { 25498 return mBackgroundTint != null ? mBackgroundTint.mBlendMode : null; 25499 } 25500 applyBackgroundTint()25501 private void applyBackgroundTint() { 25502 if (mBackground != null && mBackgroundTint != null) { 25503 final TintInfo tintInfo = mBackgroundTint; 25504 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 25505 mBackground = mBackground.mutate(); 25506 25507 if (tintInfo.mHasTintList) { 25508 mBackground.setTintList(tintInfo.mTintList); 25509 } 25510 25511 if (tintInfo.mHasTintMode) { 25512 mBackground.setTintBlendMode(tintInfo.mBlendMode); 25513 } 25514 25515 // The drawable (or one of its children) may not have been 25516 // stateful before applying the tint, so let's try again. 25517 if (mBackground.isStateful()) { 25518 mBackground.setState(getDrawableState()); 25519 } 25520 } 25521 } 25522 } 25523 25524 /** 25525 * Returns the drawable used as the foreground of this View. The 25526 * foreground drawable, if non-null, is always drawn on top of the view's content. 25527 * 25528 * @return a Drawable or null if no foreground was set 25529 * 25530 * @see #onDrawForeground(Canvas) 25531 */ 25532 @InspectableProperty getForeground()25533 public Drawable getForeground() { 25534 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 25535 } 25536 25537 /** 25538 * Supply a Drawable that is to be rendered on top of all of the content in the view. 25539 * 25540 * @param foreground the Drawable to be drawn on top of the children 25541 * 25542 * @attr ref android.R.styleable#View_foreground 25543 */ setForeground(Drawable foreground)25544 public void setForeground(Drawable foreground) { 25545 if (mForegroundInfo == null) { 25546 if (foreground == null) { 25547 // Nothing to do. 25548 return; 25549 } 25550 mForegroundInfo = new ForegroundInfo(); 25551 } 25552 25553 if (foreground == mForegroundInfo.mDrawable) { 25554 // Nothing to do 25555 return; 25556 } 25557 25558 if (mForegroundInfo.mDrawable != null) { 25559 if (isAttachedToWindow()) { 25560 mForegroundInfo.mDrawable.setVisible(false, false); 25561 } 25562 mForegroundInfo.mDrawable.setCallback(null); 25563 unscheduleDrawable(mForegroundInfo.mDrawable); 25564 } 25565 25566 mForegroundInfo.mDrawable = foreground; 25567 mForegroundInfo.mBoundsChanged = true; 25568 if (foreground != null) { 25569 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 25570 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 25571 } 25572 foreground.setLayoutDirection(getLayoutDirection()); 25573 if (foreground.isStateful()) { 25574 foreground.setState(getDrawableState()); 25575 } 25576 applyForegroundTint(); 25577 if (isAttachedToWindow()) { 25578 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 25579 } 25580 // Set callback last, since the view may still be initializing. 25581 foreground.setCallback(this); 25582 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 25583 && (mDefaultFocusHighlight == null)) { 25584 mPrivateFlags |= PFLAG_SKIP_DRAW; 25585 } 25586 requestLayout(); 25587 invalidate(); 25588 } 25589 25590 /** 25591 * Magic bit used to support features of framework-internal window decor implementation details. 25592 * This used to live exclusively in FrameLayout. 25593 * 25594 * @return true if the foreground should draw inside the padding region or false 25595 * if it should draw inset by the view's padding 25596 * @hide internal use only; only used by FrameLayout and internal screen layouts. 25597 */ isForegroundInsidePadding()25598 public boolean isForegroundInsidePadding() { 25599 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 25600 } 25601 25602 /** 25603 * Describes how the foreground is positioned. 25604 * 25605 * @return foreground gravity. 25606 * 25607 * @see #setForegroundGravity(int) 25608 * 25609 * @attr ref android.R.styleable#View_foregroundGravity 25610 */ 25611 @InspectableProperty(valueType = InspectableProperty.ValueType.GRAVITY) getForegroundGravity()25612 public int getForegroundGravity() { 25613 return mForegroundInfo != null ? mForegroundInfo.mGravity 25614 : Gravity.START | Gravity.TOP; 25615 } 25616 25617 /** 25618 * Describes how the foreground is positioned. Defaults to START and TOP. 25619 * 25620 * @param gravity see {@link android.view.Gravity} 25621 * 25622 * @see #getForegroundGravity() 25623 * 25624 * @attr ref android.R.styleable#View_foregroundGravity 25625 */ setForegroundGravity(int gravity)25626 public void setForegroundGravity(int gravity) { 25627 if (mForegroundInfo == null) { 25628 mForegroundInfo = new ForegroundInfo(); 25629 } 25630 25631 if (mForegroundInfo.mGravity != gravity) { 25632 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 25633 gravity |= Gravity.START; 25634 } 25635 25636 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 25637 gravity |= Gravity.TOP; 25638 } 25639 25640 mForegroundInfo.mGravity = gravity; 25641 requestLayout(); 25642 } 25643 } 25644 25645 /** 25646 * Applies a tint to the foreground drawable. Does not modify the current tint 25647 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 25648 * <p> 25649 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 25650 * mutate the drawable and apply the specified tint and tint mode using 25651 * {@link Drawable#setTintList(ColorStateList)}. 25652 * 25653 * @param tint the tint to apply, may be {@code null} to clear tint 25654 * 25655 * @attr ref android.R.styleable#View_foregroundTint 25656 * @see #getForegroundTintList() 25657 * @see Drawable#setTintList(ColorStateList) 25658 */ 25659 @RemotableViewMethod setForegroundTintList(@ullable ColorStateList tint)25660 public void setForegroundTintList(@Nullable ColorStateList tint) { 25661 if (mForegroundInfo == null) { 25662 mForegroundInfo = new ForegroundInfo(); 25663 } 25664 if (mForegroundInfo.mTintInfo == null) { 25665 mForegroundInfo.mTintInfo = new TintInfo(); 25666 } 25667 mForegroundInfo.mTintInfo.mTintList = tint; 25668 mForegroundInfo.mTintInfo.mHasTintList = true; 25669 25670 applyForegroundTint(); 25671 } 25672 25673 /** 25674 * Return the tint applied to the foreground drawable, if specified. 25675 * 25676 * @return the tint applied to the foreground drawable 25677 * @attr ref android.R.styleable#View_foregroundTint 25678 * @see #setForegroundTintList(ColorStateList) 25679 */ 25680 @InspectableProperty(name = "foregroundTint") 25681 @Nullable getForegroundTintList()25682 public ColorStateList getForegroundTintList() { 25683 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 25684 ? mForegroundInfo.mTintInfo.mTintList : null; 25685 } 25686 25687 /** 25688 * Specifies the blending mode used to apply the tint specified by 25689 * {@link #setForegroundTintList(ColorStateList)}} to the background 25690 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 25691 * 25692 * @param tintMode the blending mode used to apply the tint, may be 25693 * {@code null} to clear tint 25694 * @attr ref android.R.styleable#View_foregroundTintMode 25695 * @see #getForegroundTintMode() 25696 * @see Drawable#setTintMode(PorterDuff.Mode) 25697 * 25698 */ setForegroundTintMode(@ullable PorterDuff.Mode tintMode)25699 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 25700 BlendMode mode = null; 25701 if (tintMode != null) { 25702 mode = BlendMode.fromValue(tintMode.nativeInt); 25703 } 25704 setForegroundTintBlendMode(mode); 25705 } 25706 25707 /** 25708 * Specifies the blending mode used to apply the tint specified by 25709 * {@link #setForegroundTintList(ColorStateList)}} to the background 25710 * drawable. The default mode is {@link BlendMode#SRC_IN}. 25711 * 25712 * @param blendMode the blending mode used to apply the tint, may be 25713 * {@code null} to clear tint 25714 * @attr ref android.R.styleable#View_foregroundTintMode 25715 * @see #getForegroundTintMode() 25716 * @see Drawable#setTintBlendMode(BlendMode) 25717 */ 25718 @RemotableViewMethod setForegroundTintBlendMode(@ullable BlendMode blendMode)25719 public void setForegroundTintBlendMode(@Nullable BlendMode blendMode) { 25720 if (mForegroundInfo == null) { 25721 mForegroundInfo = new ForegroundInfo(); 25722 } 25723 if (mForegroundInfo.mTintInfo == null) { 25724 mForegroundInfo.mTintInfo = new TintInfo(); 25725 } 25726 mForegroundInfo.mTintInfo.mBlendMode = blendMode; 25727 mForegroundInfo.mTintInfo.mHasTintMode = true; 25728 25729 applyForegroundTint(); 25730 } 25731 25732 /** 25733 * Return the blending mode used to apply the tint to the foreground 25734 * drawable, if specified. 25735 * 25736 * @return the blending mode used to apply the tint to the foreground 25737 * drawable 25738 * @attr ref android.R.styleable#View_foregroundTintMode 25739 * @see #setForegroundTintMode(PorterDuff.Mode) 25740 */ 25741 @InspectableProperty 25742 @Nullable getForegroundTintMode()25743 public PorterDuff.Mode getForegroundTintMode() { 25744 BlendMode blendMode = mForegroundInfo != null && mForegroundInfo.mTintInfo != null 25745 ? mForegroundInfo.mTintInfo.mBlendMode : null; 25746 if (blendMode != null) { 25747 return BlendMode.blendModeToPorterDuffMode(blendMode); 25748 } else { 25749 return null; 25750 } 25751 } 25752 25753 /** 25754 * Return the blending mode used to apply the tint to the foreground 25755 * drawable, if specified. 25756 * 25757 * @return the blending mode used to apply the tint to the foreground 25758 * drawable 25759 * @attr ref android.R.styleable#View_foregroundTintMode 25760 * @see #setForegroundTintBlendMode(BlendMode) 25761 * 25762 */ getForegroundTintBlendMode()25763 public @Nullable BlendMode getForegroundTintBlendMode() { 25764 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 25765 ? mForegroundInfo.mTintInfo.mBlendMode : null; 25766 } 25767 applyForegroundTint()25768 private void applyForegroundTint() { 25769 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 25770 && mForegroundInfo.mTintInfo != null) { 25771 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 25772 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 25773 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 25774 25775 if (tintInfo.mHasTintList) { 25776 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 25777 } 25778 25779 if (tintInfo.mHasTintMode) { 25780 mForegroundInfo.mDrawable.setTintBlendMode(tintInfo.mBlendMode); 25781 } 25782 25783 // The drawable (or one of its children) may not have been 25784 // stateful before applying the tint, so let's try again. 25785 if (mForegroundInfo.mDrawable.isStateful()) { 25786 mForegroundInfo.mDrawable.setState(getDrawableState()); 25787 } 25788 } 25789 } 25790 } 25791 25792 /** 25793 * Get the drawable to be overlayed when a view is autofilled 25794 * 25795 * @return The drawable 25796 * 25797 * @throws IllegalStateException if the drawable could not be found. 25798 */ getAutofilledDrawable()25799 @Nullable private Drawable getAutofilledDrawable() { 25800 if (mAttachInfo == null) { 25801 return null; 25802 } 25803 // Lazily load the isAutofilled drawable. 25804 if (mAttachInfo.mAutofilledDrawable == null) { 25805 Context rootContext = getRootView().getContext(); 25806 TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR); 25807 int attributeResourceId = a.getResourceId(0, 0); 25808 mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId); 25809 a.recycle(); 25810 } 25811 25812 return mAttachInfo.mAutofilledDrawable; 25813 } 25814 25815 /** 25816 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled, unless 25817 * {@link #PFLAG4_AUTOFILL_HIDE_HIGHLIGHT} is enabled. 25818 * 25819 * @param canvas The canvas to draw on 25820 */ drawAutofilledHighlight(@onNull Canvas canvas)25821 private void drawAutofilledHighlight(@NonNull Canvas canvas) { 25822 if (isAutofilled() && !hideAutofillHighlight()) { 25823 Drawable autofilledHighlight = getAutofilledDrawable(); 25824 25825 if (autofilledHighlight != null) { 25826 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); 25827 autofilledHighlight.draw(canvas); 25828 } 25829 } 25830 } 25831 25832 /** 25833 * Draw any foreground content for this view. 25834 * 25835 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 25836 * drawable or other view-specific decorations. The foreground is drawn on top of the 25837 * primary view content.</p> 25838 * 25839 * @param canvas canvas to draw into 25840 */ onDrawForeground(@onNull Canvas canvas)25841 public void onDrawForeground(@NonNull Canvas canvas) { 25842 onDrawScrollIndicators(canvas); 25843 onDrawScrollBars(canvas); 25844 25845 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 25846 if (foreground != null) { 25847 if (mForegroundInfo.mBoundsChanged) { 25848 mForegroundInfo.mBoundsChanged = false; 25849 final Rect selfBounds = mForegroundInfo.mSelfBounds; 25850 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 25851 25852 if (mForegroundInfo.mInsidePadding) { 25853 selfBounds.set(0, 0, getWidth(), getHeight()); 25854 } else { 25855 selfBounds.set(getPaddingLeft(), getPaddingTop(), 25856 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 25857 } 25858 25859 final int ld = getLayoutDirection(); 25860 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 25861 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 25862 foreground.setBounds(overlayBounds); 25863 } 25864 25865 foreground.draw(canvas); 25866 } 25867 } 25868 25869 /** 25870 * Sets the padding. The view may add on the space required to display 25871 * the scrollbars, depending on the style and visibility of the scrollbars. 25872 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 25873 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 25874 * from the values set in this call. 25875 * 25876 * @attr ref android.R.styleable#View_padding 25877 * @attr ref android.R.styleable#View_paddingBottom 25878 * @attr ref android.R.styleable#View_paddingLeft 25879 * @attr ref android.R.styleable#View_paddingRight 25880 * @attr ref android.R.styleable#View_paddingTop 25881 * @param left the left padding in pixels 25882 * @param top the top padding in pixels 25883 * @param right the right padding in pixels 25884 * @param bottom the bottom padding in pixels 25885 */ setPadding(int left, int top, int right, int bottom)25886 public void setPadding(int left, int top, int right, int bottom) { 25887 resetResolvedPaddingInternal(); 25888 25889 mUserPaddingStart = UNDEFINED_PADDING; 25890 mUserPaddingEnd = UNDEFINED_PADDING; 25891 25892 mUserPaddingLeftInitial = left; 25893 mUserPaddingRightInitial = right; 25894 25895 mLeftPaddingDefined = true; 25896 mRightPaddingDefined = true; 25897 25898 internalSetPadding(left, top, right, bottom); 25899 } 25900 25901 /** 25902 * @hide 25903 */ 25904 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768420) internalSetPadding(int left, int top, int right, int bottom)25905 protected void internalSetPadding(int left, int top, int right, int bottom) { 25906 mUserPaddingLeft = left; 25907 mUserPaddingRight = right; 25908 mUserPaddingBottom = bottom; 25909 25910 final int viewFlags = mViewFlags; 25911 boolean changed = false; 25912 25913 // Common case is there are no scroll bars. 25914 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 25915 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 25916 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 25917 ? 0 : getVerticalScrollbarWidth(); 25918 switch (mVerticalScrollbarPosition) { 25919 case SCROLLBAR_POSITION_DEFAULT: 25920 if (isLayoutRtl()) { 25921 left += offset; 25922 } else { 25923 right += offset; 25924 } 25925 break; 25926 case SCROLLBAR_POSITION_RIGHT: 25927 right += offset; 25928 break; 25929 case SCROLLBAR_POSITION_LEFT: 25930 left += offset; 25931 break; 25932 } 25933 } 25934 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 25935 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 25936 ? 0 : getHorizontalScrollbarHeight(); 25937 } 25938 } 25939 25940 if (mPaddingLeft != left) { 25941 changed = true; 25942 mPaddingLeft = left; 25943 } 25944 if (mPaddingTop != top) { 25945 changed = true; 25946 mPaddingTop = top; 25947 } 25948 if (mPaddingRight != right) { 25949 changed = true; 25950 mPaddingRight = right; 25951 } 25952 if (mPaddingBottom != bottom) { 25953 changed = true; 25954 mPaddingBottom = bottom; 25955 } 25956 25957 if (changed) { 25958 requestLayout(); 25959 invalidateOutline(); 25960 } 25961 } 25962 25963 /** 25964 * Sets the relative padding. The view may add on the space required to display 25965 * the scrollbars, depending on the style and visibility of the scrollbars. 25966 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 25967 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 25968 * from the values set in this call. 25969 * 25970 * @attr ref android.R.styleable#View_padding 25971 * @attr ref android.R.styleable#View_paddingBottom 25972 * @attr ref android.R.styleable#View_paddingStart 25973 * @attr ref android.R.styleable#View_paddingEnd 25974 * @attr ref android.R.styleable#View_paddingTop 25975 * @param start the start padding in pixels 25976 * @param top the top padding in pixels 25977 * @param end the end padding in pixels 25978 * @param bottom the bottom padding in pixels 25979 */ setPaddingRelative(int start, int top, int end, int bottom)25980 public void setPaddingRelative(int start, int top, int end, int bottom) { 25981 resetResolvedPaddingInternal(); 25982 25983 mUserPaddingStart = start; 25984 mUserPaddingEnd = end; 25985 mLeftPaddingDefined = true; 25986 mRightPaddingDefined = true; 25987 25988 switch(getLayoutDirection()) { 25989 case LAYOUT_DIRECTION_RTL: 25990 mUserPaddingLeftInitial = end; 25991 mUserPaddingRightInitial = start; 25992 internalSetPadding(end, top, start, bottom); 25993 break; 25994 case LAYOUT_DIRECTION_LTR: 25995 default: 25996 mUserPaddingLeftInitial = start; 25997 mUserPaddingRightInitial = end; 25998 internalSetPadding(start, top, end, bottom); 25999 } 26000 } 26001 26002 /** 26003 * A {@link View} can be inflated from an XML layout. For such Views this method returns the 26004 * resource ID of the source layout. 26005 * 26006 * @return The layout resource id if this view was inflated from XML, otherwise 26007 * {@link Resources#ID_NULL}. 26008 */ 26009 @LayoutRes getSourceLayoutResId()26010 public int getSourceLayoutResId() { 26011 return mSourceLayoutId; 26012 } 26013 26014 /** 26015 * Returns the top padding of this view. 26016 * 26017 * @return the top padding in pixels 26018 */ 26019 @InspectableProperty getPaddingTop()26020 public int getPaddingTop() { 26021 return mPaddingTop; 26022 } 26023 26024 /** 26025 * Returns the bottom padding of this view. If there are inset and enabled 26026 * scrollbars, this value may include the space required to display the 26027 * scrollbars as well. 26028 * 26029 * @return the bottom padding in pixels 26030 */ 26031 @InspectableProperty getPaddingBottom()26032 public int getPaddingBottom() { 26033 return mPaddingBottom; 26034 } 26035 26036 /** 26037 * Returns the left padding of this view. If there are inset and enabled 26038 * scrollbars, this value may include the space required to display the 26039 * scrollbars as well. 26040 * 26041 * @return the left padding in pixels 26042 */ 26043 @InspectableProperty getPaddingLeft()26044 public int getPaddingLeft() { 26045 if (!isPaddingResolved()) { 26046 resolvePadding(); 26047 } 26048 return mPaddingLeft; 26049 } 26050 26051 /** 26052 * Returns the start padding of this view depending on its resolved layout direction. 26053 * If there are inset and enabled scrollbars, this value may include the space 26054 * required to display the scrollbars as well. 26055 * 26056 * @return the start padding in pixels 26057 */ getPaddingStart()26058 public int getPaddingStart() { 26059 if (!isPaddingResolved()) { 26060 resolvePadding(); 26061 } 26062 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 26063 mPaddingRight : mPaddingLeft; 26064 } 26065 26066 /** 26067 * Returns the right padding of this view. If there are inset and enabled 26068 * scrollbars, this value may include the space required to display the 26069 * scrollbars as well. 26070 * 26071 * @return the right padding in pixels 26072 */ 26073 @InspectableProperty getPaddingRight()26074 public int getPaddingRight() { 26075 if (!isPaddingResolved()) { 26076 resolvePadding(); 26077 } 26078 return mPaddingRight; 26079 } 26080 26081 /** 26082 * Returns the end padding of this view depending on its resolved layout direction. 26083 * If there are inset and enabled scrollbars, this value may include the space 26084 * required to display the scrollbars as well. 26085 * 26086 * @return the end padding in pixels 26087 */ getPaddingEnd()26088 public int getPaddingEnd() { 26089 if (!isPaddingResolved()) { 26090 resolvePadding(); 26091 } 26092 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 26093 mPaddingLeft : mPaddingRight; 26094 } 26095 26096 /** 26097 * Return if the padding has been set through relative values 26098 * {@link #setPaddingRelative(int, int, int, int)} or through 26099 * @attr ref android.R.styleable#View_paddingStart or 26100 * @attr ref android.R.styleable#View_paddingEnd 26101 * 26102 * @return true if the padding is relative or false if it is not. 26103 */ isPaddingRelative()26104 public boolean isPaddingRelative() { 26105 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 26106 } 26107 computeOpticalInsets()26108 Insets computeOpticalInsets() { 26109 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 26110 } 26111 26112 /** 26113 * @hide 26114 */ 26115 @UnsupportedAppUsage resetPaddingToInitialValues()26116 public void resetPaddingToInitialValues() { 26117 if (isRtlCompatibilityMode()) { 26118 mPaddingLeft = mUserPaddingLeftInitial; 26119 mPaddingRight = mUserPaddingRightInitial; 26120 return; 26121 } 26122 if (isLayoutRtl()) { 26123 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 26124 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 26125 } else { 26126 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 26127 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 26128 } 26129 } 26130 26131 /** 26132 * @hide 26133 */ getOpticalInsets()26134 public Insets getOpticalInsets() { 26135 if (mLayoutInsets == null) { 26136 mLayoutInsets = computeOpticalInsets(); 26137 } 26138 return mLayoutInsets; 26139 } 26140 26141 /** 26142 * Set this view's optical insets. 26143 * 26144 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 26145 * property. Views that compute their own optical insets should call it as part of measurement. 26146 * This method does not request layout. If you are setting optical insets outside of 26147 * measure/layout itself you will want to call requestLayout() yourself. 26148 * </p> 26149 * @hide 26150 */ setOpticalInsets(Insets insets)26151 public void setOpticalInsets(Insets insets) { 26152 mLayoutInsets = insets; 26153 } 26154 26155 /** 26156 * Changes the selection state of this view. A view can be selected or not. 26157 * Note that selection is not the same as focus. Views are typically 26158 * selected in the context of an AdapterView like ListView or GridView; 26159 * the selected view is the view that is highlighted. 26160 * 26161 * @param selected true if the view must be selected, false otherwise 26162 */ setSelected(boolean selected)26163 public void setSelected(boolean selected) { 26164 //noinspection DoubleNegation 26165 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 26166 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 26167 if (!selected) resetPressedState(); 26168 invalidate(true); 26169 refreshDrawableState(); 26170 dispatchSetSelected(selected); 26171 if (selected) { 26172 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 26173 } else { 26174 notifyViewAccessibilityStateChangedIfNeeded( 26175 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 26176 } 26177 } 26178 } 26179 26180 /** 26181 * Dispatch setSelected to all of this View's children. 26182 * 26183 * @see #setSelected(boolean) 26184 * 26185 * @param selected The new selected state 26186 */ dispatchSetSelected(boolean selected)26187 protected void dispatchSetSelected(boolean selected) { 26188 } 26189 26190 /** 26191 * Indicates the selection state of this view. 26192 * 26193 * @return true if the view is selected, false otherwise 26194 */ 26195 @ViewDebug.ExportedProperty 26196 @InspectableProperty(hasAttributeId = false) isSelected()26197 public boolean isSelected() { 26198 return (mPrivateFlags & PFLAG_SELECTED) != 0; 26199 } 26200 26201 /** 26202 * Changes the activated state of this view. A view can be activated or not. 26203 * Note that activation is not the same as selection. Selection is 26204 * a transient property, representing the view (hierarchy) the user is 26205 * currently interacting with. Activation is a longer-term state that the 26206 * user can move views in and out of. For example, in a list view with 26207 * single or multiple selection enabled, the views in the current selection 26208 * set are activated. (Um, yeah, we are deeply sorry about the terminology 26209 * here.) The activated state is propagated down to children of the view it 26210 * is set on. 26211 * 26212 * @param activated true if the view must be activated, false otherwise 26213 */ setActivated(boolean activated)26214 public void setActivated(boolean activated) { 26215 //noinspection DoubleNegation 26216 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 26217 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 26218 invalidate(true); 26219 refreshDrawableState(); 26220 dispatchSetActivated(activated); 26221 } 26222 } 26223 26224 /** 26225 * Dispatch setActivated to all of this View's children. 26226 * 26227 * @see #setActivated(boolean) 26228 * 26229 * @param activated The new activated state 26230 */ dispatchSetActivated(boolean activated)26231 protected void dispatchSetActivated(boolean activated) { 26232 } 26233 26234 /** 26235 * Indicates the activation state of this view. 26236 * 26237 * @return true if the view is activated, false otherwise 26238 */ 26239 @ViewDebug.ExportedProperty 26240 @InspectableProperty(hasAttributeId = false) isActivated()26241 public boolean isActivated() { 26242 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 26243 } 26244 26245 /** 26246 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 26247 * observer can be used to get notifications when global events, like 26248 * layout, happen. 26249 * 26250 * The returned ViewTreeObserver observer is not guaranteed to remain 26251 * valid for the lifetime of this View. If the caller of this method keeps 26252 * a long-lived reference to ViewTreeObserver, it should always check for 26253 * the return value of {@link ViewTreeObserver#isAlive()}. 26254 * 26255 * @return The ViewTreeObserver for this view's hierarchy. 26256 */ getViewTreeObserver()26257 public ViewTreeObserver getViewTreeObserver() { 26258 if (mAttachInfo != null) { 26259 return mAttachInfo.mTreeObserver; 26260 } 26261 if (mFloatingTreeObserver == null) { 26262 mFloatingTreeObserver = new ViewTreeObserver(mContext); 26263 } 26264 return mFloatingTreeObserver; 26265 } 26266 26267 /** 26268 * <p>Finds the topmost view in the current view hierarchy.</p> 26269 * 26270 * @return the topmost view containing this view 26271 */ getRootView()26272 public View getRootView() { 26273 if (mAttachInfo != null) { 26274 final View v = mAttachInfo.mRootView; 26275 if (v != null) { 26276 return v; 26277 } 26278 } 26279 26280 View parent = this; 26281 26282 while (parent.mParent instanceof View) { 26283 parent = (View) parent.mParent; 26284 } 26285 26286 return parent; 26287 } 26288 26289 /** 26290 * Transforms a motion event from view-local coordinates to on-screen 26291 * coordinates. 26292 * 26293 * @param ev the view-local motion event 26294 * @return false if the transformation could not be applied 26295 * @hide 26296 */ 26297 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) toGlobalMotionEvent(MotionEvent ev)26298 public boolean toGlobalMotionEvent(MotionEvent ev) { 26299 final AttachInfo info = mAttachInfo; 26300 if (info == null) { 26301 return false; 26302 } 26303 26304 final Matrix m = info.mTmpMatrix; 26305 m.set(Matrix.IDENTITY_MATRIX); 26306 transformMatrixToGlobal(m); 26307 ev.transform(m); 26308 return true; 26309 } 26310 26311 /** 26312 * Transforms a motion event from on-screen coordinates to view-local 26313 * coordinates. 26314 * 26315 * @param ev the on-screen motion event 26316 * @return false if the transformation could not be applied 26317 * @hide 26318 */ 26319 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) toLocalMotionEvent(MotionEvent ev)26320 public boolean toLocalMotionEvent(MotionEvent ev) { 26321 final AttachInfo info = mAttachInfo; 26322 if (info == null) { 26323 return false; 26324 } 26325 26326 final Matrix m = info.mTmpMatrix; 26327 m.set(Matrix.IDENTITY_MATRIX); 26328 transformMatrixToLocal(m); 26329 ev.transform(m); 26330 return true; 26331 } 26332 26333 /** 26334 * Modifies the input matrix such that it maps view-local coordinates to 26335 * on-screen coordinates. 26336 * 26337 * @param matrix input matrix to modify 26338 */ transformMatrixToGlobal(@onNull Matrix matrix)26339 public void transformMatrixToGlobal(@NonNull Matrix matrix) { 26340 final ViewParent parent = mParent; 26341 if (parent instanceof View) { 26342 final View vp = (View) parent; 26343 vp.transformMatrixToGlobal(matrix); 26344 matrix.preTranslate(-vp.mScrollX, -vp.mScrollY); 26345 } else if (parent instanceof ViewRootImpl) { 26346 final ViewRootImpl vr = (ViewRootImpl) parent; 26347 vr.transformMatrixToGlobal(matrix); 26348 matrix.preTranslate(0, -vr.mCurScrollY); 26349 } 26350 26351 matrix.preTranslate(mLeft, mTop); 26352 26353 if (!hasIdentityMatrix()) { 26354 matrix.preConcat(getMatrix()); 26355 } 26356 } 26357 26358 /** 26359 * Modifies the input matrix such that it maps on-screen coordinates to 26360 * view-local coordinates. 26361 * 26362 * @param matrix input matrix to modify 26363 */ transformMatrixToLocal(@onNull Matrix matrix)26364 public void transformMatrixToLocal(@NonNull Matrix matrix) { 26365 final ViewParent parent = mParent; 26366 if (parent instanceof View) { 26367 final View vp = (View) parent; 26368 vp.transformMatrixToLocal(matrix); 26369 matrix.postTranslate(vp.mScrollX, vp.mScrollY); 26370 } else if (parent instanceof ViewRootImpl) { 26371 final ViewRootImpl vr = (ViewRootImpl) parent; 26372 vr.transformMatrixToLocal(matrix); 26373 matrix.postTranslate(0, vr.mCurScrollY); 26374 } 26375 26376 matrix.postTranslate(-mLeft, -mTop); 26377 26378 if (!hasIdentityMatrix()) { 26379 matrix.postConcat(getInverseMatrix()); 26380 } 26381 } 26382 26383 /** 26384 * @hide 26385 */ 26386 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 26387 @ViewDebug.IntToString(from = 0, to = "x"), 26388 @ViewDebug.IntToString(from = 1, to = "y") 26389 }) 26390 @UnsupportedAppUsage getLocationOnScreen()26391 public int[] getLocationOnScreen() { 26392 int[] location = new int[2]; 26393 getLocationOnScreen(location); 26394 return location; 26395 } 26396 26397 /** 26398 * Gets the coordinates of this view in the coordinate space of the device 26399 * screen, irrespective of system decorations and whether the system is in 26400 * multi-window mode. 26401 * 26402 * <p>In multi-window mode, the coordinate space encompasses the entire 26403 * device screen, ignoring the bounds of the app window. For example, if the 26404 * view is in the bottom portion of a horizontal split screen, the top edge 26405 * of the screen—not the top edge of the window—is the origin 26406 * from which the y-coordinate is calculated. 26407 * 26408 * <p>In multiple-screen scenarios, the coordinate space can span screens. 26409 * For example, if the app is spanning both screens of a dual-screen device 26410 * and the view is located on the right-hand screen, the x-coordinate is 26411 * calculated from the left edge of the left-hand screen to the left edge of 26412 * the view. When the app is restricted to a single screen in a 26413 * multiple-screen environment, the coordinate space includes only the 26414 * screen on which the app is running. 26415 * 26416 * <p>After the method returns, the argument array contains the x and y 26417 * coordinates of the view relative to the view's left and top edges, 26418 * respectively. 26419 * 26420 * @param outLocation A two-element integer array in which the view 26421 * coordinates are stored. The x-coordinate is at index 0; the 26422 * y-coordinate, at index 1. 26423 */ getLocationOnScreen(@ize2) int[] outLocation)26424 public void getLocationOnScreen(@Size(2) int[] outLocation) { 26425 getLocationInWindow(outLocation); 26426 26427 final AttachInfo info = mAttachInfo; 26428 if (info != null) { 26429 outLocation[0] += info.mWindowLeft; 26430 outLocation[1] += info.mWindowTop; 26431 // If OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS override is enabled, 26432 // applyViewLocationSandboxingIfNeeded sandboxes outLocation within window bounds. 26433 info.mViewRootImpl.applyViewLocationSandboxingIfNeeded(outLocation); 26434 } 26435 } 26436 26437 /** 26438 * Gets the coordinates of this view in the coordinate space of the window 26439 * that contains the view, irrespective of system decorations. 26440 * 26441 * <p>In multi-window mode, the origin of the coordinate space is the 26442 * top left corner of the window that contains the view. In full screen 26443 * mode, the origin is the top left corner of the device screen. 26444 * 26445 * <p>In multiple-screen scenarios, if the app spans multiple screens, the 26446 * coordinate space also spans multiple screens. But if the app is 26447 * restricted to a single screen, the coordinate space includes only the 26448 * screen on which the app is running. 26449 * 26450 * <p>After the method returns, the argument array contains the x and y 26451 * coordinates of the view relative to the view's left and top edges, 26452 * respectively. 26453 * 26454 * @param outLocation A two-element integer array in which the view 26455 * coordinates are stored. The x-coordinate is at index 0; the 26456 * y-coordinate, at index 1. 26457 */ getLocationInWindow(@ize2) int[] outLocation)26458 public void getLocationInWindow(@Size(2) int[] outLocation) { 26459 if (outLocation == null || outLocation.length < 2) { 26460 throw new IllegalArgumentException("outLocation must be an array of two integers"); 26461 } 26462 26463 outLocation[0] = 0; 26464 outLocation[1] = 0; 26465 26466 transformFromViewToWindowSpace(outLocation); 26467 } 26468 26469 /** @hide */ transformFromViewToWindowSpace(@ize2) int[] inOutLocation)26470 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 26471 if (inOutLocation == null || inOutLocation.length < 2) { 26472 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 26473 } 26474 26475 if (mAttachInfo == null) { 26476 // When the view is not attached to a window, this method does not make sense 26477 inOutLocation[0] = inOutLocation[1] = 0; 26478 return; 26479 } 26480 26481 float position[] = mAttachInfo.mTmpTransformLocation; 26482 position[0] = inOutLocation[0]; 26483 position[1] = inOutLocation[1]; 26484 26485 if (!hasIdentityMatrix()) { 26486 getMatrix().mapPoints(position); 26487 } 26488 26489 position[0] += mLeft; 26490 position[1] += mTop; 26491 26492 ViewParent viewParent = mParent; 26493 while (viewParent instanceof View) { 26494 final View view = (View) viewParent; 26495 26496 position[0] -= view.mScrollX; 26497 position[1] -= view.mScrollY; 26498 26499 if (!view.hasIdentityMatrix()) { 26500 view.getMatrix().mapPoints(position); 26501 } 26502 26503 position[0] += view.mLeft; 26504 position[1] += view.mTop; 26505 26506 viewParent = view.mParent; 26507 } 26508 26509 if (viewParent instanceof ViewRootImpl) { 26510 // *cough* 26511 final ViewRootImpl vr = (ViewRootImpl) viewParent; 26512 position[1] -= vr.mCurScrollY; 26513 } 26514 26515 inOutLocation[0] = Math.round(position[0]); 26516 inOutLocation[1] = Math.round(position[1]); 26517 } 26518 26519 /** 26520 * @param id the id of the view to be found 26521 * @return the view of the specified id, null if cannot be found 26522 * @hide 26523 */ findViewTraversal(@dRes int id)26524 protected <T extends View> T findViewTraversal(@IdRes int id) { 26525 if (id == mID) { 26526 return (T) this; 26527 } 26528 return null; 26529 } 26530 26531 /** 26532 * @param tag the tag of the view to be found 26533 * @return the view of specified tag, null if cannot be found 26534 * @hide 26535 */ findViewWithTagTraversal(Object tag)26536 protected <T extends View> T findViewWithTagTraversal(Object tag) { 26537 if (tag != null && tag.equals(mTag)) { 26538 return (T) this; 26539 } 26540 return null; 26541 } 26542 26543 /** 26544 * @param predicate The predicate to evaluate. 26545 * @param childToSkip If not null, ignores this child during the recursive traversal. 26546 * @return The first view that matches the predicate or null. 26547 * @hide 26548 */ findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip)26549 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 26550 View childToSkip) { 26551 if (predicate.test(this)) { 26552 return (T) this; 26553 } 26554 return null; 26555 } 26556 26557 /** 26558 * Finds the first descendant view with the given ID, the view itself if 26559 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid 26560 * (< 0) or there is no matching view in the hierarchy. 26561 * <p> 26562 * <strong>Note:</strong> In most cases -- depending on compiler support -- 26563 * the resulting view is automatically cast to the target class type. If 26564 * the target class type is unconstrained, an explicit cast may be 26565 * necessary. 26566 * 26567 * @param id the ID to search for 26568 * @return a view with given ID if found, or {@code null} otherwise 26569 * @see View#requireViewById(int) 26570 */ 26571 @Nullable findViewById(@dRes int id)26572 public final <T extends View> T findViewById(@IdRes int id) { 26573 if (id == NO_ID) { 26574 return null; 26575 } 26576 return findViewTraversal(id); 26577 } 26578 26579 /** 26580 * Finds the first descendant view with the given ID, the view itself if the ID matches 26581 * {@link #getId()}, or throws an IllegalArgumentException if the ID is invalid or there is no 26582 * matching view in the hierarchy. 26583 * <p> 26584 * <strong>Note:</strong> In most cases -- depending on compiler support -- 26585 * the resulting view is automatically cast to the target class type. If 26586 * the target class type is unconstrained, an explicit cast may be 26587 * necessary. 26588 * 26589 * @param id the ID to search for 26590 * @return a view with given ID 26591 * @see View#findViewById(int) 26592 */ 26593 @NonNull requireViewById(@dRes int id)26594 public final <T extends View> T requireViewById(@IdRes int id) { 26595 T view = findViewById(id); 26596 if (view == null) { 26597 throw new IllegalArgumentException("ID does not reference a View inside this View"); 26598 } 26599 return view; 26600 } 26601 26602 /** 26603 * Performs the traversal to find a view by its unique and stable accessibility id. 26604 * 26605 * <strong>Note:</strong>This method does not stop at the root namespace 26606 * boundary since the user can touch the screen at an arbitrary location 26607 * potentially crossing the root namespace boundary which will send an 26608 * accessibility event to accessibility services and they should be able 26609 * to obtain the event source. Also accessibility ids are guaranteed to be 26610 * unique in the window. 26611 * 26612 * @param accessibilityId The accessibility id. 26613 * @return The found view. 26614 * @hide 26615 */ findViewByAccessibilityIdTraversal(int accessibilityId)26616 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 26617 if (getAccessibilityViewId() == accessibilityId) { 26618 return (T) this; 26619 } 26620 return null; 26621 } 26622 26623 /** 26624 * Performs the traversal to find a view by its autofill id. 26625 * 26626 * <strong>Note:</strong>This method does not stop at the root namespace 26627 * boundary. 26628 * 26629 * @param autofillId The autofill id. 26630 * @return The found view. 26631 * @hide 26632 */ findViewByAutofillIdTraversal(int autofillId)26633 public <T extends View> T findViewByAutofillIdTraversal(int autofillId) { 26634 if (getAutofillViewId() == autofillId) { 26635 return (T) this; 26636 } 26637 return null; 26638 } 26639 26640 /** 26641 * Look for a child view with the given tag. If this view has the given 26642 * tag, return this view. 26643 * 26644 * @param tag The tag to search for, using "tag.equals(getTag())". 26645 * @return The View that has the given tag in the hierarchy or null 26646 */ findViewWithTag(Object tag)26647 public final <T extends View> T findViewWithTag(Object tag) { 26648 if (tag == null) { 26649 return null; 26650 } 26651 return findViewWithTagTraversal(tag); 26652 } 26653 26654 /** 26655 * Look for a child view that matches the specified predicate. 26656 * If this view matches the predicate, return this view. 26657 * 26658 * @param predicate The predicate to evaluate. 26659 * @return The first view that matches the predicate or null. 26660 * @hide 26661 */ findViewByPredicate(Predicate<View> predicate)26662 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 26663 return findViewByPredicateTraversal(predicate, null); 26664 } 26665 26666 /** 26667 * Look for a child view that matches the specified predicate, 26668 * starting with the specified view and its descendents and then 26669 * recusively searching the ancestors and siblings of that view 26670 * until this view is reached. 26671 * 26672 * This method is useful in cases where the predicate does not match 26673 * a single unique view (perhaps multiple views use the same id) 26674 * and we are trying to find the view that is "closest" in scope to the 26675 * starting view. 26676 * 26677 * @param start The view to start from. 26678 * @param predicate The predicate to evaluate. 26679 * @return The first view that matches the predicate or null. 26680 * @hide 26681 */ findViewByPredicateInsideOut( View start, Predicate<View> predicate)26682 public final <T extends View> T findViewByPredicateInsideOut( 26683 View start, Predicate<View> predicate) { 26684 View childToSkip = null; 26685 for (;;) { 26686 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 26687 if (view != null || start == this) { 26688 return view; 26689 } 26690 26691 ViewParent parent = start.getParent(); 26692 if (parent == null || !(parent instanceof View)) { 26693 return null; 26694 } 26695 26696 childToSkip = start; 26697 start = (View) parent; 26698 } 26699 } 26700 26701 /** 26702 * Sets the identifier for this view. The identifier does not have to be 26703 * unique in this view's hierarchy. The identifier should be a positive 26704 * number. 26705 * 26706 * @see #NO_ID 26707 * @see #getId() 26708 * @see #findViewById(int) 26709 * 26710 * @param id a number used to identify the view 26711 * 26712 * @attr ref android.R.styleable#View_id 26713 */ setId(@dRes int id)26714 public void setId(@IdRes int id) { 26715 mID = id; 26716 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 26717 mID = generateViewId(); 26718 } 26719 } 26720 26721 /** 26722 * {@hide} 26723 * 26724 * @param isRoot true if the view belongs to the root namespace, false 26725 * otherwise 26726 */ 26727 @UnsupportedAppUsage 26728 @TestApi setIsRootNamespace(boolean isRoot)26729 public void setIsRootNamespace(boolean isRoot) { 26730 if (isRoot) { 26731 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 26732 } else { 26733 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 26734 } 26735 } 26736 26737 /** 26738 * {@hide} 26739 * 26740 * @return true if the view belongs to the root namespace, false otherwise 26741 */ 26742 @UnsupportedAppUsage isRootNamespace()26743 public boolean isRootNamespace() { 26744 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 26745 } 26746 26747 /** 26748 * Returns this view's identifier. 26749 * 26750 * @return a positive integer used to identify the view or {@link #NO_ID} 26751 * if the view has no ID 26752 * 26753 * @see #setId(int) 26754 * @see #findViewById(int) 26755 * @attr ref android.R.styleable#View_id 26756 */ 26757 @IdRes 26758 @ViewDebug.CapturedViewProperty 26759 @InspectableProperty getId()26760 public int getId() { 26761 return mID; 26762 } 26763 26764 /** 26765 * Get the identifier used for this view by the drawing system. 26766 * 26767 * @see RenderNode#getUniqueId() 26768 * @return A long that uniquely identifies this view's drawing component 26769 */ getUniqueDrawingId()26770 public long getUniqueDrawingId() { 26771 return mRenderNode.getUniqueId(); 26772 } 26773 26774 /** 26775 * Returns this view's tag. 26776 * 26777 * @return the Object stored in this view as a tag, or {@code null} if not 26778 * set 26779 * 26780 * @see #setTag(Object) 26781 * @see #getTag(int) 26782 */ 26783 @ViewDebug.ExportedProperty 26784 @InspectableProperty getTag()26785 public Object getTag() { 26786 return mTag; 26787 } 26788 26789 /** 26790 * Sets the tag associated with this view. A tag can be used to mark 26791 * a view in its hierarchy and does not have to be unique within the 26792 * hierarchy. Tags can also be used to store data within a view without 26793 * resorting to another data structure. 26794 * 26795 * @param tag an Object to tag the view with 26796 * 26797 * @see #getTag() 26798 * @see #setTag(int, Object) 26799 */ setTag(final Object tag)26800 public void setTag(final Object tag) { 26801 mTag = tag; 26802 } 26803 26804 /** 26805 * Returns the tag associated with this view and the specified key. 26806 * 26807 * @param key The key identifying the tag 26808 * 26809 * @return the Object stored in this view as a tag, or {@code null} if not 26810 * set 26811 * 26812 * @see #setTag(int, Object) 26813 * @see #getTag() 26814 */ getTag(int key)26815 public Object getTag(int key) { 26816 if (mKeyedTags != null) return mKeyedTags.get(key); 26817 return null; 26818 } 26819 26820 /** 26821 * Sets a tag associated with this view and a key. A tag can be used 26822 * to mark a view in its hierarchy and does not have to be unique within 26823 * the hierarchy. Tags can also be used to store data within a view 26824 * without resorting to another data structure. 26825 * 26826 * The specified key should be an id declared in the resources of the 26827 * application to ensure it is unique (see the <a 26828 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 26829 * Keys identified as belonging to 26830 * the Android framework or not associated with any package will cause 26831 * an {@link IllegalArgumentException} to be thrown. 26832 * 26833 * @param key The key identifying the tag 26834 * @param tag An Object to tag the view with 26835 * 26836 * @throws IllegalArgumentException If they specified key is not valid 26837 * 26838 * @see #setTag(Object) 26839 * @see #getTag(int) 26840 */ setTag(int key, final Object tag)26841 public void setTag(int key, final Object tag) { 26842 // If the package id is 0x00 or 0x01, it's either an undefined package 26843 // or a framework id 26844 if ((key >>> 24) < 2) { 26845 throw new IllegalArgumentException("The key must be an application-specific " 26846 + "resource id."); 26847 } 26848 26849 setKeyedTag(key, tag); 26850 } 26851 26852 /** 26853 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 26854 * framework id. 26855 * 26856 * @hide 26857 */ 26858 @UnsupportedAppUsage setTagInternal(int key, Object tag)26859 public void setTagInternal(int key, Object tag) { 26860 if ((key >>> 24) != 0x1) { 26861 throw new IllegalArgumentException("The key must be a framework-specific " 26862 + "resource id."); 26863 } 26864 26865 setKeyedTag(key, tag); 26866 } 26867 setKeyedTag(int key, Object tag)26868 private void setKeyedTag(int key, Object tag) { 26869 if (mKeyedTags == null) { 26870 mKeyedTags = new SparseArray<Object>(2); 26871 } 26872 26873 mKeyedTags.put(key, tag); 26874 } 26875 26876 /** 26877 * Prints information about this view in the log output, with the tag 26878 * {@link #VIEW_LOG_TAG}. 26879 * 26880 * @hide 26881 */ 26882 @UnsupportedAppUsage debug()26883 public void debug() { 26884 debug(0); 26885 } 26886 26887 /** 26888 * Prints information about this view in the log output, with the tag 26889 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 26890 * indentation defined by the <code>depth</code>. 26891 * 26892 * @param depth the indentation level 26893 * 26894 * @hide 26895 */ 26896 @UnsupportedAppUsage debug(int depth)26897 protected void debug(int depth) { 26898 String output = debugIndent(depth - 1); 26899 26900 output += "+ " + this; 26901 int id = getId(); 26902 if (id != -1) { 26903 output += " (id=" + id + ")"; 26904 } 26905 Object tag = getTag(); 26906 if (tag != null) { 26907 output += " (tag=" + tag + ")"; 26908 } 26909 Log.d(VIEW_LOG_TAG, output); 26910 26911 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 26912 output = debugIndent(depth) + " FOCUSED"; 26913 Log.d(VIEW_LOG_TAG, output); 26914 } 26915 26916 output = debugIndent(depth); 26917 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 26918 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 26919 + "} "; 26920 Log.d(VIEW_LOG_TAG, output); 26921 26922 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 26923 || mPaddingBottom != 0) { 26924 output = debugIndent(depth); 26925 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 26926 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 26927 Log.d(VIEW_LOG_TAG, output); 26928 } 26929 26930 output = debugIndent(depth); 26931 output += "mMeasureWidth=" + mMeasuredWidth + 26932 " mMeasureHeight=" + mMeasuredHeight; 26933 Log.d(VIEW_LOG_TAG, output); 26934 26935 output = debugIndent(depth); 26936 if (mLayoutParams == null) { 26937 output += "BAD! no layout params"; 26938 } else { 26939 output = mLayoutParams.debug(output); 26940 } 26941 Log.d(VIEW_LOG_TAG, output); 26942 26943 output = debugIndent(depth); 26944 output += "flags={"; 26945 output += View.printFlags(mViewFlags); 26946 output += "}"; 26947 Log.d(VIEW_LOG_TAG, output); 26948 26949 output = debugIndent(depth); 26950 output += "privateFlags={"; 26951 output += View.printPrivateFlags(mPrivateFlags); 26952 output += "}"; 26953 Log.d(VIEW_LOG_TAG, output); 26954 } 26955 26956 /** 26957 * Creates a string of whitespaces used for indentation. 26958 * 26959 * @param depth the indentation level 26960 * @return a String containing (depth * 2 + 3) * 2 white spaces 26961 * 26962 * @hide 26963 */ debugIndent(int depth)26964 protected static String debugIndent(int depth) { 26965 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 26966 for (int i = 0; i < (depth * 2) + 3; i++) { 26967 spaces.append(' ').append(' '); 26968 } 26969 return spaces.toString(); 26970 } 26971 26972 /** 26973 * <p>Return the offset of the widget's text baseline from the widget's top 26974 * boundary. If this widget does not support baseline alignment, this 26975 * method returns -1. </p> 26976 * 26977 * @return the offset of the baseline within the widget's bounds or -1 26978 * if baseline alignment is not supported 26979 */ 26980 @ViewDebug.ExportedProperty(category = "layout") 26981 @InspectableProperty getBaseline()26982 public int getBaseline() { 26983 return -1; 26984 } 26985 26986 /** 26987 * Returns whether the view hierarchy is currently undergoing a layout pass. This 26988 * information is useful to avoid situations such as calling {@link #requestLayout()} during 26989 * a layout pass. 26990 * 26991 * @return whether the view hierarchy is currently undergoing a layout pass 26992 */ isInLayout()26993 public boolean isInLayout() { 26994 ViewRootImpl viewRoot = getViewRootImpl(); 26995 return (viewRoot != null && viewRoot.isInLayout()); 26996 } 26997 26998 /** To be used only for debugging purposes. */ printStackStrace(String name)26999 private void printStackStrace(String name) { 27000 Log.d(VIEW_LOG_TAG, "---- ST:" + name); 27001 27002 StringBuilder sb = new StringBuilder(); 27003 StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); 27004 int startIndex = 1; 27005 int endIndex = Math.min(stackTraceElements.length, startIndex + 20); // max 20 entries. 27006 for (int i = startIndex; i < endIndex; i++) { 27007 StackTraceElement s = stackTraceElements[i]; 27008 sb.append(s.getMethodName()) 27009 .append("(") 27010 .append(s.getFileName()) 27011 .append(":") 27012 .append(s.getLineNumber()) 27013 .append(") <- "); 27014 } 27015 Log.d(VIEW_LOG_TAG, name + ": " + sb); 27016 } 27017 /** 27018 * Call this when something has changed which has invalidated the 27019 * layout of this view. This will schedule a layout pass of the view 27020 * tree. This should not be called while the view hierarchy is currently in a layout 27021 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 27022 * end of the current layout pass (and then layout will run again) or after the current 27023 * frame is drawn and the next layout occurs. 27024 * 27025 * <p>Subclasses which override this method should call the superclass method to 27026 * handle possible request-during-layout errors correctly.</p> 27027 */ 27028 @CallSuper requestLayout()27029 public void requestLayout() { 27030 if (isRelayoutTracingEnabled()) { 27031 Trace.instantForTrack(TRACE_TAG_APP, "requestLayoutTracing", 27032 mTracingStrings.classSimpleName); 27033 printStackStrace(mTracingStrings.requestLayoutStacktracePrefix); 27034 } 27035 27036 if (mMeasureCache != null) mMeasureCache.clear(); 27037 27038 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 27039 // Only trigger request-during-layout logic if this is the view requesting it, 27040 // not the views in its parent hierarchy 27041 ViewRootImpl viewRoot = getViewRootImpl(); 27042 if (viewRoot != null && viewRoot.isInLayout()) { 27043 if (!viewRoot.requestLayoutDuringLayout(this)) { 27044 return; 27045 } 27046 } 27047 mAttachInfo.mViewRequestingLayout = this; 27048 } 27049 27050 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 27051 mPrivateFlags |= PFLAG_INVALIDATED; 27052 27053 if (mParent != null && !mParent.isLayoutRequested()) { 27054 mParent.requestLayout(); 27055 } 27056 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 27057 mAttachInfo.mViewRequestingLayout = null; 27058 } 27059 } 27060 27061 /** 27062 * Forces this view to be laid out during the next layout pass. 27063 * This method does not call requestLayout() or forceLayout() 27064 * on the parent. 27065 */ forceLayout()27066 public void forceLayout() { 27067 if (mMeasureCache != null) mMeasureCache.clear(); 27068 27069 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 27070 mPrivateFlags |= PFLAG_INVALIDATED; 27071 } 27072 27073 /** 27074 * <p> 27075 * This is called to find out how big a view should be. The parent 27076 * supplies constraint information in the width and height parameters. 27077 * </p> 27078 * 27079 * <p> 27080 * The actual measurement work of a view is performed in 27081 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 27082 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 27083 * </p> 27084 * 27085 * 27086 * @param widthMeasureSpec Horizontal space requirements as imposed by the 27087 * parent 27088 * @param heightMeasureSpec Vertical space requirements as imposed by the 27089 * parent 27090 * 27091 * @see #onMeasure(int, int) 27092 */ measure(int widthMeasureSpec, int heightMeasureSpec)27093 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 27094 boolean optical = isLayoutModeOptical(this); 27095 if (optical != isLayoutModeOptical(mParent)) { 27096 Insets insets = getOpticalInsets(); 27097 int oWidth = insets.left + insets.right; 27098 int oHeight = insets.top + insets.bottom; 27099 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 27100 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 27101 } 27102 27103 // Suppress sign extension for the low bytes 27104 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 27105 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 27106 27107 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 27108 27109 // Optimize layout by avoiding an extra EXACTLY pass when the view is 27110 // already measured as the correct size. In API 23 and below, this 27111 // extra pass is required to make LinearLayout re-distribute weight. 27112 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 27113 || heightMeasureSpec != mOldHeightMeasureSpec; 27114 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 27115 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 27116 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 27117 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 27118 final boolean needsLayout = specChanged 27119 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 27120 27121 if (forceLayout || needsLayout) { 27122 // first clears the measured dimension flag 27123 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 27124 27125 resolveRtlPropertiesIfNeeded(); 27126 27127 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 27128 if (cacheIndex < 0 || sIgnoreMeasureCache) { 27129 if (isTraversalTracingEnabled()) { 27130 Trace.beginSection(mTracingStrings.onMeasure); 27131 } 27132 // measure ourselves, this should set the measured dimension flag back 27133 onMeasure(widthMeasureSpec, heightMeasureSpec); 27134 if (isTraversalTracingEnabled()) { 27135 Trace.endSection(); 27136 } 27137 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 27138 } else { 27139 long value = mMeasureCache.valueAt(cacheIndex); 27140 // Casting a long to int drops the high 32 bits, no mask needed 27141 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 27142 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 27143 } 27144 27145 // flag not set, setMeasuredDimension() was not invoked, we raise 27146 // an exception to warn the developer 27147 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 27148 throw new IllegalStateException("View with id " + getId() + ": " 27149 + getClass().getName() + "#onMeasure() did not set the" 27150 + " measured dimension by calling" 27151 + " setMeasuredDimension()"); 27152 } 27153 27154 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 27155 } 27156 27157 mOldWidthMeasureSpec = widthMeasureSpec; 27158 mOldHeightMeasureSpec = heightMeasureSpec; 27159 27160 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 27161 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 27162 } 27163 27164 /** 27165 * <p> 27166 * Measure the view and its content to determine the measured width and the 27167 * measured height. This method is invoked by {@link #measure(int, int)} and 27168 * should be overridden by subclasses to provide accurate and efficient 27169 * measurement of their contents. 27170 * </p> 27171 * 27172 * <p> 27173 * <strong>CONTRACT:</strong> When overriding this method, you 27174 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 27175 * measured width and height of this view. Failure to do so will trigger an 27176 * <code>IllegalStateException</code>, thrown by 27177 * {@link #measure(int, int)}. Calling the superclass' 27178 * {@link #onMeasure(int, int)} is a valid use. 27179 * </p> 27180 * 27181 * <p> 27182 * The base class implementation of measure defaults to the background size, 27183 * unless a larger size is allowed by the MeasureSpec. Subclasses should 27184 * override {@link #onMeasure(int, int)} to provide better measurements of 27185 * their content. 27186 * </p> 27187 * 27188 * <p> 27189 * If this method is overridden, it is the subclass's responsibility to make 27190 * sure the measured height and width are at least the view's minimum height 27191 * and width ({@link #getSuggestedMinimumHeight()} and 27192 * {@link #getSuggestedMinimumWidth()}). 27193 * </p> 27194 * 27195 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 27196 * The requirements are encoded with 27197 * {@link android.view.View.MeasureSpec}. 27198 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 27199 * The requirements are encoded with 27200 * {@link android.view.View.MeasureSpec}. 27201 * 27202 * @see #getMeasuredWidth() 27203 * @see #getMeasuredHeight() 27204 * @see #setMeasuredDimension(int, int) 27205 * @see #getSuggestedMinimumHeight() 27206 * @see #getSuggestedMinimumWidth() 27207 * @see android.view.View.MeasureSpec#getMode(int) 27208 * @see android.view.View.MeasureSpec#getSize(int) 27209 */ onMeasure(int widthMeasureSpec, int heightMeasureSpec)27210 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 27211 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 27212 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 27213 } 27214 27215 /** 27216 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 27217 * measured width and measured height. Failing to do so will trigger an 27218 * exception at measurement time.</p> 27219 * 27220 * @param measuredWidth The measured width of this view. May be a complex 27221 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 27222 * {@link #MEASURED_STATE_TOO_SMALL}. 27223 * @param measuredHeight The measured height of this view. May be a complex 27224 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 27225 * {@link #MEASURED_STATE_TOO_SMALL}. 27226 */ setMeasuredDimension(int measuredWidth, int measuredHeight)27227 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 27228 boolean optical = isLayoutModeOptical(this); 27229 if (optical != isLayoutModeOptical(mParent)) { 27230 Insets insets = getOpticalInsets(); 27231 int opticalWidth = insets.left + insets.right; 27232 int opticalHeight = insets.top + insets.bottom; 27233 27234 measuredWidth += optical ? opticalWidth : -opticalWidth; 27235 measuredHeight += optical ? opticalHeight : -opticalHeight; 27236 } 27237 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 27238 } 27239 27240 /** 27241 * Sets the measured dimension without extra processing for things like optical bounds. 27242 * Useful for reapplying consistent values that have already been cooked with adjustments 27243 * for optical bounds, etc. such as those from the measurement cache. 27244 * 27245 * @param measuredWidth The measured width of this view. May be a complex 27246 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 27247 * {@link #MEASURED_STATE_TOO_SMALL}. 27248 * @param measuredHeight The measured height of this view. May be a complex 27249 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 27250 * {@link #MEASURED_STATE_TOO_SMALL}. 27251 */ setMeasuredDimensionRaw(int measuredWidth, int measuredHeight)27252 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 27253 mMeasuredWidth = measuredWidth; 27254 mMeasuredHeight = measuredHeight; 27255 27256 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 27257 } 27258 27259 /** 27260 * Merge two states as returned by {@link #getMeasuredState()}. 27261 * @param curState The current state as returned from a view or the result 27262 * of combining multiple views. 27263 * @param newState The new view state to combine. 27264 * @return Returns a new integer reflecting the combination of the two 27265 * states. 27266 */ combineMeasuredStates(int curState, int newState)27267 public static int combineMeasuredStates(int curState, int newState) { 27268 return curState | newState; 27269 } 27270 27271 /** 27272 * Version of {@link #resolveSizeAndState(int, int, int)} 27273 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 27274 */ resolveSize(int size, int measureSpec)27275 public static int resolveSize(int size, int measureSpec) { 27276 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 27277 } 27278 27279 /** 27280 * Utility to reconcile a desired size and state, with constraints imposed 27281 * by a MeasureSpec. Will take the desired size, unless a different size 27282 * is imposed by the constraints. The returned value is a compound integer, 27283 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 27284 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 27285 * resulting size is smaller than the size the view wants to be. 27286 * 27287 * @param size How big the view wants to be. 27288 * @param measureSpec Constraints imposed by the parent. 27289 * @param childMeasuredState Size information bit mask for the view's 27290 * children. 27291 * @return Size information bit mask as defined by 27292 * {@link #MEASURED_SIZE_MASK} and 27293 * {@link #MEASURED_STATE_TOO_SMALL}. 27294 */ resolveSizeAndState(int size, int measureSpec, int childMeasuredState)27295 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 27296 final int specMode = MeasureSpec.getMode(measureSpec); 27297 final int specSize = MeasureSpec.getSize(measureSpec); 27298 final int result; 27299 switch (specMode) { 27300 case MeasureSpec.AT_MOST: 27301 if (specSize < size) { 27302 result = specSize | MEASURED_STATE_TOO_SMALL; 27303 } else { 27304 result = size; 27305 } 27306 break; 27307 case MeasureSpec.EXACTLY: 27308 result = specSize; 27309 break; 27310 case MeasureSpec.UNSPECIFIED: 27311 default: 27312 result = size; 27313 } 27314 return result | (childMeasuredState & MEASURED_STATE_MASK); 27315 } 27316 27317 /** 27318 * Utility to return a default size. Uses the supplied size if the 27319 * MeasureSpec imposed no constraints. Will get larger if allowed 27320 * by the MeasureSpec. 27321 * 27322 * @param size Default size for this view 27323 * @param measureSpec Constraints imposed by the parent 27324 * @return The size this view should be. 27325 */ getDefaultSize(int size, int measureSpec)27326 public static int getDefaultSize(int size, int measureSpec) { 27327 int result = size; 27328 int specMode = MeasureSpec.getMode(measureSpec); 27329 int specSize = MeasureSpec.getSize(measureSpec); 27330 27331 switch (specMode) { 27332 case MeasureSpec.UNSPECIFIED: 27333 result = size; 27334 break; 27335 case MeasureSpec.AT_MOST: 27336 case MeasureSpec.EXACTLY: 27337 result = specSize; 27338 break; 27339 } 27340 return result; 27341 } 27342 27343 /** 27344 * Returns the suggested minimum height that the view should use. This 27345 * returns the maximum of the view's minimum height 27346 * and the background's minimum height 27347 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 27348 * <p> 27349 * When being used in {@link #onMeasure(int, int)}, the caller should still 27350 * ensure the returned height is within the requirements of the parent. 27351 * 27352 * @return The suggested minimum height of the view. 27353 */ getSuggestedMinimumHeight()27354 protected int getSuggestedMinimumHeight() { 27355 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 27356 27357 } 27358 27359 /** 27360 * Returns the suggested minimum width that the view should use. This 27361 * returns the maximum of the view's minimum width 27362 * and the background's minimum width 27363 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 27364 * <p> 27365 * When being used in {@link #onMeasure(int, int)}, the caller should still 27366 * ensure the returned width is within the requirements of the parent. 27367 * 27368 * @return The suggested minimum width of the view. 27369 */ getSuggestedMinimumWidth()27370 protected int getSuggestedMinimumWidth() { 27371 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 27372 } 27373 27374 /** 27375 * Returns the minimum height of the view. 27376 * 27377 * @return the minimum height the view will try to be, in pixels 27378 * 27379 * @see #setMinimumHeight(int) 27380 * 27381 * @attr ref android.R.styleable#View_minHeight 27382 */ 27383 @InspectableProperty(name = "minHeight") getMinimumHeight()27384 public int getMinimumHeight() { 27385 return mMinHeight; 27386 } 27387 27388 /** 27389 * Sets the minimum height of the view. It is not guaranteed the view will 27390 * be able to achieve this minimum height (for example, if its parent layout 27391 * constrains it with less available height). 27392 * 27393 * @param minHeight The minimum height the view will try to be, in pixels 27394 * 27395 * @see #getMinimumHeight() 27396 * 27397 * @attr ref android.R.styleable#View_minHeight 27398 */ 27399 @RemotableViewMethod setMinimumHeight(int minHeight)27400 public void setMinimumHeight(int minHeight) { 27401 mMinHeight = minHeight; 27402 requestLayout(); 27403 } 27404 27405 /** 27406 * Returns the minimum width of the view. 27407 * 27408 * @return the minimum width the view will try to be, in pixels 27409 * 27410 * @see #setMinimumWidth(int) 27411 * 27412 * @attr ref android.R.styleable#View_minWidth 27413 */ 27414 @InspectableProperty(name = "minWidth") getMinimumWidth()27415 public int getMinimumWidth() { 27416 return mMinWidth; 27417 } 27418 27419 /** 27420 * Sets the minimum width of the view. It is not guaranteed the view will 27421 * be able to achieve this minimum width (for example, if its parent layout 27422 * constrains it with less available width). 27423 * 27424 * @param minWidth The minimum width the view will try to be, in pixels 27425 * 27426 * @see #getMinimumWidth() 27427 * 27428 * @attr ref android.R.styleable#View_minWidth 27429 */ 27430 @RemotableViewMethod setMinimumWidth(int minWidth)27431 public void setMinimumWidth(int minWidth) { 27432 mMinWidth = minWidth; 27433 requestLayout(); 27434 27435 } 27436 27437 /** 27438 * Get the animation currently associated with this view. 27439 * 27440 * @return The animation that is currently playing or 27441 * scheduled to play for this view. 27442 */ getAnimation()27443 public Animation getAnimation() { 27444 return mCurrentAnimation; 27445 } 27446 27447 /** 27448 * Start the specified animation now. 27449 * 27450 * @param animation the animation to start now 27451 */ startAnimation(Animation animation)27452 public void startAnimation(Animation animation) { 27453 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 27454 setAnimation(animation); 27455 invalidateParentCaches(); 27456 invalidate(true); 27457 } 27458 27459 /** 27460 * Cancels any animations for this view. 27461 */ clearAnimation()27462 public void clearAnimation() { 27463 if (mCurrentAnimation != null) { 27464 mCurrentAnimation.detach(); 27465 } 27466 mCurrentAnimation = null; 27467 invalidateParentIfNeeded(); 27468 } 27469 27470 /** 27471 * Sets the next animation to play for this view. 27472 * If you want the animation to play immediately, use 27473 * {@link #startAnimation(android.view.animation.Animation)} instead. 27474 * This method provides allows fine-grained 27475 * control over the start time and invalidation, but you 27476 * must make sure that 1) the animation has a start time set, and 27477 * 2) the view's parent (which controls animations on its children) 27478 * will be invalidated when the animation is supposed to 27479 * start. 27480 * 27481 * @param animation The next animation, or null. 27482 */ setAnimation(Animation animation)27483 public void setAnimation(Animation animation) { 27484 mCurrentAnimation = animation; 27485 27486 if (animation != null) { 27487 // If the screen is off assume the animation start time is now instead of 27488 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 27489 // would cause the animation to start when the screen turns back on 27490 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 27491 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 27492 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 27493 } 27494 animation.reset(); 27495 } 27496 } 27497 27498 /** 27499 * Invoked by a parent ViewGroup to notify the start of the animation 27500 * currently associated with this view. If you override this method, 27501 * always call super.onAnimationStart(); 27502 * 27503 * @see #setAnimation(android.view.animation.Animation) 27504 * @see #getAnimation() 27505 */ 27506 @CallSuper onAnimationStart()27507 protected void onAnimationStart() { 27508 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 27509 } 27510 27511 /** 27512 * Invoked by a parent ViewGroup to notify the end of the animation 27513 * currently associated with this view. If you override this method, 27514 * always call super.onAnimationEnd(); 27515 * 27516 * @see #setAnimation(android.view.animation.Animation) 27517 * @see #getAnimation() 27518 */ 27519 @CallSuper onAnimationEnd()27520 protected void onAnimationEnd() { 27521 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 27522 } 27523 27524 /** 27525 * Invoked if there is a Transform that involves alpha. Subclass that can 27526 * draw themselves with the specified alpha should return true, and then 27527 * respect that alpha when their onDraw() is called. If this returns false 27528 * then the view may be redirected to draw into an offscreen buffer to 27529 * fulfill the request, which will look fine, but may be slower than if the 27530 * subclass handles it internally. The default implementation returns false. 27531 * 27532 * @param alpha The alpha (0..255) to apply to the view's drawing 27533 * @return true if the view can draw with the specified alpha. 27534 */ onSetAlpha(int alpha)27535 protected boolean onSetAlpha(int alpha) { 27536 return false; 27537 } 27538 27539 /** 27540 * This is used by the ViewRoot to perform an optimization when 27541 * the view hierarchy contains one or several SurfaceView. 27542 * SurfaceView is always considered transparent, but its children are not, 27543 * therefore all View objects remove themselves from the global transparent 27544 * region (passed as a parameter to this function). 27545 * 27546 * @param region The transparent region for this ViewAncestor (window). 27547 * 27548 * @return Returns true if the effective visibility of the view at this 27549 * point is opaque, regardless of the transparent region; returns false 27550 * if it is possible for underlying windows to be seen behind the view. 27551 * 27552 */ gatherTransparentRegion(@ullable Region region)27553 public boolean gatherTransparentRegion(@Nullable Region region) { 27554 final AttachInfo attachInfo = mAttachInfo; 27555 if (region != null && attachInfo != null) { 27556 final int pflags = mPrivateFlags; 27557 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 27558 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 27559 // remove it from the transparent region. 27560 final int[] location = attachInfo.mTransparentLocation; 27561 getLocationInWindow(location); 27562 // When a view has Z value, then it will be better to leave some area below the view 27563 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 27564 // the bottom part needs more offset than the left, top and right parts due to the 27565 // spot light effects. 27566 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 27567 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 27568 location[0] + mRight - mLeft + shadowOffset, 27569 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 27570 } else { 27571 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 27572 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 27573 // the background drawable's non-transparent parts from this transparent region. 27574 applyDrawableToTransparentRegion(mBackground, region); 27575 } 27576 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 27577 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 27578 // Similarly, we remove the foreground drawable's non-transparent parts. 27579 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 27580 } 27581 if (mDefaultFocusHighlight != null 27582 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { 27583 // Similarly, we remove the default focus highlight's non-transparent parts. 27584 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); 27585 } 27586 } 27587 } 27588 return true; 27589 } 27590 27591 /** 27592 * Play a sound effect for this view. 27593 * 27594 * <p>The framework will play sound effects for some built in actions, such as 27595 * clicking, but you may wish to play these effects in your widget, 27596 * for instance, for internal navigation. 27597 * 27598 * <p>The sound effect will only be played if sound effects are enabled by the user, and 27599 * {@link #isSoundEffectsEnabled()} is true. 27600 * 27601 * @param soundConstant One of the constants defined in {@link SoundEffectConstants}. 27602 */ playSoundEffect(@oundEffectConstants.SoundEffect int soundConstant)27603 public void playSoundEffect(@SoundEffectConstants.SoundEffect int soundConstant) { 27604 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 27605 return; 27606 } 27607 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 27608 } 27609 27610 /** 27611 * BZZZTT!!1! 27612 * 27613 * <p>Provide haptic feedback to the user for this view. 27614 * 27615 * <p>The framework will provide haptic feedback for some built in actions, 27616 * such as long presses, but you may wish to provide feedback for your 27617 * own widget. 27618 * 27619 * <p>The feedback will only be performed if 27620 * {@link #isHapticFeedbackEnabled()} is true. 27621 * 27622 * @param feedbackConstant One of the constants defined in 27623 * {@link HapticFeedbackConstants} 27624 */ performHapticFeedback(int feedbackConstant)27625 public boolean performHapticFeedback(int feedbackConstant) { 27626 return performHapticFeedback(feedbackConstant, 0); 27627 } 27628 27629 /** 27630 * BZZZTT!!1! 27631 * 27632 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 27633 * 27634 * @param feedbackConstant One of the constants defined in 27635 * {@link HapticFeedbackConstants} 27636 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 27637 */ performHapticFeedback(int feedbackConstant, int flags)27638 public boolean performHapticFeedback(int feedbackConstant, int flags) { 27639 if (feedbackConstant == HapticFeedbackConstants.NO_HAPTICS 27640 || mAttachInfo == null) { 27641 return false; 27642 } 27643 //noinspection SimplifiableIfStatement 27644 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 27645 && !isHapticFeedbackEnabled()) { 27646 return false; 27647 } 27648 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 27649 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 27650 } 27651 27652 /** 27653 * Request that the visibility of the status bar or other screen/window 27654 * decorations be changed. 27655 * 27656 * <p>This method is used to put the over device UI into temporary modes 27657 * where the user's attention is focused more on the application content, 27658 * by dimming or hiding surrounding system affordances. This is typically 27659 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 27660 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 27661 * to be placed behind the action bar (and with these flags other system 27662 * affordances) so that smooth transitions between hiding and showing them 27663 * can be done. 27664 * 27665 * <p>Two representative examples of the use of system UI visibility is 27666 * implementing a content browsing application (like a magazine reader) 27667 * and a video playing application. 27668 * 27669 * <p>The first code shows a typical implementation of a View in a content 27670 * browsing application. In this implementation, the application goes 27671 * into a content-oriented mode by hiding the status bar and action bar, 27672 * and putting the navigation elements into lights out mode. The user can 27673 * then interact with content while in this mode. Such an application should 27674 * provide an easy way for the user to toggle out of the mode (such as to 27675 * check information in the status bar or access notifications). In the 27676 * implementation here, this is done simply by tapping on the content. 27677 * 27678 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 27679 * content} 27680 * 27681 * <p>This second code sample shows a typical implementation of a View 27682 * in a video playing application. In this situation, while the video is 27683 * playing the application would like to go into a complete full-screen mode, 27684 * to use as much of the display as possible for the video. When in this state 27685 * the user can not interact with the application; the system intercepts 27686 * touching on the screen to pop the UI out of full screen mode. See 27687 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 27688 * 27689 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 27690 * content} 27691 * 27692 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 27693 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 27694 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 27695 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 27696 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 27697 * 27698 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 27699 * instead. 27700 */ 27701 @Deprecated setSystemUiVisibility(int visibility)27702 public void setSystemUiVisibility(int visibility) { 27703 if (visibility != mSystemUiVisibility) { 27704 mSystemUiVisibility = visibility; 27705 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 27706 mParent.recomputeViewAttributes(this); 27707 } 27708 } 27709 } 27710 27711 /** 27712 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 27713 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 27714 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 27715 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 27716 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 27717 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 27718 * 27719 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 27720 * instead. 27721 */ 27722 @Deprecated getSystemUiVisibility()27723 public int getSystemUiVisibility() { 27724 return mSystemUiVisibility; 27725 } 27726 27727 /** 27728 * Returns the current system UI visibility that is currently set for 27729 * the entire window. This is the combination of the 27730 * {@link #setSystemUiVisibility(int)} values supplied by all of the 27731 * views in the window. 27732 * 27733 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 27734 * instead. 27735 */ 27736 @Deprecated getWindowSystemUiVisibility()27737 public int getWindowSystemUiVisibility() { 27738 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 27739 } 27740 27741 /** 27742 * Override to find out when the window's requested system UI visibility 27743 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 27744 * This is different from the callbacks received through 27745 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 27746 * in that this is only telling you about the local request of the window, 27747 * not the actual values applied by the system. 27748 * 27749 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 27750 * instead. 27751 */ 27752 @Deprecated onWindowSystemUiVisibilityChanged(int visible)27753 public void onWindowSystemUiVisibilityChanged(int visible) { 27754 } 27755 27756 /** 27757 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 27758 * the view hierarchy. 27759 * 27760 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 27761 * instead. 27762 */ 27763 @Deprecated dispatchWindowSystemUiVisiblityChanged(int visible)27764 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 27765 onWindowSystemUiVisibilityChanged(visible); 27766 } 27767 27768 /** 27769 * Set a listener to receive callbacks when the visibility of the system bar changes. 27770 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 27771 * 27772 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 27773 * by setting a {@link OnApplyWindowInsetsListener} on this view. 27774 */ 27775 @Deprecated setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l)27776 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 27777 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 27778 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 27779 mParent.recomputeViewAttributes(this); 27780 } 27781 } 27782 27783 /** 27784 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 27785 * the view hierarchy. 27786 * 27787 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 27788 * by setting a {@link OnApplyWindowInsetsListener} on this view. 27789 */ 27790 @Deprecated dispatchSystemUiVisibilityChanged(int visibility)27791 public void dispatchSystemUiVisibilityChanged(int visibility) { 27792 ListenerInfo li = mListenerInfo; 27793 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 27794 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 27795 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 27796 } 27797 } 27798 updateLocalSystemUiVisibility(int localValue, int localChanges)27799 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 27800 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 27801 if (val != mSystemUiVisibility) { 27802 setSystemUiVisibility(val); 27803 return true; 27804 } 27805 return false; 27806 } 27807 27808 /** @hide */ 27809 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setDisabledSystemUiVisibility(int flags)27810 public void setDisabledSystemUiVisibility(int flags) { 27811 if (mAttachInfo != null) { 27812 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 27813 mAttachInfo.mDisabledSystemUiVisibility = flags; 27814 if (mParent != null) { 27815 mParent.recomputeViewAttributes(this); 27816 } 27817 } 27818 } 27819 } 27820 27821 /** 27822 * This needs to be a better API before it is exposed. For now, only the root view will get 27823 * notified. 27824 * @hide 27825 */ onSystemBarAppearanceChanged(@indowInsetsController.Appearance int appearance)27826 public void onSystemBarAppearanceChanged(@WindowInsetsController.Appearance int appearance) { 27827 } 27828 27829 /** 27830 * Creates an image that the system displays during the drag and drop 27831 * operation. This is called a "drag shadow". The default implementation 27832 * for a DragShadowBuilder based on a View returns an image that has exactly the same 27833 * appearance as the given View. The default also positions the center of the drag shadow 27834 * directly under the touch point. If no View is provided (the constructor with no parameters 27835 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 27836 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 27837 * default is an invisible drag shadow. 27838 * <p> 27839 * You are not required to use the View you provide to the constructor as the basis of the 27840 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 27841 * anything you want as the drag shadow. 27842 * </p> 27843 * <p> 27844 * You pass a DragShadowBuilder object to the system when you start the drag. The system 27845 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 27846 * size and position of the drag shadow. It uses this data to construct a 27847 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 27848 * so that your application can draw the shadow image in the Canvas. 27849 * </p> 27850 * 27851 * <div class="special reference"> 27852 * <h3>Developer Guides</h3> 27853 * <p>For a guide to implementing drag and drop features, read the 27854 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 27855 * </div> 27856 */ 27857 public static class DragShadowBuilder { 27858 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 27859 private final WeakReference<View> mView; 27860 27861 /** 27862 * Constructs a shadow image builder based on a View. By default, the resulting drag 27863 * shadow will have the same appearance and dimensions as the View, with the touch point 27864 * over the center of the View. 27865 * @param view A View. Any View in scope can be used. 27866 */ DragShadowBuilder(View view)27867 public DragShadowBuilder(View view) { 27868 mView = new WeakReference<View>(view); 27869 } 27870 27871 /** 27872 * Construct a shadow builder object with no associated View. This 27873 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 27874 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 27875 * to supply the drag shadow's dimensions and appearance without 27876 * reference to any View object. 27877 */ DragShadowBuilder()27878 public DragShadowBuilder() { 27879 mView = new WeakReference<View>(null); 27880 } 27881 27882 /** 27883 * Returns the View object that had been passed to the 27884 * {@link #DragShadowBuilder(View)} 27885 * constructor. If that View parameter was {@code null} or if the 27886 * {@link #DragShadowBuilder()} 27887 * constructor was used to instantiate the builder object, this method will return 27888 * null. 27889 * 27890 * @return The View object associate with this builder object. 27891 */ 27892 @SuppressWarnings({"JavadocReference"}) getView()27893 final public View getView() { 27894 return mView.get(); 27895 } 27896 27897 /** 27898 * Provides the metrics for the shadow image. These include the dimensions of 27899 * the shadow image, and the point within that shadow that should 27900 * be centered under the touch location while dragging. 27901 * <p> 27902 * The default implementation sets the dimensions of the shadow to be the 27903 * same as the dimensions of the View itself and centers the shadow under 27904 * the touch point. 27905 * </p> 27906 * 27907 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 27908 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 27909 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 27910 * image. Since Android P, the width and height must be positive values. 27911 * 27912 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 27913 * shadow image that should be underneath the touch point during the drag and drop 27914 * operation. Your application must set {@link android.graphics.Point#x} to the 27915 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 27916 */ onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint)27917 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 27918 final View view = mView.get(); 27919 if (view != null) { 27920 outShadowSize.set(view.getWidth(), view.getHeight()); 27921 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 27922 } else { 27923 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 27924 } 27925 } 27926 27927 /** 27928 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 27929 * based on the dimensions it received from the 27930 * {@link #onProvideShadowMetrics(Point, Point)} callback. 27931 * 27932 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 27933 */ onDrawShadow(@onNull Canvas canvas)27934 public void onDrawShadow(@NonNull Canvas canvas) { 27935 final View view = mView.get(); 27936 if (view != null) { 27937 view.draw(canvas); 27938 } else { 27939 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 27940 } 27941 } 27942 } 27943 27944 /** 27945 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 27946 * startDragAndDrop()} for newer platform versions. 27947 */ 27948 @Deprecated startDrag(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)27949 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 27950 Object myLocalState, int flags) { 27951 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 27952 } 27953 27954 /** 27955 * Starts a drag and drop operation. When your application calls this method, it passes a 27956 * {@link android.view.View.DragShadowBuilder} object to the system. The 27957 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 27958 * to get metrics for the drag shadow, and then calls the object's 27959 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 27960 * <p> 27961 * Once the system has the drag shadow, it begins the drag and drop operation by sending 27962 * drag events to all the View objects in your application that are currently visible. It does 27963 * this either by calling the View object's drag listener (an implementation of 27964 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 27965 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 27966 * Both are passed a {@link android.view.DragEvent} object that has a 27967 * {@link android.view.DragEvent#getAction()} value of 27968 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 27969 * </p> 27970 * <p> 27971 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 27972 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 27973 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 27974 * to the View the user selected for dragging. 27975 * </p> 27976 * @param data A {@link android.content.ClipData} object pointing to the data to be 27977 * transferred by the drag and drop operation. 27978 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 27979 * drag shadow. 27980 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 27981 * drop operation. When dispatching drag events to views in the same activity this object 27982 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 27983 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 27984 * will return null). 27985 * <p> 27986 * myLocalState is a lightweight mechanism for the sending information from the dragged View 27987 * to the target Views. For example, it can contain flags that differentiate between a 27988 * a copy operation and a move operation. 27989 * </p> 27990 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 27991 * flags, or any combination of the following: 27992 * <ul> 27993 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 27994 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 27995 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 27996 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 27997 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 27998 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 27999 * <li>{@link #DRAG_FLAG_ACCESSIBILITY_ACTION}</li> 28000 * </ul> 28001 * @return {@code true} if the method completes successfully, or 28002 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 28003 * do a drag because of another ongoing operation or some other reasons. 28004 */ startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)28005 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 28006 Object myLocalState, int flags) { 28007 if (ViewDebug.DEBUG_DRAG) { 28008 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 28009 } 28010 if (mAttachInfo == null) { 28011 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 28012 return false; 28013 } 28014 if (!mAttachInfo.mViewRootImpl.mSurface.isValid()) { 28015 Log.w(VIEW_LOG_TAG, "startDragAndDrop called with an invalid surface."); 28016 return false; 28017 } 28018 28019 if (data != null) { 28020 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 28021 } 28022 28023 Rect bounds = new Rect(); 28024 getBoundsOnScreen(bounds, true); 28025 28026 Point lastTouchPoint = new Point(); 28027 mAttachInfo.mViewRootImpl.getLastTouchPoint(lastTouchPoint); 28028 final ViewRootImpl root = mAttachInfo.mViewRootImpl; 28029 28030 // Skip surface logic since shadows and animation are not required during the a11y drag 28031 final boolean a11yEnabled = AccessibilityManager.getInstance(mContext).isEnabled(); 28032 if (a11yEnabled && (flags & View.DRAG_FLAG_ACCESSIBILITY_ACTION) != 0) { 28033 try { 28034 IBinder token = mAttachInfo.mSession.performDrag( 28035 mAttachInfo.mWindow, flags, null, 28036 mAttachInfo.mViewRootImpl.getLastTouchSource(), 28037 0f, 0f, 0f, 0f, data); 28038 if (ViewDebug.DEBUG_DRAG) { 28039 Log.d(VIEW_LOG_TAG, "startDragAndDrop via a11y action returned " + token); 28040 } 28041 if (token != null) { 28042 root.setLocalDragState(myLocalState); 28043 mAttachInfo.mDragToken = token; 28044 mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this); 28045 setAccessibilityDragStarted(true); 28046 } 28047 return token != null; 28048 } catch (Exception e) { 28049 Log.e(VIEW_LOG_TAG, "Unable to initiate a11y drag", e); 28050 return false; 28051 } 28052 } 28053 28054 Point shadowSize = new Point(); 28055 Point shadowTouchPoint = new Point(); 28056 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 28057 28058 if ((shadowSize.x < 0) || (shadowSize.y < 0) 28059 || (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 28060 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 28061 } 28062 final float overrideInvScale = CompatibilityInfo.getOverrideInvertedScale(); 28063 if (overrideInvScale != 1f) { 28064 shadowTouchPoint.x = (int) (shadowTouchPoint.x / overrideInvScale); 28065 shadowTouchPoint.y = (int) (shadowTouchPoint.y / overrideInvScale); 28066 } 28067 28068 // Create 1x1 surface when zero surface size is specified because SurfaceControl.Builder 28069 // does not accept zero size surface. 28070 if (shadowSize.x == 0 || shadowSize.y == 0) { 28071 if (!sAcceptZeroSizeDragShadow) { 28072 throw new IllegalStateException("Drag shadow dimensions must be positive"); 28073 } 28074 shadowSize.x = 1; 28075 shadowSize.y = 1; 28076 } 28077 28078 if (ViewDebug.DEBUG_DRAG) { 28079 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 28080 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 28081 } 28082 28083 final SurfaceSession session = new SurfaceSession(); 28084 final SurfaceControl surfaceControl = new SurfaceControl.Builder(session) 28085 .setName("drag surface") 28086 .setParent(root.getSurfaceControl()) 28087 .setBufferSize(shadowSize.x, shadowSize.y) 28088 .setFormat(PixelFormat.TRANSLUCENT) 28089 .setCallsite("View.startDragAndDrop") 28090 .build(); 28091 if (overrideInvScale != 1f) { 28092 final SurfaceControl.Transaction transaction = new SurfaceControl.Transaction(); 28093 transaction.setMatrix(surfaceControl, 1 / overrideInvScale, 0, 0, 1 / overrideInvScale) 28094 .apply(); 28095 } 28096 final Surface surface = new Surface(); 28097 surface.copyFrom(surfaceControl); 28098 IBinder token = null; 28099 try { 28100 final Canvas canvas = isHardwareAccelerated() 28101 ? surface.lockHardwareCanvas() 28102 : surface.lockCanvas(null); 28103 try { 28104 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 28105 shadowBuilder.onDrawShadow(canvas); 28106 } finally { 28107 surface.unlockCanvasAndPost(canvas); 28108 } 28109 28110 token = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, flags, surfaceControl, 28111 root.getLastTouchSource(), lastTouchPoint.x, lastTouchPoint.y, 28112 shadowTouchPoint.x, shadowTouchPoint.y, data); 28113 if (ViewDebug.DEBUG_DRAG) { 28114 Log.d(VIEW_LOG_TAG, "performDrag returned " + token); 28115 } 28116 if (token != null) { 28117 if (mAttachInfo.mDragSurface != null) { 28118 mAttachInfo.mDragSurface.release(); 28119 } 28120 mAttachInfo.mDragSurface = surface; 28121 mAttachInfo.mDragToken = token; 28122 // Cache the local state object for delivery with DragEvents 28123 root.setLocalDragState(myLocalState); 28124 if (a11yEnabled) { 28125 // Set for AccessibilityEvents 28126 mAttachInfo.mViewRootImpl.setDragStartedViewForAccessibility(this); 28127 } 28128 } 28129 return token != null; 28130 } catch (Exception e) { 28131 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 28132 return false; 28133 } finally { 28134 if (token == null) { 28135 surface.destroy(); 28136 } 28137 session.kill(); 28138 } 28139 } 28140 setAccessibilityDragStarted(boolean started)28141 void setAccessibilityDragStarted(boolean started) { 28142 int pflags4 = mPrivateFlags4; 28143 if (started) { 28144 pflags4 |= PFLAG4_DRAG_A11Y_STARTED; 28145 } else { 28146 pflags4 &= ~PFLAG4_DRAG_A11Y_STARTED; 28147 } 28148 28149 if (pflags4 != mPrivateFlags4) { 28150 mPrivateFlags4 = pflags4; 28151 sendWindowContentChangedAccessibilityEvent(CONTENT_CHANGE_TYPE_UNDEFINED); 28152 } 28153 } 28154 startedSystemDragForAccessibility()28155 private boolean startedSystemDragForAccessibility() { 28156 return (mPrivateFlags4 & PFLAG4_DRAG_A11Y_STARTED) != 0; 28157 } 28158 28159 /** 28160 * Cancels an ongoing drag and drop operation. 28161 * <p> 28162 * A {@link android.view.DragEvent} object with 28163 * {@link android.view.DragEvent#getAction()} value of 28164 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 28165 * {@link android.view.DragEvent#getResult()} value of {@code false} 28166 * will be sent to every 28167 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 28168 * even if they are not currently visible. 28169 * </p> 28170 * <p> 28171 * This method can be called on any View in the same window as the View on which 28172 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 28173 * was called. 28174 * </p> 28175 */ cancelDragAndDrop()28176 public final void cancelDragAndDrop() { 28177 if (ViewDebug.DEBUG_DRAG) { 28178 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 28179 } 28180 if (mAttachInfo == null) { 28181 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 28182 return; 28183 } 28184 if (mAttachInfo.mDragToken != null) { 28185 try { 28186 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken, false); 28187 } catch (Exception e) { 28188 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 28189 } 28190 mAttachInfo.mDragToken = null; 28191 } else { 28192 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 28193 } 28194 } 28195 28196 /** 28197 * Updates the drag shadow for the ongoing drag and drop operation. 28198 * 28199 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 28200 * new drag shadow. 28201 */ updateDragShadow(DragShadowBuilder shadowBuilder)28202 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 28203 if (ViewDebug.DEBUG_DRAG) { 28204 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 28205 } 28206 if (mAttachInfo == null) { 28207 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 28208 return; 28209 } 28210 if (mAttachInfo.mDragToken != null) { 28211 try { 28212 Canvas canvas = isHardwareAccelerated() 28213 ? mAttachInfo.mDragSurface.lockHardwareCanvas() 28214 : mAttachInfo.mDragSurface.lockCanvas(null); 28215 try { 28216 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 28217 shadowBuilder.onDrawShadow(canvas); 28218 } finally { 28219 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 28220 } 28221 } catch (Exception e) { 28222 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 28223 } 28224 } else { 28225 Log.e(VIEW_LOG_TAG, "No active drag"); 28226 } 28227 } 28228 28229 /** 28230 * Starts a move from {startX, startY}, the amount of the movement will be the offset 28231 * between {startX, startY} and the new cursor positon. 28232 * @param startX horizontal coordinate where the move started. 28233 * @param startY vertical coordinate where the move started. 28234 * @return whether moving was started successfully. 28235 * @hide 28236 */ startMovingTask(float startX, float startY)28237 public final boolean startMovingTask(float startX, float startY) { 28238 if (ViewDebug.DEBUG_POSITIONING) { 28239 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 28240 } 28241 try { 28242 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 28243 } catch (RemoteException e) { 28244 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 28245 } 28246 return false; 28247 } 28248 28249 /** 28250 * Finish a window move task. 28251 * @hide 28252 */ finishMovingTask()28253 public void finishMovingTask() { 28254 if (ViewDebug.DEBUG_POSITIONING) { 28255 Log.d(VIEW_LOG_TAG, "finishMovingTask"); 28256 } 28257 try { 28258 mAttachInfo.mSession.finishMovingTask(mAttachInfo.mWindow); 28259 } catch (RemoteException e) { 28260 Log.e(VIEW_LOG_TAG, "Unable to finish moving", e); 28261 } 28262 } 28263 28264 /** 28265 * Handles drag events sent by the system following a call to 28266 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 28267 * startDragAndDrop()}. 28268 * <p> 28269 * The system calls this method and passes a {@link DragEvent} object in response to drag and 28270 * drop events. This method can then call {@link DragEvent#getAction()} to determine the state 28271 * of the drag and drop operation. 28272 * <p> 28273 * The default implementation returns {@code false} unless an {@link OnReceiveContentListener} 28274 * has been set for this view (see {@link #setOnReceiveContentListener}), in which case 28275 * the default implementation does the following: 28276 * <ul> 28277 * <li>Returns {@code true} for an 28278 * {@link DragEvent#ACTION_DRAG_STARTED ACTION_DRAG_STARTED} event 28279 * <li>Calls {@link #performReceiveContent} for an 28280 * {@link DragEvent#ACTION_DROP ACTION_DROP} event 28281 * <li>Returns {@code true} for an {@link DragEvent#ACTION_DROP ACTION_DROP} event if the 28282 * {@code OnReceiveContentListener} consumed some or all of the content 28283 * </ul> 28284 * 28285 * @param event The {@link DragEvent} object sent by the system. The 28286 * {@link DragEvent#getAction()} method returns an action type constant that indicates the 28287 * type of drag event represented by this object. 28288 * @return {@code true} if the method successfully handled the drag event, otherwise 28289 * {@code false}. 28290 * <p> 28291 * The method must return {@code true} in response to an 28292 * {@link DragEvent#ACTION_DRAG_STARTED ACTION_DRAG_STARTED} action type to continue to 28293 * receive drag events for the current drag and drop operation. 28294 * <p> 28295 * The method should return {@code true} in response to an 28296 * {@link DragEvent#ACTION_DROP ACTION_DROP} action type if the dropped data was consumed 28297 * (at least partially); {@code false}, if none of the data was consumed. 28298 * <p> 28299 * For all other events, the return value is {@code false}. 28300 */ onDragEvent(DragEvent event)28301 public boolean onDragEvent(DragEvent event) { 28302 if (mListenerInfo == null || mListenerInfo.mOnReceiveContentListener == null) { 28303 return false; 28304 } 28305 // Accept drag events by default if there's an OnReceiveContentListener set. 28306 if (event.getAction() == DragEvent.ACTION_DRAG_STARTED) { 28307 return true; 28308 } 28309 if (event.getAction() == DragEvent.ACTION_DROP) { 28310 final DragAndDropPermissions permissions = DragAndDropPermissions.obtain(event); 28311 if (permissions != null) { 28312 permissions.takeTransient(); 28313 } 28314 final ContentInfo payload = 28315 new ContentInfo.Builder(event.getClipData(), SOURCE_DRAG_AND_DROP) 28316 .setDragAndDropPermissions(permissions) 28317 .build(); 28318 ContentInfo remainingPayload = performReceiveContent(payload); 28319 // Return true unless none of the payload was consumed. 28320 return remainingPayload != payload; 28321 } 28322 return false; 28323 } 28324 28325 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. dispatchDragEnterExitInPreN(DragEvent event)28326 boolean dispatchDragEnterExitInPreN(DragEvent event) { 28327 return callDragEventHandler(event); 28328 } 28329 28330 /** 28331 * Detects if this View is enabled and has a drag event listener. 28332 * If both are true, then it calls the drag event listener with the 28333 * {@link android.view.DragEvent} it received. If the drag event listener returns 28334 * {@code true}, then dispatchDragEvent() returns {@code true}. 28335 * <p> 28336 * For all other cases, the method calls the 28337 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 28338 * method and returns its result. 28339 * </p> 28340 * <p> 28341 * This ensures that a drag event is always consumed, even if the View does not have a drag 28342 * event listener. However, if the View has a listener and the listener returns true, then 28343 * onDragEvent() is not called. 28344 * </p> 28345 */ dispatchDragEvent(DragEvent event)28346 public boolean dispatchDragEvent(DragEvent event) { 28347 event.mEventHandlerWasCalled = true; 28348 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 28349 event.mAction == DragEvent.ACTION_DROP) { 28350 // About to deliver an event with coordinates to this view. Notify that now this view 28351 // has drag focus. This will send exit/enter events as needed. 28352 getViewRootImpl().setDragFocus(this, event); 28353 } 28354 return callDragEventHandler(event); 28355 } 28356 callDragEventHandler(DragEvent event)28357 final boolean callDragEventHandler(DragEvent event) { 28358 final boolean result; 28359 28360 ListenerInfo li = mListenerInfo; 28361 //noinspection SimplifiableIfStatement 28362 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 28363 && li.mOnDragListener.onDrag(this, event)) { 28364 result = true; 28365 } else { 28366 result = onDragEvent(event); 28367 } 28368 28369 switch (event.mAction) { 28370 case DragEvent.ACTION_DRAG_STARTED: { 28371 if (result && li != null && li.mOnDragListener != null) { 28372 sendWindowContentChangedAccessibilityEvent( 28373 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 28374 } 28375 } break; 28376 case DragEvent.ACTION_DRAG_ENTERED: { 28377 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 28378 refreshDrawableState(); 28379 } break; 28380 case DragEvent.ACTION_DRAG_EXITED: { 28381 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 28382 refreshDrawableState(); 28383 } break; 28384 case DragEvent.ACTION_DROP: { 28385 if (result && li != null && (li.mOnDragListener != null 28386 || li.mOnReceiveContentListener != null)) { 28387 sendWindowContentChangedAccessibilityEvent( 28388 AccessibilityEvent.CONTENT_CHANGE_TYPE_DRAG_DROPPED); 28389 } 28390 } break; 28391 case DragEvent.ACTION_DRAG_ENDED: { 28392 sendWindowContentChangedAccessibilityEvent( 28393 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 28394 mPrivateFlags2 &= ~View.DRAG_MASK; 28395 refreshDrawableState(); 28396 } break; 28397 } 28398 28399 return result; 28400 } 28401 canAcceptDrag()28402 boolean canAcceptDrag() { 28403 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 28404 } 28405 sendWindowContentChangedAccessibilityEvent(int changeType)28406 void sendWindowContentChangedAccessibilityEvent(int changeType) { 28407 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 28408 AccessibilityEvent event = AccessibilityEvent.obtain(); 28409 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 28410 event.setContentChangeTypes(changeType); 28411 sendAccessibilityEventUnchecked(event); 28412 } 28413 } 28414 28415 /** 28416 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 28417 * it is ever exposed at all. 28418 * @hide 28419 */ 28420 @UnsupportedAppUsage onCloseSystemDialogs(String reason)28421 public void onCloseSystemDialogs(String reason) { 28422 } 28423 28424 /** 28425 * Given a Drawable whose bounds have been set to draw into this view, 28426 * update a Region being computed for 28427 * {@link #gatherTransparentRegion(android.graphics.Region)} so 28428 * that any non-transparent parts of the Drawable are removed from the 28429 * given transparent region. 28430 * 28431 * @param dr The Drawable whose transparency is to be applied to the region. 28432 * @param region A Region holding the current transparency information, 28433 * where any parts of the region that are set are considered to be 28434 * transparent. On return, this region will be modified to have the 28435 * transparency information reduced by the corresponding parts of the 28436 * Drawable that are not transparent. 28437 * {@hide} 28438 */ 28439 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) applyDrawableToTransparentRegion(Drawable dr, Region region)28440 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 28441 if (DBG) { 28442 Log.i("View", "Getting transparent region for: " + this); 28443 } 28444 final Region r = dr.getTransparentRegion(); 28445 final Rect db = dr.getBounds(); 28446 final AttachInfo attachInfo = mAttachInfo; 28447 if (r != null && attachInfo != null) { 28448 final int w = getRight()-getLeft(); 28449 final int h = getBottom()-getTop(); 28450 if (db.left > 0) { 28451 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 28452 r.op(0, 0, db.left, h, Region.Op.UNION); 28453 } 28454 if (db.right < w) { 28455 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 28456 r.op(db.right, 0, w, h, Region.Op.UNION); 28457 } 28458 if (db.top > 0) { 28459 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 28460 r.op(0, 0, w, db.top, Region.Op.UNION); 28461 } 28462 if (db.bottom < h) { 28463 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 28464 r.op(0, db.bottom, w, h, Region.Op.UNION); 28465 } 28466 final int[] location = attachInfo.mTransparentLocation; 28467 getLocationInWindow(location); 28468 r.translate(location[0], location[1]); 28469 region.op(r, Region.Op.INTERSECT); 28470 } else { 28471 region.op(db, Region.Op.DIFFERENCE); 28472 } 28473 } 28474 checkForLongClick(long delay, float x, float y, int classification)28475 private void checkForLongClick(long delay, float x, float y, int classification) { 28476 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 28477 mHasPerformedLongPress = false; 28478 28479 if (mPendingCheckForLongPress == null) { 28480 mPendingCheckForLongPress = new CheckForLongPress(); 28481 } 28482 mPendingCheckForLongPress.setAnchor(x, y); 28483 mPendingCheckForLongPress.rememberWindowAttachCount(); 28484 mPendingCheckForLongPress.rememberPressedState(); 28485 mPendingCheckForLongPress.setClassification(classification); 28486 postDelayed(mPendingCheckForLongPress, delay); 28487 } 28488 } 28489 28490 /** 28491 * Inflate a view from an XML resource. This convenience method wraps the {@link 28492 * LayoutInflater} class, which provides a full range of options for view inflation. 28493 * 28494 * @param context The Context object for your activity or application. 28495 * @param resource The resource ID to inflate 28496 * @param root A view group that will be the parent. Used to properly inflate the 28497 * layout_* parameters. 28498 * @see LayoutInflater 28499 */ inflate(Context context, @LayoutRes int resource, ViewGroup root)28500 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 28501 LayoutInflater factory = LayoutInflater.from(context); 28502 return factory.inflate(resource, root); 28503 } 28504 28505 /** 28506 * Scroll the view with standard behavior for scrolling beyond the normal 28507 * content boundaries. Views that call this method should override 28508 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 28509 * results of an over-scroll operation. 28510 * 28511 * Views can use this method to handle any touch or fling-based scrolling. 28512 * 28513 * @param deltaX Change in X in pixels 28514 * @param deltaY Change in Y in pixels 28515 * @param scrollX Current X scroll value in pixels before applying deltaX 28516 * @param scrollY Current Y scroll value in pixels before applying deltaY 28517 * @param scrollRangeX Maximum content scroll range along the X axis 28518 * @param scrollRangeY Maximum content scroll range along the Y axis 28519 * @param maxOverScrollX Number of pixels to overscroll by in either direction 28520 * along the X axis. 28521 * @param maxOverScrollY Number of pixels to overscroll by in either direction 28522 * along the Y axis. 28523 * @param isTouchEvent true if this scroll operation is the result of a touch event. 28524 * @return true if scrolling was clamped to an over-scroll boundary along either 28525 * axis, false otherwise. 28526 */ 28527 @SuppressWarnings({"UnusedParameters"}) overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent)28528 protected boolean overScrollBy(int deltaX, int deltaY, 28529 int scrollX, int scrollY, 28530 int scrollRangeX, int scrollRangeY, 28531 int maxOverScrollX, int maxOverScrollY, 28532 boolean isTouchEvent) { 28533 final int overScrollMode = mOverScrollMode; 28534 final boolean canScrollHorizontal = 28535 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 28536 final boolean canScrollVertical = 28537 computeVerticalScrollRange() > computeVerticalScrollExtent(); 28538 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 28539 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 28540 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 28541 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 28542 28543 int newScrollX = scrollX + deltaX; 28544 if (!overScrollHorizontal) { 28545 maxOverScrollX = 0; 28546 } 28547 28548 int newScrollY = scrollY + deltaY; 28549 if (!overScrollVertical) { 28550 maxOverScrollY = 0; 28551 } 28552 28553 // Clamp values if at the limits and record 28554 final int left = -maxOverScrollX; 28555 final int right = maxOverScrollX + scrollRangeX; 28556 final int top = -maxOverScrollY; 28557 final int bottom = maxOverScrollY + scrollRangeY; 28558 28559 boolean clampedX = false; 28560 if (newScrollX > right) { 28561 newScrollX = right; 28562 clampedX = true; 28563 } else if (newScrollX < left) { 28564 newScrollX = left; 28565 clampedX = true; 28566 } 28567 28568 boolean clampedY = false; 28569 if (newScrollY > bottom) { 28570 newScrollY = bottom; 28571 clampedY = true; 28572 } else if (newScrollY < top) { 28573 newScrollY = top; 28574 clampedY = true; 28575 } 28576 28577 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 28578 28579 return clampedX || clampedY; 28580 } 28581 28582 /** 28583 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 28584 * respond to the results of an over-scroll operation. 28585 * 28586 * @param scrollX New X scroll value in pixels 28587 * @param scrollY New Y scroll value in pixels 28588 * @param clampedX True if scrollX was clamped to an over-scroll boundary 28589 * @param clampedY True if scrollY was clamped to an over-scroll boundary 28590 */ onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY)28591 protected void onOverScrolled(int scrollX, int scrollY, 28592 boolean clampedX, boolean clampedY) { 28593 // Intentionally empty. 28594 } 28595 28596 /** 28597 * Returns the over-scroll mode for this view. The result will be 28598 * one of {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 28599 * (allow over-scrolling only if the view content is larger than the container), 28600 * or {@link #OVER_SCROLL_NEVER}. 28601 * 28602 * @return This view's over-scroll mode. 28603 */ 28604 @InspectableProperty(enumMapping = { 28605 @EnumEntry(value = OVER_SCROLL_ALWAYS, name = "always"), 28606 @EnumEntry(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"), 28607 @EnumEntry(value = OVER_SCROLL_NEVER, name = "never") 28608 }) getOverScrollMode()28609 public int getOverScrollMode() { 28610 return mOverScrollMode; 28611 } 28612 28613 /** 28614 * Set the over-scroll mode for this view. Valid over-scroll modes are 28615 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 28616 * (allow over-scrolling only if the view content is larger than the container), 28617 * or {@link #OVER_SCROLL_NEVER}. 28618 * 28619 * Setting the over-scroll mode of a view will have an effect only if the 28620 * view is capable of scrolling. 28621 * 28622 * @param overScrollMode The new over-scroll mode for this view. 28623 */ setOverScrollMode(int overScrollMode)28624 public void setOverScrollMode(int overScrollMode) { 28625 if (overScrollMode != OVER_SCROLL_ALWAYS && 28626 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 28627 overScrollMode != OVER_SCROLL_NEVER) { 28628 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 28629 } 28630 mOverScrollMode = overScrollMode; 28631 } 28632 28633 /** 28634 * Enable or disable nested scrolling for this view. 28635 * 28636 * <p>If this property is set to true the view will be permitted to initiate nested 28637 * scrolling operations with a compatible parent view in the current hierarchy. If this 28638 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 28639 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 28640 * the nested scroll.</p> 28641 * 28642 * @param enabled true to enable nested scrolling, false to disable 28643 * 28644 * @see #isNestedScrollingEnabled() 28645 */ setNestedScrollingEnabled(boolean enabled)28646 public void setNestedScrollingEnabled(boolean enabled) { 28647 if (enabled) { 28648 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 28649 } else { 28650 stopNestedScroll(); 28651 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 28652 } 28653 } 28654 28655 /** 28656 * Returns true if nested scrolling is enabled for this view. 28657 * 28658 * <p>If nested scrolling is enabled and this View class implementation supports it, 28659 * this view will act as a nested scrolling child view when applicable, forwarding data 28660 * about the scroll operation in progress to a compatible and cooperating nested scrolling 28661 * parent.</p> 28662 * 28663 * @return true if nested scrolling is enabled 28664 * 28665 * @see #setNestedScrollingEnabled(boolean) 28666 */ 28667 @InspectableProperty isNestedScrollingEnabled()28668 public boolean isNestedScrollingEnabled() { 28669 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 28670 PFLAG3_NESTED_SCROLLING_ENABLED; 28671 } 28672 28673 /** 28674 * Begin a nestable scroll operation along the given axes. 28675 * 28676 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 28677 * 28678 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 28679 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 28680 * In the case of touch scrolling the nested scroll will be terminated automatically in 28681 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 28682 * In the event of programmatic scrolling the caller must explicitly call 28683 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 28684 * 28685 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 28686 * If it returns false the caller may ignore the rest of this contract until the next scroll. 28687 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 28688 * 28689 * <p>At each incremental step of the scroll the caller should invoke 28690 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 28691 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 28692 * parent at least partially consumed the scroll and the caller should adjust the amount it 28693 * scrolls by.</p> 28694 * 28695 * <p>After applying the remainder of the scroll delta the caller should invoke 28696 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 28697 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 28698 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 28699 * </p> 28700 * 28701 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 28702 * {@link #SCROLL_AXIS_VERTICAL}. 28703 * @return true if a cooperative parent was found and nested scrolling has been enabled for 28704 * the current gesture. 28705 * 28706 * @see #stopNestedScroll() 28707 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 28708 * @see #dispatchNestedScroll(int, int, int, int, int[]) 28709 */ startNestedScroll(int axes)28710 public boolean startNestedScroll(int axes) { 28711 if (hasNestedScrollingParent()) { 28712 // Already in progress 28713 return true; 28714 } 28715 if (isNestedScrollingEnabled()) { 28716 ViewParent p = getParent(); 28717 View child = this; 28718 while (p != null) { 28719 try { 28720 if (p.onStartNestedScroll(child, this, axes)) { 28721 mNestedScrollingParent = p; 28722 p.onNestedScrollAccepted(child, this, axes); 28723 return true; 28724 } 28725 } catch (AbstractMethodError e) { 28726 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 28727 "method onStartNestedScroll", e); 28728 // Allow the search upward to continue 28729 } 28730 if (p instanceof View) { 28731 child = (View) p; 28732 } 28733 p = p.getParent(); 28734 } 28735 } 28736 return false; 28737 } 28738 28739 /** 28740 * Stop a nested scroll in progress. 28741 * 28742 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 28743 * 28744 * @see #startNestedScroll(int) 28745 */ stopNestedScroll()28746 public void stopNestedScroll() { 28747 if (mNestedScrollingParent != null) { 28748 mNestedScrollingParent.onStopNestedScroll(this); 28749 mNestedScrollingParent = null; 28750 } 28751 } 28752 28753 /** 28754 * Returns true if this view has a nested scrolling parent. 28755 * 28756 * <p>The presence of a nested scrolling parent indicates that this view has initiated 28757 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 28758 * 28759 * @return whether this view has a nested scrolling parent 28760 */ hasNestedScrollingParent()28761 public boolean hasNestedScrollingParent() { 28762 return mNestedScrollingParent != null; 28763 } 28764 28765 /** 28766 * Dispatch one step of a nested scroll in progress. 28767 * 28768 * <p>Implementations of views that support nested scrolling should call this to report 28769 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 28770 * is not currently in progress or nested scrolling is not 28771 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 28772 * 28773 * <p>Compatible View implementations should also call 28774 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 28775 * consuming a component of the scroll event themselves.</p> 28776 * 28777 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 28778 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 28779 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 28780 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 28781 * @param offsetInWindow Optional. If not null, on return this will contain the offset 28782 * in local view coordinates of this view from before this operation 28783 * to after it completes. View implementations may use this to adjust 28784 * expected input coordinate tracking. 28785 * @return true if the event was dispatched, false if it could not be dispatched. 28786 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 28787 */ dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow)28788 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 28789 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 28790 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 28791 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 28792 int startX = 0; 28793 int startY = 0; 28794 if (offsetInWindow != null) { 28795 getLocationInWindow(offsetInWindow); 28796 startX = offsetInWindow[0]; 28797 startY = offsetInWindow[1]; 28798 } 28799 28800 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 28801 dxUnconsumed, dyUnconsumed); 28802 28803 if (offsetInWindow != null) { 28804 getLocationInWindow(offsetInWindow); 28805 offsetInWindow[0] -= startX; 28806 offsetInWindow[1] -= startY; 28807 } 28808 return true; 28809 } else if (offsetInWindow != null) { 28810 // No motion, no dispatch. Keep offsetInWindow up to date. 28811 offsetInWindow[0] = 0; 28812 offsetInWindow[1] = 0; 28813 } 28814 } 28815 return false; 28816 } 28817 28818 /** 28819 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 28820 * 28821 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 28822 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 28823 * scrolling operation to consume some or all of the scroll operation before the child view 28824 * consumes it.</p> 28825 * 28826 * @param dx Horizontal scroll distance in pixels 28827 * @param dy Vertical scroll distance in pixels 28828 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 28829 * and consumed[1] the consumed dy. 28830 * @param offsetInWindow Optional. If not null, on return this will contain the offset 28831 * in local view coordinates of this view from before this operation 28832 * to after it completes. View implementations may use this to adjust 28833 * expected input coordinate tracking. 28834 * @return true if the parent consumed some or all of the scroll delta 28835 * @see #dispatchNestedScroll(int, int, int, int, int[]) 28836 */ dispatchNestedPreScroll(int dx, int dy, @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow)28837 public boolean dispatchNestedPreScroll(int dx, int dy, 28838 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 28839 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 28840 if (dx != 0 || dy != 0) { 28841 int startX = 0; 28842 int startY = 0; 28843 if (offsetInWindow != null) { 28844 getLocationInWindow(offsetInWindow); 28845 startX = offsetInWindow[0]; 28846 startY = offsetInWindow[1]; 28847 } 28848 28849 if (consumed == null) { 28850 if (mTempNestedScrollConsumed == null) { 28851 mTempNestedScrollConsumed = new int[2]; 28852 } 28853 consumed = mTempNestedScrollConsumed; 28854 } 28855 consumed[0] = 0; 28856 consumed[1] = 0; 28857 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 28858 28859 if (offsetInWindow != null) { 28860 getLocationInWindow(offsetInWindow); 28861 offsetInWindow[0] -= startX; 28862 offsetInWindow[1] -= startY; 28863 } 28864 return consumed[0] != 0 || consumed[1] != 0; 28865 } else if (offsetInWindow != null) { 28866 offsetInWindow[0] = 0; 28867 offsetInWindow[1] = 0; 28868 } 28869 } 28870 return false; 28871 } 28872 28873 /** 28874 * Dispatch a fling to a nested scrolling parent. 28875 * 28876 * <p>This method should be used to indicate that a nested scrolling child has detected 28877 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 28878 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 28879 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 28880 * along a scrollable axis.</p> 28881 * 28882 * <p>If a nested scrolling child view would normally fling but it is at the edge of 28883 * its own content, it can use this method to delegate the fling to its nested scrolling 28884 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 28885 * 28886 * @param velocityX Horizontal fling velocity in pixels per second 28887 * @param velocityY Vertical fling velocity in pixels per second 28888 * @param consumed true if the child consumed the fling, false otherwise 28889 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 28890 */ dispatchNestedFling(float velocityX, float velocityY, boolean consumed)28891 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 28892 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 28893 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 28894 } 28895 return false; 28896 } 28897 28898 /** 28899 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 28900 * 28901 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 28902 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 28903 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 28904 * before the child view consumes it. If this method returns <code>true</code>, a nested 28905 * parent view consumed the fling and this view should not scroll as a result.</p> 28906 * 28907 * <p>For a better user experience, only one view in a nested scrolling chain should consume 28908 * the fling at a time. If a parent view consumed the fling this method will return false. 28909 * Custom view implementations should account for this in two ways:</p> 28910 * 28911 * <ul> 28912 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 28913 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 28914 * position regardless.</li> 28915 * <li>If a nested parent does consume the fling, this view should not scroll at all, 28916 * even to settle back to a valid idle position.</li> 28917 * </ul> 28918 * 28919 * <p>Views should also not offer fling velocities to nested parent views along an axis 28920 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 28921 * should not offer a horizontal fling velocity to its parents since scrolling along that 28922 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 28923 * 28924 * @param velocityX Horizontal fling velocity in pixels per second 28925 * @param velocityY Vertical fling velocity in pixels per second 28926 * @return true if a nested scrolling parent consumed the fling 28927 */ dispatchNestedPreFling(float velocityX, float velocityY)28928 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 28929 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 28930 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 28931 } 28932 return false; 28933 } 28934 28935 /** 28936 * Gets a scale factor that determines the distance the view should scroll 28937 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 28938 * @return The vertical scroll scale factor. 28939 * @hide 28940 */ 28941 @UnsupportedAppUsage getVerticalScrollFactor()28942 protected float getVerticalScrollFactor() { 28943 if (mVerticalScrollFactor == 0) { 28944 TypedValue outValue = new TypedValue(); 28945 if (!mContext.getTheme().resolveAttribute( 28946 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 28947 throw new IllegalStateException( 28948 "Expected theme to define listPreferredItemHeight."); 28949 } 28950 mVerticalScrollFactor = outValue.getDimension( 28951 mContext.getResources().getDisplayMetrics()); 28952 } 28953 return mVerticalScrollFactor; 28954 } 28955 28956 /** 28957 * Gets a scale factor that determines the distance the view should scroll 28958 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 28959 * @return The horizontal scroll scale factor. 28960 * @hide 28961 */ 28962 @UnsupportedAppUsage getHorizontalScrollFactor()28963 protected float getHorizontalScrollFactor() { 28964 // TODO: Should use something else. 28965 return getVerticalScrollFactor(); 28966 } 28967 28968 /** 28969 * Return the value specifying the text direction or policy that was set with 28970 * {@link #setTextDirection(int)}. 28971 * 28972 * @return the defined text direction. It can be one of: 28973 * 28974 * {@link #TEXT_DIRECTION_INHERIT}, 28975 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 28976 * {@link #TEXT_DIRECTION_ANY_RTL}, 28977 * {@link #TEXT_DIRECTION_LTR}, 28978 * {@link #TEXT_DIRECTION_RTL}, 28979 * {@link #TEXT_DIRECTION_LOCALE}, 28980 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 28981 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 28982 * 28983 * @attr ref android.R.styleable#View_textDirection 28984 * 28985 * @hide 28986 */ 28987 @ViewDebug.ExportedProperty(category = "text", mapping = { 28988 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 28989 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 28990 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 28991 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 28992 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 28993 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 28994 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 28995 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 28996 }) 28997 @InspectableProperty(hasAttributeId = false, enumMapping = { 28998 @EnumEntry(value = TEXT_DIRECTION_INHERIT, name = "inherit"), 28999 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 29000 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 29001 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 29002 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 29003 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 29004 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 29005 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 29006 }) 29007 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getRawTextDirection()29008 public int getRawTextDirection() { 29009 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 29010 } 29011 29012 /** 29013 * Set the text direction. 29014 * 29015 * @param textDirection the direction to set. Should be one of: 29016 * 29017 * {@link #TEXT_DIRECTION_INHERIT}, 29018 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 29019 * {@link #TEXT_DIRECTION_ANY_RTL}, 29020 * {@link #TEXT_DIRECTION_LTR}, 29021 * {@link #TEXT_DIRECTION_RTL}, 29022 * {@link #TEXT_DIRECTION_LOCALE} 29023 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 29024 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 29025 * 29026 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 29027 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 29028 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 29029 * 29030 * @attr ref android.R.styleable#View_textDirection 29031 */ setTextDirection(int textDirection)29032 public void setTextDirection(int textDirection) { 29033 if (getRawTextDirection() != textDirection) { 29034 // Reset the current text direction and the resolved one 29035 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 29036 resetResolvedTextDirection(); 29037 // Set the new text direction 29038 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 29039 // Do resolution 29040 resolveTextDirection(); 29041 // Notify change 29042 onRtlPropertiesChanged(getLayoutDirection()); 29043 // Refresh 29044 requestLayout(); 29045 invalidate(true); 29046 } 29047 } 29048 29049 /** 29050 * Return the resolved text direction. 29051 * 29052 * @return the resolved text direction. Returns one of: 29053 * 29054 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 29055 * {@link #TEXT_DIRECTION_ANY_RTL}, 29056 * {@link #TEXT_DIRECTION_LTR}, 29057 * {@link #TEXT_DIRECTION_RTL}, 29058 * {@link #TEXT_DIRECTION_LOCALE}, 29059 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 29060 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 29061 * 29062 * @attr ref android.R.styleable#View_textDirection 29063 */ 29064 @ViewDebug.ExportedProperty(category = "text", mapping = { 29065 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 29066 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 29067 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 29068 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 29069 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 29070 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 29071 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 29072 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 29073 }) 29074 @InspectableProperty(hasAttributeId = false, enumMapping = { 29075 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 29076 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 29077 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 29078 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 29079 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 29080 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 29081 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 29082 }) getTextDirection()29083 public int getTextDirection() { 29084 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 29085 } 29086 29087 /** 29088 * Resolve the text direction. 29089 * 29090 * @return true if resolution has been done, false otherwise. 29091 * 29092 * @hide 29093 */ resolveTextDirection()29094 public boolean resolveTextDirection() { 29095 // Reset any previous text direction resolution 29096 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 29097 29098 if (hasRtlSupport()) { 29099 // Set resolved text direction flag depending on text direction flag 29100 final int textDirection = getRawTextDirection(); 29101 switch(textDirection) { 29102 case TEXT_DIRECTION_INHERIT: 29103 if (!canResolveTextDirection()) { 29104 // We cannot do the resolution if there is no parent, so use the default one 29105 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 29106 // Resolution will need to happen again later 29107 return false; 29108 } 29109 29110 // Parent has not yet resolved, so we still return the default 29111 try { 29112 if (!mParent.isTextDirectionResolved()) { 29113 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 29114 // Resolution will need to happen again later 29115 return false; 29116 } 29117 } catch (AbstractMethodError e) { 29118 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 29119 " does not fully implement ViewParent", e); 29120 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 29121 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 29122 return true; 29123 } 29124 29125 // Set current resolved direction to the same value as the parent's one 29126 int parentResolvedDirection; 29127 try { 29128 parentResolvedDirection = mParent.getTextDirection(); 29129 } catch (AbstractMethodError e) { 29130 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 29131 " does not fully implement ViewParent", e); 29132 parentResolvedDirection = TEXT_DIRECTION_LTR; 29133 } 29134 switch (parentResolvedDirection) { 29135 case TEXT_DIRECTION_FIRST_STRONG: 29136 case TEXT_DIRECTION_ANY_RTL: 29137 case TEXT_DIRECTION_LTR: 29138 case TEXT_DIRECTION_RTL: 29139 case TEXT_DIRECTION_LOCALE: 29140 case TEXT_DIRECTION_FIRST_STRONG_LTR: 29141 case TEXT_DIRECTION_FIRST_STRONG_RTL: 29142 mPrivateFlags2 |= 29143 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 29144 break; 29145 default: 29146 // Default resolved direction is "first strong" heuristic 29147 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 29148 } 29149 break; 29150 case TEXT_DIRECTION_FIRST_STRONG: 29151 case TEXT_DIRECTION_ANY_RTL: 29152 case TEXT_DIRECTION_LTR: 29153 case TEXT_DIRECTION_RTL: 29154 case TEXT_DIRECTION_LOCALE: 29155 case TEXT_DIRECTION_FIRST_STRONG_LTR: 29156 case TEXT_DIRECTION_FIRST_STRONG_RTL: 29157 // Resolved direction is the same as text direction 29158 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 29159 break; 29160 default: 29161 // Default resolved direction is "first strong" heuristic 29162 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 29163 } 29164 } else { 29165 // Default resolved direction is "first strong" heuristic 29166 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 29167 } 29168 29169 // Set to resolved 29170 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 29171 return true; 29172 } 29173 29174 /** 29175 * Check if text direction resolution can be done. 29176 * 29177 * @return true if text direction resolution can be done otherwise return false. 29178 */ canResolveTextDirection()29179 public boolean canResolveTextDirection() { 29180 switch (getRawTextDirection()) { 29181 case TEXT_DIRECTION_INHERIT: 29182 if (mParent != null) { 29183 try { 29184 return mParent.canResolveTextDirection(); 29185 } catch (AbstractMethodError e) { 29186 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 29187 " does not fully implement ViewParent", e); 29188 } 29189 } 29190 return false; 29191 29192 default: 29193 return true; 29194 } 29195 } 29196 29197 /** 29198 * Reset resolved text direction. Text direction will be resolved during a call to 29199 * {@link #onMeasure(int, int)}. 29200 * 29201 * @hide 29202 */ 29203 @TestApi resetResolvedTextDirection()29204 public void resetResolvedTextDirection() { 29205 // Reset any previous text direction resolution 29206 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 29207 // Set to default value 29208 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 29209 } 29210 29211 /** 29212 * @return true if text direction is inherited. 29213 * 29214 * @hide 29215 */ isTextDirectionInherited()29216 public boolean isTextDirectionInherited() { 29217 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 29218 } 29219 29220 /** 29221 * @return true if text direction is resolved. 29222 */ isTextDirectionResolved()29223 public boolean isTextDirectionResolved() { 29224 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 29225 } 29226 29227 /** 29228 * Return the value specifying the text alignment or policy that was set with 29229 * {@link #setTextAlignment(int)}. 29230 * 29231 * @return the defined text alignment. It can be one of: 29232 * 29233 * {@link #TEXT_ALIGNMENT_INHERIT}, 29234 * {@link #TEXT_ALIGNMENT_GRAVITY}, 29235 * {@link #TEXT_ALIGNMENT_CENTER}, 29236 * {@link #TEXT_ALIGNMENT_TEXT_START}, 29237 * {@link #TEXT_ALIGNMENT_TEXT_END}, 29238 * {@link #TEXT_ALIGNMENT_VIEW_START}, 29239 * {@link #TEXT_ALIGNMENT_VIEW_END} 29240 * 29241 * @attr ref android.R.styleable#View_textAlignment 29242 * 29243 * @hide 29244 */ 29245 @ViewDebug.ExportedProperty(category = "text", mapping = { 29246 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 29247 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 29248 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 29249 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 29250 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 29251 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 29252 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 29253 }) 29254 @InspectableProperty(hasAttributeId = false, enumMapping = { 29255 @EnumEntry(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"), 29256 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 29257 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 29258 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 29259 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 29260 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 29261 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 29262 }) 29263 @TextAlignment 29264 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getRawTextAlignment()29265 public int getRawTextAlignment() { 29266 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 29267 } 29268 29269 /** 29270 * Set the text alignment. 29271 * 29272 * @param textAlignment The text alignment to set. Should be one of 29273 * 29274 * {@link #TEXT_ALIGNMENT_INHERIT}, 29275 * {@link #TEXT_ALIGNMENT_GRAVITY}, 29276 * {@link #TEXT_ALIGNMENT_CENTER}, 29277 * {@link #TEXT_ALIGNMENT_TEXT_START}, 29278 * {@link #TEXT_ALIGNMENT_TEXT_END}, 29279 * {@link #TEXT_ALIGNMENT_VIEW_START}, 29280 * {@link #TEXT_ALIGNMENT_VIEW_END} 29281 * 29282 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 29283 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 29284 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 29285 * 29286 * @attr ref android.R.styleable#View_textAlignment 29287 */ setTextAlignment(@extAlignment int textAlignment)29288 public void setTextAlignment(@TextAlignment int textAlignment) { 29289 if (textAlignment != getRawTextAlignment()) { 29290 // Reset the current and resolved text alignment 29291 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 29292 resetResolvedTextAlignment(); 29293 // Set the new text alignment 29294 mPrivateFlags2 |= 29295 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 29296 // Do resolution 29297 resolveTextAlignment(); 29298 // Notify change 29299 onRtlPropertiesChanged(getLayoutDirection()); 29300 // Refresh 29301 requestLayout(); 29302 invalidate(true); 29303 } 29304 } 29305 29306 /** 29307 * Return the resolved text alignment. 29308 * 29309 * @return the resolved text alignment. Returns one of: 29310 * 29311 * {@link #TEXT_ALIGNMENT_GRAVITY}, 29312 * {@link #TEXT_ALIGNMENT_CENTER}, 29313 * {@link #TEXT_ALIGNMENT_TEXT_START}, 29314 * {@link #TEXT_ALIGNMENT_TEXT_END}, 29315 * {@link #TEXT_ALIGNMENT_VIEW_START}, 29316 * {@link #TEXT_ALIGNMENT_VIEW_END} 29317 * 29318 * @attr ref android.R.styleable#View_textAlignment 29319 */ 29320 @ViewDebug.ExportedProperty(category = "text", mapping = { 29321 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 29322 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 29323 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 29324 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 29325 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 29326 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 29327 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 29328 }) 29329 @InspectableProperty(enumMapping = { 29330 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 29331 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 29332 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 29333 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 29334 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 29335 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 29336 }) 29337 @TextAlignment getTextAlignment()29338 public int getTextAlignment() { 29339 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 29340 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 29341 } 29342 29343 /** 29344 * Resolve the text alignment. 29345 * 29346 * @return true if resolution has been done, false otherwise. 29347 * 29348 * @hide 29349 */ resolveTextAlignment()29350 public boolean resolveTextAlignment() { 29351 // Reset any previous text alignment resolution 29352 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 29353 29354 if (hasRtlSupport()) { 29355 // Set resolved text alignment flag depending on text alignment flag 29356 final int textAlignment = getRawTextAlignment(); 29357 switch (textAlignment) { 29358 case TEXT_ALIGNMENT_INHERIT: 29359 // Check if we can resolve the text alignment 29360 if (!canResolveTextAlignment()) { 29361 // We cannot do the resolution if there is no parent so use the default 29362 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 29363 // Resolution will need to happen again later 29364 return false; 29365 } 29366 29367 // Parent has not yet resolved, so we still return the default 29368 try { 29369 if (!mParent.isTextAlignmentResolved()) { 29370 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 29371 // Resolution will need to happen again later 29372 return false; 29373 } 29374 } catch (AbstractMethodError e) { 29375 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 29376 " does not fully implement ViewParent", e); 29377 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 29378 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 29379 return true; 29380 } 29381 29382 int parentResolvedTextAlignment; 29383 try { 29384 parentResolvedTextAlignment = mParent.getTextAlignment(); 29385 } catch (AbstractMethodError e) { 29386 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 29387 " does not fully implement ViewParent", e); 29388 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 29389 } 29390 switch (parentResolvedTextAlignment) { 29391 case TEXT_ALIGNMENT_GRAVITY: 29392 case TEXT_ALIGNMENT_TEXT_START: 29393 case TEXT_ALIGNMENT_TEXT_END: 29394 case TEXT_ALIGNMENT_CENTER: 29395 case TEXT_ALIGNMENT_VIEW_START: 29396 case TEXT_ALIGNMENT_VIEW_END: 29397 // Resolved text alignment is the same as the parent resolved 29398 // text alignment 29399 mPrivateFlags2 |= 29400 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 29401 break; 29402 default: 29403 // Use default resolved text alignment 29404 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 29405 } 29406 break; 29407 case TEXT_ALIGNMENT_GRAVITY: 29408 case TEXT_ALIGNMENT_TEXT_START: 29409 case TEXT_ALIGNMENT_TEXT_END: 29410 case TEXT_ALIGNMENT_CENTER: 29411 case TEXT_ALIGNMENT_VIEW_START: 29412 case TEXT_ALIGNMENT_VIEW_END: 29413 // Resolved text alignment is the same as text alignment 29414 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 29415 break; 29416 default: 29417 // Use default resolved text alignment 29418 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 29419 } 29420 } else { 29421 // Use default resolved text alignment 29422 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 29423 } 29424 29425 // Set the resolved 29426 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 29427 return true; 29428 } 29429 29430 /** 29431 * Check if text alignment resolution can be done. 29432 * 29433 * @return true if text alignment resolution can be done otherwise return false. 29434 */ canResolveTextAlignment()29435 public boolean canResolveTextAlignment() { 29436 switch (getRawTextAlignment()) { 29437 case TEXT_DIRECTION_INHERIT: 29438 if (mParent != null) { 29439 try { 29440 return mParent.canResolveTextAlignment(); 29441 } catch (AbstractMethodError e) { 29442 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 29443 " does not fully implement ViewParent", e); 29444 } 29445 } 29446 return false; 29447 29448 default: 29449 return true; 29450 } 29451 } 29452 29453 /** 29454 * Reset resolved text alignment. Text alignment will be resolved during a call to 29455 * {@link #onMeasure(int, int)}. 29456 * 29457 * @hide 29458 */ 29459 @TestApi resetResolvedTextAlignment()29460 public void resetResolvedTextAlignment() { 29461 // Reset any previous text alignment resolution 29462 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 29463 // Set to default 29464 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 29465 } 29466 29467 /** 29468 * @return true if text alignment is inherited. 29469 * 29470 * @hide 29471 */ isTextAlignmentInherited()29472 public boolean isTextAlignmentInherited() { 29473 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 29474 } 29475 29476 /** 29477 * @return true if text alignment is resolved. 29478 */ isTextAlignmentResolved()29479 public boolean isTextAlignmentResolved() { 29480 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 29481 } 29482 29483 /** 29484 * Generate a value suitable for use in {@link #setId(int)}. 29485 * This value will not collide with ID values generated at build time by aapt for R.id. 29486 * 29487 * @return a generated ID value 29488 */ generateViewId()29489 public static int generateViewId() { 29490 for (;;) { 29491 final int result = sNextGeneratedId.get(); 29492 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 29493 int newValue = result + 1; 29494 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 29495 if (sNextGeneratedId.compareAndSet(result, newValue)) { 29496 return result; 29497 } 29498 } 29499 } 29500 isViewIdGenerated(int id)29501 private static boolean isViewIdGenerated(int id) { 29502 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 29503 } 29504 29505 /** 29506 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 29507 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 29508 * a normal View or a ViewGroup with 29509 * {@link android.view.ViewGroup#isTransitionGroup()} true. 29510 * @hide 29511 */ captureTransitioningViews(List<View> transitioningViews)29512 public void captureTransitioningViews(List<View> transitioningViews) { 29513 if (getVisibility() == View.VISIBLE) { 29514 transitioningViews.add(this); 29515 } 29516 } 29517 29518 /** 29519 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 29520 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 29521 * @hide 29522 */ findNamedViews(Map<String, View> namedElements)29523 public void findNamedViews(Map<String, View> namedElements) { 29524 if (getVisibility() == VISIBLE || mGhostView != null) { 29525 String transitionName = getTransitionName(); 29526 if (transitionName != null) { 29527 namedElements.put(transitionName, this); 29528 } 29529 } 29530 } 29531 29532 /** 29533 * Resolve the pointer icon that should be used for specified pointer in the motion event. 29534 * 29535 * The default implementation will resolve the pointer icon to one set using 29536 * {@link #setPointerIcon(PointerIcon)} for mouse devices. Subclasses may override this to 29537 * customize the icon for the given pointer. 29538 * 29539 * For example, the pointer icon for a stylus pointer can be resolved in the following way: 29540 * <code><pre> 29541 * @Override 29542 * public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 29543 * final int toolType = event.getToolType(pointerIndex); 29544 * if (!event.isFromSource(InputDevice.SOURCE_MOUSE) 29545 * && event.isFromSource(InputDevice.SOURCE_STYLUS) 29546 * && (toolType == MotionEvent.TOOL_TYPE_STYLUS 29547 * || toolType == MotionEvent.TOOL_TYPE_ERASER)) { 29548 * // Show this pointer icon only if this pointer is a stylus. 29549 * return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_WAIT); 29550 * } 29551 * // Use the default logic for determining the pointer icon for other non-stylus pointers, 29552 * // like for the mouse cursor. 29553 * return super.onResolvePointerIcon(event, pointerIndex); 29554 * } 29555 * </pre></code> 29556 * 29557 * @param event The {@link MotionEvent} that requires a pointer icon to be resolved for one of 29558 * pointers. 29559 * @param pointerIndex The index of the pointer in {@code event} for which to retrieve the 29560 * {@link PointerIcon}. This will be between 0 and {@link MotionEvent#getPointerCount()}. 29561 * @return the pointer icon to use for specified pointer, or {@code null} if a pointer icon 29562 * is not specified and the default icon should be used. 29563 * @see PointerIcon 29564 * @see InputManager#isStylusPointerIconEnabled() 29565 */ onResolvePointerIcon(MotionEvent event, int pointerIndex)29566 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 29567 final float x = event.getX(pointerIndex); 29568 final float y = event.getY(pointerIndex); 29569 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 29570 // Use the default pointer icon. 29571 return null; 29572 } 29573 29574 // Note: A drawing tablet will have both SOURCE_MOUSE and SOURCE_STYLUS, but it would use 29575 // TOOL_TYPE_STYLUS. For now, treat drawing tablets the same way as a mouse or touchpad. 29576 if (event.isFromSource(InputDevice.SOURCE_MOUSE)) { 29577 return mMousePointerIcon; 29578 } 29579 29580 return null; 29581 } 29582 29583 /** 29584 * Set the pointer icon to be used for a mouse pointer in the current view. 29585 * 29586 * Passing {@code null} will restore the pointer icon to its default value. 29587 * Note that setting the pointer icon using this method will only set it for events coming from 29588 * a mouse device (i.e. with source {@link InputDevice#SOURCE_MOUSE}). To resolve 29589 * the pointer icon for other device types like styluses, override 29590 * {@link #onResolvePointerIcon(MotionEvent, int)}. 29591 * 29592 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 29593 * @see #onResolvePointerIcon(MotionEvent, int) 29594 * @see PointerIcon 29595 */ setPointerIcon(PointerIcon pointerIcon)29596 public void setPointerIcon(PointerIcon pointerIcon) { 29597 mMousePointerIcon = pointerIcon; 29598 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 29599 return; 29600 } 29601 try { 29602 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 29603 } catch (RemoteException e) { 29604 } 29605 } 29606 29607 /** 29608 * Gets the mouse pointer icon for the current view. 29609 * 29610 * @see #setPointerIcon(PointerIcon) 29611 */ 29612 @InspectableProperty getPointerIcon()29613 public PointerIcon getPointerIcon() { 29614 return mMousePointerIcon; 29615 } 29616 29617 /** 29618 * Checks pointer capture status. 29619 * 29620 * @return true if the view has pointer capture. 29621 * @see #requestPointerCapture() 29622 * @see #hasPointerCapture() 29623 */ hasPointerCapture()29624 public boolean hasPointerCapture() { 29625 final ViewRootImpl viewRootImpl = getViewRootImpl(); 29626 if (viewRootImpl == null) { 29627 return false; 29628 } 29629 return viewRootImpl.hasPointerCapture(); 29630 } 29631 29632 /** 29633 * Requests pointer capture mode. 29634 * <p> 29635 * When the window has pointer capture, the mouse pointer icon will disappear and will not 29636 * change its position. Enabling pointer capture will change the behavior of input devices in 29637 * the following ways: 29638 * <ul> 29639 * <li>Events from a mouse will be delivered with the source 29640 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be 29641 * available through {@link MotionEvent#getX} and {@link MotionEvent#getY}.</li> 29642 * 29643 * <li>Events from a touchpad or trackpad will be delivered with the source 29644 * {@link InputDevice#SOURCE_TOUCHPAD}, where the absolute position of each of the pointers 29645 * on the touchpad will be available through {@link MotionEvent#getX(int)} and 29646 * {@link MotionEvent#getY(int)}, and their relative movements are stored in 29647 * {@link MotionEvent#AXIS_RELATIVE_X} and {@link MotionEvent#AXIS_RELATIVE_Y}.</li> 29648 * 29649 * <li>Events from other types of devices, such as touchscreens, will not be affected.</li> 29650 * </ul> 29651 * <p> 29652 * When pointer capture changes, connected mouse and trackpad devices may be reconfigured, 29653 * and their properties (such as their sources or motion ranges) may change. Use an 29654 * {@link android.hardware.input.InputManager.InputDeviceListener} to be notified when a device 29655 * changes (which may happen after enabling or disabling pointer capture), and use 29656 * {@link InputDevice#getDevice(int)} to get the updated {@link InputDevice}. 29657 * <p> 29658 * Events captured through pointer capture will be dispatched to 29659 * {@link OnCapturedPointerListener#onCapturedPointer(View, MotionEvent)} if an 29660 * {@link OnCapturedPointerListener} is set, and otherwise to 29661 * {@link #onCapturedPointerEvent(MotionEvent)}. 29662 * <p> 29663 * If the window already has pointer capture, this call does nothing. 29664 * <p> 29665 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 29666 * automatically when the window loses focus. 29667 * 29668 * @see #releasePointerCapture() 29669 * @see #hasPointerCapture() 29670 * @see #onPointerCaptureChange(boolean) 29671 */ requestPointerCapture()29672 public void requestPointerCapture() { 29673 final ViewRootImpl viewRootImpl = getViewRootImpl(); 29674 if (viewRootImpl != null) { 29675 viewRootImpl.requestPointerCapture(true); 29676 } 29677 } 29678 29679 29680 /** 29681 * Releases the pointer capture. 29682 * <p> 29683 * If the window does not have pointer capture, this call will do nothing. 29684 * @see #requestPointerCapture() 29685 * @see #hasPointerCapture() 29686 * @see #onPointerCaptureChange(boolean) 29687 */ releasePointerCapture()29688 public void releasePointerCapture() { 29689 final ViewRootImpl viewRootImpl = getViewRootImpl(); 29690 if (viewRootImpl != null) { 29691 viewRootImpl.requestPointerCapture(false); 29692 } 29693 } 29694 29695 /** 29696 * Called when the window has just acquired or lost pointer capture. 29697 * 29698 * @param hasCapture True if the view now has pointerCapture, false otherwise. 29699 */ 29700 @CallSuper onPointerCaptureChange(boolean hasCapture)29701 public void onPointerCaptureChange(boolean hasCapture) { 29702 } 29703 29704 /** 29705 * @see #onPointerCaptureChange 29706 */ dispatchPointerCaptureChanged(boolean hasCapture)29707 public void dispatchPointerCaptureChanged(boolean hasCapture) { 29708 onPointerCaptureChange(hasCapture); 29709 } 29710 29711 /** 29712 * Implement this method to handle captured pointer events 29713 * 29714 * @param event The captured pointer event. 29715 * @return True if the event was handled, false otherwise. 29716 * @see #requestPointerCapture() 29717 */ onCapturedPointerEvent(MotionEvent event)29718 public boolean onCapturedPointerEvent(MotionEvent event) { 29719 return false; 29720 } 29721 29722 /** 29723 * Interface definition for a callback to be invoked when a captured pointer event 29724 * is being dispatched this view. The callback will be invoked before the event is 29725 * given to the view. 29726 */ 29727 public interface OnCapturedPointerListener { 29728 /** 29729 * Called when a captured pointer event is dispatched to a view. 29730 * @param view The view this event has been dispatched to. 29731 * @param event The captured event. 29732 * @return True if the listener has consumed the event, false otherwise. 29733 */ onCapturedPointer(View view, MotionEvent event)29734 boolean onCapturedPointer(View view, MotionEvent event); 29735 } 29736 29737 /** 29738 * Set a listener to receive callbacks when the pointer capture state of a view changes. 29739 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 29740 */ setOnCapturedPointerListener(OnCapturedPointerListener l)29741 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 29742 getListenerInfo().mOnCapturedPointerListener = l; 29743 } 29744 29745 // Properties 29746 // 29747 /** 29748 * A Property wrapper around the <code>alpha</code> functionality handled by the 29749 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 29750 */ 29751 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 29752 @Override 29753 public void setValue(View object, float value) { 29754 object.setAlpha(value); 29755 } 29756 29757 @Override 29758 public Float get(View object) { 29759 return object.getAlpha(); 29760 } 29761 }; 29762 29763 /** 29764 * A Property wrapper around the <code>translationX</code> functionality handled by the 29765 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 29766 */ 29767 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 29768 @Override 29769 public void setValue(View object, float value) { 29770 object.setTranslationX(value); 29771 } 29772 29773 @Override 29774 public Float get(View object) { 29775 return object.getTranslationX(); 29776 } 29777 }; 29778 29779 /** 29780 * A Property wrapper around the <code>translationY</code> functionality handled by the 29781 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 29782 */ 29783 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 29784 @Override 29785 public void setValue(View object, float value) { 29786 object.setTranslationY(value); 29787 } 29788 29789 @Override 29790 public Float get(View object) { 29791 return object.getTranslationY(); 29792 } 29793 }; 29794 29795 /** 29796 * A Property wrapper around the <code>translationZ</code> functionality handled by the 29797 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 29798 */ 29799 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 29800 @Override 29801 public void setValue(View object, float value) { 29802 object.setTranslationZ(value); 29803 } 29804 29805 @Override 29806 public Float get(View object) { 29807 return object.getTranslationZ(); 29808 } 29809 }; 29810 29811 /** 29812 * A Property wrapper around the <code>x</code> functionality handled by the 29813 * {@link View#setX(float)} and {@link View#getX()} methods. 29814 */ 29815 public static final Property<View, Float> X = new FloatProperty<View>("x") { 29816 @Override 29817 public void setValue(View object, float value) { 29818 object.setX(value); 29819 } 29820 29821 @Override 29822 public Float get(View object) { 29823 return object.getX(); 29824 } 29825 }; 29826 29827 /** 29828 * A Property wrapper around the <code>y</code> functionality handled by the 29829 * {@link View#setY(float)} and {@link View#getY()} methods. 29830 */ 29831 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 29832 @Override 29833 public void setValue(View object, float value) { 29834 object.setY(value); 29835 } 29836 29837 @Override 29838 public Float get(View object) { 29839 return object.getY(); 29840 } 29841 }; 29842 29843 /** 29844 * A Property wrapper around the <code>z</code> functionality handled by the 29845 * {@link View#setZ(float)} and {@link View#getZ()} methods. 29846 */ 29847 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 29848 @Override 29849 public void setValue(View object, float value) { 29850 object.setZ(value); 29851 } 29852 29853 @Override 29854 public Float get(View object) { 29855 return object.getZ(); 29856 } 29857 }; 29858 29859 /** 29860 * A Property wrapper around the <code>rotation</code> functionality handled by the 29861 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 29862 */ 29863 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 29864 @Override 29865 public void setValue(View object, float value) { 29866 object.setRotation(value); 29867 } 29868 29869 @Override 29870 public Float get(View object) { 29871 return object.getRotation(); 29872 } 29873 }; 29874 29875 /** 29876 * A Property wrapper around the <code>rotationX</code> functionality handled by the 29877 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 29878 */ 29879 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 29880 @Override 29881 public void setValue(View object, float value) { 29882 object.setRotationX(value); 29883 } 29884 29885 @Override 29886 public Float get(View object) { 29887 return object.getRotationX(); 29888 } 29889 }; 29890 29891 /** 29892 * A Property wrapper around the <code>rotationY</code> functionality handled by the 29893 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 29894 */ 29895 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 29896 @Override 29897 public void setValue(View object, float value) { 29898 object.setRotationY(value); 29899 } 29900 29901 @Override 29902 public Float get(View object) { 29903 return object.getRotationY(); 29904 } 29905 }; 29906 29907 /** 29908 * A Property wrapper around the <code>scaleX</code> functionality handled by the 29909 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 29910 */ 29911 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 29912 @Override 29913 public void setValue(View object, float value) { 29914 object.setScaleX(value); 29915 } 29916 29917 @Override 29918 public Float get(View object) { 29919 return object.getScaleX(); 29920 } 29921 }; 29922 29923 /** 29924 * A Property wrapper around the <code>scaleY</code> functionality handled by the 29925 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 29926 */ 29927 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 29928 @Override 29929 public void setValue(View object, float value) { 29930 object.setScaleY(value); 29931 } 29932 29933 @Override 29934 public Float get(View object) { 29935 return object.getScaleY(); 29936 } 29937 }; 29938 29939 /** 29940 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 29941 * Each MeasureSpec represents a requirement for either the width or the height. 29942 * A MeasureSpec is comprised of a size and a mode. There are three possible 29943 * modes: 29944 * <dl> 29945 * <dt>UNSPECIFIED</dt> 29946 * <dd> 29947 * The parent has not imposed any constraint on the child. It can be whatever size 29948 * it wants. 29949 * </dd> 29950 * 29951 * <dt>EXACTLY</dt> 29952 * <dd> 29953 * The parent has determined an exact size for the child. The child is going to be 29954 * given those bounds regardless of how big it wants to be. 29955 * </dd> 29956 * 29957 * <dt>AT_MOST</dt> 29958 * <dd> 29959 * The child can be as large as it wants up to the specified size. 29960 * </dd> 29961 * </dl> 29962 * 29963 * MeasureSpecs are implemented as ints to reduce object allocation. This class 29964 * is provided to pack and unpack the <size, mode> tuple into the int. 29965 */ 29966 public static class MeasureSpec { 29967 private static final int MODE_SHIFT = 30; 29968 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 29969 29970 /** @hide */ 29971 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 29972 @Retention(RetentionPolicy.SOURCE) 29973 public @interface MeasureSpecMode {} 29974 29975 /** 29976 * Measure specification mode: The parent has not imposed any constraint 29977 * on the child. It can be whatever size it wants. 29978 */ 29979 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 29980 29981 /** 29982 * Measure specification mode: The parent has determined an exact size 29983 * for the child. The child is going to be given those bounds regardless 29984 * of how big it wants to be. 29985 */ 29986 public static final int EXACTLY = 1 << MODE_SHIFT; 29987 29988 /** 29989 * Measure specification mode: The child can be as large as it wants up 29990 * to the specified size. 29991 */ 29992 public static final int AT_MOST = 2 << MODE_SHIFT; 29993 29994 /** 29995 * Creates a measure specification based on the supplied size and mode. 29996 * 29997 * The mode must always be one of the following: 29998 * <ul> 29999 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 30000 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 30001 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 30002 * </ul> 30003 * 30004 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 30005 * implementation was such that the order of arguments did not matter 30006 * and overflow in either value could impact the resulting MeasureSpec. 30007 * {@link android.widget.RelativeLayout} was affected by this bug. 30008 * Apps targeting API levels greater than 17 will get the fixed, more strict 30009 * behavior.</p> 30010 * 30011 * @param size the size of the measure specification 30012 * @param mode the mode of the measure specification 30013 * @return the measure specification based on size and mode 30014 */ makeMeasureSpec(@ntRangefrom = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode)30015 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 30016 @MeasureSpecMode int mode) { 30017 if (sUseBrokenMakeMeasureSpec) { 30018 return size + mode; 30019 } else { 30020 return (size & ~MODE_MASK) | (mode & MODE_MASK); 30021 } 30022 } 30023 30024 /** 30025 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 30026 * will automatically get a size of 0. Older apps expect this. 30027 * 30028 * @hide internal use only for compatibility with system widgets and older apps 30029 */ 30030 @UnsupportedAppUsage makeSafeMeasureSpec(int size, int mode)30031 public static int makeSafeMeasureSpec(int size, int mode) { 30032 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 30033 return 0; 30034 } 30035 return makeMeasureSpec(size, mode); 30036 } 30037 30038 /** 30039 * Extracts the mode from the supplied measure specification. 30040 * 30041 * @param measureSpec the measure specification to extract the mode from 30042 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 30043 * {@link android.view.View.MeasureSpec#AT_MOST} or 30044 * {@link android.view.View.MeasureSpec#EXACTLY} 30045 */ 30046 @MeasureSpecMode getMode(int measureSpec)30047 public static int getMode(int measureSpec) { 30048 //noinspection ResourceType 30049 return (measureSpec & MODE_MASK); 30050 } 30051 30052 /** 30053 * Extracts the size from the supplied measure specification. 30054 * 30055 * @param measureSpec the measure specification to extract the size from 30056 * @return the size in pixels defined in the supplied measure specification 30057 */ getSize(int measureSpec)30058 public static int getSize(int measureSpec) { 30059 return (measureSpec & ~MODE_MASK); 30060 } 30061 adjust(int measureSpec, int delta)30062 static int adjust(int measureSpec, int delta) { 30063 final int mode = getMode(measureSpec); 30064 int size = getSize(measureSpec); 30065 if (mode == UNSPECIFIED) { 30066 // No need to adjust size for UNSPECIFIED mode. 30067 return makeMeasureSpec(size, UNSPECIFIED); 30068 } 30069 size += delta; 30070 if (size < 0) { 30071 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 30072 ") spec: " + toString(measureSpec) + " delta: " + delta); 30073 size = 0; 30074 } 30075 return makeMeasureSpec(size, mode); 30076 } 30077 30078 /** 30079 * Returns a String representation of the specified measure 30080 * specification. 30081 * 30082 * @param measureSpec the measure specification to convert to a String 30083 * @return a String with the following format: "MeasureSpec: MODE SIZE" 30084 */ toString(int measureSpec)30085 public static String toString(int measureSpec) { 30086 int mode = getMode(measureSpec); 30087 int size = getSize(measureSpec); 30088 30089 StringBuilder sb = new StringBuilder("MeasureSpec: "); 30090 30091 if (mode == UNSPECIFIED) 30092 sb.append("UNSPECIFIED "); 30093 else if (mode == EXACTLY) 30094 sb.append("EXACTLY "); 30095 else if (mode == AT_MOST) 30096 sb.append("AT_MOST "); 30097 else 30098 sb.append(mode).append(" "); 30099 30100 sb.append(size); 30101 return sb.toString(); 30102 } 30103 } 30104 30105 private final class CheckForLongPress implements Runnable { 30106 private int mOriginalWindowAttachCount; 30107 private float mX; 30108 private float mY; 30109 private boolean mOriginalPressedState; 30110 /** 30111 * The classification of the long click being checked: one of the 30112 * FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__* constants. 30113 */ 30114 private int mClassification; 30115 30116 @UnsupportedAppUsage CheckForLongPress()30117 private CheckForLongPress() { 30118 } 30119 30120 @Override run()30121 public void run() { 30122 if ((mOriginalPressedState == isPressed()) && (mParent != null) 30123 && mOriginalWindowAttachCount == mWindowAttachCount) { 30124 recordGestureClassification(mClassification); 30125 if (performLongClick(mX, mY)) { 30126 mHasPerformedLongPress = true; 30127 } 30128 } 30129 } 30130 setAnchor(float x, float y)30131 public void setAnchor(float x, float y) { 30132 mX = x; 30133 mY = y; 30134 } 30135 rememberWindowAttachCount()30136 public void rememberWindowAttachCount() { 30137 mOriginalWindowAttachCount = mWindowAttachCount; 30138 } 30139 rememberPressedState()30140 public void rememberPressedState() { 30141 mOriginalPressedState = isPressed(); 30142 } 30143 setClassification(int classification)30144 public void setClassification(int classification) { 30145 mClassification = classification; 30146 } 30147 } 30148 30149 private final class CheckForTap implements Runnable { 30150 public float x; 30151 public float y; 30152 30153 @Override run()30154 public void run() { 30155 mPrivateFlags &= ~PFLAG_PREPRESSED; 30156 setPressed(true, x, y); 30157 final long delay = 30158 ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout(); 30159 checkForLongClick(delay, x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 30160 } 30161 } 30162 30163 private final class PerformClick implements Runnable { 30164 @Override run()30165 public void run() { 30166 recordGestureClassification(TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP); 30167 performClickInternal(); 30168 } 30169 } 30170 30171 /** Records a classification for the current event stream. */ recordGestureClassification(int classification)30172 private void recordGestureClassification(int classification) { 30173 if (classification == TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION) { 30174 return; 30175 } 30176 // To avoid negatively impacting View performance, the latency and displacement metrics 30177 // are omitted. 30178 FrameworkStatsLog.write(FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED, getClass().getName(), 30179 classification); 30180 } 30181 30182 /** 30183 * This method returns a ViewPropertyAnimator object, which can be used to animate 30184 * specific properties on this View. 30185 * 30186 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 30187 */ animate()30188 public ViewPropertyAnimator animate() { 30189 if (mAnimator == null) { 30190 mAnimator = new ViewPropertyAnimator(this); 30191 } 30192 return mAnimator; 30193 } 30194 30195 /** 30196 * Sets the name of the View to be used to identify Views in Transitions. 30197 * Names should be unique in the View hierarchy. 30198 * 30199 * @param transitionName The name of the View to uniquely identify it for Transitions. 30200 */ setTransitionName(String transitionName)30201 public final void setTransitionName(String transitionName) { 30202 mTransitionName = transitionName; 30203 } 30204 30205 /** 30206 * Returns the name of the View to be used to identify Views in Transitions. 30207 * Names should be unique in the View hierarchy. 30208 * 30209 * <p>This returns null if the View has not been given a name.</p> 30210 * 30211 * @return The name used of the View to be used to identify Views in Transitions or null 30212 * if no name has been given. 30213 */ 30214 @ViewDebug.ExportedProperty 30215 @InspectableProperty getTransitionName()30216 public String getTransitionName() { 30217 return mTransitionName; 30218 } 30219 30220 /** 30221 * @hide 30222 */ requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId)30223 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 30224 // Do nothing. 30225 } 30226 30227 /** 30228 * Interface definition for a callback to be invoked when a hardware key event is 30229 * dispatched to this view. The callback will be invoked before the key event is 30230 * given to the view. This is only useful for hardware keyboards; a software input 30231 * method has no obligation to trigger this listener. 30232 */ 30233 public interface OnKeyListener { 30234 /** 30235 * Called when a hardware key is dispatched to a view. This allows listeners to 30236 * get a chance to respond before the target view. 30237 * <p>Key presses in software keyboards will generally NOT trigger this method, 30238 * although some may elect to do so in some situations. Do not assume a 30239 * software input method has to be key-based; even if it is, it may use key presses 30240 * in a different way than you expect, so there is no way to reliably catch soft 30241 * input key presses. 30242 * 30243 * @param v The view the key has been dispatched to. 30244 * @param keyCode The code for the physical key that was pressed 30245 * @param event The KeyEvent object containing full information about 30246 * the event. 30247 * @return True if the listener has consumed the event, false otherwise. 30248 */ onKey(View v, int keyCode, KeyEvent event)30249 boolean onKey(View v, int keyCode, KeyEvent event); 30250 } 30251 30252 /** 30253 * Interface definition for a callback to be invoked when a hardware key event hasn't 30254 * been handled by the view hierarchy. 30255 */ 30256 public interface OnUnhandledKeyEventListener { 30257 /** 30258 * Called when a hardware key is dispatched to a view after being unhandled during normal 30259 * {@link KeyEvent} dispatch. 30260 * 30261 * @param v The view the key has been dispatched to. 30262 * @param event The KeyEvent object containing information about the event. 30263 * @return {@code true} if the listener has consumed the event, {@code false} otherwise. 30264 */ onUnhandledKeyEvent(View v, KeyEvent event)30265 boolean onUnhandledKeyEvent(View v, KeyEvent event); 30266 } 30267 30268 /** 30269 * Interface definition for a callback to be invoked when a touch event is 30270 * dispatched to this view. The callback will be invoked before the touch 30271 * event is given to the view. 30272 */ 30273 public interface OnTouchListener { 30274 /** 30275 * Called when a touch event is dispatched to a view. This allows listeners to 30276 * get a chance to respond before the target view. 30277 * 30278 * @param v The view the touch event has been dispatched to. 30279 * @param event The MotionEvent object containing full information about 30280 * the event. 30281 * @return True if the listener has consumed the event, false otherwise. 30282 */ onTouch(View v, MotionEvent event)30283 boolean onTouch(View v, MotionEvent event); 30284 } 30285 30286 /** 30287 * Interface definition for a callback to be invoked when a hover event is 30288 * dispatched to this view. The callback will be invoked before the hover 30289 * event is given to the view. 30290 */ 30291 public interface OnHoverListener { 30292 /** 30293 * Called when a hover event is dispatched to a view. This allows listeners to 30294 * get a chance to respond before the target view. 30295 * 30296 * @param v The view the hover event has been dispatched to. 30297 * @param event The MotionEvent object containing full information about 30298 * the event. 30299 * @return True if the listener has consumed the event, false otherwise. 30300 */ onHover(View v, MotionEvent event)30301 boolean onHover(View v, MotionEvent event); 30302 } 30303 30304 /** 30305 * Interface definition for a callback to be invoked when a generic motion event is 30306 * dispatched to this view. The callback will be invoked before the generic motion 30307 * event is given to the view. 30308 */ 30309 public interface OnGenericMotionListener { 30310 /** 30311 * Called when a generic motion event is dispatched to a view. This allows listeners to 30312 * get a chance to respond before the target view. 30313 * 30314 * @param v The view the generic motion event has been dispatched to. 30315 * @param event The MotionEvent object containing full information about 30316 * the event. 30317 * @return True if the listener has consumed the event, false otherwise. 30318 */ onGenericMotion(View v, MotionEvent event)30319 boolean onGenericMotion(View v, MotionEvent event); 30320 } 30321 30322 /** 30323 * Interface definition for a callback to be invoked when a view has been clicked and held. 30324 */ 30325 public interface OnLongClickListener { 30326 /** 30327 * Called when a view has been clicked and held. 30328 * 30329 * @param v The view that was clicked and held. 30330 * 30331 * @return true if the callback consumed the long click, false otherwise. 30332 */ onLongClick(View v)30333 boolean onLongClick(View v); 30334 30335 /** 30336 * Returns whether the default {@link HapticFeedbackConstants#LONG_PRESS} haptic feedback 30337 * is performed when this listener has consumed the long click. This method is called 30338 * immediately after {@link #onLongClick} has returned true. 30339 * 30340 * @param v The view that was clicked and held. 30341 * @return true to perform the default {@link HapticFeedbackConstants#LONG_PRESS} haptic 30342 * feedback, or false if the handler manages all haptics itself. 30343 */ onLongClickUseDefaultHapticFeedback(@onNull View v)30344 default boolean onLongClickUseDefaultHapticFeedback(@NonNull View v) { 30345 return true; 30346 } 30347 } 30348 30349 /** 30350 * Interface definition for a listener that's invoked when a drag event is dispatched to this 30351 * view. The listener is invoked before the view's own 30352 * {@link #onDragEvent(DragEvent)} method. To fall back to the view's 30353 * {@code onDragEvent(DragEvent)} behavior, return {@code false} from the listener method. 30354 * 30355 * <div class="special reference"> 30356 * <h3>Developer Guides</h3> 30357 * <p>For a guide to implementing drag and drop features, see the 30358 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and drop</a> developer guide.</p> 30359 * </div> 30360 */ 30361 public interface OnDragListener { 30362 /** 30363 * Called when a drag event is dispatched to a view. Enables listeners to override the 30364 * base behavior provided by {@link #onDragEvent(DragEvent)}. 30365 * 30366 * @param v The {@code View} that received the drag event. 30367 * @param event The event object for the drag event. 30368 * @return {@code true} if the drag event was handled successfully; {@code false}, if the 30369 * drag event was not handled. <b>Note:</b> A {@code false} return value triggers the 30370 * view's {@link #onDragEvent(DragEvent)} handler. 30371 */ onDrag(View v, DragEvent event)30372 boolean onDrag(View v, DragEvent event); 30373 } 30374 30375 /** 30376 * Interface definition for a callback to be invoked when the focus state of 30377 * a view changed. 30378 */ 30379 public interface OnFocusChangeListener { 30380 /** 30381 * Called when the focus state of a view has changed. 30382 * 30383 * @param v The view whose state has changed. 30384 * @param hasFocus The new focus state of v. 30385 */ onFocusChange(View v, boolean hasFocus)30386 void onFocusChange(View v, boolean hasFocus); 30387 } 30388 30389 /** 30390 * Interface definition for a callback to be invoked when a view is clicked. 30391 */ 30392 public interface OnClickListener { 30393 /** 30394 * Called when a view has been clicked. 30395 * 30396 * @param v The view that was clicked. 30397 */ onClick(View v)30398 void onClick(View v); 30399 } 30400 30401 /** 30402 * Interface definition for a callback to be invoked when a view is context clicked. 30403 */ 30404 public interface OnContextClickListener { 30405 /** 30406 * Called when a view is context clicked. 30407 * 30408 * @param v The view that has been context clicked. 30409 * @return true if the callback consumed the context click, false otherwise. 30410 */ onContextClick(View v)30411 boolean onContextClick(View v); 30412 } 30413 30414 /** 30415 * Interface definition for a callback to be invoked when the context menu 30416 * for this view is being built. 30417 */ 30418 public interface OnCreateContextMenuListener { 30419 /** 30420 * Called when the context menu for this view is being built. It is not 30421 * safe to hold onto the menu after this method returns. 30422 * 30423 * @param menu The context menu that is being built 30424 * @param v The view for which the context menu is being built 30425 * @param menuInfo Extra information about the item for which the 30426 * context menu should be shown. This information will vary 30427 * depending on the class of v. 30428 */ onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)30429 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 30430 } 30431 30432 /** 30433 * Interface definition for a callback to be invoked when the status bar changes 30434 * visibility. This reports <strong>global</strong> changes to the system UI 30435 * state, not what the application is requesting. 30436 * 30437 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 30438 * 30439 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 30440 * by setting a {@link OnApplyWindowInsetsListener} on this view. 30441 */ 30442 @Deprecated 30443 public interface OnSystemUiVisibilityChangeListener { 30444 /** 30445 * Called when the status bar changes visibility because of a call to 30446 * {@link View#setSystemUiVisibility(int)}. 30447 * 30448 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 30449 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 30450 * This tells you the <strong>global</strong> state of these UI visibility 30451 * flags, not what your app is currently applying. 30452 */ onSystemUiVisibilityChange(int visibility)30453 public void onSystemUiVisibilityChange(int visibility); 30454 } 30455 30456 /** 30457 * Interface definition for a callback to be invoked when this view is attached 30458 * or detached from its window. 30459 */ 30460 public interface OnAttachStateChangeListener { 30461 /** 30462 * Called when the view is attached to a window. 30463 * @param v The view that was attached 30464 */ onViewAttachedToWindow(@onNull View v)30465 public void onViewAttachedToWindow(@NonNull View v); 30466 /** 30467 * Called when the view is detached from a window. 30468 * @param v The view that was detached 30469 */ onViewDetachedFromWindow(@onNull View v)30470 public void onViewDetachedFromWindow(@NonNull View v); 30471 } 30472 30473 /** 30474 * Listener for applying window insets on a view in a custom way. 30475 * 30476 * <p>Apps may choose to implement this interface if they want to apply custom policy 30477 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 30478 * is set, its 30479 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 30480 * method will be called instead of the View's own 30481 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 30482 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 30483 * the View's normal behavior as part of its own.</p> 30484 */ 30485 public interface OnApplyWindowInsetsListener { 30486 /** 30487 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 30488 * on a View, this listener method will be called instead of the view's own 30489 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 30490 * 30491 * @param v The view applying window insets 30492 * @param insets The insets to apply 30493 * @return The insets supplied, minus any insets that were consumed 30494 */ onApplyWindowInsets(@onNull View v, @NonNull WindowInsets insets)30495 public @NonNull WindowInsets onApplyWindowInsets(@NonNull View v, 30496 @NonNull WindowInsets insets); 30497 } 30498 30499 private final class UnsetPressedState implements Runnable { 30500 @Override run()30501 public void run() { 30502 setPressed(false); 30503 } 30504 } 30505 30506 /** 30507 * When a view becomes invisible checks if autofill considers the view invisible too. This 30508 * happens after the regular removal operation to make sure the operation is finished by the 30509 * time this is called. 30510 */ 30511 private static class VisibilityChangeForAutofillHandler extends Handler { 30512 private final AutofillManager mAfm; 30513 private final View mView; 30514 VisibilityChangeForAutofillHandler(@onNull AutofillManager afm, @NonNull View view)30515 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, 30516 @NonNull View view) { 30517 mAfm = afm; 30518 mView = view; 30519 } 30520 30521 @Override handleMessage(Message msg)30522 public void handleMessage(Message msg) { 30523 mAfm.notifyViewVisibilityChanged(mView, mView.isShown()); 30524 } 30525 } 30526 30527 /** 30528 * Base class for derived classes that want to save and restore their own 30529 * state in {@link android.view.View#onSaveInstanceState()}. 30530 */ 30531 public static class BaseSavedState extends AbsSavedState { 30532 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; 30533 static final int IS_AUTOFILLED = 0b10; 30534 static final int AUTOFILL_ID = 0b100; 30535 30536 // Flags that describe what data in this state is valid 30537 int mSavedData; 30538 String mStartActivityRequestWhoSaved; 30539 boolean mIsAutofilled; 30540 boolean mHideHighlight; 30541 int mAutofillViewId; 30542 30543 /** 30544 * Constructor used when reading from a parcel. Reads the state of the superclass. 30545 * 30546 * @param source parcel to read from 30547 */ BaseSavedState(Parcel source)30548 public BaseSavedState(Parcel source) { 30549 this(source, null); 30550 } 30551 30552 /** 30553 * Constructor used when reading from a parcel using a given class loader. 30554 * Reads the state of the superclass. 30555 * 30556 * @param source parcel to read from 30557 * @param loader ClassLoader to use for reading 30558 */ BaseSavedState(Parcel source, ClassLoader loader)30559 public BaseSavedState(Parcel source, ClassLoader loader) { 30560 super(source, loader); 30561 mSavedData = source.readInt(); 30562 mStartActivityRequestWhoSaved = source.readString(); 30563 mIsAutofilled = source.readBoolean(); 30564 mHideHighlight = source.readBoolean(); 30565 mAutofillViewId = source.readInt(); 30566 } 30567 30568 /** 30569 * Constructor called by derived classes when creating their SavedState objects 30570 * 30571 * @param superState The state of the superclass of this view 30572 */ BaseSavedState(Parcelable superState)30573 public BaseSavedState(Parcelable superState) { 30574 super(superState); 30575 } 30576 30577 @Override writeToParcel(Parcel out, int flags)30578 public void writeToParcel(Parcel out, int flags) { 30579 super.writeToParcel(out, flags); 30580 30581 out.writeInt(mSavedData); 30582 out.writeString(mStartActivityRequestWhoSaved); 30583 out.writeBoolean(mIsAutofilled); 30584 out.writeBoolean(mHideHighlight); 30585 out.writeInt(mAutofillViewId); 30586 } 30587 30588 public static final @android.annotation.NonNull Parcelable.Creator<BaseSavedState> CREATOR 30589 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 30590 @Override 30591 public BaseSavedState createFromParcel(Parcel in) { 30592 return new BaseSavedState(in); 30593 } 30594 30595 @Override 30596 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 30597 return new BaseSavedState(in, loader); 30598 } 30599 30600 @Override 30601 public BaseSavedState[] newArray(int size) { 30602 return new BaseSavedState[size]; 30603 } 30604 }; 30605 } 30606 30607 /** 30608 * A set of information given to a view when it is attached to its parent 30609 * window. 30610 */ 30611 final static class AttachInfo { 30612 30613 interface Callbacks { playSoundEffect(int effectId)30614 void playSoundEffect(int effectId); performHapticFeedback(int effectId, boolean always)30615 boolean performHapticFeedback(int effectId, boolean always); 30616 } 30617 30618 /** 30619 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 30620 * to a Handler. This class contains the target (View) to invalidate and 30621 * the coordinates of the dirty rectangle. 30622 * 30623 * For performance purposes, this class also implements a pool of up to 30624 * POOL_LIMIT objects that get reused. This reduces memory allocations 30625 * whenever possible. 30626 */ 30627 static class InvalidateInfo { 30628 30629 @UnsupportedAppUsage InvalidateInfo()30630 InvalidateInfo() { 30631 } 30632 30633 private static final int POOL_LIMIT = 10; 30634 30635 private static final SynchronizedPool<InvalidateInfo> sPool = 30636 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 30637 30638 @UnsupportedAppUsage 30639 View target; 30640 30641 @UnsupportedAppUsage 30642 int left; 30643 @UnsupportedAppUsage 30644 int top; 30645 @UnsupportedAppUsage 30646 int right; 30647 @UnsupportedAppUsage 30648 int bottom; 30649 obtain()30650 public static InvalidateInfo obtain() { 30651 InvalidateInfo instance = sPool.acquire(); 30652 return (instance != null) ? instance : new InvalidateInfo(); 30653 } 30654 recycle()30655 public void recycle() { 30656 target = null; 30657 sPool.release(this); 30658 } 30659 } 30660 30661 @UnsupportedAppUsage 30662 final IWindowSession mSession; 30663 30664 @UnsupportedAppUsage 30665 final IWindow mWindow; 30666 30667 final IBinder mWindowToken; 30668 30669 Display mDisplay; 30670 30671 final Callbacks mRootCallbacks; 30672 30673 IWindowId mIWindowId; 30674 WindowId mWindowId; 30675 30676 /** 30677 * The top view of the hierarchy. 30678 */ 30679 View mRootView; 30680 30681 IBinder mPanelParentWindowToken; 30682 30683 boolean mHardwareAccelerated; 30684 boolean mHardwareAccelerationRequested; 30685 ThreadedRenderer mThreadedRenderer; 30686 List<RenderNode> mPendingAnimatingRenderNodes; 30687 30688 /** 30689 * The state of the display to which the window is attached, as reported 30690 * by {@link Display#getState()}. Note that the display state constants 30691 * declared by {@link Display} do not exactly line up with the screen state 30692 * constants declared by {@link View} (there are more display states than 30693 * screen states). 30694 */ 30695 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 30696 int mDisplayState = Display.STATE_UNKNOWN; 30697 30698 /** 30699 * Scale factor used by the compatibility mode 30700 */ 30701 @UnsupportedAppUsage 30702 float mApplicationScale; 30703 30704 /** 30705 * Indicates whether the application is in compatibility mode 30706 */ 30707 @UnsupportedAppUsage 30708 boolean mScalingRequired; 30709 30710 /** 30711 * Left position of this view's window 30712 */ 30713 int mWindowLeft; 30714 30715 /** 30716 * Top position of this view's window 30717 */ 30718 int mWindowTop; 30719 30720 /** 30721 * Indicates whether views need to use 32-bit drawing caches 30722 */ 30723 boolean mUse32BitDrawingCache; 30724 30725 /** 30726 * For windows that are full-screen but using insets to layout inside 30727 * of the screen decorations, these are the current insets for the 30728 * content of the window. 30729 */ 30730 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 30731 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 30732 final Rect mContentInsets = new Rect(); 30733 30734 /** 30735 * For windows that are full-screen but using insets to layout inside 30736 * of the screen decorations, these are the current insets for the 30737 * actual visible parts of the window. 30738 */ 30739 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 30740 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 30741 final Rect mVisibleInsets = new Rect(); 30742 30743 /** 30744 * For windows that are full-screen but using insets to layout inside 30745 * of the screen decorations, these are the current insets for the 30746 * stable system windows. 30747 */ 30748 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.Q, 30749 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 30750 final Rect mStableInsets = new Rect(); 30751 30752 /** 30753 * Current caption insets to the display coordinate. 30754 */ 30755 final Rect mCaptionInsets = new Rect(); 30756 30757 /** 30758 * In multi-window we force show the system bars. Because we don't want that the surface 30759 * size changes in this mode, we instead have a flag whether the system bars sizes should 30760 * always be consumed, so the app is treated like there are no virtual system bars at all. 30761 */ 30762 boolean mAlwaysConsumeSystemBars; 30763 30764 /** 30765 * The internal insets given by this window. This value is 30766 * supplied by the client (through 30767 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 30768 * be given to the window manager when changed to be used in laying 30769 * out windows behind it. 30770 */ 30771 @UnsupportedAppUsage 30772 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 30773 = new ViewTreeObserver.InternalInsetsInfo(); 30774 30775 /** 30776 * Set to true when mGivenInternalInsets is non-empty. 30777 */ 30778 boolean mHasNonEmptyGivenInternalInsets; 30779 30780 /** 30781 * All views in the window's hierarchy that serve as scroll containers, 30782 * used to determine if the window can be resized or must be panned 30783 * to adjust for a soft input area. 30784 */ 30785 @UnsupportedAppUsage 30786 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 30787 30788 @UnsupportedAppUsage 30789 final KeyEvent.DispatcherState mKeyDispatchState 30790 = new KeyEvent.DispatcherState(); 30791 30792 /** 30793 * Indicates whether the view's window currently has the focus. 30794 */ 30795 @UnsupportedAppUsage 30796 boolean mHasWindowFocus; 30797 30798 /** 30799 * The current visibility of the window. 30800 */ 30801 int mWindowVisibility; 30802 30803 /** 30804 * Indicates the time at which drawing started to occur. 30805 */ 30806 @UnsupportedAppUsage 30807 long mDrawingTime; 30808 30809 /** 30810 * Indicates whether the view's window is currently in touch mode. 30811 */ 30812 @UnsupportedAppUsage 30813 boolean mInTouchMode; 30814 30815 /** 30816 * Indicates whether the view has requested unbuffered input dispatching for the current 30817 * event stream. 30818 */ 30819 boolean mUnbufferedDispatchRequested; 30820 30821 /** 30822 * Indicates that ViewAncestor should trigger a global layout change 30823 * the next time it performs a traversal 30824 */ 30825 @UnsupportedAppUsage 30826 boolean mRecomputeGlobalAttributes; 30827 30828 /** 30829 * Always report new attributes at next traversal. 30830 */ 30831 boolean mForceReportNewAttributes; 30832 30833 /** 30834 * Set during a traveral if any views want to keep the screen on. 30835 */ 30836 @UnsupportedAppUsage 30837 boolean mKeepScreenOn; 30838 30839 /** 30840 * Set during a traveral if the light center needs to be updated. 30841 */ 30842 boolean mNeedsUpdateLightCenter; 30843 30844 /** 30845 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 30846 */ 30847 int mSystemUiVisibility; 30848 30849 /** 30850 * Hack to force certain system UI visibility flags to be cleared. 30851 */ 30852 int mDisabledSystemUiVisibility; 30853 30854 /** 30855 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 30856 * attached. 30857 */ 30858 boolean mHasSystemUiListeners; 30859 30860 /** 30861 * Set if the visibility of any views has changed. 30862 */ 30863 @UnsupportedAppUsage 30864 boolean mViewVisibilityChanged; 30865 30866 /** 30867 * Set to true if a view has been scrolled. 30868 */ 30869 @UnsupportedAppUsage 30870 boolean mViewScrollChanged; 30871 30872 /** 30873 * Set to true if a pointer event is currently being handled. 30874 */ 30875 boolean mHandlingPointerEvent; 30876 30877 /** 30878 * The window matrix of this view when it's on a {@link SurfaceControlViewHost} that is 30879 * embedded within a SurfaceView. 30880 */ 30881 Matrix mWindowMatrixInEmbeddedHierarchy; 30882 30883 /** 30884 * Global to the view hierarchy used as a temporary for dealing with 30885 * x/y points in the transparent region computations. 30886 */ 30887 final int[] mTransparentLocation = new int[2]; 30888 30889 /** 30890 * Global to the view hierarchy used as a temporary for dealing with 30891 * x/y points in the ViewGroup.invalidateChild implementation. 30892 */ 30893 final int[] mInvalidateChildLocation = new int[2]; 30894 30895 /** 30896 * Global to the view hierarchy used as a temporary for dealing with 30897 * computing absolute on-screen location. 30898 */ 30899 final int[] mTmpLocation = new int[2]; 30900 30901 /** 30902 * Global to the view hierarchy used as a temporary for dealing with 30903 * x/y location when view is transformed. 30904 */ 30905 final float[] mTmpTransformLocation = new float[2]; 30906 30907 /** 30908 * The view tree observer used to dispatch global events like 30909 * layout, pre-draw, touch mode change, etc. 30910 */ 30911 @UnsupportedAppUsage 30912 final ViewTreeObserver mTreeObserver; 30913 30914 /** 30915 * A Canvas used by the view hierarchy to perform bitmap caching. 30916 */ 30917 Canvas mCanvas; 30918 30919 /** 30920 * The view root impl. 30921 */ 30922 final ViewRootImpl mViewRootImpl; 30923 30924 /** 30925 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 30926 * handler can be used to pump events in the UI events queue. 30927 */ 30928 @UnsupportedAppUsage 30929 final Handler mHandler; 30930 30931 /** 30932 * Temporary for use in computing invalidate rectangles while 30933 * calling up the hierarchy. 30934 */ 30935 final Rect mTmpInvalRect = new Rect(); 30936 30937 /** 30938 * Temporary for use in computing hit areas with transformed views 30939 */ 30940 final RectF mTmpTransformRect = new RectF(); 30941 30942 /** 30943 * Temporary for use in computing hit areas with transformed views 30944 */ 30945 final RectF mTmpTransformRect1 = new RectF(); 30946 30947 /** 30948 * Temporary list of rectanges. 30949 */ 30950 final List<RectF> mTmpRectList = new ArrayList<>(); 30951 30952 /** 30953 * Temporary for use in transforming invalidation rect 30954 */ 30955 final Matrix mTmpMatrix = new Matrix(); 30956 30957 /** 30958 * Temporary for use in transforming invalidation rect 30959 */ 30960 final Transformation mTmpTransformation = new Transformation(); 30961 30962 /** 30963 * Temporary for use in querying outlines from OutlineProviders 30964 */ 30965 final Outline mTmpOutline = new Outline(); 30966 30967 /** 30968 * Temporary list for use in collecting focusable descendents of a view. 30969 */ 30970 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 30971 30972 /** 30973 * The id of the window for accessibility purposes. 30974 */ 30975 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 30976 30977 /** 30978 * Flags related to accessibility processing. 30979 * 30980 * @see AccessibilityNodeInfo#FLAG_SERVICE_REQUESTS_INCLUDE_NOT_IMPORTANT_VIEWS 30981 * @see AccessibilityNodeInfo#FLAG_SERVICE_REQUESTS_REPORT_VIEW_IDS 30982 */ 30983 int mAccessibilityFetchFlags; 30984 30985 /** 30986 * The drawable for highlighting accessibility focus. 30987 */ 30988 Drawable mAccessibilityFocusDrawable; 30989 30990 /** 30991 * The drawable for highlighting autofilled views. 30992 * 30993 * @see #isAutofilled() 30994 */ 30995 Drawable mAutofilledDrawable; 30996 30997 /** 30998 * Show where the margins, bounds and layout bounds are for each view. 30999 */ 31000 boolean mDebugLayout = DisplayProperties.debug_layout().orElse(false); 31001 31002 /** 31003 * Point used to compute visible regions. 31004 */ 31005 final Point mPoint = new Point(); 31006 31007 /** 31008 * Used to track which View originated a requestLayout() call, used when 31009 * requestLayout() is called during layout. 31010 */ 31011 View mViewRequestingLayout; 31012 31013 /** 31014 * Used to track the identity of the current drag operation. 31015 */ 31016 IBinder mDragToken; 31017 31018 /** 31019 * The drag shadow surface for the current drag operation. 31020 */ 31021 public Surface mDragSurface; 31022 31023 31024 /** 31025 * The view that currently has a tooltip displayed. 31026 */ 31027 View mTooltipHost; 31028 31029 /** 31030 * The initial structure has been reported so the view is ready to report updates. 31031 */ 31032 boolean mReadyForContentCaptureUpdates; 31033 31034 /** 31035 * Map(keyed by session) of content capture events that need to be notified after the view 31036 * hierarchy is traversed: value is either the view itself for appearead events, or its 31037 * autofill id for disappeared. 31038 */ 31039 SparseArray<ArrayList<Object>> mContentCaptureEvents; 31040 31041 /** 31042 * Cached reference to the {@link ContentCaptureManager}. 31043 */ 31044 ContentCaptureManager mContentCaptureManager; 31045 31046 /** 31047 * Listener used to fit content on window level. 31048 */ 31049 OnContentApplyWindowInsetsListener mContentOnApplyWindowInsetsListener; 31050 31051 /** 31052 * The leash token of this view's parent when it's in an embedded hierarchy that is 31053 * re-parented to another window. 31054 */ 31055 IBinder mLeashedParentToken; 31056 31057 /** 31058 * The accessibility view id of this view's parent when it's in an embedded 31059 * hierarchy that is re-parented to another window. 31060 */ 31061 int mLeashedParentAccessibilityViewId; 31062 31063 /** 31064 * 31065 */ 31066 ScrollCaptureInternal mScrollCaptureInternal; 31067 31068 /** 31069 * Creates a new set of attachment information with the specified 31070 * events handler and thread. 31071 * 31072 * @param handler the events handler the view must use 31073 */ AttachInfo(IWindowSession session, IWindow window, Display display, ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, Context context)31074 AttachInfo(IWindowSession session, IWindow window, Display display, 31075 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 31076 Context context) { 31077 mSession = session; 31078 mWindow = window; 31079 mWindowToken = window.asBinder(); 31080 mDisplay = display; 31081 mViewRootImpl = viewRootImpl; 31082 mHandler = handler; 31083 mRootCallbacks = effectPlayer; 31084 mTreeObserver = new ViewTreeObserver(context); 31085 } 31086 31087 @Nullable getContentCaptureManager(@onNull Context context)31088 ContentCaptureManager getContentCaptureManager(@NonNull Context context) { 31089 if (mContentCaptureManager != null) { 31090 return mContentCaptureManager; 31091 } 31092 mContentCaptureManager = context.getSystemService(ContentCaptureManager.class); 31093 return mContentCaptureManager; 31094 } 31095 delayNotifyContentCaptureInsetsEvent(@onNull Insets insets)31096 void delayNotifyContentCaptureInsetsEvent(@NonNull Insets insets) { 31097 if (mContentCaptureManager == null) { 31098 return; 31099 } 31100 31101 ArrayList<Object> events = ensureEvents( 31102 mContentCaptureManager.getMainContentCaptureSession()); 31103 events.add(insets); 31104 } 31105 delayNotifyContentCaptureEvent(@onNull ContentCaptureSession session, @NonNull View view, boolean appeared)31106 private void delayNotifyContentCaptureEvent(@NonNull ContentCaptureSession session, 31107 @NonNull View view, boolean appeared) { 31108 ArrayList<Object> events = ensureEvents(session); 31109 events.add(appeared ? view : view.getAutofillId()); 31110 } 31111 31112 @NonNull ensureEvents(@onNull ContentCaptureSession session)31113 private ArrayList<Object> ensureEvents(@NonNull ContentCaptureSession session) { 31114 if (mContentCaptureEvents == null) { 31115 // Most of the time there will be just one session, so intial capacity is 1 31116 mContentCaptureEvents = new SparseArray<>(1); 31117 } 31118 int sessionId = session.getId(); 31119 // TODO: life would be much easier if we provided a MultiMap implementation somwhere... 31120 ArrayList<Object> events = mContentCaptureEvents.get(sessionId); 31121 if (events == null) { 31122 events = new ArrayList<>(); 31123 mContentCaptureEvents.put(sessionId, events); 31124 } 31125 31126 return events; 31127 } 31128 31129 @Nullable getScrollCaptureInternal()31130 ScrollCaptureInternal getScrollCaptureInternal() { 31131 if (mScrollCaptureInternal != null) { 31132 mScrollCaptureInternal = new ScrollCaptureInternal(); 31133 } 31134 return mScrollCaptureInternal; 31135 } 31136 getRootSurfaceControl()31137 AttachedSurfaceControl getRootSurfaceControl() { 31138 return mViewRootImpl; 31139 } 31140 dump(String prefix, PrintWriter writer)31141 public void dump(String prefix, PrintWriter writer) { 31142 String innerPrefix = prefix + " "; 31143 writer.println(prefix + "AttachInfo:"); 31144 writer.println(innerPrefix + "mHasWindowFocus=" + mHasWindowFocus); 31145 writer.println(innerPrefix + "mWindowVisibility=" + mWindowVisibility); 31146 writer.println(innerPrefix + "mInTouchMode=" + mInTouchMode); 31147 writer.println(innerPrefix + "mUnbufferedDispatchRequested=" 31148 + mUnbufferedDispatchRequested); 31149 } 31150 } 31151 31152 /** 31153 * <p>ScrollabilityCache holds various fields used by a View when scrolling 31154 * is supported. This avoids keeping too many unused fields in most 31155 * instances of View.</p> 31156 */ 31157 private static class ScrollabilityCache implements Runnable { 31158 31159 /** 31160 * Scrollbars are not visible 31161 */ 31162 public static final int OFF = 0; 31163 31164 /** 31165 * Scrollbars are visible 31166 */ 31167 public static final int ON = 1; 31168 31169 /** 31170 * Scrollbars are fading away 31171 */ 31172 public static final int FADING = 2; 31173 31174 public boolean fadeScrollBars; 31175 31176 public int fadingEdgeLength; 31177 public int scrollBarDefaultDelayBeforeFade; 31178 public int scrollBarFadeDuration; 31179 31180 public int scrollBarSize; 31181 public int scrollBarMinTouchTarget; 31182 @UnsupportedAppUsage 31183 public ScrollBarDrawable scrollBar; 31184 public float[] interpolatorValues; 31185 @UnsupportedAppUsage 31186 public View host; 31187 31188 public final Paint paint; 31189 public final Matrix matrix; 31190 public Shader shader; 31191 31192 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 31193 31194 private static final float[] OPAQUE = { 255 }; 31195 private static final float[] TRANSPARENT = { 0.0f }; 31196 31197 /** 31198 * When fading should start. This time moves into the future every time 31199 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 31200 */ 31201 public long fadeStartTime; 31202 31203 31204 /** 31205 * The current state of the scrollbars: ON, OFF, or FADING 31206 */ 31207 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 31208 public int state = OFF; 31209 31210 private int mLastColor; 31211 31212 public final Rect mScrollBarBounds = new Rect(); 31213 public final Rect mScrollBarTouchBounds = new Rect(); 31214 31215 public static final int NOT_DRAGGING = 0; 31216 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 31217 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 31218 public int mScrollBarDraggingState = NOT_DRAGGING; 31219 31220 public float mScrollBarDraggingPos = 0; 31221 ScrollabilityCache(ViewConfiguration configuration, View host)31222 public ScrollabilityCache(ViewConfiguration configuration, View host) { 31223 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 31224 scrollBarSize = configuration.getScaledScrollBarSize(); 31225 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 31226 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 31227 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 31228 31229 paint = new Paint(); 31230 matrix = new Matrix(); 31231 // use use a height of 1, and then wack the matrix each time we 31232 // actually use it. 31233 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 31234 paint.setShader(shader); 31235 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 31236 31237 this.host = host; 31238 } 31239 setFadeColor(int color)31240 public void setFadeColor(int color) { 31241 if (color != mLastColor) { 31242 mLastColor = color; 31243 31244 if (color != 0) { 31245 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 31246 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 31247 paint.setShader(shader); 31248 // Restore the default transfer mode (src_over) 31249 paint.setXfermode(null); 31250 } else { 31251 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 31252 paint.setShader(shader); 31253 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 31254 } 31255 } 31256 } 31257 run()31258 public void run() { 31259 long now = AnimationUtils.currentAnimationTimeMillis(); 31260 if (now >= fadeStartTime) { 31261 31262 // the animation fades the scrollbars out by changing 31263 // the opacity (alpha) from fully opaque to fully 31264 // transparent 31265 int nextFrame = (int) now; 31266 int framesCount = 0; 31267 31268 Interpolator interpolator = scrollBarInterpolator; 31269 31270 // Start opaque 31271 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 31272 31273 // End transparent 31274 nextFrame += scrollBarFadeDuration; 31275 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 31276 31277 state = FADING; 31278 31279 // Kick off the fade animation 31280 host.invalidate(true); 31281 } 31282 } 31283 } 31284 31285 private class SendAccessibilityEventThrottle implements Runnable { 31286 public volatile boolean mIsPending; 31287 private AccessibilityEvent mAccessibilityEvent; 31288 post(AccessibilityEvent accessibilityEvent)31289 public void post(AccessibilityEvent accessibilityEvent) { 31290 updateWithAccessibilityEvent(accessibilityEvent); 31291 if (!mIsPending) { 31292 mIsPending = true; 31293 postDelayed(this, 31294 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 31295 } 31296 } 31297 31298 @Override run()31299 public void run() { 31300 if (AccessibilityManager.getInstance(mContext).isEnabled() && isShown()) { 31301 requestParentSendAccessibilityEvent(mAccessibilityEvent); 31302 } 31303 reset(); 31304 } 31305 updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent)31306 public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { 31307 mAccessibilityEvent = accessibilityEvent; 31308 } 31309 reset()31310 public void reset() { 31311 mIsPending = false; 31312 mAccessibilityEvent = null; 31313 } 31314 31315 } 31316 31317 /** 31318 * Resuable callback for sending 31319 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 31320 */ 31321 private class SendViewScrolledAccessibilityEvent extends SendAccessibilityEventThrottle { 31322 public int mDeltaX; 31323 public int mDeltaY; 31324 31325 @Override updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent)31326 public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { 31327 super.updateWithAccessibilityEvent(accessibilityEvent); 31328 mDeltaX += accessibilityEvent.getScrollDeltaX(); 31329 mDeltaY += accessibilityEvent.getScrollDeltaY(); 31330 accessibilityEvent.setScrollDeltaX(mDeltaX); 31331 accessibilityEvent.setScrollDeltaY(mDeltaY); 31332 } 31333 31334 @Override reset()31335 public void reset() { 31336 super.reset(); 31337 mDeltaX = 0; 31338 mDeltaY = 0; 31339 } 31340 } 31341 /** 31342 * Remove the pending callback for sending a throttled accessibility event. 31343 */ 31344 @UnsupportedAppUsage cancel(@ullable SendAccessibilityEventThrottle callback)31345 private void cancel(@Nullable SendAccessibilityEventThrottle callback) { 31346 if (callback == null || !callback.mIsPending) return; 31347 removeCallbacks(callback); 31348 callback.reset(); 31349 } 31350 31351 /** 31352 * <p> 31353 * This class represents a delegate that can be registered in a {@link View} 31354 * to enhance accessibility support via composition rather via inheritance. 31355 * It is specifically targeted to widget developers that extend basic View 31356 * classes i.e. classes in package android.view, that would like their 31357 * applications to be backwards compatible. 31358 * </p> 31359 * <div class="special reference"> 31360 * <h3>Developer Guides</h3> 31361 * <p>For more information about making applications accessible, read the 31362 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 31363 * developer guide.</p> 31364 * </div> 31365 * <p> 31366 * A scenario in which a developer would like to use an accessibility delegate 31367 * is overriding a method introduced in a later API version than the minimal API 31368 * version supported by the application. For example, the method 31369 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 31370 * in API version 4 when the accessibility APIs were first introduced. If a 31371 * developer would like their application to run on API version 4 devices (assuming 31372 * all other APIs used by the application are version 4 or lower) and take advantage 31373 * of this method, instead of overriding the method which would break the application's 31374 * backwards compatibility, they can override the corresponding method in this 31375 * delegate and register the delegate in the target View if the API version of 31376 * the system is high enough, i.e. the API version is the same as or higher than the API 31377 * version that introduced 31378 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 31379 * </p> 31380 * <p> 31381 * Here is an example implementation: 31382 * </p> 31383 * <code><pre><p> 31384 * if (Build.VERSION.SDK_INT >= 14) { 31385 * // If the API version is equal of higher than the version in 31386 * // which onInitializeAccessibilityNodeInfo was introduced we 31387 * // register a delegate with a customized implementation. 31388 * View view = findViewById(R.id.view_id); 31389 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 31390 * public void onInitializeAccessibilityNodeInfo(View host, 31391 * AccessibilityNodeInfo info) { 31392 * // Let the default implementation populate the info. 31393 * super.onInitializeAccessibilityNodeInfo(host, info); 31394 * // Set some other information. 31395 * info.setEnabled(host.isEnabled()); 31396 * } 31397 * }); 31398 * } 31399 * </code></pre></p> 31400 * <p> 31401 * This delegate contains methods that correspond to the accessibility methods 31402 * in View. If a delegate has been specified the implementation in View hands 31403 * off handling to the corresponding method in this delegate. The default 31404 * implementation the delegate methods behaves exactly as the corresponding 31405 * method in View for the case of no accessibility delegate been set. Hence, 31406 * to customize the behavior of a View method, clients can override only the 31407 * corresponding delegate method without altering the behavior of the rest 31408 * accessibility related methods of the host view. 31409 * </p> 31410 * <p> 31411 * <strong>Note:</strong> On platform versions prior to 31412 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 31413 * views in the {@code android.widget.*} package are called <i>before</i> 31414 * host methods. This prevents certain properties such as class name from 31415 * being modified by overriding 31416 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 31417 * as any changes will be overwritten by the host class. 31418 * <p> 31419 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 31420 * methods are called <i>after</i> host methods, which all properties to be 31421 * modified without being overwritten by the host class. 31422 */ 31423 public static class AccessibilityDelegate { 31424 31425 /** 31426 * Sends an accessibility event of the given type. If accessibility is not 31427 * enabled this method has no effect. 31428 * <p> 31429 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 31430 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 31431 * been set. 31432 * </p> 31433 * 31434 * @param host The View hosting the delegate. 31435 * @param eventType The type of the event to send. 31436 * 31437 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 31438 */ sendAccessibilityEvent(@onNull View host, int eventType)31439 public void sendAccessibilityEvent(@NonNull View host, int eventType) { 31440 host.sendAccessibilityEventInternal(eventType); 31441 } 31442 31443 /** 31444 * Performs the specified accessibility action on the view. For 31445 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 31446 * <p> 31447 * The default implementation behaves as 31448 * {@link View#performAccessibilityAction(int, Bundle) 31449 * View#performAccessibilityAction(int, Bundle)} for the case of 31450 * no accessibility delegate been set. 31451 * </p> 31452 * 31453 * @param action The action to perform. 31454 * @return Whether the action was performed. 31455 * 31456 * @see View#performAccessibilityAction(int, Bundle) 31457 * View#performAccessibilityAction(int, Bundle) 31458 */ performAccessibilityAction(@onNull View host, int action, @Nullable Bundle args)31459 public boolean performAccessibilityAction(@NonNull View host, int action, 31460 @Nullable Bundle args) { 31461 return host.performAccessibilityActionInternal(action, args); 31462 } 31463 31464 /** 31465 * Sends an accessibility event. This method behaves exactly as 31466 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 31467 * empty {@link AccessibilityEvent} and does not perform a check whether 31468 * accessibility is enabled. 31469 * <p> 31470 * The default implementation behaves as 31471 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 31472 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 31473 * the case of no accessibility delegate been set. 31474 * </p> 31475 * 31476 * @param host The View hosting the delegate. 31477 * @param event The event to send. 31478 * 31479 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 31480 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 31481 */ sendAccessibilityEventUnchecked(@onNull View host, @NonNull AccessibilityEvent event)31482 public void sendAccessibilityEventUnchecked(@NonNull View host, 31483 @NonNull AccessibilityEvent event) { 31484 host.sendAccessibilityEventUncheckedInternal(event); 31485 } 31486 31487 /** 31488 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 31489 * to its children for adding their text content to the event. 31490 * <p> 31491 * The default implementation behaves as 31492 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 31493 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 31494 * the case of no accessibility delegate been set. 31495 * </p> 31496 * 31497 * @param host The View hosting the delegate. 31498 * @param event The event. 31499 * @return True if the event population was completed. 31500 * 31501 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 31502 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 31503 */ dispatchPopulateAccessibilityEvent(@onNull View host, @NonNull AccessibilityEvent event)31504 public boolean dispatchPopulateAccessibilityEvent(@NonNull View host, 31505 @NonNull AccessibilityEvent event) { 31506 return host.dispatchPopulateAccessibilityEventInternal(event); 31507 } 31508 31509 /** 31510 * Gives a chance to the host View to populate the accessibility event with its 31511 * text content. 31512 * <p> 31513 * The default implementation behaves as 31514 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 31515 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 31516 * the case of no accessibility delegate been set. 31517 * </p> 31518 * 31519 * @param host The View hosting the delegate. 31520 * @param event The accessibility event which to populate. 31521 * 31522 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 31523 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 31524 */ onPopulateAccessibilityEvent(@onNull View host, @NonNull AccessibilityEvent event)31525 public void onPopulateAccessibilityEvent(@NonNull View host, 31526 @NonNull AccessibilityEvent event) { 31527 host.onPopulateAccessibilityEventInternal(event); 31528 } 31529 31530 /** 31531 * Initializes an {@link AccessibilityEvent} with information about the 31532 * the host View which is the event source. 31533 * <p> 31534 * The default implementation behaves as 31535 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 31536 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 31537 * the case of no accessibility delegate been set. 31538 * </p> 31539 * 31540 * @param host The View hosting the delegate. 31541 * @param event The event to initialize. 31542 * 31543 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 31544 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 31545 */ onInitializeAccessibilityEvent(@onNull View host, @NonNull AccessibilityEvent event)31546 public void onInitializeAccessibilityEvent(@NonNull View host, 31547 @NonNull AccessibilityEvent event) { 31548 host.onInitializeAccessibilityEventInternal(event); 31549 } 31550 31551 /** 31552 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 31553 * <p> 31554 * The default implementation behaves as 31555 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 31556 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 31557 * the case of no accessibility delegate been set. 31558 * </p> 31559 * 31560 * @param host The View hosting the delegate. 31561 * @param info The instance to initialize. 31562 * 31563 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 31564 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 31565 */ onInitializeAccessibilityNodeInfo(@onNull View host, @NonNull AccessibilityNodeInfo info)31566 public void onInitializeAccessibilityNodeInfo(@NonNull View host, 31567 @NonNull AccessibilityNodeInfo info) { 31568 host.onInitializeAccessibilityNodeInfoInternal(info); 31569 } 31570 31571 /** 31572 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 31573 * additional data. 31574 * <p> 31575 * This method only needs to be implemented if the View offers to provide additional data. 31576 * </p> 31577 * <p> 31578 * The default implementation behaves as 31579 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle) 31580 * for the case where no accessibility delegate is set. 31581 * </p> 31582 * 31583 * @param host The View hosting the delegate. Never {@code null}. 31584 * @param info The info to which to add the extra data. Never {@code null}. 31585 * @param extraDataKey A key specifying the type of extra data to add to the info. The 31586 * extra data should be added to the {@link Bundle} returned by 31587 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 31588 * {@code null}. 31589 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 31590 * May be {@code null} if the if the service provided no arguments. 31591 * 31592 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 31593 */ addExtraDataToAccessibilityNodeInfo(@onNull View host, @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, @Nullable Bundle arguments)31594 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 31595 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 31596 @Nullable Bundle arguments) { 31597 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 31598 } 31599 31600 /** 31601 * Called when a child of the host View has requested sending an 31602 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 31603 * to augment the event. 31604 * <p> 31605 * The default implementation behaves as 31606 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 31607 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 31608 * the case of no accessibility delegate been set. 31609 * </p> 31610 * 31611 * @param host The View hosting the delegate. 31612 * @param child The child which requests sending the event. 31613 * @param event The event to be sent. 31614 * @return True if the event should be sent 31615 * 31616 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 31617 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 31618 */ onRequestSendAccessibilityEvent(@onNull ViewGroup host, @NonNull View child, @NonNull AccessibilityEvent event)31619 public boolean onRequestSendAccessibilityEvent(@NonNull ViewGroup host, @NonNull View child, 31620 @NonNull AccessibilityEvent event) { 31621 return host.onRequestSendAccessibilityEventInternal(child, event); 31622 } 31623 31624 /** 31625 * Gets the provider for managing a virtual view hierarchy rooted at this View 31626 * and reported to {@link android.accessibilityservice.AccessibilityService}s 31627 * that explore the window content. 31628 * <p> 31629 * The default implementation behaves as 31630 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 31631 * the case of no accessibility delegate been set. 31632 * </p> 31633 * 31634 * @return The provider. 31635 * 31636 * @see AccessibilityNodeProvider 31637 */ getAccessibilityNodeProvider( @onNull View host)31638 public @Nullable AccessibilityNodeProvider getAccessibilityNodeProvider( 31639 @NonNull View host) { 31640 return null; 31641 } 31642 31643 /** 31644 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 31645 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 31646 * This method is responsible for obtaining an accessibility node info from a 31647 * pool of reusable instances and calling 31648 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 31649 * view to initialize the former. 31650 * <p> 31651 * <strong>Note:</strong> The client is responsible for recycling the obtained 31652 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 31653 * creation. 31654 * </p> 31655 * <p> 31656 * The default implementation behaves as 31657 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 31658 * the case of no accessibility delegate been set. 31659 * </p> 31660 * @return A populated {@link AccessibilityNodeInfo}. 31661 * 31662 * @see AccessibilityNodeInfo 31663 * 31664 * @hide 31665 */ 31666 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) createAccessibilityNodeInfo(@onNull View host)31667 public AccessibilityNodeInfo createAccessibilityNodeInfo(@NonNull View host) { 31668 return host.createAccessibilityNodeInfoInternal(); 31669 } 31670 } 31671 31672 private static class MatchIdPredicate implements Predicate<View> { 31673 public int mId; 31674 31675 @Override test(View view)31676 public boolean test(View view) { 31677 return (view.mID == mId); 31678 } 31679 } 31680 31681 private static class MatchLabelForPredicate implements Predicate<View> { 31682 private int mLabeledId; 31683 31684 @Override test(View view)31685 public boolean test(View view) { 31686 return (view.mLabelForId == mLabeledId); 31687 } 31688 } 31689 31690 31691 /** 31692 * Returns the current scroll capture hint for this view. 31693 * 31694 * @return the current scroll capture hint 31695 */ 31696 @ScrollCaptureHint getScrollCaptureHint()31697 public int getScrollCaptureHint() { 31698 return (mPrivateFlags4 & PFLAG4_SCROLL_CAPTURE_HINT_MASK) 31699 >> PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; 31700 } 31701 31702 /** 31703 * Sets the scroll capture hint for this View. These flags affect the search for a potential 31704 * scroll capture targets. 31705 * 31706 * @param hint the scrollCaptureHint flags value to set 31707 */ setScrollCaptureHint(@crollCaptureHint int hint)31708 public void setScrollCaptureHint(@ScrollCaptureHint int hint) { 31709 mPrivateFlags4 &= ~PFLAG4_SCROLL_CAPTURE_HINT_MASK; 31710 // Since include/exclude are mutually exclusive, exclude takes precedence. 31711 if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) { 31712 hint &= ~SCROLL_CAPTURE_HINT_INCLUDE; 31713 } 31714 mPrivateFlags4 |= ((hint << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT) 31715 & PFLAG4_SCROLL_CAPTURE_HINT_MASK); 31716 } 31717 31718 /** 31719 * Sets the callback to receive scroll capture requests. This component is the adapter between 31720 * the scroll capture API and application UI code. If no callback is set, the system may provide 31721 * an implementation. Any value provided here will take precedence over a system version. 31722 * <p> 31723 * This view will be ignored when {@link #SCROLL_CAPTURE_HINT_EXCLUDE} is set in its {@link 31724 * #setScrollCaptureHint(int) scrollCaptureHint}, regardless whether a callback has been set. 31725 * <p> 31726 * It is recommended to set the scroll capture hint {@link #SCROLL_CAPTURE_HINT_INCLUDE} when 31727 * setting a custom callback to help ensure it is selected as the target. 31728 * 31729 * @param callback the new callback to assign 31730 */ setScrollCaptureCallback(@ullable ScrollCaptureCallback callback)31731 public final void setScrollCaptureCallback(@Nullable ScrollCaptureCallback callback) { 31732 getListenerInfo().mScrollCaptureCallback = callback; 31733 } 31734 31735 /** {@hide} */ 31736 @Nullable createScrollCaptureCallbackInternal(@onNull Rect localVisibleRect, @NonNull Point windowOffset)31737 public ScrollCaptureCallback createScrollCaptureCallbackInternal(@NonNull Rect localVisibleRect, 31738 @NonNull Point windowOffset) { 31739 if (mAttachInfo == null) { 31740 return null; 31741 } 31742 if (mAttachInfo.mScrollCaptureInternal == null) { 31743 mAttachInfo.mScrollCaptureInternal = new ScrollCaptureInternal(); 31744 } 31745 return mAttachInfo.mScrollCaptureInternal.requestCallback(this, localVisibleRect, 31746 windowOffset); 31747 } 31748 31749 /** 31750 * Dispatch a scroll capture search request down the view hierarchy. 31751 * 31752 * @param localVisibleRect the visible area of this ViewGroup in local coordinates, according to 31753 * the parent 31754 * @param windowOffset the offset of this view within the window 31755 * @param targets accepts potential scroll capture targets; {@link Consumer#accept 31756 * results.accept} may be called zero or more times on the calling 31757 * thread before onScrollCaptureSearch returns 31758 */ dispatchScrollCaptureSearch( @onNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets)31759 public void dispatchScrollCaptureSearch( 31760 @NonNull Rect localVisibleRect, @NonNull Point windowOffset, 31761 @NonNull Consumer<ScrollCaptureTarget> targets) { 31762 onScrollCaptureSearch(localVisibleRect, windowOffset, targets); 31763 } 31764 31765 /** 31766 * Called when scroll capture is requested, to search for appropriate content to scroll. If 31767 * applicable, this view adds itself to the provided list for consideration, subject to the 31768 * flags set by {@link #setScrollCaptureHint}. 31769 * 31770 * @param localVisibleRect the local visible rect of this view 31771 * @param windowOffset the offset of localVisibleRect within the window 31772 * @param targets accepts potential scroll capture targets; {@link Consumer#accept 31773 * results.accept} may be called zero or more times on the calling 31774 * thread before onScrollCaptureSearch returns 31775 * @throws IllegalStateException if this view is not attached to a window 31776 */ onScrollCaptureSearch(@onNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets)31777 public void onScrollCaptureSearch(@NonNull Rect localVisibleRect, 31778 @NonNull Point windowOffset, @NonNull Consumer<ScrollCaptureTarget> targets) { 31779 int hint = getScrollCaptureHint(); 31780 if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) { 31781 return; 31782 } 31783 boolean rectIsVisible = true; 31784 31785 // Apply clipBounds if present. 31786 if (mClipBounds != null) { 31787 rectIsVisible = localVisibleRect.intersect(mClipBounds); 31788 } 31789 if (!rectIsVisible) { 31790 return; 31791 } 31792 31793 // Get a callback provided by the framework, library or application. 31794 ScrollCaptureCallback callback = 31795 (mListenerInfo == null) ? null : mListenerInfo.mScrollCaptureCallback; 31796 31797 // Try framework support for standard scrolling containers. 31798 if (callback == null) { 31799 callback = createScrollCaptureCallbackInternal(localVisibleRect, windowOffset); 31800 } 31801 31802 // If found, then add it to the list. 31803 if (callback != null) { 31804 // Add to the list for consideration 31805 Point offset = new Point(windowOffset.x, windowOffset.y); 31806 Rect rect = new Rect(localVisibleRect); 31807 targets.accept(new ScrollCaptureTarget(this, rect, offset, callback)); 31808 } 31809 } 31810 31811 /** 31812 * Dump all private flags in readable format, useful for documentation and 31813 * consistency checking. 31814 */ dumpFlags()31815 private static void dumpFlags() { 31816 final HashMap<String, String> found = Maps.newHashMap(); 31817 try { 31818 for (Field field : View.class.getDeclaredFields()) { 31819 final int modifiers = field.getModifiers(); 31820 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 31821 if (field.getType().equals(int.class)) { 31822 final int value = field.getInt(null); 31823 dumpFlag(found, field.getName(), value); 31824 } else if (field.getType().equals(int[].class)) { 31825 final int[] values = (int[]) field.get(null); 31826 for (int i = 0; i < values.length; i++) { 31827 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 31828 } 31829 } 31830 } 31831 } 31832 } catch (IllegalAccessException e) { 31833 throw new RuntimeException(e); 31834 } 31835 31836 final ArrayList<String> keys = Lists.newArrayList(); 31837 keys.addAll(found.keySet()); 31838 Collections.sort(keys); 31839 for (String key : keys) { 31840 Log.d(VIEW_LOG_TAG, found.get(key)); 31841 } 31842 } 31843 dumpFlag(HashMap<String, String> found, String name, int value)31844 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 31845 // Sort flags by prefix, then by bits, always keeping unique keys 31846 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 31847 final int prefix = name.indexOf('_'); 31848 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 31849 final String output = bits + " " + name; 31850 found.put(key, output); 31851 } 31852 31853 /** {@hide} */ encode(@onNull ViewHierarchyEncoder stream)31854 public void encode(@NonNull ViewHierarchyEncoder stream) { 31855 stream.beginObject(this); 31856 encodeProperties(stream); 31857 stream.endObject(); 31858 } 31859 31860 /** {@hide} */ 31861 @CallSuper encodeProperties(@onNull ViewHierarchyEncoder stream)31862 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 31863 Object resolveId = ViewDebug.resolveId(getContext(), mID); 31864 if (resolveId instanceof String) { 31865 stream.addProperty("id", (String) resolveId); 31866 } else { 31867 stream.addProperty("id", mID); 31868 } 31869 31870 stream.addProperty("misc:transformation.alpha", 31871 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 31872 stream.addProperty("misc:transitionName", getTransitionName()); 31873 31874 // layout 31875 stream.addProperty("layout:left", mLeft); 31876 stream.addProperty("layout:right", mRight); 31877 stream.addProperty("layout:top", mTop); 31878 stream.addProperty("layout:bottom", mBottom); 31879 stream.addProperty("layout:width", getWidth()); 31880 stream.addProperty("layout:height", getHeight()); 31881 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 31882 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 31883 stream.addProperty("layout:hasTransientState", hasTransientState()); 31884 stream.addProperty("layout:baseline", getBaseline()); 31885 31886 // layout params 31887 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 31888 if (layoutParams != null) { 31889 stream.addPropertyKey("layoutParams"); 31890 layoutParams.encode(stream); 31891 } 31892 31893 // scrolling 31894 stream.addProperty("scrolling:scrollX", mScrollX); 31895 stream.addProperty("scrolling:scrollY", mScrollY); 31896 31897 // padding 31898 stream.addProperty("padding:paddingLeft", mPaddingLeft); 31899 stream.addProperty("padding:paddingRight", mPaddingRight); 31900 stream.addProperty("padding:paddingTop", mPaddingTop); 31901 stream.addProperty("padding:paddingBottom", mPaddingBottom); 31902 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 31903 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 31904 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 31905 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 31906 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 31907 31908 // measurement 31909 stream.addProperty("measurement:minHeight", mMinHeight); 31910 stream.addProperty("measurement:minWidth", mMinWidth); 31911 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 31912 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 31913 31914 // drawing 31915 stream.addProperty("drawing:elevation", getElevation()); 31916 stream.addProperty("drawing:translationX", getTranslationX()); 31917 stream.addProperty("drawing:translationY", getTranslationY()); 31918 stream.addProperty("drawing:translationZ", getTranslationZ()); 31919 stream.addProperty("drawing:rotation", getRotation()); 31920 stream.addProperty("drawing:rotationX", getRotationX()); 31921 stream.addProperty("drawing:rotationY", getRotationY()); 31922 stream.addProperty("drawing:scaleX", getScaleX()); 31923 stream.addProperty("drawing:scaleY", getScaleY()); 31924 stream.addProperty("drawing:pivotX", getPivotX()); 31925 stream.addProperty("drawing:pivotY", getPivotY()); 31926 stream.addProperty("drawing:clipBounds", 31927 mClipBounds == null ? null : mClipBounds.toString()); 31928 stream.addProperty("drawing:opaque", isOpaque()); 31929 stream.addProperty("drawing:alpha", getAlpha()); 31930 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 31931 stream.addProperty("drawing:shadow", hasShadow()); 31932 stream.addProperty("drawing:solidColor", getSolidColor()); 31933 stream.addProperty("drawing:layerType", mLayerType); 31934 stream.addProperty("drawing:willNotDraw", willNotDraw()); 31935 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 31936 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 31937 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 31938 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 31939 stream.addProperty("drawing:outlineAmbientShadowColor", getOutlineAmbientShadowColor()); 31940 stream.addProperty("drawing:outlineSpotShadowColor", getOutlineSpotShadowColor()); 31941 31942 // focus 31943 stream.addProperty("focus:hasFocus", hasFocus()); 31944 stream.addProperty("focus:isFocused", isFocused()); 31945 stream.addProperty("focus:focusable", getFocusable()); 31946 stream.addProperty("focus:isFocusable", isFocusable()); 31947 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 31948 31949 stream.addProperty("misc:clickable", isClickable()); 31950 stream.addProperty("misc:pressed", isPressed()); 31951 stream.addProperty("misc:selected", isSelected()); 31952 stream.addProperty("misc:touchMode", isInTouchMode()); 31953 stream.addProperty("misc:hovered", isHovered()); 31954 stream.addProperty("misc:activated", isActivated()); 31955 31956 stream.addProperty("misc:visibility", getVisibility()); 31957 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 31958 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 31959 31960 stream.addProperty("misc:enabled", isEnabled()); 31961 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 31962 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 31963 31964 // theme attributes 31965 Resources.Theme theme = getContext().getTheme(); 31966 if (theme != null) { 31967 stream.addPropertyKey("theme"); 31968 theme.encode(stream); 31969 } 31970 31971 // view attribute information 31972 int n = mAttributes != null ? mAttributes.length : 0; 31973 stream.addProperty("meta:__attrCount__", n/2); 31974 for (int i = 0; i < n; i += 2) { 31975 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 31976 } 31977 31978 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 31979 31980 // text 31981 stream.addProperty("text:textDirection", getTextDirection()); 31982 stream.addProperty("text:textAlignment", getTextAlignment()); 31983 31984 // accessibility 31985 CharSequence contentDescription = getContentDescription(); 31986 stream.addUserProperty("accessibility:contentDescription", 31987 contentDescription == null ? "" : contentDescription.toString()); 31988 stream.addProperty("accessibility:labelFor", getLabelFor()); 31989 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 31990 } 31991 31992 /** 31993 * Determine if this view is rendered on a round wearable device and is the main view 31994 * on the screen. 31995 */ shouldDrawRoundScrollbar()31996 boolean shouldDrawRoundScrollbar() { 31997 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 31998 return false; 31999 } 32000 32001 final View rootView = getRootView(); 32002 final WindowInsets insets = getRootWindowInsets(); 32003 32004 int height = getHeight(); 32005 int width = getWidth(); 32006 int displayHeight = rootView.getHeight(); 32007 int displayWidth = rootView.getWidth(); 32008 32009 if (height != displayHeight || width != displayWidth) { 32010 return false; 32011 } 32012 32013 getLocationInWindow(mAttachInfo.mTmpLocation); 32014 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 32015 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 32016 } 32017 32018 /** 32019 * Sets the tooltip text which will be displayed in a small popup next to the view. 32020 * <p> 32021 * The tooltip will be displayed: 32022 * <ul> 32023 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context 32024 * menu). </li> 32025 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 32026 * </ul> 32027 * <p> 32028 * <strong>Note:</strong> Do not override this method, as it will have no 32029 * effect on the text displayed in the tooltip. 32030 * 32031 * @param tooltipText the tooltip text, or null if no tooltip is required 32032 * @see #getTooltipText() 32033 * @attr ref android.R.styleable#View_tooltipText 32034 */ setTooltipText(@ullable CharSequence tooltipText)32035 public void setTooltipText(@Nullable CharSequence tooltipText) { 32036 if (TextUtils.isEmpty(tooltipText)) { 32037 setFlags(0, TOOLTIP); 32038 hideTooltip(); 32039 mTooltipInfo = null; 32040 } else { 32041 setFlags(TOOLTIP, TOOLTIP); 32042 if (mTooltipInfo == null) { 32043 mTooltipInfo = new TooltipInfo(); 32044 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 32045 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 32046 mTooltipInfo.mHoverSlop = ViewConfiguration.get(mContext).getScaledHoverSlop(); 32047 mTooltipInfo.clearAnchorPos(); 32048 } 32049 mTooltipInfo.mTooltipText = tooltipText; 32050 } 32051 } 32052 32053 /** 32054 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 32055 */ 32056 @UnsupportedAppUsage setTooltip(@ullable CharSequence tooltipText)32057 public void setTooltip(@Nullable CharSequence tooltipText) { 32058 setTooltipText(tooltipText); 32059 } 32060 32061 /** 32062 * Returns the view's tooltip text. 32063 * 32064 * <strong>Note:</strong> Do not override this method, as it will have no 32065 * effect on the text displayed in the tooltip. You must call 32066 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 32067 * 32068 * @return the tooltip text 32069 * @see #setTooltipText(CharSequence) 32070 * @attr ref android.R.styleable#View_tooltipText 32071 */ 32072 @InspectableProperty 32073 @Nullable getTooltipText()32074 public CharSequence getTooltipText() { 32075 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 32076 } 32077 32078 /** 32079 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 32080 */ 32081 @Nullable getTooltip()32082 public CharSequence getTooltip() { 32083 return getTooltipText(); 32084 } 32085 showTooltip(int x, int y, boolean fromLongClick)32086 private boolean showTooltip(int x, int y, boolean fromLongClick) { 32087 if (mAttachInfo == null || mTooltipInfo == null) { 32088 return false; 32089 } 32090 if (fromLongClick && (mViewFlags & ENABLED_MASK) != ENABLED) { 32091 return false; 32092 } 32093 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 32094 return false; 32095 } 32096 hideTooltip(); 32097 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 32098 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 32099 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 32100 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 32101 mAttachInfo.mTooltipHost = this; 32102 // The available accessibility actions have changed 32103 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 32104 return true; 32105 } 32106 32107 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) hideTooltip()32108 void hideTooltip() { 32109 if (mTooltipInfo == null) { 32110 return; 32111 } 32112 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 32113 if (mTooltipInfo.mTooltipPopup == null) { 32114 return; 32115 } 32116 mTooltipInfo.mTooltipPopup.hide(); 32117 mTooltipInfo.mTooltipPopup = null; 32118 mTooltipInfo.mTooltipFromLongClick = false; 32119 mTooltipInfo.clearAnchorPos(); 32120 if (mAttachInfo != null) { 32121 mAttachInfo.mTooltipHost = null; 32122 } 32123 // The available accessibility actions have changed 32124 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 32125 } 32126 showLongClickTooltip(int x, int y)32127 private boolean showLongClickTooltip(int x, int y) { 32128 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 32129 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 32130 return showTooltip(x, y, true); 32131 } 32132 showHoverTooltip()32133 private boolean showHoverTooltip() { 32134 return showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 32135 } 32136 dispatchTooltipHoverEvent(MotionEvent event)32137 boolean dispatchTooltipHoverEvent(MotionEvent event) { 32138 if (mTooltipInfo == null) { 32139 return false; 32140 } 32141 switch(event.getAction()) { 32142 case MotionEvent.ACTION_HOVER_MOVE: 32143 if ((mViewFlags & TOOLTIP) != TOOLTIP) { 32144 break; 32145 } 32146 if (!mTooltipInfo.mTooltipFromLongClick && mTooltipInfo.updateAnchorPos(event)) { 32147 if (mTooltipInfo.mTooltipPopup == null) { 32148 // Schedule showing the tooltip after a timeout. 32149 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 32150 postDelayed(mTooltipInfo.mShowTooltipRunnable, 32151 ViewConfiguration.getHoverTooltipShowTimeout()); 32152 } 32153 32154 // Hide hover-triggered tooltip after a period of inactivity. 32155 // Match the timeout used by NativeInputManager to hide the mouse pointer 32156 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 32157 final int timeout; 32158 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 32159 == SYSTEM_UI_FLAG_LOW_PROFILE) { 32160 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 32161 } else { 32162 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 32163 } 32164 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 32165 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 32166 } 32167 return true; 32168 32169 case MotionEvent.ACTION_HOVER_EXIT: 32170 mTooltipInfo.clearAnchorPos(); 32171 if (!mTooltipInfo.mTooltipFromLongClick) { 32172 hideTooltip(); 32173 } 32174 break; 32175 } 32176 return false; 32177 } 32178 handleTooltipKey(KeyEvent event)32179 void handleTooltipKey(KeyEvent event) { 32180 switch (event.getAction()) { 32181 case KeyEvent.ACTION_DOWN: 32182 if (event.getRepeatCount() == 0) { 32183 hideTooltip(); 32184 } 32185 break; 32186 32187 case KeyEvent.ACTION_UP: 32188 handleTooltipUp(); 32189 break; 32190 } 32191 } 32192 handleTooltipUp()32193 private void handleTooltipUp() { 32194 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 32195 return; 32196 } 32197 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 32198 postDelayed(mTooltipInfo.mHideTooltipRunnable, 32199 ViewConfiguration.getLongPressTooltipHideTimeout()); 32200 } 32201 getFocusableAttribute(TypedArray attributes)32202 private int getFocusableAttribute(TypedArray attributes) { 32203 TypedValue val = new TypedValue(); 32204 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 32205 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 32206 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 32207 } else { 32208 return val.data; 32209 } 32210 } else { 32211 return FOCUSABLE_AUTO; 32212 } 32213 } 32214 32215 /** 32216 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 32217 * is not showing. 32218 * @hide 32219 */ 32220 @TestApi getTooltipView()32221 public View getTooltipView() { 32222 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 32223 return null; 32224 } 32225 return mTooltipInfo.mTooltipPopup.getContentView(); 32226 } 32227 32228 /** 32229 * @return {@code true} if the default focus highlight is enabled, {@code false} otherwies. 32230 * @hide 32231 */ 32232 @TestApi isDefaultFocusHighlightEnabled()32233 public static boolean isDefaultFocusHighlightEnabled() { 32234 return sUseDefaultFocusHighlight; 32235 } 32236 32237 /** 32238 * Dispatch a previously unhandled {@link KeyEvent} to this view. Unlike normal key dispatch, 32239 * this dispatches to ALL child views until it is consumed. The dispatch order is z-order 32240 * (visually on-top views first). 32241 * 32242 * @param evt the previously unhandled {@link KeyEvent}. 32243 * @return the {@link View} which consumed the event or {@code null} if not consumed. 32244 */ dispatchUnhandledKeyEvent(KeyEvent evt)32245 View dispatchUnhandledKeyEvent(KeyEvent evt) { 32246 if (onUnhandledKeyEvent(evt)) { 32247 return this; 32248 } 32249 return null; 32250 } 32251 32252 /** 32253 * Allows this view to handle {@link KeyEvent}s which weren't handled by normal dispatch. This 32254 * occurs after the normal view hierarchy dispatch, but before the window callback. By default, 32255 * this will dispatch into all the listeners registered via 32256 * {@link #addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener)} in last-in-first-out 32257 * order (most recently added will receive events first). 32258 * 32259 * @param event An unhandled event. 32260 * @return {@code true} if the event was handled, {@code false} otherwise. 32261 * @see #addOnUnhandledKeyEventListener 32262 */ onUnhandledKeyEvent(@onNull KeyEvent event)32263 boolean onUnhandledKeyEvent(@NonNull KeyEvent event) { 32264 if (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null) { 32265 for (int i = mListenerInfo.mUnhandledKeyListeners.size() - 1; i >= 0; --i) { 32266 if (mListenerInfo.mUnhandledKeyListeners.get(i).onUnhandledKeyEvent(this, event)) { 32267 return true; 32268 } 32269 } 32270 } 32271 return false; 32272 } 32273 hasUnhandledKeyListener()32274 boolean hasUnhandledKeyListener() { 32275 return (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null 32276 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()); 32277 } 32278 32279 /** 32280 * Adds a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 32281 * UI thread. 32282 * 32283 * @param listener a receiver of unhandled {@link KeyEvent}s. 32284 * @see #removeOnUnhandledKeyEventListener 32285 */ addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)32286 public void addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 32287 ArrayList<OnUnhandledKeyEventListener> listeners = getListenerInfo().mUnhandledKeyListeners; 32288 if (listeners == null) { 32289 listeners = new ArrayList<>(); 32290 getListenerInfo().mUnhandledKeyListeners = listeners; 32291 } 32292 listeners.add(listener); 32293 if (listeners.size() == 1 && mParent instanceof ViewGroup) { 32294 ((ViewGroup) mParent).incrementChildUnhandledKeyListeners(); 32295 } 32296 } 32297 32298 /** 32299 * Removes a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 32300 * UI thread. 32301 * 32302 * @param listener a receiver of unhandled {@link KeyEvent}s. 32303 * @see #addOnUnhandledKeyEventListener 32304 */ removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)32305 public void removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 32306 if (mListenerInfo != null) { 32307 if (mListenerInfo.mUnhandledKeyListeners != null 32308 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 32309 mListenerInfo.mUnhandledKeyListeners.remove(listener); 32310 if (mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 32311 mListenerInfo.mUnhandledKeyListeners = null; 32312 if (mParent instanceof ViewGroup) { 32313 ((ViewGroup) mParent).decrementChildUnhandledKeyListeners(); 32314 } 32315 } 32316 } 32317 } 32318 } 32319 32320 /** 32321 * Set the view to be detached or not detached. 32322 * 32323 * @param detached Whether the view is detached. 32324 * 32325 * @hide 32326 */ setDetached(boolean detached)32327 protected void setDetached(boolean detached) { 32328 if (detached) { 32329 mPrivateFlags4 |= PFLAG4_DETACHED; 32330 } else { 32331 mPrivateFlags4 &= ~PFLAG4_DETACHED; 32332 } 32333 } 32334 32335 /** 32336 * Sets whether this view is a credential for Credential Manager purposes. 32337 * 32338 * <p>See {@link #isCredential()}. 32339 * 32340 * @param isCredential Whether the view is a credential. 32341 * 32342 * @attr ref android.R.styleable#View_isCredential 32343 */ setIsCredential(boolean isCredential)32344 public void setIsCredential(boolean isCredential) { 32345 if (isCredential) { 32346 mPrivateFlags4 |= PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER; 32347 } else { 32348 mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER; 32349 } 32350 } 32351 32352 /** 32353 * Gets the mode for determining whether this view is a credential. 32354 * 32355 * <p>See {@link #setIsCredential(boolean)}. 32356 * 32357 * @return false by default, or value passed to {@link #setIsCredential(boolean)}. 32358 * 32359 * @attr ref android.R.styleable#View_isCredential 32360 */ isCredential()32361 public boolean isCredential() { 32362 return ((mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER) 32363 == PFLAG4_IMPORTANT_FOR_CREDENTIAL_MANAGER); 32364 } 32365 32366 /** 32367 * Set whether this view enables automatic handwriting initiation. 32368 * 32369 * For a view with an active {@link InputConnection}, if auto handwriting is enabled then 32370 * stylus movement within its view boundary will automatically trigger the handwriting mode. 32371 * Check {@link android.view.inputmethod.InputMethodManager#startStylusHandwriting(View)} for 32372 * more details about handwriting mode. 32373 * 32374 * If the View wants to initiate handwriting mode by itself, it can set this field to 32375 * {@code false} and call 32376 * {@link android.view.inputmethod.InputMethodManager#startStylusHandwriting(View)} when there 32377 * is stylus movement detected. 32378 * 32379 * Note that this attribute has no effect on the View's children. For example, if a 32380 * {@link ViewGroup} disables auto handwriting but its children set auto handwriting to true, 32381 * auto handwriting will still work for the children, and vice versa. 32382 * 32383 * @see #onCreateInputConnection(EditorInfo) 32384 * @see android.view.inputmethod.InputMethodManager#startStylusHandwriting(View) 32385 * @param enabled whether auto handwriting initiation is enabled for this view. 32386 * @attr ref android.R.styleable#View_autoHandwritingEnabled 32387 */ setAutoHandwritingEnabled(boolean enabled)32388 public void setAutoHandwritingEnabled(boolean enabled) { 32389 if (enabled) { 32390 mPrivateFlags4 |= PFLAG4_AUTO_HANDWRITING_ENABLED; 32391 } else { 32392 mPrivateFlags4 &= ~PFLAG4_AUTO_HANDWRITING_ENABLED; 32393 } 32394 updatePositionUpdateListener(); 32395 postUpdate(this::updateHandwritingArea); 32396 } 32397 32398 /** 32399 * Return whether the View allows automatic handwriting initiation. Returns true if automatic 32400 * handwriting initiation is enabled, and verse visa. 32401 * @see #setAutoHandwritingEnabled(boolean) 32402 */ isAutoHandwritingEnabled()32403 public boolean isAutoHandwritingEnabled() { 32404 return (mPrivateFlags4 & PFLAG4_AUTO_HANDWRITING_ENABLED) 32405 == PFLAG4_AUTO_HANDWRITING_ENABLED; 32406 } 32407 32408 /** 32409 * Return whether the stylus handwriting is available for this View. 32410 * @hide 32411 */ isStylusHandwritingAvailable()32412 public boolean isStylusHandwritingAvailable() { 32413 return getContext().getSystemService(InputMethodManager.class) 32414 .isStylusHandwritingAvailable(); 32415 } 32416 setTraversalTracingEnabled(boolean enabled)32417 private void setTraversalTracingEnabled(boolean enabled) { 32418 if (enabled) { 32419 if (mTracingStrings == null) { 32420 mTracingStrings = new ViewTraversalTracingStrings(this); 32421 } 32422 mPrivateFlags4 |= PFLAG4_TRAVERSAL_TRACING_ENABLED; 32423 } else { 32424 mPrivateFlags4 &= ~PFLAG4_TRAVERSAL_TRACING_ENABLED; 32425 } 32426 } 32427 isTraversalTracingEnabled()32428 private boolean isTraversalTracingEnabled() { 32429 return (mPrivateFlags4 & PFLAG4_TRAVERSAL_TRACING_ENABLED) 32430 == PFLAG4_TRAVERSAL_TRACING_ENABLED; 32431 } 32432 setRelayoutTracingEnabled(boolean enabled)32433 private void setRelayoutTracingEnabled(boolean enabled) { 32434 if (enabled) { 32435 if (mTracingStrings == null) { 32436 mTracingStrings = new ViewTraversalTracingStrings(this); 32437 } 32438 mPrivateFlags4 |= PFLAG4_RELAYOUT_TRACING_ENABLED; 32439 } else { 32440 mPrivateFlags4 &= ~PFLAG4_RELAYOUT_TRACING_ENABLED; 32441 } 32442 } 32443 isRelayoutTracingEnabled()32444 private boolean isRelayoutTracingEnabled() { 32445 return (mPrivateFlags4 & PFLAG4_RELAYOUT_TRACING_ENABLED) 32446 == PFLAG4_RELAYOUT_TRACING_ENABLED; 32447 } 32448 32449 /** 32450 * Collects a {@link ViewTranslationRequest} which represents the content to be translated in 32451 * the view. 32452 * 32453 * <p>The default implementation does nothing.</p> 32454 * 32455 * @param supportedFormats the supported translation formats. For now, the only possible value 32456 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 32457 * @param requestsCollector a {@link ViewTranslationRequest} collector that can be used to 32458 * collect the information to be translated in the view. The {@code requestsCollector} only 32459 * accepts one request; an IllegalStateException is thrown if more than one 32460 * {@link ViewTranslationRequest} is submitted to it. The {@link AutofillId} must be set on the 32461 * {@link ViewTranslationRequest}. 32462 */ onCreateViewTranslationRequest(@onNull @ataFormat int[] supportedFormats, @NonNull Consumer<ViewTranslationRequest> requestsCollector)32463 public void onCreateViewTranslationRequest(@NonNull @DataFormat int[] supportedFormats, 32464 @NonNull Consumer<ViewTranslationRequest> requestsCollector) { 32465 } 32466 32467 /** 32468 * Collects {@link ViewTranslationRequest}s which represents the content to be translated 32469 * for the virtual views in the host view. This is called if this view returned a virtual 32470 * view structure from {@link #onProvideContentCaptureStructure} and the system determined that 32471 * those virtual views were relevant for translation. 32472 * 32473 * <p>The default implementation does nothing.</p> 32474 * 32475 * @param virtualIds the virtual view ids which represents the virtual views in the host 32476 * view. 32477 * @param supportedFormats the supported translation formats. For now, the only possible value 32478 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 32479 * @param requestsCollector a {@link ViewTranslationRequest} collector that can be called 32480 * multiple times to collect the information to be translated in the host view. One 32481 * {@link ViewTranslationRequest} per virtual child. The {@link ViewTranslationRequest} must 32482 * contains the {@link AutofillId} corresponding to the virtualChildIds. Do not keep this 32483 * Consumer after the method returns. 32484 */ 32485 @SuppressLint("NullableCollection") onCreateVirtualViewTranslationRequests(@onNull long[] virtualIds, @NonNull @DataFormat int[] supportedFormats, @NonNull Consumer<ViewTranslationRequest> requestsCollector)32486 public void onCreateVirtualViewTranslationRequests(@NonNull long[] virtualIds, 32487 @NonNull @DataFormat int[] supportedFormats, 32488 @NonNull Consumer<ViewTranslationRequest> requestsCollector) { 32489 // no-op 32490 } 32491 32492 /** 32493 * Returns a {@link ViewTranslationCallback} that is used to display the translated information 32494 * or {@code null} if this View doesn't support translation. 32495 * 32496 * @hide 32497 */ 32498 @Nullable getViewTranslationCallback()32499 public ViewTranslationCallback getViewTranslationCallback() { 32500 return mViewTranslationCallback; 32501 } 32502 32503 /** 32504 * Sets a {@link ViewTranslationCallback} that is used to display/hide the translated 32505 * information. Developers can provide the customized implementation for show/hide translated 32506 * information. 32507 * 32508 * @param callback a {@link ViewTranslationCallback} that is used to control how to display the 32509 * translated information 32510 */ setViewTranslationCallback(@onNull ViewTranslationCallback callback)32511 public void setViewTranslationCallback(@NonNull ViewTranslationCallback callback) { 32512 mViewTranslationCallback = callback; 32513 } 32514 32515 /** 32516 * Clear the {@link ViewTranslationCallback} from this view. 32517 */ clearViewTranslationCallback()32518 public void clearViewTranslationCallback() { 32519 mViewTranslationCallback = null; 32520 } 32521 32522 /** 32523 * Returns the {@link ViewTranslationResponse} associated with this view. The response will be 32524 * set when the translation is done then {@link #onViewTranslationResponse} is called. The 32525 * {@link ViewTranslationCallback} can use to get {@link ViewTranslationResponse} to display the 32526 * translated information. 32527 * 32528 * @return a {@link ViewTranslationResponse} that contains the translated information associated 32529 * with this view or {@code null} if this View doesn't have the translation. 32530 */ 32531 @Nullable getViewTranslationResponse()32532 public ViewTranslationResponse getViewTranslationResponse() { 32533 return mViewTranslationResponse; 32534 } 32535 32536 /** 32537 * Called when the content from {@link View#onCreateViewTranslationRequest} had been translated 32538 * by the TranslationService. The {@link ViewTranslationResponse} should be saved here so that 32539 * the {@link ViewTranslationResponse} can be used to display the translation when the system 32540 * calls {@link ViewTranslationCallback#onShowTranslation}. 32541 * 32542 * <p> The default implementation will set the ViewTranslationResponse that can be get from 32543 * {@link View#getViewTranslationResponse}. </p> 32544 * 32545 * @param response a {@link ViewTranslationResponse} that contains the translated information 32546 * which can be shown in the view. 32547 */ onViewTranslationResponse(@onNull ViewTranslationResponse response)32548 public void onViewTranslationResponse(@NonNull ViewTranslationResponse response) { 32549 mViewTranslationResponse = response; 32550 } 32551 32552 /** 32553 * Clears the ViewTranslationResponse stored by the default implementation of {@link 32554 * #onViewTranslationResponse}. 32555 * 32556 * @hide 32557 */ clearViewTranslationResponse()32558 public void clearViewTranslationResponse() { 32559 mViewTranslationResponse = null; 32560 } 32561 32562 /** 32563 * Called when the content from {@link View#onCreateVirtualViewTranslationRequests} had been 32564 * translated by the TranslationService. 32565 * 32566 * <p> The default implementation does nothing.</p> 32567 * 32568 * @param response a {@link ViewTranslationResponse} SparseArray for the request that send by 32569 * {@link View#onCreateVirtualViewTranslationRequests} that contains the translated information 32570 * which can be shown in the view. The key of SparseArray is the virtual child ids. 32571 */ onVirtualViewTranslationResponses( @onNull LongSparseArray<ViewTranslationResponse> response)32572 public void onVirtualViewTranslationResponses( 32573 @NonNull LongSparseArray<ViewTranslationResponse> response) { 32574 // no-op 32575 } 32576 32577 /** 32578 * Dispatch to collect the {@link ViewTranslationRequest}s for translation purpose by traversing 32579 * the hierarchy when the app requests ui translation. Typically, this method should only be 32580 * overridden by subclasses that provide a view hierarchy (such as {@link ViewGroup}). Other 32581 * classes should override {@link View#onCreateViewTranslationRequest} for normal view or 32582 * override {@link View#onVirtualViewTranslationResponses} for view contains virtual children. 32583 * When requested to start the ui translation, the system will call this method to traverse the 32584 * view hierarchy to collect {@link ViewTranslationRequest}s and create a 32585 * {@link android.view.translation.Translator} to translate the requests. All the 32586 * {@link ViewTranslationRequest}s must be added when the traversal is done. 32587 * 32588 * <p> The default implementation calls {@link View#onCreateViewTranslationRequest} for normal 32589 * view or calls {@link View#onVirtualViewTranslationResponses} for view contains virtual 32590 * children to build {@link ViewTranslationRequest} if the view should be translated. 32591 * The view is marked as having {@link #setHasTransientState(boolean) transient state} so that 32592 * recycling of views doesn't prevent the system from attaching the response to it. Therefore, 32593 * if overriding this method, you should set or reset the transient state. </p> 32594 * 32595 * @param viewIds a map for the view's {@link AutofillId} and its virtual child ids or 32596 * {@code null} if the view doesn't have virtual child that should be translated. The virtual 32597 * child ids are the same virtual ids provided by ContentCapture. 32598 * @param supportedFormats the supported translation formats. For now, the only possible value 32599 * is the {@link android.view.translation.TranslationSpec#DATA_FORMAT_TEXT}. 32600 * @param capability a {@link TranslationCapability} that holds translation capability. 32601 * information, e.g. source spec, target spec. 32602 * @param requests fill in with {@link ViewTranslationRequest}s for translation purpose. 32603 */ dispatchCreateViewTranslationRequest(@onNull Map<AutofillId, long[]> viewIds, @NonNull @DataFormat int[] supportedFormats, @NonNull TranslationCapability capability, @NonNull List<ViewTranslationRequest> requests)32604 public void dispatchCreateViewTranslationRequest(@NonNull Map<AutofillId, long[]> viewIds, 32605 @NonNull @DataFormat int[] supportedFormats, 32606 @NonNull TranslationCapability capability, 32607 @NonNull List<ViewTranslationRequest> requests) { 32608 AutofillId autofillId = getAutofillId(); 32609 if (viewIds.containsKey(autofillId)) { 32610 if (viewIds.get(autofillId) == null) { 32611 // TODO: avoiding the allocation per view 32612 onCreateViewTranslationRequest(supportedFormats, 32613 new ViewTranslationRequestConsumer(requests)); 32614 } else { 32615 onCreateVirtualViewTranslationRequests(viewIds.get(autofillId), supportedFormats, 32616 request -> { 32617 requests.add(request); 32618 }); 32619 } 32620 } 32621 } 32622 32623 private class ViewTranslationRequestConsumer implements Consumer<ViewTranslationRequest> { 32624 private final List<ViewTranslationRequest> mRequests; 32625 private boolean mCalled; 32626 ViewTranslationRequestConsumer(List<ViewTranslationRequest> requests)32627 ViewTranslationRequestConsumer(List<ViewTranslationRequest> requests) { 32628 mRequests = requests; 32629 } 32630 32631 @Override accept(ViewTranslationRequest request)32632 public void accept(ViewTranslationRequest request) { 32633 if (mCalled) { 32634 throw new IllegalStateException("The translation Consumer is not reusable."); 32635 } 32636 mCalled = true; 32637 if (request != null && request.getKeys().size() > 0) { 32638 mRequests.add(request); 32639 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 32640 Log.v(CONTENT_CAPTURE_LOG_TAG, "Calling setHasTransientState(true) for " 32641 + getAutofillId()); 32642 } 32643 setHasTransientState(true); 32644 setHasTranslationTransientState(true); 32645 } 32646 } 32647 } 32648 32649 /** 32650 * Called to generate a {@link DisplayHash} for this view. 32651 * 32652 * @param hashAlgorithm The hash algorithm to use when hashing the display. Must be one of 32653 * the values returned from 32654 * {@link DisplayHashManager#getSupportedHashAlgorithms()} 32655 * @param bounds The bounds for the content within the View to generate the hash for. If 32656 * bounds are null, the entire View's bounds will be used. If empty, it will 32657 * invoke the callback 32658 * {@link DisplayHashResultCallback#onDisplayHashError} with error 32659 * {@link DisplayHashResultCallback#DISPLAY_HASH_ERROR_INVALID_BOUNDS} 32660 * @param executor The executor that the callback should be invoked on. 32661 * @param callback The callback to handle the results of generating the display hash 32662 */ generateDisplayHash(@onNull String hashAlgorithm, @Nullable Rect bounds, @NonNull Executor executor, @NonNull DisplayHashResultCallback callback)32663 public void generateDisplayHash(@NonNull String hashAlgorithm, 32664 @Nullable Rect bounds, @NonNull Executor executor, 32665 @NonNull DisplayHashResultCallback callback) { 32666 IWindowSession session = getWindowSession(); 32667 if (session == null) { 32668 callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); 32669 return; 32670 } 32671 IWindow window = getWindow(); 32672 if (window == null) { 32673 callback.onDisplayHashError(DISPLAY_HASH_ERROR_MISSING_WINDOW); 32674 return; 32675 } 32676 32677 Rect visibleBounds = new Rect(); 32678 getGlobalVisibleRect(visibleBounds); 32679 32680 if (bounds != null && bounds.isEmpty()) { 32681 callback.onDisplayHashError(DISPLAY_HASH_ERROR_INVALID_BOUNDS); 32682 return; 32683 } 32684 32685 if (bounds != null) { 32686 bounds.offset(visibleBounds.left, visibleBounds.top); 32687 visibleBounds.intersectUnchecked(bounds); 32688 } 32689 32690 if (visibleBounds.isEmpty()) { 32691 callback.onDisplayHashError(DISPLAY_HASH_ERROR_NOT_VISIBLE_ON_SCREEN); 32692 return; 32693 } 32694 32695 RemoteCallback remoteCallback = new RemoteCallback(result -> 32696 executor.execute(() -> { 32697 DisplayHash displayHash = result.getParcelable(EXTRA_DISPLAY_HASH, android.view.displayhash.DisplayHash.class); 32698 int errorCode = result.getInt(EXTRA_DISPLAY_HASH_ERROR_CODE, 32699 DISPLAY_HASH_ERROR_UNKNOWN); 32700 if (displayHash != null) { 32701 callback.onDisplayHashResult(displayHash); 32702 } else { 32703 callback.onDisplayHashError(errorCode); 32704 } 32705 })); 32706 32707 try { 32708 session.generateDisplayHash(window, visibleBounds, hashAlgorithm, remoteCallback); 32709 } catch (RemoteException e) { 32710 Log.e(VIEW_LOG_TAG, "Failed to call generateDisplayHash"); 32711 callback.onDisplayHashError(DISPLAY_HASH_ERROR_UNKNOWN); 32712 } 32713 } 32714 32715 /** 32716 * The AttachedSurfaceControl itself is not a View, it is just the interface to the 32717 * windowing-system object that contains the entire view hierarchy. 32718 * For the root View of a given hierarchy see {@link #getRootView}. 32719 32720 * @return The {@link android.view.AttachedSurfaceControl} interface for this View. 32721 * This will only return a non-null value when called between {@link #onAttachedToWindow} 32722 * and {@link #onDetachedFromWindow}. 32723 */ getRootSurfaceControl()32724 public @Nullable AttachedSurfaceControl getRootSurfaceControl() { 32725 if (mAttachInfo != null) { 32726 return mAttachInfo.getRootSurfaceControl(); 32727 } 32728 return null; 32729 } 32730 } 32731