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.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS; 21 import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS; 22 import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP; 23 import static android.util.StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; 24 import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL; 25 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; 26 27 import static java.lang.Math.max; 28 29 import android.animation.AnimatorInflater; 30 import android.animation.StateListAnimator; 31 import android.annotation.AttrRes; 32 import android.annotation.CallSuper; 33 import android.annotation.ColorInt; 34 import android.annotation.DrawableRes; 35 import android.annotation.FloatRange; 36 import android.annotation.IdRes; 37 import android.annotation.IntDef; 38 import android.annotation.IntRange; 39 import android.annotation.LayoutRes; 40 import android.annotation.NonNull; 41 import android.annotation.Nullable; 42 import android.annotation.Size; 43 import android.annotation.StyleRes; 44 import android.annotation.TestApi; 45 import android.annotation.UiThread; 46 import android.annotation.UnsupportedAppUsage; 47 import android.content.AutofillOptions; 48 import android.content.ClipData; 49 import android.content.Context; 50 import android.content.ContextWrapper; 51 import android.content.Intent; 52 import android.content.res.ColorStateList; 53 import android.content.res.Configuration; 54 import android.content.res.Resources; 55 import android.content.res.TypedArray; 56 import android.graphics.Bitmap; 57 import android.graphics.BlendMode; 58 import android.graphics.Canvas; 59 import android.graphics.Color; 60 import android.graphics.Insets; 61 import android.graphics.Interpolator; 62 import android.graphics.LinearGradient; 63 import android.graphics.Matrix; 64 import android.graphics.Outline; 65 import android.graphics.Paint; 66 import android.graphics.PixelFormat; 67 import android.graphics.Point; 68 import android.graphics.PorterDuff; 69 import android.graphics.PorterDuffXfermode; 70 import android.graphics.RecordingCanvas; 71 import android.graphics.Rect; 72 import android.graphics.RectF; 73 import android.graphics.Region; 74 import android.graphics.RenderNode; 75 import android.graphics.Shader; 76 import android.graphics.drawable.ColorDrawable; 77 import android.graphics.drawable.Drawable; 78 import android.hardware.display.DisplayManagerGlobal; 79 import android.net.Uri; 80 import android.os.Build; 81 import android.os.Bundle; 82 import android.os.Handler; 83 import android.os.IBinder; 84 import android.os.Message; 85 import android.os.Parcel; 86 import android.os.Parcelable; 87 import android.os.RemoteException; 88 import android.os.SystemClock; 89 import android.os.Trace; 90 import android.sysprop.DisplayProperties; 91 import android.text.InputType; 92 import android.text.TextUtils; 93 import android.util.AttributeSet; 94 import android.util.FloatProperty; 95 import android.util.LayoutDirection; 96 import android.util.Log; 97 import android.util.LongSparseLongArray; 98 import android.util.Pools.SynchronizedPool; 99 import android.util.Property; 100 import android.util.SparseArray; 101 import android.util.SparseIntArray; 102 import android.util.StateSet; 103 import android.util.StatsLog; 104 import android.util.SuperNotCalledException; 105 import android.util.TypedValue; 106 import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 107 import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 108 import android.view.AccessibilityIterators.TextSegmentIterator; 109 import android.view.AccessibilityIterators.WordTextSegmentIterator; 110 import android.view.ContextMenu.ContextMenuInfo; 111 import android.view.WindowInsetsAnimationListener.InsetsAnimation; 112 import android.view.accessibility.AccessibilityEvent; 113 import android.view.accessibility.AccessibilityEventSource; 114 import android.view.accessibility.AccessibilityManager; 115 import android.view.accessibility.AccessibilityNodeIdManager; 116 import android.view.accessibility.AccessibilityNodeInfo; 117 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 118 import android.view.accessibility.AccessibilityNodeProvider; 119 import android.view.accessibility.AccessibilityWindowInfo; 120 import android.view.animation.Animation; 121 import android.view.animation.AnimationUtils; 122 import android.view.animation.Transformation; 123 import android.view.autofill.AutofillId; 124 import android.view.autofill.AutofillManager; 125 import android.view.autofill.AutofillValue; 126 import android.view.contentcapture.ContentCaptureContext; 127 import android.view.contentcapture.ContentCaptureManager; 128 import android.view.contentcapture.ContentCaptureSession; 129 import android.view.inputmethod.EditorInfo; 130 import android.view.inputmethod.InputConnection; 131 import android.view.inputmethod.InputMethodManager; 132 import android.view.inspector.InspectableProperty; 133 import android.view.inspector.InspectableProperty.EnumEntry; 134 import android.view.inspector.InspectableProperty.FlagEntry; 135 import android.widget.Checkable; 136 import android.widget.FrameLayout; 137 import android.widget.ScrollBarDrawable; 138 139 import com.android.internal.R; 140 import com.android.internal.view.TooltipPopup; 141 import com.android.internal.view.menu.MenuBuilder; 142 import com.android.internal.widget.ScrollBarUtils; 143 144 import com.google.android.collect.Lists; 145 import com.google.android.collect.Maps; 146 147 import java.lang.annotation.Retention; 148 import java.lang.annotation.RetentionPolicy; 149 import java.lang.ref.WeakReference; 150 import java.lang.reflect.Field; 151 import java.lang.reflect.InvocationTargetException; 152 import java.lang.reflect.Method; 153 import java.lang.reflect.Modifier; 154 import java.util.ArrayList; 155 import java.util.Arrays; 156 import java.util.Calendar; 157 import java.util.Collection; 158 import java.util.Collections; 159 import java.util.HashMap; 160 import java.util.List; 161 import java.util.Locale; 162 import java.util.Map; 163 import java.util.concurrent.CopyOnWriteArrayList; 164 import java.util.concurrent.atomic.AtomicInteger; 165 import java.util.function.Predicate; 166 167 /** 168 * <p> 169 * This class represents the basic building block for user interface components. A View 170 * occupies a rectangular area on the screen and is responsible for drawing and 171 * event handling. View is the base class for <em>widgets</em>, which are 172 * used to create interactive UI components (buttons, text fields, etc.). The 173 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 174 * are invisible containers that hold other Views (or other ViewGroups) and define 175 * their layout properties. 176 * </p> 177 * 178 * <div class="special reference"> 179 * <h3>Developer Guides</h3> 180 * <p>For information about using this class to develop your application's user interface, 181 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 182 * </div> 183 * 184 * <a name="Using"></a> 185 * <h3>Using Views</h3> 186 * <p> 187 * All of the views in a window are arranged in a single tree. You can add views 188 * either from code or by specifying a tree of views in one or more XML layout 189 * files. There are many specialized subclasses of views that act as controls or 190 * are capable of displaying text, images, or other content. 191 * </p> 192 * <p> 193 * Once you have created a tree of views, there are typically a few types of 194 * common operations you may wish to perform: 195 * <ul> 196 * <li><strong>Set properties:</strong> for example setting the text of a 197 * {@link android.widget.TextView}. The available properties and the methods 198 * that set them will vary among the different subclasses of views. Note that 199 * properties that are known at build time can be set in the XML layout 200 * files.</li> 201 * <li><strong>Set focus:</strong> The framework will handle moving focus in 202 * response to user input. To force focus to a specific view, call 203 * {@link #requestFocus}.</li> 204 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 205 * that will be notified when something interesting happens to the view. For 206 * example, all views will let you set a listener to be notified when the view 207 * gains or loses focus. You can register such a listener using 208 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 209 * Other view subclasses offer more specialized listeners. For example, a Button 210 * exposes a listener to notify clients when the button is clicked.</li> 211 * <li><strong>Set visibility:</strong> You can hide or show views using 212 * {@link #setVisibility(int)}.</li> 213 * </ul> 214 * </p> 215 * <p><em> 216 * Note: The Android framework is responsible for measuring, laying out and 217 * drawing views. You should not call methods that perform these actions on 218 * views yourself unless you are actually implementing a 219 * {@link android.view.ViewGroup}. 220 * </em></p> 221 * 222 * <a name="Lifecycle"></a> 223 * <h3>Implementing a Custom View</h3> 224 * 225 * <p> 226 * To implement a custom view, you will usually begin by providing overrides for 227 * some of the standard methods that the framework calls on all views. You do 228 * not need to override all of these methods. In fact, you can start by just 229 * overriding {@link #onDraw(android.graphics.Canvas)}. 230 * <table border="2" width="85%" align="center" cellpadding="5"> 231 * <thead> 232 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 233 * </thead> 234 * 235 * <tbody> 236 * <tr> 237 * <td rowspan="2">Creation</td> 238 * <td>Constructors</td> 239 * <td>There is a form of the constructor that are called when the view 240 * is created from code and a form that is called when the view is 241 * inflated from a layout file. The second form should parse and apply 242 * any attributes defined in the layout file. 243 * </td> 244 * </tr> 245 * <tr> 246 * <td><code>{@link #onFinishInflate()}</code></td> 247 * <td>Called after a view and all of its children has been inflated 248 * from XML.</td> 249 * </tr> 250 * 251 * <tr> 252 * <td rowspan="3">Layout</td> 253 * <td><code>{@link #onMeasure(int, int)}</code></td> 254 * <td>Called to determine the size requirements for this view and all 255 * of its children. 256 * </td> 257 * </tr> 258 * <tr> 259 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 260 * <td>Called when this view should assign a size and position to all 261 * of its children. 262 * </td> 263 * </tr> 264 * <tr> 265 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 266 * <td>Called when the size of this view has changed. 267 * </td> 268 * </tr> 269 * 270 * <tr> 271 * <td>Drawing</td> 272 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 273 * <td>Called when the view should render its content. 274 * </td> 275 * </tr> 276 * 277 * <tr> 278 * <td rowspan="4">Event processing</td> 279 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 280 * <td>Called when a new hardware key event occurs. 281 * </td> 282 * </tr> 283 * <tr> 284 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 285 * <td>Called when a hardware key up event occurs. 286 * </td> 287 * </tr> 288 * <tr> 289 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 290 * <td>Called when a trackball motion event occurs. 291 * </td> 292 * </tr> 293 * <tr> 294 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 295 * <td>Called when a touch screen motion event occurs. 296 * </td> 297 * </tr> 298 * 299 * <tr> 300 * <td rowspan="2">Focus</td> 301 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 302 * <td>Called when the view gains or loses focus. 303 * </td> 304 * </tr> 305 * 306 * <tr> 307 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 308 * <td>Called when the window containing the view gains or loses focus. 309 * </td> 310 * </tr> 311 * 312 * <tr> 313 * <td rowspan="3">Attaching</td> 314 * <td><code>{@link #onAttachedToWindow()}</code></td> 315 * <td>Called when the view is attached to a window. 316 * </td> 317 * </tr> 318 * 319 * <tr> 320 * <td><code>{@link #onDetachedFromWindow}</code></td> 321 * <td>Called when the view is detached from its window. 322 * </td> 323 * </tr> 324 * 325 * <tr> 326 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 327 * <td>Called when the visibility of the window containing the view 328 * has changed. 329 * </td> 330 * </tr> 331 * </tbody> 332 * 333 * </table> 334 * </p> 335 * 336 * <a name="IDs"></a> 337 * <h3>IDs</h3> 338 * Views may have an integer id associated with them. These ids are typically 339 * assigned in the layout XML files, and are used to find specific views within 340 * the view tree. A common pattern is to: 341 * <ul> 342 * <li>Define a Button in the layout file and assign it a unique ID. 343 * <pre> 344 * <Button 345 * android:id="@+id/my_button" 346 * android:layout_width="wrap_content" 347 * android:layout_height="wrap_content" 348 * android:text="@string/my_button_text"/> 349 * </pre></li> 350 * <li>From the onCreate method of an Activity, find the Button 351 * <pre class="prettyprint"> 352 * Button myButton = findViewById(R.id.my_button); 353 * </pre></li> 354 * </ul> 355 * <p> 356 * View IDs need not be unique throughout the tree, but it is good practice to 357 * ensure that they are at least unique within the part of the tree you are 358 * searching. 359 * </p> 360 * 361 * <a name="Position"></a> 362 * <h3>Position</h3> 363 * <p> 364 * The geometry of a view is that of a rectangle. A view has a location, 365 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 366 * two dimensions, expressed as a width and a height. The unit for location 367 * and dimensions is the pixel. 368 * </p> 369 * 370 * <p> 371 * It is possible to retrieve the location of a view by invoking the methods 372 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 373 * coordinate of the rectangle representing the view. The latter returns the 374 * top, or Y, coordinate of the rectangle representing the view. These methods 375 * both return the location of the view relative to its parent. For instance, 376 * when getLeft() returns 20, that means the view is located 20 pixels to the 377 * right of the left edge of its direct parent. 378 * </p> 379 * 380 * <p> 381 * In addition, several convenience methods are offered to avoid unnecessary 382 * computations, namely {@link #getRight()} and {@link #getBottom()}. 383 * These methods return the coordinates of the right and bottom edges of the 384 * rectangle representing the view. For instance, calling {@link #getRight()} 385 * is similar to the following computation: <code>getLeft() + getWidth()</code> 386 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 387 * </p> 388 * 389 * <a name="SizePaddingMargins"></a> 390 * <h3>Size, padding and margins</h3> 391 * <p> 392 * The size of a view is expressed with a width and a height. A view actually 393 * possess two pairs of width and height values. 394 * </p> 395 * 396 * <p> 397 * The first pair is known as <em>measured width</em> and 398 * <em>measured height</em>. These dimensions define how big a view wants to be 399 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 400 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 401 * and {@link #getMeasuredHeight()}. 402 * </p> 403 * 404 * <p> 405 * The second pair is simply known as <em>width</em> and <em>height</em>, or 406 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 407 * dimensions define the actual size of the view on screen, at drawing time and 408 * after layout. These values may, but do not have to, be different from the 409 * measured width and height. The width and height can be obtained by calling 410 * {@link #getWidth()} and {@link #getHeight()}. 411 * </p> 412 * 413 * <p> 414 * To measure its dimensions, a view takes into account its padding. The padding 415 * is expressed in pixels for the left, top, right and bottom parts of the view. 416 * Padding can be used to offset the content of the view by a specific amount of 417 * pixels. For instance, a left padding of 2 will push the view's content by 418 * 2 pixels to the right of the left edge. Padding can be set using the 419 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 420 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 421 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 422 * {@link #getPaddingEnd()}. 423 * </p> 424 * 425 * <p> 426 * Even though a view can define a padding, it does not provide any support for 427 * margins. However, view groups provide such a support. Refer to 428 * {@link android.view.ViewGroup} and 429 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 430 * </p> 431 * 432 * <a name="Layout"></a> 433 * <h3>Layout</h3> 434 * <p> 435 * Layout is a two pass process: a measure pass and a layout pass. The measuring 436 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 437 * of the view tree. Each view pushes dimension specifications down the tree 438 * during the recursion. At the end of the measure pass, every view has stored 439 * its measurements. The second pass happens in 440 * {@link #layout(int,int,int,int)} and is also top-down. During 441 * this pass each parent is responsible for positioning all of its children 442 * using the sizes computed in the measure pass. 443 * </p> 444 * 445 * <p> 446 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 447 * {@link #getMeasuredHeight()} values must be set, along with those for all of 448 * that view's descendants. A view's measured width and measured height values 449 * must respect the constraints imposed by the view's parents. This guarantees 450 * that at the end of the measure pass, all parents accept all of their 451 * children's measurements. A parent view may call measure() more than once on 452 * its children. For example, the parent may measure each child once with 453 * unspecified dimensions to find out how big they want to be, then call 454 * measure() on them again with actual numbers if the sum of all the children's 455 * unconstrained sizes is too big or too small. 456 * </p> 457 * 458 * <p> 459 * The measure pass uses two classes to communicate dimensions. The 460 * {@link MeasureSpec} class is used by views to tell their parents how they 461 * want to be measured and positioned. The base LayoutParams class just 462 * describes how big the view wants to be for both width and height. For each 463 * dimension, it can specify one of: 464 * <ul> 465 * <li> an exact number 466 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 467 * (minus padding) 468 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 469 * enclose its content (plus padding). 470 * </ul> 471 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 472 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 473 * an X and Y value. 474 * </p> 475 * 476 * <p> 477 * MeasureSpecs are used to push requirements down the tree from parent to 478 * child. A MeasureSpec can be in one of three modes: 479 * <ul> 480 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 481 * of a child view. For example, a LinearLayout may call measure() on its child 482 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 483 * tall the child view wants to be given a width of 240 pixels. 484 * <li>EXACTLY: This is used by the parent to impose an exact size on the 485 * child. The child must use this size, and guarantee that all of its 486 * descendants will fit within this size. 487 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 488 * child. The child must guarantee that it and all of its descendants will fit 489 * within this size. 490 * </ul> 491 * </p> 492 * 493 * <p> 494 * To initiate a layout, call {@link #requestLayout}. This method is typically 495 * called by a view on itself when it believes that is can no longer fit within 496 * its current bounds. 497 * </p> 498 * 499 * <a name="Drawing"></a> 500 * <h3>Drawing</h3> 501 * <p> 502 * Drawing is handled by walking the tree and recording the drawing commands of 503 * any View that needs to update. After this, the drawing commands of the 504 * entire tree are issued to screen, clipped to the newly damaged area. 505 * </p> 506 * 507 * <p> 508 * The tree is largely recorded and drawn in order, with parents drawn before 509 * (i.e., behind) their children, with siblings drawn in the order they appear 510 * in the tree. If you set a background drawable for a View, then the View will 511 * draw it before calling back to its <code>onDraw()</code> method. The child 512 * drawing order can be overridden with 513 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 514 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 515 * </p> 516 * 517 * <p> 518 * To force a view to draw, call {@link #invalidate()}. 519 * </p> 520 * 521 * <a name="EventHandlingThreading"></a> 522 * <h3>Event Handling and Threading</h3> 523 * <p> 524 * The basic cycle of a view is as follows: 525 * <ol> 526 * <li>An event comes in and is dispatched to the appropriate view. The view 527 * handles the event and notifies any listeners.</li> 528 * <li>If in the course of processing the event, the view's bounds may need 529 * to be changed, the view will call {@link #requestLayout()}.</li> 530 * <li>Similarly, if in the course of processing the event the view's appearance 531 * may need to be changed, the view will call {@link #invalidate()}.</li> 532 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 533 * the framework will take care of measuring, laying out, and drawing the tree 534 * as appropriate.</li> 535 * </ol> 536 * </p> 537 * 538 * <p><em>Note: The entire view tree is single threaded. You must always be on 539 * the UI thread when calling any method on any view.</em> 540 * If you are doing work on other threads and want to update the state of a view 541 * from that thread, you should use a {@link Handler}. 542 * </p> 543 * 544 * <a name="FocusHandling"></a> 545 * <h3>Focus Handling</h3> 546 * <p> 547 * The framework will handle routine focus movement in response to user input. 548 * This includes changing the focus as views are removed or hidden, or as new 549 * views become available. Views indicate their willingness to take focus 550 * through the {@link #isFocusable} method. To change whether a view can take 551 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 552 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 553 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 554 * </p> 555 * <p> 556 * Focus movement is based on an algorithm which finds the nearest neighbor in a 557 * given direction. In rare cases, the default algorithm may not match the 558 * intended behavior of the developer. In these situations, you can provide 559 * explicit overrides by using these XML attributes in the layout file: 560 * <pre> 561 * nextFocusDown 562 * nextFocusLeft 563 * nextFocusRight 564 * nextFocusUp 565 * </pre> 566 * </p> 567 * 568 * 569 * <p> 570 * To get a particular view to take focus, call {@link #requestFocus()}. 571 * </p> 572 * 573 * <a name="TouchMode"></a> 574 * <h3>Touch Mode</h3> 575 * <p> 576 * When a user is navigating a user interface via directional keys such as a D-pad, it is 577 * necessary to give focus to actionable items such as buttons so the user can see 578 * what will take input. If the device has touch capabilities, however, and the user 579 * begins interacting with the interface by touching it, it is no longer necessary to 580 * always highlight, or give focus to, a particular view. This motivates a mode 581 * for interaction named 'touch mode'. 582 * </p> 583 * <p> 584 * For a touch capable device, once the user touches the screen, the device 585 * will enter touch mode. From this point onward, only views for which 586 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 587 * Other views that are touchable, like buttons, will not take focus when touched; they will 588 * only fire the on click listeners. 589 * </p> 590 * <p> 591 * Any time a user hits a directional key, such as a D-pad direction, the view device will 592 * exit touch mode, and find a view to take focus, so that the user may resume interacting 593 * with the user interface without touching the screen again. 594 * </p> 595 * <p> 596 * The touch mode state is maintained across {@link android.app.Activity}s. Call 597 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 598 * </p> 599 * 600 * <a name="Scrolling"></a> 601 * <h3>Scrolling</h3> 602 * <p> 603 * The framework provides basic support for views that wish to internally 604 * scroll their content. This includes keeping track of the X and Y scroll 605 * offset as well as mechanisms for drawing scrollbars. See 606 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 607 * {@link #awakenScrollBars()} for more details. 608 * </p> 609 * 610 * <a name="Tags"></a> 611 * <h3>Tags</h3> 612 * <p> 613 * Unlike IDs, tags are not used to identify views. Tags are essentially an 614 * extra piece of information that can be associated with a view. They are most 615 * often used as a convenience to store data related to views in the views 616 * themselves rather than by putting them in a separate structure. 617 * </p> 618 * <p> 619 * Tags may be specified with character sequence values in layout XML as either 620 * a single tag using the {@link android.R.styleable#View_tag android:tag} 621 * attribute or multiple tags using the {@code <tag>} child element: 622 * <pre> 623 * <View ... 624 * android:tag="@string/mytag_value" /> 625 * <View ...> 626 * <tag android:id="@+id/mytag" 627 * android:value="@string/mytag_value" /> 628 * </View> 629 * </pre> 630 * </p> 631 * <p> 632 * Tags may also be specified with arbitrary objects from code using 633 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 634 * </p> 635 * 636 * <a name="Themes"></a> 637 * <h3>Themes</h3> 638 * <p> 639 * By default, Views are created using the theme of the Context object supplied 640 * to their constructor; however, a different theme may be specified by using 641 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 642 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 643 * code. 644 * </p> 645 * <p> 646 * When the {@link android.R.styleable#View_theme android:theme} attribute is 647 * used in XML, the specified theme is applied on top of the inflation 648 * context's theme (see {@link LayoutInflater}) and used for the view itself as 649 * well as any child elements. 650 * </p> 651 * <p> 652 * In the following example, both views will be created using the Material dark 653 * color scheme; however, because an overlay theme is used which only defines a 654 * subset of attributes, the value of 655 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 656 * the inflation context's theme (e.g. the Activity theme) will be preserved. 657 * <pre> 658 * <LinearLayout 659 * ... 660 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 661 * <View ...> 662 * </LinearLayout> 663 * </pre> 664 * </p> 665 * 666 * <a name="Properties"></a> 667 * <h3>Properties</h3> 668 * <p> 669 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 670 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 671 * available both in the {@link Property} form as well as in similarly-named setter/getter 672 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 673 * be used to set persistent state associated with these rendering-related properties on the view. 674 * The properties and methods can also be used in conjunction with 675 * {@link android.animation.Animator Animator}-based animations, described more in the 676 * <a href="#Animation">Animation</a> section. 677 * </p> 678 * 679 * <a name="Animation"></a> 680 * <h3>Animation</h3> 681 * <p> 682 * Starting with Android 3.0, the preferred way of animating views is to use the 683 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 684 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 685 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 686 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 687 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 688 * makes animating these View properties particularly easy and efficient. 689 * </p> 690 * <p> 691 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 692 * You can attach an {@link Animation} object to a view using 693 * {@link #setAnimation(Animation)} or 694 * {@link #startAnimation(Animation)}. The animation can alter the scale, 695 * rotation, translation and alpha of a view over time. If the animation is 696 * attached to a view that has children, the animation will affect the entire 697 * subtree rooted by that node. When an animation is started, the framework will 698 * take care of redrawing the appropriate views until the animation completes. 699 * </p> 700 * 701 * <a name="Security"></a> 702 * <h3>Security</h3> 703 * <p> 704 * Sometimes it is essential that an application be able to verify that an action 705 * is being performed with the full knowledge and consent of the user, such as 706 * granting a permission request, making a purchase or clicking on an advertisement. 707 * Unfortunately, a malicious application could try to spoof the user into 708 * performing these actions, unaware, by concealing the intended purpose of the view. 709 * As a remedy, the framework offers a touch filtering mechanism that can be used to 710 * improve the security of views that provide access to sensitive functionality. 711 * </p><p> 712 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 713 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 714 * will discard touches that are received whenever the view's window is obscured by 715 * another visible window. As a result, the view will not receive touches whenever a 716 * toast, dialog or other window appears above the view's window. 717 * </p><p> 718 * For more fine-grained control over security, consider overriding the 719 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 720 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 721 * </p> 722 * 723 * @attr ref android.R.styleable#View_accessibilityHeading 724 * @attr ref android.R.styleable#View_alpha 725 * @attr ref android.R.styleable#View_background 726 * @attr ref android.R.styleable#View_clickable 727 * @attr ref android.R.styleable#View_contentDescription 728 * @attr ref android.R.styleable#View_drawingCacheQuality 729 * @attr ref android.R.styleable#View_duplicateParentState 730 * @attr ref android.R.styleable#View_id 731 * @attr ref android.R.styleable#View_requiresFadingEdge 732 * @attr ref android.R.styleable#View_fadeScrollbars 733 * @attr ref android.R.styleable#View_fadingEdgeLength 734 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 735 * @attr ref android.R.styleable#View_fitsSystemWindows 736 * @attr ref android.R.styleable#View_isScrollContainer 737 * @attr ref android.R.styleable#View_focusable 738 * @attr ref android.R.styleable#View_focusableInTouchMode 739 * @attr ref android.R.styleable#View_focusedByDefault 740 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 741 * @attr ref android.R.styleable#View_keepScreenOn 742 * @attr ref android.R.styleable#View_keyboardNavigationCluster 743 * @attr ref android.R.styleable#View_layerType 744 * @attr ref android.R.styleable#View_layoutDirection 745 * @attr ref android.R.styleable#View_longClickable 746 * @attr ref android.R.styleable#View_minHeight 747 * @attr ref android.R.styleable#View_minWidth 748 * @attr ref android.R.styleable#View_nextClusterForward 749 * @attr ref android.R.styleable#View_nextFocusDown 750 * @attr ref android.R.styleable#View_nextFocusLeft 751 * @attr ref android.R.styleable#View_nextFocusRight 752 * @attr ref android.R.styleable#View_nextFocusUp 753 * @attr ref android.R.styleable#View_onClick 754 * @attr ref android.R.styleable#View_outlineSpotShadowColor 755 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 756 * @attr ref android.R.styleable#View_padding 757 * @attr ref android.R.styleable#View_paddingHorizontal 758 * @attr ref android.R.styleable#View_paddingVertical 759 * @attr ref android.R.styleable#View_paddingBottom 760 * @attr ref android.R.styleable#View_paddingLeft 761 * @attr ref android.R.styleable#View_paddingRight 762 * @attr ref android.R.styleable#View_paddingTop 763 * @attr ref android.R.styleable#View_paddingStart 764 * @attr ref android.R.styleable#View_paddingEnd 765 * @attr ref android.R.styleable#View_saveEnabled 766 * @attr ref android.R.styleable#View_rotation 767 * @attr ref android.R.styleable#View_rotationX 768 * @attr ref android.R.styleable#View_rotationY 769 * @attr ref android.R.styleable#View_scaleX 770 * @attr ref android.R.styleable#View_scaleY 771 * @attr ref android.R.styleable#View_scrollX 772 * @attr ref android.R.styleable#View_scrollY 773 * @attr ref android.R.styleable#View_scrollbarSize 774 * @attr ref android.R.styleable#View_scrollbarStyle 775 * @attr ref android.R.styleable#View_scrollbars 776 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 777 * @attr ref android.R.styleable#View_scrollbarFadeDuration 778 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 779 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 780 * @attr ref android.R.styleable#View_scrollbarThumbVertical 781 * @attr ref android.R.styleable#View_scrollbarTrackVertical 782 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 783 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 784 * @attr ref android.R.styleable#View_stateListAnimator 785 * @attr ref android.R.styleable#View_transitionName 786 * @attr ref android.R.styleable#View_soundEffectsEnabled 787 * @attr ref android.R.styleable#View_tag 788 * @attr ref android.R.styleable#View_textAlignment 789 * @attr ref android.R.styleable#View_textDirection 790 * @attr ref android.R.styleable#View_transformPivotX 791 * @attr ref android.R.styleable#View_transformPivotY 792 * @attr ref android.R.styleable#View_translationX 793 * @attr ref android.R.styleable#View_translationY 794 * @attr ref android.R.styleable#View_translationZ 795 * @attr ref android.R.styleable#View_visibility 796 * @attr ref android.R.styleable#View_theme 797 * 798 * @see android.view.ViewGroup 799 */ 800 @UiThread 801 public class View implements Drawable.Callback, KeyEvent.Callback, 802 AccessibilityEventSource { 803 @UnsupportedAppUsage 804 private static final boolean DBG = false; 805 806 /** @hide */ 807 public static boolean DEBUG_DRAW = false; 808 809 /** 810 * The logging tag used by this class with android.util.Log. 811 */ 812 protected static final String VIEW_LOG_TAG = "View"; 813 814 /** 815 * The logging tag used by this class when logging verbose, autofill-related messages. 816 */ 817 // NOTE: We cannot use android.view.autofill.Helper.sVerbose because that variable is not 818 // set if a session is not started. 819 private static final String AUTOFILL_LOG_TAG = "View.Autofill"; 820 821 /** 822 * The logging tag used by this class when logging content capture-related messages. 823 */ 824 private static final String CONTENT_CAPTURE_LOG_TAG = "View.ContentCapture"; 825 826 private static final boolean DEBUG_CONTENT_CAPTURE = false; 827 828 /** 829 * When set to true, this view will save its attribute data. 830 * 831 * @hide 832 */ 833 public static boolean sDebugViewAttributes = false; 834 835 /** 836 * When set to this application package view will save its attribute data. 837 * 838 * @hide 839 */ 840 public static String sDebugViewAttributesApplicationPackage; 841 842 /** 843 * Used to mark a View that has no ID. 844 */ 845 public static final int NO_ID = -1; 846 847 /** 848 * Last ID that is given to Views that are no part of activities. 849 * 850 * {@hide} 851 */ 852 public static final int LAST_APP_AUTOFILL_ID = Integer.MAX_VALUE / 2; 853 854 /** 855 * Attribute to find the autofilled highlight 856 * 857 * @see #getAutofilledDrawable() 858 */ 859 private static final int[] AUTOFILL_HIGHLIGHT_ATTR = 860 new int[]{android.R.attr.autofilledHighlight}; 861 862 /** 863 * Signals that compatibility booleans have been initialized according to 864 * target SDK versions. 865 */ 866 private static boolean sCompatibilityDone = false; 867 868 /** 869 * Use the old (broken) way of building MeasureSpecs. 870 */ 871 private static boolean sUseBrokenMakeMeasureSpec = false; 872 873 /** 874 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 875 */ 876 static boolean sUseZeroUnspecifiedMeasureSpec = false; 877 878 /** 879 * Ignore any optimizations using the measure cache. 880 */ 881 private static boolean sIgnoreMeasureCache = false; 882 883 /** 884 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 885 */ 886 private static boolean sAlwaysRemeasureExactly = false; 887 888 /** 889 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 890 * without throwing 891 */ 892 static boolean sTextureViewIgnoresDrawableSetters = false; 893 894 /** 895 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 896 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 897 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 898 * check is implemented for backwards compatibility. 899 * 900 * {@hide} 901 */ 902 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 903 904 /** 905 * Prior to N, when drag enters into child of a view that has already received an 906 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 907 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 908 * false from its event handler for these events. 909 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 910 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 911 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 912 */ 913 static boolean sCascadedDragDrop; 914 915 /** 916 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 917 * to determine things like whether or not to permit item click events. We can't break 918 * apps that do this just because more things (clickable things) are now auto-focusable 919 * and they would get different results, so give old behavior to old apps. 920 */ 921 static boolean sHasFocusableExcludeAutoFocusable; 922 923 /** 924 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 925 * made focusable by default. As a result, apps could (incorrectly) change the clickable 926 * setting of views off the UI thread. Now that clickable can effect the focusable state, 927 * changing the clickable attribute off the UI thread will cause an exception (since changing 928 * the focusable state checks). In order to prevent apps from crashing, we will handle this 929 * specific case and just not notify parents on new focusables resulting from marking views 930 * clickable from outside the UI thread. 931 */ 932 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 933 934 /** 935 * Prior to P things like setScaleX() allowed passing float values that were bogus such as 936 * Float.NaN. If the app is targetting P or later then passing these values will result in an 937 * exception being thrown. If the app is targetting an earlier SDK version, then we will 938 * silently clamp these values to avoid crashes elsewhere when the rendering code hits 939 * these bogus values. 940 */ 941 private static boolean sThrowOnInvalidFloatProperties; 942 943 /** 944 * Prior to P, {@code #startDragAndDrop} accepts a builder which produces an empty drag shadow. 945 * Currently zero size SurfaceControl cannot be created thus we create a dummy 1x1 surface 946 * instead. 947 */ 948 private static boolean sAcceptZeroSizeDragShadow; 949 950 /** 951 * Prior to Q, {@link #dispatchApplyWindowInsets} had some issues: 952 * <ul> 953 * <li>The modified insets changed by {@link #onApplyWindowInsets} were passed to the 954 * entire view hierarchy in prefix order, including siblings as well as siblings of parents 955 * further down the hierarchy. This violates the basic concepts of the view hierarchy, and 956 * thus, the hierarchical dispatching mechanism was hard to use for apps.</li> 957 * 958 * <li>Dispatch was stopped after the insets were fully consumed. This is somewhat confusing 959 * for developers, but more importantly, by adding more granular information to 960 * {@link WindowInsets} it becomes really cumbersome to define what consumed actually means 961 * </li> 962 * </ul> 963 * 964 * In order to make window inset dispatching work properly, we dispatch window insets 965 * in the view hierarchy in a proper hierarchical manner and don't stop dispatching if the 966 * insets are consumed if this flag is set to {@code false}. 967 */ 968 static boolean sBrokenInsetsDispatch; 969 970 /** 971 * Prior to Q, calling 972 * {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} 973 * did not call update the window format so the opacity of the background was not correctly 974 * applied to the window. Some applications rely on this misbehavior to work properly. 975 * <p> 976 * From Q, {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} is 977 * the same as {@link com.android.internal.policy.DecorView#setWindowBackground(Drawable)} 978 * which updates the window format. 979 * @hide 980 */ 981 protected static boolean sBrokenWindowBackground; 982 983 /** @hide */ 984 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 985 @Retention(RetentionPolicy.SOURCE) 986 public @interface Focusable {} 987 988 /** 989 * This view does not want keystrokes. 990 * <p> 991 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 992 * android:focusable}. 993 */ 994 public static final int NOT_FOCUSABLE = 0x00000000; 995 996 /** 997 * This view wants keystrokes. 998 * <p> 999 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1000 * android:focusable}. 1001 */ 1002 public static final int FOCUSABLE = 0x00000001; 1003 1004 /** 1005 * This view determines focusability automatically. This is the default. 1006 * <p> 1007 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1008 * android:focusable}. 1009 */ 1010 public static final int FOCUSABLE_AUTO = 0x00000010; 1011 1012 /** 1013 * Mask for use with setFlags indicating bits used for focus. 1014 */ 1015 private static final int FOCUSABLE_MASK = 0x00000011; 1016 1017 /** 1018 * This view will adjust its padding to fit sytem windows (e.g. status bar) 1019 */ 1020 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 1021 1022 /** @hide */ 1023 @IntDef({VISIBLE, INVISIBLE, GONE}) 1024 @Retention(RetentionPolicy.SOURCE) 1025 public @interface Visibility {} 1026 1027 /** 1028 * This view is visible. 1029 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1030 * android:visibility}. 1031 */ 1032 public static final int VISIBLE = 0x00000000; 1033 1034 /** 1035 * This view is invisible, but it still takes up space for layout purposes. 1036 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1037 * android:visibility}. 1038 */ 1039 public static final int INVISIBLE = 0x00000004; 1040 1041 /** 1042 * This view is invisible, and it doesn't take any space for layout 1043 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1044 * android:visibility}. 1045 */ 1046 public static final int GONE = 0x00000008; 1047 1048 /** 1049 * Mask for use with setFlags indicating bits used for visibility. 1050 * {@hide} 1051 */ 1052 static final int VISIBILITY_MASK = 0x0000000C; 1053 1054 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 1055 1056 /** 1057 * Hint indicating that this view can be autofilled with an email address. 1058 * 1059 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1060 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1061 * value should be <code>{@value #AUTOFILL_HINT_EMAIL_ADDRESS}</code>). 1062 * 1063 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1064 */ 1065 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 1066 1067 /** 1068 * Hint indicating that this view can be autofilled with a user's real name. 1069 * 1070 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1071 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1072 * value should be <code>{@value #AUTOFILL_HINT_NAME}</code>). 1073 * 1074 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1075 */ 1076 public static final String AUTOFILL_HINT_NAME = "name"; 1077 1078 /** 1079 * Hint indicating that this view can be autofilled with a username. 1080 * 1081 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1082 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1083 * value should be <code>{@value #AUTOFILL_HINT_USERNAME}</code>). 1084 * 1085 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1086 */ 1087 public static final String AUTOFILL_HINT_USERNAME = "username"; 1088 1089 /** 1090 * Hint indicating that this view can be autofilled with a password. 1091 * 1092 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1093 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1094 * value should be <code>{@value #AUTOFILL_HINT_PASSWORD}</code>). 1095 * 1096 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1097 */ 1098 public static final String AUTOFILL_HINT_PASSWORD = "password"; 1099 1100 /** 1101 * Hint indicating that this view can be autofilled with a phone number. 1102 * 1103 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1104 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1105 * value should be <code>{@value #AUTOFILL_HINT_PHONE}</code>). 1106 * 1107 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1108 */ 1109 public static final String AUTOFILL_HINT_PHONE = "phone"; 1110 1111 /** 1112 * Hint indicating that this view can be autofilled with a postal address. 1113 * 1114 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1115 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1116 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_ADDRESS}</code>). 1117 * 1118 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1119 */ 1120 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1121 1122 /** 1123 * Hint indicating that this view can be autofilled with a postal code. 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_POSTAL_CODE}</code>). 1128 * 1129 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1130 */ 1131 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1132 1133 /** 1134 * Hint indicating that this view can be autofilled with a credit card number. 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_CREDIT_CARD_NUMBER}</code>). 1139 * 1140 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1141 */ 1142 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1143 1144 /** 1145 * Hint indicating that this view can be autofilled with a credit card security code. 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_CREDIT_CARD_SECURITY_CODE}</code>). 1150 * 1151 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1152 */ 1153 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1154 1155 /** 1156 * Hint indicating that this view can be autofilled with a credit card expiration date. 1157 * 1158 * <p>It should be used when the credit card expiration date is represented by just one view; 1159 * if it is represented by more than one (for example, one view for the month and another view 1160 * for the year), then each of these views should use the hint specific for the unit 1161 * ({@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 1162 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 1163 * or {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}). 1164 * 1165 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1166 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1167 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}</code>). 1168 * 1169 * <p>When annotating a view with this hint, it's recommended to use a date autofill value to 1170 * avoid ambiguity when the autofill service provides a value for it. To understand why a 1171 * value can be ambiguous, consider "April of 2020", which could be represented as either of 1172 * the following options: 1173 * 1174 * <ul> 1175 * <li>{@code "04/2020"} 1176 * <li>{@code "4/2020"} 1177 * <li>{@code "2020/04"} 1178 * <li>{@code "2020/4"} 1179 * <li>{@code "April/2020"} 1180 * <li>{@code "Apr/2020"} 1181 * </ul> 1182 * 1183 * <p>You define a date autofill value for the view by overriding the following methods: 1184 * 1185 * <ol> 1186 * <li>{@link #getAutofillType()} to return {@link #AUTOFILL_TYPE_DATE}. 1187 * <li>{@link #getAutofillValue()} to return a 1188 * {@link AutofillValue#forDate(long) date autofillvalue}. 1189 * <li>{@link #autofill(AutofillValue)} to expect a data autofillvalue. 1190 * </ol> 1191 * 1192 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1193 */ 1194 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1195 "creditCardExpirationDate"; 1196 1197 /** 1198 * Hint indicating that this view can be autofilled with a credit card expiration month. 1199 * 1200 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1201 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1202 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}</code>). 1203 * 1204 * <p>When annotating a view with this hint, it's recommended to use a text autofill value 1205 * whose value is the numerical representation of the month, starting on {@code 1} to avoid 1206 * ambiguity when the autofill service provides a value for it. To understand why a 1207 * value can be ambiguous, consider "January", which could be represented as either of 1208 * 1209 * <ul> 1210 * <li>{@code "1"}: recommended way. 1211 * <li>{@code "0"}: if following the {@link Calendar#MONTH} convention. 1212 * <li>{@code "January"}: full name, in English. 1213 * <li>{@code "jan"}: abbreviated name, in English. 1214 * <li>{@code "Janeiro"}: full name, in another language. 1215 * </ul> 1216 * 1217 * <p>Another recommended approach is to use a date autofill value - see 1218 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE} for more details. 1219 * 1220 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1221 */ 1222 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1223 "creditCardExpirationMonth"; 1224 1225 /** 1226 * Hint indicating that this view can be autofilled with a credit card expiration year. 1227 * 1228 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1229 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1230 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}</code>). 1231 * 1232 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1233 */ 1234 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1235 "creditCardExpirationYear"; 1236 1237 /** 1238 * Hint indicating that this view can be autofilled with a credit card expiration day. 1239 * 1240 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1241 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1242 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}</code>). 1243 * 1244 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1245 */ 1246 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1247 1248 /** 1249 * Hints for the autofill services that describes the content of the view. 1250 */ 1251 private @Nullable String[] mAutofillHints; 1252 1253 /** 1254 * Autofill id, lazily created on calls to {@link #getAutofillId()}. 1255 */ 1256 private AutofillId mAutofillId; 1257 1258 /** @hide */ 1259 @IntDef(prefix = { "AUTOFILL_TYPE_" }, value = { 1260 AUTOFILL_TYPE_NONE, 1261 AUTOFILL_TYPE_TEXT, 1262 AUTOFILL_TYPE_TOGGLE, 1263 AUTOFILL_TYPE_LIST, 1264 AUTOFILL_TYPE_DATE 1265 }) 1266 @Retention(RetentionPolicy.SOURCE) 1267 public @interface AutofillType {} 1268 1269 /** 1270 * Autofill type for views that cannot be autofilled. 1271 * 1272 * <p>Typically used when the view is read-only; for example, a text label. 1273 * 1274 * @see #getAutofillType() 1275 */ 1276 public static final int AUTOFILL_TYPE_NONE = 0; 1277 1278 /** 1279 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1280 * 1281 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1282 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1283 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1284 * 1285 * @see #getAutofillType() 1286 */ 1287 public static final int AUTOFILL_TYPE_TEXT = 1; 1288 1289 /** 1290 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1291 * 1292 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1293 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1294 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1295 * 1296 * @see #getAutofillType() 1297 */ 1298 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1299 1300 /** 1301 * Autofill type for a selection list field, which is filled by an {@code int} 1302 * representing the element index inside the list (starting at {@code 0}). 1303 * 1304 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1305 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1306 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1307 * 1308 * <p>The available options in the selection list are typically provided by 1309 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1310 * 1311 * @see #getAutofillType() 1312 */ 1313 public static final int AUTOFILL_TYPE_LIST = 3; 1314 1315 1316 /** 1317 * Autofill type for a field that contains a date, which is represented by a long representing 1318 * the number of milliseconds since the standard base time known as "the epoch", namely 1319 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1320 * 1321 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1322 * {@link AutofillValue#forDate(long)}, and the values passed to 1323 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1324 * 1325 * @see #getAutofillType() 1326 */ 1327 public static final int AUTOFILL_TYPE_DATE = 4; 1328 1329 /** @hide */ 1330 @IntDef(prefix = { "IMPORTANT_FOR_AUTOFILL_" }, value = { 1331 IMPORTANT_FOR_AUTOFILL_AUTO, 1332 IMPORTANT_FOR_AUTOFILL_YES, 1333 IMPORTANT_FOR_AUTOFILL_NO, 1334 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 1335 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 1336 }) 1337 @Retention(RetentionPolicy.SOURCE) 1338 public @interface AutofillImportance {} 1339 1340 /** 1341 * Automatically determine whether a view is important for autofill. 1342 * 1343 * @see #isImportantForAutofill() 1344 * @see #setImportantForAutofill(int) 1345 */ 1346 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1347 1348 /** 1349 * The view is important for autofill, and its children (if any) will be traversed. 1350 * 1351 * @see #isImportantForAutofill() 1352 * @see #setImportantForAutofill(int) 1353 */ 1354 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1355 1356 /** 1357 * The view is not important for autofill, but its children (if any) will be traversed. 1358 * 1359 * @see #isImportantForAutofill() 1360 * @see #setImportantForAutofill(int) 1361 */ 1362 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1363 1364 /** 1365 * The view is important for autofill, but its children (if any) will not be traversed. 1366 * 1367 * @see #isImportantForAutofill() 1368 * @see #setImportantForAutofill(int) 1369 */ 1370 public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; 1371 1372 /** 1373 * The view is not important for autofill, and its children (if any) will not be traversed. 1374 * 1375 * @see #isImportantForAutofill() 1376 * @see #setImportantForAutofill(int) 1377 */ 1378 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; 1379 1380 /** @hide */ 1381 @IntDef(flag = true, prefix = { "AUTOFILL_FLAG_" }, value = { 1382 AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 1383 }) 1384 @Retention(RetentionPolicy.SOURCE) 1385 public @interface AutofillFlags {} 1386 1387 /** 1388 * Flag requesting you to add views that are marked as not important for autofill 1389 * (see {@link #setImportantForAutofill(int)}) to a {@link ViewStructure}. 1390 */ 1391 public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; 1392 1393 /** 1394 * This view is enabled. Interpretation varies by subclass. 1395 * Use with ENABLED_MASK when calling setFlags. 1396 * {@hide} 1397 */ 1398 static final int ENABLED = 0x00000000; 1399 1400 /** 1401 * This view is disabled. Interpretation varies by subclass. 1402 * Use with ENABLED_MASK when calling setFlags. 1403 * {@hide} 1404 */ 1405 static final int DISABLED = 0x00000020; 1406 1407 /** 1408 * Mask for use with setFlags indicating bits used for indicating whether 1409 * this view is enabled 1410 * {@hide} 1411 */ 1412 static final int ENABLED_MASK = 0x00000020; 1413 1414 /** 1415 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1416 * called and further optimizations will be performed. It is okay to have 1417 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1418 * {@hide} 1419 */ 1420 static final int WILL_NOT_DRAW = 0x00000080; 1421 1422 /** 1423 * Mask for use with setFlags indicating bits used for indicating whether 1424 * this view is will draw 1425 * {@hide} 1426 */ 1427 static final int DRAW_MASK = 0x00000080; 1428 1429 /** 1430 * <p>This view doesn't show scrollbars.</p> 1431 * {@hide} 1432 */ 1433 static final int SCROLLBARS_NONE = 0x00000000; 1434 1435 /** 1436 * <p>This view shows horizontal scrollbars.</p> 1437 * {@hide} 1438 */ 1439 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1440 1441 /** 1442 * <p>This view shows vertical scrollbars.</p> 1443 * {@hide} 1444 */ 1445 static final int SCROLLBARS_VERTICAL = 0x00000200; 1446 1447 /** 1448 * <p>Mask for use with setFlags indicating bits used for indicating which 1449 * scrollbars are enabled.</p> 1450 * {@hide} 1451 */ 1452 static final int SCROLLBARS_MASK = 0x00000300; 1453 1454 /** 1455 * Indicates that the view should filter touches when its window is obscured. 1456 * Refer to the class comments for more information about this security feature. 1457 * {@hide} 1458 */ 1459 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1460 1461 /** 1462 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1463 * that they are optional and should be skipped if the window has 1464 * requested system UI flags that ignore those insets for layout. 1465 */ 1466 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1467 1468 /** 1469 * <p>This view doesn't show fading edges.</p> 1470 * {@hide} 1471 */ 1472 static final int FADING_EDGE_NONE = 0x00000000; 1473 1474 /** 1475 * <p>This view shows horizontal fading edges.</p> 1476 * {@hide} 1477 */ 1478 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1479 1480 /** 1481 * <p>This view shows vertical fading edges.</p> 1482 * {@hide} 1483 */ 1484 static final int FADING_EDGE_VERTICAL = 0x00002000; 1485 1486 /** 1487 * <p>Mask for use with setFlags indicating bits used for indicating which 1488 * fading edges are enabled.</p> 1489 * {@hide} 1490 */ 1491 static final int FADING_EDGE_MASK = 0x00003000; 1492 1493 /** 1494 * <p>Indicates this view can be clicked. When clickable, a View reacts 1495 * to clicks by notifying the OnClickListener.<p> 1496 * {@hide} 1497 */ 1498 static final int CLICKABLE = 0x00004000; 1499 1500 /** 1501 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1502 * {@hide} 1503 */ 1504 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1505 1506 /** 1507 * <p>Indicates that no icicle should be saved for this view.<p> 1508 * {@hide} 1509 */ 1510 static final int SAVE_DISABLED = 0x000010000; 1511 1512 /** 1513 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1514 * property.</p> 1515 * {@hide} 1516 */ 1517 static final int SAVE_DISABLED_MASK = 0x000010000; 1518 1519 /** 1520 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1521 * {@hide} 1522 */ 1523 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1524 1525 /** 1526 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1527 * {@hide} 1528 */ 1529 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1530 1531 /** @hide */ 1532 @Retention(RetentionPolicy.SOURCE) 1533 @IntDef(prefix = { "DRAWING_CACHE_QUALITY_" }, value = { 1534 DRAWING_CACHE_QUALITY_LOW, 1535 DRAWING_CACHE_QUALITY_HIGH, 1536 DRAWING_CACHE_QUALITY_AUTO 1537 }) 1538 public @interface DrawingCacheQuality {} 1539 1540 /** 1541 * <p>Enables low quality mode for the drawing cache.</p> 1542 * 1543 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1544 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1545 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1546 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1547 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1548 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1549 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1550 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1551 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1552 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1553 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1554 * reports or unit testing the {@link PixelCopy} API is recommended. 1555 */ 1556 @Deprecated 1557 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1558 1559 /** 1560 * <p>Enables high quality mode for the drawing cache.</p> 1561 * 1562 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1563 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1564 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1565 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1566 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1567 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1568 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1569 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1570 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1571 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1572 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1573 * reports or unit testing the {@link PixelCopy} API is recommended. 1574 */ 1575 @Deprecated 1576 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1577 1578 /** 1579 * <p>Enables automatic quality mode for the drawing cache.</p> 1580 * 1581 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1582 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1583 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1584 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1585 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1586 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1587 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1588 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1589 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1590 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1591 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1592 * reports or unit testing the {@link PixelCopy} API is recommended. 1593 */ 1594 @Deprecated 1595 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1596 1597 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1598 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1599 }; 1600 1601 /** 1602 * <p>Mask for use with setFlags indicating bits used for the cache 1603 * quality property.</p> 1604 * {@hide} 1605 */ 1606 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1607 1608 /** 1609 * <p> 1610 * Indicates this view can be long clicked. When long clickable, a View 1611 * reacts to long clicks by notifying the OnLongClickListener or showing a 1612 * context menu. 1613 * </p> 1614 * {@hide} 1615 */ 1616 static final int LONG_CLICKABLE = 0x00200000; 1617 1618 /** 1619 * <p>Indicates that this view gets its drawable states from its direct parent 1620 * and ignores its original internal states.</p> 1621 * 1622 * @hide 1623 */ 1624 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1625 1626 /** 1627 * <p> 1628 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1629 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1630 * OnContextClickListener. 1631 * </p> 1632 * {@hide} 1633 */ 1634 static final int CONTEXT_CLICKABLE = 0x00800000; 1635 1636 /** @hide */ 1637 @IntDef(prefix = { "SCROLLBARS_" }, value = { 1638 SCROLLBARS_INSIDE_OVERLAY, 1639 SCROLLBARS_INSIDE_INSET, 1640 SCROLLBARS_OUTSIDE_OVERLAY, 1641 SCROLLBARS_OUTSIDE_INSET 1642 }) 1643 @Retention(RetentionPolicy.SOURCE) 1644 public @interface ScrollBarStyle {} 1645 1646 /** 1647 * The scrollbar style to display the scrollbars inside the content area, 1648 * without increasing the padding. The scrollbars will be overlaid with 1649 * translucency on the view's content. 1650 */ 1651 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1652 1653 /** 1654 * The scrollbar style to display the scrollbars inside the padded area, 1655 * increasing the padding of the view. The scrollbars will not overlap the 1656 * content area of the view. 1657 */ 1658 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1659 1660 /** 1661 * The scrollbar style to display the scrollbars at the edge of the view, 1662 * without increasing the padding. The scrollbars will be overlaid with 1663 * translucency. 1664 */ 1665 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1666 1667 /** 1668 * The scrollbar style to display the scrollbars at the edge of the view, 1669 * increasing the padding of the view. The scrollbars will only overlap the 1670 * background, if any. 1671 */ 1672 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1673 1674 /** 1675 * Mask to check if the scrollbar style is overlay or inset. 1676 * {@hide} 1677 */ 1678 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1679 1680 /** 1681 * Mask to check if the scrollbar style is inside or outside. 1682 * {@hide} 1683 */ 1684 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1685 1686 /** 1687 * Mask for scrollbar style. 1688 * {@hide} 1689 */ 1690 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1691 1692 /** 1693 * View flag indicating that the screen should remain on while the 1694 * window containing this view is visible to the user. This effectively 1695 * takes care of automatically setting the WindowManager's 1696 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1697 */ 1698 public static final int KEEP_SCREEN_ON = 0x04000000; 1699 1700 /** 1701 * View flag indicating whether this view should have sound effects enabled 1702 * for events such as clicking and touching. 1703 */ 1704 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1705 1706 /** 1707 * View flag indicating whether this view should have haptic feedback 1708 * enabled for events such as long presses. 1709 */ 1710 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1711 1712 /** 1713 * <p>Indicates that the view hierarchy should stop saving state when 1714 * it reaches this view. If state saving is initiated immediately at 1715 * the view, it will be allowed. 1716 * {@hide} 1717 */ 1718 static final int PARENT_SAVE_DISABLED = 0x20000000; 1719 1720 /** 1721 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1722 * {@hide} 1723 */ 1724 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1725 1726 private static Paint sDebugPaint; 1727 1728 /** 1729 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1730 * {@hide} 1731 */ 1732 static final int TOOLTIP = 0x40000000; 1733 1734 /** @hide */ 1735 @IntDef(flag = true, prefix = { "FOCUSABLES_" }, value = { 1736 FOCUSABLES_ALL, 1737 FOCUSABLES_TOUCH_MODE 1738 }) 1739 @Retention(RetentionPolicy.SOURCE) 1740 public @interface FocusableMode {} 1741 1742 /** 1743 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1744 * should add all focusable Views regardless if they are focusable in touch mode. 1745 */ 1746 public static final int FOCUSABLES_ALL = 0x00000000; 1747 1748 /** 1749 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1750 * should add only Views focusable in touch mode. 1751 */ 1752 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1753 1754 /** @hide */ 1755 @IntDef(prefix = { "FOCUS_" }, value = { 1756 FOCUS_BACKWARD, 1757 FOCUS_FORWARD, 1758 FOCUS_LEFT, 1759 FOCUS_UP, 1760 FOCUS_RIGHT, 1761 FOCUS_DOWN 1762 }) 1763 @Retention(RetentionPolicy.SOURCE) 1764 public @interface FocusDirection {} 1765 1766 /** @hide */ 1767 @IntDef(prefix = { "FOCUS_" }, value = { 1768 FOCUS_LEFT, 1769 FOCUS_UP, 1770 FOCUS_RIGHT, 1771 FOCUS_DOWN 1772 }) 1773 @Retention(RetentionPolicy.SOURCE) 1774 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1775 1776 /** 1777 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1778 * item. 1779 */ 1780 public static final int FOCUS_BACKWARD = 0x00000001; 1781 1782 /** 1783 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1784 * item. 1785 */ 1786 public static final int FOCUS_FORWARD = 0x00000002; 1787 1788 /** 1789 * Use with {@link #focusSearch(int)}. Move focus to the left. 1790 */ 1791 public static final int FOCUS_LEFT = 0x00000011; 1792 1793 /** 1794 * Use with {@link #focusSearch(int)}. Move focus up. 1795 */ 1796 public static final int FOCUS_UP = 0x00000021; 1797 1798 /** 1799 * Use with {@link #focusSearch(int)}. Move focus to the right. 1800 */ 1801 public static final int FOCUS_RIGHT = 0x00000042; 1802 1803 /** 1804 * Use with {@link #focusSearch(int)}. Move focus down. 1805 */ 1806 public static final int FOCUS_DOWN = 0x00000082; 1807 1808 /** 1809 * Bits of {@link #getMeasuredWidthAndState()} and 1810 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1811 */ 1812 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1813 1814 /** 1815 * Bits of {@link #getMeasuredWidthAndState()} and 1816 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1817 */ 1818 public static final int MEASURED_STATE_MASK = 0xff000000; 1819 1820 /** 1821 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1822 * for functions that combine both width and height into a single int, 1823 * such as {@link #getMeasuredState()} and the childState argument of 1824 * {@link #resolveSizeAndState(int, int, int)}. 1825 */ 1826 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1827 1828 /** 1829 * Bit of {@link #getMeasuredWidthAndState()} and 1830 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1831 * is smaller that the space the view would like to have. 1832 */ 1833 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1834 1835 /** 1836 * Base View state sets 1837 */ 1838 // Singles 1839 /** 1840 * Indicates the view has no states set. States are used with 1841 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1842 * view depending on its state. 1843 * 1844 * @see android.graphics.drawable.Drawable 1845 * @see #getDrawableState() 1846 */ 1847 protected static final int[] EMPTY_STATE_SET; 1848 /** 1849 * Indicates the view is enabled. States are used with 1850 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1851 * view depending on its state. 1852 * 1853 * @see android.graphics.drawable.Drawable 1854 * @see #getDrawableState() 1855 */ 1856 protected static final int[] ENABLED_STATE_SET; 1857 /** 1858 * Indicates the view is focused. States are used with 1859 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1860 * view depending on its state. 1861 * 1862 * @see android.graphics.drawable.Drawable 1863 * @see #getDrawableState() 1864 */ 1865 protected static final int[] FOCUSED_STATE_SET; 1866 /** 1867 * Indicates the view is selected. States are used with 1868 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1869 * view depending on its state. 1870 * 1871 * @see android.graphics.drawable.Drawable 1872 * @see #getDrawableState() 1873 */ 1874 protected static final int[] SELECTED_STATE_SET; 1875 /** 1876 * Indicates the view is pressed. States are used with 1877 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1878 * view depending on its state. 1879 * 1880 * @see android.graphics.drawable.Drawable 1881 * @see #getDrawableState() 1882 */ 1883 protected static final int[] PRESSED_STATE_SET; 1884 /** 1885 * Indicates the view's window has focus. States are used with 1886 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1887 * view depending on its state. 1888 * 1889 * @see android.graphics.drawable.Drawable 1890 * @see #getDrawableState() 1891 */ 1892 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1893 // Doubles 1894 /** 1895 * Indicates the view is enabled and has the focus. 1896 * 1897 * @see #ENABLED_STATE_SET 1898 * @see #FOCUSED_STATE_SET 1899 */ 1900 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1901 /** 1902 * Indicates the view is enabled and selected. 1903 * 1904 * @see #ENABLED_STATE_SET 1905 * @see #SELECTED_STATE_SET 1906 */ 1907 protected static final int[] ENABLED_SELECTED_STATE_SET; 1908 /** 1909 * Indicates the view is enabled and that its window has focus. 1910 * 1911 * @see #ENABLED_STATE_SET 1912 * @see #WINDOW_FOCUSED_STATE_SET 1913 */ 1914 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1915 /** 1916 * Indicates the view is focused and selected. 1917 * 1918 * @see #FOCUSED_STATE_SET 1919 * @see #SELECTED_STATE_SET 1920 */ 1921 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1922 /** 1923 * Indicates the view has the focus and that its window has the focus. 1924 * 1925 * @see #FOCUSED_STATE_SET 1926 * @see #WINDOW_FOCUSED_STATE_SET 1927 */ 1928 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1929 /** 1930 * Indicates the view is selected and that its window has the focus. 1931 * 1932 * @see #SELECTED_STATE_SET 1933 * @see #WINDOW_FOCUSED_STATE_SET 1934 */ 1935 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 1936 // Triples 1937 /** 1938 * Indicates the view is enabled, focused and selected. 1939 * 1940 * @see #ENABLED_STATE_SET 1941 * @see #FOCUSED_STATE_SET 1942 * @see #SELECTED_STATE_SET 1943 */ 1944 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 1945 /** 1946 * Indicates the view is enabled, focused and its window has the focus. 1947 * 1948 * @see #ENABLED_STATE_SET 1949 * @see #FOCUSED_STATE_SET 1950 * @see #WINDOW_FOCUSED_STATE_SET 1951 */ 1952 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 1953 /** 1954 * Indicates the view is enabled, selected and its window has the focus. 1955 * 1956 * @see #ENABLED_STATE_SET 1957 * @see #SELECTED_STATE_SET 1958 * @see #WINDOW_FOCUSED_STATE_SET 1959 */ 1960 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1961 /** 1962 * Indicates the view is focused, selected and its window has the focus. 1963 * 1964 * @see #FOCUSED_STATE_SET 1965 * @see #SELECTED_STATE_SET 1966 * @see #WINDOW_FOCUSED_STATE_SET 1967 */ 1968 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1969 /** 1970 * Indicates the view is enabled, focused, selected and its window 1971 * has the focus. 1972 * 1973 * @see #ENABLED_STATE_SET 1974 * @see #FOCUSED_STATE_SET 1975 * @see #SELECTED_STATE_SET 1976 * @see #WINDOW_FOCUSED_STATE_SET 1977 */ 1978 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 1979 /** 1980 * Indicates the view is pressed and its window has the focus. 1981 * 1982 * @see #PRESSED_STATE_SET 1983 * @see #WINDOW_FOCUSED_STATE_SET 1984 */ 1985 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 1986 /** 1987 * Indicates the view is pressed and selected. 1988 * 1989 * @see #PRESSED_STATE_SET 1990 * @see #SELECTED_STATE_SET 1991 */ 1992 protected static final int[] PRESSED_SELECTED_STATE_SET; 1993 /** 1994 * Indicates the view is pressed, selected and its window has the focus. 1995 * 1996 * @see #PRESSED_STATE_SET 1997 * @see #SELECTED_STATE_SET 1998 * @see #WINDOW_FOCUSED_STATE_SET 1999 */ 2000 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2001 /** 2002 * Indicates the view is pressed and focused. 2003 * 2004 * @see #PRESSED_STATE_SET 2005 * @see #FOCUSED_STATE_SET 2006 */ 2007 protected static final int[] PRESSED_FOCUSED_STATE_SET; 2008 /** 2009 * Indicates the view is pressed, focused and its window has the focus. 2010 * 2011 * @see #PRESSED_STATE_SET 2012 * @see #FOCUSED_STATE_SET 2013 * @see #WINDOW_FOCUSED_STATE_SET 2014 */ 2015 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2016 /** 2017 * Indicates the view is pressed, focused and selected. 2018 * 2019 * @see #PRESSED_STATE_SET 2020 * @see #SELECTED_STATE_SET 2021 * @see #FOCUSED_STATE_SET 2022 */ 2023 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 2024 /** 2025 * Indicates the view is pressed, focused, selected and its window has the focus. 2026 * 2027 * @see #PRESSED_STATE_SET 2028 * @see #FOCUSED_STATE_SET 2029 * @see #SELECTED_STATE_SET 2030 * @see #WINDOW_FOCUSED_STATE_SET 2031 */ 2032 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2033 /** 2034 * Indicates the view is pressed and enabled. 2035 * 2036 * @see #PRESSED_STATE_SET 2037 * @see #ENABLED_STATE_SET 2038 */ 2039 protected static final int[] PRESSED_ENABLED_STATE_SET; 2040 /** 2041 * Indicates the view is pressed, enabled and its window has the focus. 2042 * 2043 * @see #PRESSED_STATE_SET 2044 * @see #ENABLED_STATE_SET 2045 * @see #WINDOW_FOCUSED_STATE_SET 2046 */ 2047 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 2048 /** 2049 * Indicates the view is pressed, enabled and selected. 2050 * 2051 * @see #PRESSED_STATE_SET 2052 * @see #ENABLED_STATE_SET 2053 * @see #SELECTED_STATE_SET 2054 */ 2055 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 2056 /** 2057 * Indicates the view is pressed, enabled, selected and its window has the 2058 * focus. 2059 * 2060 * @see #PRESSED_STATE_SET 2061 * @see #ENABLED_STATE_SET 2062 * @see #SELECTED_STATE_SET 2063 * @see #WINDOW_FOCUSED_STATE_SET 2064 */ 2065 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2066 /** 2067 * Indicates the view is pressed, enabled and focused. 2068 * 2069 * @see #PRESSED_STATE_SET 2070 * @see #ENABLED_STATE_SET 2071 * @see #FOCUSED_STATE_SET 2072 */ 2073 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 2074 /** 2075 * Indicates the view is pressed, enabled, focused and its window has the 2076 * focus. 2077 * 2078 * @see #PRESSED_STATE_SET 2079 * @see #ENABLED_STATE_SET 2080 * @see #FOCUSED_STATE_SET 2081 * @see #WINDOW_FOCUSED_STATE_SET 2082 */ 2083 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2084 /** 2085 * Indicates the view is pressed, enabled, focused and selected. 2086 * 2087 * @see #PRESSED_STATE_SET 2088 * @see #ENABLED_STATE_SET 2089 * @see #SELECTED_STATE_SET 2090 * @see #FOCUSED_STATE_SET 2091 */ 2092 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 2093 /** 2094 * Indicates the view is pressed, enabled, focused, selected and its window 2095 * has the focus. 2096 * 2097 * @see #PRESSED_STATE_SET 2098 * @see #ENABLED_STATE_SET 2099 * @see #SELECTED_STATE_SET 2100 * @see #FOCUSED_STATE_SET 2101 * @see #WINDOW_FOCUSED_STATE_SET 2102 */ 2103 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2104 2105 static { 2106 EMPTY_STATE_SET = StateSet.get(0); 2107 2108 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 2109 2110 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 2111 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2112 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 2113 2114 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 2115 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2116 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 2117 FOCUSED_SELECTED_STATE_SET = StateSet.get( 2118 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 2119 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2120 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2121 | StateSet.VIEW_STATE_FOCUSED); 2122 2123 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 2124 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2125 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2126 ENABLED_SELECTED_STATE_SET = StateSet.get( 2127 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 2128 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2129 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2130 | StateSet.VIEW_STATE_ENABLED); 2131 ENABLED_FOCUSED_STATE_SET = StateSet.get( 2132 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2133 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2134 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2135 | StateSet.VIEW_STATE_ENABLED); 2136 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2137 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2138 | StateSet.VIEW_STATE_ENABLED); 2139 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2140 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2141 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 2142 2143 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 2144 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2145 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2146 PRESSED_SELECTED_STATE_SET = StateSet.get( 2147 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 2148 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2149 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2150 | StateSet.VIEW_STATE_PRESSED); 2151 PRESSED_FOCUSED_STATE_SET = StateSet.get( 2152 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2153 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2154 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2155 | StateSet.VIEW_STATE_PRESSED); 2156 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2157 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2158 | StateSet.VIEW_STATE_PRESSED); 2159 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2160 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2161 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2162 PRESSED_ENABLED_STATE_SET = StateSet.get( 2163 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2164 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2165 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 2166 | StateSet.VIEW_STATE_PRESSED); 2167 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 2168 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 2169 | StateSet.VIEW_STATE_PRESSED); 2170 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2171 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2172 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2173 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 2174 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 2175 | StateSet.VIEW_STATE_PRESSED); 2176 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2177 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2178 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2179 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2180 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2181 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2182 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2183 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2184 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 2185 | StateSet.VIEW_STATE_PRESSED); 2186 } 2187 2188 /** 2189 * Accessibility event types that are dispatched for text population. 2190 */ 2191 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 2192 AccessibilityEvent.TYPE_VIEW_CLICKED 2193 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 2194 | AccessibilityEvent.TYPE_VIEW_SELECTED 2195 | AccessibilityEvent.TYPE_VIEW_FOCUSED 2196 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 2197 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 2198 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 2199 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 2200 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 2201 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 2202 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 2203 2204 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 2205 2206 static final int DEBUG_CORNERS_SIZE_DIP = 8; 2207 2208 /** 2209 * Temporary Rect currently for use in setBackground(). This will probably 2210 * be extended in the future to hold our own class with more than just 2211 * a Rect. :) 2212 */ 2213 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 2214 2215 /** 2216 * Map used to store views' tags. 2217 */ 2218 @UnsupportedAppUsage 2219 private SparseArray<Object> mKeyedTags; 2220 2221 /** 2222 * The next available accessibility id. 2223 */ 2224 private static int sNextAccessibilityViewId; 2225 2226 /** 2227 * The animation currently associated with this view. 2228 * @hide 2229 */ 2230 protected Animation mCurrentAnimation = null; 2231 2232 /** 2233 * Width as measured during measure pass. 2234 * {@hide} 2235 */ 2236 @ViewDebug.ExportedProperty(category = "measurement") 2237 @UnsupportedAppUsage 2238 int mMeasuredWidth; 2239 2240 /** 2241 * Height as measured during measure pass. 2242 * {@hide} 2243 */ 2244 @ViewDebug.ExportedProperty(category = "measurement") 2245 @UnsupportedAppUsage 2246 int mMeasuredHeight; 2247 2248 /** 2249 * Flag to indicate that this view was marked INVALIDATED, or had its display list 2250 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 2251 * its display list. This flag, used only when hw accelerated, allows us to clear the 2252 * flag while retaining this information until it's needed (at getDisplayList() time and 2253 * in drawChild(), when we decide to draw a view's children's display lists into our own). 2254 * 2255 * {@hide} 2256 */ 2257 @UnsupportedAppUsage 2258 boolean mRecreateDisplayList = false; 2259 2260 /** 2261 * The view's identifier. 2262 * {@hide} 2263 * 2264 * @see #setId(int) 2265 * @see #getId() 2266 */ 2267 @IdRes 2268 @ViewDebug.ExportedProperty(resolveId = true) 2269 int mID = NO_ID; 2270 2271 /** The ID of this view for autofill purposes. 2272 * <ul> 2273 * <li>== {@link #NO_ID}: ID has not been assigned yet 2274 * <li>≤ {@link #LAST_APP_AUTOFILL_ID}: View is not part of a activity. The ID is 2275 * unique in the process. This might change 2276 * over activity lifecycle events. 2277 * <li>> {@link #LAST_APP_AUTOFILL_ID}: View is part of a activity. The ID is 2278 * unique in the activity. This stays the same 2279 * over activity lifecycle events. 2280 */ 2281 private int mAutofillViewId = NO_ID; 2282 2283 // ID for accessibility purposes. This ID must be unique for every window 2284 @UnsupportedAppUsage 2285 private int mAccessibilityViewId = NO_ID; 2286 2287 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2288 2289 /** 2290 * The view's tag. 2291 * {@hide} 2292 * 2293 * @see #setTag(Object) 2294 * @see #getTag() 2295 */ 2296 @UnsupportedAppUsage 2297 protected Object mTag = null; 2298 2299 /* 2300 * Masks for mPrivateFlags, as generated by dumpFlags(): 2301 * 2302 * |-------|-------|-------|-------| 2303 * 1 PFLAG_WANTS_FOCUS 2304 * 1 PFLAG_FOCUSED 2305 * 1 PFLAG_SELECTED 2306 * 1 PFLAG_IS_ROOT_NAMESPACE 2307 * 1 PFLAG_HAS_BOUNDS 2308 * 1 PFLAG_DRAWN 2309 * 1 PFLAG_DRAW_ANIMATION 2310 * 1 PFLAG_SKIP_DRAW 2311 * 1 PFLAG_REQUEST_TRANSPARENT_REGIONS 2312 * 1 PFLAG_DRAWABLE_STATE_DIRTY 2313 * 1 PFLAG_MEASURED_DIMENSION_SET 2314 * 1 PFLAG_FORCE_LAYOUT 2315 * 1 PFLAG_LAYOUT_REQUIRED 2316 * 1 PFLAG_PRESSED 2317 * 1 PFLAG_DRAWING_CACHE_VALID 2318 * 1 PFLAG_ANIMATION_STARTED 2319 * 1 PFLAG_SAVE_STATE_CALLED 2320 * 1 PFLAG_ALPHA_SET 2321 * 1 PFLAG_SCROLL_CONTAINER 2322 * 1 PFLAG_SCROLL_CONTAINER_ADDED 2323 * 1 PFLAG_DIRTY 2324 * 1 PFLAG_DIRTY_MASK 2325 * 1 PFLAG_OPAQUE_BACKGROUND 2326 * 1 PFLAG_OPAQUE_SCROLLBARS 2327 * 11 PFLAG_OPAQUE_MASK 2328 * 1 PFLAG_PREPRESSED 2329 * 1 PFLAG_CANCEL_NEXT_UP_EVENT 2330 * 1 PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH 2331 * 1 PFLAG_HOVERED 2332 * 1 PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK 2333 * 1 PFLAG_ACTIVATED 2334 * 1 PFLAG_INVALIDATED 2335 * |-------|-------|-------|-------| 2336 */ 2337 /** {@hide} */ 2338 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2339 /** {@hide} */ 2340 static final int PFLAG_FOCUSED = 0x00000002; 2341 /** {@hide} */ 2342 static final int PFLAG_SELECTED = 0x00000004; 2343 /** {@hide} */ 2344 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2345 /** {@hide} */ 2346 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2347 /** {@hide} */ 2348 static final int PFLAG_DRAWN = 0x00000020; 2349 /** 2350 * When this flag is set, this view is running an animation on behalf of its 2351 * children and should therefore not cancel invalidate requests, even if they 2352 * lie outside of this view's bounds. 2353 * 2354 * {@hide} 2355 */ 2356 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2357 /** {@hide} */ 2358 static final int PFLAG_SKIP_DRAW = 0x00000080; 2359 /** {@hide} */ 2360 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2361 /** {@hide} */ 2362 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2363 /** {@hide} */ 2364 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2365 /** {@hide} */ 2366 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2367 /** {@hide} */ 2368 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2369 2370 private static final int PFLAG_PRESSED = 0x00004000; 2371 2372 /** {@hide} */ 2373 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2374 /** 2375 * Flag used to indicate that this view should be drawn once more (and only once 2376 * more) after its animation has completed. 2377 * {@hide} 2378 */ 2379 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2380 2381 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2382 2383 /** 2384 * Indicates that the View returned true when onSetAlpha() was called and that 2385 * the alpha must be restored. 2386 * {@hide} 2387 */ 2388 static final int PFLAG_ALPHA_SET = 0x00040000; 2389 2390 /** 2391 * Set by {@link #setScrollContainer(boolean)}. 2392 */ 2393 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2394 2395 /** 2396 * Set by {@link #setScrollContainer(boolean)}. 2397 */ 2398 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2399 2400 /** 2401 * View flag indicating whether this view was invalidated (fully or partially.) 2402 * 2403 * @hide 2404 */ 2405 static final int PFLAG_DIRTY = 0x00200000; 2406 2407 /** 2408 * Mask for {@link #PFLAG_DIRTY}. 2409 * 2410 * @hide 2411 */ 2412 static final int PFLAG_DIRTY_MASK = 0x00200000; 2413 2414 /** 2415 * Indicates whether the background is opaque. 2416 * 2417 * @hide 2418 */ 2419 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2420 2421 /** 2422 * Indicates whether the scrollbars are opaque. 2423 * 2424 * @hide 2425 */ 2426 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2427 2428 /** 2429 * Indicates whether the view is opaque. 2430 * 2431 * @hide 2432 */ 2433 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2434 2435 /** 2436 * Indicates a prepressed state; 2437 * the short time between ACTION_DOWN and recognizing 2438 * a 'real' press. Prepressed is used to recognize quick taps 2439 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2440 * 2441 * @hide 2442 */ 2443 private static final int PFLAG_PREPRESSED = 0x02000000; 2444 2445 /** 2446 * Indicates whether the view is temporarily detached. 2447 * 2448 * @hide 2449 */ 2450 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2451 2452 /** 2453 * Indicates that we should awaken scroll bars once attached 2454 * 2455 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2456 * during window attachment and it is no longer needed. Feel free to repurpose it. 2457 * 2458 * @hide 2459 */ 2460 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2461 2462 /** 2463 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2464 * @hide 2465 */ 2466 private static final int PFLAG_HOVERED = 0x10000000; 2467 2468 /** 2469 * Flag set by {@link AutofillManager} if it needs to be notified when this view is clicked. 2470 */ 2471 private static final int PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK = 0x20000000; 2472 2473 /** {@hide} */ 2474 static final int PFLAG_ACTIVATED = 0x40000000; 2475 2476 /** 2477 * Indicates that this view was specifically invalidated, not just dirtied because some 2478 * child view was invalidated. The flag is used to determine when we need to recreate 2479 * a view's display list (as opposed to just returning a reference to its existing 2480 * display list). 2481 * 2482 * @hide 2483 */ 2484 static final int PFLAG_INVALIDATED = 0x80000000; 2485 2486 /* End of masks for mPrivateFlags */ 2487 2488 /* 2489 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2490 * 2491 * |-------|-------|-------|-------| 2492 * 1 PFLAG2_DRAG_CAN_ACCEPT 2493 * 1 PFLAG2_DRAG_HOVERED 2494 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2495 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2496 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2497 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2498 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2499 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2500 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2501 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2502 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2503 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2504 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2505 * 111 PFLAG2_TEXT_DIRECTION_MASK 2506 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2507 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2508 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2509 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2510 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2511 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2512 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2513 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2514 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2515 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2516 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2517 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2518 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2519 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2520 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2521 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2522 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2523 * 1 PFLAG2_VIEW_QUICK_REJECTED 2524 * 1 PFLAG2_PADDING_RESOLVED 2525 * 1 PFLAG2_DRAWABLE_RESOLVED 2526 * 1 PFLAG2_HAS_TRANSIENT_STATE 2527 * |-------|-------|-------|-------| 2528 */ 2529 2530 /** 2531 * Indicates that this view has reported that it can accept the current drag's content. 2532 * Cleared when the drag operation concludes. 2533 * @hide 2534 */ 2535 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2536 2537 /** 2538 * Indicates that this view is currently directly under the drag location in a 2539 * drag-and-drop operation involving content that it can accept. Cleared when 2540 * the drag exits the view, or when the drag operation concludes. 2541 * @hide 2542 */ 2543 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2544 2545 /** @hide */ 2546 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2547 LAYOUT_DIRECTION_LTR, 2548 LAYOUT_DIRECTION_RTL, 2549 LAYOUT_DIRECTION_INHERIT, 2550 LAYOUT_DIRECTION_LOCALE 2551 }) 2552 @Retention(RetentionPolicy.SOURCE) 2553 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2554 public @interface LayoutDir {} 2555 2556 /** @hide */ 2557 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2558 LAYOUT_DIRECTION_LTR, 2559 LAYOUT_DIRECTION_RTL 2560 }) 2561 @Retention(RetentionPolicy.SOURCE) 2562 public @interface ResolvedLayoutDir {} 2563 2564 /** 2565 * A flag to indicate that the layout direction of this view has not been defined yet. 2566 * @hide 2567 */ 2568 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2569 2570 /** 2571 * Horizontal layout direction of this view is from Left to Right. 2572 * Use with {@link #setLayoutDirection}. 2573 */ 2574 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2575 2576 /** 2577 * Horizontal layout direction of this view is from Right to Left. 2578 * Use with {@link #setLayoutDirection}. 2579 */ 2580 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2581 2582 /** 2583 * Horizontal layout direction of this view is inherited from its parent. 2584 * Use with {@link #setLayoutDirection}. 2585 */ 2586 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2587 2588 /** 2589 * Horizontal layout direction of this view is from deduced from the default language 2590 * script for the locale. Use with {@link #setLayoutDirection}. 2591 */ 2592 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2593 2594 /** 2595 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2596 * @hide 2597 */ 2598 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2599 2600 /** 2601 * Mask for use with private flags indicating bits used for horizontal layout direction. 2602 * @hide 2603 */ 2604 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2605 2606 /** 2607 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2608 * right-to-left direction. 2609 * @hide 2610 */ 2611 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2612 2613 /** 2614 * Indicates whether the view horizontal layout direction has been resolved. 2615 * @hide 2616 */ 2617 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2618 2619 /** 2620 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2621 * @hide 2622 */ 2623 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2624 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2625 2626 /* 2627 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2628 * flag value. 2629 * @hide 2630 */ 2631 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2632 LAYOUT_DIRECTION_LTR, 2633 LAYOUT_DIRECTION_RTL, 2634 LAYOUT_DIRECTION_INHERIT, 2635 LAYOUT_DIRECTION_LOCALE 2636 }; 2637 2638 /** 2639 * Default horizontal layout direction. 2640 */ 2641 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2642 2643 /** 2644 * Default horizontal layout direction. 2645 * @hide 2646 */ 2647 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2648 2649 /** 2650 * Text direction is inherited through {@link ViewGroup} 2651 */ 2652 public static final int TEXT_DIRECTION_INHERIT = 0; 2653 2654 /** 2655 * Text direction is using "first strong algorithm". The first strong directional character 2656 * determines the paragraph direction. If there is no strong directional character, the 2657 * paragraph direction is the view's resolved layout direction. 2658 */ 2659 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2660 2661 /** 2662 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2663 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2664 * If there are neither, the paragraph direction is the view's resolved layout direction. 2665 */ 2666 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2667 2668 /** 2669 * Text direction is forced to LTR. 2670 */ 2671 public static final int TEXT_DIRECTION_LTR = 3; 2672 2673 /** 2674 * Text direction is forced to RTL. 2675 */ 2676 public static final int TEXT_DIRECTION_RTL = 4; 2677 2678 /** 2679 * Text direction is coming from the system Locale. 2680 */ 2681 public static final int TEXT_DIRECTION_LOCALE = 5; 2682 2683 /** 2684 * Text direction is using "first strong algorithm". The first strong directional character 2685 * determines the paragraph direction. If there is no strong directional character, the 2686 * paragraph direction is LTR. 2687 */ 2688 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2689 2690 /** 2691 * Text direction is using "first strong algorithm". The first strong directional character 2692 * determines the paragraph direction. If there is no strong directional character, the 2693 * paragraph direction is RTL. 2694 */ 2695 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2696 2697 /** 2698 * Default text direction is inherited 2699 */ 2700 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2701 2702 /** 2703 * Default resolved text direction 2704 * @hide 2705 */ 2706 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2707 2708 /** 2709 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2710 * @hide 2711 */ 2712 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2713 2714 /** 2715 * Mask for use with private flags indicating bits used for text direction. 2716 * @hide 2717 */ 2718 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2719 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2720 2721 /** 2722 * Array of text direction flags for mapping attribute "textDirection" to correct 2723 * flag value. 2724 * @hide 2725 */ 2726 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2727 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2728 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2729 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2730 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2731 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2732 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2733 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2734 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2735 }; 2736 2737 /** 2738 * Indicates whether the view text direction has been resolved. 2739 * @hide 2740 */ 2741 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2742 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2743 2744 /** 2745 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2746 * @hide 2747 */ 2748 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2749 2750 /** 2751 * Mask for use with private flags indicating bits used for resolved text direction. 2752 * @hide 2753 */ 2754 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2755 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2756 2757 /** 2758 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2759 * @hide 2760 */ 2761 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2762 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2763 2764 /** @hide */ 2765 @IntDef(prefix = { "TEXT_ALIGNMENT_" }, value = { 2766 TEXT_ALIGNMENT_INHERIT, 2767 TEXT_ALIGNMENT_GRAVITY, 2768 TEXT_ALIGNMENT_CENTER, 2769 TEXT_ALIGNMENT_TEXT_START, 2770 TEXT_ALIGNMENT_TEXT_END, 2771 TEXT_ALIGNMENT_VIEW_START, 2772 TEXT_ALIGNMENT_VIEW_END 2773 }) 2774 @Retention(RetentionPolicy.SOURCE) 2775 public @interface TextAlignment {} 2776 2777 /** 2778 * Default text alignment. The text alignment of this View is inherited from its parent. 2779 * Use with {@link #setTextAlignment(int)} 2780 */ 2781 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2782 2783 /** 2784 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2785 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph’s text direction. 2786 * 2787 * Use with {@link #setTextAlignment(int)} 2788 */ 2789 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2790 2791 /** 2792 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2793 * 2794 * Use with {@link #setTextAlignment(int)} 2795 */ 2796 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2797 2798 /** 2799 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2800 * 2801 * Use with {@link #setTextAlignment(int)} 2802 */ 2803 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2804 2805 /** 2806 * Center the paragraph, e.g. ALIGN_CENTER. 2807 * 2808 * Use with {@link #setTextAlignment(int)} 2809 */ 2810 public static final int TEXT_ALIGNMENT_CENTER = 4; 2811 2812 /** 2813 * Align to the start of the view, which is ALIGN_LEFT if the view’s resolved 2814 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2815 * 2816 * Use with {@link #setTextAlignment(int)} 2817 */ 2818 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2819 2820 /** 2821 * Align to the end of the view, which is ALIGN_RIGHT if the view’s resolved 2822 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2823 * 2824 * Use with {@link #setTextAlignment(int)} 2825 */ 2826 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2827 2828 /** 2829 * Default text alignment is inherited 2830 */ 2831 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2832 2833 /** 2834 * Default resolved text alignment 2835 * @hide 2836 */ 2837 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2838 2839 /** 2840 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2841 * @hide 2842 */ 2843 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2844 2845 /** 2846 * Mask for use with private flags indicating bits used for text alignment. 2847 * @hide 2848 */ 2849 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2850 2851 /** 2852 * Array of text direction flags for mapping attribute "textAlignment" to correct 2853 * flag value. 2854 * @hide 2855 */ 2856 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2857 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2858 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2859 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2860 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2861 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2862 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2863 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2864 }; 2865 2866 /** 2867 * Indicates whether the view text alignment has been resolved. 2868 * @hide 2869 */ 2870 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2871 2872 /** 2873 * Bit shift to get the resolved text alignment. 2874 * @hide 2875 */ 2876 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2877 2878 /** 2879 * Mask for use with private flags indicating bits used for text alignment. 2880 * @hide 2881 */ 2882 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2883 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2884 2885 /** 2886 * Indicates whether if the view text alignment has been resolved to gravity 2887 */ 2888 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2889 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2890 2891 // Accessiblity constants for mPrivateFlags2 2892 2893 /** 2894 * Shift for the bits in {@link #mPrivateFlags2} related to the 2895 * "importantForAccessibility" attribute. 2896 */ 2897 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2898 2899 /** 2900 * Automatically determine whether a view is important for accessibility. 2901 */ 2902 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2903 2904 /** 2905 * The view is important for accessibility. 2906 */ 2907 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2908 2909 /** 2910 * The view is not important for accessibility. 2911 */ 2912 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2913 2914 /** 2915 * The view is not important for accessibility, nor are any of its 2916 * descendant views. 2917 */ 2918 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 2919 2920 /** 2921 * The default whether the view is important for accessibility. 2922 */ 2923 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2924 2925 /** 2926 * Mask for obtaining the bits which specify how to determine 2927 * whether a view is important for accessibility. 2928 */ 2929 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2930 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 2931 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 2932 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 2933 2934 /** 2935 * Shift for the bits in {@link #mPrivateFlags2} related to the 2936 * "accessibilityLiveRegion" attribute. 2937 */ 2938 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 2939 2940 /** 2941 * Live region mode specifying that accessibility services should not 2942 * automatically announce changes to this view. This is the default live 2943 * region mode for most views. 2944 * <p> 2945 * Use with {@link #setAccessibilityLiveRegion(int)}. 2946 */ 2947 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 2948 2949 /** 2950 * Live region mode specifying that accessibility services should announce 2951 * changes to this view. 2952 * <p> 2953 * Use with {@link #setAccessibilityLiveRegion(int)}. 2954 */ 2955 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 2956 2957 /** 2958 * Live region mode specifying that accessibility services should interrupt 2959 * ongoing speech to immediately announce changes to this view. 2960 * <p> 2961 * Use with {@link #setAccessibilityLiveRegion(int)}. 2962 */ 2963 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 2964 2965 /** 2966 * The default whether the view is important for accessibility. 2967 */ 2968 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 2969 2970 /** 2971 * Mask for obtaining the bits which specify a view's accessibility live 2972 * region mode. 2973 */ 2974 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 2975 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 2976 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 2977 2978 /** 2979 * Flag indicating whether a view has accessibility focus. 2980 */ 2981 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 2982 2983 /** 2984 * Flag whether the accessibility state of the subtree rooted at this view changed. 2985 */ 2986 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 2987 2988 /** 2989 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 2990 * is used to check whether later changes to the view's transform should invalidate the 2991 * view to force the quickReject test to run again. 2992 */ 2993 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 2994 2995 /** 2996 * Flag indicating that start/end padding has been resolved into left/right padding 2997 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 2998 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 2999 * during measurement. In some special cases this is required such as when an adapter-based 3000 * view measures prospective children without attaching them to a window. 3001 */ 3002 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 3003 3004 /** 3005 * Flag indicating that the start/end drawables has been resolved into left/right ones. 3006 */ 3007 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 3008 3009 /** 3010 * Indicates that the view is tracking some sort of transient state 3011 * that the app should not need to be aware of, but that the framework 3012 * should take special care to preserve. 3013 */ 3014 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 3015 3016 /** 3017 * Group of bits indicating that RTL properties resolution is done. 3018 */ 3019 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 3020 PFLAG2_TEXT_DIRECTION_RESOLVED | 3021 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 3022 PFLAG2_PADDING_RESOLVED | 3023 PFLAG2_DRAWABLE_RESOLVED; 3024 3025 // There are a couple of flags left in mPrivateFlags2 3026 3027 /* End of masks for mPrivateFlags2 */ 3028 3029 /* 3030 * Masks for mPrivateFlags3, as generated by dumpFlags(): 3031 * 3032 * |-------|-------|-------|-------| 3033 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 3034 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 3035 * 1 PFLAG3_IS_LAID_OUT 3036 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 3037 * 1 PFLAG3_CALLED_SUPER 3038 * 1 PFLAG3_APPLYING_INSETS 3039 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 3040 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 3041 * 1 PFLAG3_SCROLL_INDICATOR_TOP 3042 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 3043 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 3044 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 3045 * 1 PFLAG3_SCROLL_INDICATOR_START 3046 * 1 PFLAG3_SCROLL_INDICATOR_END 3047 * 1 PFLAG3_ASSIST_BLOCKED 3048 * 1 PFLAG3_CLUSTER 3049 * 1 PFLAG3_IS_AUTOFILLED 3050 * 1 PFLAG3_FINGER_DOWN 3051 * 1 PFLAG3_FOCUSED_BY_DEFAULT 3052 * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL 3053 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 3054 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 3055 * 1 PFLAG3_TEMPORARY_DETACH 3056 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 3057 * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT 3058 * 1 PFLAG3_SCREEN_READER_FOCUSABLE 3059 * 1 PFLAG3_AGGREGATED_VISIBLE 3060 * 1 PFLAG3_AUTOFILLID_EXPLICITLY_SET 3061 * 1 PFLAG3_ACCESSIBILITY_HEADING 3062 * |-------|-------|-------|-------| 3063 */ 3064 3065 /** 3066 * Flag indicating that view has a transform animation set on it. This is used to track whether 3067 * an animation is cleared between successive frames, in order to tell the associated 3068 * DisplayList to clear its animation matrix. 3069 */ 3070 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 3071 3072 /** 3073 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 3074 * animation is cleared between successive frames, in order to tell the associated 3075 * DisplayList to restore its alpha value. 3076 */ 3077 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 3078 3079 /** 3080 * Flag indicating that the view has been through at least one layout since it 3081 * was last attached to a window. 3082 */ 3083 static final int PFLAG3_IS_LAID_OUT = 0x4; 3084 3085 /** 3086 * Flag indicating that a call to measure() was skipped and should be done 3087 * instead when layout() is invoked. 3088 */ 3089 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 3090 3091 /** 3092 * Flag indicating that an overridden method correctly called down to 3093 * the superclass implementation as required by the API spec. 3094 */ 3095 static final int PFLAG3_CALLED_SUPER = 0x10; 3096 3097 /** 3098 * Flag indicating that we're in the process of applying window insets. 3099 */ 3100 static final int PFLAG3_APPLYING_INSETS = 0x20; 3101 3102 /** 3103 * Flag indicating that we're in the process of fitting system windows using the old method. 3104 */ 3105 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 3106 3107 /** 3108 * Flag indicating that nested scrolling is enabled for this view. 3109 * The view will optionally cooperate with views up its parent chain to allow for 3110 * integrated nested scrolling along the same axis. 3111 */ 3112 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 3113 3114 /** 3115 * Flag indicating that the bottom scroll indicator should be displayed 3116 * when this view can scroll up. 3117 */ 3118 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 3119 3120 /** 3121 * Flag indicating that the bottom scroll indicator should be displayed 3122 * when this view can scroll down. 3123 */ 3124 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 3125 3126 /** 3127 * Flag indicating that the left scroll indicator should be displayed 3128 * when this view can scroll left. 3129 */ 3130 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 3131 3132 /** 3133 * Flag indicating that the right scroll indicator should be displayed 3134 * when this view can scroll right. 3135 */ 3136 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 3137 3138 /** 3139 * Flag indicating that the start scroll indicator should be displayed 3140 * when this view can scroll in the start direction. 3141 */ 3142 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 3143 3144 /** 3145 * Flag indicating that the end scroll indicator should be displayed 3146 * when this view can scroll in the end direction. 3147 */ 3148 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 3149 3150 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 3151 3152 static final int SCROLL_INDICATORS_NONE = 0x0000; 3153 3154 /** 3155 * Mask for use with setFlags indicating bits used for indicating which 3156 * scroll indicators are enabled. 3157 */ 3158 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 3159 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 3160 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 3161 | PFLAG3_SCROLL_INDICATOR_END; 3162 3163 /** 3164 * Left-shift required to translate between public scroll indicator flags 3165 * and internal PFLAGS3 flags. When used as a right-shift, translates 3166 * PFLAGS3 flags to public flags. 3167 */ 3168 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 3169 3170 /** @hide */ 3171 @Retention(RetentionPolicy.SOURCE) 3172 @IntDef(flag = true, prefix = { "SCROLL_INDICATOR_" }, value = { 3173 SCROLL_INDICATOR_TOP, 3174 SCROLL_INDICATOR_BOTTOM, 3175 SCROLL_INDICATOR_LEFT, 3176 SCROLL_INDICATOR_RIGHT, 3177 SCROLL_INDICATOR_START, 3178 SCROLL_INDICATOR_END, 3179 }) 3180 public @interface ScrollIndicators {} 3181 3182 /** 3183 * Scroll indicator direction for the top edge of the view. 3184 * 3185 * @see #setScrollIndicators(int) 3186 * @see #setScrollIndicators(int, int) 3187 * @see #getScrollIndicators() 3188 */ 3189 public static final int SCROLL_INDICATOR_TOP = 3190 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3191 3192 /** 3193 * Scroll indicator direction for the bottom edge of the view. 3194 * 3195 * @see #setScrollIndicators(int) 3196 * @see #setScrollIndicators(int, int) 3197 * @see #getScrollIndicators() 3198 */ 3199 public static final int SCROLL_INDICATOR_BOTTOM = 3200 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3201 3202 /** 3203 * Scroll indicator direction for the left edge of the view. 3204 * 3205 * @see #setScrollIndicators(int) 3206 * @see #setScrollIndicators(int, int) 3207 * @see #getScrollIndicators() 3208 */ 3209 public static final int SCROLL_INDICATOR_LEFT = 3210 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3211 3212 /** 3213 * Scroll indicator direction for the right edge of the view. 3214 * 3215 * @see #setScrollIndicators(int) 3216 * @see #setScrollIndicators(int, int) 3217 * @see #getScrollIndicators() 3218 */ 3219 public static final int SCROLL_INDICATOR_RIGHT = 3220 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3221 3222 /** 3223 * Scroll indicator direction for the starting edge of the view. 3224 * <p> 3225 * Resolved according to the view's layout direction, see 3226 * {@link #getLayoutDirection()} for more information. 3227 * 3228 * @see #setScrollIndicators(int) 3229 * @see #setScrollIndicators(int, int) 3230 * @see #getScrollIndicators() 3231 */ 3232 public static final int SCROLL_INDICATOR_START = 3233 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3234 3235 /** 3236 * Scroll indicator direction for the ending edge of the view. 3237 * <p> 3238 * Resolved according to the view's layout direction, see 3239 * {@link #getLayoutDirection()} for more information. 3240 * 3241 * @see #setScrollIndicators(int) 3242 * @see #setScrollIndicators(int, int) 3243 * @see #getScrollIndicators() 3244 */ 3245 public static final int SCROLL_INDICATOR_END = 3246 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3247 3248 /** 3249 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 3250 * into this view.<p> 3251 */ 3252 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 3253 3254 /** 3255 * Flag indicating that the view is a root of a keyboard navigation cluster. 3256 * 3257 * @see #isKeyboardNavigationCluster() 3258 * @see #setKeyboardNavigationCluster(boolean) 3259 */ 3260 private static final int PFLAG3_CLUSTER = 0x8000; 3261 3262 /** 3263 * Flag indicating that the view is autofilled 3264 * 3265 * @see #isAutofilled() 3266 * @see #setAutofilled(boolean) 3267 */ 3268 private static final int PFLAG3_IS_AUTOFILLED = 0x10000; 3269 3270 /** 3271 * Indicates that the user is currently touching the screen. 3272 * Currently used for the tooltip positioning only. 3273 */ 3274 private static final int PFLAG3_FINGER_DOWN = 0x20000; 3275 3276 /** 3277 * Flag indicating that this view is the default-focus view. 3278 * 3279 * @see #isFocusedByDefault() 3280 * @see #setFocusedByDefault(boolean) 3281 */ 3282 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 3283 3284 /** 3285 * Shift for the bits in {@link #mPrivateFlags3} related to the 3286 * "importantForAutofill" attribute. 3287 */ 3288 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19; 3289 3290 /** 3291 * Mask for obtaining the bits which specify how to determine 3292 * whether a view is important for autofill. 3293 */ 3294 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 3295 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO 3296 | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 3297 | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS) 3298 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 3299 3300 /** 3301 * Whether this view has rendered elements that overlap (see {@link 3302 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 3303 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 3304 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 3305 * determined by whatever {@link #hasOverlappingRendering()} returns. 3306 */ 3307 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 3308 3309 /** 3310 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 3311 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 3312 */ 3313 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 3314 3315 /** 3316 * Flag indicating that the view is temporarily detached from the parent view. 3317 * 3318 * @see #onStartTemporaryDetach() 3319 * @see #onFinishTemporaryDetach() 3320 */ 3321 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3322 3323 /** 3324 * Flag indicating that the view does not wish to be revealed within its parent 3325 * hierarchy when it gains focus. Expressed in the negative since the historical 3326 * default behavior is to reveal on focus; this flag suppresses that behavior. 3327 * 3328 * @see #setRevealOnFocusHint(boolean) 3329 * @see #getRevealOnFocusHint() 3330 */ 3331 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3332 3333 /** 3334 * Flag indicating that when layout is completed we should notify 3335 * that the view was entered for autofill purposes. To minimize 3336 * showing autofill for views not visible to the user we evaluate 3337 * user visibility which cannot be done until the view is laid out. 3338 */ 3339 static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000; 3340 3341 /** 3342 * Works like focusable for screen readers, but without the side effects on input focus. 3343 * @see #setScreenReaderFocusable(boolean) 3344 */ 3345 private static final int PFLAG3_SCREEN_READER_FOCUSABLE = 0x10000000; 3346 3347 /** 3348 * The last aggregated visibility. Used to detect when it truly changes. 3349 */ 3350 private static final int PFLAG3_AGGREGATED_VISIBLE = 0x20000000; 3351 3352 /** 3353 * Used to indicate that {@link #mAutofillId} was explicitly set through 3354 * {@link #setAutofillId(AutofillId)}. 3355 */ 3356 private static final int PFLAG3_AUTOFILLID_EXPLICITLY_SET = 0x40000000; 3357 3358 /** 3359 * Indicates if the View is a heading for accessibility purposes 3360 */ 3361 private static final int PFLAG3_ACCESSIBILITY_HEADING = 0x80000000; 3362 3363 /* End of masks for mPrivateFlags3 */ 3364 3365 /** @hide */ 3366 protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0; 3367 /** @hide */ 3368 protected static final int VIEW_STRUCTURE_FOR_AUTOFILL = 1; 3369 /** @hide */ 3370 protected static final int VIEW_STRUCTURE_FOR_CONTENT_CAPTURE = 2; 3371 3372 /** @hide */ 3373 @IntDef(flag = true, prefix = { "VIEW_STRUCTURE_FOR" }, value = { 3374 VIEW_STRUCTURE_FOR_ASSIST, 3375 VIEW_STRUCTURE_FOR_AUTOFILL, 3376 VIEW_STRUCTURE_FOR_CONTENT_CAPTURE 3377 }) 3378 @Retention(RetentionPolicy.SOURCE) 3379 public @interface ViewStructureType {} 3380 3381 /** 3382 * Always allow a user to over-scroll this view, provided it is a 3383 * view that can scroll. 3384 * 3385 * @see #getOverScrollMode() 3386 * @see #setOverScrollMode(int) 3387 */ 3388 public static final int OVER_SCROLL_ALWAYS = 0; 3389 3390 /** 3391 * Allow a user to over-scroll this view only if the content is large 3392 * enough to meaningfully scroll, provided it is a view that can scroll. 3393 * 3394 * @see #getOverScrollMode() 3395 * @see #setOverScrollMode(int) 3396 */ 3397 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 3398 3399 /** 3400 * Never allow a user to over-scroll this view. 3401 * 3402 * @see #getOverScrollMode() 3403 * @see #setOverScrollMode(int) 3404 */ 3405 public static final int OVER_SCROLL_NEVER = 2; 3406 3407 /** 3408 * Special constant for {@link #setSystemUiVisibility(int)}: View has 3409 * requested the system UI (status bar) to be visible (the default). 3410 * 3411 * @see #setSystemUiVisibility(int) 3412 */ 3413 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 3414 3415 /** 3416 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 3417 * system UI to enter an unobtrusive "low profile" mode. 3418 * 3419 * <p>This is for use in games, book readers, video players, or any other 3420 * "immersive" application where the usual system chrome is deemed too distracting. 3421 * 3422 * <p>In low profile mode, the status bar and/or navigation icons may dim. 3423 * 3424 * @see #setSystemUiVisibility(int) 3425 */ 3426 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 3427 3428 /** 3429 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 3430 * system navigation be temporarily hidden. 3431 * 3432 * <p>This is an even less obtrusive state than that called for by 3433 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 3434 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 3435 * those to disappear. This is useful (in conjunction with the 3436 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 3437 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 3438 * window flags) for displaying content using every last pixel on the display. 3439 * 3440 * <p>There is a limitation: because navigation controls are so important, the least user 3441 * interaction will cause them to reappear immediately. When this happens, both 3442 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 3443 * so that both elements reappear at the same time. 3444 * 3445 * @see #setSystemUiVisibility(int) 3446 */ 3447 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 3448 3449 /** 3450 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 3451 * into the normal fullscreen mode so that its content can take over the screen 3452 * while still allowing the user to interact with the application. 3453 * 3454 * <p>This has the same visual effect as 3455 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 3456 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 3457 * meaning that non-critical screen decorations (such as the status bar) will be 3458 * hidden while the user is in the View's window, focusing the experience on 3459 * that content. Unlike the window flag, if you are using ActionBar in 3460 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3461 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 3462 * hide the action bar. 3463 * 3464 * <p>This approach to going fullscreen is best used over the window flag when 3465 * it is a transient state -- that is, the application does this at certain 3466 * points in its user interaction where it wants to allow the user to focus 3467 * on content, but not as a continuous state. For situations where the application 3468 * would like to simply stay full screen the entire time (such as a game that 3469 * wants to take over the screen), the 3470 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 3471 * is usually a better approach. The state set here will be removed by the system 3472 * in various situations (such as the user moving to another application) like 3473 * the other system UI states. 3474 * 3475 * <p>When using this flag, the application should provide some easy facility 3476 * for the user to go out of it. A common example would be in an e-book 3477 * reader, where tapping on the screen brings back whatever screen and UI 3478 * decorations that had been hidden while the user was immersed in reading 3479 * the book. 3480 * 3481 * @see #setSystemUiVisibility(int) 3482 */ 3483 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 3484 3485 /** 3486 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 3487 * flags, we would like a stable view of the content insets given to 3488 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 3489 * will always represent the worst case that the application can expect 3490 * as a continuous state. In the stock Android UI this is the space for 3491 * the system bar, nav bar, and status bar, but not more transient elements 3492 * such as an input method. 3493 * 3494 * The stable layout your UI sees is based on the system UI modes you can 3495 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 3496 * then you will get a stable layout for changes of the 3497 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 3498 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 3499 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 3500 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 3501 * with a stable layout. (Note that you should avoid using 3502 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 3503 * 3504 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 3505 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 3506 * then a hidden status bar will be considered a "stable" state for purposes 3507 * here. This allows your UI to continually hide the status bar, while still 3508 * using the system UI flags to hide the action bar while still retaining 3509 * a stable layout. Note that changing the window fullscreen flag will never 3510 * provide a stable layout for a clean transition. 3511 * 3512 * <p>If you are using ActionBar in 3513 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3514 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 3515 * insets it adds to those given to the application. 3516 */ 3517 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 3518 3519 /** 3520 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3521 * to be laid out as if it has requested 3522 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 3523 * allows it to avoid artifacts when switching in and out of that mode, at 3524 * the expense that some of its user interface may be covered by screen 3525 * decorations when they are shown. You can perform layout of your inner 3526 * UI elements to account for the navigation system UI through the 3527 * {@link #fitSystemWindows(Rect)} method. 3528 */ 3529 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 3530 3531 /** 3532 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3533 * to be laid out as if it has requested 3534 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 3535 * allows it to avoid artifacts when switching in and out of that mode, at 3536 * the expense that some of its user interface may be covered by screen 3537 * decorations when they are shown. You can perform layout of your inner 3538 * UI elements to account for non-fullscreen system UI through the 3539 * {@link #fitSystemWindows(Rect)} method. 3540 * 3541 * <p>Note: on displays that have a {@link DisplayCutout}, the window may still be placed 3542 * differently than if {@link #SYSTEM_UI_FLAG_FULLSCREEN} was set, if the 3543 * window's {@link WindowManager.LayoutParams#layoutInDisplayCutoutMode 3544 * layoutInDisplayCutoutMode} is 3545 * {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3546 * LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT}. To avoid this, use either of the other modes. 3547 * 3548 * @see WindowManager.LayoutParams#layoutInDisplayCutoutMode 3549 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3550 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 3551 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 3552 */ 3553 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 3554 3555 /** 3556 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3557 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 3558 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 3559 * user interaction. 3560 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 3561 * has an effect when used in combination with that flag.</p> 3562 */ 3563 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 3564 3565 /** 3566 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3567 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 3568 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 3569 * experience while also hiding the system bars. If this flag is not set, 3570 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 3571 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 3572 * if the user swipes from the top of the screen. 3573 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 3574 * system gestures, such as swiping from the top of the screen. These transient system bars 3575 * will overlay app’s content, may have some degree of transparency, and will automatically 3576 * hide after a short timeout. 3577 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 3578 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 3579 * with one or both of those flags.</p> 3580 */ 3581 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 3582 3583 /** 3584 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 3585 * is compatible with light status bar backgrounds. 3586 * 3587 * <p>For this to take effect, the window must request 3588 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3589 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3590 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 3591 * FLAG_TRANSLUCENT_STATUS}. 3592 * 3593 * @see android.R.attr#windowLightStatusBar 3594 */ 3595 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 3596 3597 /** 3598 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3599 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3600 */ 3601 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 3602 3603 /** 3604 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3605 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3606 */ 3607 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 3608 3609 /** 3610 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 3611 * that is compatible with light navigation bar backgrounds. 3612 * 3613 * <p>For this to take effect, the window must request 3614 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3615 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3616 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 3617 * FLAG_TRANSLUCENT_NAVIGATION}. 3618 * 3619 * @see android.R.attr#windowLightNavigationBar 3620 */ 3621 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 3622 3623 /** 3624 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 3625 */ 3626 @Deprecated 3627 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 3628 3629 /** 3630 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3631 */ 3632 @Deprecated 3633 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 3634 3635 /** 3636 * @hide 3637 * 3638 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3639 * out of the public fields to keep the undefined bits out of the developer's way. 3640 * 3641 * Flag to make the status bar not expandable. Unless you also 3642 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3643 */ 3644 @UnsupportedAppUsage 3645 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3646 3647 /** 3648 * @hide 3649 * 3650 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3651 * out of the public fields to keep the undefined bits out of the developer's way. 3652 * 3653 * Flag to hide notification icons and scrolling ticker text. 3654 */ 3655 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3656 3657 /** 3658 * @hide 3659 * 3660 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3661 * out of the public fields to keep the undefined bits out of the developer's way. 3662 * 3663 * Flag to disable incoming notification alerts. This will not block 3664 * icons, but it will block sound, vibrating and other visual or aural notifications. 3665 */ 3666 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3667 3668 /** 3669 * @hide 3670 * 3671 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3672 * out of the public fields to keep the undefined bits out of the developer's way. 3673 * 3674 * Flag to hide only the scrolling ticker. Note that 3675 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3676 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3677 */ 3678 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3679 3680 /** 3681 * @hide 3682 * 3683 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3684 * out of the public fields to keep the undefined bits out of the developer's way. 3685 * 3686 * Flag to hide the center system info area. 3687 */ 3688 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3689 3690 /** 3691 * @hide 3692 * 3693 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3694 * out of the public fields to keep the undefined bits out of the developer's way. 3695 * 3696 * Flag to hide only the home button. Don't use this 3697 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3698 */ 3699 @UnsupportedAppUsage 3700 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3701 3702 /** 3703 * @hide 3704 * 3705 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3706 * out of the public fields to keep the undefined bits out of the developer's way. 3707 * 3708 * Flag to hide only the back button. Don't use this 3709 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3710 */ 3711 @UnsupportedAppUsage 3712 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3713 3714 /** 3715 * @hide 3716 * 3717 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3718 * out of the public fields to keep the undefined bits out of the developer's way. 3719 * 3720 * Flag to hide only the clock. You might use this if your activity has 3721 * its own clock making the status bar's clock redundant. 3722 */ 3723 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3724 3725 /** 3726 * @hide 3727 * 3728 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3729 * out of the public fields to keep the undefined bits out of the developer's way. 3730 * 3731 * Flag to hide only the recent apps button. Don't use this 3732 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3733 */ 3734 @UnsupportedAppUsage 3735 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3736 3737 /** 3738 * @hide 3739 * 3740 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3741 * out of the public fields to keep the undefined bits out of the developer's way. 3742 * 3743 * Flag to disable the global search gesture. Don't use this 3744 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3745 */ 3746 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3747 3748 /** 3749 * @hide 3750 * 3751 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3752 * out of the public fields to keep the undefined bits out of the developer's way. 3753 * 3754 * Flag to specify that the status bar is displayed in transient mode. 3755 */ 3756 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3757 3758 /** 3759 * @hide 3760 * 3761 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3762 * out of the public fields to keep the undefined bits out of the developer's way. 3763 * 3764 * Flag to specify that the navigation bar is displayed in transient mode. 3765 */ 3766 @UnsupportedAppUsage 3767 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3768 3769 /** 3770 * @hide 3771 * 3772 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3773 * out of the public fields to keep the undefined bits out of the developer's way. 3774 * 3775 * Flag to specify that the hidden status bar would like to be shown. 3776 */ 3777 public static final int STATUS_BAR_UNHIDE = 0x10000000; 3778 3779 /** 3780 * @hide 3781 * 3782 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3783 * out of the public fields to keep the undefined bits out of the developer's way. 3784 * 3785 * Flag to specify that the hidden navigation bar would like to be shown. 3786 */ 3787 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 3788 3789 /** 3790 * @hide 3791 * 3792 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3793 * out of the public fields to keep the undefined bits out of the developer's way. 3794 * 3795 * Flag to specify that the status bar is displayed in translucent mode. 3796 */ 3797 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 3798 3799 /** 3800 * @hide 3801 * 3802 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3803 * out of the public fields to keep the undefined bits out of the developer's way. 3804 * 3805 * Flag to specify that the navigation bar is displayed in translucent mode. 3806 */ 3807 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 3808 3809 /** 3810 * @hide 3811 * 3812 * Makes navigation bar transparent (but not the status bar). 3813 */ 3814 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 3815 3816 /** 3817 * @hide 3818 * 3819 * Makes status bar transparent (but not the navigation bar). 3820 */ 3821 public static final int STATUS_BAR_TRANSPARENT = 0x00000008; 3822 3823 /** 3824 * @hide 3825 * 3826 * Makes both status bar and navigation bar transparent. 3827 */ 3828 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 3829 | STATUS_BAR_TRANSPARENT; 3830 3831 /** 3832 * @hide 3833 */ 3834 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 3835 3836 /** 3837 * These are the system UI flags that can be cleared by events outside 3838 * of an application. Currently this is just the ability to tap on the 3839 * screen while hiding the navigation bar to have it return. 3840 * @hide 3841 */ 3842 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 3843 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 3844 | SYSTEM_UI_FLAG_FULLSCREEN; 3845 3846 /** 3847 * Flags that can impact the layout in relation to system UI. 3848 */ 3849 public static final int SYSTEM_UI_LAYOUT_FLAGS = 3850 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3851 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3852 3853 /** @hide */ 3854 @IntDef(flag = true, prefix = { "FIND_VIEWS_" }, value = { 3855 FIND_VIEWS_WITH_TEXT, 3856 FIND_VIEWS_WITH_CONTENT_DESCRIPTION 3857 }) 3858 @Retention(RetentionPolicy.SOURCE) 3859 public @interface FindViewFlags {} 3860 3861 /** 3862 * Find views that render the specified text. 3863 * 3864 * @see #findViewsWithText(ArrayList, CharSequence, int) 3865 */ 3866 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 3867 3868 /** 3869 * Find find views that contain the specified content description. 3870 * 3871 * @see #findViewsWithText(ArrayList, CharSequence, int) 3872 */ 3873 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 3874 3875 /** 3876 * Find views that contain {@link AccessibilityNodeProvider}. Such 3877 * a View is a root of virtual view hierarchy and may contain the searched 3878 * text. If this flag is set Views with providers are automatically 3879 * added and it is a responsibility of the client to call the APIs of 3880 * the provider to determine whether the virtual tree rooted at this View 3881 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 3882 * representing the virtual views with this text. 3883 * 3884 * @see #findViewsWithText(ArrayList, CharSequence, int) 3885 * 3886 * @hide 3887 */ 3888 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 3889 3890 /** 3891 * The undefined cursor position. 3892 * 3893 * @hide 3894 */ 3895 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 3896 3897 /** 3898 * Indicates that the screen has changed state and is now off. 3899 * 3900 * @see #onScreenStateChanged(int) 3901 */ 3902 public static final int SCREEN_STATE_OFF = 0x0; 3903 3904 /** 3905 * Indicates that the screen has changed state and is now on. 3906 * 3907 * @see #onScreenStateChanged(int) 3908 */ 3909 public static final int SCREEN_STATE_ON = 0x1; 3910 3911 /** 3912 * Indicates no axis of view scrolling. 3913 */ 3914 public static final int SCROLL_AXIS_NONE = 0; 3915 3916 /** 3917 * Indicates scrolling along the horizontal axis. 3918 */ 3919 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 3920 3921 /** 3922 * Indicates scrolling along the vertical axis. 3923 */ 3924 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 3925 3926 /** 3927 * Controls the over-scroll mode for this view. 3928 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 3929 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 3930 * and {@link #OVER_SCROLL_NEVER}. 3931 */ 3932 private int mOverScrollMode; 3933 3934 /** 3935 * The parent this view is attached to. 3936 * {@hide} 3937 * 3938 * @see #getParent() 3939 */ 3940 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 3941 protected ViewParent mParent; 3942 3943 /** 3944 * {@hide} 3945 * 3946 * Not available for general use. If you need help, hang up and then dial one of the following 3947 * public APIs: 3948 * 3949 * @see #isAttachedToWindow() for current attach state 3950 * @see #onAttachedToWindow() for subclasses performing work when becoming attached 3951 * @see #onDetachedFromWindow() for subclasses performing work when becoming detached 3952 * @see OnAttachStateChangeListener for other code performing work on attach/detach 3953 * @see #getHandler() for posting messages to this view's UI thread/looper 3954 * @see #getParent() for interacting with the parent chain 3955 * @see #getWindowToken() for the current window token 3956 * @see #getRootView() for the view at the root of the attached hierarchy 3957 * @see #getDisplay() for the Display this view is presented on 3958 * @see #getRootWindowInsets() for the current insets applied to the whole attached window 3959 * @see #hasWindowFocus() for whether the attached window is currently focused 3960 * @see #getWindowVisibility() for checking the visibility of the attached window 3961 */ 3962 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 3963 AttachInfo mAttachInfo; 3964 3965 /** 3966 * {@hide} 3967 */ 3968 @ViewDebug.ExportedProperty(flagMapping = { 3969 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 3970 name = "FORCE_LAYOUT"), 3971 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 3972 name = "LAYOUT_REQUIRED"), 3973 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 3974 name = "DRAWING_CACHE_INVALID", outputIf = false), 3975 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 3976 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 3977 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 3978 }, formatToHexString = true) 3979 3980 /* @hide */ 3981 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769414) 3982 public int mPrivateFlags; 3983 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768943) 3984 int mPrivateFlags2; 3985 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 129147060) 3986 int mPrivateFlags3; 3987 3988 /** 3989 * This view's request for the visibility of the status bar. 3990 * @hide 3991 */ 3992 @ViewDebug.ExportedProperty(flagMapping = { 3993 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 3994 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 3995 name = "LOW_PROFILE"), 3996 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3997 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 3998 name = "HIDE_NAVIGATION"), 3999 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_FULLSCREEN, 4000 equals = SYSTEM_UI_FLAG_FULLSCREEN, 4001 name = "FULLSCREEN"), 4002 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4003 equals = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4004 name = "LAYOUT_STABLE"), 4005 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4006 equals = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4007 name = "LAYOUT_HIDE_NAVIGATION"), 4008 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4009 equals = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4010 name = "LAYOUT_FULLSCREEN"), 4011 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE, 4012 equals = SYSTEM_UI_FLAG_IMMERSIVE, 4013 name = "IMMERSIVE"), 4014 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4015 equals = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4016 name = "IMMERSIVE_STICKY"), 4017 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4018 equals = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4019 name = "LIGHT_STATUS_BAR"), 4020 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4021 equals = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4022 name = "LIGHT_NAVIGATION_BAR"), 4023 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_EXPAND, 4024 equals = STATUS_BAR_DISABLE_EXPAND, 4025 name = "STATUS_BAR_DISABLE_EXPAND"), 4026 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4027 equals = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4028 name = "STATUS_BAR_DISABLE_NOTIFICATION_ICONS"), 4029 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4030 equals = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4031 name = "STATUS_BAR_DISABLE_NOTIFICATION_ALERTS"), 4032 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4033 equals = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4034 name = "STATUS_BAR_DISABLE_NOTIFICATION_TICKER"), 4035 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SYSTEM_INFO, 4036 equals = STATUS_BAR_DISABLE_SYSTEM_INFO, 4037 name = "STATUS_BAR_DISABLE_SYSTEM_INFO"), 4038 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_HOME, 4039 equals = STATUS_BAR_DISABLE_HOME, 4040 name = "STATUS_BAR_DISABLE_HOME"), 4041 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_BACK, 4042 equals = STATUS_BAR_DISABLE_BACK, 4043 name = "STATUS_BAR_DISABLE_BACK"), 4044 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_CLOCK, 4045 equals = STATUS_BAR_DISABLE_CLOCK, 4046 name = "STATUS_BAR_DISABLE_CLOCK"), 4047 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_RECENT, 4048 equals = STATUS_BAR_DISABLE_RECENT, 4049 name = "STATUS_BAR_DISABLE_RECENT"), 4050 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH, 4051 equals = STATUS_BAR_DISABLE_SEARCH, 4052 name = "STATUS_BAR_DISABLE_SEARCH"), 4053 @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSIENT, 4054 equals = STATUS_BAR_TRANSIENT, 4055 name = "STATUS_BAR_TRANSIENT"), 4056 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSIENT, 4057 equals = NAVIGATION_BAR_TRANSIENT, 4058 name = "NAVIGATION_BAR_TRANSIENT"), 4059 @ViewDebug.FlagToString(mask = STATUS_BAR_UNHIDE, 4060 equals = STATUS_BAR_UNHIDE, 4061 name = "STATUS_BAR_UNHIDE"), 4062 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_UNHIDE, 4063 equals = NAVIGATION_BAR_UNHIDE, 4064 name = "NAVIGATION_BAR_UNHIDE"), 4065 @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSLUCENT, 4066 equals = STATUS_BAR_TRANSLUCENT, 4067 name = "STATUS_BAR_TRANSLUCENT"), 4068 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSLUCENT, 4069 equals = NAVIGATION_BAR_TRANSLUCENT, 4070 name = "NAVIGATION_BAR_TRANSLUCENT"), 4071 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSPARENT, 4072 equals = NAVIGATION_BAR_TRANSPARENT, 4073 name = "NAVIGATION_BAR_TRANSPARENT"), 4074 @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSPARENT, 4075 equals = STATUS_BAR_TRANSPARENT, 4076 name = "STATUS_BAR_TRANSPARENT") 4077 }, formatToHexString = true) 4078 int mSystemUiVisibility; 4079 4080 /** 4081 * Reference count for transient state. 4082 * @see #setHasTransientState(boolean) 4083 */ 4084 int mTransientStateCount = 0; 4085 4086 /** 4087 * Count of how many windows this view has been attached to. 4088 */ 4089 int mWindowAttachCount; 4090 4091 /** 4092 * The layout parameters associated with this view and used by the parent 4093 * {@link android.view.ViewGroup} to determine how this view should be 4094 * laid out. 4095 * 4096 * The field should not be used directly. Instead {@link #getLayoutParams()} and {@link 4097 * #setLayoutParams(ViewGroup.LayoutParams)} should be used. The setter guarantees internal 4098 * state correctness of the class. 4099 * {@hide} 4100 */ 4101 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4102 protected ViewGroup.LayoutParams mLayoutParams; 4103 4104 /** 4105 * The view flags hold various views states. 4106 * 4107 * Use {@link #setTransitionVisibility(int)} to change the visibility of this view without 4108 * triggering updates. 4109 * {@hide} 4110 */ 4111 @ViewDebug.ExportedProperty(formatToHexString = true) 4112 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4113 int mViewFlags; 4114 4115 static class TransformationInfo { 4116 /** 4117 * The transform matrix for the View. This transform is calculated internally 4118 * based on the translation, rotation, and scale properties. 4119 * 4120 * Do *not* use this variable directly; instead call getMatrix(), which will 4121 * load the value from the View's RenderNode. 4122 */ 4123 private final Matrix mMatrix = new Matrix(); 4124 4125 /** 4126 * The inverse transform matrix for the View. This transform is calculated 4127 * internally based on the translation, rotation, and scale properties. 4128 * 4129 * Do *not* use this variable directly; instead call getInverseMatrix(), 4130 * which will load the value from the View's RenderNode. 4131 */ 4132 private Matrix mInverseMatrix; 4133 4134 /** 4135 * The opacity of the View. This is a value from 0 to 1, where 0 means 4136 * completely transparent and 1 means completely opaque. 4137 */ 4138 @ViewDebug.ExportedProperty 4139 private float mAlpha = 1f; 4140 4141 /** 4142 * The opacity of the view as manipulated by the Fade transition. This is a 4143 * property only used by transitions, which is composited with the other alpha 4144 * values to calculate the final visual alpha value. 4145 */ 4146 float mTransitionAlpha = 1f; 4147 } 4148 4149 /** @hide */ 4150 @UnsupportedAppUsage 4151 public TransformationInfo mTransformationInfo; 4152 4153 /** 4154 * Current clip bounds. to which all drawing of this view are constrained. 4155 */ 4156 @ViewDebug.ExportedProperty(category = "drawing") 4157 Rect mClipBounds = null; 4158 4159 private boolean mLastIsOpaque; 4160 4161 /** 4162 * The distance in pixels from the left edge of this view's parent 4163 * to the left edge of this view. 4164 * {@hide} 4165 */ 4166 @ViewDebug.ExportedProperty(category = "layout") 4167 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4168 protected int mLeft; 4169 /** 4170 * The distance in pixels from the left edge of this view's parent 4171 * to the right edge of this view. 4172 * {@hide} 4173 */ 4174 @ViewDebug.ExportedProperty(category = "layout") 4175 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4176 protected int mRight; 4177 /** 4178 * The distance in pixels from the top edge of this view's parent 4179 * to the top edge of this view. 4180 * {@hide} 4181 */ 4182 @ViewDebug.ExportedProperty(category = "layout") 4183 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4184 protected int mTop; 4185 /** 4186 * The distance in pixels from the top edge of this view's parent 4187 * to the bottom edge of this view. 4188 * {@hide} 4189 */ 4190 @ViewDebug.ExportedProperty(category = "layout") 4191 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4192 protected int mBottom; 4193 4194 /** 4195 * The offset, in pixels, by which the content of this view is scrolled 4196 * horizontally. 4197 * Please use {@link View#getScrollX()} and {@link View#setScrollX(int)} instead of 4198 * accessing these directly. 4199 * {@hide} 4200 */ 4201 @ViewDebug.ExportedProperty(category = "scrolling") 4202 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4203 protected int mScrollX; 4204 /** 4205 * The offset, in pixels, by which the content of this view is scrolled 4206 * vertically. 4207 * Please use {@link View#getScrollY()} and {@link View#setScrollY(int)} instead of 4208 * accessing these directly. 4209 * {@hide} 4210 */ 4211 @ViewDebug.ExportedProperty(category = "scrolling") 4212 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4213 protected int mScrollY; 4214 4215 /** 4216 * The final computed left padding in pixels that is used for drawing. This is the distance in 4217 * pixels between the left edge of this view and the left edge of its content. 4218 * {@hide} 4219 */ 4220 @ViewDebug.ExportedProperty(category = "padding") 4221 @UnsupportedAppUsage 4222 protected int mPaddingLeft = 0; 4223 /** 4224 * The final computed right padding in pixels that is used for drawing. This is the distance in 4225 * pixels between the right edge of this view and the right edge of its content. 4226 * {@hide} 4227 */ 4228 @ViewDebug.ExportedProperty(category = "padding") 4229 @UnsupportedAppUsage 4230 protected int mPaddingRight = 0; 4231 /** 4232 * The final computed top padding in pixels that is used for drawing. This is the distance in 4233 * pixels between the top edge of this view and the top edge of its content. 4234 * {@hide} 4235 */ 4236 @ViewDebug.ExportedProperty(category = "padding") 4237 @UnsupportedAppUsage 4238 protected int mPaddingTop; 4239 /** 4240 * The final computed bottom padding in pixels that is used for drawing. This is the distance in 4241 * pixels between the bottom edge of this view and the bottom edge of its content. 4242 * {@hide} 4243 */ 4244 @ViewDebug.ExportedProperty(category = "padding") 4245 @UnsupportedAppUsage 4246 protected int mPaddingBottom; 4247 4248 /** 4249 * The layout insets in pixels, that is the distance in pixels between the 4250 * visible edges of this view its bounds. 4251 */ 4252 private Insets mLayoutInsets; 4253 4254 /** 4255 * Briefly describes the view and is primarily used for accessibility support. 4256 */ 4257 private CharSequence mContentDescription; 4258 4259 /** 4260 * If this view represents a distinct part of the window, it can have a title that labels the 4261 * area. 4262 */ 4263 private CharSequence mAccessibilityPaneTitle; 4264 4265 /** 4266 * Specifies the id of a view for which this view serves as a label for 4267 * accessibility purposes. 4268 */ 4269 private int mLabelForId = View.NO_ID; 4270 4271 /** 4272 * Predicate for matching labeled view id with its label for 4273 * accessibility purposes. 4274 */ 4275 private MatchLabelForPredicate mMatchLabelForPredicate; 4276 4277 /** 4278 * Specifies a view before which this one is visited in accessibility traversal. 4279 */ 4280 private int mAccessibilityTraversalBeforeId = NO_ID; 4281 4282 /** 4283 * Specifies a view after which this one is visited in accessibility traversal. 4284 */ 4285 private int mAccessibilityTraversalAfterId = NO_ID; 4286 4287 /** 4288 * Predicate for matching a view by its id. 4289 */ 4290 private MatchIdPredicate mMatchIdPredicate; 4291 4292 /** 4293 * The right padding after RTL resolution, but before taking account of scroll bars. 4294 * 4295 * @hide 4296 */ 4297 @ViewDebug.ExportedProperty(category = "padding") 4298 protected int mUserPaddingRight; 4299 4300 /** 4301 * The resolved bottom padding before taking account of scroll bars. 4302 * 4303 * @hide 4304 */ 4305 @ViewDebug.ExportedProperty(category = "padding") 4306 protected int mUserPaddingBottom; 4307 4308 /** 4309 * The left padding after RTL resolution, but before taking account of scroll bars. 4310 * 4311 * @hide 4312 */ 4313 @ViewDebug.ExportedProperty(category = "padding") 4314 protected int mUserPaddingLeft; 4315 4316 /** 4317 * Cache the paddingStart set by the user to append to the scrollbar's size. 4318 * 4319 */ 4320 @ViewDebug.ExportedProperty(category = "padding") 4321 int mUserPaddingStart; 4322 4323 /** 4324 * Cache the paddingEnd set by the user to append to the scrollbar's size. 4325 * 4326 */ 4327 @ViewDebug.ExportedProperty(category = "padding") 4328 int mUserPaddingEnd; 4329 4330 /** 4331 * The left padding as set by a setter method, a background's padding, or via XML property 4332 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4333 * 4334 * @hide 4335 */ 4336 int mUserPaddingLeftInitial; 4337 4338 /** 4339 * The right padding as set by a setter method, a background's padding, or via XML property 4340 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4341 * 4342 * @hide 4343 */ 4344 int mUserPaddingRightInitial; 4345 4346 /** 4347 * Default undefined padding 4348 */ 4349 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 4350 4351 /** 4352 * Cache if a left padding has been defined explicitly via padding, horizontal padding, 4353 * or leftPadding in XML, or by setPadding(...) or setRelativePadding(...) 4354 */ 4355 private boolean mLeftPaddingDefined = false; 4356 4357 /** 4358 * Cache if a right padding has been defined explicitly via padding, horizontal padding, 4359 * or rightPadding in XML, or by setPadding(...) or setRelativePadding(...) 4360 */ 4361 private boolean mRightPaddingDefined = false; 4362 4363 /** 4364 * @hide 4365 */ 4366 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 4367 /** 4368 * @hide 4369 */ 4370 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 4371 4372 private LongSparseLongArray mMeasureCache; 4373 4374 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 4375 @UnsupportedAppUsage 4376 private Drawable mBackground; 4377 private TintInfo mBackgroundTint; 4378 4379 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 4380 private ForegroundInfo mForegroundInfo; 4381 4382 private Drawable mScrollIndicatorDrawable; 4383 4384 /** 4385 * RenderNode used for backgrounds. 4386 * <p> 4387 * When non-null and valid, this is expected to contain an up-to-date copy 4388 * of the background drawable. It is cleared on temporary detach, and reset 4389 * on cleanup. 4390 */ 4391 private RenderNode mBackgroundRenderNode; 4392 4393 @UnsupportedAppUsage 4394 private int mBackgroundResource; 4395 private boolean mBackgroundSizeChanged; 4396 4397 /** The default focus highlight. 4398 * @see #mDefaultFocusHighlightEnabled 4399 * @see Drawable#hasFocusStateSpecified() 4400 */ 4401 private Drawable mDefaultFocusHighlight; 4402 private Drawable mDefaultFocusHighlightCache; 4403 private boolean mDefaultFocusHighlightSizeChanged; 4404 /** 4405 * True if the default focus highlight is needed on the target device. 4406 */ 4407 private static boolean sUseDefaultFocusHighlight; 4408 4409 /** 4410 * True if zero-sized views can be focused. 4411 */ 4412 private static boolean sCanFocusZeroSized; 4413 4414 /** 4415 * Always assign focus if a focusable View is available. 4416 */ 4417 private static boolean sAlwaysAssignFocus; 4418 4419 private String mTransitionName; 4420 4421 static class TintInfo { 4422 ColorStateList mTintList; 4423 BlendMode mBlendMode; 4424 boolean mHasTintMode; 4425 boolean mHasTintList; 4426 } 4427 4428 private static class ForegroundInfo { 4429 private Drawable mDrawable; 4430 private TintInfo mTintInfo; 4431 private int mGravity = Gravity.FILL; 4432 private boolean mInsidePadding = true; 4433 private boolean mBoundsChanged = true; 4434 private final Rect mSelfBounds = new Rect(); 4435 private final Rect mOverlayBounds = new Rect(); 4436 } 4437 4438 static class ListenerInfo { 4439 /** 4440 * Listener used to dispatch focus change events. 4441 * This field should be made private, so it is hidden from the SDK. 4442 * {@hide} 4443 */ 4444 @UnsupportedAppUsage 4445 protected OnFocusChangeListener mOnFocusChangeListener; 4446 4447 /** 4448 * Listeners for layout change events. 4449 */ 4450 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 4451 4452 protected OnScrollChangeListener mOnScrollChangeListener; 4453 4454 /** 4455 * Listeners for attach events. 4456 */ 4457 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 4458 4459 /** 4460 * Listener used to dispatch click events. 4461 * This field should be made private, so it is hidden from the SDK. 4462 * {@hide} 4463 */ 4464 @UnsupportedAppUsage 4465 public OnClickListener mOnClickListener; 4466 4467 /** 4468 * Listener used to dispatch long click events. 4469 * This field should be made private, so it is hidden from the SDK. 4470 * {@hide} 4471 */ 4472 @UnsupportedAppUsage 4473 protected OnLongClickListener mOnLongClickListener; 4474 4475 /** 4476 * Listener used to dispatch context click events. This field should be made private, so it 4477 * is hidden from the SDK. 4478 * {@hide} 4479 */ 4480 protected OnContextClickListener mOnContextClickListener; 4481 4482 /** 4483 * Listener used to build the context menu. 4484 * This field should be made private, so it is hidden from the SDK. 4485 * {@hide} 4486 */ 4487 @UnsupportedAppUsage 4488 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 4489 4490 @UnsupportedAppUsage 4491 private OnKeyListener mOnKeyListener; 4492 4493 @UnsupportedAppUsage 4494 private OnTouchListener mOnTouchListener; 4495 4496 @UnsupportedAppUsage 4497 private OnHoverListener mOnHoverListener; 4498 4499 @UnsupportedAppUsage 4500 private OnGenericMotionListener mOnGenericMotionListener; 4501 4502 @UnsupportedAppUsage 4503 private OnDragListener mOnDragListener; 4504 4505 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 4506 4507 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 4508 4509 OnCapturedPointerListener mOnCapturedPointerListener; 4510 4511 private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners; 4512 4513 private WindowInsetsAnimationListener mWindowInsetsAnimationListener; 4514 4515 /** 4516 * This lives here since it's only valid for interactive views. 4517 */ 4518 private List<Rect> mSystemGestureExclusionRects; 4519 4520 /** 4521 * Used to track {@link #mSystemGestureExclusionRects} 4522 */ 4523 public RenderNode.PositionUpdateListener mPositionUpdateListener; 4524 } 4525 4526 @UnsupportedAppUsage 4527 ListenerInfo mListenerInfo; 4528 4529 private static class TooltipInfo { 4530 /** 4531 * Text to be displayed in a tooltip popup. 4532 */ 4533 @Nullable 4534 CharSequence mTooltipText; 4535 4536 /** 4537 * View-relative position of the tooltip anchor point. 4538 */ 4539 int mAnchorX; 4540 int mAnchorY; 4541 4542 /** 4543 * The tooltip popup. 4544 */ 4545 @Nullable 4546 TooltipPopup mTooltipPopup; 4547 4548 /** 4549 * Set to true if the tooltip was shown as a result of a long click. 4550 */ 4551 boolean mTooltipFromLongClick; 4552 4553 /** 4554 * Keep these Runnables so that they can be used to reschedule. 4555 */ 4556 Runnable mShowTooltipRunnable; 4557 Runnable mHideTooltipRunnable; 4558 4559 /** 4560 * Hover move is ignored if it is within this distance in pixels from the previous one. 4561 */ 4562 int mHoverSlop; 4563 4564 /** 4565 * Update the anchor position if it significantly (that is by at least mHoverSlop) 4566 * different from the previously stored position. Ignoring insignificant changes 4567 * filters out the jitter which is typical for such input sources as stylus. 4568 * 4569 * @return True if the position has been updated. 4570 */ updateAnchorPos(MotionEvent event)4571 private boolean updateAnchorPos(MotionEvent event) { 4572 final int newAnchorX = (int) event.getX(); 4573 final int newAnchorY = (int) event.getY(); 4574 if (Math.abs(newAnchorX - mAnchorX) <= mHoverSlop 4575 && Math.abs(newAnchorY - mAnchorY) <= mHoverSlop) { 4576 return false; 4577 } 4578 mAnchorX = newAnchorX; 4579 mAnchorY = newAnchorY; 4580 return true; 4581 } 4582 4583 /** 4584 * Clear the anchor position to ensure that the next change is considered significant. 4585 */ clearAnchorPos()4586 private void clearAnchorPos() { 4587 mAnchorX = Integer.MAX_VALUE; 4588 mAnchorY = Integer.MAX_VALUE; 4589 } 4590 } 4591 4592 TooltipInfo mTooltipInfo; 4593 4594 // Temporary values used to hold (x,y) coordinates when delegating from the 4595 // two-arg performLongClick() method to the legacy no-arg version. 4596 private float mLongClickX = Float.NaN; 4597 private float mLongClickY = Float.NaN; 4598 4599 /** 4600 * The application environment this view lives in. 4601 * This field should be made private, so it is hidden from the SDK. 4602 * {@hide} 4603 */ 4604 @ViewDebug.ExportedProperty(deepExport = true) 4605 @UnsupportedAppUsage 4606 protected Context mContext; 4607 4608 @UnsupportedAppUsage 4609 private final Resources mResources; 4610 4611 @UnsupportedAppUsage 4612 private ScrollabilityCache mScrollCache; 4613 4614 private int[] mDrawableState = null; 4615 4616 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 4617 4618 /** 4619 * Animator that automatically runs based on state changes. 4620 */ 4621 private StateListAnimator mStateListAnimator; 4622 4623 /** 4624 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 4625 * the user may specify which view to go to next. 4626 */ 4627 private int mNextFocusLeftId = View.NO_ID; 4628 4629 /** 4630 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 4631 * the user may specify which view to go to next. 4632 */ 4633 private int mNextFocusRightId = View.NO_ID; 4634 4635 /** 4636 * When this view has focus and the next focus is {@link #FOCUS_UP}, 4637 * the user may specify which view to go to next. 4638 */ 4639 private int mNextFocusUpId = View.NO_ID; 4640 4641 /** 4642 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 4643 * the user may specify which view to go to next. 4644 */ 4645 private int mNextFocusDownId = View.NO_ID; 4646 4647 /** 4648 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 4649 * the user may specify which view to go to next. 4650 */ 4651 int mNextFocusForwardId = View.NO_ID; 4652 4653 /** 4654 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction. 4655 * 4656 * @see #findUserSetNextKeyboardNavigationCluster(View, int) 4657 */ 4658 int mNextClusterForwardId = View.NO_ID; 4659 4660 /** 4661 * Whether this View should use a default focus highlight when it gets focused but doesn't 4662 * have {@link android.R.attr#state_focused} defined in its background. 4663 */ 4664 boolean mDefaultFocusHighlightEnabled = true; 4665 4666 private CheckForLongPress mPendingCheckForLongPress; 4667 @UnsupportedAppUsage 4668 private CheckForTap mPendingCheckForTap = null; 4669 private PerformClick mPerformClick; 4670 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 4671 4672 private UnsetPressedState mUnsetPressedState; 4673 4674 /** 4675 * Whether the long press's action has been invoked. The tap's action is invoked on the 4676 * up event while a long press is invoked as soon as the long press duration is reached, so 4677 * a long press could be performed before the tap is checked, in which case the tap's action 4678 * should not be invoked. 4679 */ 4680 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 4681 private boolean mHasPerformedLongPress; 4682 4683 /** 4684 * Whether a context click button is currently pressed down. This is true when the stylus is 4685 * touching the screen and the primary button has been pressed, or if a mouse's right button is 4686 * pressed. This is false once the button is released or if the stylus has been lifted. 4687 */ 4688 private boolean mInContextButtonPress; 4689 4690 /** 4691 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 4692 * true after a stylus button press has occured, when the next up event should not be recognized 4693 * as a tap. 4694 */ 4695 private boolean mIgnoreNextUpEvent; 4696 4697 /** 4698 * The minimum height of the view. We'll try our best to have the height 4699 * of this view to at least this amount. 4700 */ 4701 @ViewDebug.ExportedProperty(category = "measurement") 4702 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4703 private int mMinHeight; 4704 4705 /** 4706 * The minimum width of the view. We'll try our best to have the width 4707 * of this view to at least this amount. 4708 */ 4709 @ViewDebug.ExportedProperty(category = "measurement") 4710 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4711 private int mMinWidth; 4712 4713 /** 4714 * The delegate to handle touch events that are physically in this view 4715 * but should be handled by another view. 4716 */ 4717 private TouchDelegate mTouchDelegate = null; 4718 4719 /** 4720 * While touch exploration is in use, set to true when hovering across boundaries and 4721 * inside the touch area of the delegate at receiving {@link MotionEvent#ACTION_HOVER_ENTER} 4722 * or {@link MotionEvent#ACTION_HOVER_MOVE}. False when leaving boundaries or receiving a 4723 * {@link MotionEvent#ACTION_HOVER_EXIT}. 4724 * Note that children of view group are excluded in the touch area. 4725 * @see #dispatchTouchExplorationHoverEvent 4726 */ 4727 private boolean mHoveringTouchDelegate = false; 4728 4729 /** 4730 * Solid color to use as a background when creating the drawing cache. Enables 4731 * the cache to use 16 bit bitmaps instead of 32 bit. 4732 */ 4733 private int mDrawingCacheBackgroundColor = 0; 4734 4735 /** 4736 * Special tree observer used when mAttachInfo is null. 4737 */ 4738 private ViewTreeObserver mFloatingTreeObserver; 4739 4740 /** 4741 * Cache the touch slop from the context that created the view. 4742 */ 4743 private int mTouchSlop; 4744 4745 /** 4746 * Object that handles automatic animation of view properties. 4747 */ 4748 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 4749 private ViewPropertyAnimator mAnimator = null; 4750 4751 /** 4752 * List of registered FrameMetricsObservers. 4753 */ 4754 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 4755 4756 /** 4757 * Flag indicating that a drag can cross window boundaries. When 4758 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4759 * with this flag set, all visible applications with targetSdkVersion >= 4760 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 4761 * in the drag operation and receive the dragged content. 4762 * 4763 * <p>If this is the only flag set, then the drag recipient will only have access to text data 4764 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 4765 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 4766 */ 4767 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 4768 4769 /** 4770 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4771 * request read access to the content URI(s) contained in the {@link ClipData} object. 4772 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION 4773 */ 4774 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 4775 4776 /** 4777 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4778 * request write access to the content URI(s) contained in the {@link ClipData} object. 4779 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION 4780 */ 4781 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 4782 4783 /** 4784 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4785 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 4786 * reboots until explicitly revoked with 4787 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}. 4788 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION 4789 */ 4790 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 4791 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 4792 4793 /** 4794 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4795 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 4796 * match against the original granted URI. 4797 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION 4798 */ 4799 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 4800 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 4801 4802 /** 4803 * Flag indicating that the drag shadow will be opaque. When 4804 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4805 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 4806 */ 4807 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 4808 4809 /** 4810 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 4811 */ 4812 private float mVerticalScrollFactor; 4813 4814 /** 4815 * Position of the vertical scroll bar. 4816 */ 4817 @UnsupportedAppUsage 4818 private int mVerticalScrollbarPosition; 4819 4820 /** 4821 * Position the scroll bar at the default position as determined by the system. 4822 */ 4823 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 4824 4825 /** 4826 * Position the scroll bar along the left edge. 4827 */ 4828 public static final int SCROLLBAR_POSITION_LEFT = 1; 4829 4830 /** 4831 * Position the scroll bar along the right edge. 4832 */ 4833 public static final int SCROLLBAR_POSITION_RIGHT = 2; 4834 4835 /** 4836 * Indicates that the view does not have a layer. 4837 * 4838 * @see #getLayerType() 4839 * @see #setLayerType(int, android.graphics.Paint) 4840 * @see #LAYER_TYPE_SOFTWARE 4841 * @see #LAYER_TYPE_HARDWARE 4842 */ 4843 public static final int LAYER_TYPE_NONE = 0; 4844 4845 /** 4846 * <p>Indicates that the view has a software layer. A software layer is backed 4847 * by a bitmap and causes the view to be rendered using Android's software 4848 * rendering pipeline, even if hardware acceleration is enabled.</p> 4849 * 4850 * <p>Software layers have various usages:</p> 4851 * <p>When the application is not using hardware acceleration, a software layer 4852 * is useful to apply a specific color filter and/or blending mode and/or 4853 * translucency to a view and all its children.</p> 4854 * <p>When the application is using hardware acceleration, a software layer 4855 * is useful to render drawing primitives not supported by the hardware 4856 * accelerated pipeline. It can also be used to cache a complex view tree 4857 * into a texture and reduce the complexity of drawing operations. For instance, 4858 * when animating a complex view tree with a translation, a software layer can 4859 * be used to render the view tree only once.</p> 4860 * <p>Software layers should be avoided when the affected view tree updates 4861 * often. Every update will require to re-render the software layer, which can 4862 * potentially be slow (particularly when hardware acceleration is turned on 4863 * since the layer will have to be uploaded into a hardware texture after every 4864 * update.)</p> 4865 * 4866 * @see #getLayerType() 4867 * @see #setLayerType(int, android.graphics.Paint) 4868 * @see #LAYER_TYPE_NONE 4869 * @see #LAYER_TYPE_HARDWARE 4870 */ 4871 public static final int LAYER_TYPE_SOFTWARE = 1; 4872 4873 /** 4874 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 4875 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 4876 * OpenGL hardware) and causes the view to be rendered using Android's hardware 4877 * rendering pipeline, but only if hardware acceleration is turned on for the 4878 * view hierarchy. When hardware acceleration is turned off, hardware layers 4879 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 4880 * 4881 * <p>A hardware layer is useful to apply a specific color filter and/or 4882 * blending mode and/or translucency to a view and all its children.</p> 4883 * <p>A hardware layer can be used to cache a complex view tree into a 4884 * texture and reduce the complexity of drawing operations. For instance, 4885 * when animating a complex view tree with a translation, a hardware layer can 4886 * be used to render the view tree only once.</p> 4887 * <p>A hardware layer can also be used to increase the rendering quality when 4888 * rotation transformations are applied on a view. It can also be used to 4889 * prevent potential clipping issues when applying 3D transforms on a view.</p> 4890 * 4891 * @see #getLayerType() 4892 * @see #setLayerType(int, android.graphics.Paint) 4893 * @see #LAYER_TYPE_NONE 4894 * @see #LAYER_TYPE_SOFTWARE 4895 */ 4896 public static final int LAYER_TYPE_HARDWARE = 2; 4897 4898 /** @hide */ 4899 @IntDef(prefix = { "LAYER_TYPE_" }, value = { 4900 LAYER_TYPE_NONE, 4901 LAYER_TYPE_SOFTWARE, 4902 LAYER_TYPE_HARDWARE 4903 }) 4904 @Retention(RetentionPolicy.SOURCE) 4905 public @interface LayerType {} 4906 4907 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 4908 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 4909 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 4910 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 4911 }) 4912 int mLayerType = LAYER_TYPE_NONE; 4913 Paint mLayerPaint; 4914 4915 /** 4916 * Set to true when drawing cache is enabled and cannot be created. 4917 * 4918 * @hide 4919 */ 4920 @UnsupportedAppUsage 4921 public boolean mCachingFailed; 4922 @UnsupportedAppUsage 4923 private Bitmap mDrawingCache; 4924 @UnsupportedAppUsage 4925 private Bitmap mUnscaledDrawingCache; 4926 4927 /** 4928 * RenderNode holding View properties, potentially holding a DisplayList of View content. 4929 * <p> 4930 * When non-null and valid, this is expected to contain an up-to-date copy 4931 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 4932 * cleanup. 4933 */ 4934 @UnsupportedAppUsage 4935 final RenderNode mRenderNode; 4936 4937 /** 4938 * Set to true when the view is sending hover accessibility events because it 4939 * is the innermost hovered view. 4940 */ 4941 private boolean mSendingHoverAccessibilityEvents; 4942 4943 /** 4944 * Delegate for injecting accessibility functionality. 4945 */ 4946 @UnsupportedAppUsage 4947 AccessibilityDelegate mAccessibilityDelegate; 4948 4949 /** 4950 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 4951 * and add/remove objects to/from the overlay directly through the Overlay methods. 4952 */ 4953 ViewOverlay mOverlay; 4954 4955 /** 4956 * The currently active parent view for receiving delegated nested scrolling events. 4957 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 4958 * by {@link #stopNestedScroll()} at the same point where we clear 4959 * requestDisallowInterceptTouchEvent. 4960 */ 4961 private ViewParent mNestedScrollingParent; 4962 4963 /** 4964 * Consistency verifier for debugging purposes. 4965 * @hide 4966 */ 4967 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 4968 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 4969 new InputEventConsistencyVerifier(this, 0) : null; 4970 4971 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 4972 4973 private int[] mTempNestedScrollConsumed; 4974 4975 /** 4976 * An overlay is going to draw this View instead of being drawn as part of this 4977 * View's parent. mGhostView is the View in the Overlay that must be invalidated 4978 * when this view is invalidated. 4979 */ 4980 GhostView mGhostView; 4981 4982 /** 4983 * Holds pairs of adjacent attribute data: attribute name followed by its value. 4984 * @hide 4985 */ 4986 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 4987 public String[] mAttributes; 4988 4989 /** 4990 * Maps a Resource id to its name. 4991 */ 4992 private static SparseArray<String> mAttributeMap; 4993 4994 /** 4995 * Queue of pending runnables. Used to postpone calls to post() until this 4996 * view is attached and has a handler. 4997 */ 4998 private HandlerActionQueue mRunQueue; 4999 5000 /** 5001 * The pointer icon when the mouse hovers on this view. The default is null. 5002 */ 5003 private PointerIcon mPointerIcon; 5004 5005 /** 5006 * @hide 5007 */ 5008 @UnsupportedAppUsage 5009 String mStartActivityRequestWho; 5010 5011 @Nullable 5012 private RoundScrollbarRenderer mRoundScrollbarRenderer; 5013 5014 /** Used to delay visibility updates sent to the autofill manager */ 5015 private Handler mVisibilityChangeForAutofillHandler; 5016 5017 /** 5018 * Used when app developers explicitly set the {@link ContentCaptureSession} associated with the 5019 * view (through {@link #setContentCaptureSession(ContentCaptureSession)}. 5020 */ 5021 @Nullable 5022 private ContentCaptureSession mContentCaptureSession; 5023 5024 @LayoutRes 5025 private int mSourceLayoutId = ID_NULL; 5026 5027 @Nullable 5028 private SparseIntArray mAttributeSourceResId; 5029 5030 @Nullable 5031 private SparseArray<int[]> mAttributeResolutionStacks; 5032 5033 @StyleRes 5034 private int mExplicitStyle; 5035 5036 /** 5037 * Cached reference to the {@link ContentCaptureSession}, is reset on {@link #invalidate()}. 5038 */ 5039 private ContentCaptureSession mCachedContentCaptureSession; 5040 5041 /** 5042 * Simple constructor to use when creating a view from code. 5043 * 5044 * @param context The Context the view is running in, through which it can 5045 * access the current theme, resources, etc. 5046 */ View(Context context)5047 public View(Context context) { 5048 mContext = context; 5049 mResources = context != null ? context.getResources() : null; 5050 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 5051 // Set some flags defaults 5052 mPrivateFlags2 = 5053 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 5054 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 5055 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 5056 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 5057 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 5058 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 5059 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 5060 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 5061 mUserPaddingStart = UNDEFINED_PADDING; 5062 mUserPaddingEnd = UNDEFINED_PADDING; 5063 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 5064 5065 if (!sCompatibilityDone && context != null) { 5066 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5067 5068 // Older apps may need this compatibility hack for measurement. 5069 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; 5070 5071 // Older apps expect onMeasure() to always be called on a layout pass, regardless 5072 // of whether a layout was requested on that View. 5073 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; 5074 5075 Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M; 5076 Canvas.sCompatibilitySetBitmap = targetSdkVersion < Build.VERSION_CODES.O; 5077 Canvas.setCompatibilityVersion(targetSdkVersion); 5078 5079 // In M and newer, our widgets can pass a "hint" value in the size 5080 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 5081 // know what the expected parent size is going to be, so e.g. list items can size 5082 // themselves at 1/3 the size of their container. It breaks older apps though, 5083 // specifically apps that use some popular open source libraries. 5084 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M; 5085 5086 // Old versions of the platform would give different results from 5087 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 5088 // modes, so we always need to run an additional EXACTLY pass. 5089 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 5090 5091 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 5092 // On N+, we throw, but that breaks compatibility with apps that use these methods. 5093 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 5094 5095 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 5096 // in apps so we target check it to avoid breaking existing apps. 5097 sPreserveMarginParamsInLayoutParamConversion = 5098 targetSdkVersion >= Build.VERSION_CODES.N; 5099 5100 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 5101 5102 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 5103 5104 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 5105 5106 sUseDefaultFocusHighlight = context.getResources().getBoolean( 5107 com.android.internal.R.bool.config_useDefaultFocusHighlight); 5108 5109 sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P; 5110 5111 sCanFocusZeroSized = targetSdkVersion < Build.VERSION_CODES.P; 5112 5113 sAlwaysAssignFocus = targetSdkVersion < Build.VERSION_CODES.P; 5114 5115 sAcceptZeroSizeDragShadow = targetSdkVersion < Build.VERSION_CODES.P; 5116 5117 sBrokenInsetsDispatch = ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL 5118 || targetSdkVersion < Build.VERSION_CODES.Q; 5119 5120 sBrokenWindowBackground = targetSdkVersion < Build.VERSION_CODES.Q; 5121 5122 sCompatibilityDone = true; 5123 } 5124 } 5125 5126 /** 5127 * Constructor that is called when inflating a view from XML. This is called 5128 * when a view is being constructed from an XML file, supplying attributes 5129 * that were specified in the XML file. This version uses a default style of 5130 * 0, so the only attribute values applied are those in the Context's Theme 5131 * and the given AttributeSet. 5132 * 5133 * <p> 5134 * The method onFinishInflate() will be called after all children have been 5135 * added. 5136 * 5137 * @param context The Context the view is running in, through which it can 5138 * access the current theme, resources, etc. 5139 * @param attrs The attributes of the XML tag that is inflating the view. 5140 * @see #View(Context, AttributeSet, int) 5141 */ 5142 public View(Context context, @Nullable AttributeSet attrs) { 5143 this(context, attrs, 0); 5144 } 5145 5146 /** 5147 * Perform inflation from XML and apply a class-specific base style from a 5148 * theme attribute. This constructor of View allows subclasses to use their 5149 * own base style when they are inflating. For example, a Button class's 5150 * constructor would call this version of the super class constructor and 5151 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 5152 * allows the theme's button style to modify all of the base view attributes 5153 * (in particular its background) as well as the Button class's attributes. 5154 * 5155 * @param context The Context the view is running in, through which it can 5156 * access the current theme, resources, etc. 5157 * @param attrs The attributes of the XML tag that is inflating the view. 5158 * @param defStyleAttr An attribute in the current theme that contains a 5159 * reference to a style resource that supplies default values for 5160 * the view. Can be 0 to not look for defaults. 5161 * @see #View(Context, AttributeSet) 5162 */ 5163 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 5164 this(context, attrs, defStyleAttr, 0); 5165 } 5166 5167 /** 5168 * Perform inflation from XML and apply a class-specific base style from a 5169 * theme attribute or style resource. This constructor of View allows 5170 * subclasses to use their own base style when they are inflating. 5171 * <p> 5172 * When determining the final value of a particular attribute, there are 5173 * four inputs that come into play: 5174 * <ol> 5175 * <li>Any attribute values in the given AttributeSet. 5176 * <li>The style resource specified in the AttributeSet (named "style"). 5177 * <li>The default style specified by <var>defStyleAttr</var>. 5178 * <li>The default style specified by <var>defStyleRes</var>. 5179 * <li>The base values in this theme. 5180 * </ol> 5181 * <p> 5182 * Each of these inputs is considered in-order, with the first listed taking 5183 * precedence over the following ones. In other words, if in the 5184 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 5185 * , then the button's text will <em>always</em> be black, regardless of 5186 * what is specified in any of the styles. 5187 * 5188 * @param context The Context the view is running in, through which it can 5189 * access the current theme, resources, etc. 5190 * @param attrs The attributes of the XML tag that is inflating the view. 5191 * @param defStyleAttr An attribute in the current theme that contains a 5192 * reference to a style resource that supplies default values for 5193 * the view. Can be 0 to not look for defaults. 5194 * @param defStyleRes A resource identifier of a style resource that 5195 * supplies default values for the view, used only if 5196 * defStyleAttr is 0 or can not be found in the theme. Can be 0 5197 * to not look for defaults. 5198 * @see #View(Context, AttributeSet, int) 5199 */ 5200 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 5201 this(context); 5202 5203 mSourceLayoutId = Resources.getAttributeSetSourceResId(attrs); 5204 5205 final TypedArray a = context.obtainStyledAttributes( 5206 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 5207 5208 retrieveExplicitStyle(context.getTheme(), attrs); 5209 saveAttributeDataForStyleable(context, com.android.internal.R.styleable.View, attrs, a, 5210 defStyleAttr, defStyleRes); 5211 5212 if (sDebugViewAttributes) { 5213 saveAttributeData(attrs, a); 5214 } 5215 5216 Drawable background = null; 5217 5218 int leftPadding = -1; 5219 int topPadding = -1; 5220 int rightPadding = -1; 5221 int bottomPadding = -1; 5222 int startPadding = UNDEFINED_PADDING; 5223 int endPadding = UNDEFINED_PADDING; 5224 5225 int padding = -1; 5226 int paddingHorizontal = -1; 5227 int paddingVertical = -1; 5228 5229 int viewFlagValues = 0; 5230 int viewFlagMasks = 0; 5231 5232 boolean setScrollContainer = false; 5233 5234 int x = 0; 5235 int y = 0; 5236 5237 float tx = 0; 5238 float ty = 0; 5239 float tz = 0; 5240 float elevation = 0; 5241 float rotation = 0; 5242 float rotationX = 0; 5243 float rotationY = 0; 5244 float sx = 1f; 5245 float sy = 1f; 5246 boolean transformSet = false; 5247 5248 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 5249 int overScrollMode = mOverScrollMode; 5250 boolean initializeScrollbars = false; 5251 boolean initializeScrollIndicators = false; 5252 5253 boolean startPaddingDefined = false; 5254 boolean endPaddingDefined = false; 5255 boolean leftPaddingDefined = false; 5256 boolean rightPaddingDefined = false; 5257 5258 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5259 5260 // Set default values. 5261 viewFlagValues |= FOCUSABLE_AUTO; 5262 viewFlagMasks |= FOCUSABLE_AUTO; 5263 5264 final int N = a.getIndexCount(); 5265 for (int i = 0; i < N; i++) { 5266 int attr = a.getIndex(i); 5267 switch (attr) { 5268 case com.android.internal.R.styleable.View_background: 5269 background = a.getDrawable(attr); 5270 break; 5271 case com.android.internal.R.styleable.View_padding: 5272 padding = a.getDimensionPixelSize(attr, -1); 5273 mUserPaddingLeftInitial = padding; 5274 mUserPaddingRightInitial = padding; 5275 leftPaddingDefined = true; 5276 rightPaddingDefined = true; 5277 break; 5278 case com.android.internal.R.styleable.View_paddingHorizontal: 5279 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 5280 mUserPaddingLeftInitial = paddingHorizontal; 5281 mUserPaddingRightInitial = paddingHorizontal; 5282 leftPaddingDefined = true; 5283 rightPaddingDefined = true; 5284 break; 5285 case com.android.internal.R.styleable.View_paddingVertical: 5286 paddingVertical = a.getDimensionPixelSize(attr, -1); 5287 break; 5288 case com.android.internal.R.styleable.View_paddingLeft: 5289 leftPadding = a.getDimensionPixelSize(attr, -1); 5290 mUserPaddingLeftInitial = leftPadding; 5291 leftPaddingDefined = true; 5292 break; 5293 case com.android.internal.R.styleable.View_paddingTop: 5294 topPadding = a.getDimensionPixelSize(attr, -1); 5295 break; 5296 case com.android.internal.R.styleable.View_paddingRight: 5297 rightPadding = a.getDimensionPixelSize(attr, -1); 5298 mUserPaddingRightInitial = rightPadding; 5299 rightPaddingDefined = true; 5300 break; 5301 case com.android.internal.R.styleable.View_paddingBottom: 5302 bottomPadding = a.getDimensionPixelSize(attr, -1); 5303 break; 5304 case com.android.internal.R.styleable.View_paddingStart: 5305 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5306 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 5307 break; 5308 case com.android.internal.R.styleable.View_paddingEnd: 5309 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5310 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 5311 break; 5312 case com.android.internal.R.styleable.View_scrollX: 5313 x = a.getDimensionPixelOffset(attr, 0); 5314 break; 5315 case com.android.internal.R.styleable.View_scrollY: 5316 y = a.getDimensionPixelOffset(attr, 0); 5317 break; 5318 case com.android.internal.R.styleable.View_alpha: 5319 setAlpha(a.getFloat(attr, 1f)); 5320 break; 5321 case com.android.internal.R.styleable.View_transformPivotX: 5322 setPivotX(a.getDimension(attr, 0)); 5323 break; 5324 case com.android.internal.R.styleable.View_transformPivotY: 5325 setPivotY(a.getDimension(attr, 0)); 5326 break; 5327 case com.android.internal.R.styleable.View_translationX: 5328 tx = a.getDimension(attr, 0); 5329 transformSet = true; 5330 break; 5331 case com.android.internal.R.styleable.View_translationY: 5332 ty = a.getDimension(attr, 0); 5333 transformSet = true; 5334 break; 5335 case com.android.internal.R.styleable.View_translationZ: 5336 tz = a.getDimension(attr, 0); 5337 transformSet = true; 5338 break; 5339 case com.android.internal.R.styleable.View_elevation: 5340 elevation = a.getDimension(attr, 0); 5341 transformSet = true; 5342 break; 5343 case com.android.internal.R.styleable.View_rotation: 5344 rotation = a.getFloat(attr, 0); 5345 transformSet = true; 5346 break; 5347 case com.android.internal.R.styleable.View_rotationX: 5348 rotationX = a.getFloat(attr, 0); 5349 transformSet = true; 5350 break; 5351 case com.android.internal.R.styleable.View_rotationY: 5352 rotationY = a.getFloat(attr, 0); 5353 transformSet = true; 5354 break; 5355 case com.android.internal.R.styleable.View_scaleX: 5356 sx = a.getFloat(attr, 1f); 5357 transformSet = true; 5358 break; 5359 case com.android.internal.R.styleable.View_scaleY: 5360 sy = a.getFloat(attr, 1f); 5361 transformSet = true; 5362 break; 5363 case com.android.internal.R.styleable.View_id: 5364 mID = a.getResourceId(attr, NO_ID); 5365 break; 5366 case com.android.internal.R.styleable.View_tag: 5367 mTag = a.getText(attr); 5368 break; 5369 case com.android.internal.R.styleable.View_fitsSystemWindows: 5370 if (a.getBoolean(attr, false)) { 5371 viewFlagValues |= FITS_SYSTEM_WINDOWS; 5372 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 5373 } 5374 break; 5375 case com.android.internal.R.styleable.View_focusable: 5376 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 5377 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 5378 viewFlagMasks |= FOCUSABLE_MASK; 5379 } 5380 break; 5381 case com.android.internal.R.styleable.View_focusableInTouchMode: 5382 if (a.getBoolean(attr, false)) { 5383 // unset auto focus since focusableInTouchMode implies explicit focusable 5384 viewFlagValues &= ~FOCUSABLE_AUTO; 5385 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 5386 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 5387 } 5388 break; 5389 case com.android.internal.R.styleable.View_clickable: 5390 if (a.getBoolean(attr, false)) { 5391 viewFlagValues |= CLICKABLE; 5392 viewFlagMasks |= CLICKABLE; 5393 } 5394 break; 5395 case com.android.internal.R.styleable.View_longClickable: 5396 if (a.getBoolean(attr, false)) { 5397 viewFlagValues |= LONG_CLICKABLE; 5398 viewFlagMasks |= LONG_CLICKABLE; 5399 } 5400 break; 5401 case com.android.internal.R.styleable.View_contextClickable: 5402 if (a.getBoolean(attr, false)) { 5403 viewFlagValues |= CONTEXT_CLICKABLE; 5404 viewFlagMasks |= CONTEXT_CLICKABLE; 5405 } 5406 break; 5407 case com.android.internal.R.styleable.View_saveEnabled: 5408 if (!a.getBoolean(attr, true)) { 5409 viewFlagValues |= SAVE_DISABLED; 5410 viewFlagMasks |= SAVE_DISABLED_MASK; 5411 } 5412 break; 5413 case com.android.internal.R.styleable.View_duplicateParentState: 5414 if (a.getBoolean(attr, false)) { 5415 viewFlagValues |= DUPLICATE_PARENT_STATE; 5416 viewFlagMasks |= DUPLICATE_PARENT_STATE; 5417 } 5418 break; 5419 case com.android.internal.R.styleable.View_visibility: 5420 final int visibility = a.getInt(attr, 0); 5421 if (visibility != 0) { 5422 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 5423 viewFlagMasks |= VISIBILITY_MASK; 5424 } 5425 break; 5426 case com.android.internal.R.styleable.View_layoutDirection: 5427 // Clear any layout direction flags (included resolved bits) already set 5428 mPrivateFlags2 &= 5429 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 5430 // Set the layout direction flags depending on the value of the attribute 5431 final int layoutDirection = a.getInt(attr, -1); 5432 final int value = (layoutDirection != -1) ? 5433 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 5434 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 5435 break; 5436 case com.android.internal.R.styleable.View_drawingCacheQuality: 5437 final int cacheQuality = a.getInt(attr, 0); 5438 if (cacheQuality != 0) { 5439 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 5440 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 5441 } 5442 break; 5443 case com.android.internal.R.styleable.View_contentDescription: 5444 setContentDescription(a.getString(attr)); 5445 break; 5446 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 5447 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 5448 break; 5449 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 5450 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 5451 break; 5452 case com.android.internal.R.styleable.View_labelFor: 5453 setLabelFor(a.getResourceId(attr, NO_ID)); 5454 break; 5455 case com.android.internal.R.styleable.View_soundEffectsEnabled: 5456 if (!a.getBoolean(attr, true)) { 5457 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 5458 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 5459 } 5460 break; 5461 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 5462 if (!a.getBoolean(attr, true)) { 5463 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 5464 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 5465 } 5466 break; 5467 case R.styleable.View_scrollbars: 5468 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 5469 if (scrollbars != SCROLLBARS_NONE) { 5470 viewFlagValues |= scrollbars; 5471 viewFlagMasks |= SCROLLBARS_MASK; 5472 initializeScrollbars = true; 5473 } 5474 break; 5475 //noinspection deprecation 5476 case R.styleable.View_fadingEdge: 5477 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 5478 // Ignore the attribute starting with ICS 5479 break; 5480 } 5481 // With builds < ICS, fall through and apply fading edges 5482 case R.styleable.View_requiresFadingEdge: 5483 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 5484 if (fadingEdge != FADING_EDGE_NONE) { 5485 viewFlagValues |= fadingEdge; 5486 viewFlagMasks |= FADING_EDGE_MASK; 5487 initializeFadingEdgeInternal(a); 5488 } 5489 break; 5490 case R.styleable.View_scrollbarStyle: 5491 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 5492 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5493 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 5494 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 5495 } 5496 break; 5497 case R.styleable.View_isScrollContainer: 5498 setScrollContainer = true; 5499 if (a.getBoolean(attr, false)) { 5500 setScrollContainer(true); 5501 } 5502 break; 5503 case com.android.internal.R.styleable.View_keepScreenOn: 5504 if (a.getBoolean(attr, false)) { 5505 viewFlagValues |= KEEP_SCREEN_ON; 5506 viewFlagMasks |= KEEP_SCREEN_ON; 5507 } 5508 break; 5509 case R.styleable.View_filterTouchesWhenObscured: 5510 if (a.getBoolean(attr, false)) { 5511 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 5512 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 5513 } 5514 break; 5515 case R.styleable.View_nextFocusLeft: 5516 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 5517 break; 5518 case R.styleable.View_nextFocusRight: 5519 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 5520 break; 5521 case R.styleable.View_nextFocusUp: 5522 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 5523 break; 5524 case R.styleable.View_nextFocusDown: 5525 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 5526 break; 5527 case R.styleable.View_nextFocusForward: 5528 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 5529 break; 5530 case R.styleable.View_nextClusterForward: 5531 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 5532 break; 5533 case R.styleable.View_minWidth: 5534 mMinWidth = a.getDimensionPixelSize(attr, 0); 5535 break; 5536 case R.styleable.View_minHeight: 5537 mMinHeight = a.getDimensionPixelSize(attr, 0); 5538 break; 5539 case R.styleable.View_onClick: 5540 if (context.isRestricted()) { 5541 throw new IllegalStateException("The android:onClick attribute cannot " 5542 + "be used within a restricted context"); 5543 } 5544 5545 final String handlerName = a.getString(attr); 5546 if (handlerName != null) { 5547 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 5548 } 5549 break; 5550 case R.styleable.View_overScrollMode: 5551 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 5552 break; 5553 case R.styleable.View_verticalScrollbarPosition: 5554 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 5555 break; 5556 case R.styleable.View_layerType: 5557 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 5558 break; 5559 case R.styleable.View_textDirection: 5560 // Clear any text direction flag already set 5561 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 5562 // Set the text direction flags depending on the value of the attribute 5563 final int textDirection = a.getInt(attr, -1); 5564 if (textDirection != -1) { 5565 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 5566 } 5567 break; 5568 case R.styleable.View_textAlignment: 5569 // Clear any text alignment flag already set 5570 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 5571 // Set the text alignment flag depending on the value of the attribute 5572 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 5573 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 5574 break; 5575 case R.styleable.View_importantForAccessibility: 5576 setImportantForAccessibility(a.getInt(attr, 5577 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 5578 break; 5579 case R.styleable.View_accessibilityLiveRegion: 5580 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 5581 break; 5582 case R.styleable.View_transitionName: 5583 setTransitionName(a.getString(attr)); 5584 break; 5585 case R.styleable.View_nestedScrollingEnabled: 5586 setNestedScrollingEnabled(a.getBoolean(attr, false)); 5587 break; 5588 case R.styleable.View_stateListAnimator: 5589 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 5590 a.getResourceId(attr, 0))); 5591 break; 5592 case R.styleable.View_backgroundTint: 5593 // This will get applied later during setBackground(). 5594 if (mBackgroundTint == null) { 5595 mBackgroundTint = new TintInfo(); 5596 } 5597 mBackgroundTint.mTintList = a.getColorStateList( 5598 R.styleable.View_backgroundTint); 5599 mBackgroundTint.mHasTintList = true; 5600 break; 5601 case R.styleable.View_backgroundTintMode: 5602 // This will get applied later during setBackground(). 5603 if (mBackgroundTint == null) { 5604 mBackgroundTint = new TintInfo(); 5605 } 5606 mBackgroundTint.mBlendMode = Drawable.parseBlendMode(a.getInt( 5607 R.styleable.View_backgroundTintMode, -1), null); 5608 mBackgroundTint.mHasTintMode = true; 5609 break; 5610 case R.styleable.View_outlineProvider: 5611 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 5612 PROVIDER_BACKGROUND)); 5613 break; 5614 case R.styleable.View_foreground: 5615 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5616 setForeground(a.getDrawable(attr)); 5617 } 5618 break; 5619 case R.styleable.View_foregroundGravity: 5620 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5621 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 5622 } 5623 break; 5624 case R.styleable.View_foregroundTintMode: 5625 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5626 setForegroundTintBlendMode( 5627 Drawable.parseBlendMode(a.getInt(attr, -1), 5628 null)); 5629 } 5630 break; 5631 case R.styleable.View_foregroundTint: 5632 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5633 setForegroundTintList(a.getColorStateList(attr)); 5634 } 5635 break; 5636 case R.styleable.View_foregroundInsidePadding: 5637 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5638 if (mForegroundInfo == null) { 5639 mForegroundInfo = new ForegroundInfo(); 5640 } 5641 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 5642 mForegroundInfo.mInsidePadding); 5643 } 5644 break; 5645 case R.styleable.View_scrollIndicators: 5646 final int scrollIndicators = 5647 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 5648 & SCROLL_INDICATORS_PFLAG3_MASK; 5649 if (scrollIndicators != 0) { 5650 mPrivateFlags3 |= scrollIndicators; 5651 initializeScrollIndicators = true; 5652 } 5653 break; 5654 case R.styleable.View_pointerIcon: 5655 final int resourceId = a.getResourceId(attr, 0); 5656 if (resourceId != 0) { 5657 setPointerIcon(PointerIcon.load( 5658 context.getResources(), resourceId)); 5659 } else { 5660 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 5661 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 5662 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 5663 } 5664 } 5665 break; 5666 case R.styleable.View_forceHasOverlappingRendering: 5667 if (a.peekValue(attr) != null) { 5668 forceHasOverlappingRendering(a.getBoolean(attr, true)); 5669 } 5670 break; 5671 case R.styleable.View_tooltipText: 5672 setTooltipText(a.getText(attr)); 5673 break; 5674 case R.styleable.View_keyboardNavigationCluster: 5675 if (a.peekValue(attr) != null) { 5676 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 5677 } 5678 break; 5679 case R.styleable.View_focusedByDefault: 5680 if (a.peekValue(attr) != null) { 5681 setFocusedByDefault(a.getBoolean(attr, true)); 5682 } 5683 break; 5684 case R.styleable.View_autofillHints: 5685 if (a.peekValue(attr) != null) { 5686 CharSequence[] rawHints = null; 5687 String rawString = null; 5688 5689 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 5690 int resId = a.getResourceId(attr, 0); 5691 5692 try { 5693 rawHints = a.getTextArray(attr); 5694 } catch (Resources.NotFoundException e) { 5695 rawString = getResources().getString(resId); 5696 } 5697 } else { 5698 rawString = a.getString(attr); 5699 } 5700 5701 if (rawHints == null) { 5702 if (rawString == null) { 5703 throw new IllegalArgumentException( 5704 "Could not resolve autofillHints"); 5705 } else { 5706 rawHints = rawString.split(","); 5707 } 5708 } 5709 5710 String[] hints = new String[rawHints.length]; 5711 5712 int numHints = rawHints.length; 5713 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 5714 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 5715 } 5716 setAutofillHints(hints); 5717 } 5718 break; 5719 case R.styleable.View_importantForAutofill: 5720 if (a.peekValue(attr) != null) { 5721 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 5722 } 5723 break; 5724 case R.styleable.View_defaultFocusHighlightEnabled: 5725 if (a.peekValue(attr) != null) { 5726 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); 5727 } 5728 break; 5729 case R.styleable.View_screenReaderFocusable: 5730 if (a.peekValue(attr) != null) { 5731 setScreenReaderFocusable(a.getBoolean(attr, false)); 5732 } 5733 break; 5734 case R.styleable.View_accessibilityPaneTitle: 5735 if (a.peekValue(attr) != null) { 5736 setAccessibilityPaneTitle(a.getString(attr)); 5737 } 5738 break; 5739 case R.styleable.View_outlineSpotShadowColor: 5740 setOutlineSpotShadowColor(a.getColor(attr, Color.BLACK)); 5741 break; 5742 case R.styleable.View_outlineAmbientShadowColor: 5743 setOutlineAmbientShadowColor(a.getColor(attr, Color.BLACK)); 5744 break; 5745 case com.android.internal.R.styleable.View_accessibilityHeading: 5746 setAccessibilityHeading(a.getBoolean(attr, false)); 5747 break; 5748 case R.styleable.View_forceDarkAllowed: 5749 mRenderNode.setForceDarkAllowed(a.getBoolean(attr, true)); 5750 break; 5751 } 5752 } 5753 5754 setOverScrollMode(overScrollMode); 5755 5756 // Cache start/end user padding as we cannot fully resolve padding here (we don't have yet 5757 // the resolved layout direction). Those cached values will be used later during padding 5758 // resolution. 5759 mUserPaddingStart = startPadding; 5760 mUserPaddingEnd = endPadding; 5761 5762 if (background != null) { 5763 setBackground(background); 5764 } 5765 5766 // setBackground above will record that padding is currently provided by the background. 5767 // If we have padding specified via xml, record that here instead and use it. 5768 mLeftPaddingDefined = leftPaddingDefined; 5769 mRightPaddingDefined = rightPaddingDefined; 5770 5771 // Valid paddingHorizontal/paddingVertical beats leftPadding, rightPadding, topPadding, 5772 // bottomPadding, and padding set by background. Valid padding beats everything. 5773 if (padding >= 0) { 5774 leftPadding = padding; 5775 topPadding = padding; 5776 rightPadding = padding; 5777 bottomPadding = padding; 5778 mUserPaddingLeftInitial = padding; 5779 mUserPaddingRightInitial = padding; 5780 } else { 5781 if (paddingHorizontal >= 0) { 5782 leftPadding = paddingHorizontal; 5783 rightPadding = paddingHorizontal; 5784 mUserPaddingLeftInitial = paddingHorizontal; 5785 mUserPaddingRightInitial = paddingHorizontal; 5786 } 5787 if (paddingVertical >= 0) { 5788 topPadding = paddingVertical; 5789 bottomPadding = paddingVertical; 5790 } 5791 } 5792 5793 if (isRtlCompatibilityMode()) { 5794 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 5795 // left / right padding are used if defined (meaning here nothing to do). If they are not 5796 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 5797 // start / end and resolve them as left / right (layout direction is not taken into account). 5798 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5799 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5800 // defined. 5801 if (!mLeftPaddingDefined && startPaddingDefined) { 5802 leftPadding = startPadding; 5803 } 5804 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 5805 if (!mRightPaddingDefined && endPaddingDefined) { 5806 rightPadding = endPadding; 5807 } 5808 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 5809 } else { 5810 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 5811 // values defined. Otherwise, left /right values are used. 5812 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5813 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5814 // defined. 5815 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 5816 5817 if (mLeftPaddingDefined && !hasRelativePadding) { 5818 mUserPaddingLeftInitial = leftPadding; 5819 } 5820 if (mRightPaddingDefined && !hasRelativePadding) { 5821 mUserPaddingRightInitial = rightPadding; 5822 } 5823 } 5824 5825 // mPaddingTop and mPaddingBottom may have been set by setBackground(Drawable) so must pass 5826 // them on if topPadding or bottomPadding are not valid. 5827 internalSetPadding( 5828 mUserPaddingLeftInitial, 5829 topPadding >= 0 ? topPadding : mPaddingTop, 5830 mUserPaddingRightInitial, 5831 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 5832 5833 if (viewFlagMasks != 0) { 5834 setFlags(viewFlagValues, viewFlagMasks); 5835 } 5836 5837 if (initializeScrollbars) { 5838 initializeScrollbarsInternal(a); 5839 } 5840 5841 if (initializeScrollIndicators) { 5842 initializeScrollIndicatorsInternal(); 5843 } 5844 5845 a.recycle(); 5846 5847 // Needs to be called after mViewFlags is set 5848 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5849 recomputePadding(); 5850 } 5851 5852 if (x != 0 || y != 0) { 5853 scrollTo(x, y); 5854 } 5855 5856 if (transformSet) { 5857 setTranslationX(tx); 5858 setTranslationY(ty); 5859 setTranslationZ(tz); 5860 setElevation(elevation); 5861 setRotation(rotation); 5862 setRotationX(rotationX); 5863 setRotationY(rotationY); 5864 setScaleX(sx); 5865 setScaleY(sy); 5866 } 5867 5868 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 5869 setScrollContainer(true); 5870 } 5871 5872 computeOpaqueFlags(); 5873 } 5874 5875 /** 5876 * Returns the ordered list of resource ID that are considered when resolving attribute values 5877 * for this {@link View}. The list will include layout resource ID if the View is inflated from 5878 * XML. It will also include a set of explicit styles if specified in XML using 5879 * {@code style="..."}. Finally, it will include the default styles resolved from the theme. 5880 * 5881 * <p> 5882 * <b>Note:</b> this method will only return actual values if the view attribute debugging 5883 * is enabled in Android developer options. 5884 * 5885 * @param attribute Attribute resource ID for which the resolution stack should be returned. 5886 * @return ordered list of resource ID that are considered when resolving attribute values for 5887 * this {@link View}. 5888 */ 5889 @NonNull 5890 public int[] getAttributeResolutionStack(@AttrRes int attribute) { 5891 if (!sDebugViewAttributes 5892 || mAttributeResolutionStacks == null 5893 || mAttributeResolutionStacks.get(attribute) == null) { 5894 return new int[0]; 5895 } 5896 int[] attributeResolutionStack = mAttributeResolutionStacks.get(attribute); 5897 int stackSize = attributeResolutionStack.length; 5898 if (mSourceLayoutId != ID_NULL) { 5899 stackSize++; 5900 } 5901 5902 int currentIndex = 0; 5903 int[] stack = new int[stackSize]; 5904 5905 if (mSourceLayoutId != ID_NULL) { 5906 stack[currentIndex] = mSourceLayoutId; 5907 currentIndex++; 5908 } 5909 for (int i = 0; i < attributeResolutionStack.length; i++) { 5910 stack[currentIndex] = attributeResolutionStack[i]; 5911 currentIndex++; 5912 } 5913 return stack; 5914 } 5915 5916 /** 5917 * Returns the mapping of attribute resource ID to source resource ID where the attribute value 5918 * was set. Source resource ID can either be a layout resource ID, if the value was set in XML 5919 * within the View tag, or a style resource ID, if the attribute was set in a style. The source 5920 * resource value will be one of the resource IDs from {@link #getAttributeSourceResourceMap()}. 5921 * 5922 * <p> 5923 * <b>Note:</b> this method will only return actual values if the view attribute debugging 5924 * is enabled in Android developer options. 5925 * 5926 * @return mapping of attribute resource ID to source resource ID where the attribute value 5927 * was set. 5928 */ 5929 @NonNull 5930 public Map<Integer, Integer> getAttributeSourceResourceMap() { 5931 HashMap<Integer, Integer> map = new HashMap<>(); 5932 if (!sDebugViewAttributes || mAttributeSourceResId == null) { 5933 return map; 5934 } 5935 for (int i = 0; i < mAttributeSourceResId.size(); i++) { 5936 map.put(mAttributeSourceResId.keyAt(i), mAttributeSourceResId.valueAt(i)); 5937 } 5938 return map; 5939 } 5940 5941 /** 5942 * Returns the resource ID for the style specified using {@code style="..."} in the 5943 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise if not 5944 * specified or otherwise not applicable. 5945 * <p> 5946 * Each {@link View} can have an explicit style specified in the layout file. 5947 * This style is used first during the {@link View} attribute resolution, then if an attribute 5948 * is not defined there the resource system looks at default style and theme as fallbacks. 5949 * 5950 * <p> 5951 * <b>Note:</b> this method will only return actual values if the view attribute debugging 5952 * is enabled in Android developer options. 5953 * 5954 * @return The resource ID for the style specified using {@code style="..."} in the 5955 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise 5956 * if not specified or otherwise not applicable. 5957 */ 5958 @StyleRes 5959 public int getExplicitStyle() { 5960 if (!sDebugViewAttributes) { 5961 return ID_NULL; 5962 } 5963 return mExplicitStyle; 5964 } 5965 5966 /** 5967 * An implementation of OnClickListener that attempts to lazily load a 5968 * named click handling method from a parent or ancestor context. 5969 */ 5970 private static class DeclaredOnClickListener implements OnClickListener { 5971 private final View mHostView; 5972 private final String mMethodName; 5973 5974 private Method mResolvedMethod; 5975 private Context mResolvedContext; 5976 5977 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 5978 mHostView = hostView; 5979 mMethodName = methodName; 5980 } 5981 5982 @Override 5983 public void onClick(@NonNull View v) { 5984 if (mResolvedMethod == null) { 5985 resolveMethod(mHostView.getContext(), mMethodName); 5986 } 5987 5988 try { 5989 mResolvedMethod.invoke(mResolvedContext, v); 5990 } catch (IllegalAccessException e) { 5991 throw new IllegalStateException( 5992 "Could not execute non-public method for android:onClick", e); 5993 } catch (InvocationTargetException e) { 5994 throw new IllegalStateException( 5995 "Could not execute method for android:onClick", e); 5996 } 5997 } 5998 5999 @NonNull 6000 private void resolveMethod(@Nullable Context context, @NonNull String name) { 6001 while (context != null) { 6002 try { 6003 if (!context.isRestricted()) { 6004 final Method method = context.getClass().getMethod(mMethodName, View.class); 6005 if (method != null) { 6006 mResolvedMethod = method; 6007 mResolvedContext = context; 6008 return; 6009 } 6010 } 6011 } catch (NoSuchMethodException e) { 6012 // Failed to find method, keep searching up the hierarchy. 6013 } 6014 6015 if (context instanceof ContextWrapper) { 6016 context = ((ContextWrapper) context).getBaseContext(); 6017 } else { 6018 // Can't search up the hierarchy, null out and fail. 6019 context = null; 6020 } 6021 } 6022 6023 final int id = mHostView.getId(); 6024 final String idText = id == NO_ID ? "" : " with id '" 6025 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 6026 throw new IllegalStateException("Could not find method " + mMethodName 6027 + "(View) in a parent or ancestor Context for android:onClick " 6028 + "attribute defined on view " + mHostView.getClass() + idText); 6029 } 6030 } 6031 6032 /** 6033 * Non-public constructor for use in testing 6034 */ 6035 @UnsupportedAppUsage 6036 View() { 6037 mResources = null; 6038 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 6039 } 6040 6041 final boolean debugDraw() { 6042 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 6043 } 6044 6045 private static SparseArray<String> getAttributeMap() { 6046 if (mAttributeMap == null) { 6047 mAttributeMap = new SparseArray<>(); 6048 } 6049 return mAttributeMap; 6050 } 6051 6052 private void retrieveExplicitStyle(@NonNull Resources.Theme theme, 6053 @Nullable AttributeSet attrs) { 6054 if (!sDebugViewAttributes) { 6055 return; 6056 } 6057 mExplicitStyle = theme.getExplicitStyle(attrs); 6058 } 6059 6060 /** 6061 * Stores debugging information about attributes. This should be called in a constructor by 6062 * every custom {@link View} that uses a custom styleable. If the custom view does not call it, 6063 * then the custom attributes used by this view will not be visible in layout inspection tools. 6064 * 6065 * @param context Context under which this view is created. 6066 * @param styleable A reference to styleable array R.styleable.Foo 6067 * @param attrs AttributeSet used to construct this view. 6068 * @param t Resolved {@link TypedArray} returned by a call to 6069 * {@link Resources#obtainAttributes(AttributeSet, int[])}. 6070 * @param defStyleAttr Default style attribute passed into the view constructor. 6071 * @param defStyleRes Default style resource passed into the view constructor. 6072 */ 6073 public final void saveAttributeDataForStyleable(@NonNull Context context, 6074 @NonNull int[] styleable, @Nullable AttributeSet attrs, @NonNull TypedArray t, 6075 int defStyleAttr, int defStyleRes) { 6076 if (!sDebugViewAttributes) { 6077 return; 6078 } 6079 6080 int[] attributeResolutionStack = context.getTheme().getAttributeResolutionStack( 6081 defStyleAttr, defStyleRes, mExplicitStyle); 6082 6083 if (mAttributeResolutionStacks == null) { 6084 mAttributeResolutionStacks = new SparseArray<>(); 6085 } 6086 6087 if (mAttributeSourceResId == null) { 6088 mAttributeSourceResId = new SparseIntArray(); 6089 } 6090 6091 final int indexCount = t.getIndexCount(); 6092 for (int j = 0; j < indexCount; ++j) { 6093 final int index = t.getIndex(j); 6094 mAttributeSourceResId.append(styleable[index], t.getSourceResourceId(index, 0)); 6095 mAttributeResolutionStacks.append(styleable[index], attributeResolutionStack); 6096 } 6097 } 6098 6099 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 6100 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 6101 final int indexCount = t.getIndexCount(); 6102 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 6103 6104 int i = 0; 6105 6106 // Store raw XML attributes. 6107 for (int j = 0; j < attrsCount; ++j) { 6108 attributes[i] = attrs.getAttributeName(j); 6109 attributes[i + 1] = attrs.getAttributeValue(j); 6110 i += 2; 6111 } 6112 6113 // Store resolved styleable attributes. 6114 final Resources res = t.getResources(); 6115 final SparseArray<String> attributeMap = getAttributeMap(); 6116 for (int j = 0; j < indexCount; ++j) { 6117 final int index = t.getIndex(j); 6118 if (!t.hasValueOrEmpty(index)) { 6119 // Value is undefined. Skip it. 6120 continue; 6121 } 6122 6123 final int resourceId = t.getResourceId(index, 0); 6124 if (resourceId == 0) { 6125 // Value is not a reference. Skip it. 6126 continue; 6127 } 6128 6129 String resourceName = attributeMap.get(resourceId); 6130 if (resourceName == null) { 6131 try { 6132 resourceName = res.getResourceName(resourceId); 6133 } catch (Resources.NotFoundException e) { 6134 resourceName = "0x" + Integer.toHexString(resourceId); 6135 } 6136 attributeMap.put(resourceId, resourceName); 6137 } 6138 6139 attributes[i] = resourceName; 6140 attributes[i + 1] = t.getString(index); 6141 i += 2; 6142 } 6143 6144 // Trim to fit contents. 6145 final String[] trimmed = new String[i]; 6146 System.arraycopy(attributes, 0, trimmed, 0, i); 6147 mAttributes = trimmed; 6148 } 6149 6150 @Override 6151 public String toString() { 6152 StringBuilder out = new StringBuilder(128); 6153 out.append(getClass().getName()); 6154 out.append('{'); 6155 out.append(Integer.toHexString(System.identityHashCode(this))); 6156 out.append(' '); 6157 switch (mViewFlags&VISIBILITY_MASK) { 6158 case VISIBLE: out.append('V'); break; 6159 case INVISIBLE: out.append('I'); break; 6160 case GONE: out.append('G'); break; 6161 default: out.append('.'); break; 6162 } 6163 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 6164 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 6165 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 6166 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 6167 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 6168 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 6169 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 6170 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 6171 out.append(' '); 6172 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 6173 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 6174 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 6175 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 6176 out.append('p'); 6177 } else { 6178 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 6179 } 6180 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 6181 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 6182 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 6183 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 6184 out.append(' '); 6185 out.append(mLeft); 6186 out.append(','); 6187 out.append(mTop); 6188 out.append('-'); 6189 out.append(mRight); 6190 out.append(','); 6191 out.append(mBottom); 6192 final int id = getId(); 6193 if (id != NO_ID) { 6194 out.append(" #"); 6195 out.append(Integer.toHexString(id)); 6196 final Resources r = mResources; 6197 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 6198 try { 6199 String pkgname; 6200 switch (id&0xff000000) { 6201 case 0x7f000000: 6202 pkgname="app"; 6203 break; 6204 case 0x01000000: 6205 pkgname="android"; 6206 break; 6207 default: 6208 pkgname = r.getResourcePackageName(id); 6209 break; 6210 } 6211 String typename = r.getResourceTypeName(id); 6212 String entryname = r.getResourceEntryName(id); 6213 out.append(" "); 6214 out.append(pkgname); 6215 out.append(":"); 6216 out.append(typename); 6217 out.append("/"); 6218 out.append(entryname); 6219 } catch (Resources.NotFoundException e) { 6220 } 6221 } 6222 } 6223 if (mAutofillId != null) { 6224 out.append(" aid="); out.append(mAutofillId); 6225 } 6226 out.append("}"); 6227 return out.toString(); 6228 } 6229 6230 /** 6231 * <p> 6232 * Initializes the fading edges from a given set of styled attributes. This 6233 * method should be called by subclasses that need fading edges and when an 6234 * instance of these subclasses is created programmatically rather than 6235 * being inflated from XML. This method is automatically called when the XML 6236 * is inflated. 6237 * </p> 6238 * 6239 * @param a the styled attributes set to initialize the fading edges from 6240 * 6241 * @removed 6242 */ 6243 protected void initializeFadingEdge(TypedArray a) { 6244 // This method probably shouldn't have been included in the SDK to begin with. 6245 // It relies on 'a' having been initialized using an attribute filter array that is 6246 // not publicly available to the SDK. The old method has been renamed 6247 // to initializeFadingEdgeInternal and hidden for framework use only; 6248 // this one initializes using defaults to make it safe to call for apps. 6249 6250 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 6251 6252 initializeFadingEdgeInternal(arr); 6253 6254 arr.recycle(); 6255 } 6256 6257 /** 6258 * <p> 6259 * Initializes the fading edges from a given set of styled attributes. This 6260 * method should be called by subclasses that need fading edges and when an 6261 * instance of these subclasses is created programmatically rather than 6262 * being inflated from XML. This method is automatically called when the XML 6263 * is inflated. 6264 * </p> 6265 * 6266 * @param a the styled attributes set to initialize the fading edges from 6267 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 6268 */ 6269 protected void initializeFadingEdgeInternal(TypedArray a) { 6270 initScrollCache(); 6271 6272 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 6273 R.styleable.View_fadingEdgeLength, 6274 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 6275 } 6276 6277 /** 6278 * Returns the size of the vertical faded edges used to indicate that more 6279 * content in this view is visible. 6280 * 6281 * @return The size in pixels of the vertical faded edge or 0 if vertical 6282 * faded edges are not enabled for this view. 6283 * @attr ref android.R.styleable#View_fadingEdgeLength 6284 */ 6285 public int getVerticalFadingEdgeLength() { 6286 if (isVerticalFadingEdgeEnabled()) { 6287 ScrollabilityCache cache = mScrollCache; 6288 if (cache != null) { 6289 return cache.fadingEdgeLength; 6290 } 6291 } 6292 return 0; 6293 } 6294 6295 /** 6296 * Set the size of the faded edge used to indicate that more content in this 6297 * view is available. Will not change whether the fading edge is enabled; use 6298 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 6299 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 6300 * for the vertical or horizontal fading edges. 6301 * 6302 * @param length The size in pixels of the faded edge used to indicate that more 6303 * content in this view is visible. 6304 */ 6305 public void setFadingEdgeLength(int length) { 6306 initScrollCache(); 6307 mScrollCache.fadingEdgeLength = length; 6308 } 6309 6310 /** 6311 * Returns the size of the horizontal faded edges used to indicate that more 6312 * content in this view is visible. 6313 * 6314 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 6315 * faded edges are not enabled for this view. 6316 * @attr ref android.R.styleable#View_fadingEdgeLength 6317 */ 6318 public int getHorizontalFadingEdgeLength() { 6319 if (isHorizontalFadingEdgeEnabled()) { 6320 ScrollabilityCache cache = mScrollCache; 6321 if (cache != null) { 6322 return cache.fadingEdgeLength; 6323 } 6324 } 6325 return 0; 6326 } 6327 6328 /** 6329 * Returns the width of the vertical scrollbar. 6330 * 6331 * @return The width in pixels of the vertical scrollbar or 0 if there 6332 * is no vertical scrollbar. 6333 */ 6334 public int getVerticalScrollbarWidth() { 6335 ScrollabilityCache cache = mScrollCache; 6336 if (cache != null) { 6337 ScrollBarDrawable scrollBar = cache.scrollBar; 6338 if (scrollBar != null) { 6339 int size = scrollBar.getSize(true); 6340 if (size <= 0) { 6341 size = cache.scrollBarSize; 6342 } 6343 return size; 6344 } 6345 return 0; 6346 } 6347 return 0; 6348 } 6349 6350 /** 6351 * Returns the height of the horizontal scrollbar. 6352 * 6353 * @return The height in pixels of the horizontal scrollbar or 0 if 6354 * there is no horizontal scrollbar. 6355 */ 6356 protected int getHorizontalScrollbarHeight() { 6357 ScrollabilityCache cache = mScrollCache; 6358 if (cache != null) { 6359 ScrollBarDrawable scrollBar = cache.scrollBar; 6360 if (scrollBar != null) { 6361 int size = scrollBar.getSize(false); 6362 if (size <= 0) { 6363 size = cache.scrollBarSize; 6364 } 6365 return size; 6366 } 6367 return 0; 6368 } 6369 return 0; 6370 } 6371 6372 /** 6373 * <p> 6374 * Initializes the scrollbars from a given set of styled attributes. This 6375 * method should be called by subclasses that need scrollbars and when an 6376 * instance of these subclasses is created programmatically rather than 6377 * being inflated from XML. This method is automatically called when the XML 6378 * is inflated. 6379 * </p> 6380 * 6381 * @param a the styled attributes set to initialize the scrollbars from 6382 * 6383 * @removed 6384 */ 6385 protected void initializeScrollbars(TypedArray a) { 6386 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 6387 // using the View filter array which is not available to the SDK. As such, internal 6388 // framework usage now uses initializeScrollbarsInternal and we grab a default 6389 // TypedArray with the right filter instead here. 6390 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 6391 6392 initializeScrollbarsInternal(arr); 6393 6394 // We ignored the method parameter. Recycle the one we actually did use. 6395 arr.recycle(); 6396 } 6397 6398 private void initializeScrollBarDrawable() { 6399 initScrollCache(); 6400 6401 if (mScrollCache.scrollBar == null) { 6402 mScrollCache.scrollBar = new ScrollBarDrawable(); 6403 mScrollCache.scrollBar.setState(getDrawableState()); 6404 mScrollCache.scrollBar.setCallback(this); 6405 } 6406 } 6407 6408 /** 6409 * <p> 6410 * Initializes the scrollbars from a given set of styled attributes. This 6411 * method should be called by subclasses that need scrollbars and when an 6412 * instance of these subclasses is created programmatically rather than 6413 * being inflated from XML. This method is automatically called when the XML 6414 * is inflated. 6415 * </p> 6416 * 6417 * @param a the styled attributes set to initialize the scrollbars from 6418 * @hide 6419 */ 6420 @UnsupportedAppUsage 6421 protected void initializeScrollbarsInternal(TypedArray a) { 6422 initScrollCache(); 6423 6424 final ScrollabilityCache scrollabilityCache = mScrollCache; 6425 6426 if (scrollabilityCache.scrollBar == null) { 6427 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 6428 scrollabilityCache.scrollBar.setState(getDrawableState()); 6429 scrollabilityCache.scrollBar.setCallback(this); 6430 } 6431 6432 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 6433 6434 if (!fadeScrollbars) { 6435 scrollabilityCache.state = ScrollabilityCache.ON; 6436 } 6437 scrollabilityCache.fadeScrollBars = fadeScrollbars; 6438 6439 6440 scrollabilityCache.scrollBarFadeDuration = a.getInt( 6441 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 6442 .getScrollBarFadeDuration()); 6443 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 6444 R.styleable.View_scrollbarDefaultDelayBeforeFade, 6445 ViewConfiguration.getScrollDefaultDelay()); 6446 6447 6448 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 6449 com.android.internal.R.styleable.View_scrollbarSize, 6450 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 6451 6452 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 6453 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 6454 6455 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 6456 if (thumb != null) { 6457 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 6458 } 6459 6460 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 6461 false); 6462 if (alwaysDraw) { 6463 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 6464 } 6465 6466 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 6467 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 6468 6469 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 6470 if (thumb != null) { 6471 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 6472 } 6473 6474 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 6475 false); 6476 if (alwaysDraw) { 6477 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 6478 } 6479 6480 // Apply layout direction to the new Drawables if needed 6481 final int layoutDirection = getLayoutDirection(); 6482 if (track != null) { 6483 track.setLayoutDirection(layoutDirection); 6484 } 6485 if (thumb != null) { 6486 thumb.setLayoutDirection(layoutDirection); 6487 } 6488 6489 // Re-apply user/background padding so that scrollbar(s) get added 6490 resolvePadding(); 6491 } 6492 6493 /** 6494 * Defines the vertical scrollbar thumb drawable 6495 * @attr ref android.R.styleable#View_scrollbarThumbVertical 6496 * 6497 * @see #awakenScrollBars(int) 6498 * @see #isVerticalScrollBarEnabled() 6499 * @see #setVerticalScrollBarEnabled(boolean) 6500 */ 6501 public void setVerticalScrollbarThumbDrawable(@Nullable Drawable drawable) { 6502 initializeScrollBarDrawable(); 6503 mScrollCache.scrollBar.setVerticalThumbDrawable(drawable); 6504 } 6505 6506 /** 6507 * Defines the vertical scrollbar track drawable 6508 * @attr ref android.R.styleable#View_scrollbarTrackVertical 6509 * 6510 * @see #awakenScrollBars(int) 6511 * @see #isVerticalScrollBarEnabled() 6512 * @see #setVerticalScrollBarEnabled(boolean) 6513 */ 6514 public void setVerticalScrollbarTrackDrawable(@Nullable Drawable drawable) { 6515 initializeScrollBarDrawable(); 6516 mScrollCache.scrollBar.setVerticalTrackDrawable(drawable); 6517 } 6518 6519 /** 6520 * Defines the horizontal thumb drawable 6521 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 6522 * 6523 * @see #awakenScrollBars(int) 6524 * @see #isHorizontalScrollBarEnabled() 6525 * @see #setHorizontalScrollBarEnabled(boolean) 6526 */ 6527 public void setHorizontalScrollbarThumbDrawable(@Nullable Drawable drawable) { 6528 initializeScrollBarDrawable(); 6529 mScrollCache.scrollBar.setHorizontalThumbDrawable(drawable); 6530 } 6531 6532 /** 6533 * Defines the horizontal track drawable 6534 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 6535 * 6536 * @see #awakenScrollBars(int) 6537 * @see #isHorizontalScrollBarEnabled() 6538 * @see #setHorizontalScrollBarEnabled(boolean) 6539 */ 6540 public void setHorizontalScrollbarTrackDrawable(@Nullable Drawable drawable) { 6541 initializeScrollBarDrawable(); 6542 mScrollCache.scrollBar.setHorizontalTrackDrawable(drawable); 6543 } 6544 6545 /** 6546 * Returns the currently configured Drawable for the thumb of the vertical scroll bar if it 6547 * exists, null otherwise. 6548 * 6549 * @see #awakenScrollBars(int) 6550 * @see #isVerticalScrollBarEnabled() 6551 * @see #setVerticalScrollBarEnabled(boolean) 6552 */ 6553 public @Nullable Drawable getVerticalScrollbarThumbDrawable() { 6554 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalThumbDrawable() : null; 6555 } 6556 6557 /** 6558 * Returns the currently configured Drawable for the track of the vertical scroll bar if it 6559 * exists, null otherwise. 6560 * 6561 * @see #awakenScrollBars(int) 6562 * @see #isVerticalScrollBarEnabled() 6563 * @see #setVerticalScrollBarEnabled(boolean) 6564 */ 6565 public @Nullable Drawable getVerticalScrollbarTrackDrawable() { 6566 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalTrackDrawable() : null; 6567 } 6568 6569 /** 6570 * Returns the currently configured Drawable for the thumb of the horizontal scroll bar if it 6571 * exists, null otherwise. 6572 * 6573 * @see #awakenScrollBars(int) 6574 * @see #isHorizontalScrollBarEnabled() 6575 * @see #setHorizontalScrollBarEnabled(boolean) 6576 */ 6577 public @Nullable Drawable getHorizontalScrollbarThumbDrawable() { 6578 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalThumbDrawable() : null; 6579 } 6580 6581 /** 6582 * Returns the currently configured Drawable for the track of the horizontal scroll bar if it 6583 * exists, null otherwise. 6584 * 6585 * @see #awakenScrollBars(int) 6586 * @see #isHorizontalScrollBarEnabled() 6587 * @see #setHorizontalScrollBarEnabled(boolean) 6588 */ 6589 public @Nullable Drawable getHorizontalScrollbarTrackDrawable() { 6590 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalTrackDrawable() : null; 6591 } 6592 6593 private void initializeScrollIndicatorsInternal() { 6594 // Some day maybe we'll break this into top/left/start/etc. and let the 6595 // client control it. Until then, you can have any scroll indicator you 6596 // want as long as it's a 1dp foreground-colored rectangle. 6597 if (mScrollIndicatorDrawable == null) { 6598 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 6599 } 6600 } 6601 6602 /** 6603 * <p> 6604 * Initalizes the scrollability cache if necessary. 6605 * </p> 6606 */ 6607 private void initScrollCache() { 6608 if (mScrollCache == null) { 6609 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 6610 } 6611 } 6612 6613 @UnsupportedAppUsage 6614 private ScrollabilityCache getScrollCache() { 6615 initScrollCache(); 6616 return mScrollCache; 6617 } 6618 6619 /** 6620 * Set the position of the vertical scroll bar. Should be one of 6621 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 6622 * {@link #SCROLLBAR_POSITION_RIGHT}. 6623 * 6624 * @param position Where the vertical scroll bar should be positioned. 6625 */ 6626 public void setVerticalScrollbarPosition(int position) { 6627 if (mVerticalScrollbarPosition != position) { 6628 mVerticalScrollbarPosition = position; 6629 computeOpaqueFlags(); 6630 resolvePadding(); 6631 } 6632 } 6633 6634 /** 6635 * @return The position where the vertical scroll bar will show, if applicable. 6636 * @see #setVerticalScrollbarPosition(int) 6637 */ 6638 public int getVerticalScrollbarPosition() { 6639 return mVerticalScrollbarPosition; 6640 } 6641 6642 boolean isOnScrollbar(float x, float y) { 6643 if (mScrollCache == null) { 6644 return false; 6645 } 6646 x += getScrollX(); 6647 y += getScrollY(); 6648 final boolean canScrollVertically = 6649 computeVerticalScrollRange() > computeVerticalScrollExtent(); 6650 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden() && canScrollVertically) { 6651 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6652 getVerticalScrollBarBounds(null, touchBounds); 6653 if (touchBounds.contains((int) x, (int) y)) { 6654 return true; 6655 } 6656 } 6657 final boolean canScrollHorizontally = 6658 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 6659 if (isHorizontalScrollBarEnabled() && canScrollHorizontally) { 6660 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6661 getHorizontalScrollBarBounds(null, touchBounds); 6662 if (touchBounds.contains((int) x, (int) y)) { 6663 return true; 6664 } 6665 } 6666 return false; 6667 } 6668 6669 @UnsupportedAppUsage 6670 boolean isOnScrollbarThumb(float x, float y) { 6671 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 6672 } 6673 6674 private boolean isOnVerticalScrollbarThumb(float x, float y) { 6675 if (mScrollCache == null || !isVerticalScrollBarEnabled() || isVerticalScrollBarHidden()) { 6676 return false; 6677 } 6678 final int range = computeVerticalScrollRange(); 6679 final int extent = computeVerticalScrollExtent(); 6680 if (range > extent) { 6681 x += getScrollX(); 6682 y += getScrollY(); 6683 final Rect bounds = mScrollCache.mScrollBarBounds; 6684 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6685 getVerticalScrollBarBounds(bounds, touchBounds); 6686 final int offset = computeVerticalScrollOffset(); 6687 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 6688 extent, range); 6689 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 6690 extent, range, offset); 6691 final int thumbTop = bounds.top + thumbOffset; 6692 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 6693 if (x >= touchBounds.left && x <= touchBounds.right 6694 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 6695 return true; 6696 } 6697 } 6698 return false; 6699 } 6700 6701 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 6702 if (mScrollCache == null || !isHorizontalScrollBarEnabled()) { 6703 return false; 6704 } 6705 final int range = computeHorizontalScrollRange(); 6706 final int extent = computeHorizontalScrollExtent(); 6707 if (range > extent) { 6708 x += getScrollX(); 6709 y += getScrollY(); 6710 final Rect bounds = mScrollCache.mScrollBarBounds; 6711 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6712 getHorizontalScrollBarBounds(bounds, touchBounds); 6713 final int offset = computeHorizontalScrollOffset(); 6714 6715 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 6716 extent, range); 6717 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 6718 extent, range, offset); 6719 final int thumbLeft = bounds.left + thumbOffset; 6720 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 6721 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 6722 && y >= touchBounds.top && y <= touchBounds.bottom) { 6723 return true; 6724 } 6725 } 6726 return false; 6727 } 6728 6729 @UnsupportedAppUsage 6730 boolean isDraggingScrollBar() { 6731 return mScrollCache != null 6732 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 6733 } 6734 6735 /** 6736 * Sets the state of all scroll indicators. 6737 * <p> 6738 * See {@link #setScrollIndicators(int, int)} for usage information. 6739 * 6740 * @param indicators a bitmask of indicators that should be enabled, or 6741 * {@code 0} to disable all indicators 6742 * @see #setScrollIndicators(int, int) 6743 * @see #getScrollIndicators() 6744 * @attr ref android.R.styleable#View_scrollIndicators 6745 */ 6746 public void setScrollIndicators(@ScrollIndicators int indicators) { 6747 setScrollIndicators(indicators, 6748 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 6749 } 6750 6751 /** 6752 * Sets the state of the scroll indicators specified by the mask. To change 6753 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 6754 * <p> 6755 * When a scroll indicator is enabled, it will be displayed if the view 6756 * can scroll in the direction of the indicator. 6757 * <p> 6758 * Multiple indicator types may be enabled or disabled by passing the 6759 * logical OR of the desired types. If multiple types are specified, they 6760 * will all be set to the same enabled state. 6761 * <p> 6762 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 6763 * 6764 * @param indicators the indicator direction, or the logical OR of multiple 6765 * indicator directions. One or more of: 6766 * <ul> 6767 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 6768 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 6769 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 6770 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 6771 * <li>{@link #SCROLL_INDICATOR_START}</li> 6772 * <li>{@link #SCROLL_INDICATOR_END}</li> 6773 * </ul> 6774 * @see #setScrollIndicators(int) 6775 * @see #getScrollIndicators() 6776 * @attr ref android.R.styleable#View_scrollIndicators 6777 */ 6778 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 6779 // Shift and sanitize mask. 6780 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 6781 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 6782 6783 // Shift and mask indicators. 6784 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 6785 indicators &= mask; 6786 6787 // Merge with non-masked flags. 6788 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 6789 6790 if (mPrivateFlags3 != updatedFlags) { 6791 mPrivateFlags3 = updatedFlags; 6792 6793 if (indicators != 0) { 6794 initializeScrollIndicatorsInternal(); 6795 } 6796 invalidate(); 6797 } 6798 } 6799 6800 /** 6801 * Returns a bitmask representing the enabled scroll indicators. 6802 * <p> 6803 * For example, if the top and left scroll indicators are enabled and all 6804 * other indicators are disabled, the return value will be 6805 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 6806 * <p> 6807 * To check whether the bottom scroll indicator is enabled, use the value 6808 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 6809 * 6810 * @return a bitmask representing the enabled scroll indicators 6811 */ 6812 @InspectableProperty(flagMapping = { 6813 @FlagEntry(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"), 6814 @FlagEntry(target = SCROLL_INDICATOR_TOP, name = "top"), 6815 @FlagEntry(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"), 6816 @FlagEntry(target = SCROLL_INDICATOR_LEFT, name = "left"), 6817 @FlagEntry(target = SCROLL_INDICATOR_RIGHT, name = "right"), 6818 @FlagEntry(target = SCROLL_INDICATOR_START, name = "start"), 6819 @FlagEntry(target = SCROLL_INDICATOR_END, name = "end") 6820 }) 6821 @ScrollIndicators 6822 public int getScrollIndicators() { 6823 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 6824 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 6825 } 6826 6827 @UnsupportedAppUsage 6828 ListenerInfo getListenerInfo() { 6829 if (mListenerInfo != null) { 6830 return mListenerInfo; 6831 } 6832 mListenerInfo = new ListenerInfo(); 6833 return mListenerInfo; 6834 } 6835 6836 /** 6837 * Register a callback to be invoked when the scroll X or Y positions of 6838 * this view change. 6839 * <p> 6840 * <b>Note:</b> Some views handle scrolling independently from View and may 6841 * have their own separate listeners for scroll-type events. For example, 6842 * {@link android.widget.ListView ListView} allows clients to register an 6843 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 6844 * to listen for changes in list scroll position. 6845 * 6846 * @param l The listener to notify when the scroll X or Y position changes. 6847 * @see android.view.View#getScrollX() 6848 * @see android.view.View#getScrollY() 6849 */ 6850 public void setOnScrollChangeListener(OnScrollChangeListener l) { 6851 getListenerInfo().mOnScrollChangeListener = l; 6852 } 6853 6854 /** 6855 * Register a callback to be invoked when focus of this view changed. 6856 * 6857 * @param l The callback that will run. 6858 */ 6859 public void setOnFocusChangeListener(OnFocusChangeListener l) { 6860 getListenerInfo().mOnFocusChangeListener = l; 6861 } 6862 6863 /** 6864 * Add a listener that will be called when the bounds of the view change due to 6865 * layout processing. 6866 * 6867 * @param listener The listener that will be called when layout bounds change. 6868 */ 6869 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 6870 ListenerInfo li = getListenerInfo(); 6871 if (li.mOnLayoutChangeListeners == null) { 6872 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 6873 } 6874 if (!li.mOnLayoutChangeListeners.contains(listener)) { 6875 li.mOnLayoutChangeListeners.add(listener); 6876 } 6877 } 6878 6879 /** 6880 * Remove a listener for layout changes. 6881 * 6882 * @param listener The listener for layout bounds change. 6883 */ 6884 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 6885 ListenerInfo li = mListenerInfo; 6886 if (li == null || li.mOnLayoutChangeListeners == null) { 6887 return; 6888 } 6889 li.mOnLayoutChangeListeners.remove(listener); 6890 } 6891 6892 /** 6893 * Add a listener for attach state changes. 6894 * 6895 * This listener will be called whenever this view is attached or detached 6896 * from a window. Remove the listener using 6897 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 6898 * 6899 * @param listener Listener to attach 6900 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 6901 */ 6902 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 6903 ListenerInfo li = getListenerInfo(); 6904 if (li.mOnAttachStateChangeListeners == null) { 6905 li.mOnAttachStateChangeListeners 6906 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 6907 } 6908 li.mOnAttachStateChangeListeners.add(listener); 6909 } 6910 6911 /** 6912 * Remove a listener for attach state changes. The listener will receive no further 6913 * notification of window attach/detach events. 6914 * 6915 * @param listener Listener to remove 6916 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 6917 */ 6918 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 6919 ListenerInfo li = mListenerInfo; 6920 if (li == null || li.mOnAttachStateChangeListeners == null) { 6921 return; 6922 } 6923 li.mOnAttachStateChangeListeners.remove(listener); 6924 } 6925 6926 /** 6927 * Returns the focus-change callback registered for this view. 6928 * 6929 * @return The callback, or null if one is not registered. 6930 */ 6931 public OnFocusChangeListener getOnFocusChangeListener() { 6932 ListenerInfo li = mListenerInfo; 6933 return li != null ? li.mOnFocusChangeListener : null; 6934 } 6935 6936 /** 6937 * Register a callback to be invoked when this view is clicked. If this view is not 6938 * clickable, it becomes clickable. 6939 * 6940 * @param l The callback that will run 6941 * 6942 * @see #setClickable(boolean) 6943 */ 6944 public void setOnClickListener(@Nullable OnClickListener l) { 6945 if (!isClickable()) { 6946 setClickable(true); 6947 } 6948 getListenerInfo().mOnClickListener = l; 6949 } 6950 6951 /** 6952 * Return whether this view has an attached OnClickListener. Returns 6953 * true if there is a listener, false if there is none. 6954 */ 6955 public boolean hasOnClickListeners() { 6956 ListenerInfo li = mListenerInfo; 6957 return (li != null && li.mOnClickListener != null); 6958 } 6959 6960 /** 6961 * Register a callback to be invoked when this view is clicked and held. If this view is not 6962 * long clickable, it becomes long clickable. 6963 * 6964 * @param l The callback that will run 6965 * 6966 * @see #setLongClickable(boolean) 6967 */ 6968 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 6969 if (!isLongClickable()) { 6970 setLongClickable(true); 6971 } 6972 getListenerInfo().mOnLongClickListener = l; 6973 } 6974 6975 /** 6976 * Register a callback to be invoked when this view is context clicked. If the view is not 6977 * context clickable, it becomes context clickable. 6978 * 6979 * @param l The callback that will run 6980 * @see #setContextClickable(boolean) 6981 */ 6982 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 6983 if (!isContextClickable()) { 6984 setContextClickable(true); 6985 } 6986 getListenerInfo().mOnContextClickListener = l; 6987 } 6988 6989 /** 6990 * Register a callback to be invoked when the context menu for this view is 6991 * being built. If this view is not long clickable, it becomes long clickable. 6992 * 6993 * @param l The callback that will run 6994 * 6995 */ 6996 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 6997 if (!isLongClickable()) { 6998 setLongClickable(true); 6999 } 7000 getListenerInfo().mOnCreateContextMenuListener = l; 7001 } 7002 7003 /** 7004 * Set an observer to collect stats for each frame rendered for this view. 7005 * 7006 * @hide 7007 */ 7008 public void addFrameMetricsListener(Window window, 7009 Window.OnFrameMetricsAvailableListener listener, 7010 Handler handler) { 7011 if (mAttachInfo != null) { 7012 if (mAttachInfo.mThreadedRenderer != null) { 7013 if (mFrameMetricsObservers == null) { 7014 mFrameMetricsObservers = new ArrayList<>(); 7015 } 7016 7017 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 7018 handler.getLooper(), listener); 7019 mFrameMetricsObservers.add(fmo); 7020 mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); 7021 } else { 7022 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7023 } 7024 } else { 7025 if (mFrameMetricsObservers == null) { 7026 mFrameMetricsObservers = new ArrayList<>(); 7027 } 7028 7029 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 7030 handler.getLooper(), listener); 7031 mFrameMetricsObservers.add(fmo); 7032 } 7033 } 7034 7035 /** 7036 * Remove observer configured to collect frame stats for this view. 7037 * 7038 * @hide 7039 */ 7040 public void removeFrameMetricsListener( 7041 Window.OnFrameMetricsAvailableListener listener) { 7042 ThreadedRenderer renderer = getThreadedRenderer(); 7043 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 7044 if (fmo == null) { 7045 throw new IllegalArgumentException( 7046 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 7047 } 7048 7049 if (mFrameMetricsObservers != null) { 7050 mFrameMetricsObservers.remove(fmo); 7051 if (renderer != null) { 7052 renderer.removeFrameMetricsObserver(fmo); 7053 } 7054 } 7055 } 7056 7057 private void registerPendingFrameMetricsObservers() { 7058 if (mFrameMetricsObservers != null) { 7059 ThreadedRenderer renderer = getThreadedRenderer(); 7060 if (renderer != null) { 7061 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 7062 renderer.addFrameMetricsObserver(fmo); 7063 } 7064 } else { 7065 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7066 } 7067 } 7068 } 7069 7070 private FrameMetricsObserver findFrameMetricsObserver( 7071 Window.OnFrameMetricsAvailableListener listener) { 7072 if (mFrameMetricsObservers != null) { 7073 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 7074 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 7075 if (observer.mListener == listener) { 7076 return observer; 7077 } 7078 } 7079 } 7080 7081 return null; 7082 } 7083 7084 /** @hide */ 7085 public void setNotifyAutofillManagerOnClick(boolean notify) { 7086 if (notify) { 7087 mPrivateFlags |= PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7088 } else { 7089 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7090 } 7091 } 7092 7093 private void notifyAutofillManagerOnClick() { 7094 if ((mPrivateFlags & PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK) != 0) { 7095 try { 7096 getAutofillManager().notifyViewClicked(this); 7097 } finally { 7098 // Set it to already called so it's not called twice when called by 7099 // performClickInternal() 7100 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7101 } 7102 } 7103 } 7104 7105 /** 7106 * Entry point for {@link #performClick()} - other methods on View should call it instead of 7107 * {@code performClick()} directly to make sure the autofill manager is notified when 7108 * necessary (as subclasses could extend {@code performClick()} without calling the parent's 7109 * method). 7110 */ 7111 private boolean performClickInternal() { 7112 // Must notify autofill manager before performing the click actions to avoid scenarios where 7113 // the app has a click listener that changes the state of views the autofill service might 7114 // be interested on. 7115 notifyAutofillManagerOnClick(); 7116 7117 return performClick(); 7118 } 7119 7120 /** 7121 * Call this view's OnClickListener, if it is defined. Performs all normal 7122 * actions associated with clicking: reporting accessibility event, playing 7123 * a sound, etc. 7124 * 7125 * @return True there was an assigned OnClickListener that was called, false 7126 * otherwise is returned. 7127 */ 7128 // NOTE: other methods on View should not call this method directly, but performClickInternal() 7129 // instead, to guarantee that the autofill manager is notified when necessary (as subclasses 7130 // could extend this method without calling super.performClick()). 7131 public boolean performClick() { 7132 // We still need to call this method to handle the cases where performClick() was called 7133 // externally, instead of through performClickInternal() 7134 notifyAutofillManagerOnClick(); 7135 7136 final boolean result; 7137 final ListenerInfo li = mListenerInfo; 7138 if (li != null && li.mOnClickListener != null) { 7139 playSoundEffect(SoundEffectConstants.CLICK); 7140 li.mOnClickListener.onClick(this); 7141 result = true; 7142 } else { 7143 result = false; 7144 } 7145 7146 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 7147 7148 notifyEnterOrExitForAutoFillIfNeeded(true); 7149 7150 return result; 7151 } 7152 7153 /** 7154 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 7155 * this only calls the listener, and does not do any associated clicking 7156 * actions like reporting an accessibility event. 7157 * 7158 * @return True there was an assigned OnClickListener that was called, false 7159 * otherwise is returned. 7160 */ 7161 public boolean callOnClick() { 7162 ListenerInfo li = mListenerInfo; 7163 if (li != null && li.mOnClickListener != null) { 7164 li.mOnClickListener.onClick(this); 7165 return true; 7166 } 7167 return false; 7168 } 7169 7170 /** 7171 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7172 * context menu if the OnLongClickListener did not consume the event. 7173 * 7174 * @return {@code true} if one of the above receivers consumed the event, 7175 * {@code false} otherwise 7176 */ 7177 public boolean performLongClick() { 7178 return performLongClickInternal(mLongClickX, mLongClickY); 7179 } 7180 7181 /** 7182 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7183 * context menu if the OnLongClickListener did not consume the event, 7184 * anchoring it to an (x,y) coordinate. 7185 * 7186 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 7187 * to disable anchoring 7188 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 7189 * to disable anchoring 7190 * @return {@code true} if one of the above receivers consumed the event, 7191 * {@code false} otherwise 7192 */ 7193 public boolean performLongClick(float x, float y) { 7194 mLongClickX = x; 7195 mLongClickY = y; 7196 final boolean handled = performLongClick(); 7197 mLongClickX = Float.NaN; 7198 mLongClickY = Float.NaN; 7199 return handled; 7200 } 7201 7202 /** 7203 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7204 * context menu if the OnLongClickListener did not consume the event, 7205 * optionally anchoring it to an (x,y) coordinate. 7206 * 7207 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 7208 * to disable anchoring 7209 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 7210 * to disable anchoring 7211 * @return {@code true} if one of the above receivers consumed the event, 7212 * {@code false} otherwise 7213 */ 7214 private boolean performLongClickInternal(float x, float y) { 7215 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 7216 7217 boolean handled = false; 7218 final ListenerInfo li = mListenerInfo; 7219 if (li != null && li.mOnLongClickListener != null) { 7220 handled = li.mOnLongClickListener.onLongClick(View.this); 7221 } 7222 if (!handled) { 7223 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 7224 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 7225 } 7226 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 7227 if (!handled) { 7228 handled = showLongClickTooltip((int) x, (int) y); 7229 } 7230 } 7231 if (handled) { 7232 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 7233 } 7234 return handled; 7235 } 7236 7237 /** 7238 * Call this view's OnContextClickListener, if it is defined. 7239 * 7240 * @param x the x coordinate of the context click 7241 * @param y the y coordinate of the context click 7242 * @return True if there was an assigned OnContextClickListener that consumed the event, false 7243 * otherwise. 7244 */ 7245 public boolean performContextClick(float x, float y) { 7246 return performContextClick(); 7247 } 7248 7249 /** 7250 * Call this view's OnContextClickListener, if it is defined. 7251 * 7252 * @return True if there was an assigned OnContextClickListener that consumed the event, false 7253 * otherwise. 7254 */ 7255 public boolean performContextClick() { 7256 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 7257 7258 boolean handled = false; 7259 ListenerInfo li = mListenerInfo; 7260 if (li != null && li.mOnContextClickListener != null) { 7261 handled = li.mOnContextClickListener.onContextClick(View.this); 7262 } 7263 if (handled) { 7264 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 7265 } 7266 return handled; 7267 } 7268 7269 /** 7270 * Performs button-related actions during a touch down event. 7271 * 7272 * @param event The event. 7273 * @return True if the down was consumed. 7274 * 7275 * @hide 7276 */ 7277 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 7278 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 7279 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 7280 showContextMenu(event.getX(), event.getY()); 7281 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 7282 return true; 7283 } 7284 return false; 7285 } 7286 7287 /** 7288 * Shows the context menu for this view. 7289 * 7290 * @return {@code true} if the context menu was shown, {@code false} 7291 * otherwise 7292 * @see #showContextMenu(float, float) 7293 */ 7294 public boolean showContextMenu() { 7295 return getParent().showContextMenuForChild(this); 7296 } 7297 7298 /** 7299 * Shows the context menu for this view anchored to the specified 7300 * view-relative coordinate. 7301 * 7302 * @param x the X coordinate in pixels relative to the view to which the 7303 * menu should be anchored, or {@link Float#NaN} to disable anchoring 7304 * @param y the Y coordinate in pixels relative to the view to which the 7305 * menu should be anchored, or {@link Float#NaN} to disable anchoring 7306 * @return {@code true} if the context menu was shown, {@code false} 7307 * otherwise 7308 */ 7309 public boolean showContextMenu(float x, float y) { 7310 return getParent().showContextMenuForChild(this, x, y); 7311 } 7312 7313 /** 7314 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 7315 * 7316 * @param callback Callback that will control the lifecycle of the action mode 7317 * @return The new action mode if it is started, null otherwise 7318 * 7319 * @see ActionMode 7320 * @see #startActionMode(android.view.ActionMode.Callback, int) 7321 */ 7322 public ActionMode startActionMode(ActionMode.Callback callback) { 7323 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 7324 } 7325 7326 /** 7327 * Start an action mode with the given type. 7328 * 7329 * @param callback Callback that will control the lifecycle of the action mode 7330 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 7331 * @return The new action mode if it is started, null otherwise 7332 * 7333 * @see ActionMode 7334 */ 7335 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 7336 ViewParent parent = getParent(); 7337 if (parent == null) return null; 7338 try { 7339 return parent.startActionModeForChild(this, callback, type); 7340 } catch (AbstractMethodError ame) { 7341 // Older implementations of custom views might not implement this. 7342 return parent.startActionModeForChild(this, callback); 7343 } 7344 } 7345 7346 /** 7347 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 7348 * Context, creating a unique View identifier to retrieve the result. 7349 * 7350 * @param intent The Intent to be started. 7351 * @param requestCode The request code to use. 7352 * @hide 7353 */ 7354 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 7355 public void startActivityForResult(Intent intent, int requestCode) { 7356 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 7357 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 7358 } 7359 7360 /** 7361 * If this View corresponds to the calling who, dispatches the activity result. 7362 * @param who The identifier for the targeted View to receive the result. 7363 * @param requestCode The integer request code originally supplied to 7364 * startActivityForResult(), allowing you to identify who this 7365 * result came from. 7366 * @param resultCode The integer result code returned by the child activity 7367 * through its setResult(). 7368 * @param data An Intent, which can return result data to the caller 7369 * (various data can be attached to Intent "extras"). 7370 * @return {@code true} if the activity result was dispatched. 7371 * @hide 7372 */ 7373 public boolean dispatchActivityResult( 7374 String who, int requestCode, int resultCode, Intent data) { 7375 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 7376 onActivityResult(requestCode, resultCode, data); 7377 mStartActivityRequestWho = null; 7378 return true; 7379 } 7380 return false; 7381 } 7382 7383 /** 7384 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 7385 * 7386 * @param requestCode The integer request code originally supplied to 7387 * startActivityForResult(), allowing you to identify who this 7388 * result came from. 7389 * @param resultCode The integer result code returned by the child activity 7390 * through its setResult(). 7391 * @param data An Intent, which can return result data to the caller 7392 * (various data can be attached to Intent "extras"). 7393 * @hide 7394 */ 7395 public void onActivityResult(int requestCode, int resultCode, Intent data) { 7396 // Do nothing. 7397 } 7398 7399 /** 7400 * Register a callback to be invoked when a hardware key is pressed in this view. 7401 * Key presses in software input methods will generally not trigger the methods of 7402 * this listener. 7403 * @param l the key listener to attach to this view 7404 */ 7405 public void setOnKeyListener(OnKeyListener l) { 7406 getListenerInfo().mOnKeyListener = l; 7407 } 7408 7409 /** 7410 * Register a callback to be invoked when a touch event is sent to this view. 7411 * @param l the touch listener to attach to this view 7412 */ 7413 public void setOnTouchListener(OnTouchListener l) { 7414 getListenerInfo().mOnTouchListener = l; 7415 } 7416 7417 /** 7418 * Register a callback to be invoked when a generic motion event is sent to this view. 7419 * @param l the generic motion listener to attach to this view 7420 */ 7421 public void setOnGenericMotionListener(OnGenericMotionListener l) { 7422 getListenerInfo().mOnGenericMotionListener = l; 7423 } 7424 7425 /** 7426 * Register a callback to be invoked when a hover event is sent to this view. 7427 * @param l the hover listener to attach to this view 7428 */ 7429 public void setOnHoverListener(OnHoverListener l) { 7430 getListenerInfo().mOnHoverListener = l; 7431 } 7432 7433 /** 7434 * Register a drag event listener callback object for this View. The parameter is 7435 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 7436 * View, the system calls the 7437 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 7438 * @param l An implementation of {@link android.view.View.OnDragListener}. 7439 */ 7440 public void setOnDragListener(OnDragListener l) { 7441 getListenerInfo().mOnDragListener = l; 7442 } 7443 7444 /** 7445 * Give this view focus. This will cause 7446 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 7447 * 7448 * Note: this does not check whether this {@link View} should get focus, it just 7449 * gives it focus no matter what. It should only be called internally by framework 7450 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 7451 * 7452 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 7453 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 7454 * focus moved when requestFocus() is called. It may not always 7455 * apply, in which case use the default View.FOCUS_DOWN. 7456 * @param previouslyFocusedRect The rectangle of the view that had focus 7457 * prior in this View's coordinate system. 7458 */ 7459 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 7460 if (DBG) { 7461 System.out.println(this + " requestFocus()"); 7462 } 7463 7464 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 7465 mPrivateFlags |= PFLAG_FOCUSED; 7466 7467 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 7468 7469 if (mParent != null) { 7470 mParent.requestChildFocus(this, this); 7471 updateFocusedInCluster(oldFocus, direction); 7472 } 7473 7474 if (mAttachInfo != null) { 7475 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 7476 } 7477 7478 onFocusChanged(true, direction, previouslyFocusedRect); 7479 refreshDrawableState(); 7480 } 7481 } 7482 7483 /** 7484 * Sets this view's preference for reveal behavior when it gains focus. 7485 * 7486 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 7487 * this view would prefer to be brought fully into view when it gains focus. 7488 * For example, a text field that a user is meant to type into. Other views such 7489 * as scrolling containers may prefer to opt-out of this behavior.</p> 7490 * 7491 * <p>The default value for views is true, though subclasses may change this 7492 * based on their preferred behavior.</p> 7493 * 7494 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 7495 * 7496 * @see #getRevealOnFocusHint() 7497 */ 7498 public final void setRevealOnFocusHint(boolean revealOnFocus) { 7499 if (revealOnFocus) { 7500 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 7501 } else { 7502 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 7503 } 7504 } 7505 7506 /** 7507 * Returns this view's preference for reveal behavior when it gains focus. 7508 * 7509 * <p>When this method returns true for a child view requesting focus, ancestor 7510 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 7511 * should make a best effort to make the newly focused child fully visible to the user. 7512 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 7513 * other properties affecting visibility to the user as part of the focus change.</p> 7514 * 7515 * @return true if this view would prefer to become fully visible when it gains focus, 7516 * false if it would prefer not to disrupt scroll positioning 7517 * 7518 * @see #setRevealOnFocusHint(boolean) 7519 */ 7520 public final boolean getRevealOnFocusHint() { 7521 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 7522 } 7523 7524 /** 7525 * Populates <code>outRect</code> with the hotspot bounds. By default, 7526 * the hotspot bounds are identical to the screen bounds. 7527 * 7528 * @param outRect rect to populate with hotspot bounds 7529 * @hide Only for internal use by views and widgets. 7530 */ 7531 public void getHotspotBounds(Rect outRect) { 7532 final Drawable background = getBackground(); 7533 if (background != null) { 7534 background.getHotspotBounds(outRect); 7535 } else { 7536 getBoundsOnScreen(outRect); 7537 } 7538 } 7539 7540 /** 7541 * Request that a rectangle of this view be visible on the screen, 7542 * scrolling if necessary just enough. 7543 * 7544 * <p>A View should call this if it maintains some notion of which part 7545 * of its content is interesting. For example, a text editing view 7546 * should call this when its cursor moves. 7547 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 7548 * It should not be affected by which part of the View is currently visible or its scroll 7549 * position. 7550 * 7551 * @param rectangle The rectangle in the View's content coordinate space 7552 * @return Whether any parent scrolled. 7553 */ 7554 public boolean requestRectangleOnScreen(Rect rectangle) { 7555 return requestRectangleOnScreen(rectangle, false); 7556 } 7557 7558 /** 7559 * Request that a rectangle of this view be visible on the screen, 7560 * scrolling if necessary just enough. 7561 * 7562 * <p>A View should call this if it maintains some notion of which part 7563 * of its content is interesting. For example, a text editing view 7564 * should call this when its cursor moves. 7565 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 7566 * It should not be affected by which part of the View is currently visible or its scroll 7567 * position. 7568 * <p>When <code>immediate</code> is set to true, scrolling will not be 7569 * animated. 7570 * 7571 * @param rectangle The rectangle in the View's content coordinate space 7572 * @param immediate True to forbid animated scrolling, false otherwise 7573 * @return Whether any parent scrolled. 7574 */ 7575 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 7576 if (mParent == null) { 7577 return false; 7578 } 7579 7580 View child = this; 7581 7582 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 7583 position.set(rectangle); 7584 7585 ViewParent parent = mParent; 7586 boolean scrolled = false; 7587 while (parent != null) { 7588 rectangle.set((int) position.left, (int) position.top, 7589 (int) position.right, (int) position.bottom); 7590 7591 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 7592 7593 if (!(parent instanceof View)) { 7594 break; 7595 } 7596 7597 // move it from child's content coordinate space to parent's content coordinate space 7598 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 7599 7600 child = (View) parent; 7601 parent = child.getParent(); 7602 } 7603 7604 return scrolled; 7605 } 7606 7607 /** 7608 * Called when this view wants to give up focus. If focus is cleared 7609 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 7610 * <p> 7611 * <strong>Note:</strong> When not in touch-mode, the framework will try to give focus 7612 * to the first focusable View from the top after focus is cleared. Hence, if this 7613 * View is the first from the top that can take focus, then all callbacks 7614 * related to clearing focus will be invoked after which the framework will 7615 * give focus to this view. 7616 * </p> 7617 */ 7618 public void clearFocus() { 7619 if (DBG) { 7620 System.out.println(this + " clearFocus()"); 7621 } 7622 7623 final boolean refocus = sAlwaysAssignFocus || !isInTouchMode(); 7624 clearFocusInternal(null, true, refocus); 7625 } 7626 7627 /** 7628 * Clears focus from the view, optionally propagating the change up through 7629 * the parent hierarchy and requesting that the root view place new focus. 7630 * 7631 * @param propagate whether to propagate the change up through the parent 7632 * hierarchy 7633 * @param refocus when propagate is true, specifies whether to request the 7634 * root view place new focus 7635 */ 7636 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 7637 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 7638 mPrivateFlags &= ~PFLAG_FOCUSED; 7639 clearParentsWantFocus(); 7640 7641 if (propagate && mParent != null) { 7642 mParent.clearChildFocus(this); 7643 } 7644 7645 onFocusChanged(false, 0, null); 7646 refreshDrawableState(); 7647 7648 if (propagate && (!refocus || !rootViewRequestFocus())) { 7649 notifyGlobalFocusCleared(this); 7650 } 7651 } 7652 } 7653 7654 void notifyGlobalFocusCleared(View oldFocus) { 7655 if (oldFocus != null && mAttachInfo != null) { 7656 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 7657 } 7658 } 7659 7660 boolean rootViewRequestFocus() { 7661 final View root = getRootView(); 7662 return root != null && root.requestFocus(); 7663 } 7664 7665 /** 7666 * Called internally by the view system when a new view is getting focus. 7667 * This is what clears the old focus. 7668 * <p> 7669 * <b>NOTE:</b> The parent view's focused child must be updated manually 7670 * after calling this method. Otherwise, the view hierarchy may be left in 7671 * an inconstent state. 7672 */ 7673 void unFocus(View focused) { 7674 if (DBG) { 7675 System.out.println(this + " unFocus()"); 7676 } 7677 7678 clearFocusInternal(focused, false, false); 7679 } 7680 7681 /** 7682 * Returns true if this view has focus itself, or is the ancestor of the 7683 * view that has focus. 7684 * 7685 * @return True if this view has or contains focus, false otherwise. 7686 */ 7687 @ViewDebug.ExportedProperty(category = "focus") 7688 public boolean hasFocus() { 7689 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 7690 } 7691 7692 /** 7693 * Returns true if this view is focusable or if it contains a reachable View 7694 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 7695 * is a view whose parents do not block descendants focus. 7696 * Only {@link #VISIBLE} views are considered focusable. 7697 * 7698 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 7699 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 7700 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 7701 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 7702 * {@code false} for views not explicitly marked as focusable. 7703 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 7704 * behavior.</p> 7705 * 7706 * @return {@code true} if the view is focusable or if the view contains a focusable 7707 * view, {@code false} otherwise 7708 * 7709 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 7710 * @see ViewGroup#getTouchscreenBlocksFocus() 7711 * @see #hasExplicitFocusable() 7712 */ 7713 public boolean hasFocusable() { 7714 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 7715 } 7716 7717 /** 7718 * Returns true if this view is focusable or if it contains a reachable View 7719 * for which {@link #hasExplicitFocusable()} returns {@code true}. 7720 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 7721 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 7722 * {@link #FOCUSABLE} are considered focusable. 7723 * 7724 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 7725 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 7726 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 7727 * to focusable will not.</p> 7728 * 7729 * @return {@code true} if the view is focusable or if the view contains a focusable 7730 * view, {@code false} otherwise 7731 * 7732 * @see #hasFocusable() 7733 */ 7734 public boolean hasExplicitFocusable() { 7735 return hasFocusable(false, true); 7736 } 7737 7738 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 7739 if (!isFocusableInTouchMode()) { 7740 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 7741 final ViewGroup g = (ViewGroup) p; 7742 if (g.shouldBlockFocusForTouchscreen()) { 7743 return false; 7744 } 7745 } 7746 } 7747 7748 // Invisible, gone, or disabled views are never focusable. 7749 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE 7750 || (mViewFlags & ENABLED_MASK) != ENABLED) { 7751 return false; 7752 } 7753 7754 // Only use effective focusable value when allowed. 7755 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 7756 return true; 7757 } 7758 7759 return false; 7760 } 7761 7762 /** 7763 * Called by the view system when the focus state of this view changes. 7764 * When the focus change event is caused by directional navigation, direction 7765 * and previouslyFocusedRect provide insight into where the focus is coming from. 7766 * When overriding, be sure to call up through to the super class so that 7767 * the standard focus handling will occur. 7768 * 7769 * @param gainFocus True if the View has focus; false otherwise. 7770 * @param direction The direction focus has moved when requestFocus() 7771 * is called to give this view focus. Values are 7772 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 7773 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 7774 * It may not always apply, in which case use the default. 7775 * @param previouslyFocusedRect The rectangle, in this view's coordinate 7776 * system, of the previously focused view. If applicable, this will be 7777 * passed in as finer grained information about where the focus is coming 7778 * from (in addition to direction). Will be <code>null</code> otherwise. 7779 */ 7780 @CallSuper 7781 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 7782 @Nullable Rect previouslyFocusedRect) { 7783 if (gainFocus) { 7784 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 7785 } else { 7786 notifyViewAccessibilityStateChangedIfNeeded( 7787 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7788 } 7789 7790 // Here we check whether we still need the default focus highlight, and switch it on/off. 7791 switchDefaultFocusHighlight(); 7792 7793 if (!gainFocus) { 7794 if (isPressed()) { 7795 setPressed(false); 7796 } 7797 if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 7798 notifyFocusChangeToInputMethodManager(false /* hasFocus */); 7799 } 7800 onFocusLost(); 7801 } else if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 7802 notifyFocusChangeToInputMethodManager(true /* hasFocus */); 7803 } 7804 7805 invalidate(true); 7806 ListenerInfo li = mListenerInfo; 7807 if (li != null && li.mOnFocusChangeListener != null) { 7808 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 7809 } 7810 7811 if (mAttachInfo != null) { 7812 mAttachInfo.mKeyDispatchState.reset(this); 7813 } 7814 7815 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 7816 } 7817 7818 /** 7819 * Notify {@link InputMethodManager} about the focus change of the {@link View}. 7820 * 7821 * <p>Does nothing when {@link InputMethodManager} is not available.</p> 7822 * 7823 * @param hasFocus {@code true} when the {@link View} is being focused. 7824 */ 7825 private void notifyFocusChangeToInputMethodManager(boolean hasFocus) { 7826 final InputMethodManager imm = 7827 getContext().getSystemService(InputMethodManager.class); 7828 if (imm == null) { 7829 return; 7830 } 7831 if (hasFocus) { 7832 imm.focusIn(this); 7833 } else { 7834 imm.focusOut(this); 7835 } 7836 } 7837 7838 /** @hide */ 7839 public void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 7840 if (canNotifyAutofillEnterExitEvent()) { 7841 AutofillManager afm = getAutofillManager(); 7842 if (afm != null) { 7843 if (enter && isFocused()) { 7844 // We have not been laid out yet, hence cannot evaluate 7845 // whether this view is visible to the user, we will do 7846 // the evaluation once layout is complete. 7847 if (!isLaidOut()) { 7848 mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 7849 } else if (isVisibleToUser()) { 7850 // TODO This is a potential problem that View gets focus before it's visible 7851 // to User. Ideally View should handle the event when isVisibleToUser() 7852 // becomes true where it should issue notifyViewEntered(). 7853 afm.notifyViewEntered(this); 7854 } 7855 } else if (!enter && !isFocused()) { 7856 afm.notifyViewExited(this); 7857 } 7858 } 7859 } 7860 } 7861 7862 /** 7863 * Visually distinct portion of a window with window-like semantics are considered panes for 7864 * accessibility purposes. One example is the content view of a fragment that is replaced. 7865 * In order for accessibility services to understand a pane's window-like behavior, panes 7866 * should have descriptive titles. Views with pane titles produce {@link AccessibilityEvent}s 7867 * when they appear, disappear, or change title. 7868 * 7869 * @param accessibilityPaneTitle The pane's title. Setting to {@code null} indicates that this 7870 * View is not a pane. 7871 * 7872 * {@see AccessibilityNodeInfo#setPaneTitle(CharSequence)} 7873 * 7874 * @attr ref android.R.styleable#View_accessibilityPaneTitle 7875 */ 7876 public void setAccessibilityPaneTitle(@Nullable CharSequence accessibilityPaneTitle) { 7877 if (!TextUtils.equals(accessibilityPaneTitle, mAccessibilityPaneTitle)) { 7878 mAccessibilityPaneTitle = accessibilityPaneTitle; 7879 notifyViewAccessibilityStateChangedIfNeeded( 7880 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE); 7881 } 7882 } 7883 7884 /** 7885 * Get the title of the pane for purposes of accessibility. 7886 * 7887 * @return The current pane title. 7888 * 7889 * {@see #setAccessibilityPaneTitle}. 7890 * 7891 * @attr ref android.R.styleable#View_accessibilityPaneTitle 7892 */ 7893 @InspectableProperty 7894 @Nullable 7895 public CharSequence getAccessibilityPaneTitle() { 7896 return mAccessibilityPaneTitle; 7897 } 7898 7899 private boolean isAccessibilityPane() { 7900 return mAccessibilityPaneTitle != null; 7901 } 7902 7903 /** 7904 * Sends an accessibility event of the given type. If accessibility is 7905 * not enabled this method has no effect. The default implementation calls 7906 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 7907 * to populate information about the event source (this View), then calls 7908 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 7909 * populate the text content of the event source including its descendants, 7910 * and last calls 7911 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 7912 * on its parent to request sending of the event to interested parties. 7913 * <p> 7914 * If an {@link AccessibilityDelegate} has been specified via calling 7915 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7916 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 7917 * responsible for handling this call. 7918 * </p> 7919 * 7920 * @param eventType The type of the event to send, as defined by several types from 7921 * {@link android.view.accessibility.AccessibilityEvent}, such as 7922 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 7923 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 7924 * 7925 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 7926 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 7927 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 7928 * @see AccessibilityDelegate 7929 */ 7930 public void sendAccessibilityEvent(int eventType) { 7931 if (mAccessibilityDelegate != null) { 7932 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 7933 } else { 7934 sendAccessibilityEventInternal(eventType); 7935 } 7936 } 7937 7938 /** 7939 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 7940 * {@link AccessibilityEvent} to suggest that an accessibility service announce the 7941 * specified text to its users. 7942 * <p> 7943 * Note: The event generated with this API carries no semantic meaning, and is appropriate only 7944 * in exceptional situations. Apps can generally achieve correct behavior for accessibility by 7945 * accurately supplying the semantics of their UI. 7946 * They should not need to specify what exactly is announced to users. 7947 * 7948 * @param text The announcement text. 7949 */ 7950 public void announceForAccessibility(CharSequence text) { 7951 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 7952 AccessibilityEvent event = AccessibilityEvent.obtain( 7953 AccessibilityEvent.TYPE_ANNOUNCEMENT); 7954 onInitializeAccessibilityEvent(event); 7955 event.getText().add(text); 7956 event.setContentDescription(null); 7957 mParent.requestSendAccessibilityEvent(this, event); 7958 } 7959 } 7960 7961 /** 7962 * @see #sendAccessibilityEvent(int) 7963 * 7964 * Note: Called from the default {@link AccessibilityDelegate}. 7965 * 7966 * @hide 7967 */ 7968 public void sendAccessibilityEventInternal(int eventType) { 7969 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 7970 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 7971 } 7972 } 7973 7974 /** 7975 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 7976 * takes as an argument an empty {@link AccessibilityEvent} and does not 7977 * perform a check whether accessibility is enabled. 7978 * <p> 7979 * If an {@link AccessibilityDelegate} has been specified via calling 7980 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 7981 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 7982 * is responsible for handling this call. 7983 * </p> 7984 * 7985 * @param event The event to send. 7986 * 7987 * @see #sendAccessibilityEvent(int) 7988 */ 7989 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 7990 if (mAccessibilityDelegate != null) { 7991 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 7992 } else { 7993 sendAccessibilityEventUncheckedInternal(event); 7994 } 7995 } 7996 7997 /** 7998 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 7999 * 8000 * Note: Called from the default {@link AccessibilityDelegate}. 8001 * 8002 * @hide 8003 */ 8004 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 8005 // Panes disappearing are relevant even if though the view is no longer visible. 8006 boolean isWindowStateChanged = 8007 (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 8008 boolean isWindowDisappearedEvent = isWindowStateChanged && ((event.getContentChangeTypes() 8009 & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) != 0); 8010 if (!isShown() && !isWindowDisappearedEvent) { 8011 return; 8012 } 8013 onInitializeAccessibilityEvent(event); 8014 // Only a subset of accessibility events populates text content. 8015 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 8016 dispatchPopulateAccessibilityEvent(event); 8017 } 8018 // In the beginning we called #isShown(), so we know that getParent() is not null. 8019 ViewParent parent = getParent(); 8020 if (parent != null) { 8021 getParent().requestSendAccessibilityEvent(this, event); 8022 } 8023 } 8024 8025 /** 8026 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 8027 * to its children for adding their text content to the event. Note that the 8028 * event text is populated in a separate dispatch path since we add to the 8029 * event not only the text of the source but also the text of all its descendants. 8030 * A typical implementation will call 8031 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 8032 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 8033 * on each child. Override this method if custom population of the event text 8034 * content is required. 8035 * <p> 8036 * If an {@link AccessibilityDelegate} has been specified via calling 8037 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8038 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 8039 * is responsible for handling this call. 8040 * </p> 8041 * <p> 8042 * <em>Note:</em> Accessibility events of certain types are not dispatched for 8043 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 8044 * </p> 8045 * 8046 * @param event The event. 8047 * 8048 * @return True if the event population was completed. 8049 */ 8050 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 8051 if (mAccessibilityDelegate != null) { 8052 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 8053 } else { 8054 return dispatchPopulateAccessibilityEventInternal(event); 8055 } 8056 } 8057 8058 /** 8059 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8060 * 8061 * Note: Called from the default {@link AccessibilityDelegate}. 8062 * 8063 * @hide 8064 */ 8065 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 8066 onPopulateAccessibilityEvent(event); 8067 return false; 8068 } 8069 8070 /** 8071 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 8072 * giving a chance to this View to populate the accessibility event with its 8073 * text content. While this method is free to modify event 8074 * attributes other than text content, doing so should normally be performed in 8075 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 8076 * <p> 8077 * Example: Adding formatted date string to an accessibility event in addition 8078 * to the text added by the super implementation: 8079 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 8080 * super.onPopulateAccessibilityEvent(event); 8081 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 8082 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 8083 * mCurrentDate.getTimeInMillis(), flags); 8084 * event.getText().add(selectedDateUtterance); 8085 * }</pre> 8086 * <p> 8087 * If an {@link AccessibilityDelegate} has been specified via calling 8088 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8089 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 8090 * is responsible for handling this call. 8091 * </p> 8092 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 8093 * information to the event, in case the default implementation has basic information to add. 8094 * </p> 8095 * 8096 * @param event The accessibility event which to populate. 8097 * 8098 * @see #sendAccessibilityEvent(int) 8099 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8100 */ 8101 @CallSuper 8102 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 8103 if (mAccessibilityDelegate != null) { 8104 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 8105 } else { 8106 onPopulateAccessibilityEventInternal(event); 8107 } 8108 } 8109 8110 /** 8111 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 8112 * 8113 * Note: Called from the default {@link AccessibilityDelegate}. 8114 * 8115 * @hide 8116 */ 8117 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 8118 if ((event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) 8119 && isAccessibilityPane()) { 8120 event.getText().add(getAccessibilityPaneTitle()); 8121 } 8122 } 8123 8124 /** 8125 * Initializes an {@link AccessibilityEvent} with information about 8126 * this View which is the event source. In other words, the source of 8127 * an accessibility event is the view whose state change triggered firing 8128 * the event. 8129 * <p> 8130 * Example: Setting the password property of an event in addition 8131 * to properties set by the super implementation: 8132 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 8133 * super.onInitializeAccessibilityEvent(event); 8134 * event.setPassword(true); 8135 * }</pre> 8136 * <p> 8137 * If an {@link AccessibilityDelegate} has been specified via calling 8138 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8139 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 8140 * is responsible for handling this call. 8141 * </p> 8142 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 8143 * information to the event, in case the default implementation has basic information to add. 8144 * </p> 8145 * @param event The event to initialize. 8146 * 8147 * @see #sendAccessibilityEvent(int) 8148 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8149 */ 8150 @CallSuper 8151 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 8152 if (mAccessibilityDelegate != null) { 8153 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 8154 } else { 8155 onInitializeAccessibilityEventInternal(event); 8156 } 8157 } 8158 8159 /** 8160 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 8161 * 8162 * Note: Called from the default {@link AccessibilityDelegate}. 8163 * 8164 * @hide 8165 */ 8166 @UnsupportedAppUsage 8167 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 8168 event.setSource(this); 8169 event.setClassName(getAccessibilityClassName()); 8170 event.setPackageName(getContext().getPackageName()); 8171 event.setEnabled(isEnabled()); 8172 event.setContentDescription(mContentDescription); 8173 8174 switch (event.getEventType()) { 8175 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 8176 ArrayList<View> focusablesTempList = (mAttachInfo != null) 8177 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 8178 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 8179 event.setItemCount(focusablesTempList.size()); 8180 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 8181 if (mAttachInfo != null) { 8182 focusablesTempList.clear(); 8183 } 8184 } break; 8185 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 8186 CharSequence text = getIterableTextForAccessibility(); 8187 if (text != null && text.length() > 0) { 8188 event.setFromIndex(getAccessibilitySelectionStart()); 8189 event.setToIndex(getAccessibilitySelectionEnd()); 8190 event.setItemCount(text.length()); 8191 } 8192 } break; 8193 } 8194 } 8195 8196 /** 8197 * Returns an {@link AccessibilityNodeInfo} representing this view from the 8198 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 8199 * This method is responsible for obtaining an accessibility node info from a 8200 * pool of reusable instances and calling 8201 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 8202 * initialize the former. 8203 * <p> 8204 * Note: The client is responsible for recycling the obtained instance by calling 8205 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 8206 * </p> 8207 * 8208 * @return A populated {@link AccessibilityNodeInfo}. 8209 * 8210 * @see AccessibilityNodeInfo 8211 */ 8212 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 8213 if (mAccessibilityDelegate != null) { 8214 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 8215 } else { 8216 return createAccessibilityNodeInfoInternal(); 8217 } 8218 } 8219 8220 /** 8221 * @see #createAccessibilityNodeInfo() 8222 * 8223 * @hide 8224 */ 8225 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 8226 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8227 if (provider != null) { 8228 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 8229 } else { 8230 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 8231 onInitializeAccessibilityNodeInfo(info); 8232 return info; 8233 } 8234 } 8235 8236 /** 8237 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 8238 * The base implementation sets: 8239 * <ul> 8240 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 8241 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 8242 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 8243 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 8244 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 8245 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 8246 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 8247 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 8248 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 8249 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 8250 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 8251 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 8252 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 8253 * </ul> 8254 * <p> 8255 * Subclasses should override this method, call the super implementation, 8256 * and set additional attributes. 8257 * </p> 8258 * <p> 8259 * If an {@link AccessibilityDelegate} has been specified via calling 8260 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8261 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 8262 * is responsible for handling this call. 8263 * </p> 8264 * 8265 * @param info The instance to initialize. 8266 */ 8267 @CallSuper 8268 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 8269 if (mAccessibilityDelegate != null) { 8270 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 8271 } else { 8272 onInitializeAccessibilityNodeInfoInternal(info); 8273 } 8274 } 8275 8276 /** 8277 * Gets the location of this view in screen coordinates. 8278 * 8279 * @param outRect The output location 8280 * @hide 8281 */ 8282 @UnsupportedAppUsage 8283 public void getBoundsOnScreen(Rect outRect) { 8284 getBoundsOnScreen(outRect, false); 8285 } 8286 8287 /** 8288 * Gets the location of this view in screen coordinates. 8289 * 8290 * @param outRect The output location 8291 * @param clipToParent Whether to clip child bounds to the parent ones. 8292 * @hide 8293 */ 8294 @UnsupportedAppUsage 8295 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 8296 if (mAttachInfo == null) { 8297 return; 8298 } 8299 8300 RectF position = mAttachInfo.mTmpTransformRect; 8301 position.set(0, 0, mRight - mLeft, mBottom - mTop); 8302 mapRectFromViewToScreenCoords(position, clipToParent); 8303 outRect.set(Math.round(position.left), Math.round(position.top), 8304 Math.round(position.right), Math.round(position.bottom)); 8305 } 8306 8307 /** 8308 * Map a rectangle from view-relative coordinates to screen-relative coordinates 8309 * 8310 * @param rect The rectangle to be mapped 8311 * @param clipToParent Whether to clip child bounds to the parent ones. 8312 * @hide 8313 */ 8314 public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { 8315 if (!hasIdentityMatrix()) { 8316 getMatrix().mapRect(rect); 8317 } 8318 8319 rect.offset(mLeft, mTop); 8320 8321 ViewParent parent = mParent; 8322 while (parent instanceof View) { 8323 View parentView = (View) parent; 8324 8325 rect.offset(-parentView.mScrollX, -parentView.mScrollY); 8326 8327 if (clipToParent) { 8328 rect.left = Math.max(rect.left, 0); 8329 rect.top = Math.max(rect.top, 0); 8330 rect.right = Math.min(rect.right, parentView.getWidth()); 8331 rect.bottom = Math.min(rect.bottom, parentView.getHeight()); 8332 } 8333 8334 if (!parentView.hasIdentityMatrix()) { 8335 parentView.getMatrix().mapRect(rect); 8336 } 8337 8338 rect.offset(parentView.mLeft, parentView.mTop); 8339 8340 parent = parentView.mParent; 8341 } 8342 8343 if (parent instanceof ViewRootImpl) { 8344 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 8345 rect.offset(0, -viewRootImpl.mCurScrollY); 8346 } 8347 8348 rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 8349 } 8350 8351 /** 8352 * Return the class name of this object to be used for accessibility purposes. 8353 * Subclasses should only override this if they are implementing something that 8354 * should be seen as a completely new class of view when used by accessibility, 8355 * unrelated to the class it is deriving from. This is used to fill in 8356 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 8357 */ 8358 public CharSequence getAccessibilityClassName() { 8359 return View.class.getName(); 8360 } 8361 8362 /** 8363 * Called when assist structure is being retrieved from a view as part of 8364 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 8365 * @param structure Fill in with structured view data. The default implementation 8366 * fills in all data that can be inferred from the view itself. 8367 */ 8368 public void onProvideStructure(ViewStructure structure) { 8369 onProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 8370 } 8371 8372 /** 8373 * Populates a {@link ViewStructure} to fullfil an autofill request. 8374 * 8375 * <p>The structure should contain at least the following properties: 8376 * <ul> 8377 * <li>Autofill id ({@link ViewStructure#setAutofillId(AutofillId, int)}). 8378 * <li>Autofill type ({@link ViewStructure#setAutofillType(int)}). 8379 * <li>Autofill value ({@link ViewStructure#setAutofillValue(AutofillValue)}). 8380 * <li>Whether the data is sensitive ({@link ViewStructure#setDataIsSensitive(boolean)}). 8381 * </ul> 8382 * 8383 * <p>It's also recommended to set the following properties - the more properties the structure 8384 * has, the higher the changes of an {@link android.service.autofill.AutofillService} properly 8385 * using the structure: 8386 * 8387 * <ul> 8388 * <li>Autofill hints ({@link ViewStructure#setAutofillHints(String[])}). 8389 * <li>Autofill options ({@link ViewStructure#setAutofillOptions(CharSequence[])}) when the 8390 * view can only be filled with predefined values (typically used when the autofill type 8391 * is {@link #AUTOFILL_TYPE_LIST}). 8392 * <li>Resource id ({@link ViewStructure#setId(int, String, String, String)}). 8393 * <li>Class name ({@link ViewStructure#setClassName(String)}). 8394 * <li>Content description ({@link ViewStructure#setContentDescription(CharSequence)}). 8395 * <li>Visual properties such as visibility ({@link ViewStructure#setVisibility(int)}), 8396 * dimensions ({@link ViewStructure#setDimens(int, int, int, int, int, int)}), and 8397 * opacity ({@link ViewStructure#setOpaque(boolean)}). 8398 * <li>For views representing text fields, text properties such as the text itself 8399 * ({@link ViewStructure#setText(CharSequence)}), text hints 8400 * ({@link ViewStructure#setHint(CharSequence)}, input type 8401 * ({@link ViewStructure#setInputType(int)}), 8402 * <li>For views representing HTML nodes, its web domain 8403 * ({@link ViewStructure#setWebDomain(String)}) and HTML properties 8404 * (({@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}). 8405 * </ul> 8406 * 8407 * <p>The default implementation of this method already sets most of these properties based on 8408 * related {@link View} methods (for example, the autofill id is set using 8409 * {@link #getAutofillId()}, the autofill type set using {@link #getAutofillType()}, etc.), 8410 * and views in the standard Android widgets library also override it to set their 8411 * relevant properties (for example, {@link android.widget.TextView} already sets the text 8412 * properties), so it's recommended to only override this method 8413 * (and call {@code super.onProvideAutofillStructure()}) when: 8414 * 8415 * <ul> 8416 * <li>The view contents does not include PII (Personally Identifiable Information), so it 8417 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 8418 * <li>The view can only be autofilled with predefined options, so it can call 8419 * {@link ViewStructure#setAutofillOptions(CharSequence[])}. 8420 * </ul> 8421 * 8422 * <p><b>Note:</b> The {@code left} and {@code top} values set in 8423 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the next 8424 * {@link ViewGroup#isImportantForAutofill()} predecessor view included in the structure. 8425 * 8426 * <p>Views support the Autofill Framework mainly by: 8427 * <ul> 8428 * <li>Providing the metadata defining what the view means and how it can be autofilled. 8429 * <li>Notifying the Android System when the view value changed by calling 8430 * {@link AutofillManager#notifyValueChanged(View)}. 8431 * <li>Implementing the methods that autofill the view. 8432 * </ul> 8433 * <p>This method is responsible for the former; {@link #autofill(AutofillValue)} is responsible 8434 * for the latter. 8435 * 8436 * @param structure fill in with structured view data for autofill purposes. 8437 * @param flags optional flags. 8438 * 8439 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 8440 */ 8441 public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) { 8442 onProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 8443 } 8444 8445 /** @hide */ 8446 protected void onProvideStructure(@NonNull ViewStructure structure, 8447 @ViewStructureType int viewFor, int flags) { 8448 final int id = mID; 8449 if (id != NO_ID && !isViewIdGenerated(id)) { 8450 String pkg, type, entry; 8451 try { 8452 final Resources res = getResources(); 8453 entry = res.getResourceEntryName(id); 8454 type = res.getResourceTypeName(id); 8455 pkg = res.getResourcePackageName(id); 8456 } catch (Resources.NotFoundException e) { 8457 entry = type = pkg = null; 8458 } 8459 structure.setId(id, pkg, type, entry); 8460 } else { 8461 structure.setId(id, null, null, null); 8462 } 8463 8464 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 8465 || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { 8466 final @AutofillType int autofillType = getAutofillType(); 8467 // Don't need to fill autofill info if view does not support it. 8468 // For example, only TextViews that are editable support autofill 8469 if (autofillType != AUTOFILL_TYPE_NONE) { 8470 structure.setAutofillType(autofillType); 8471 structure.setAutofillHints(getAutofillHints()); 8472 structure.setAutofillValue(getAutofillValue()); 8473 } 8474 structure.setImportantForAutofill(getImportantForAutofill()); 8475 } 8476 8477 int ignoredParentLeft = 0; 8478 int ignoredParentTop = 0; 8479 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 8480 && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 8481 View parentGroup = null; 8482 8483 ViewParent viewParent = getParent(); 8484 if (viewParent instanceof View) { 8485 parentGroup = (View) viewParent; 8486 } 8487 8488 while (parentGroup != null && !parentGroup.isImportantForAutofill()) { 8489 ignoredParentLeft += parentGroup.mLeft; 8490 ignoredParentTop += parentGroup.mTop; 8491 8492 viewParent = parentGroup.getParent(); 8493 if (viewParent instanceof View) { 8494 parentGroup = (View) viewParent; 8495 } else { 8496 break; 8497 } 8498 } 8499 } 8500 8501 structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY, 8502 mRight - mLeft, mBottom - mTop); 8503 if (viewFor == VIEW_STRUCTURE_FOR_ASSIST) { 8504 if (!hasIdentityMatrix()) { 8505 structure.setTransformation(getMatrix()); 8506 } 8507 structure.setElevation(getZ()); 8508 } 8509 structure.setVisibility(getVisibility()); 8510 structure.setEnabled(isEnabled()); 8511 if (isClickable()) { 8512 structure.setClickable(true); 8513 } 8514 if (isFocusable()) { 8515 structure.setFocusable(true); 8516 } 8517 if (isFocused()) { 8518 structure.setFocused(true); 8519 } 8520 if (isAccessibilityFocused()) { 8521 structure.setAccessibilityFocused(true); 8522 } 8523 if (isSelected()) { 8524 structure.setSelected(true); 8525 } 8526 if (isActivated()) { 8527 structure.setActivated(true); 8528 } 8529 if (isLongClickable()) { 8530 structure.setLongClickable(true); 8531 } 8532 if (this instanceof Checkable) { 8533 structure.setCheckable(true); 8534 if (((Checkable)this).isChecked()) { 8535 structure.setChecked(true); 8536 } 8537 } 8538 if (isOpaque()) { 8539 structure.setOpaque(true); 8540 } 8541 if (isContextClickable()) { 8542 structure.setContextClickable(true); 8543 } 8544 structure.setClassName(getAccessibilityClassName().toString()); 8545 structure.setContentDescription(getContentDescription()); 8546 } 8547 8548 /** 8549 * Called when assist structure is being retrieved from a view as part of 8550 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 8551 * generate additional virtual structure under this view. The defaullt implementation 8552 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 8553 * view's virtual accessibility nodes, if any. You can override this for a more 8554 * optimal implementation providing this data. 8555 */ 8556 public void onProvideVirtualStructure(ViewStructure structure) { 8557 onProvideVirtualStructureCompat(structure, false); 8558 } 8559 8560 /** 8561 * Fallback implementation to populate a ViewStructure from accessibility state. 8562 * 8563 * @param structure The structure to populate. 8564 * @param forAutofill Whether the structure is needed for autofill. 8565 */ 8566 private void onProvideVirtualStructureCompat(ViewStructure structure, boolean forAutofill) { 8567 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8568 if (provider != null) { 8569 if (forAutofill && Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 8570 Log.v(AUTOFILL_LOG_TAG, "onProvideVirtualStructureCompat() for " + this); 8571 } 8572 final AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 8573 structure.setChildCount(1); 8574 final ViewStructure root = structure.newChild(0); 8575 populateVirtualStructure(root, provider, info, forAutofill); 8576 info.recycle(); 8577 } 8578 } 8579 8580 /** 8581 * Populates a {@link ViewStructure} containing virtual children to fullfil an autofill 8582 * request. 8583 * 8584 * <p>This method should be used when the view manages a virtual structure under this view. For 8585 * example, a view that draws input fields using {@link #draw(Canvas)}. 8586 * 8587 * <p>When implementing this method, subclasses must follow the rules below: 8588 * 8589 * <ul> 8590 * <li>Add virtual children by calling the {@link ViewStructure#newChild(int)} or 8591 * {@link ViewStructure#asyncNewChild(int)} methods, where the {@code id} is an unique id 8592 * identifying the children in the virtual structure. 8593 * <li>The children hierarchy can have multiple levels if necessary, but ideally it should 8594 * exclude intermediate levels that are irrelevant for autofill; that would improve the 8595 * autofill performance. 8596 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual 8597 * children. 8598 * <li>Set the autofill properties of the child structure as defined by 8599 * {@link #onProvideAutofillStructure(ViewStructure, int)}, using 8600 * {@link ViewStructure#setAutofillId(AutofillId, int)} to set its autofill id. 8601 * <li>Call {@link android.view.autofill.AutofillManager#notifyViewEntered(View, int, Rect)} 8602 * and/or {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} 8603 * when the focused virtual child changed. 8604 * <li>Override {@link #isVisibleToUserForAutofill(int)} to allow the platform to query 8605 * whether a given virtual view is visible to the user in order to support triggering 8606 * save when all views of interest go away. 8607 * <li>Call 8608 * {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, AutofillValue)} 8609 * when the value of a virtual child changed. 8610 * <li>Call {@link 8611 * android.view.autofill.AutofillManager#notifyViewVisibilityChanged(View, int, boolean)} 8612 * when the visibility of a virtual child changed. 8613 * <li>Call 8614 * {@link android.view.autofill.AutofillManager#notifyViewClicked(View, int)} when a virtual 8615 * child is clicked. 8616 * <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure 8617 * changed and the current context should be committed (for example, when the user tapped 8618 * a {@code SUBMIT} button in an HTML page). 8619 * <li>Call {@link AutofillManager#cancel()} when the autofill context of the view structure 8620 * changed and the current context should be canceled (for example, when the user tapped 8621 * a {@code CANCEL} button in an HTML page). 8622 * <li>Provide ways for users to manually request autofill by calling 8623 * {@link AutofillManager#requestAutofill(View, int, Rect)}. 8624 * <li>The {@code left} and {@code top} values set in 8625 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the 8626 * next {@link ViewGroup#isImportantForAutofill()} predecessor view included in the 8627 * structure. 8628 * </ul> 8629 * 8630 * <p>Views with virtual children support the Autofill Framework mainly by: 8631 * <ul> 8632 * <li>Providing the metadata defining what the virtual children mean and how they can be 8633 * autofilled. 8634 * <li>Implementing the methods that autofill the virtual children. 8635 * </ul> 8636 * <p>This method is responsible for the former; {@link #autofill(SparseArray)} is responsible 8637 * for the latter. 8638 * 8639 * @param structure fill in with virtual children data for autofill purposes. 8640 * @param flags optional flags. 8641 * 8642 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 8643 */ 8644 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 8645 if (mContext.isAutofillCompatibilityEnabled()) { 8646 onProvideVirtualStructureCompat(structure, true); 8647 } 8648 } 8649 8650 /** 8651 * Automatically fills the content of this view with the {@code value}. 8652 * 8653 * <p>Views support the Autofill Framework mainly by: 8654 * <ul> 8655 * <li>Providing the metadata defining what the view means and how it can be autofilled. 8656 * <li>Implementing the methods that autofill the view. 8657 * </ul> 8658 * <p>{@link #onProvideAutofillStructure(ViewStructure, int)} is responsible for the former, 8659 * this method is responsible for latter. 8660 * 8661 * <p>This method does nothing by default, but when overridden it typically: 8662 * <ol> 8663 * <li>Checks if the provided value matches the expected type (which is defined by 8664 * {@link #getAutofillType()}). 8665 * <li>Checks if the view is editable - if it isn't, it should return right away. 8666 * <li>Call the proper getter method on {@link AutofillValue} to fetch the actual value. 8667 * <li>Pass the actual value to the equivalent setter in the view. 8668 * </ol> 8669 * 8670 * <p>For example, a text-field view could implement the method this way: 8671 * 8672 * <pre class="prettyprint"> 8673 * @Override 8674 * public void autofill(AutofillValue value) { 8675 * if (!value.isText() || !this.isEditable()) { 8676 * return; 8677 * } 8678 * CharSequence text = value.getTextValue(); 8679 * if (text != null) { 8680 * this.setText(text); 8681 * } 8682 * } 8683 * </pre> 8684 * 8685 * <p>If the value is updated asynchronously, the next call to 8686 * {@link AutofillManager#notifyValueChanged(View)} must happen <b>after</b> the value was 8687 * changed to the autofilled value. If not, the view will not be considered autofilled. 8688 * 8689 * <p><b>Note:</b> After this method is called, the value returned by 8690 * {@link #getAutofillValue()} must be equal to the {@code value} passed to it, otherwise the 8691 * view will not be highlighted as autofilled. 8692 * 8693 * @param value value to be autofilled. 8694 */ 8695 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 8696 } 8697 8698 /** 8699 * Automatically fills the content of the virtual children within this view. 8700 * 8701 * <p>Views with virtual children support the Autofill Framework mainly by: 8702 * <ul> 8703 * <li>Providing the metadata defining what the virtual children mean and how they can be 8704 * autofilled. 8705 * <li>Implementing the methods that autofill the virtual children. 8706 * </ul> 8707 * <p>{@link #onProvideAutofillVirtualStructure(ViewStructure, int)} is responsible for the 8708 * former, this method is responsible for the latter - see {@link #autofill(AutofillValue)} and 8709 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info about autofill. 8710 * 8711 * <p>If a child value is updated asynchronously, the next call to 8712 * {@link AutofillManager#notifyValueChanged(View, int, AutofillValue)} must happen 8713 * <b>after</b> the value was changed to the autofilled value. If not, the child will not be 8714 * considered autofilled. 8715 * 8716 * <p><b>Note:</b> To indicate that a virtual view was autofilled, 8717 * <code>?android:attr/autofilledHighlight</code> should be drawn over it until the data 8718 * changes. 8719 * 8720 * @param values map of values to be autofilled, keyed by virtual child id. 8721 * 8722 * @attr ref android.R.styleable#Theme_autofilledHighlight 8723 */ 8724 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { 8725 if (!mContext.isAutofillCompatibilityEnabled()) { 8726 return; 8727 } 8728 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8729 if (provider == null) { 8730 return; 8731 } 8732 final int valueCount = values.size(); 8733 for (int i = 0; i < valueCount; i++) { 8734 final AutofillValue value = values.valueAt(i); 8735 if (value.isText()) { 8736 final int virtualId = values.keyAt(i); 8737 final CharSequence text = value.getTextValue(); 8738 final Bundle arguments = new Bundle(); 8739 arguments.putCharSequence( 8740 AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text); 8741 provider.performAction(virtualId, AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); 8742 } 8743 } 8744 } 8745 8746 /** 8747 * Gets the unique, logical identifier of this view in the activity, for autofill purposes. 8748 * 8749 * <p>The autofill id is created on demand, unless it is explicitly set by 8750 * {@link #setAutofillId(AutofillId)}. 8751 * 8752 * <p>See {@link #setAutofillId(AutofillId)} for more info. 8753 * 8754 * @return The View's autofill id. 8755 */ 8756 public final AutofillId getAutofillId() { 8757 if (mAutofillId == null) { 8758 // The autofill id needs to be unique, but its value doesn't matter, 8759 // so it's better to reuse the accessibility id to save space. 8760 mAutofillId = new AutofillId(getAutofillViewId()); 8761 } 8762 return mAutofillId; 8763 } 8764 8765 /** 8766 * Sets the unique, logical identifier of this view in the activity, for autofill purposes. 8767 * 8768 * <p>The autofill id is created on demand, and this method should only be called when a view is 8769 * reused after {@link #dispatchProvideAutofillStructure(ViewStructure, int)} is called, as 8770 * that method creates a snapshot of the view that is passed along to the autofill service. 8771 * 8772 * <p>This method is typically used when view subtrees are recycled to represent different 8773 * content* —in this case, the autofill id can be saved before the view content is swapped 8774 * out, and restored later when it's swapped back in. For example: 8775 * 8776 * <pre> 8777 * EditText reusableView = ...; 8778 * ViewGroup parentView = ...; 8779 * AutofillManager afm = ...; 8780 * 8781 * // Swap out the view and change its contents 8782 * AutofillId oldId = reusableView.getAutofillId(); 8783 * CharSequence oldText = reusableView.getText(); 8784 * parentView.removeView(reusableView); 8785 * AutofillId newId = afm.getNextAutofillId(); 8786 * reusableView.setText("New I am"); 8787 * reusableView.setAutofillId(newId); 8788 * parentView.addView(reusableView); 8789 * 8790 * // Later, swap the old content back in 8791 * parentView.removeView(reusableView); 8792 * reusableView.setAutofillId(oldId); 8793 * reusableView.setText(oldText); 8794 * parentView.addView(reusableView); 8795 * </pre> 8796 * 8797 * @param id an autofill ID that is unique in the {@link android.app.Activity} hosting the view, 8798 * or {@code null} to reset it. Usually it's an id previously allocated to another view (and 8799 * obtained through {@link #getAutofillId()}), or a new value obtained through 8800 * {@link AutofillManager#getNextAutofillId()}. 8801 * 8802 * @throws IllegalStateException if the view is already {@link #isAttachedToWindow() attached to 8803 * a window}. 8804 * 8805 * @throws IllegalArgumentException if the id is an autofill id associated with a virtual view. 8806 */ 8807 public void setAutofillId(@Nullable AutofillId id) { 8808 // TODO(b/37566627): add unit / CTS test for all possible combinations below 8809 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 8810 Log.v(AUTOFILL_LOG_TAG, "setAutofill(): from " + mAutofillId + " to " + id); 8811 } 8812 if (isAttachedToWindow()) { 8813 throw new IllegalStateException("Cannot set autofill id when view is attached"); 8814 } 8815 if (id != null && !id.isNonVirtual()) { 8816 throw new IllegalStateException("Cannot set autofill id assigned to virtual views"); 8817 } 8818 if (id == null && (mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) == 0) { 8819 // Ignore reset because it was never explicitly set before. 8820 return; 8821 } 8822 mAutofillId = id; 8823 if (id != null) { 8824 mAutofillViewId = id.getViewId(); 8825 mPrivateFlags3 |= PFLAG3_AUTOFILLID_EXPLICITLY_SET; 8826 } else { 8827 mAutofillViewId = NO_ID; 8828 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 8829 } 8830 } 8831 8832 /** 8833 * Describes the autofill type of this view, so an 8834 * {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue} 8835 * when autofilling the view. 8836 * 8837 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it to properly 8838 * support the Autofill Framework. 8839 * 8840 * @return either {@link #AUTOFILL_TYPE_NONE}, {@link #AUTOFILL_TYPE_TEXT}, 8841 * {@link #AUTOFILL_TYPE_LIST}, {@link #AUTOFILL_TYPE_DATE}, or {@link #AUTOFILL_TYPE_TOGGLE}. 8842 * 8843 * @see #onProvideAutofillStructure(ViewStructure, int) 8844 * @see #autofill(AutofillValue) 8845 */ 8846 public @AutofillType int getAutofillType() { 8847 return AUTOFILL_TYPE_NONE; 8848 } 8849 8850 /** 8851 * Gets the hints that help an {@link android.service.autofill.AutofillService} determine how 8852 * to autofill the view with the user's data. 8853 * 8854 * <p>See {@link #setAutofillHints(String...)} for more info about these hints. 8855 * 8856 * @return The hints set via the attribute or {@link #setAutofillHints(String...)}, or 8857 * {@code null} if no hints were set. 8858 * 8859 * @attr ref android.R.styleable#View_autofillHints 8860 */ 8861 @ViewDebug.ExportedProperty() 8862 @InspectableProperty 8863 @Nullable public String[] getAutofillHints() { 8864 return mAutofillHints; 8865 } 8866 8867 /** 8868 * @hide 8869 */ 8870 @TestApi 8871 public boolean isAutofilled() { 8872 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; 8873 } 8874 8875 /** 8876 * Gets the {@link View}'s current autofill value. 8877 * 8878 * <p>By default returns {@code null}, but subclasses should override it and return an 8879 * appropriate value to properly support the Autofill Framework. 8880 * 8881 * @see #onProvideAutofillStructure(ViewStructure, int) 8882 * @see #autofill(AutofillValue) 8883 */ 8884 @Nullable 8885 public AutofillValue getAutofillValue() { 8886 return null; 8887 } 8888 8889 /** 8890 * Gets the mode for determining whether this view is important for autofill. 8891 * 8892 * <p>See {@link #setImportantForAutofill(int)} and {@link #isImportantForAutofill()} for more 8893 * info about this mode. 8894 * 8895 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 8896 * {@link #setImportantForAutofill(int)}. 8897 * 8898 * @attr ref android.R.styleable#View_importantForAutofill 8899 */ 8900 @ViewDebug.ExportedProperty(mapping = { 8901 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 8902 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 8903 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), 8904 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 8905 to = "yesExcludeDescendants"), 8906 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 8907 to = "noExcludeDescendants")}) 8908 @InspectableProperty(enumMapping = { 8909 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"), 8910 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"), 8911 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"), 8912 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 8913 name = "yesExcludeDescendants"), 8914 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 8915 name = "noExcludeDescendants"), 8916 }) 8917 public @AutofillImportance int getImportantForAutofill() { 8918 return (mPrivateFlags3 8919 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 8920 } 8921 8922 /** 8923 * Sets the mode for determining whether this view is considered important for autofill. 8924 * 8925 * <p>The platform determines the importance for autofill automatically but you 8926 * can use this method to customize the behavior. For example: 8927 * 8928 * <ol> 8929 * <li>When the view contents is irrelevant for autofill (for example, a text field used in a 8930 * "Captcha" challenge), it should be {@link #IMPORTANT_FOR_AUTOFILL_NO}. 8931 * <li>When both the view and its children are irrelevant for autofill (for example, the root 8932 * view of an activity containing a spreadhseet editor), it should be 8933 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 8934 * <li>When the view content is relevant for autofill but its children aren't (for example, 8935 * a credit card expiration date represented by a custom view that overrides the proper 8936 * autofill methods and has 2 children representing the month and year), it should 8937 * be {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}. 8938 * </ol> 8939 * 8940 * <p><b>Note:</b> Setting the mode as {@link #IMPORTANT_FOR_AUTOFILL_NO} or 8941 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and its 8942 * children) will be always be considered not important; for example, when the user explicitly 8943 * makes an autofill request, all views are considered important. See 8944 * {@link #isImportantForAutofill()} for more details about how the View's importance for 8945 * autofill is used. 8946 * 8947 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 8948 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, 8949 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 8950 * 8951 * @attr ref android.R.styleable#View_importantForAutofill 8952 */ 8953 public void setImportantForAutofill(@AutofillImportance int mode) { 8954 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 8955 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 8956 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 8957 } 8958 8959 /** 8960 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 8961 * associated with this view is considered important for autofill purposes. 8962 * 8963 * <p>Generally speaking, a view is important for autofill if: 8964 * <ol> 8965 * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}. 8966 * <li>The view contents can help an {@link android.service.autofill.AutofillService} 8967 * determine how other views can be autofilled. 8968 * <ol> 8969 * 8970 * <p>For example, view containers should typically return {@code false} for performance reasons 8971 * (since the important info is provided by their children), but if its properties have relevant 8972 * information (for example, a resource id called {@code credentials}, it should return 8973 * {@code true}. On the other hand, views representing labels or editable fields should 8974 * typically return {@code true}, but in some cases they could return {@code false} 8975 * (for example, if they're part of a "Captcha" mechanism). 8976 * 8977 * <p>The value returned by this method depends on the value returned by 8978 * {@link #getImportantForAutofill()}: 8979 * 8980 * <ol> 8981 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_YES} or 8982 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, then it returns {@code true} 8983 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_NO} or 8984 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}, then it returns {@code false} 8985 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, then it uses some simple heuristics 8986 * that can return {@code true} in some cases (like a container with a resource id), 8987 * but {@code false} in most. 8988 * <li>otherwise, it returns {@code false}. 8989 * </ol> 8990 * 8991 * <p>When a view is considered important for autofill: 8992 * <ul> 8993 * <li>The view might automatically trigger an autofill request when focused on. 8994 * <li>The contents of the view are included in the {@link ViewStructure} used in an autofill 8995 * request. 8996 * </ul> 8997 * 8998 * <p>On the other hand, when a view is considered not important for autofill: 8999 * <ul> 9000 * <li>The view never automatically triggers autofill requests, but it can trigger a manual 9001 * request through {@link AutofillManager#requestAutofill(View)}. 9002 * <li>The contents of the view are not included in the {@link ViewStructure} used in an 9003 * autofill request, unless the request has the 9004 * {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag. 9005 * </ul> 9006 * 9007 * @return whether the view is considered important for autofill. 9008 * 9009 * @see #setImportantForAutofill(int) 9010 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 9011 * @see #IMPORTANT_FOR_AUTOFILL_YES 9012 * @see #IMPORTANT_FOR_AUTOFILL_NO 9013 * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 9014 * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9015 * @see AutofillManager#requestAutofill(View) 9016 */ 9017 public final boolean isImportantForAutofill() { 9018 // Check parent mode to ensure we're not hidden. 9019 ViewParent parent = mParent; 9020 while (parent instanceof View) { 9021 final int parentImportance = ((View) parent).getImportantForAutofill(); 9022 if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9023 || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) { 9024 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9025 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 9026 + "because parent " + parent + "'s importance is " + parentImportance); 9027 } 9028 return false; 9029 } 9030 parent = parent.getParent(); 9031 } 9032 9033 final int importance = getImportantForAutofill(); 9034 9035 // First, check the explicit states. 9036 if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 9037 || importance == IMPORTANT_FOR_AUTOFILL_YES) { 9038 return true; 9039 } 9040 if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9041 || importance == IMPORTANT_FOR_AUTOFILL_NO) { 9042 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9043 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 9044 + "because its importance is " + importance); 9045 } 9046 return false; 9047 } 9048 9049 // Then use some heuristics to handle AUTO. 9050 if (importance != IMPORTANT_FOR_AUTOFILL_AUTO) { 9051 Log.w(AUTOFILL_LOG_TAG, "invalid autofill importance (" + importance + " on view " 9052 + this); 9053 return false; 9054 } 9055 9056 // Always include views that have an explicit resource id. 9057 final int id = mID; 9058 if (id != NO_ID && !isViewIdGenerated(id)) { 9059 final Resources res = getResources(); 9060 String entry = null; 9061 String pkg = null; 9062 try { 9063 entry = res.getResourceEntryName(id); 9064 pkg = res.getResourcePackageName(id); 9065 } catch (Resources.NotFoundException e) { 9066 // ignore 9067 } 9068 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 9069 return true; 9070 } 9071 } 9072 9073 // If the app developer explicitly set hints for it, it's important. 9074 if (getAutofillHints() != null) { 9075 return true; 9076 } 9077 9078 // Otherwise, assume it's not important... 9079 return false; 9080 } 9081 9082 /** 9083 * Sets the (optional) {@link ContentCaptureSession} associated with this view. 9084 * 9085 * <p>This method should be called when you need to associate a {@link ContentCaptureContext} to 9086 * the content capture events associated with this view or its view hierarchy (if it's a 9087 * {@link ViewGroup}). 9088 * 9089 * <p>For example, if your activity is associated with a web domain, first you would need to 9090 * set the context for the main DOM: 9091 * 9092 * <pre> 9093 * ContentCaptureSession mainSession = rootView.getContentCaptureSession(); 9094 * mainSession.setContentCaptureContext(ContentCaptureContext.forLocusId(Uri.parse(myUrl)); 9095 * </pre> 9096 * 9097 * <p>Then if the page had an {@code IFRAME}, you would create a new session for it: 9098 * 9099 * <pre> 9100 * ContentCaptureSession iframeSession = mainSession.createContentCaptureSession( 9101 * ContentCaptureContext.forLocusId(Uri.parse(iframeUrl))); 9102 * iframeView.setContentCaptureSession(iframeSession); 9103 * </pre> 9104 * 9105 * @param contentCaptureSession a session created by 9106 * {@link ContentCaptureSession#createContentCaptureSession( 9107 * android.view.contentcapture.ContentCaptureContext)}. 9108 */ 9109 public void setContentCaptureSession(@Nullable ContentCaptureSession contentCaptureSession) { 9110 mContentCaptureSession = contentCaptureSession; 9111 } 9112 9113 /** 9114 * Gets the session used to notify content capture events. 9115 * 9116 * @return session explicitly set by {@link #setContentCaptureSession(ContentCaptureSession)}, 9117 * inherited by ancestors, default session or {@code null} if content capture is disabled for 9118 * this view. 9119 */ 9120 @Nullable 9121 public final ContentCaptureSession getContentCaptureSession() { 9122 if (mCachedContentCaptureSession != null) { 9123 return mCachedContentCaptureSession; 9124 } 9125 9126 mCachedContentCaptureSession = getAndCacheContentCaptureSession(); 9127 return mCachedContentCaptureSession; 9128 } 9129 9130 @Nullable 9131 private ContentCaptureSession getAndCacheContentCaptureSession() { 9132 // First try the session explicitly set by setContentCaptureSession() 9133 if (mContentCaptureSession != null) return mContentCaptureSession; 9134 9135 // Then the session explicitly set in an ancestor 9136 ContentCaptureSession session = null; 9137 if (mParent instanceof View) { 9138 session = ((View) mParent).getContentCaptureSession(); 9139 } 9140 9141 // Finally, if no session was explicitly set, use the context's default session. 9142 if (session == null) { 9143 final ContentCaptureManager ccm = mContext 9144 .getSystemService(ContentCaptureManager.class); 9145 return ccm == null ? null : ccm.getMainContentCaptureSession(); 9146 } 9147 return session; 9148 } 9149 9150 @Nullable 9151 private AutofillManager getAutofillManager() { 9152 return mContext.getSystemService(AutofillManager.class); 9153 } 9154 9155 private boolean isAutofillable() { 9156 if (getAutofillType() == AUTOFILL_TYPE_NONE) return false; 9157 9158 if (!isImportantForAutofill()) { 9159 // View is not important for "regular" autofill, so we must check if Augmented Autofill 9160 // is enabled for the activity 9161 final AutofillOptions options = mContext.getAutofillOptions(); 9162 if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { 9163 return false; 9164 } 9165 final AutofillManager afm = getAutofillManager(); 9166 if (afm == null) return false; 9167 afm.notifyViewEnteredForAugmentedAutofill(this); 9168 } 9169 9170 return getAutofillViewId() > LAST_APP_AUTOFILL_ID; 9171 } 9172 9173 /** @hide */ 9174 public boolean canNotifyAutofillEnterExitEvent() { 9175 return isAutofillable() && isAttachedToWindow(); 9176 } 9177 9178 private void populateVirtualStructure(ViewStructure structure, 9179 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, 9180 boolean forAutofill) { 9181 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 9182 null, null, info.getViewIdResourceName()); 9183 Rect rect = structure.getTempRect(); 9184 info.getBoundsInParent(rect); 9185 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 9186 structure.setVisibility(VISIBLE); 9187 structure.setEnabled(info.isEnabled()); 9188 if (info.isClickable()) { 9189 structure.setClickable(true); 9190 } 9191 if (info.isFocusable()) { 9192 structure.setFocusable(true); 9193 } 9194 if (info.isFocused()) { 9195 structure.setFocused(true); 9196 } 9197 if (info.isAccessibilityFocused()) { 9198 structure.setAccessibilityFocused(true); 9199 } 9200 if (info.isSelected()) { 9201 structure.setSelected(true); 9202 } 9203 if (info.isLongClickable()) { 9204 structure.setLongClickable(true); 9205 } 9206 if (info.isCheckable()) { 9207 structure.setCheckable(true); 9208 if (info.isChecked()) { 9209 structure.setChecked(true); 9210 } 9211 } 9212 if (info.isContextClickable()) { 9213 structure.setContextClickable(true); 9214 } 9215 if (forAutofill) { 9216 structure.setAutofillId(new AutofillId(getAutofillId(), 9217 AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()))); 9218 } 9219 CharSequence cname = info.getClassName(); 9220 structure.setClassName(cname != null ? cname.toString() : null); 9221 structure.setContentDescription(info.getContentDescription()); 9222 if (forAutofill) { 9223 final int maxTextLength = info.getMaxTextLength(); 9224 if (maxTextLength != -1) { 9225 structure.setMaxTextLength(maxTextLength); 9226 } 9227 structure.setHint(info.getHintText()); 9228 } 9229 CharSequence text = info.getText(); 9230 boolean hasText = text != null || info.getError() != null; 9231 if (hasText) { 9232 structure.setText(text, info.getTextSelectionStart(), info.getTextSelectionEnd()); 9233 } 9234 if (forAutofill) { 9235 if (info.isEditable()) { 9236 structure.setDataIsSensitive(true); 9237 if (hasText) { 9238 structure.setAutofillType(AUTOFILL_TYPE_TEXT); 9239 structure.setAutofillValue(AutofillValue.forText(text)); 9240 } 9241 int inputType = info.getInputType(); 9242 if (inputType == 0 && info.isPassword()) { 9243 inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD; 9244 } 9245 structure.setInputType(inputType); 9246 } else { 9247 structure.setDataIsSensitive(false); 9248 } 9249 } 9250 final int NCHILDREN = info.getChildCount(); 9251 if (NCHILDREN > 0) { 9252 structure.setChildCount(NCHILDREN); 9253 for (int i=0; i<NCHILDREN; i++) { 9254 if (AccessibilityNodeInfo.getVirtualDescendantId(info.getChildNodeIds().get(i)) 9255 == AccessibilityNodeProvider.HOST_VIEW_ID) { 9256 Log.e(VIEW_LOG_TAG, "Virtual view pointing to its host. Ignoring"); 9257 continue; 9258 } 9259 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 9260 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 9261 ViewStructure child = structure.newChild(i); 9262 populateVirtualStructure(child, provider, cinfo, forAutofill); 9263 cinfo.recycle(); 9264 } 9265 } 9266 } 9267 9268 /** 9269 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 9270 * implementation calls {@link #onProvideStructure} and 9271 * {@link #onProvideVirtualStructure}. 9272 */ 9273 public void dispatchProvideStructure(ViewStructure structure) { 9274 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 9275 } 9276 9277 /** 9278 * Dispatches creation of a {@link ViewStructure}s for autofill purposes down the hierarchy, 9279 * when an Assist structure is being created as part of an autofill request. 9280 * 9281 * <p>The default implementation does the following: 9282 * <ul> 9283 * <li>Sets the {@link AutofillId} in the structure. 9284 * <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}. 9285 * <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 9286 * </ul> 9287 * 9288 * <p>Typically, this method should only be overridden by subclasses that provide a view 9289 * hierarchy (such as {@link ViewGroup}) - other classes should override 9290 * {@link #onProvideAutofillStructure(ViewStructure, int)} or 9291 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} instead. 9292 * 9293 * <p>When overridden, it must: 9294 * 9295 * <ul> 9296 * <li>Either call 9297 * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly 9298 * set the {@link AutofillId} in the structure (for example, by calling 9299 * {@code structure.setAutofillId(getAutofillId())}). 9300 * <li>Decide how to handle the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag - when 9301 * set, all views in the structure should be considered important for autofill, 9302 * regardless of what {@link #isImportantForAutofill()} returns. We encourage you to 9303 * respect this flag to provide a better user experience - this flag is typically used 9304 * when an user explicitly requested autofill. If the flag is not set, 9305 * then only views marked as important for autofill should be included in the 9306 * structure - skipping non-important views optimizes the overall autofill performance. 9307 * </ul> 9308 * 9309 * @param structure fill in with structured view data for autofill purposes. 9310 * @param flags optional flags. 9311 * 9312 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 9313 */ 9314 public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, 9315 @AutofillFlags int flags) { 9316 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 9317 } 9318 9319 private void dispatchProvideStructure(@NonNull ViewStructure structure, 9320 @ViewStructureType int viewFor, @AutofillFlags int flags) { 9321 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { 9322 structure.setAutofillId(getAutofillId()); 9323 onProvideAutofillStructure(structure, flags); 9324 onProvideAutofillVirtualStructure(structure, flags); 9325 } else if (!isAssistBlocked()) { 9326 onProvideStructure(structure); 9327 onProvideVirtualStructure(structure); 9328 } else { 9329 structure.setClassName(getAccessibilityClassName().toString()); 9330 structure.setAssistBlocked(true); 9331 } 9332 } 9333 9334 /** 9335 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 9336 * 9337 * Note: Called from the default {@link AccessibilityDelegate}. 9338 * 9339 * @hide 9340 */ 9341 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 9342 if (mAttachInfo == null) { 9343 return; 9344 } 9345 9346 Rect bounds = mAttachInfo.mTmpInvalRect; 9347 9348 getDrawingRect(bounds); 9349 info.setBoundsInParent(bounds); 9350 9351 getBoundsOnScreen(bounds, true); 9352 info.setBoundsInScreen(bounds); 9353 9354 ViewParent parent = getParentForAccessibility(); 9355 if (parent instanceof View) { 9356 info.setParent((View) parent); 9357 } 9358 9359 if (mID != View.NO_ID) { 9360 View rootView = getRootView(); 9361 if (rootView == null) { 9362 rootView = this; 9363 } 9364 9365 View label = rootView.findLabelForView(this, mID); 9366 if (label != null) { 9367 info.setLabeledBy(label); 9368 } 9369 9370 if ((mAttachInfo.mAccessibilityFetchFlags 9371 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 9372 && Resources.resourceHasPackage(mID)) { 9373 try { 9374 String viewId = getResources().getResourceName(mID); 9375 info.setViewIdResourceName(viewId); 9376 } catch (Resources.NotFoundException nfe) { 9377 /* ignore */ 9378 } 9379 } 9380 } 9381 9382 if (mLabelForId != View.NO_ID) { 9383 View rootView = getRootView(); 9384 if (rootView == null) { 9385 rootView = this; 9386 } 9387 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 9388 if (labeled != null) { 9389 info.setLabelFor(labeled); 9390 } 9391 } 9392 9393 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 9394 View rootView = getRootView(); 9395 if (rootView == null) { 9396 rootView = this; 9397 } 9398 View next = rootView.findViewInsideOutShouldExist(this, 9399 mAccessibilityTraversalBeforeId); 9400 if (next != null && next.includeForAccessibility()) { 9401 info.setTraversalBefore(next); 9402 } 9403 } 9404 9405 if (mAccessibilityTraversalAfterId != View.NO_ID) { 9406 View rootView = getRootView(); 9407 if (rootView == null) { 9408 rootView = this; 9409 } 9410 View next = rootView.findViewInsideOutShouldExist(this, 9411 mAccessibilityTraversalAfterId); 9412 if (next != null && next.includeForAccessibility()) { 9413 info.setTraversalAfter(next); 9414 } 9415 } 9416 9417 info.setVisibleToUser(isVisibleToUser()); 9418 9419 info.setImportantForAccessibility(isImportantForAccessibility()); 9420 info.setPackageName(mContext.getPackageName()); 9421 info.setClassName(getAccessibilityClassName()); 9422 info.setContentDescription(getContentDescription()); 9423 9424 info.setEnabled(isEnabled()); 9425 info.setClickable(isClickable()); 9426 info.setFocusable(isFocusable()); 9427 info.setScreenReaderFocusable(isScreenReaderFocusable()); 9428 info.setFocused(isFocused()); 9429 info.setAccessibilityFocused(isAccessibilityFocused()); 9430 info.setSelected(isSelected()); 9431 info.setLongClickable(isLongClickable()); 9432 info.setContextClickable(isContextClickable()); 9433 info.setLiveRegion(getAccessibilityLiveRegion()); 9434 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipText != null)) { 9435 info.setTooltipText(mTooltipInfo.mTooltipText); 9436 info.addAction((mTooltipInfo.mTooltipPopup == null) 9437 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP 9438 : AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP); 9439 } 9440 9441 // TODO: These make sense only if we are in an AdapterView but all 9442 // views can be selected. Maybe from accessibility perspective 9443 // we should report as selectable view in an AdapterView. 9444 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 9445 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 9446 9447 if (isFocusable()) { 9448 if (isFocused()) { 9449 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 9450 } else { 9451 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 9452 } 9453 } 9454 9455 if (!isAccessibilityFocused()) { 9456 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 9457 } else { 9458 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 9459 } 9460 9461 if (isClickable() && isEnabled()) { 9462 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 9463 } 9464 9465 if (isLongClickable() && isEnabled()) { 9466 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 9467 } 9468 9469 if (isContextClickable() && isEnabled()) { 9470 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 9471 } 9472 9473 CharSequence text = getIterableTextForAccessibility(); 9474 if (text != null && text.length() > 0) { 9475 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 9476 9477 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 9478 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 9479 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 9480 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 9481 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 9482 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 9483 } 9484 9485 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 9486 populateAccessibilityNodeInfoDrawingOrderInParent(info); 9487 info.setPaneTitle(mAccessibilityPaneTitle); 9488 info.setHeading(isAccessibilityHeading()); 9489 9490 if (mTouchDelegate != null) { 9491 info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo()); 9492 } 9493 } 9494 9495 /** 9496 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 9497 * additional data. 9498 * <p> 9499 * This method only needs overloading if the node is marked as having extra data available. 9500 * </p> 9501 * 9502 * @param info The info to which to add the extra data. Never {@code null}. 9503 * @param extraDataKey A key specifying the type of extra data to add to the info. The 9504 * extra data should be added to the {@link Bundle} returned by 9505 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 9506 * {@code null}. 9507 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 9508 * {@code null} if the service provided no arguments. 9509 * 9510 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 9511 */ 9512 public void addExtraDataToAccessibilityNodeInfo( 9513 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 9514 @Nullable Bundle arguments) { 9515 } 9516 9517 /** 9518 * Determine the order in which this view will be drawn relative to its siblings for a11y 9519 * 9520 * @param info The info whose drawing order should be populated 9521 */ 9522 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 9523 /* 9524 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 9525 * drawing order may not be well-defined, and some Views with custom drawing order may 9526 * not be initialized sufficiently to respond properly getChildDrawingOrder. 9527 */ 9528 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 9529 info.setDrawingOrder(0); 9530 return; 9531 } 9532 int drawingOrderInParent = 1; 9533 // Iterate up the hierarchy if parents are not important for a11y 9534 View viewAtDrawingLevel = this; 9535 final ViewParent parent = getParentForAccessibility(); 9536 while (viewAtDrawingLevel != parent) { 9537 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 9538 if (!(currentParent instanceof ViewGroup)) { 9539 // Should only happen for the Decor 9540 drawingOrderInParent = 0; 9541 break; 9542 } else { 9543 final ViewGroup parentGroup = (ViewGroup) currentParent; 9544 final int childCount = parentGroup.getChildCount(); 9545 if (childCount > 1) { 9546 List<View> preorderedList = parentGroup.buildOrderedChildList(); 9547 if (preorderedList != null) { 9548 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 9549 for (int i = 0; i < childDrawIndex; i++) { 9550 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 9551 } 9552 } else { 9553 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 9554 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 9555 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 9556 .getChildDrawingOrder(childCount, childIndex) : childIndex; 9557 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 9558 if (childDrawIndex != 0) { 9559 for (int i = 0; i < numChildrenToIterate; i++) { 9560 final int otherDrawIndex = (customOrder ? 9561 parentGroup.getChildDrawingOrder(childCount, i) : i); 9562 if (otherDrawIndex < childDrawIndex) { 9563 drawingOrderInParent += 9564 numViewsForAccessibility(parentGroup.getChildAt(i)); 9565 } 9566 } 9567 } 9568 } 9569 } 9570 } 9571 viewAtDrawingLevel = (View) currentParent; 9572 } 9573 info.setDrawingOrder(drawingOrderInParent); 9574 } 9575 9576 private static int numViewsForAccessibility(View view) { 9577 if (view != null) { 9578 if (view.includeForAccessibility()) { 9579 return 1; 9580 } else if (view instanceof ViewGroup) { 9581 return ((ViewGroup) view).getNumChildrenForAccessibility(); 9582 } 9583 } 9584 return 0; 9585 } 9586 9587 private View findLabelForView(View view, int labeledId) { 9588 if (mMatchLabelForPredicate == null) { 9589 mMatchLabelForPredicate = new MatchLabelForPredicate(); 9590 } 9591 mMatchLabelForPredicate.mLabeledId = labeledId; 9592 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 9593 } 9594 9595 /** 9596 * Computes whether this virtual autofill view is visible to the user. 9597 * 9598 * <p><b>Note: </b>By default it returns {@code true}, but views providing a virtual hierarchy 9599 * view must override it. 9600 * 9601 * @return Whether the view is visible on the screen. 9602 */ 9603 public boolean isVisibleToUserForAutofill(int virtualId) { 9604 if (mContext.isAutofillCompatibilityEnabled()) { 9605 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 9606 if (provider != null) { 9607 final AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(virtualId); 9608 if (node != null) { 9609 return node.isVisibleToUser(); 9610 } 9611 // if node is null, assume it's not visible anymore 9612 } else { 9613 Log.w(VIEW_LOG_TAG, "isVisibleToUserForAutofill(" + virtualId + "): no provider"); 9614 } 9615 return false; 9616 } 9617 return true; 9618 } 9619 9620 /** 9621 * Computes whether this view is visible to the user. Such a view is 9622 * attached, visible, all its predecessors are visible, it is not clipped 9623 * entirely by its predecessors, and has an alpha greater than zero. 9624 * 9625 * @return Whether the view is visible on the screen. 9626 * 9627 * @hide 9628 */ 9629 @UnsupportedAppUsage 9630 public boolean isVisibleToUser() { 9631 return isVisibleToUser(null); 9632 } 9633 9634 /** 9635 * Computes whether the given portion of this view is visible to the user. 9636 * Such a view is attached, visible, all its predecessors are visible, 9637 * has an alpha greater than zero, and the specified portion is not 9638 * clipped entirely by its predecessors. 9639 * 9640 * @param boundInView the portion of the view to test; coordinates should be relative; may be 9641 * <code>null</code>, and the entire view will be tested in this case. 9642 * When <code>true</code> is returned by the function, the actual visible 9643 * region will be stored in this parameter; that is, if boundInView is fully 9644 * contained within the view, no modification will be made, otherwise regions 9645 * outside of the visible area of the view will be clipped. 9646 * 9647 * @return Whether the specified portion of the view is visible on the screen. 9648 * 9649 * @hide 9650 */ 9651 @UnsupportedAppUsage 9652 protected boolean isVisibleToUser(Rect boundInView) { 9653 if (mAttachInfo != null) { 9654 // Attached to invisible window means this view is not visible. 9655 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 9656 return false; 9657 } 9658 // An invisible predecessor or one with alpha zero means 9659 // that this view is not visible to the user. 9660 Object current = this; 9661 while (current instanceof View) { 9662 View view = (View) current; 9663 // We have attach info so this view is attached and there is no 9664 // need to check whether we reach to ViewRootImpl on the way up. 9665 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 9666 view.getVisibility() != VISIBLE) { 9667 return false; 9668 } 9669 current = view.mParent; 9670 } 9671 // Check if the view is entirely covered by its predecessors. 9672 Rect visibleRect = mAttachInfo.mTmpInvalRect; 9673 Point offset = mAttachInfo.mPoint; 9674 if (!getGlobalVisibleRect(visibleRect, offset)) { 9675 return false; 9676 } 9677 // Check if the visible portion intersects the rectangle of interest. 9678 if (boundInView != null) { 9679 visibleRect.offset(-offset.x, -offset.y); 9680 return boundInView.intersect(visibleRect); 9681 } 9682 return true; 9683 } 9684 return false; 9685 } 9686 9687 /** 9688 * Returns the delegate for implementing accessibility support via 9689 * composition. For more details see {@link AccessibilityDelegate}. 9690 * 9691 * @return The delegate, or null if none set. 9692 */ 9693 public AccessibilityDelegate getAccessibilityDelegate() { 9694 return mAccessibilityDelegate; 9695 } 9696 9697 /** 9698 * Sets a delegate for implementing accessibility support via composition 9699 * (as opposed to inheritance). For more details, see 9700 * {@link AccessibilityDelegate}. 9701 * <p> 9702 * <strong>Note:</strong> On platform versions prior to 9703 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 9704 * views in the {@code android.widget.*} package are called <i>before</i> 9705 * host methods. This prevents certain properties such as class name from 9706 * being modified by overriding 9707 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 9708 * as any changes will be overwritten by the host class. 9709 * <p> 9710 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 9711 * methods are called <i>after</i> host methods, which all properties to be 9712 * modified without being overwritten by the host class. 9713 * 9714 * @param delegate the object to which accessibility method calls should be 9715 * delegated 9716 * @see AccessibilityDelegate 9717 */ 9718 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 9719 mAccessibilityDelegate = delegate; 9720 } 9721 9722 /** 9723 * Gets the provider for managing a virtual view hierarchy rooted at this View 9724 * and reported to {@link android.accessibilityservice.AccessibilityService}s 9725 * that explore the window content. 9726 * <p> 9727 * If this method returns an instance, this instance is responsible for managing 9728 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 9729 * View including the one representing the View itself. Similarly the returned 9730 * instance is responsible for performing accessibility actions on any virtual 9731 * view or the root view itself. 9732 * </p> 9733 * <p> 9734 * If an {@link AccessibilityDelegate} has been specified via calling 9735 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 9736 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 9737 * is responsible for handling this call. 9738 * </p> 9739 * 9740 * @return The provider. 9741 * 9742 * @see AccessibilityNodeProvider 9743 */ 9744 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 9745 if (mAccessibilityDelegate != null) { 9746 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 9747 } else { 9748 return null; 9749 } 9750 } 9751 9752 /** 9753 * Gets the unique identifier of this view on the screen for accessibility purposes. 9754 * 9755 * @return The view accessibility id. 9756 * 9757 * @hide 9758 */ 9759 @UnsupportedAppUsage 9760 public int getAccessibilityViewId() { 9761 if (mAccessibilityViewId == NO_ID) { 9762 mAccessibilityViewId = sNextAccessibilityViewId++; 9763 } 9764 return mAccessibilityViewId; 9765 } 9766 9767 /** 9768 * Gets the unique identifier of this view on the screen for autofill purposes. 9769 * 9770 * @return The view autofill id. 9771 * 9772 * @hide 9773 */ 9774 public int getAutofillViewId() { 9775 if (mAutofillViewId == NO_ID) { 9776 mAutofillViewId = mContext.getNextAutofillId(); 9777 } 9778 return mAutofillViewId; 9779 } 9780 9781 /** 9782 * Gets the unique identifier of the window in which this View reseides. 9783 * 9784 * @return The window accessibility id. 9785 * 9786 * @hide 9787 */ 9788 public int getAccessibilityWindowId() { 9789 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 9790 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 9791 } 9792 9793 /** 9794 * Returns the {@link View}'s content description. 9795 * <p> 9796 * <strong>Note:</strong> Do not override this method, as it will have no 9797 * effect on the content description presented to accessibility services. 9798 * You must call {@link #setContentDescription(CharSequence)} to modify the 9799 * content description. 9800 * 9801 * @return the content description 9802 * @see #setContentDescription(CharSequence) 9803 * @attr ref android.R.styleable#View_contentDescription 9804 */ 9805 @ViewDebug.ExportedProperty(category = "accessibility") 9806 @InspectableProperty 9807 public CharSequence getContentDescription() { 9808 return mContentDescription; 9809 } 9810 9811 /** 9812 * Sets the {@link View}'s content description. 9813 * <p> 9814 * A content description briefly describes the view and is primarily used 9815 * for accessibility support to determine how a view should be presented to 9816 * the user. In the case of a view with no textual representation, such as 9817 * {@link android.widget.ImageButton}, a useful content description 9818 * explains what the view does. For example, an image button with a phone 9819 * icon that is used to place a call may use "Call" as its content 9820 * description. An image of a floppy disk that is used to save a file may 9821 * use "Save". 9822 * 9823 * @param contentDescription The content description. 9824 * @see #getContentDescription() 9825 * @attr ref android.R.styleable#View_contentDescription 9826 */ 9827 @RemotableViewMethod 9828 public void setContentDescription(CharSequence contentDescription) { 9829 if (mContentDescription == null) { 9830 if (contentDescription == null) { 9831 return; 9832 } 9833 } else if (mContentDescription.equals(contentDescription)) { 9834 return; 9835 } 9836 mContentDescription = contentDescription; 9837 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 9838 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 9839 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 9840 notifySubtreeAccessibilityStateChangedIfNeeded(); 9841 } else { 9842 notifyViewAccessibilityStateChangedIfNeeded( 9843 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 9844 } 9845 } 9846 9847 /** 9848 * Sets the id of a view before which this one is visited in accessibility traversal. 9849 * A screen-reader must visit the content of this view before the content of the one 9850 * it precedes. For example, if view B is set to be before view A, then a screen-reader 9851 * will traverse the entire content of B before traversing the entire content of A, 9852 * regardles of what traversal strategy it is using. 9853 * <p> 9854 * Views that do not have specified before/after relationships are traversed in order 9855 * determined by the screen-reader. 9856 * </p> 9857 * <p> 9858 * Setting that this view is before a view that is not important for accessibility 9859 * or if this view is not important for accessibility will have no effect as the 9860 * screen-reader is not aware of unimportant views. 9861 * </p> 9862 * 9863 * @param beforeId The id of a view this one precedes in accessibility traversal. 9864 * 9865 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 9866 * 9867 * @see #setImportantForAccessibility(int) 9868 */ 9869 @RemotableViewMethod 9870 public void setAccessibilityTraversalBefore(@IdRes int beforeId) { 9871 if (mAccessibilityTraversalBeforeId == beforeId) { 9872 return; 9873 } 9874 mAccessibilityTraversalBeforeId = beforeId; 9875 notifyViewAccessibilityStateChangedIfNeeded( 9876 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9877 } 9878 9879 /** 9880 * Gets the id of a view before which this one is visited in accessibility traversal. 9881 * 9882 * @return The id of a view this one precedes in accessibility traversal if 9883 * specified, otherwise {@link #NO_ID}. 9884 * 9885 * @see #setAccessibilityTraversalBefore(int) 9886 */ 9887 @IdRes 9888 @InspectableProperty 9889 public int getAccessibilityTraversalBefore() { 9890 return mAccessibilityTraversalBeforeId; 9891 } 9892 9893 /** 9894 * Sets the id of a view after which this one is visited in accessibility traversal. 9895 * A screen-reader must visit the content of the other view before the content of this 9896 * one. For example, if view B is set to be after view A, then a screen-reader 9897 * will traverse the entire content of A before traversing the entire content of B, 9898 * regardles of what traversal strategy it is using. 9899 * <p> 9900 * Views that do not have specified before/after relationships are traversed in order 9901 * determined by the screen-reader. 9902 * </p> 9903 * <p> 9904 * Setting that this view is after a view that is not important for accessibility 9905 * or if this view is not important for accessibility will have no effect as the 9906 * screen-reader is not aware of unimportant views. 9907 * </p> 9908 * 9909 * @param afterId The id of a view this one succedees in accessibility traversal. 9910 * 9911 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 9912 * 9913 * @see #setImportantForAccessibility(int) 9914 */ 9915 @RemotableViewMethod 9916 public void setAccessibilityTraversalAfter(@IdRes int afterId) { 9917 if (mAccessibilityTraversalAfterId == afterId) { 9918 return; 9919 } 9920 mAccessibilityTraversalAfterId = afterId; 9921 notifyViewAccessibilityStateChangedIfNeeded( 9922 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9923 } 9924 9925 /** 9926 * Gets the id of a view after which this one is visited in accessibility traversal. 9927 * 9928 * @return The id of a view this one succeedes in accessibility traversal if 9929 * specified, otherwise {@link #NO_ID}. 9930 * 9931 * @see #setAccessibilityTraversalAfter(int) 9932 */ 9933 @IdRes 9934 @InspectableProperty 9935 public int getAccessibilityTraversalAfter() { 9936 return mAccessibilityTraversalAfterId; 9937 } 9938 9939 /** 9940 * Gets the id of a view for which this view serves as a label for 9941 * accessibility purposes. 9942 * 9943 * @return The labeled view id. 9944 */ 9945 @IdRes 9946 @ViewDebug.ExportedProperty(category = "accessibility") 9947 @InspectableProperty 9948 public int getLabelFor() { 9949 return mLabelForId; 9950 } 9951 9952 /** 9953 * Sets the id of a view for which this view serves as a label for 9954 * accessibility purposes. 9955 * 9956 * @param id The labeled view id. 9957 */ 9958 @RemotableViewMethod 9959 public void setLabelFor(@IdRes int id) { 9960 if (mLabelForId == id) { 9961 return; 9962 } 9963 mLabelForId = id; 9964 if (mLabelForId != View.NO_ID 9965 && mID == View.NO_ID) { 9966 mID = generateViewId(); 9967 } 9968 notifyViewAccessibilityStateChangedIfNeeded( 9969 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 9970 } 9971 9972 /** 9973 * Invoked whenever this view loses focus, either by losing window focus or by losing 9974 * focus within its window. This method can be used to clear any state tied to the 9975 * focus. For instance, if a button is held pressed with the trackball and the window 9976 * loses focus, this method can be used to cancel the press. 9977 * 9978 * Subclasses of View overriding this method should always call super.onFocusLost(). 9979 * 9980 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 9981 * @see #onWindowFocusChanged(boolean) 9982 * 9983 * @hide pending API council approval 9984 */ 9985 @CallSuper 9986 @UnsupportedAppUsage 9987 protected void onFocusLost() { 9988 resetPressedState(); 9989 } 9990 9991 private void resetPressedState() { 9992 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 9993 return; 9994 } 9995 9996 if (isPressed()) { 9997 setPressed(false); 9998 9999 if (!mHasPerformedLongPress) { 10000 removeLongPressCallback(); 10001 } 10002 } 10003 } 10004 10005 /** 10006 * Returns true if this view has focus 10007 * 10008 * @return True if this view has focus, false otherwise. 10009 */ 10010 @ViewDebug.ExportedProperty(category = "focus") 10011 @InspectableProperty(hasAttributeId = false) 10012 public boolean isFocused() { 10013 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 10014 } 10015 10016 /** 10017 * Find the view in the hierarchy rooted at this view that currently has 10018 * focus. 10019 * 10020 * @return The view that currently has focus, or null if no focused view can 10021 * be found. 10022 */ 10023 public View findFocus() { 10024 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 10025 } 10026 10027 /** 10028 * Indicates whether this view is one of the set of scrollable containers in 10029 * its window. 10030 * 10031 * @return whether this view is one of the set of scrollable containers in 10032 * its window 10033 * 10034 * @attr ref android.R.styleable#View_isScrollContainer 10035 */ 10036 @InspectableProperty(name = "isScrollContainer") 10037 public boolean isScrollContainer() { 10038 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 10039 } 10040 10041 /** 10042 * Change whether this view is one of the set of scrollable containers in 10043 * its window. This will be used to determine whether the window can 10044 * resize or must pan when a soft input area is open -- scrollable 10045 * containers allow the window to use resize mode since the container 10046 * will appropriately shrink. 10047 * 10048 * @attr ref android.R.styleable#View_isScrollContainer 10049 */ 10050 public void setScrollContainer(boolean isScrollContainer) { 10051 if (isScrollContainer) { 10052 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 10053 mAttachInfo.mScrollContainers.add(this); 10054 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 10055 } 10056 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 10057 } else { 10058 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 10059 mAttachInfo.mScrollContainers.remove(this); 10060 } 10061 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 10062 } 10063 } 10064 10065 /** 10066 * Returns the quality of the drawing cache. 10067 * 10068 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 10069 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 10070 * 10071 * @see #setDrawingCacheQuality(int) 10072 * @see #setDrawingCacheEnabled(boolean) 10073 * @see #isDrawingCacheEnabled() 10074 * 10075 * @attr ref android.R.styleable#View_drawingCacheQuality 10076 * 10077 * @deprecated The view drawing cache was largely made obsolete with the introduction of 10078 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 10079 * layers are largely unnecessary and can easily result in a net loss in performance due to the 10080 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 10081 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 10082 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 10083 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 10084 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 10085 * software-rendered usages are discouraged and have compatibility issues with hardware-only 10086 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 10087 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 10088 * reports or unit testing the {@link PixelCopy} API is recommended. 10089 */ 10090 @Deprecated 10091 @DrawingCacheQuality 10092 @InspectableProperty(enumMapping = { 10093 @EnumEntry(value = DRAWING_CACHE_QUALITY_LOW, name = "low"), 10094 @EnumEntry(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"), 10095 @EnumEntry(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto") 10096 }) 10097 public int getDrawingCacheQuality() { 10098 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 10099 } 10100 10101 /** 10102 * Set the drawing cache quality of this view. This value is used only when the 10103 * drawing cache is enabled 10104 * 10105 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 10106 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 10107 * 10108 * @see #getDrawingCacheQuality() 10109 * @see #setDrawingCacheEnabled(boolean) 10110 * @see #isDrawingCacheEnabled() 10111 * 10112 * @attr ref android.R.styleable#View_drawingCacheQuality 10113 * 10114 * @deprecated The view drawing cache was largely made obsolete with the introduction of 10115 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 10116 * layers are largely unnecessary and can easily result in a net loss in performance due to the 10117 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 10118 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 10119 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 10120 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 10121 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 10122 * software-rendered usages are discouraged and have compatibility issues with hardware-only 10123 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 10124 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 10125 * reports or unit testing the {@link PixelCopy} API is recommended. 10126 */ 10127 @Deprecated 10128 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 10129 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 10130 } 10131 10132 /** 10133 * Returns whether the screen should remain on, corresponding to the current 10134 * value of {@link #KEEP_SCREEN_ON}. 10135 * 10136 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 10137 * 10138 * @see #setKeepScreenOn(boolean) 10139 * 10140 * @attr ref android.R.styleable#View_keepScreenOn 10141 */ 10142 @InspectableProperty 10143 public boolean getKeepScreenOn() { 10144 return (mViewFlags & KEEP_SCREEN_ON) != 0; 10145 } 10146 10147 /** 10148 * Controls whether the screen should remain on, modifying the 10149 * value of {@link #KEEP_SCREEN_ON}. 10150 * 10151 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 10152 * 10153 * @see #getKeepScreenOn() 10154 * 10155 * @attr ref android.R.styleable#View_keepScreenOn 10156 */ 10157 public void setKeepScreenOn(boolean keepScreenOn) { 10158 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 10159 } 10160 10161 /** 10162 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 10163 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 10164 * 10165 * @attr ref android.R.styleable#View_nextFocusLeft 10166 */ 10167 @IdRes 10168 @InspectableProperty(name = "nextFocusLeft") 10169 public int getNextFocusLeftId() { 10170 return mNextFocusLeftId; 10171 } 10172 10173 /** 10174 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 10175 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 10176 * decide automatically. 10177 * 10178 * @attr ref android.R.styleable#View_nextFocusLeft 10179 */ 10180 public void setNextFocusLeftId(@IdRes int nextFocusLeftId) { 10181 mNextFocusLeftId = nextFocusLeftId; 10182 } 10183 10184 /** 10185 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 10186 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 10187 * 10188 * @attr ref android.R.styleable#View_nextFocusRight 10189 */ 10190 @IdRes 10191 @InspectableProperty(name = "nextFocusRight") 10192 public int getNextFocusRightId() { 10193 return mNextFocusRightId; 10194 } 10195 10196 /** 10197 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 10198 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 10199 * decide automatically. 10200 * 10201 * @attr ref android.R.styleable#View_nextFocusRight 10202 */ 10203 public void setNextFocusRightId(@IdRes int nextFocusRightId) { 10204 mNextFocusRightId = nextFocusRightId; 10205 } 10206 10207 /** 10208 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 10209 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 10210 * 10211 * @attr ref android.R.styleable#View_nextFocusUp 10212 */ 10213 @IdRes 10214 @InspectableProperty(name = "nextFocusUp") 10215 public int getNextFocusUpId() { 10216 return mNextFocusUpId; 10217 } 10218 10219 /** 10220 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 10221 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 10222 * decide automatically. 10223 * 10224 * @attr ref android.R.styleable#View_nextFocusUp 10225 */ 10226 public void setNextFocusUpId(@IdRes int nextFocusUpId) { 10227 mNextFocusUpId = nextFocusUpId; 10228 } 10229 10230 /** 10231 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 10232 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 10233 * 10234 * @attr ref android.R.styleable#View_nextFocusDown 10235 */ 10236 @IdRes 10237 @InspectableProperty(name = "nextFocusDown") 10238 public int getNextFocusDownId() { 10239 return mNextFocusDownId; 10240 } 10241 10242 /** 10243 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 10244 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 10245 * decide automatically. 10246 * 10247 * @attr ref android.R.styleable#View_nextFocusDown 10248 */ 10249 public void setNextFocusDownId(@IdRes int nextFocusDownId) { 10250 mNextFocusDownId = nextFocusDownId; 10251 } 10252 10253 /** 10254 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 10255 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 10256 * 10257 * @attr ref android.R.styleable#View_nextFocusForward 10258 */ 10259 @IdRes 10260 @InspectableProperty(name = "nextFocusForward") 10261 public int getNextFocusForwardId() { 10262 return mNextFocusForwardId; 10263 } 10264 10265 /** 10266 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 10267 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 10268 * decide automatically. 10269 * 10270 * @attr ref android.R.styleable#View_nextFocusForward 10271 */ 10272 public void setNextFocusForwardId(@IdRes int nextFocusForwardId) { 10273 mNextFocusForwardId = nextFocusForwardId; 10274 } 10275 10276 /** 10277 * Gets the id of the root of the next keyboard navigation cluster. 10278 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 10279 * decide automatically. 10280 * 10281 * @attr ref android.R.styleable#View_nextClusterForward 10282 */ 10283 @IdRes 10284 @InspectableProperty(name = "nextClusterForward") 10285 public int getNextClusterForwardId() { 10286 return mNextClusterForwardId; 10287 } 10288 10289 /** 10290 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 10291 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 10292 * decide automatically. 10293 * 10294 * @attr ref android.R.styleable#View_nextClusterForward 10295 */ 10296 public void setNextClusterForwardId(@IdRes int nextClusterForwardId) { 10297 mNextClusterForwardId = nextClusterForwardId; 10298 } 10299 10300 /** 10301 * Returns the visibility of this view and all of its ancestors 10302 * 10303 * @return True if this view and all of its ancestors are {@link #VISIBLE} 10304 */ 10305 public boolean isShown() { 10306 View current = this; 10307 //noinspection ConstantConditions 10308 do { 10309 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 10310 return false; 10311 } 10312 ViewParent parent = current.mParent; 10313 if (parent == null) { 10314 return false; // We are not attached to the view root 10315 } 10316 if (!(parent instanceof View)) { 10317 return true; 10318 } 10319 current = (View) parent; 10320 } while (current != null); 10321 10322 return false; 10323 } 10324 10325 /** 10326 * Called by the view hierarchy when the content insets for a window have 10327 * changed, to allow it to adjust its content to fit within those windows. 10328 * The content insets tell you the space that the status bar, input method, 10329 * and other system windows infringe on the application's window. 10330 * 10331 * <p>You do not normally need to deal with this function, since the default 10332 * window decoration given to applications takes care of applying it to the 10333 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 10334 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 10335 * and your content can be placed under those system elements. You can then 10336 * use this method within your view hierarchy if you have parts of your UI 10337 * which you would like to ensure are not being covered. 10338 * 10339 * <p>The default implementation of this method simply applies the content 10340 * insets to the view's padding, consuming that content (modifying the 10341 * insets to be 0), and returning true. This behavior is off by default, but can 10342 * be enabled through {@link #setFitsSystemWindows(boolean)}. 10343 * 10344 * <p>This function's traversal down the hierarchy is depth-first. The same content 10345 * insets object is propagated down the hierarchy, so any changes made to it will 10346 * be seen by all following views (including potentially ones above in 10347 * the hierarchy since this is a depth-first traversal). The first view 10348 * that returns true will abort the entire traversal. 10349 * 10350 * <p>The default implementation works well for a situation where it is 10351 * used with a container that covers the entire window, allowing it to 10352 * apply the appropriate insets to its content on all edges. If you need 10353 * a more complicated layout (such as two different views fitting system 10354 * windows, one on the top of the window, and one on the bottom), 10355 * you can override the method and handle the insets however you would like. 10356 * Note that the insets provided by the framework are always relative to the 10357 * far edges of the window, not accounting for the location of the called view 10358 * within that window. (In fact when this method is called you do not yet know 10359 * where the layout will place the view, as it is done before layout happens.) 10360 * 10361 * <p>Note: unlike many View methods, there is no dispatch phase to this 10362 * call. If you are overriding it in a ViewGroup and want to allow the 10363 * call to continue to your children, you must be sure to call the super 10364 * implementation. 10365 * 10366 * <p>Here is a sample layout that makes use of fitting system windows 10367 * to have controls for a video view placed inside of the window decorations 10368 * that it hides and shows. This can be used with code like the second 10369 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 10370 * 10371 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 10372 * 10373 * @param insets Current content insets of the window. Prior to 10374 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 10375 * the insets or else you and Android will be unhappy. 10376 * 10377 * @return {@code true} if this view applied the insets and it should not 10378 * continue propagating further down the hierarchy, {@code false} otherwise. 10379 * @see #getFitsSystemWindows() 10380 * @see #setFitsSystemWindows(boolean) 10381 * @see #setSystemUiVisibility(int) 10382 * 10383 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 10384 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 10385 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 10386 * to implement handling their own insets. 10387 */ 10388 @Deprecated 10389 protected boolean fitSystemWindows(Rect insets) { 10390 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 10391 if (insets == null) { 10392 // Null insets by definition have already been consumed. 10393 // This call cannot apply insets since there are none to apply, 10394 // so return false. 10395 return false; 10396 } 10397 // If we're not in the process of dispatching the newer apply insets call, 10398 // that means we're not in the compatibility path. Dispatch into the newer 10399 // apply insets path and take things from there. 10400 try { 10401 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 10402 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 10403 } finally { 10404 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 10405 } 10406 } else { 10407 // We're being called from the newer apply insets path. 10408 // Perform the standard fallback behavior. 10409 return fitSystemWindowsInt(insets); 10410 } 10411 } 10412 10413 private boolean fitSystemWindowsInt(Rect insets) { 10414 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 10415 mUserPaddingStart = UNDEFINED_PADDING; 10416 mUserPaddingEnd = UNDEFINED_PADDING; 10417 Rect localInsets = sThreadLocal.get(); 10418 if (localInsets == null) { 10419 localInsets = new Rect(); 10420 sThreadLocal.set(localInsets); 10421 } 10422 boolean res = computeFitSystemWindows(insets, localInsets); 10423 mUserPaddingLeftInitial = localInsets.left; 10424 mUserPaddingRightInitial = localInsets.right; 10425 internalSetPadding(localInsets.left, localInsets.top, 10426 localInsets.right, localInsets.bottom); 10427 return res; 10428 } 10429 return false; 10430 } 10431 10432 /** 10433 * Called when the view should apply {@link WindowInsets} according to its internal policy. 10434 * 10435 * <p>This method should be overridden by views that wish to apply a policy different from or 10436 * in addition to the default behavior. Clients that wish to force a view subtree 10437 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 10438 * 10439 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 10440 * it will be called during dispatch instead of this method. The listener may optionally 10441 * call this method from its own implementation if it wishes to apply the view's default 10442 * insets policy in addition to its own.</p> 10443 * 10444 * <p>Implementations of this method should either return the insets parameter unchanged 10445 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 10446 * that this view applied itself. This allows new inset types added in future platform 10447 * versions to pass through existing implementations unchanged without being erroneously 10448 * consumed.</p> 10449 * 10450 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 10451 * property is set then the view will consume the system window insets and apply them 10452 * as padding for the view.</p> 10453 * 10454 * @param insets Insets to apply 10455 * @return The supplied insets with any applied insets consumed 10456 */ 10457 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 10458 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 10459 // We weren't called from within a direct call to fitSystemWindows, 10460 // call into it as a fallback in case we're in a class that overrides it 10461 // and has logic to perform. 10462 if (fitSystemWindows(insets.getSystemWindowInsetsAsRect())) { 10463 return insets.consumeSystemWindowInsets(); 10464 } 10465 } else { 10466 // We were called from within a direct call to fitSystemWindows. 10467 if (fitSystemWindowsInt(insets.getSystemWindowInsetsAsRect())) { 10468 return insets.consumeSystemWindowInsets(); 10469 } 10470 } 10471 return insets; 10472 } 10473 10474 /** 10475 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 10476 * window insets to this view. The listener's 10477 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 10478 * method will be called instead of the view's 10479 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 10480 * 10481 * @param listener Listener to set 10482 * 10483 * @see #onApplyWindowInsets(WindowInsets) 10484 */ 10485 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 10486 getListenerInfo().mOnApplyWindowInsetsListener = listener; 10487 } 10488 10489 /** 10490 * Request to apply the given window insets to this view or another view in its subtree. 10491 * 10492 * <p>This method should be called by clients wishing to apply insets corresponding to areas 10493 * obscured by window decorations or overlays. This can include the status and navigation bars, 10494 * action bars, input methods and more. New inset categories may be added in the future. 10495 * The method returns the insets provided minus any that were applied by this view or its 10496 * children.</p> 10497 * 10498 * <p>Clients wishing to provide custom behavior should override the 10499 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 10500 * {@link OnApplyWindowInsetsListener} via the 10501 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 10502 * method.</p> 10503 * 10504 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 10505 * </p> 10506 * 10507 * @param insets Insets to apply 10508 * @return The provided insets minus the insets that were consumed 10509 */ 10510 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 10511 try { 10512 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 10513 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 10514 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 10515 } else { 10516 return onApplyWindowInsets(insets); 10517 } 10518 } finally { 10519 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 10520 } 10521 } 10522 10523 /** 10524 * Sets a {@link WindowInsetsAnimationListener} to be notified about animations of windows that 10525 * cause insets. 10526 * 10527 * @param listener The listener to set. 10528 * @hide pending unhide 10529 */ 10530 public void setWindowInsetsAnimationListener(WindowInsetsAnimationListener listener) { 10531 getListenerInfo().mWindowInsetsAnimationListener = listener; 10532 } 10533 10534 void dispatchWindowInsetsAnimationStarted(InsetsAnimation animation) { 10535 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationListener != null) { 10536 mListenerInfo.mWindowInsetsAnimationListener.onStarted(animation); 10537 } 10538 } 10539 10540 WindowInsets dispatchWindowInsetsAnimationProgress(WindowInsets insets) { 10541 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationListener != null) { 10542 return mListenerInfo.mWindowInsetsAnimationListener.onProgress(insets); 10543 } else { 10544 return insets; 10545 } 10546 } 10547 10548 void dispatchWindowInsetsAnimationFinished(InsetsAnimation animation) { 10549 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationListener != null) { 10550 mListenerInfo.mWindowInsetsAnimationListener.onFinished(animation); 10551 } 10552 } 10553 10554 /** 10555 * Sets a list of areas within this view's post-layout coordinate space where the system 10556 * should not intercept touch or other pointing device gestures. <em>This method should 10557 * be called by {@link #onLayout(boolean, int, int, int, int)} or {@link #onDraw(Canvas)}.</em> 10558 * 10559 * <p>Use this to tell the system which specific sub-areas of a view need to receive gesture 10560 * input in order to function correctly in the presence of global system gestures that may 10561 * conflict. For example, if the system wishes to capture swipe-in-from-screen-edge gestures 10562 * to provide system-level navigation functionality, a view such as a navigation drawer 10563 * container can mark the left (or starting) edge of itself as requiring gesture capture 10564 * priority using this API. The system may then choose to relax its own gesture recognition 10565 * to allow the app to consume the user's gesture. It is not necessary for an app to register 10566 * exclusion rects for broadly spanning regions such as the entirety of a 10567 * <code>ScrollView</code> or for simple press and release click targets such as 10568 * <code>Button</code>. Mark an exclusion rect when interacting with a view requires 10569 * a precision touch gesture in a small area in either the X or Y dimension, such as 10570 * an edge swipe or dragging a <code>SeekBar</code> thumb.</p> 10571 * 10572 * <p>Do not modify the provided list after this method is called.</p> 10573 * 10574 * @param rects A list of precision gesture regions that this view needs to function correctly 10575 */ 10576 public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) { 10577 if (rects.isEmpty() && mListenerInfo == null) return; 10578 10579 final ListenerInfo info = getListenerInfo(); 10580 if (rects.isEmpty()) { 10581 info.mSystemGestureExclusionRects = null; 10582 if (info.mPositionUpdateListener != null) { 10583 mRenderNode.removePositionUpdateListener(info.mPositionUpdateListener); 10584 } 10585 } else { 10586 info.mSystemGestureExclusionRects = rects; 10587 if (info.mPositionUpdateListener == null) { 10588 info.mPositionUpdateListener = new RenderNode.PositionUpdateListener() { 10589 @Override 10590 public void positionChanged(long n, int l, int t, int r, int b) { 10591 postUpdateSystemGestureExclusionRects(); 10592 } 10593 10594 @Override 10595 public void positionLost(long frameNumber) { 10596 postUpdateSystemGestureExclusionRects(); 10597 } 10598 }; 10599 mRenderNode.addPositionUpdateListener(info.mPositionUpdateListener); 10600 } 10601 } 10602 postUpdateSystemGestureExclusionRects(); 10603 } 10604 10605 /** 10606 * WARNING: this can be called by a hwui worker thread, not just the UI thread! 10607 */ 10608 void postUpdateSystemGestureExclusionRects() { 10609 // Potentially racey from a background thread. It's ok if it's not perfect. 10610 final Handler h = getHandler(); 10611 if (h != null) { 10612 h.postAtFrontOfQueue(this::updateSystemGestureExclusionRects); 10613 } 10614 } 10615 10616 void updateSystemGestureExclusionRects() { 10617 final AttachInfo ai = mAttachInfo; 10618 if (ai != null) { 10619 ai.mViewRootImpl.updateSystemGestureExclusionRectsForView(this); 10620 } 10621 } 10622 10623 /** 10624 * Retrieve the list of areas within this view's post-layout coordinate space where the system 10625 * should not intercept touch or other pointing device gestures. 10626 * 10627 * <p>Do not modify the returned list.</p> 10628 * 10629 * @return the list set by {@link #setSystemGestureExclusionRects(List)} 10630 */ 10631 @NonNull 10632 public List<Rect> getSystemGestureExclusionRects() { 10633 final ListenerInfo info = mListenerInfo; 10634 if (info != null) { 10635 final List<Rect> list = info.mSystemGestureExclusionRects; 10636 if (list != null) { 10637 return list; 10638 } 10639 } 10640 return Collections.emptyList(); 10641 } 10642 10643 /** 10644 * Compute the view's coordinate within the surface. 10645 * 10646 * <p>Computes the coordinates of this view in its surface. The argument 10647 * must be an array of two integers. After the method returns, the array 10648 * contains the x and y location in that order.</p> 10649 * 10650 * @param location an array of two integers in which to hold the coordinates 10651 */ 10652 public void getLocationInSurface(@NonNull @Size(2) int[] location) { 10653 getLocationInWindow(location); 10654 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 10655 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 10656 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 10657 } 10658 } 10659 10660 /** 10661 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 10662 * only available if the view is attached. 10663 * 10664 * @return WindowInsets from the top of the view hierarchy or null if View is detached 10665 */ 10666 public WindowInsets getRootWindowInsets() { 10667 if (mAttachInfo != null) { 10668 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 10669 } 10670 return null; 10671 } 10672 10673 /** 10674 * Retrieves the single {@link WindowInsetsController} of the window this view is attached to. 10675 * 10676 * @return The {@link WindowInsetsController} or {@code null} if the view isn't attached to a 10677 * a window. 10678 * @see Window#getInsetsController() 10679 * @hide pending unhide 10680 */ 10681 public @Nullable WindowInsetsController getWindowInsetsController() { 10682 if (mAttachInfo != null) { 10683 return mAttachInfo.mViewRootImpl.getInsetsController(); 10684 } 10685 return null; 10686 } 10687 10688 /** 10689 * @hide Compute the insets that should be consumed by this view and the ones 10690 * that should propagate to those under it. 10691 * 10692 * Note: This is used by appcompat's ActionBarOverlayLayout through reflection. 10693 * 10694 * @param inoutInsets the insets given to this view 10695 * @param outLocalInsets the insets that should be applied to this view 10696 * @deprecated use {@link #computeSystemWindowInsets} 10697 * @return 10698 */ 10699 @Deprecated 10700 @UnsupportedAppUsage 10701 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 10702 WindowInsets innerInsets = computeSystemWindowInsets(new WindowInsets(inoutInsets), 10703 outLocalInsets); 10704 inoutInsets.set(innerInsets.getSystemWindowInsetsAsRect()); 10705 return innerInsets.isSystemWindowInsetsConsumed(); 10706 } 10707 10708 /** 10709 * Compute insets that should be consumed by this view and the ones that should propagate 10710 * to those under it. 10711 * 10712 * @param in Insets currently being processed by this View, likely received as a parameter 10713 * to {@link #onApplyWindowInsets(WindowInsets)}. 10714 * @param outLocalInsets A Rect that will receive the insets that should be consumed 10715 * by this view 10716 * @return Insets that should be passed along to views under this one 10717 */ 10718 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 10719 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 10720 || mAttachInfo == null 10721 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 10722 && !mAttachInfo.mOverscanRequested)) { 10723 outLocalInsets.set(in.getSystemWindowInsetsAsRect()); 10724 return in.consumeSystemWindowInsets().inset(outLocalInsets); 10725 } else { 10726 // The application wants to take care of fitting system window for 10727 // the content... however we still need to take care of any overscan here. 10728 final Rect overscan = mAttachInfo.mOverscanInsets; 10729 outLocalInsets.set(overscan); 10730 return in.inset(outLocalInsets); 10731 } 10732 } 10733 10734 /** 10735 * Sets whether or not this view should account for system screen decorations 10736 * such as the status bar and inset its content; that is, controlling whether 10737 * the default implementation of {@link #fitSystemWindows(Rect)} will be 10738 * executed. See that method for more details. 10739 * 10740 * <p>Note that if you are providing your own implementation of 10741 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 10742 * flag to true -- your implementation will be overriding the default 10743 * implementation that checks this flag. 10744 * 10745 * @param fitSystemWindows If true, then the default implementation of 10746 * {@link #fitSystemWindows(Rect)} will be executed. 10747 * 10748 * @attr ref android.R.styleable#View_fitsSystemWindows 10749 * @see #getFitsSystemWindows() 10750 * @see #fitSystemWindows(Rect) 10751 * @see #setSystemUiVisibility(int) 10752 */ 10753 public void setFitsSystemWindows(boolean fitSystemWindows) { 10754 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 10755 } 10756 10757 /** 10758 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 10759 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 10760 * will be executed. 10761 * 10762 * @return {@code true} if the default implementation of 10763 * {@link #fitSystemWindows(Rect)} will be executed. 10764 * 10765 * @attr ref android.R.styleable#View_fitsSystemWindows 10766 * @see #setFitsSystemWindows(boolean) 10767 * @see #fitSystemWindows(Rect) 10768 * @see #setSystemUiVisibility(int) 10769 */ 10770 @ViewDebug.ExportedProperty 10771 @InspectableProperty 10772 public boolean getFitsSystemWindows() { 10773 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 10774 } 10775 10776 /** @hide */ 10777 @UnsupportedAppUsage 10778 public boolean fitsSystemWindows() { 10779 return getFitsSystemWindows(); 10780 } 10781 10782 /** 10783 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 10784 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 10785 */ 10786 @Deprecated 10787 public void requestFitSystemWindows() { 10788 if (mParent != null) { 10789 mParent.requestFitSystemWindows(); 10790 } 10791 } 10792 10793 /** 10794 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 10795 */ 10796 public void requestApplyInsets() { 10797 requestFitSystemWindows(); 10798 } 10799 10800 /** 10801 * For use by PhoneWindow to make its own system window fitting optional. 10802 * @hide 10803 */ 10804 @UnsupportedAppUsage 10805 public void makeOptionalFitsSystemWindows() { 10806 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 10807 } 10808 10809 /** 10810 * Returns the outsets, which areas of the device that aren't a surface, but we would like to 10811 * treat them as such. 10812 * @hide 10813 */ 10814 public void getOutsets(Rect outOutsetRect) { 10815 if (mAttachInfo != null) { 10816 outOutsetRect.set(mAttachInfo.mOutsets); 10817 } else { 10818 outOutsetRect.setEmpty(); 10819 } 10820 } 10821 10822 /** 10823 * Returns the visibility status for this view. 10824 * 10825 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 10826 * @attr ref android.R.styleable#View_visibility 10827 */ 10828 @ViewDebug.ExportedProperty(mapping = { 10829 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 10830 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 10831 @ViewDebug.IntToString(from = GONE, to = "GONE") 10832 }) 10833 @InspectableProperty(enumMapping = { 10834 @EnumEntry(value = VISIBLE, name = "visible"), 10835 @EnumEntry(value = INVISIBLE, name = "invisible"), 10836 @EnumEntry(value = GONE, name = "gone") 10837 }) 10838 @Visibility 10839 public int getVisibility() { 10840 return mViewFlags & VISIBILITY_MASK; 10841 } 10842 10843 /** 10844 * Set the visibility state of this view. 10845 * 10846 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 10847 * @attr ref android.R.styleable#View_visibility 10848 */ 10849 @RemotableViewMethod 10850 public void setVisibility(@Visibility int visibility) { 10851 setFlags(visibility, VISIBILITY_MASK); 10852 } 10853 10854 /** 10855 * Returns the enabled status for this view. The interpretation of the 10856 * enabled state varies by subclass. 10857 * 10858 * @return True if this view is enabled, false otherwise. 10859 */ 10860 @ViewDebug.ExportedProperty 10861 @InspectableProperty 10862 public boolean isEnabled() { 10863 return (mViewFlags & ENABLED_MASK) == ENABLED; 10864 } 10865 10866 /** 10867 * Set the enabled state of this view. The interpretation of the enabled 10868 * state varies by subclass. 10869 * 10870 * @param enabled True if this view is enabled, false otherwise. 10871 */ 10872 @RemotableViewMethod 10873 public void setEnabled(boolean enabled) { 10874 if (enabled == isEnabled()) return; 10875 10876 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 10877 10878 /* 10879 * The View most likely has to change its appearance, so refresh 10880 * the drawable state. 10881 */ 10882 refreshDrawableState(); 10883 10884 // Invalidate too, since the default behavior for views is to be 10885 // be drawn at 50% alpha rather than to change the drawable. 10886 invalidate(true); 10887 10888 if (!enabled) { 10889 cancelPendingInputEvents(); 10890 } 10891 } 10892 10893 /** 10894 * Set whether this view can receive the focus. 10895 * <p> 10896 * Setting this to false will also ensure that this view is not focusable 10897 * in touch mode. 10898 * 10899 * @param focusable If true, this view can receive the focus. 10900 * 10901 * @see #setFocusableInTouchMode(boolean) 10902 * @see #setFocusable(int) 10903 * @attr ref android.R.styleable#View_focusable 10904 */ 10905 public void setFocusable(boolean focusable) { 10906 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 10907 } 10908 10909 /** 10910 * Sets whether this view can receive focus. 10911 * <p> 10912 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 10913 * automatically based on the view's interactivity. This is the default. 10914 * <p> 10915 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 10916 * in touch mode. 10917 * 10918 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 10919 * or {@link #FOCUSABLE_AUTO}. 10920 * @see #setFocusableInTouchMode(boolean) 10921 * @attr ref android.R.styleable#View_focusable 10922 */ 10923 public void setFocusable(@Focusable int focusable) { 10924 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 10925 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 10926 } 10927 setFlags(focusable, FOCUSABLE_MASK); 10928 } 10929 10930 /** 10931 * Set whether this view can receive focus while in touch mode. 10932 * 10933 * Setting this to true will also ensure that this view is focusable. 10934 * 10935 * @param focusableInTouchMode If true, this view can receive the focus while 10936 * in touch mode. 10937 * 10938 * @see #setFocusable(boolean) 10939 * @attr ref android.R.styleable#View_focusableInTouchMode 10940 */ 10941 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 10942 // Focusable in touch mode should always be set before the focusable flag 10943 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 10944 // which, in touch mode, will not successfully request focus on this view 10945 // because the focusable in touch mode flag is not set 10946 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 10947 10948 // Clear FOCUSABLE_AUTO if set. 10949 if (focusableInTouchMode) { 10950 // Clears FOCUSABLE_AUTO if set. 10951 setFlags(FOCUSABLE, FOCUSABLE_MASK); 10952 } 10953 } 10954 10955 /** 10956 * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how 10957 * to autofill the view with the user's data. 10958 * 10959 * <p>Typically, there is only one way to autofill a view, but there could be more than one. 10960 * For example, if the application accepts either an username or email address to identify 10961 * an user. 10962 * 10963 * <p>These hints are not validated by the Android System, but passed "as is" to the service. 10964 * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_} 10965 * constants such as: 10966 * {@link #AUTOFILL_HINT_USERNAME}, {@link #AUTOFILL_HINT_PASSWORD}, 10967 * {@link #AUTOFILL_HINT_EMAIL_ADDRESS}, 10968 * {@link #AUTOFILL_HINT_NAME}, 10969 * {@link #AUTOFILL_HINT_PHONE}, 10970 * {@link #AUTOFILL_HINT_POSTAL_ADDRESS}, {@link #AUTOFILL_HINT_POSTAL_CODE}, 10971 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 10972 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 10973 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 10974 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or 10975 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}. 10976 * 10977 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set. 10978 * @attr ref android.R.styleable#View_autofillHints 10979 */ 10980 public void setAutofillHints(@Nullable String... autofillHints) { 10981 if (autofillHints == null || autofillHints.length == 0) { 10982 mAutofillHints = null; 10983 } else { 10984 mAutofillHints = autofillHints; 10985 } 10986 } 10987 10988 /** 10989 * @hide 10990 */ 10991 @TestApi 10992 public void setAutofilled(boolean isAutofilled) { 10993 boolean wasChanged = isAutofilled != isAutofilled(); 10994 10995 if (wasChanged) { 10996 if (isAutofilled) { 10997 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; 10998 } else { 10999 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; 11000 } 11001 11002 invalidate(); 11003 } 11004 } 11005 11006 /** 11007 * Set whether this view should have sound effects enabled for events such as 11008 * clicking and touching. 11009 * 11010 * <p>You may wish to disable sound effects for a view if you already play sounds, 11011 * for instance, a dial key that plays dtmf tones. 11012 * 11013 * @param soundEffectsEnabled whether sound effects are enabled for this view. 11014 * @see #isSoundEffectsEnabled() 11015 * @see #playSoundEffect(int) 11016 * @attr ref android.R.styleable#View_soundEffectsEnabled 11017 */ 11018 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 11019 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 11020 } 11021 11022 /** 11023 * @return whether this view should have sound effects enabled for events such as 11024 * clicking and touching. 11025 * 11026 * @see #setSoundEffectsEnabled(boolean) 11027 * @see #playSoundEffect(int) 11028 * @attr ref android.R.styleable#View_soundEffectsEnabled 11029 */ 11030 @ViewDebug.ExportedProperty 11031 @InspectableProperty 11032 public boolean isSoundEffectsEnabled() { 11033 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 11034 } 11035 11036 /** 11037 * Set whether this view should have haptic feedback for events such as 11038 * long presses. 11039 * 11040 * <p>You may wish to disable haptic feedback if your view already controls 11041 * its own haptic feedback. 11042 * 11043 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 11044 * @see #isHapticFeedbackEnabled() 11045 * @see #performHapticFeedback(int) 11046 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 11047 */ 11048 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 11049 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 11050 } 11051 11052 /** 11053 * @return whether this view should have haptic feedback enabled for events 11054 * long presses. 11055 * 11056 * @see #setHapticFeedbackEnabled(boolean) 11057 * @see #performHapticFeedback(int) 11058 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 11059 */ 11060 @ViewDebug.ExportedProperty 11061 @InspectableProperty 11062 public boolean isHapticFeedbackEnabled() { 11063 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 11064 } 11065 11066 /** 11067 * Returns the layout direction for this view. 11068 * 11069 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 11070 * {@link #LAYOUT_DIRECTION_RTL}, 11071 * {@link #LAYOUT_DIRECTION_INHERIT} or 11072 * {@link #LAYOUT_DIRECTION_LOCALE}. 11073 * 11074 * @attr ref android.R.styleable#View_layoutDirection 11075 * 11076 * @hide 11077 */ 11078 @ViewDebug.ExportedProperty(category = "layout", mapping = { 11079 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 11080 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 11081 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 11082 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 11083 }) 11084 @InspectableProperty(hasAttributeId = false, enumMapping = { 11085 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 11086 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl"), 11087 @EnumEntry(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"), 11088 @EnumEntry(value = LAYOUT_DIRECTION_LOCALE, name = "locale") 11089 }) 11090 @LayoutDir 11091 public int getRawLayoutDirection() { 11092 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 11093 } 11094 11095 /** 11096 * Set the layout direction for this view. This will propagate a reset of layout direction 11097 * resolution to the view's children and resolve layout direction for this view. 11098 * 11099 * @param layoutDirection the layout direction to set. Should be one of: 11100 * 11101 * {@link #LAYOUT_DIRECTION_LTR}, 11102 * {@link #LAYOUT_DIRECTION_RTL}, 11103 * {@link #LAYOUT_DIRECTION_INHERIT}, 11104 * {@link #LAYOUT_DIRECTION_LOCALE}. 11105 * 11106 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 11107 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 11108 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 11109 * 11110 * @attr ref android.R.styleable#View_layoutDirection 11111 */ 11112 @RemotableViewMethod 11113 public void setLayoutDirection(@LayoutDir int layoutDirection) { 11114 if (getRawLayoutDirection() != layoutDirection) { 11115 // Reset the current layout direction and the resolved one 11116 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 11117 resetRtlProperties(); 11118 // Set the new layout direction (filtered) 11119 mPrivateFlags2 |= 11120 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 11121 // We need to resolve all RTL properties as they all depend on layout direction 11122 resolveRtlPropertiesIfNeeded(); 11123 requestLayout(); 11124 invalidate(true); 11125 } 11126 } 11127 11128 /** 11129 * Returns the resolved layout direction for this view. 11130 * 11131 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 11132 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 11133 * 11134 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 11135 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 11136 * 11137 * @attr ref android.R.styleable#View_layoutDirection 11138 */ 11139 @ViewDebug.ExportedProperty(category = "layout", mapping = { 11140 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 11141 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 11142 }) 11143 @InspectableProperty(enumMapping = { 11144 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 11145 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl") 11146 }) 11147 @ResolvedLayoutDir 11148 public int getLayoutDirection() { 11149 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 11150 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 11151 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 11152 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 11153 } 11154 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 11155 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 11156 } 11157 11158 /** 11159 * Indicates whether or not this view's layout is right-to-left. This is resolved from 11160 * layout attribute and/or the inherited value from the parent 11161 * 11162 * @return true if the layout is right-to-left. 11163 * 11164 * @hide 11165 */ 11166 @ViewDebug.ExportedProperty(category = "layout") 11167 @UnsupportedAppUsage 11168 public boolean isLayoutRtl() { 11169 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 11170 } 11171 11172 /** 11173 * Indicates whether the view is currently tracking transient state that the 11174 * app should not need to concern itself with saving and restoring, but that 11175 * the framework should take special note to preserve when possible. 11176 * 11177 * <p>A view with transient state cannot be trivially rebound from an external 11178 * data source, such as an adapter binding item views in a list. This may be 11179 * because the view is performing an animation, tracking user selection 11180 * of content, or similar.</p> 11181 * 11182 * @return true if the view has transient state 11183 */ 11184 @ViewDebug.ExportedProperty(category = "layout") 11185 public boolean hasTransientState() { 11186 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 11187 } 11188 11189 /** 11190 * Set whether this view is currently tracking transient state that the 11191 * framework should attempt to preserve when possible. This flag is reference counted, 11192 * so every call to setHasTransientState(true) should be paired with a later call 11193 * to setHasTransientState(false). 11194 * 11195 * <p>A view with transient state cannot be trivially rebound from an external 11196 * data source, such as an adapter binding item views in a list. This may be 11197 * because the view is performing an animation, tracking user selection 11198 * of content, or similar.</p> 11199 * 11200 * @param hasTransientState true if this view has transient state 11201 */ 11202 public void setHasTransientState(boolean hasTransientState) { 11203 final boolean oldHasTransientState = hasTransientState(); 11204 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 11205 mTransientStateCount - 1; 11206 if (mTransientStateCount < 0) { 11207 mTransientStateCount = 0; 11208 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 11209 "unmatched pair of setHasTransientState calls"); 11210 } else if ((hasTransientState && mTransientStateCount == 1) || 11211 (!hasTransientState && mTransientStateCount == 0)) { 11212 // update flag if we've just incremented up from 0 or decremented down to 0 11213 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 11214 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 11215 final boolean newHasTransientState = hasTransientState(); 11216 if (mParent != null && newHasTransientState != oldHasTransientState) { 11217 try { 11218 mParent.childHasTransientStateChanged(this, newHasTransientState); 11219 } catch (AbstractMethodError e) { 11220 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 11221 " does not fully implement ViewParent", e); 11222 } 11223 } 11224 } 11225 } 11226 11227 /** 11228 * Returns true if this view is currently attached to a window. 11229 */ 11230 public boolean isAttachedToWindow() { 11231 return mAttachInfo != null; 11232 } 11233 11234 /** 11235 * Returns true if this view has been through at least one layout since it 11236 * was last attached to or detached from a window. 11237 */ 11238 public boolean isLaidOut() { 11239 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 11240 } 11241 11242 /** 11243 * @return {@code true} if laid-out and not about to do another layout. 11244 */ 11245 boolean isLayoutValid() { 11246 return isLaidOut() && ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == 0); 11247 } 11248 11249 /** 11250 * If this view doesn't do any drawing on its own, set this flag to 11251 * allow further optimizations. By default, this flag is not set on 11252 * View, but could be set on some View subclasses such as ViewGroup. 11253 * 11254 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 11255 * you should clear this flag. 11256 * 11257 * @param willNotDraw whether or not this View draw on its own 11258 */ 11259 public void setWillNotDraw(boolean willNotDraw) { 11260 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 11261 } 11262 11263 /** 11264 * Returns whether or not this View draws on its own. 11265 * 11266 * @return true if this view has nothing to draw, false otherwise 11267 */ 11268 @ViewDebug.ExportedProperty(category = "drawing") 11269 public boolean willNotDraw() { 11270 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 11271 } 11272 11273 /** 11274 * When a View's drawing cache is enabled, drawing is redirected to an 11275 * offscreen bitmap. Some views, like an ImageView, must be able to 11276 * bypass this mechanism if they already draw a single bitmap, to avoid 11277 * unnecessary usage of the memory. 11278 * 11279 * @param willNotCacheDrawing true if this view does not cache its 11280 * drawing, false otherwise 11281 * 11282 * @deprecated The view drawing cache was largely made obsolete with the introduction of 11283 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 11284 * layers are largely unnecessary and can easily result in a net loss in performance due to the 11285 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 11286 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 11287 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 11288 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 11289 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 11290 * software-rendered usages are discouraged and have compatibility issues with hardware-only 11291 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 11292 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 11293 * reports or unit testing the {@link PixelCopy} API is recommended. 11294 */ 11295 @Deprecated 11296 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 11297 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 11298 } 11299 11300 /** 11301 * Returns whether or not this View can cache its drawing or not. 11302 * 11303 * @return true if this view does not cache its drawing, false otherwise 11304 * 11305 * @deprecated The view drawing cache was largely made obsolete with the introduction of 11306 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 11307 * layers are largely unnecessary and can easily result in a net loss in performance due to the 11308 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 11309 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 11310 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 11311 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 11312 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 11313 * software-rendered usages are discouraged and have compatibility issues with hardware-only 11314 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 11315 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 11316 * reports or unit testing the {@link PixelCopy} API is recommended. 11317 */ 11318 @ViewDebug.ExportedProperty(category = "drawing") 11319 @Deprecated 11320 public boolean willNotCacheDrawing() { 11321 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 11322 } 11323 11324 /** 11325 * Indicates whether this view reacts to click events or not. 11326 * 11327 * @return true if the view is clickable, false otherwise 11328 * 11329 * @see #setClickable(boolean) 11330 * @attr ref android.R.styleable#View_clickable 11331 */ 11332 @ViewDebug.ExportedProperty 11333 @InspectableProperty 11334 public boolean isClickable() { 11335 return (mViewFlags & CLICKABLE) == CLICKABLE; 11336 } 11337 11338 /** 11339 * Enables or disables click events for this view. When a view 11340 * is clickable it will change its state to "pressed" on every click. 11341 * Subclasses should set the view clickable to visually react to 11342 * user's clicks. 11343 * 11344 * @param clickable true to make the view clickable, false otherwise 11345 * 11346 * @see #isClickable() 11347 * @attr ref android.R.styleable#View_clickable 11348 */ 11349 public void setClickable(boolean clickable) { 11350 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 11351 } 11352 11353 /** 11354 * Indicates whether this view reacts to long click events or not. 11355 * 11356 * @return true if the view is long clickable, false otherwise 11357 * 11358 * @see #setLongClickable(boolean) 11359 * @attr ref android.R.styleable#View_longClickable 11360 */ 11361 @InspectableProperty 11362 public boolean isLongClickable() { 11363 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 11364 } 11365 11366 /** 11367 * Enables or disables long click events for this view. When a view is long 11368 * clickable it reacts to the user holding down the button for a longer 11369 * duration than a tap. This event can either launch the listener or a 11370 * context menu. 11371 * 11372 * @param longClickable true to make the view long clickable, false otherwise 11373 * @see #isLongClickable() 11374 * @attr ref android.R.styleable#View_longClickable 11375 */ 11376 public void setLongClickable(boolean longClickable) { 11377 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 11378 } 11379 11380 /** 11381 * Indicates whether this view reacts to context clicks or not. 11382 * 11383 * @return true if the view is context clickable, false otherwise 11384 * @see #setContextClickable(boolean) 11385 * @attr ref android.R.styleable#View_contextClickable 11386 */ 11387 @InspectableProperty 11388 public boolean isContextClickable() { 11389 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 11390 } 11391 11392 /** 11393 * Enables or disables context clicking for this view. This event can launch the listener. 11394 * 11395 * @param contextClickable true to make the view react to a context click, false otherwise 11396 * @see #isContextClickable() 11397 * @attr ref android.R.styleable#View_contextClickable 11398 */ 11399 public void setContextClickable(boolean contextClickable) { 11400 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 11401 } 11402 11403 /** 11404 * Sets the pressed state for this view and provides a touch coordinate for 11405 * animation hinting. 11406 * 11407 * @param pressed Pass true to set the View's internal state to "pressed", 11408 * or false to reverts the View's internal state from a 11409 * previously set "pressed" state. 11410 * @param x The x coordinate of the touch that caused the press 11411 * @param y The y coordinate of the touch that caused the press 11412 */ 11413 private void setPressed(boolean pressed, float x, float y) { 11414 if (pressed) { 11415 drawableHotspotChanged(x, y); 11416 } 11417 11418 setPressed(pressed); 11419 } 11420 11421 /** 11422 * Sets the pressed state for this view. 11423 * 11424 * @see #isClickable() 11425 * @see #setClickable(boolean) 11426 * 11427 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 11428 * the View's internal state from a previously set "pressed" state. 11429 */ 11430 public void setPressed(boolean pressed) { 11431 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 11432 11433 if (pressed) { 11434 mPrivateFlags |= PFLAG_PRESSED; 11435 } else { 11436 mPrivateFlags &= ~PFLAG_PRESSED; 11437 } 11438 11439 if (needsRefresh) { 11440 refreshDrawableState(); 11441 } 11442 dispatchSetPressed(pressed); 11443 } 11444 11445 /** 11446 * Dispatch setPressed to all of this View's children. 11447 * 11448 * @see #setPressed(boolean) 11449 * 11450 * @param pressed The new pressed state 11451 */ 11452 protected void dispatchSetPressed(boolean pressed) { 11453 } 11454 11455 /** 11456 * Indicates whether the view is currently in pressed state. Unless 11457 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 11458 * the pressed state. 11459 * 11460 * @see #setPressed(boolean) 11461 * @see #isClickable() 11462 * @see #setClickable(boolean) 11463 * 11464 * @return true if the view is currently pressed, false otherwise 11465 */ 11466 @ViewDebug.ExportedProperty 11467 @InspectableProperty(hasAttributeId = false) 11468 public boolean isPressed() { 11469 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 11470 } 11471 11472 /** 11473 * @hide 11474 * Indicates whether this view will participate in data collection through 11475 * {@link ViewStructure}. If true, it will not provide any data 11476 * for itself or its children. If false, the normal data collection will be allowed. 11477 * 11478 * @return Returns false if assist data collection is not blocked, else true. 11479 * 11480 * @see #setAssistBlocked(boolean) 11481 * @attr ref android.R.styleable#View_assistBlocked 11482 */ 11483 public boolean isAssistBlocked() { 11484 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 11485 } 11486 11487 /** 11488 * @hide 11489 * Controls whether assist data collection from this view and its children is enabled 11490 * (that is, whether {@link #onProvideStructure} and 11491 * {@link #onProvideVirtualStructure} will be called). The default value is false, 11492 * allowing normal assist collection. Setting this to false will disable assist collection. 11493 * 11494 * @param enabled Set to true to <em>disable</em> assist data collection, or false 11495 * (the default) to allow it. 11496 * 11497 * @see #isAssistBlocked() 11498 * @see #onProvideStructure 11499 * @see #onProvideVirtualStructure 11500 * @attr ref android.R.styleable#View_assistBlocked 11501 */ 11502 @UnsupportedAppUsage 11503 public void setAssistBlocked(boolean enabled) { 11504 if (enabled) { 11505 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 11506 } else { 11507 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 11508 } 11509 } 11510 11511 /** 11512 * Indicates whether this view will save its state (that is, 11513 * whether its {@link #onSaveInstanceState} method will be called). 11514 * 11515 * @return Returns true if the view state saving is enabled, else false. 11516 * 11517 * @see #setSaveEnabled(boolean) 11518 * @attr ref android.R.styleable#View_saveEnabled 11519 */ 11520 @InspectableProperty 11521 public boolean isSaveEnabled() { 11522 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 11523 } 11524 11525 /** 11526 * Controls whether the saving of this view's state is 11527 * enabled (that is, whether its {@link #onSaveInstanceState} method 11528 * will be called). Note that even if freezing is enabled, the 11529 * view still must have an id assigned to it (via {@link #setId(int)}) 11530 * for its state to be saved. This flag can only disable the 11531 * saving of this view; any child views may still have their state saved. 11532 * 11533 * @param enabled Set to false to <em>disable</em> state saving, or true 11534 * (the default) to allow it. 11535 * 11536 * @see #isSaveEnabled() 11537 * @see #setId(int) 11538 * @see #onSaveInstanceState() 11539 * @attr ref android.R.styleable#View_saveEnabled 11540 */ 11541 public void setSaveEnabled(boolean enabled) { 11542 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 11543 } 11544 11545 /** 11546 * Gets whether the framework should discard touches when the view's 11547 * window is obscured by another visible window. 11548 * Refer to the {@link View} security documentation for more details. 11549 * 11550 * @return True if touch filtering is enabled. 11551 * 11552 * @see #setFilterTouchesWhenObscured(boolean) 11553 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 11554 */ 11555 @ViewDebug.ExportedProperty 11556 @InspectableProperty 11557 public boolean getFilterTouchesWhenObscured() { 11558 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 11559 } 11560 11561 /** 11562 * Sets whether the framework should discard touches when the view's 11563 * window is obscured by another visible window. 11564 * Refer to the {@link View} security documentation for more details. 11565 * 11566 * @param enabled True if touch filtering should be enabled. 11567 * 11568 * @see #getFilterTouchesWhenObscured 11569 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 11570 */ 11571 public void setFilterTouchesWhenObscured(boolean enabled) { 11572 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 11573 FILTER_TOUCHES_WHEN_OBSCURED); 11574 } 11575 11576 /** 11577 * Indicates whether the entire hierarchy under this view will save its 11578 * state when a state saving traversal occurs from its parent. The default 11579 * is true; if false, these views will not be saved unless 11580 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 11581 * 11582 * @return Returns true if the view state saving from parent is enabled, else false. 11583 * 11584 * @see #setSaveFromParentEnabled(boolean) 11585 */ 11586 public boolean isSaveFromParentEnabled() { 11587 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 11588 } 11589 11590 /** 11591 * Controls whether the entire hierarchy under this view will save its 11592 * state when a state saving traversal occurs from its parent. The default 11593 * is true; if false, these views will not be saved unless 11594 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 11595 * 11596 * @param enabled Set to false to <em>disable</em> state saving, or true 11597 * (the default) to allow it. 11598 * 11599 * @see #isSaveFromParentEnabled() 11600 * @see #setId(int) 11601 * @see #onSaveInstanceState() 11602 */ 11603 public void setSaveFromParentEnabled(boolean enabled) { 11604 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 11605 } 11606 11607 11608 /** 11609 * Returns whether this View is currently able to take focus. 11610 * 11611 * @return True if this view can take focus, or false otherwise. 11612 */ 11613 @ViewDebug.ExportedProperty(category = "focus") 11614 public final boolean isFocusable() { 11615 return FOCUSABLE == (mViewFlags & FOCUSABLE); 11616 } 11617 11618 /** 11619 * Returns the focusable setting for this view. 11620 * 11621 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 11622 * @attr ref android.R.styleable#View_focusable 11623 */ 11624 @ViewDebug.ExportedProperty(mapping = { 11625 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 11626 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 11627 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 11628 }, category = "focus") 11629 @InspectableProperty(enumMapping = { 11630 @EnumEntry(value = NOT_FOCUSABLE, name = "false"), 11631 @EnumEntry(value = FOCUSABLE, name = "true"), 11632 @EnumEntry(value = FOCUSABLE_AUTO, name = "auto") 11633 }) 11634 @Focusable 11635 public int getFocusable() { 11636 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 11637 } 11638 11639 /** 11640 * When a view is focusable, it may not want to take focus when in touch mode. 11641 * For example, a button would like focus when the user is navigating via a D-pad 11642 * so that the user can click on it, but once the user starts touching the screen, 11643 * the button shouldn't take focus 11644 * @return Whether the view is focusable in touch mode. 11645 * @attr ref android.R.styleable#View_focusableInTouchMode 11646 */ 11647 @ViewDebug.ExportedProperty(category = "focus") 11648 @InspectableProperty 11649 public final boolean isFocusableInTouchMode() { 11650 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 11651 } 11652 11653 /** 11654 * Returns whether the view should be treated as a focusable unit by screen reader 11655 * accessibility tools. 11656 * @see #setScreenReaderFocusable(boolean) 11657 * 11658 * @return Whether the view should be treated as a focusable unit by screen reader. 11659 * 11660 * @attr ref android.R.styleable#View_screenReaderFocusable 11661 */ 11662 @InspectableProperty 11663 public boolean isScreenReaderFocusable() { 11664 return (mPrivateFlags3 & PFLAG3_SCREEN_READER_FOCUSABLE) != 0; 11665 } 11666 11667 /** 11668 * Sets whether this View should be a focusable element for screen readers 11669 * and include non-focusable Views from its subtree when providing feedback. 11670 * <p> 11671 * Note: this is similar to using <a href="#attr_android:focusable">{@code android:focusable}, 11672 * but does not impact input focus behavior. 11673 * 11674 * @param screenReaderFocusable Whether the view should be treated as a unit by screen reader 11675 * accessibility tools. 11676 * 11677 * @attr ref android.R.styleable#View_screenReaderFocusable 11678 */ 11679 public void setScreenReaderFocusable(boolean screenReaderFocusable) { 11680 updatePflags3AndNotifyA11yIfChanged(PFLAG3_SCREEN_READER_FOCUSABLE, screenReaderFocusable); 11681 } 11682 11683 /** 11684 * Gets whether this view is a heading for accessibility purposes. 11685 * 11686 * @return {@code true} if the view is a heading, {@code false} otherwise. 11687 * 11688 * @attr ref android.R.styleable#View_accessibilityHeading 11689 */ 11690 @InspectableProperty 11691 public boolean isAccessibilityHeading() { 11692 return (mPrivateFlags3 & PFLAG3_ACCESSIBILITY_HEADING) != 0; 11693 } 11694 11695 /** 11696 * Set if view is a heading for a section of content for accessibility purposes. 11697 * 11698 * @param isHeading {@code true} if the view is a heading, {@code false} otherwise. 11699 * 11700 * @attr ref android.R.styleable#View_accessibilityHeading 11701 */ 11702 public void setAccessibilityHeading(boolean isHeading) { 11703 updatePflags3AndNotifyA11yIfChanged(PFLAG3_ACCESSIBILITY_HEADING, isHeading); 11704 } 11705 11706 private void updatePflags3AndNotifyA11yIfChanged(int mask, boolean newValue) { 11707 int pflags3 = mPrivateFlags3; 11708 if (newValue) { 11709 pflags3 |= mask; 11710 } else { 11711 pflags3 &= ~mask; 11712 } 11713 11714 if (pflags3 != mPrivateFlags3) { 11715 mPrivateFlags3 = pflags3; 11716 notifyViewAccessibilityStateChangedIfNeeded( 11717 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 11718 } 11719 } 11720 11721 /** 11722 * Find the nearest view in the specified direction that can take focus. 11723 * This does not actually give focus to that view. 11724 * 11725 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 11726 * 11727 * @return The nearest focusable in the specified direction, or null if none 11728 * can be found. 11729 */ 11730 public View focusSearch(@FocusRealDirection int direction) { 11731 if (mParent != null) { 11732 return mParent.focusSearch(this, direction); 11733 } else { 11734 return null; 11735 } 11736 } 11737 11738 /** 11739 * Returns whether this View is a root of a keyboard navigation cluster. 11740 * 11741 * @return True if this view is a root of a cluster, or false otherwise. 11742 * @attr ref android.R.styleable#View_keyboardNavigationCluster 11743 */ 11744 @ViewDebug.ExportedProperty(category = "focus") 11745 @InspectableProperty 11746 public final boolean isKeyboardNavigationCluster() { 11747 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 11748 } 11749 11750 /** 11751 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters 11752 * will be ignored. 11753 * 11754 * @return the keyboard navigation cluster that this view is in (can be this view) 11755 * or {@code null} if not in one 11756 */ 11757 View findKeyboardNavigationCluster() { 11758 if (mParent instanceof View) { 11759 View cluster = ((View) mParent).findKeyboardNavigationCluster(); 11760 if (cluster != null) { 11761 return cluster; 11762 } else if (isKeyboardNavigationCluster()) { 11763 return this; 11764 } 11765 } 11766 return null; 11767 } 11768 11769 /** 11770 * Set whether this view is a root of a keyboard navigation cluster. 11771 * 11772 * @param isCluster If true, this view is a root of a cluster. 11773 * 11774 * @attr ref android.R.styleable#View_keyboardNavigationCluster 11775 */ 11776 public void setKeyboardNavigationCluster(boolean isCluster) { 11777 if (isCluster) { 11778 mPrivateFlags3 |= PFLAG3_CLUSTER; 11779 } else { 11780 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 11781 } 11782 } 11783 11784 /** 11785 * Sets this View as the one which receives focus the next time cluster navigation jumps 11786 * to the cluster containing this View. This does NOT change focus even if the cluster 11787 * containing this view is current. 11788 * 11789 * @hide 11790 */ 11791 @TestApi 11792 public final void setFocusedInCluster() { 11793 setFocusedInCluster(findKeyboardNavigationCluster()); 11794 } 11795 11796 private void setFocusedInCluster(View cluster) { 11797 if (this instanceof ViewGroup) { 11798 ((ViewGroup) this).mFocusedInCluster = null; 11799 } 11800 if (cluster == this) { 11801 return; 11802 } 11803 ViewParent parent = mParent; 11804 View child = this; 11805 while (parent instanceof ViewGroup) { 11806 ((ViewGroup) parent).mFocusedInCluster = child; 11807 if (parent == cluster) { 11808 break; 11809 } 11810 child = (View) parent; 11811 parent = parent.getParent(); 11812 } 11813 } 11814 11815 private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) { 11816 if (oldFocus != null) { 11817 View oldCluster = oldFocus.findKeyboardNavigationCluster(); 11818 View cluster = findKeyboardNavigationCluster(); 11819 if (oldCluster != cluster) { 11820 // Going from one cluster to another, so save last-focused. 11821 // This covers cluster jumps because they are always FOCUS_DOWN 11822 oldFocus.setFocusedInCluster(oldCluster); 11823 if (!(oldFocus.mParent instanceof ViewGroup)) { 11824 return; 11825 } 11826 if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) { 11827 // This is a result of ordered navigation so consider navigation through 11828 // the previous cluster "complete" and clear its last-focused memory. 11829 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 11830 } else if (oldFocus instanceof ViewGroup 11831 && ((ViewGroup) oldFocus).getDescendantFocusability() 11832 == ViewGroup.FOCUS_AFTER_DESCENDANTS 11833 && ViewRootImpl.isViewDescendantOf(this, oldFocus)) { 11834 // This means oldFocus is not focusable since it obviously has a focusable 11835 // child (this). Don't restore focus to it in the future. 11836 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 11837 } 11838 } 11839 } 11840 } 11841 11842 /** 11843 * Returns whether this View should receive focus when the focus is restored for the view 11844 * hierarchy containing this view. 11845 * <p> 11846 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 11847 * window or serves as a target of cluster navigation. 11848 * 11849 * @see #restoreDefaultFocus() 11850 * 11851 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 11852 * @attr ref android.R.styleable#View_focusedByDefault 11853 */ 11854 @ViewDebug.ExportedProperty(category = "focus") 11855 @InspectableProperty 11856 public final boolean isFocusedByDefault() { 11857 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 11858 } 11859 11860 /** 11861 * Sets whether this View should receive focus when the focus is restored for the view 11862 * hierarchy containing this view. 11863 * <p> 11864 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 11865 * window or serves as a target of cluster navigation. 11866 * 11867 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 11868 * {@code false} otherwise. 11869 * 11870 * @see #restoreDefaultFocus() 11871 * 11872 * @attr ref android.R.styleable#View_focusedByDefault 11873 */ 11874 public void setFocusedByDefault(boolean isFocusedByDefault) { 11875 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 11876 return; 11877 } 11878 11879 if (isFocusedByDefault) { 11880 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 11881 } else { 11882 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 11883 } 11884 11885 if (mParent instanceof ViewGroup) { 11886 if (isFocusedByDefault) { 11887 ((ViewGroup) mParent).setDefaultFocus(this); 11888 } else { 11889 ((ViewGroup) mParent).clearDefaultFocus(this); 11890 } 11891 } 11892 } 11893 11894 /** 11895 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 11896 * 11897 * @return {@code true} if this view has default focus, {@code false} otherwise 11898 */ 11899 boolean hasDefaultFocus() { 11900 return isFocusedByDefault(); 11901 } 11902 11903 /** 11904 * Find the nearest keyboard navigation cluster in the specified direction. 11905 * This does not actually give focus to that cluster. 11906 * 11907 * @param currentCluster The starting point of the search. Null means the current cluster is not 11908 * found yet 11909 * @param direction Direction to look 11910 * 11911 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 11912 * can be found 11913 */ 11914 public View keyboardNavigationClusterSearch(View currentCluster, 11915 @FocusDirection int direction) { 11916 if (isKeyboardNavigationCluster()) { 11917 currentCluster = this; 11918 } 11919 if (isRootNamespace()) { 11920 // Root namespace means we should consider ourselves the top of the 11921 // tree for group searching; otherwise we could be group searching 11922 // into other tabs. see LocalActivityManager and TabHost for more info. 11923 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 11924 this, currentCluster, direction); 11925 } else if (mParent != null) { 11926 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 11927 } 11928 return null; 11929 } 11930 11931 /** 11932 * This method is the last chance for the focused view and its ancestors to 11933 * respond to an arrow key. This is called when the focused view did not 11934 * consume the key internally, nor could the view system find a new view in 11935 * the requested direction to give focus to. 11936 * 11937 * @param focused The currently focused view. 11938 * @param direction The direction focus wants to move. One of FOCUS_UP, 11939 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 11940 * @return True if the this view consumed this unhandled move. 11941 */ 11942 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 11943 return false; 11944 } 11945 11946 /** 11947 * Sets whether this View should use a default focus highlight when it gets focused but doesn't 11948 * have {@link android.R.attr#state_focused} defined in its background. 11949 * 11950 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus 11951 * highlight, {@code false} otherwise. 11952 * 11953 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 11954 */ 11955 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { 11956 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; 11957 } 11958 11959 /** 11960 11961 /** 11962 * Returns whether this View should use a default focus highlight when it gets focused but 11963 * doesn't have {@link android.R.attr#state_focused} defined in its background. 11964 * 11965 * @return True if this View should use a default focus highlight. 11966 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 11967 */ 11968 @ViewDebug.ExportedProperty(category = "focus") 11969 @InspectableProperty 11970 public final boolean getDefaultFocusHighlightEnabled() { 11971 return mDefaultFocusHighlightEnabled; 11972 } 11973 11974 /** 11975 * If a user manually specified the next view id for a particular direction, 11976 * use the root to look up the view. 11977 * @param root The root view of the hierarchy containing this view. 11978 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 11979 * or FOCUS_BACKWARD. 11980 * @return The user specified next view, or null if there is none. 11981 */ 11982 View findUserSetNextFocus(View root, @FocusDirection int direction) { 11983 switch (direction) { 11984 case FOCUS_LEFT: 11985 if (mNextFocusLeftId == View.NO_ID) return null; 11986 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 11987 case FOCUS_RIGHT: 11988 if (mNextFocusRightId == View.NO_ID) return null; 11989 return findViewInsideOutShouldExist(root, mNextFocusRightId); 11990 case FOCUS_UP: 11991 if (mNextFocusUpId == View.NO_ID) return null; 11992 return findViewInsideOutShouldExist(root, mNextFocusUpId); 11993 case FOCUS_DOWN: 11994 if (mNextFocusDownId == View.NO_ID) return null; 11995 return findViewInsideOutShouldExist(root, mNextFocusDownId); 11996 case FOCUS_FORWARD: 11997 if (mNextFocusForwardId == View.NO_ID) return null; 11998 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 11999 case FOCUS_BACKWARD: { 12000 if (mID == View.NO_ID) return null; 12001 final int id = mID; 12002 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 12003 @Override 12004 public boolean test(View t) { 12005 return t.mNextFocusForwardId == id; 12006 } 12007 }); 12008 } 12009 } 12010 return null; 12011 } 12012 12013 /** 12014 * If a user manually specified the next keyboard-navigation cluster for a particular direction, 12015 * use the root to look up the view. 12016 * 12017 * @param root the root view of the hierarchy containing this view 12018 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD} 12019 * @return the user-specified next cluster, or {@code null} if there is none 12020 */ 12021 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { 12022 switch (direction) { 12023 case FOCUS_FORWARD: 12024 if (mNextClusterForwardId == View.NO_ID) return null; 12025 return findViewInsideOutShouldExist(root, mNextClusterForwardId); 12026 case FOCUS_BACKWARD: { 12027 if (mID == View.NO_ID) return null; 12028 final int id = mID; 12029 return root.findViewByPredicateInsideOut(this, 12030 (Predicate<View>) t -> t.mNextClusterForwardId == id); 12031 } 12032 } 12033 return null; 12034 } 12035 12036 private View findViewInsideOutShouldExist(View root, int id) { 12037 if (mMatchIdPredicate == null) { 12038 mMatchIdPredicate = new MatchIdPredicate(); 12039 } 12040 mMatchIdPredicate.mId = id; 12041 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 12042 if (result == null) { 12043 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 12044 } 12045 return result; 12046 } 12047 12048 /** 12049 * Find and return all focusable views that are descendants of this view, 12050 * possibly including this view if it is focusable itself. 12051 * 12052 * @param direction The direction of the focus 12053 * @return A list of focusable views 12054 */ 12055 public ArrayList<View> getFocusables(@FocusDirection int direction) { 12056 ArrayList<View> result = new ArrayList<View>(24); 12057 addFocusables(result, direction); 12058 return result; 12059 } 12060 12061 /** 12062 * Add any focusable views that are descendants of this view (possibly 12063 * including this view if it is focusable itself) to views. If we are in touch mode, 12064 * only add views that are also focusable in touch mode. 12065 * 12066 * @param views Focusable views found so far 12067 * @param direction The direction of the focus 12068 */ 12069 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 12070 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 12071 } 12072 12073 /** 12074 * Adds any focusable views that are descendants of this view (possibly 12075 * including this view if it is focusable itself) to views. This method 12076 * adds all focusable views regardless if we are in touch mode or 12077 * only views focusable in touch mode if we are in touch mode or 12078 * only views that can take accessibility focus if accessibility is enabled 12079 * depending on the focusable mode parameter. 12080 * 12081 * @param views Focusable views found so far or null if all we are interested is 12082 * the number of focusables. 12083 * @param direction The direction of the focus. 12084 * @param focusableMode The type of focusables to be added. 12085 * 12086 * @see #FOCUSABLES_ALL 12087 * @see #FOCUSABLES_TOUCH_MODE 12088 */ 12089 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 12090 @FocusableMode int focusableMode) { 12091 if (views == null) { 12092 return; 12093 } 12094 if (!canTakeFocus()) { 12095 return; 12096 } 12097 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 12098 && !isFocusableInTouchMode()) { 12099 return; 12100 } 12101 views.add(this); 12102 } 12103 12104 /** 12105 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 12106 * including this view if it is a cluster root itself) to views. 12107 * 12108 * @param views Keyboard navigation cluster roots found so far 12109 * @param direction Direction to look 12110 */ 12111 public void addKeyboardNavigationClusters( 12112 @NonNull Collection<View> views, 12113 int direction) { 12114 if (!isKeyboardNavigationCluster()) { 12115 return; 12116 } 12117 if (!hasFocusable()) { 12118 return; 12119 } 12120 views.add(this); 12121 } 12122 12123 /** 12124 * Finds the Views that contain given text. The containment is case insensitive. 12125 * The search is performed by either the text that the View renders or the content 12126 * description that describes the view for accessibility purposes and the view does 12127 * not render or both. Clients can specify how the search is to be performed via 12128 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 12129 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 12130 * 12131 * @param outViews The output list of matching Views. 12132 * @param searched The text to match against. 12133 * 12134 * @see #FIND_VIEWS_WITH_TEXT 12135 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 12136 * @see #setContentDescription(CharSequence) 12137 */ 12138 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 12139 @FindViewFlags int flags) { 12140 if (getAccessibilityNodeProvider() != null) { 12141 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 12142 outViews.add(this); 12143 } 12144 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 12145 && (searched != null && searched.length() > 0) 12146 && (mContentDescription != null && mContentDescription.length() > 0)) { 12147 String searchedLowerCase = searched.toString().toLowerCase(); 12148 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 12149 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 12150 outViews.add(this); 12151 } 12152 } 12153 } 12154 12155 /** 12156 * Find and return all touchable views that are descendants of this view, 12157 * possibly including this view if it is touchable itself. 12158 * 12159 * @return A list of touchable views 12160 */ 12161 public ArrayList<View> getTouchables() { 12162 ArrayList<View> result = new ArrayList<View>(); 12163 addTouchables(result); 12164 return result; 12165 } 12166 12167 /** 12168 * Add any touchable views that are descendants of this view (possibly 12169 * including this view if it is touchable itself) to views. 12170 * 12171 * @param views Touchable views found so far 12172 */ 12173 public void addTouchables(ArrayList<View> views) { 12174 final int viewFlags = mViewFlags; 12175 12176 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 12177 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 12178 && (viewFlags & ENABLED_MASK) == ENABLED) { 12179 views.add(this); 12180 } 12181 } 12182 12183 /** 12184 * Returns whether this View is accessibility focused. 12185 * 12186 * @return True if this View is accessibility focused. 12187 */ 12188 @InspectableProperty(hasAttributeId = false) 12189 public boolean isAccessibilityFocused() { 12190 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 12191 } 12192 12193 /** 12194 * Call this to try to give accessibility focus to this view. 12195 * 12196 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 12197 * returns false or the view is no visible or the view already has accessibility 12198 * focus. 12199 * 12200 * See also {@link #focusSearch(int)}, which is what you call to say that you 12201 * have focus, and you want your parent to look for the next one. 12202 * 12203 * @return Whether this view actually took accessibility focus. 12204 * 12205 * @hide 12206 */ 12207 @UnsupportedAppUsage 12208 public boolean requestAccessibilityFocus() { 12209 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 12210 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 12211 return false; 12212 } 12213 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 12214 return false; 12215 } 12216 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 12217 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 12218 ViewRootImpl viewRootImpl = getViewRootImpl(); 12219 if (viewRootImpl != null) { 12220 viewRootImpl.setAccessibilityFocus(this, null); 12221 } 12222 invalidate(); 12223 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 12224 return true; 12225 } 12226 return false; 12227 } 12228 12229 /** 12230 * Call this to try to clear accessibility focus of this view. 12231 * 12232 * See also {@link #focusSearch(int)}, which is what you call to say that you 12233 * have focus, and you want your parent to look for the next one. 12234 * 12235 * @hide 12236 */ 12237 @UnsupportedAppUsage 12238 public void clearAccessibilityFocus() { 12239 clearAccessibilityFocusNoCallbacks(0); 12240 12241 // Clear the global reference of accessibility focus if this view or 12242 // any of its descendants had accessibility focus. This will NOT send 12243 // an event or update internal state if focus is cleared from a 12244 // descendant view, which may leave views in inconsistent states. 12245 final ViewRootImpl viewRootImpl = getViewRootImpl(); 12246 if (viewRootImpl != null) { 12247 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 12248 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 12249 viewRootImpl.setAccessibilityFocus(null, null); 12250 } 12251 } 12252 } 12253 12254 private void sendAccessibilityHoverEvent(int eventType) { 12255 // Since we are not delivering to a client accessibility events from not 12256 // important views (unless the clinet request that) we need to fire the 12257 // event from the deepest view exposed to the client. As a consequence if 12258 // the user crosses a not exposed view the client will see enter and exit 12259 // of the exposed predecessor followed by and enter and exit of that same 12260 // predecessor when entering and exiting the not exposed descendant. This 12261 // is fine since the client has a clear idea which view is hovered at the 12262 // price of a couple more events being sent. This is a simple and 12263 // working solution. 12264 View source = this; 12265 while (true) { 12266 if (source.includeForAccessibility()) { 12267 source.sendAccessibilityEvent(eventType); 12268 return; 12269 } 12270 ViewParent parent = source.getParent(); 12271 if (parent instanceof View) { 12272 source = (View) parent; 12273 } else { 12274 return; 12275 } 12276 } 12277 } 12278 12279 /** 12280 * Clears accessibility focus without calling any callback methods 12281 * normally invoked in {@link #clearAccessibilityFocus()}. This method 12282 * is used separately from that one for clearing accessibility focus when 12283 * giving this focus to another view. 12284 * 12285 * @param action The action, if any, that led to focus being cleared. Set to 12286 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 12287 * the window. 12288 */ 12289 void clearAccessibilityFocusNoCallbacks(int action) { 12290 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 12291 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 12292 invalidate(); 12293 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 12294 AccessibilityEvent event = AccessibilityEvent.obtain( 12295 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 12296 event.setAction(action); 12297 if (mAccessibilityDelegate != null) { 12298 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 12299 } else { 12300 sendAccessibilityEventUnchecked(event); 12301 } 12302 } 12303 } 12304 } 12305 12306 /** 12307 * Call this to try to give focus to a specific view or to one of its 12308 * descendants. 12309 * 12310 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 12311 * false), or if it can't be focused due to other conditions (not focusable in touch mode 12312 * ({@link #isFocusableInTouchMode}) while the device is in touch mode, not visible, not 12313 * enabled, or has no size). 12314 * 12315 * See also {@link #focusSearch(int)}, which is what you call to say that you 12316 * have focus, and you want your parent to look for the next one. 12317 * 12318 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 12319 * {@link #FOCUS_DOWN} and <code>null</code>. 12320 * 12321 * @return Whether this view or one of its descendants actually took focus. 12322 */ 12323 public final boolean requestFocus() { 12324 return requestFocus(View.FOCUS_DOWN); 12325 } 12326 12327 /** 12328 * This will request focus for whichever View was last focused within this 12329 * cluster before a focus-jump out of it. 12330 * 12331 * @hide 12332 */ 12333 @TestApi 12334 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 12335 // Prioritize focusableByDefault over algorithmic focus selection. 12336 if (restoreDefaultFocus()) { 12337 return true; 12338 } 12339 return requestFocus(direction); 12340 } 12341 12342 /** 12343 * This will request focus for whichever View not in a cluster was last focused before a 12344 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 12345 * the "first" focusable view it finds. 12346 * 12347 * @hide 12348 */ 12349 @TestApi 12350 public boolean restoreFocusNotInCluster() { 12351 return requestFocus(View.FOCUS_DOWN); 12352 } 12353 12354 /** 12355 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 12356 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 12357 * 12358 * @return Whether this view or one of its descendants actually took focus 12359 */ 12360 public boolean restoreDefaultFocus() { 12361 return requestFocus(View.FOCUS_DOWN); 12362 } 12363 12364 /** 12365 * Call this to try to give focus to a specific view or to one of its 12366 * descendants and give it a hint about what direction focus is heading. 12367 * 12368 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 12369 * false), or if it is focusable and it is not focusable in touch mode 12370 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 12371 * 12372 * See also {@link #focusSearch(int)}, which is what you call to say that you 12373 * have focus, and you want your parent to look for the next one. 12374 * 12375 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 12376 * <code>null</code> set for the previously focused rectangle. 12377 * 12378 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 12379 * @return Whether this view or one of its descendants actually took focus. 12380 */ 12381 public final boolean requestFocus(int direction) { 12382 return requestFocus(direction, null); 12383 } 12384 12385 /** 12386 * Call this to try to give focus to a specific view or to one of its descendants 12387 * and give it hints about the direction and a specific rectangle that the focus 12388 * is coming from. The rectangle can help give larger views a finer grained hint 12389 * about where focus is coming from, and therefore, where to show selection, or 12390 * forward focus change internally. 12391 * 12392 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 12393 * false), or if it is focusable and it is not focusable in touch mode 12394 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 12395 * 12396 * A View will not take focus if it is not visible. 12397 * 12398 * A View will not take focus if one of its parents has 12399 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 12400 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 12401 * 12402 * See also {@link #focusSearch(int)}, which is what you call to say that you 12403 * have focus, and you want your parent to look for the next one. 12404 * 12405 * You may wish to override this method if your custom {@link View} has an internal 12406 * {@link View} that it wishes to forward the request to. 12407 * 12408 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 12409 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 12410 * to give a finer grained hint about where focus is coming from. May be null 12411 * if there is no hint. 12412 * @return Whether this view or one of its descendants actually took focus. 12413 */ 12414 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 12415 return requestFocusNoSearch(direction, previouslyFocusedRect); 12416 } 12417 12418 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 12419 // need to be focusable 12420 if (!canTakeFocus()) { 12421 return false; 12422 } 12423 12424 // need to be focusable in touch mode if in touch mode 12425 if (isInTouchMode() && 12426 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 12427 return false; 12428 } 12429 12430 // need to not have any parents blocking us 12431 if (hasAncestorThatBlocksDescendantFocus()) { 12432 return false; 12433 } 12434 12435 if (!isLayoutValid()) { 12436 mPrivateFlags |= PFLAG_WANTS_FOCUS; 12437 } else { 12438 clearParentsWantFocus(); 12439 } 12440 12441 handleFocusGainInternal(direction, previouslyFocusedRect); 12442 return true; 12443 } 12444 12445 void clearParentsWantFocus() { 12446 if (mParent instanceof View) { 12447 ((View) mParent).mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 12448 ((View) mParent).clearParentsWantFocus(); 12449 } 12450 } 12451 12452 /** 12453 * Call this to try to give focus to a specific view or to one of its descendants. This is a 12454 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 12455 * touch mode to request focus when they are touched. 12456 * 12457 * @return Whether this view or one of its descendants actually took focus. 12458 * 12459 * @see #isInTouchMode() 12460 * 12461 */ 12462 public final boolean requestFocusFromTouch() { 12463 // Leave touch mode if we need to 12464 if (isInTouchMode()) { 12465 ViewRootImpl viewRoot = getViewRootImpl(); 12466 if (viewRoot != null) { 12467 viewRoot.ensureTouchMode(false); 12468 } 12469 } 12470 return requestFocus(View.FOCUS_DOWN); 12471 } 12472 12473 /** 12474 * @return Whether any ancestor of this view blocks descendant focus. 12475 */ 12476 private boolean hasAncestorThatBlocksDescendantFocus() { 12477 final boolean focusableInTouchMode = isFocusableInTouchMode(); 12478 ViewParent ancestor = mParent; 12479 while (ancestor instanceof ViewGroup) { 12480 final ViewGroup vgAncestor = (ViewGroup) ancestor; 12481 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 12482 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 12483 return true; 12484 } else { 12485 ancestor = vgAncestor.getParent(); 12486 } 12487 } 12488 return false; 12489 } 12490 12491 /** 12492 * Gets the mode for determining whether this View is important for accessibility. 12493 * A view is important for accessibility if it fires accessibility events and if it 12494 * is reported to accessibility services that query the screen. 12495 * 12496 * @return The mode for determining whether a view is important for accessibility, one 12497 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 12498 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 12499 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 12500 * 12501 * @attr ref android.R.styleable#View_importantForAccessibility 12502 * 12503 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 12504 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 12505 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 12506 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 12507 */ 12508 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 12509 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 12510 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 12511 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 12512 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 12513 to = "noHideDescendants") 12514 }) 12515 @InspectableProperty(enumMapping = { 12516 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"), 12517 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"), 12518 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"), 12519 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 12520 name = "noHideDescendants"), 12521 }) 12522 public int getImportantForAccessibility() { 12523 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 12524 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 12525 } 12526 12527 /** 12528 * Sets the live region mode for this view. This indicates to accessibility 12529 * services whether they should automatically notify the user about changes 12530 * to the view's content description or text, or to the content descriptions 12531 * or text of the view's children (where applicable). 12532 * <p> 12533 * For example, in a login screen with a TextView that displays an "incorrect 12534 * password" notification, that view should be marked as a live region with 12535 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 12536 * <p> 12537 * To disable change notifications for this view, use 12538 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 12539 * mode for most views. 12540 * <p> 12541 * To indicate that the user should be notified of changes, use 12542 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 12543 * <p> 12544 * If the view's changes should interrupt ongoing speech and notify the user 12545 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 12546 * 12547 * @param mode The live region mode for this view, one of: 12548 * <ul> 12549 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 12550 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 12551 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 12552 * </ul> 12553 * @attr ref android.R.styleable#View_accessibilityLiveRegion 12554 */ 12555 public void setAccessibilityLiveRegion(int mode) { 12556 if (mode != getAccessibilityLiveRegion()) { 12557 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 12558 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 12559 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 12560 notifyViewAccessibilityStateChangedIfNeeded( 12561 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12562 } 12563 } 12564 12565 /** 12566 * Gets the live region mode for this View. 12567 * 12568 * @return The live region mode for the view. 12569 * 12570 * @attr ref android.R.styleable#View_accessibilityLiveRegion 12571 * 12572 * @see #setAccessibilityLiveRegion(int) 12573 */ 12574 @InspectableProperty(enumMapping = { 12575 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"), 12576 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"), 12577 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive") 12578 }) 12579 public int getAccessibilityLiveRegion() { 12580 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 12581 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 12582 } 12583 12584 /** 12585 * Sets how to determine whether this view is important for accessibility 12586 * which is if it fires accessibility events and if it is reported to 12587 * accessibility services that query the screen. 12588 * 12589 * @param mode How to determine whether this view is important for accessibility. 12590 * 12591 * @attr ref android.R.styleable#View_importantForAccessibility 12592 * 12593 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 12594 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 12595 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 12596 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 12597 */ 12598 public void setImportantForAccessibility(int mode) { 12599 final int oldMode = getImportantForAccessibility(); 12600 if (mode != oldMode) { 12601 final boolean hideDescendants = 12602 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 12603 12604 // If this node or its descendants are no longer important, try to 12605 // clear accessibility focus. 12606 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 12607 final View focusHost = findAccessibilityFocusHost(hideDescendants); 12608 if (focusHost != null) { 12609 focusHost.clearAccessibilityFocus(); 12610 } 12611 } 12612 12613 // If we're moving between AUTO and another state, we might not need 12614 // to send a subtree changed notification. We'll store the computed 12615 // importance, since we'll need to check it later to make sure. 12616 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 12617 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 12618 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 12619 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 12620 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 12621 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 12622 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 12623 notifySubtreeAccessibilityStateChangedIfNeeded(); 12624 } else { 12625 notifyViewAccessibilityStateChangedIfNeeded( 12626 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12627 } 12628 } 12629 } 12630 12631 /** 12632 * Returns the view within this view's hierarchy that is hosting 12633 * accessibility focus. 12634 * 12635 * @param searchDescendants whether to search for focus in descendant views 12636 * @return the view hosting accessibility focus, or {@code null} 12637 */ 12638 private View findAccessibilityFocusHost(boolean searchDescendants) { 12639 if (isAccessibilityFocusedViewOrHost()) { 12640 return this; 12641 } 12642 12643 if (searchDescendants) { 12644 final ViewRootImpl viewRoot = getViewRootImpl(); 12645 if (viewRoot != null) { 12646 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 12647 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 12648 return focusHost; 12649 } 12650 } 12651 } 12652 12653 return null; 12654 } 12655 12656 /** 12657 * Computes whether this view should be exposed for accessibility. In 12658 * general, views that are interactive or provide information are exposed 12659 * while views that serve only as containers are hidden. 12660 * <p> 12661 * If an ancestor of this view has importance 12662 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 12663 * returns <code>false</code>. 12664 * <p> 12665 * Otherwise, the value is computed according to the view's 12666 * {@link #getImportantForAccessibility()} value: 12667 * <ol> 12668 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 12669 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 12670 * </code> 12671 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 12672 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 12673 * view satisfies any of the following: 12674 * <ul> 12675 * <li>Is actionable, e.g. {@link #isClickable()}, 12676 * {@link #isLongClickable()}, or {@link #isFocusable()} 12677 * <li>Has an {@link AccessibilityDelegate} 12678 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 12679 * {@link OnKeyListener}, etc. 12680 * <li>Is an accessibility live region, e.g. 12681 * {@link #getAccessibilityLiveRegion()} is not 12682 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 12683 * </ul> 12684 * <li>Has an accessibility pane title, see {@link #setAccessibilityPaneTitle}</li> 12685 * </ol> 12686 * 12687 * @return Whether the view is exposed for accessibility. 12688 * @see #setImportantForAccessibility(int) 12689 * @see #getImportantForAccessibility() 12690 */ 12691 public boolean isImportantForAccessibility() { 12692 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 12693 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 12694 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 12695 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 12696 return false; 12697 } 12698 12699 // Check parent mode to ensure we're not hidden. 12700 ViewParent parent = mParent; 12701 while (parent instanceof View) { 12702 if (((View) parent).getImportantForAccessibility() 12703 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 12704 return false; 12705 } 12706 parent = parent.getParent(); 12707 } 12708 12709 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 12710 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 12711 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE 12712 || isAccessibilityPane(); 12713 } 12714 12715 /** 12716 * Gets the parent for accessibility purposes. Note that the parent for 12717 * accessibility is not necessary the immediate parent. It is the first 12718 * predecessor that is important for accessibility. 12719 * 12720 * @return The parent for accessibility purposes. 12721 */ 12722 public ViewParent getParentForAccessibility() { 12723 if (mParent instanceof View) { 12724 View parentView = (View) mParent; 12725 if (parentView.includeForAccessibility()) { 12726 return mParent; 12727 } else { 12728 return mParent.getParentForAccessibility(); 12729 } 12730 } 12731 return null; 12732 } 12733 12734 /** @hide */ 12735 View getSelfOrParentImportantForA11y() { 12736 if (isImportantForAccessibility()) return this; 12737 ViewParent parent = getParentForAccessibility(); 12738 if (parent instanceof View) return (View) parent; 12739 return null; 12740 } 12741 12742 /** 12743 * Adds the children of this View relevant for accessibility to the given list 12744 * as output. Since some Views are not important for accessibility the added 12745 * child views are not necessarily direct children of this view, rather they are 12746 * the first level of descendants important for accessibility. 12747 * 12748 * @param outChildren The output list that will receive children for accessibility. 12749 */ 12750 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 12751 12752 } 12753 12754 /** 12755 * Whether to regard this view for accessibility. A view is regarded for 12756 * accessibility if it is important for accessibility or the querying 12757 * accessibility service has explicitly requested that view not 12758 * important for accessibility are regarded. 12759 * 12760 * @return Whether to regard the view for accessibility. 12761 * 12762 * @hide 12763 */ 12764 @UnsupportedAppUsage 12765 public boolean includeForAccessibility() { 12766 if (mAttachInfo != null) { 12767 return (mAttachInfo.mAccessibilityFetchFlags 12768 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 12769 || isImportantForAccessibility(); 12770 } 12771 return false; 12772 } 12773 12774 /** 12775 * Returns whether the View is considered actionable from 12776 * accessibility perspective. Such view are important for 12777 * accessibility. 12778 * 12779 * @return True if the view is actionable for accessibility. 12780 * 12781 * @hide 12782 */ 12783 public boolean isActionableForAccessibility() { 12784 return (isClickable() || isLongClickable() || isFocusable()); 12785 } 12786 12787 /** 12788 * Returns whether the View has registered callbacks which makes it 12789 * important for accessibility. 12790 * 12791 * @return True if the view is actionable for accessibility. 12792 */ 12793 private boolean hasListenersForAccessibility() { 12794 ListenerInfo info = getListenerInfo(); 12795 return mTouchDelegate != null || info.mOnKeyListener != null 12796 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 12797 || info.mOnHoverListener != null || info.mOnDragListener != null; 12798 } 12799 12800 /** 12801 * Notifies that the accessibility state of this view changed. The change 12802 * is local to this view and does not represent structural changes such 12803 * as children and parent. For example, the view became focusable. The 12804 * notification is at at most once every 12805 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 12806 * to avoid unnecessary load to the system. Also once a view has a pending 12807 * notification this method is a NOP until the notification has been sent. 12808 * 12809 * @hide 12810 */ 12811 @UnsupportedAppUsage 12812 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 12813 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 12814 return; 12815 } 12816 12817 // Changes to views with a pane title count as window state changes, as the pane title 12818 // marks them as significant parts of the UI. 12819 if ((changeType != AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) 12820 && isAccessibilityPane()) { 12821 // If the pane isn't visible, content changed events are sufficient unless we're 12822 // reporting that the view just disappeared 12823 if ((getVisibility() == VISIBLE) 12824 || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)) { 12825 final AccessibilityEvent event = AccessibilityEvent.obtain(); 12826 onInitializeAccessibilityEvent(event); 12827 event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 12828 event.setContentChangeTypes(changeType); 12829 event.setSource(this); 12830 onPopulateAccessibilityEvent(event); 12831 if (mParent != null) { 12832 try { 12833 mParent.requestSendAccessibilityEvent(this, event); 12834 } catch (AbstractMethodError e) { 12835 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() 12836 + " does not fully implement ViewParent", e); 12837 } 12838 } 12839 return; 12840 } 12841 } 12842 12843 // If this is a live region, we should send a subtree change event 12844 // from this view immediately. Otherwise, we can let it propagate up. 12845 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) { 12846 final AccessibilityEvent event = AccessibilityEvent.obtain(); 12847 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 12848 event.setContentChangeTypes(changeType); 12849 sendAccessibilityEventUnchecked(event); 12850 } else if (mParent != null) { 12851 try { 12852 mParent.notifySubtreeAccessibilityStateChanged(this, this, changeType); 12853 } catch (AbstractMethodError e) { 12854 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 12855 " does not fully implement ViewParent", e); 12856 } 12857 } 12858 } 12859 12860 /** 12861 * Notifies that the accessibility state of this view changed. The change 12862 * is *not* local to this view and does represent structural changes such 12863 * as children and parent. For example, the view size changed. The 12864 * notification is at at most once every 12865 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 12866 * to avoid unnecessary load to the system. Also once a view has a pending 12867 * notification this method is a NOP until the notification has been sent. 12868 * 12869 * @hide 12870 */ 12871 @UnsupportedAppUsage 12872 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 12873 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 12874 return; 12875 } 12876 12877 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 12878 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 12879 if (mParent != null) { 12880 try { 12881 mParent.notifySubtreeAccessibilityStateChanged( 12882 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 12883 } catch (AbstractMethodError e) { 12884 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 12885 " does not fully implement ViewParent", e); 12886 } 12887 } 12888 } 12889 } 12890 12891 /** 12892 * Changes the visibility of this View without triggering any other changes. This should only 12893 * be used by animation frameworks, such as {@link android.transition.Transition}, where 12894 * visibility changes should not adjust focus or trigger a new layout. Application developers 12895 * should use {@link #setVisibility} instead to ensure that the hierarchy is correctly updated. 12896 * 12897 * <p>Only call this method when a temporary visibility must be applied during an 12898 * animation and the original visibility value is guaranteed to be reset after the 12899 * animation completes. Use {@link #setVisibility} in all other cases.</p> 12900 * 12901 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 12902 * @see #setVisibility(int) 12903 */ 12904 public void setTransitionVisibility(@Visibility int visibility) { 12905 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 12906 } 12907 12908 /** 12909 * Reset the flag indicating the accessibility state of the subtree rooted 12910 * at this view changed. 12911 */ 12912 void resetSubtreeAccessibilityStateChanged() { 12913 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 12914 } 12915 12916 /** 12917 * Report an accessibility action to this view's parents for delegated processing. 12918 * 12919 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 12920 * call this method to delegate an accessibility action to a supporting parent. If the parent 12921 * returns true from its 12922 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 12923 * method this method will return true to signify that the action was consumed.</p> 12924 * 12925 * <p>This method is useful for implementing nested scrolling child views. If 12926 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 12927 * a custom view implementation may invoke this method to allow a parent to consume the 12928 * scroll first. If this method returns true the custom view should skip its own scrolling 12929 * behavior.</p> 12930 * 12931 * @param action Accessibility action to delegate 12932 * @param arguments Optional action arguments 12933 * @return true if the action was consumed by a parent 12934 */ 12935 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 12936 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 12937 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 12938 return true; 12939 } 12940 } 12941 return false; 12942 } 12943 12944 /** 12945 * Performs the specified accessibility action on the view. For 12946 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 12947 * <p> 12948 * If an {@link AccessibilityDelegate} has been specified via calling 12949 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 12950 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 12951 * is responsible for handling this call. 12952 * </p> 12953 * 12954 * <p>The default implementation will delegate 12955 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 12956 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 12957 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 12958 * 12959 * @param action The action to perform. 12960 * @param arguments Optional action arguments. 12961 * @return Whether the action was performed. 12962 */ 12963 public boolean performAccessibilityAction(int action, Bundle arguments) { 12964 if (mAccessibilityDelegate != null) { 12965 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 12966 } else { 12967 return performAccessibilityActionInternal(action, arguments); 12968 } 12969 } 12970 12971 /** 12972 * @see #performAccessibilityAction(int, Bundle) 12973 * 12974 * Note: Called from the default {@link AccessibilityDelegate}. 12975 * 12976 * @hide 12977 */ 12978 @UnsupportedAppUsage 12979 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 12980 if (isNestedScrollingEnabled() 12981 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 12982 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 12983 || action == R.id.accessibilityActionScrollUp 12984 || action == R.id.accessibilityActionScrollLeft 12985 || action == R.id.accessibilityActionScrollDown 12986 || action == R.id.accessibilityActionScrollRight)) { 12987 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 12988 return true; 12989 } 12990 } 12991 12992 switch (action) { 12993 case AccessibilityNodeInfo.ACTION_CLICK: { 12994 if (isClickable()) { 12995 performClickInternal(); 12996 return true; 12997 } 12998 } break; 12999 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 13000 if (isLongClickable()) { 13001 performLongClick(); 13002 return true; 13003 } 13004 } break; 13005 case AccessibilityNodeInfo.ACTION_FOCUS: { 13006 if (!hasFocus()) { 13007 // Get out of touch mode since accessibility 13008 // wants to move focus around. 13009 getViewRootImpl().ensureTouchMode(false); 13010 return requestFocus(); 13011 } 13012 } break; 13013 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 13014 if (hasFocus()) { 13015 clearFocus(); 13016 return !isFocused(); 13017 } 13018 } break; 13019 case AccessibilityNodeInfo.ACTION_SELECT: { 13020 if (!isSelected()) { 13021 setSelected(true); 13022 return isSelected(); 13023 } 13024 } break; 13025 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 13026 if (isSelected()) { 13027 setSelected(false); 13028 return !isSelected(); 13029 } 13030 } break; 13031 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 13032 if (!isAccessibilityFocused()) { 13033 return requestAccessibilityFocus(); 13034 } 13035 } break; 13036 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 13037 if (isAccessibilityFocused()) { 13038 clearAccessibilityFocus(); 13039 return true; 13040 } 13041 } break; 13042 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 13043 if (arguments != null) { 13044 final int granularity = arguments.getInt( 13045 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 13046 final boolean extendSelection = arguments.getBoolean( 13047 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 13048 return traverseAtGranularity(granularity, true, extendSelection); 13049 } 13050 } break; 13051 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 13052 if (arguments != null) { 13053 final int granularity = arguments.getInt( 13054 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 13055 final boolean extendSelection = arguments.getBoolean( 13056 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 13057 return traverseAtGranularity(granularity, false, extendSelection); 13058 } 13059 } break; 13060 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 13061 CharSequence text = getIterableTextForAccessibility(); 13062 if (text == null) { 13063 return false; 13064 } 13065 final int start = (arguments != null) ? arguments.getInt( 13066 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 13067 final int end = (arguments != null) ? arguments.getInt( 13068 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 13069 // Only cursor position can be specified (selection length == 0) 13070 if ((getAccessibilitySelectionStart() != start 13071 || getAccessibilitySelectionEnd() != end) 13072 && (start == end)) { 13073 setAccessibilitySelection(start, end); 13074 notifyViewAccessibilityStateChangedIfNeeded( 13075 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13076 return true; 13077 } 13078 } break; 13079 case R.id.accessibilityActionShowOnScreen: { 13080 if (mAttachInfo != null) { 13081 final Rect r = mAttachInfo.mTmpInvalRect; 13082 getDrawingRect(r); 13083 return requestRectangleOnScreen(r, true); 13084 } 13085 } break; 13086 case R.id.accessibilityActionContextClick: { 13087 if (isContextClickable()) { 13088 performContextClick(); 13089 return true; 13090 } 13091 } break; 13092 case R.id.accessibilityActionShowTooltip: { 13093 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipPopup != null)) { 13094 // Tooltip already showing 13095 return false; 13096 } 13097 return showLongClickTooltip(0, 0); 13098 } 13099 case R.id.accessibilityActionHideTooltip: { 13100 if ((mTooltipInfo == null) || (mTooltipInfo.mTooltipPopup == null)) { 13101 // No tooltip showing 13102 return false; 13103 } 13104 hideTooltip(); 13105 return true; 13106 } 13107 } 13108 return false; 13109 } 13110 13111 private boolean traverseAtGranularity(int granularity, boolean forward, 13112 boolean extendSelection) { 13113 CharSequence text = getIterableTextForAccessibility(); 13114 if (text == null || text.length() == 0) { 13115 return false; 13116 } 13117 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 13118 if (iterator == null) { 13119 return false; 13120 } 13121 int current = getAccessibilitySelectionEnd(); 13122 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 13123 current = forward ? 0 : text.length(); 13124 } 13125 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 13126 if (range == null) { 13127 return false; 13128 } 13129 final int segmentStart = range[0]; 13130 final int segmentEnd = range[1]; 13131 int selectionStart; 13132 int selectionEnd; 13133 if (extendSelection && isAccessibilitySelectionExtendable()) { 13134 selectionStart = getAccessibilitySelectionStart(); 13135 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 13136 selectionStart = forward ? segmentStart : segmentEnd; 13137 } 13138 selectionEnd = forward ? segmentEnd : segmentStart; 13139 } else { 13140 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 13141 } 13142 setAccessibilitySelection(selectionStart, selectionEnd); 13143 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 13144 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 13145 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 13146 return true; 13147 } 13148 13149 /** 13150 * Gets the text reported for accessibility purposes. 13151 * 13152 * @return The accessibility text. 13153 * 13154 * @hide 13155 */ 13156 @UnsupportedAppUsage 13157 public CharSequence getIterableTextForAccessibility() { 13158 return getContentDescription(); 13159 } 13160 13161 /** 13162 * Gets whether accessibility selection can be extended. 13163 * 13164 * @return If selection is extensible. 13165 * 13166 * @hide 13167 */ 13168 public boolean isAccessibilitySelectionExtendable() { 13169 return false; 13170 } 13171 13172 /** 13173 * @hide 13174 */ 13175 public int getAccessibilitySelectionStart() { 13176 return mAccessibilityCursorPosition; 13177 } 13178 13179 /** 13180 * @hide 13181 */ 13182 public int getAccessibilitySelectionEnd() { 13183 return getAccessibilitySelectionStart(); 13184 } 13185 13186 /** 13187 * @hide 13188 */ 13189 public void setAccessibilitySelection(int start, int end) { 13190 if (start == end && end == mAccessibilityCursorPosition) { 13191 return; 13192 } 13193 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 13194 mAccessibilityCursorPosition = start; 13195 } else { 13196 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 13197 } 13198 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 13199 } 13200 13201 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 13202 int fromIndex, int toIndex) { 13203 if (mParent == null) { 13204 return; 13205 } 13206 AccessibilityEvent event = AccessibilityEvent.obtain( 13207 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 13208 onInitializeAccessibilityEvent(event); 13209 onPopulateAccessibilityEvent(event); 13210 event.setFromIndex(fromIndex); 13211 event.setToIndex(toIndex); 13212 event.setAction(action); 13213 event.setMovementGranularity(granularity); 13214 mParent.requestSendAccessibilityEvent(this, event); 13215 } 13216 13217 /** 13218 * @hide 13219 */ 13220 @UnsupportedAppUsage 13221 public TextSegmentIterator getIteratorForGranularity(int granularity) { 13222 switch (granularity) { 13223 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 13224 CharSequence text = getIterableTextForAccessibility(); 13225 if (text != null && text.length() > 0) { 13226 CharacterTextSegmentIterator iterator = 13227 CharacterTextSegmentIterator.getInstance( 13228 mContext.getResources().getConfiguration().locale); 13229 iterator.initialize(text.toString()); 13230 return iterator; 13231 } 13232 } break; 13233 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 13234 CharSequence text = getIterableTextForAccessibility(); 13235 if (text != null && text.length() > 0) { 13236 WordTextSegmentIterator iterator = 13237 WordTextSegmentIterator.getInstance( 13238 mContext.getResources().getConfiguration().locale); 13239 iterator.initialize(text.toString()); 13240 return iterator; 13241 } 13242 } break; 13243 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 13244 CharSequence text = getIterableTextForAccessibility(); 13245 if (text != null && text.length() > 0) { 13246 ParagraphTextSegmentIterator iterator = 13247 ParagraphTextSegmentIterator.getInstance(); 13248 iterator.initialize(text.toString()); 13249 return iterator; 13250 } 13251 } break; 13252 } 13253 return null; 13254 } 13255 13256 /** 13257 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 13258 * and {@link #onFinishTemporaryDetach()}. 13259 * 13260 * <p>This method always returns {@code true} when called directly or indirectly from 13261 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 13262 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 13263 * <ul> 13264 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 13265 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 13266 * </ul> 13267 * </p> 13268 * 13269 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 13270 * and {@link #onFinishTemporaryDetach()}. 13271 */ isTemporarilyDetached()13272 public final boolean isTemporarilyDetached() { 13273 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 13274 } 13275 13276 /** 13277 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 13278 * a container View. 13279 */ 13280 @CallSuper dispatchStartTemporaryDetach()13281 public void dispatchStartTemporaryDetach() { 13282 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 13283 notifyEnterOrExitForAutoFillIfNeeded(false); 13284 onStartTemporaryDetach(); 13285 } 13286 13287 /** 13288 * This is called when a container is going to temporarily detach a child, with 13289 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 13290 * It will either be followed by {@link #onFinishTemporaryDetach()} or 13291 * {@link #onDetachedFromWindow()} when the container is done. 13292 */ onStartTemporaryDetach()13293 public void onStartTemporaryDetach() { 13294 removeUnsetPressCallback(); 13295 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 13296 } 13297 13298 /** 13299 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 13300 * a container View. 13301 */ 13302 @CallSuper dispatchFinishTemporaryDetach()13303 public void dispatchFinishTemporaryDetach() { 13304 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 13305 onFinishTemporaryDetach(); 13306 if (hasWindowFocus() && hasFocus()) { 13307 notifyFocusChangeToInputMethodManager(true /* hasFocus */); 13308 } 13309 notifyEnterOrExitForAutoFillIfNeeded(true); 13310 } 13311 13312 /** 13313 * Called after {@link #onStartTemporaryDetach} when the container is done 13314 * changing the view. 13315 */ onFinishTemporaryDetach()13316 public void onFinishTemporaryDetach() { 13317 } 13318 13319 /** 13320 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 13321 * for this view's window. Returns null if the view is not currently attached 13322 * to the window. Normally you will not need to use this directly, but 13323 * just use the standard high-level event callbacks like 13324 * {@link #onKeyDown(int, KeyEvent)}. 13325 */ getKeyDispatcherState()13326 public KeyEvent.DispatcherState getKeyDispatcherState() { 13327 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 13328 } 13329 13330 /** 13331 * Dispatch a key event before it is processed by any input method 13332 * associated with the view hierarchy. This can be used to intercept 13333 * key events in special situations before the IME consumes them; a 13334 * typical example would be handling the BACK key to update the application's 13335 * UI instead of allowing the IME to see it and close itself. 13336 * 13337 * @param event The key event to be dispatched. 13338 * @return True if the event was handled, false otherwise. 13339 */ dispatchKeyEventPreIme(KeyEvent event)13340 public boolean dispatchKeyEventPreIme(KeyEvent event) { 13341 return onKeyPreIme(event.getKeyCode(), event); 13342 } 13343 13344 /** 13345 * Dispatch a key event to the next view on the focus path. This path runs 13346 * from the top of the view tree down to the currently focused view. If this 13347 * view has focus, it will dispatch to itself. Otherwise it will dispatch 13348 * the next node down the focus path. This method also fires any key 13349 * listeners. 13350 * 13351 * @param event The key event to be dispatched. 13352 * @return True if the event was handled, false otherwise. 13353 */ dispatchKeyEvent(KeyEvent event)13354 public boolean dispatchKeyEvent(KeyEvent event) { 13355 if (mInputEventConsistencyVerifier != null) { 13356 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 13357 } 13358 13359 // Give any attached key listener a first crack at the event. 13360 //noinspection SimplifiableIfStatement 13361 ListenerInfo li = mListenerInfo; 13362 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 13363 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 13364 return true; 13365 } 13366 13367 if (event.dispatch(this, mAttachInfo != null 13368 ? mAttachInfo.mKeyDispatchState : null, this)) { 13369 return true; 13370 } 13371 13372 if (mInputEventConsistencyVerifier != null) { 13373 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 13374 } 13375 return false; 13376 } 13377 13378 /** 13379 * Dispatches a key shortcut event. 13380 * 13381 * @param event The key event to be dispatched. 13382 * @return True if the event was handled by the view, false otherwise. 13383 */ dispatchKeyShortcutEvent(KeyEvent event)13384 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 13385 return onKeyShortcut(event.getKeyCode(), event); 13386 } 13387 13388 /** 13389 * Pass the touch screen motion event down to the target view, or this 13390 * view if it is the target. 13391 * 13392 * @param event The motion event to be dispatched. 13393 * @return True if the event was handled by the view, false otherwise. 13394 */ dispatchTouchEvent(MotionEvent event)13395 public boolean dispatchTouchEvent(MotionEvent event) { 13396 // If the event should be handled by accessibility focus first. 13397 if (event.isTargetAccessibilityFocus()) { 13398 // We don't have focus or no virtual descendant has it, do not handle the event. 13399 if (!isAccessibilityFocusedViewOrHost()) { 13400 return false; 13401 } 13402 // We have focus and got the event, then use normal event dispatch. 13403 event.setTargetAccessibilityFocus(false); 13404 } 13405 13406 boolean result = false; 13407 13408 if (mInputEventConsistencyVerifier != null) { 13409 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 13410 } 13411 13412 final int actionMasked = event.getActionMasked(); 13413 if (actionMasked == MotionEvent.ACTION_DOWN) { 13414 // Defensive cleanup for new gesture 13415 stopNestedScroll(); 13416 } 13417 13418 if (onFilterTouchEventForSecurity(event)) { 13419 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 13420 result = true; 13421 } 13422 //noinspection SimplifiableIfStatement 13423 ListenerInfo li = mListenerInfo; 13424 if (li != null && li.mOnTouchListener != null 13425 && (mViewFlags & ENABLED_MASK) == ENABLED 13426 && li.mOnTouchListener.onTouch(this, event)) { 13427 result = true; 13428 } 13429 13430 if (!result && onTouchEvent(event)) { 13431 result = true; 13432 } 13433 } 13434 13435 if (!result && mInputEventConsistencyVerifier != null) { 13436 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 13437 } 13438 13439 // Clean up after nested scrolls if this is the end of a gesture; 13440 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 13441 // of the gesture. 13442 if (actionMasked == MotionEvent.ACTION_UP || 13443 actionMasked == MotionEvent.ACTION_CANCEL || 13444 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 13445 stopNestedScroll(); 13446 } 13447 13448 return result; 13449 } 13450 isAccessibilityFocusedViewOrHost()13451 boolean isAccessibilityFocusedViewOrHost() { 13452 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 13453 .getAccessibilityFocusedHost() == this); 13454 } 13455 13456 /** 13457 * Returns whether this view can receive pointer events. 13458 * 13459 * @return {@code true} if this view can receive pointer events. 13460 * @hide 13461 */ canReceivePointerEvents()13462 protected boolean canReceivePointerEvents() { 13463 return (mViewFlags & VISIBILITY_MASK) == VISIBLE || getAnimation() != null; 13464 } 13465 13466 /** 13467 * Filter the touch event to apply security policies. 13468 * 13469 * @param event The motion event to be filtered. 13470 * @return True if the event should be dispatched, false if the event should be dropped. 13471 * 13472 * @see #getFilterTouchesWhenObscured 13473 */ onFilterTouchEventForSecurity(MotionEvent event)13474 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 13475 //noinspection RedundantIfStatement 13476 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 13477 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 13478 // Window is obscured, drop this touch. 13479 return false; 13480 } 13481 return true; 13482 } 13483 13484 /** 13485 * Pass a trackball motion event down to the focused view. 13486 * 13487 * @param event The motion event to be dispatched. 13488 * @return True if the event was handled by the view, false otherwise. 13489 */ dispatchTrackballEvent(MotionEvent event)13490 public boolean dispatchTrackballEvent(MotionEvent event) { 13491 if (mInputEventConsistencyVerifier != null) { 13492 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 13493 } 13494 13495 return onTrackballEvent(event); 13496 } 13497 13498 /** 13499 * Pass a captured pointer event down to the focused view. 13500 * 13501 * @param event The motion event to be dispatched. 13502 * @return True if the event was handled by the view, false otherwise. 13503 */ dispatchCapturedPointerEvent(MotionEvent event)13504 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 13505 if (!hasPointerCapture()) { 13506 return false; 13507 } 13508 //noinspection SimplifiableIfStatement 13509 ListenerInfo li = mListenerInfo; 13510 if (li != null && li.mOnCapturedPointerListener != null 13511 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 13512 return true; 13513 } 13514 return onCapturedPointerEvent(event); 13515 } 13516 13517 /** 13518 * Dispatch a generic motion event. 13519 * <p> 13520 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 13521 * are delivered to the view under the pointer. All other generic motion events are 13522 * delivered to the focused view. Hover events are handled specially and are delivered 13523 * to {@link #onHoverEvent(MotionEvent)}. 13524 * </p> 13525 * 13526 * @param event The motion event to be dispatched. 13527 * @return True if the event was handled by the view, false otherwise. 13528 */ dispatchGenericMotionEvent(MotionEvent event)13529 public boolean dispatchGenericMotionEvent(MotionEvent event) { 13530 if (mInputEventConsistencyVerifier != null) { 13531 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 13532 } 13533 13534 final int source = event.getSource(); 13535 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 13536 final int action = event.getAction(); 13537 if (action == MotionEvent.ACTION_HOVER_ENTER 13538 || action == MotionEvent.ACTION_HOVER_MOVE 13539 || action == MotionEvent.ACTION_HOVER_EXIT) { 13540 if (dispatchHoverEvent(event)) { 13541 return true; 13542 } 13543 } else if (dispatchGenericPointerEvent(event)) { 13544 return true; 13545 } 13546 } else if (dispatchGenericFocusedEvent(event)) { 13547 return true; 13548 } 13549 13550 if (dispatchGenericMotionEventInternal(event)) { 13551 return true; 13552 } 13553 13554 if (mInputEventConsistencyVerifier != null) { 13555 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 13556 } 13557 return false; 13558 } 13559 dispatchGenericMotionEventInternal(MotionEvent event)13560 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 13561 //noinspection SimplifiableIfStatement 13562 ListenerInfo li = mListenerInfo; 13563 if (li != null && li.mOnGenericMotionListener != null 13564 && (mViewFlags & ENABLED_MASK) == ENABLED 13565 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 13566 return true; 13567 } 13568 13569 if (onGenericMotionEvent(event)) { 13570 return true; 13571 } 13572 13573 final int actionButton = event.getActionButton(); 13574 switch (event.getActionMasked()) { 13575 case MotionEvent.ACTION_BUTTON_PRESS: 13576 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 13577 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 13578 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 13579 if (performContextClick(event.getX(), event.getY())) { 13580 mInContextButtonPress = true; 13581 setPressed(true, event.getX(), event.getY()); 13582 removeTapCallback(); 13583 removeLongPressCallback(); 13584 return true; 13585 } 13586 } 13587 break; 13588 13589 case MotionEvent.ACTION_BUTTON_RELEASE: 13590 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 13591 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 13592 mInContextButtonPress = false; 13593 mIgnoreNextUpEvent = true; 13594 } 13595 break; 13596 } 13597 13598 if (mInputEventConsistencyVerifier != null) { 13599 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 13600 } 13601 return false; 13602 } 13603 13604 /** 13605 * Dispatch a hover event. 13606 * <p> 13607 * Do not call this method directly. 13608 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 13609 * </p> 13610 * 13611 * @param event The motion event to be dispatched. 13612 * @return True if the event was handled by the view, false otherwise. 13613 */ dispatchHoverEvent(MotionEvent event)13614 protected boolean dispatchHoverEvent(MotionEvent event) { 13615 ListenerInfo li = mListenerInfo; 13616 //noinspection SimplifiableIfStatement 13617 if (li != null && li.mOnHoverListener != null 13618 && (mViewFlags & ENABLED_MASK) == ENABLED 13619 && li.mOnHoverListener.onHover(this, event)) { 13620 return true; 13621 } 13622 13623 return onHoverEvent(event); 13624 } 13625 13626 /** 13627 * Returns true if the view has a child to which it has recently sent 13628 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 13629 * it does not have a hovered child, then it must be the innermost hovered view. 13630 * @hide 13631 */ hasHoveredChild()13632 protected boolean hasHoveredChild() { 13633 return false; 13634 } 13635 13636 /** 13637 * Returns true if the given point, in local coordinates, is inside the hovered child. 13638 * 13639 * @hide 13640 */ pointInHoveredChild(MotionEvent event)13641 protected boolean pointInHoveredChild(MotionEvent event) { 13642 return false; 13643 } 13644 13645 /** 13646 * Dispatch a generic motion event to the view under the first pointer. 13647 * <p> 13648 * Do not call this method directly. 13649 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 13650 * </p> 13651 * 13652 * @param event The motion event to be dispatched. 13653 * @return True if the event was handled by the view, false otherwise. 13654 */ dispatchGenericPointerEvent(MotionEvent event)13655 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 13656 return false; 13657 } 13658 13659 /** 13660 * Dispatch a generic motion event to the currently focused view. 13661 * <p> 13662 * Do not call this method directly. 13663 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 13664 * </p> 13665 * 13666 * @param event The motion event to be dispatched. 13667 * @return True if the event was handled by the view, false otherwise. 13668 */ dispatchGenericFocusedEvent(MotionEvent event)13669 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 13670 return false; 13671 } 13672 13673 /** 13674 * Dispatch a pointer event. 13675 * <p> 13676 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 13677 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 13678 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 13679 * and should not be expected to handle other pointing device features. 13680 * </p> 13681 * 13682 * @param event The motion event to be dispatched. 13683 * @return True if the event was handled by the view, false otherwise. 13684 * @hide 13685 */ 13686 @UnsupportedAppUsage dispatchPointerEvent(MotionEvent event)13687 public final boolean dispatchPointerEvent(MotionEvent event) { 13688 if (event.isTouchEvent()) { 13689 return dispatchTouchEvent(event); 13690 } else { 13691 return dispatchGenericMotionEvent(event); 13692 } 13693 } 13694 13695 /** 13696 * Called when the window containing this view gains or loses window focus. 13697 * ViewGroups should override to route to their children. 13698 * 13699 * @param hasFocus True if the window containing this view now has focus, 13700 * false otherwise. 13701 */ dispatchWindowFocusChanged(boolean hasFocus)13702 public void dispatchWindowFocusChanged(boolean hasFocus) { 13703 onWindowFocusChanged(hasFocus); 13704 } 13705 13706 /** 13707 * Called when the window containing this view gains or loses focus. Note 13708 * that this is separate from view focus: to receive key events, both 13709 * your view and its window must have focus. If a window is displayed 13710 * on top of yours that takes input focus, then your own window will lose 13711 * focus but the view focus will remain unchanged. 13712 * 13713 * @param hasWindowFocus True if the window containing this view now has 13714 * focus, false otherwise. 13715 */ onWindowFocusChanged(boolean hasWindowFocus)13716 public void onWindowFocusChanged(boolean hasWindowFocus) { 13717 if (!hasWindowFocus) { 13718 if (isPressed()) { 13719 setPressed(false); 13720 } 13721 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 13722 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 13723 notifyFocusChangeToInputMethodManager(false /* hasFocus */); 13724 } 13725 removeLongPressCallback(); 13726 removeTapCallback(); 13727 onFocusLost(); 13728 } else if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 13729 notifyFocusChangeToInputMethodManager(true /* hasFocus */); 13730 } 13731 13732 refreshDrawableState(); 13733 } 13734 13735 /** 13736 * Returns true if this view is in a window that currently has window focus. 13737 * Note that this is not the same as the view itself having focus. 13738 * 13739 * @return True if this view is in a window that currently has window focus. 13740 */ hasWindowFocus()13741 public boolean hasWindowFocus() { 13742 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 13743 } 13744 13745 /** 13746 * Dispatch a view visibility change down the view hierarchy. 13747 * ViewGroups should override to route to their children. 13748 * @param changedView The view whose visibility changed. Could be 'this' or 13749 * an ancestor view. 13750 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 13751 * {@link #INVISIBLE} or {@link #GONE}. 13752 */ dispatchVisibilityChanged(@onNull View changedView, @Visibility int visibility)13753 protected void dispatchVisibilityChanged(@NonNull View changedView, 13754 @Visibility int visibility) { 13755 onVisibilityChanged(changedView, visibility); 13756 } 13757 13758 /** 13759 * Called when the visibility of the view or an ancestor of the view has 13760 * changed. 13761 * 13762 * @param changedView The view whose visibility changed. May be 13763 * {@code this} or an ancestor view. 13764 * @param visibility The new visibility, one of {@link #VISIBLE}, 13765 * {@link #INVISIBLE} or {@link #GONE}. 13766 */ onVisibilityChanged(@onNull View changedView, @Visibility int visibility)13767 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 13768 } 13769 13770 /** 13771 * Dispatch a hint about whether this view is displayed. For instance, when 13772 * a View moves out of the screen, it might receives a display hint indicating 13773 * the view is not displayed. Applications should not <em>rely</em> on this hint 13774 * as there is no guarantee that they will receive one. 13775 * 13776 * @param hint A hint about whether or not this view is displayed: 13777 * {@link #VISIBLE} or {@link #INVISIBLE}. 13778 */ dispatchDisplayHint(@isibility int hint)13779 public void dispatchDisplayHint(@Visibility int hint) { 13780 onDisplayHint(hint); 13781 } 13782 13783 /** 13784 * Gives this view a hint about whether is displayed or not. For instance, when 13785 * a View moves out of the screen, it might receives a display hint indicating 13786 * the view is not displayed. Applications should not <em>rely</em> on this hint 13787 * as there is no guarantee that they will receive one. 13788 * 13789 * @param hint A hint about whether or not this view is displayed: 13790 * {@link #VISIBLE} or {@link #INVISIBLE}. 13791 */ onDisplayHint(@isibility int hint)13792 protected void onDisplayHint(@Visibility int hint) { 13793 } 13794 13795 /** 13796 * Dispatch a window visibility change down the view hierarchy. 13797 * ViewGroups should override to route to their children. 13798 * 13799 * @param visibility The new visibility of the window. 13800 * 13801 * @see #onWindowVisibilityChanged(int) 13802 */ dispatchWindowVisibilityChanged(@isibility int visibility)13803 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 13804 onWindowVisibilityChanged(visibility); 13805 } 13806 13807 /** 13808 * Called when the window containing has change its visibility 13809 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 13810 * that this tells you whether or not your window is being made visible 13811 * to the window manager; this does <em>not</em> tell you whether or not 13812 * your window is obscured by other windows on the screen, even if it 13813 * is itself visible. 13814 * 13815 * @param visibility The new visibility of the window. 13816 */ onWindowVisibilityChanged(@isibility int visibility)13817 protected void onWindowVisibilityChanged(@Visibility int visibility) { 13818 if (visibility == VISIBLE) { 13819 initialAwakenScrollBars(); 13820 } 13821 } 13822 13823 /** 13824 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 13825 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 13826 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 13827 * 13828 * @param isVisible true if this view's visibility to the user is uninterrupted by its 13829 * ancestors or by window visibility 13830 * @return true if this view is visible to the user, not counting clipping or overlapping 13831 */ dispatchVisibilityAggregated(boolean isVisible)13832 boolean dispatchVisibilityAggregated(boolean isVisible) { 13833 final boolean thisVisible = getVisibility() == VISIBLE; 13834 // If we're not visible but something is telling us we are, ignore it. 13835 if (thisVisible || !isVisible) { 13836 onVisibilityAggregated(isVisible); 13837 } 13838 return thisVisible && isVisible; 13839 } 13840 13841 /** 13842 * Called when the user-visibility of this View is potentially affected by a change 13843 * to this view itself, an ancestor view or the window this view is attached to. 13844 * 13845 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 13846 * and this view's window is also visible 13847 */ 13848 @CallSuper onVisibilityAggregated(boolean isVisible)13849 public void onVisibilityAggregated(boolean isVisible) { 13850 // Update our internal visibility tracking so we can detect changes 13851 boolean oldVisible = (mPrivateFlags3 & PFLAG3_AGGREGATED_VISIBLE) != 0; 13852 mPrivateFlags3 = isVisible ? (mPrivateFlags3 | PFLAG3_AGGREGATED_VISIBLE) 13853 : (mPrivateFlags3 & ~PFLAG3_AGGREGATED_VISIBLE); 13854 if (isVisible && mAttachInfo != null) { 13855 initialAwakenScrollBars(); 13856 } 13857 13858 final Drawable dr = mBackground; 13859 if (dr != null && isVisible != dr.isVisible()) { 13860 dr.setVisible(isVisible, false); 13861 } 13862 final Drawable hl = mDefaultFocusHighlight; 13863 if (hl != null && isVisible != hl.isVisible()) { 13864 hl.setVisible(isVisible, false); 13865 } 13866 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 13867 if (fg != null && isVisible != fg.isVisible()) { 13868 fg.setVisible(isVisible, false); 13869 } 13870 13871 if (isAutofillable()) { 13872 AutofillManager afm = getAutofillManager(); 13873 13874 if (afm != null && getAutofillViewId() > LAST_APP_AUTOFILL_ID) { 13875 if (mVisibilityChangeForAutofillHandler != null) { 13876 mVisibilityChangeForAutofillHandler.removeMessages(0); 13877 } 13878 13879 // If the view is in the background but still part of the hierarchy this is called 13880 // with isVisible=false. Hence visibility==false requires further checks 13881 if (isVisible) { 13882 afm.notifyViewVisibilityChanged(this, true); 13883 } else { 13884 if (mVisibilityChangeForAutofillHandler == null) { 13885 mVisibilityChangeForAutofillHandler = 13886 new VisibilityChangeForAutofillHandler(afm, this); 13887 } 13888 // Let current operation (e.g. removal of the view from the hierarchy) 13889 // finish before checking state 13890 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); 13891 } 13892 } 13893 } 13894 if (isAccessibilityPane()) { 13895 if (isVisible != oldVisible) { 13896 notifyViewAccessibilityStateChangedIfNeeded(isVisible 13897 ? AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED 13898 : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); 13899 } 13900 } 13901 } 13902 13903 /** 13904 * Returns the current visibility of the window this view is attached to 13905 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 13906 * 13907 * @return Returns the current visibility of the view's window. 13908 */ 13909 @Visibility getWindowVisibility()13910 public int getWindowVisibility() { 13911 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 13912 } 13913 13914 /** 13915 * Retrieve the overall visible display size in which the window this view is 13916 * attached to has been positioned in. This takes into account screen 13917 * decorations above the window, for both cases where the window itself 13918 * is being position inside of them or the window is being placed under 13919 * then and covered insets are used for the window to position its content 13920 * inside. In effect, this tells you the available area where content can 13921 * be placed and remain visible to users. 13922 * 13923 * <p>This function requires an IPC back to the window manager to retrieve 13924 * the requested information, so should not be used in performance critical 13925 * code like drawing. 13926 * 13927 * @param outRect Filled in with the visible display frame. If the view 13928 * is not attached to a window, this is simply the raw display size. 13929 */ getWindowVisibleDisplayFrame(Rect outRect)13930 public void getWindowVisibleDisplayFrame(Rect outRect) { 13931 if (mAttachInfo != null) { 13932 try { 13933 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 13934 } catch (RemoteException e) { 13935 return; 13936 } 13937 // XXX This is really broken, and probably all needs to be done 13938 // in the window manager, and we need to know more about whether 13939 // we want the area behind or in front of the IME. 13940 final Rect insets = mAttachInfo.mVisibleInsets; 13941 outRect.left += insets.left; 13942 outRect.top += insets.top; 13943 outRect.right -= insets.right; 13944 outRect.bottom -= insets.bottom; 13945 return; 13946 } 13947 // The view is not attached to a display so we don't have a context. 13948 // Make a best guess about the display size. 13949 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 13950 d.getRectSize(outRect); 13951 } 13952 13953 /** 13954 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 13955 * is currently in without any insets. 13956 * 13957 * @hide 13958 */ 13959 @UnsupportedAppUsage getWindowDisplayFrame(Rect outRect)13960 public void getWindowDisplayFrame(Rect outRect) { 13961 if (mAttachInfo != null) { 13962 try { 13963 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 13964 } catch (RemoteException e) { 13965 return; 13966 } 13967 return; 13968 } 13969 // The view is not attached to a display so we don't have a context. 13970 // Make a best guess about the display size. 13971 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 13972 d.getRectSize(outRect); 13973 } 13974 13975 /** 13976 * Dispatch a notification about a resource configuration change down 13977 * the view hierarchy. 13978 * ViewGroups should override to route to their children. 13979 * 13980 * @param newConfig The new resource configuration. 13981 * 13982 * @see #onConfigurationChanged(android.content.res.Configuration) 13983 */ dispatchConfigurationChanged(Configuration newConfig)13984 public void dispatchConfigurationChanged(Configuration newConfig) { 13985 onConfigurationChanged(newConfig); 13986 } 13987 13988 /** 13989 * Called when the current configuration of the resources being used 13990 * by the application have changed. You can use this to decide when 13991 * to reload resources that can changed based on orientation and other 13992 * configuration characteristics. You only need to use this if you are 13993 * not relying on the normal {@link android.app.Activity} mechanism of 13994 * recreating the activity instance upon a configuration change. 13995 * 13996 * @param newConfig The new resource configuration. 13997 */ onConfigurationChanged(Configuration newConfig)13998 protected void onConfigurationChanged(Configuration newConfig) { 13999 } 14000 14001 /** 14002 * Private function to aggregate all per-view attributes in to the view 14003 * root. 14004 */ dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility)14005 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 14006 performCollectViewAttributes(attachInfo, visibility); 14007 } 14008 performCollectViewAttributes(AttachInfo attachInfo, int visibility)14009 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 14010 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 14011 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 14012 attachInfo.mKeepScreenOn = true; 14013 } 14014 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 14015 ListenerInfo li = mListenerInfo; 14016 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 14017 attachInfo.mHasSystemUiListeners = true; 14018 } 14019 } 14020 } 14021 needGlobalAttributesUpdate(boolean force)14022 void needGlobalAttributesUpdate(boolean force) { 14023 final AttachInfo ai = mAttachInfo; 14024 if (ai != null && !ai.mRecomputeGlobalAttributes) { 14025 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 14026 || ai.mHasSystemUiListeners) { 14027 ai.mRecomputeGlobalAttributes = true; 14028 } 14029 } 14030 } 14031 14032 /** 14033 * Returns whether the device is currently in touch mode. Touch mode is entered 14034 * once the user begins interacting with the device by touch, and affects various 14035 * things like whether focus is always visible to the user. 14036 * 14037 * @return Whether the device is in touch mode. 14038 */ 14039 @ViewDebug.ExportedProperty isInTouchMode()14040 public boolean isInTouchMode() { 14041 if (mAttachInfo != null) { 14042 return mAttachInfo.mInTouchMode; 14043 } else { 14044 return ViewRootImpl.isInTouchMode(); 14045 } 14046 } 14047 14048 /** 14049 * Returns the context the view is running in, through which it can 14050 * access the current theme, resources, etc. 14051 * 14052 * @return The view's Context. 14053 */ 14054 @ViewDebug.CapturedViewProperty getContext()14055 public final Context getContext() { 14056 return mContext; 14057 } 14058 14059 /** 14060 * Handle a key event before it is processed by any input method 14061 * associated with the view hierarchy. This can be used to intercept 14062 * key events in special situations before the IME consumes them; a 14063 * typical example would be handling the BACK key to update the application's 14064 * UI instead of allowing the IME to see it and close itself. 14065 * 14066 * @param keyCode The value in event.getKeyCode(). 14067 * @param event Description of the key event. 14068 * @return If you handled the event, return true. If you want to allow the 14069 * event to be handled by the next receiver, return false. 14070 */ onKeyPreIme(int keyCode, KeyEvent event)14071 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 14072 return false; 14073 } 14074 14075 /** 14076 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 14077 * KeyEvent.Callback.onKeyDown()}: perform press of the view 14078 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 14079 * is released, if the view is enabled and clickable. 14080 * <p> 14081 * Key presses in software keyboards will generally NOT trigger this 14082 * listener, although some may elect to do so in some situations. Do not 14083 * rely on this to catch software key presses. 14084 * 14085 * @param keyCode a key code that represents the button pressed, from 14086 * {@link android.view.KeyEvent} 14087 * @param event the KeyEvent object that defines the button action 14088 */ onKeyDown(int keyCode, KeyEvent event)14089 public boolean onKeyDown(int keyCode, KeyEvent event) { 14090 if (KeyEvent.isConfirmKey(keyCode)) { 14091 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 14092 return true; 14093 } 14094 14095 if (event.getRepeatCount() == 0) { 14096 // Long clickable items don't necessarily have to be clickable. 14097 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 14098 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 14099 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 14100 // For the purposes of menu anchoring and drawable hotspots, 14101 // key events are considered to be at the center of the view. 14102 final float x = getWidth() / 2f; 14103 final float y = getHeight() / 2f; 14104 if (clickable) { 14105 setPressed(true, x, y); 14106 } 14107 checkForLongClick( 14108 ViewConfiguration.getLongPressTimeout(), 14109 x, 14110 y, 14111 // This is not a touch gesture -- do not classify it as one. 14112 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION); 14113 return true; 14114 } 14115 } 14116 } 14117 14118 return false; 14119 } 14120 14121 /** 14122 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 14123 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 14124 * the event). 14125 * <p>Key presses in software keyboards will generally NOT trigger this listener, 14126 * although some may elect to do so in some situations. Do not rely on this to 14127 * catch software key presses. 14128 */ onKeyLongPress(int keyCode, KeyEvent event)14129 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 14130 return false; 14131 } 14132 14133 /** 14134 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 14135 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 14136 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 14137 * or {@link KeyEvent#KEYCODE_SPACE} is released. 14138 * <p>Key presses in software keyboards will generally NOT trigger this listener, 14139 * although some may elect to do so in some situations. Do not rely on this to 14140 * catch software key presses. 14141 * 14142 * @param keyCode A key code that represents the button pressed, from 14143 * {@link android.view.KeyEvent}. 14144 * @param event The KeyEvent object that defines the button action. 14145 */ onKeyUp(int keyCode, KeyEvent event)14146 public boolean onKeyUp(int keyCode, KeyEvent event) { 14147 if (KeyEvent.isConfirmKey(keyCode)) { 14148 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 14149 return true; 14150 } 14151 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 14152 setPressed(false); 14153 14154 if (!mHasPerformedLongPress) { 14155 // This is a tap, so remove the longpress check 14156 removeLongPressCallback(); 14157 if (!event.isCanceled()) { 14158 return performClickInternal(); 14159 } 14160 } 14161 } 14162 } 14163 return false; 14164 } 14165 14166 /** 14167 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 14168 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 14169 * the event). 14170 * <p>Key presses in software keyboards will generally NOT trigger this listener, 14171 * although some may elect to do so in some situations. Do not rely on this to 14172 * catch software key presses. 14173 * 14174 * @param keyCode A key code that represents the button pressed, from 14175 * {@link android.view.KeyEvent}. 14176 * @param repeatCount The number of times the action was made. 14177 * @param event The KeyEvent object that defines the button action. 14178 */ onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)14179 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 14180 return false; 14181 } 14182 14183 /** 14184 * Called on the focused view when a key shortcut event is not handled. 14185 * Override this method to implement local key shortcuts for the View. 14186 * Key shortcuts can also be implemented by setting the 14187 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 14188 * 14189 * @param keyCode The value in event.getKeyCode(). 14190 * @param event Description of the key event. 14191 * @return If you handled the event, return true. If you want to allow the 14192 * event to be handled by the next receiver, return false. 14193 */ onKeyShortcut(int keyCode, KeyEvent event)14194 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 14195 return false; 14196 } 14197 14198 /** 14199 * Check whether the called view is a text editor, in which case it 14200 * would make sense to automatically display a soft input window for 14201 * it. Subclasses should override this if they implement 14202 * {@link #onCreateInputConnection(EditorInfo)} to return true if 14203 * a call on that method would return a non-null InputConnection, and 14204 * they are really a first-class editor that the user would normally 14205 * start typing on when the go into a window containing your view. 14206 * 14207 * <p>The default implementation always returns false. This does 14208 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 14209 * will not be called or the user can not otherwise perform edits on your 14210 * view; it is just a hint to the system that this is not the primary 14211 * purpose of this view. 14212 * 14213 * @return Returns true if this view is a text editor, else false. 14214 */ onCheckIsTextEditor()14215 public boolean onCheckIsTextEditor() { 14216 return false; 14217 } 14218 14219 /** 14220 * Create a new InputConnection for an InputMethod to interact 14221 * with the view. The default implementation returns null, since it doesn't 14222 * support input methods. You can override this to implement such support. 14223 * This is only needed for views that take focus and text input. 14224 * 14225 * <p>When implementing this, you probably also want to implement 14226 * {@link #onCheckIsTextEditor()} to indicate you will return a 14227 * non-null InputConnection.</p> 14228 * 14229 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 14230 * object correctly and in its entirety, so that the connected IME can rely 14231 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 14232 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 14233 * must be filled in with the correct cursor position for IMEs to work correctly 14234 * with your application.</p> 14235 * 14236 * @param outAttrs Fill in with attribute information about the connection. 14237 */ onCreateInputConnection(EditorInfo outAttrs)14238 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 14239 return null; 14240 } 14241 14242 /** 14243 * Called by the {@link android.view.inputmethod.InputMethodManager} 14244 * when a view who is not the current 14245 * input connection target is trying to make a call on the manager. The 14246 * default implementation returns false; you can override this to return 14247 * true for certain views if you are performing InputConnection proxying 14248 * to them. 14249 * @param view The View that is making the InputMethodManager call. 14250 * @return Return true to allow the call, false to reject. 14251 */ checkInputConnectionProxy(View view)14252 public boolean checkInputConnectionProxy(View view) { 14253 return false; 14254 } 14255 14256 /** 14257 * Show the context menu for this view. It is not safe to hold on to the 14258 * menu after returning from this method. 14259 * 14260 * You should normally not overload this method. Overload 14261 * {@link #onCreateContextMenu(ContextMenu)} or define an 14262 * {@link OnCreateContextMenuListener} to add items to the context menu. 14263 * 14264 * @param menu The context menu to populate 14265 */ createContextMenu(ContextMenu menu)14266 public void createContextMenu(ContextMenu menu) { 14267 ContextMenuInfo menuInfo = getContextMenuInfo(); 14268 14269 // Sets the current menu info so all items added to menu will have 14270 // my extra info set. 14271 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 14272 14273 onCreateContextMenu(menu); 14274 ListenerInfo li = mListenerInfo; 14275 if (li != null && li.mOnCreateContextMenuListener != null) { 14276 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 14277 } 14278 14279 // Clear the extra information so subsequent items that aren't mine don't 14280 // have my extra info. 14281 ((MenuBuilder)menu).setCurrentMenuInfo(null); 14282 14283 if (mParent != null) { 14284 mParent.createContextMenu(menu); 14285 } 14286 } 14287 14288 /** 14289 * Views should implement this if they have extra information to associate 14290 * with the context menu. The return result is supplied as a parameter to 14291 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 14292 * callback. 14293 * 14294 * @return Extra information about the item for which the context menu 14295 * should be shown. This information will vary across different 14296 * subclasses of View. 14297 */ getContextMenuInfo()14298 protected ContextMenuInfo getContextMenuInfo() { 14299 return null; 14300 } 14301 14302 /** 14303 * Views should implement this if the view itself is going to add items to 14304 * the context menu. 14305 * 14306 * @param menu the context menu to populate 14307 */ onCreateContextMenu(ContextMenu menu)14308 protected void onCreateContextMenu(ContextMenu menu) { 14309 } 14310 14311 /** 14312 * Implement this method to handle trackball motion events. The 14313 * <em>relative</em> movement of the trackball since the last event 14314 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 14315 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 14316 * that a movement of 1 corresponds to the user pressing one DPAD key (so 14317 * they will often be fractional values, representing the more fine-grained 14318 * movement information available from a trackball). 14319 * 14320 * @param event The motion event. 14321 * @return True if the event was handled, false otherwise. 14322 */ onTrackballEvent(MotionEvent event)14323 public boolean onTrackballEvent(MotionEvent event) { 14324 return false; 14325 } 14326 14327 /** 14328 * Implement this method to handle generic motion events. 14329 * <p> 14330 * Generic motion events describe joystick movements, mouse hovers, track pad 14331 * touches, scroll wheel movements and other input events. The 14332 * {@link MotionEvent#getSource() source} of the motion event specifies 14333 * the class of input that was received. Implementations of this method 14334 * must examine the bits in the source before processing the event. 14335 * The following code example shows how this is done. 14336 * </p><p> 14337 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 14338 * are delivered to the view under the pointer. All other generic motion events are 14339 * delivered to the focused view. 14340 * </p> 14341 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 14342 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 14343 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 14344 * // process the joystick movement... 14345 * return true; 14346 * } 14347 * } 14348 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 14349 * switch (event.getAction()) { 14350 * case MotionEvent.ACTION_HOVER_MOVE: 14351 * // process the mouse hover movement... 14352 * return true; 14353 * case MotionEvent.ACTION_SCROLL: 14354 * // process the scroll wheel movement... 14355 * return true; 14356 * } 14357 * } 14358 * return super.onGenericMotionEvent(event); 14359 * }</pre> 14360 * 14361 * @param event The generic motion event being processed. 14362 * @return True if the event was handled, false otherwise. 14363 */ onGenericMotionEvent(MotionEvent event)14364 public boolean onGenericMotionEvent(MotionEvent event) { 14365 return false; 14366 } 14367 14368 /** 14369 * Dispatching hover events to {@link TouchDelegate} to improve accessibility. 14370 * <p> 14371 * This method is dispatching hover events to the delegate target to support explore by touch. 14372 * Similar to {@link ViewGroup#dispatchTouchEvent}, this method send proper hover events to 14373 * the delegate target according to the pointer and the touch area of the delegate while touch 14374 * exploration enabled. 14375 * </p> 14376 * 14377 * @param event The motion event dispatch to the delegate target. 14378 * @return True if the event was handled, false otherwise. 14379 * 14380 * @see #onHoverEvent 14381 */ dispatchTouchExplorationHoverEvent(MotionEvent event)14382 private boolean dispatchTouchExplorationHoverEvent(MotionEvent event) { 14383 final AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 14384 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 14385 return false; 14386 } 14387 14388 final boolean oldHoveringTouchDelegate = mHoveringTouchDelegate; 14389 final int action = event.getActionMasked(); 14390 boolean pointInDelegateRegion = false; 14391 boolean handled = false; 14392 14393 final AccessibilityNodeInfo.TouchDelegateInfo info = mTouchDelegate.getTouchDelegateInfo(); 14394 for (int i = 0; i < info.getRegionCount(); i++) { 14395 Region r = info.getRegionAt(i); 14396 if (r.contains((int) event.getX(), (int) event.getY())) { 14397 pointInDelegateRegion = true; 14398 } 14399 } 14400 14401 // Explore by touch should dispatch events to children under the pointer first if any 14402 // before dispatching to TouchDelegate. For non-hoverable views that do not consume 14403 // hover events but receive accessibility focus, it should also not delegate to these 14404 // views when hovered. 14405 if (!oldHoveringTouchDelegate) { 14406 if ((action == MotionEvent.ACTION_HOVER_ENTER 14407 || action == MotionEvent.ACTION_HOVER_MOVE) 14408 && !pointInHoveredChild(event) 14409 && pointInDelegateRegion) { 14410 mHoveringTouchDelegate = true; 14411 } 14412 } else { 14413 if (action == MotionEvent.ACTION_HOVER_EXIT 14414 || (action == MotionEvent.ACTION_HOVER_MOVE 14415 && (pointInHoveredChild(event) || !pointInDelegateRegion))) { 14416 mHoveringTouchDelegate = false; 14417 } 14418 } 14419 switch (action) { 14420 case MotionEvent.ACTION_HOVER_MOVE: 14421 if (oldHoveringTouchDelegate && mHoveringTouchDelegate) { 14422 // Inside bounds, dispatch as is. 14423 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 14424 } else if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 14425 // Moving inbound, synthesize hover enter. 14426 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 14427 ? event : MotionEvent.obtainNoHistory(event); 14428 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER); 14429 handled = mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 14430 eventNoHistory.setAction(action); 14431 handled |= mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 14432 } else if (oldHoveringTouchDelegate && !mHoveringTouchDelegate) { 14433 // Moving outbound, synthesize hover exit. 14434 final boolean hoverExitPending = event.isHoverExitPending(); 14435 event.setHoverExitPending(true); 14436 mTouchDelegate.onTouchExplorationHoverEvent(event); 14437 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 14438 ? event : MotionEvent.obtainNoHistory(event); 14439 eventNoHistory.setHoverExitPending(hoverExitPending); 14440 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); 14441 mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 14442 } // else: outside bounds, do nothing. 14443 break; 14444 case MotionEvent.ACTION_HOVER_ENTER: 14445 if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 14446 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 14447 } 14448 break; 14449 case MotionEvent.ACTION_HOVER_EXIT: 14450 if (oldHoveringTouchDelegate) { 14451 mTouchDelegate.onTouchExplorationHoverEvent(event); 14452 } 14453 break; 14454 } 14455 return handled; 14456 } 14457 14458 /** 14459 * Implement this method to handle hover events. 14460 * <p> 14461 * This method is called whenever a pointer is hovering into, over, or out of the 14462 * bounds of a view and the view is not currently being touched. 14463 * Hover events are represented as pointer events with action 14464 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 14465 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 14466 * </p> 14467 * <ul> 14468 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 14469 * when the pointer enters the bounds of the view.</li> 14470 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 14471 * when the pointer has already entered the bounds of the view and has moved.</li> 14472 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 14473 * when the pointer has exited the bounds of the view or when the pointer is 14474 * about to go down due to a button click, tap, or similar user action that 14475 * causes the view to be touched.</li> 14476 * </ul> 14477 * <p> 14478 * The view should implement this method to return true to indicate that it is 14479 * handling the hover event, such as by changing its drawable state. 14480 * </p><p> 14481 * The default implementation calls {@link #setHovered} to update the hovered state 14482 * of the view when a hover enter or hover exit event is received, if the view 14483 * is enabled and is clickable. The default implementation also sends hover 14484 * accessibility events. 14485 * </p> 14486 * 14487 * @param event The motion event that describes the hover. 14488 * @return True if the view handled the hover event. 14489 * 14490 * @see #isHovered 14491 * @see #setHovered 14492 * @see #onHoverChanged 14493 */ onHoverEvent(MotionEvent event)14494 public boolean onHoverEvent(MotionEvent event) { 14495 if (mTouchDelegate != null && dispatchTouchExplorationHoverEvent(event)) { 14496 return true; 14497 } 14498 14499 // The root view may receive hover (or touch) events that are outside the bounds of 14500 // the window. This code ensures that we only send accessibility events for 14501 // hovers that are actually within the bounds of the root view. 14502 final int action = event.getActionMasked(); 14503 if (!mSendingHoverAccessibilityEvents) { 14504 if ((action == MotionEvent.ACTION_HOVER_ENTER 14505 || action == MotionEvent.ACTION_HOVER_MOVE) 14506 && !hasHoveredChild() 14507 && pointInView(event.getX(), event.getY())) { 14508 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 14509 mSendingHoverAccessibilityEvents = true; 14510 } 14511 } else { 14512 if (action == MotionEvent.ACTION_HOVER_EXIT 14513 || (action == MotionEvent.ACTION_HOVER_MOVE 14514 && !pointInView(event.getX(), event.getY()))) { 14515 mSendingHoverAccessibilityEvents = false; 14516 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 14517 } 14518 } 14519 14520 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 14521 && event.isFromSource(InputDevice.SOURCE_MOUSE) 14522 && isOnScrollbar(event.getX(), event.getY())) { 14523 awakenScrollBars(); 14524 } 14525 14526 // If we consider ourself hoverable, or if we we're already hovered, 14527 // handle changing state in response to ENTER and EXIT events. 14528 if (isHoverable() || isHovered()) { 14529 switch (action) { 14530 case MotionEvent.ACTION_HOVER_ENTER: 14531 setHovered(true); 14532 break; 14533 case MotionEvent.ACTION_HOVER_EXIT: 14534 setHovered(false); 14535 break; 14536 } 14537 14538 // Dispatch the event to onGenericMotionEvent before returning true. 14539 // This is to provide compatibility with existing applications that 14540 // handled HOVER_MOVE events in onGenericMotionEvent and that would 14541 // break because of the new default handling for hoverable views 14542 // in onHoverEvent. 14543 // Note that onGenericMotionEvent will be called by default when 14544 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 14545 dispatchGenericMotionEventInternal(event); 14546 // The event was already handled by calling setHovered(), so always 14547 // return true. 14548 return true; 14549 } 14550 14551 return false; 14552 } 14553 14554 /** 14555 * Returns true if the view should handle {@link #onHoverEvent} 14556 * by calling {@link #setHovered} to change its hovered state. 14557 * 14558 * @return True if the view is hoverable. 14559 */ isHoverable()14560 private boolean isHoverable() { 14561 final int viewFlags = mViewFlags; 14562 if ((viewFlags & ENABLED_MASK) == DISABLED) { 14563 return false; 14564 } 14565 14566 return (viewFlags & CLICKABLE) == CLICKABLE 14567 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 14568 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 14569 } 14570 14571 /** 14572 * Returns true if the view is currently hovered. 14573 * 14574 * @return True if the view is currently hovered. 14575 * 14576 * @see #setHovered 14577 * @see #onHoverChanged 14578 */ 14579 @ViewDebug.ExportedProperty isHovered()14580 public boolean isHovered() { 14581 return (mPrivateFlags & PFLAG_HOVERED) != 0; 14582 } 14583 14584 /** 14585 * Sets whether the view is currently hovered. 14586 * <p> 14587 * Calling this method also changes the drawable state of the view. This 14588 * enables the view to react to hover by using different drawable resources 14589 * to change its appearance. 14590 * </p><p> 14591 * The {@link #onHoverChanged} method is called when the hovered state changes. 14592 * </p> 14593 * 14594 * @param hovered True if the view is hovered. 14595 * 14596 * @see #isHovered 14597 * @see #onHoverChanged 14598 */ setHovered(boolean hovered)14599 public void setHovered(boolean hovered) { 14600 if (hovered) { 14601 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 14602 mPrivateFlags |= PFLAG_HOVERED; 14603 refreshDrawableState(); 14604 onHoverChanged(true); 14605 } 14606 } else { 14607 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 14608 mPrivateFlags &= ~PFLAG_HOVERED; 14609 refreshDrawableState(); 14610 onHoverChanged(false); 14611 } 14612 } 14613 } 14614 14615 /** 14616 * Implement this method to handle hover state changes. 14617 * <p> 14618 * This method is called whenever the hover state changes as a result of a 14619 * call to {@link #setHovered}. 14620 * </p> 14621 * 14622 * @param hovered The current hover state, as returned by {@link #isHovered}. 14623 * 14624 * @see #isHovered 14625 * @see #setHovered 14626 */ onHoverChanged(boolean hovered)14627 public void onHoverChanged(boolean hovered) { 14628 } 14629 14630 /** 14631 * Handles scroll bar dragging by mouse input. 14632 * 14633 * @hide 14634 * @param event The motion event. 14635 * 14636 * @return true if the event was handled as a scroll bar dragging, false otherwise. 14637 */ handleScrollBarDragging(MotionEvent event)14638 protected boolean handleScrollBarDragging(MotionEvent event) { 14639 if (mScrollCache == null) { 14640 return false; 14641 } 14642 final float x = event.getX(); 14643 final float y = event.getY(); 14644 final int action = event.getAction(); 14645 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 14646 && action != MotionEvent.ACTION_DOWN) 14647 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 14648 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 14649 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 14650 return false; 14651 } 14652 14653 switch (action) { 14654 case MotionEvent.ACTION_MOVE: 14655 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 14656 return false; 14657 } 14658 if (mScrollCache.mScrollBarDraggingState 14659 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 14660 final Rect bounds = mScrollCache.mScrollBarBounds; 14661 getVerticalScrollBarBounds(bounds, null); 14662 final int range = computeVerticalScrollRange(); 14663 final int offset = computeVerticalScrollOffset(); 14664 final int extent = computeVerticalScrollExtent(); 14665 14666 final int thumbLength = ScrollBarUtils.getThumbLength( 14667 bounds.height(), bounds.width(), extent, range); 14668 final int thumbOffset = ScrollBarUtils.getThumbOffset( 14669 bounds.height(), thumbLength, extent, range, offset); 14670 14671 final float diff = y - mScrollCache.mScrollBarDraggingPos; 14672 final float maxThumbOffset = bounds.height() - thumbLength; 14673 final float newThumbOffset = 14674 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 14675 final int height = getHeight(); 14676 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 14677 && height > 0 && extent > 0) { 14678 final int newY = Math.round((range - extent) 14679 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 14680 if (newY != getScrollY()) { 14681 mScrollCache.mScrollBarDraggingPos = y; 14682 setScrollY(newY); 14683 } 14684 } 14685 return true; 14686 } 14687 if (mScrollCache.mScrollBarDraggingState 14688 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 14689 final Rect bounds = mScrollCache.mScrollBarBounds; 14690 getHorizontalScrollBarBounds(bounds, null); 14691 final int range = computeHorizontalScrollRange(); 14692 final int offset = computeHorizontalScrollOffset(); 14693 final int extent = computeHorizontalScrollExtent(); 14694 14695 final int thumbLength = ScrollBarUtils.getThumbLength( 14696 bounds.width(), bounds.height(), extent, range); 14697 final int thumbOffset = ScrollBarUtils.getThumbOffset( 14698 bounds.width(), thumbLength, extent, range, offset); 14699 14700 final float diff = x - mScrollCache.mScrollBarDraggingPos; 14701 final float maxThumbOffset = bounds.width() - thumbLength; 14702 final float newThumbOffset = 14703 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 14704 final int width = getWidth(); 14705 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 14706 && width > 0 && extent > 0) { 14707 final int newX = Math.round((range - extent) 14708 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 14709 if (newX != getScrollX()) { 14710 mScrollCache.mScrollBarDraggingPos = x; 14711 setScrollX(newX); 14712 } 14713 } 14714 return true; 14715 } 14716 case MotionEvent.ACTION_DOWN: 14717 if (mScrollCache.state == ScrollabilityCache.OFF) { 14718 return false; 14719 } 14720 if (isOnVerticalScrollbarThumb(x, y)) { 14721 mScrollCache.mScrollBarDraggingState = 14722 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 14723 mScrollCache.mScrollBarDraggingPos = y; 14724 return true; 14725 } 14726 if (isOnHorizontalScrollbarThumb(x, y)) { 14727 mScrollCache.mScrollBarDraggingState = 14728 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 14729 mScrollCache.mScrollBarDraggingPos = x; 14730 return true; 14731 } 14732 } 14733 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 14734 return false; 14735 } 14736 14737 /** 14738 * Implement this method to handle touch screen motion events. 14739 * <p> 14740 * If this method is used to detect click actions, it is recommended that 14741 * the actions be performed by implementing and calling 14742 * {@link #performClick()}. This will ensure consistent system behavior, 14743 * including: 14744 * <ul> 14745 * <li>obeying click sound preferences 14746 * <li>dispatching OnClickListener calls 14747 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 14748 * accessibility features are enabled 14749 * </ul> 14750 * 14751 * @param event The motion event. 14752 * @return True if the event was handled, false otherwise. 14753 */ onTouchEvent(MotionEvent event)14754 public boolean onTouchEvent(MotionEvent event) { 14755 final float x = event.getX(); 14756 final float y = event.getY(); 14757 final int viewFlags = mViewFlags; 14758 final int action = event.getAction(); 14759 14760 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 14761 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 14762 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 14763 14764 if ((viewFlags & ENABLED_MASK) == DISABLED) { 14765 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 14766 setPressed(false); 14767 } 14768 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 14769 // A disabled view that is clickable still consumes the touch 14770 // events, it just doesn't respond to them. 14771 return clickable; 14772 } 14773 if (mTouchDelegate != null) { 14774 if (mTouchDelegate.onTouchEvent(event)) { 14775 return true; 14776 } 14777 } 14778 14779 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 14780 switch (action) { 14781 case MotionEvent.ACTION_UP: 14782 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 14783 if ((viewFlags & TOOLTIP) == TOOLTIP) { 14784 handleTooltipUp(); 14785 } 14786 if (!clickable) { 14787 removeTapCallback(); 14788 removeLongPressCallback(); 14789 mInContextButtonPress = false; 14790 mHasPerformedLongPress = false; 14791 mIgnoreNextUpEvent = false; 14792 break; 14793 } 14794 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 14795 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 14796 // take focus if we don't have it already and we should in 14797 // touch mode. 14798 boolean focusTaken = false; 14799 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 14800 focusTaken = requestFocus(); 14801 } 14802 14803 if (prepressed) { 14804 // The button is being released before we actually 14805 // showed it as pressed. Make it show the pressed 14806 // state now (before scheduling the click) to ensure 14807 // the user sees it. 14808 setPressed(true, x, y); 14809 } 14810 14811 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 14812 // This is a tap, so remove the longpress check 14813 removeLongPressCallback(); 14814 14815 // Only perform take click actions if we were in the pressed state 14816 if (!focusTaken) { 14817 // Use a Runnable and post this rather than calling 14818 // performClick directly. This lets other visual state 14819 // of the view update before click actions start. 14820 if (mPerformClick == null) { 14821 mPerformClick = new PerformClick(); 14822 } 14823 if (!post(mPerformClick)) { 14824 performClickInternal(); 14825 } 14826 } 14827 } 14828 14829 if (mUnsetPressedState == null) { 14830 mUnsetPressedState = new UnsetPressedState(); 14831 } 14832 14833 if (prepressed) { 14834 postDelayed(mUnsetPressedState, 14835 ViewConfiguration.getPressedStateDuration()); 14836 } else if (!post(mUnsetPressedState)) { 14837 // If the post failed, unpress right now 14838 mUnsetPressedState.run(); 14839 } 14840 14841 removeTapCallback(); 14842 } 14843 mIgnoreNextUpEvent = false; 14844 break; 14845 14846 case MotionEvent.ACTION_DOWN: 14847 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 14848 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 14849 } 14850 mHasPerformedLongPress = false; 14851 14852 if (!clickable) { 14853 checkForLongClick( 14854 ViewConfiguration.getLongPressTimeout(), 14855 x, 14856 y, 14857 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 14858 break; 14859 } 14860 14861 if (performButtonActionOnTouchDown(event)) { 14862 break; 14863 } 14864 14865 // Walk up the hierarchy to determine if we're inside a scrolling container. 14866 boolean isInScrollingContainer = isInScrollingContainer(); 14867 14868 // For views inside a scrolling container, delay the pressed feedback for 14869 // a short period in case this is a scroll. 14870 if (isInScrollingContainer) { 14871 mPrivateFlags |= PFLAG_PREPRESSED; 14872 if (mPendingCheckForTap == null) { 14873 mPendingCheckForTap = new CheckForTap(); 14874 } 14875 mPendingCheckForTap.x = event.getX(); 14876 mPendingCheckForTap.y = event.getY(); 14877 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 14878 } else { 14879 // Not inside a scrolling container, so show the feedback right away 14880 setPressed(true, x, y); 14881 checkForLongClick( 14882 ViewConfiguration.getLongPressTimeout(), 14883 x, 14884 y, 14885 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 14886 } 14887 break; 14888 14889 case MotionEvent.ACTION_CANCEL: 14890 if (clickable) { 14891 setPressed(false); 14892 } 14893 removeTapCallback(); 14894 removeLongPressCallback(); 14895 mInContextButtonPress = false; 14896 mHasPerformedLongPress = false; 14897 mIgnoreNextUpEvent = false; 14898 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 14899 break; 14900 14901 case MotionEvent.ACTION_MOVE: 14902 if (clickable) { 14903 drawableHotspotChanged(x, y); 14904 } 14905 14906 final int motionClassification = event.getClassification(); 14907 final boolean ambiguousGesture = 14908 motionClassification == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE; 14909 int touchSlop = mTouchSlop; 14910 if (ambiguousGesture && hasPendingLongPressCallback()) { 14911 final float ambiguousMultiplier = 14912 ViewConfiguration.getAmbiguousGestureMultiplier(); 14913 if (!pointInView(x, y, touchSlop)) { 14914 // The default action here is to cancel long press. But instead, we 14915 // just extend the timeout here, in case the classification 14916 // stays ambiguous. 14917 removeLongPressCallback(); 14918 long delay = (long) (ViewConfiguration.getLongPressTimeout() 14919 * ambiguousMultiplier); 14920 // Subtract the time already spent 14921 delay -= event.getEventTime() - event.getDownTime(); 14922 checkForLongClick( 14923 delay, 14924 x, 14925 y, 14926 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 14927 } 14928 touchSlop *= ambiguousMultiplier; 14929 } 14930 14931 // Be lenient about moving outside of buttons 14932 if (!pointInView(x, y, touchSlop)) { 14933 // Outside button 14934 // Remove any future long press/tap checks 14935 removeTapCallback(); 14936 removeLongPressCallback(); 14937 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 14938 setPressed(false); 14939 } 14940 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 14941 } 14942 14943 final boolean deepPress = 14944 motionClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS; 14945 if (deepPress && hasPendingLongPressCallback()) { 14946 // process the long click action immediately 14947 removeLongPressCallback(); 14948 checkForLongClick( 14949 0 /* send immediately */, 14950 x, 14951 y, 14952 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS); 14953 } 14954 14955 break; 14956 } 14957 14958 return true; 14959 } 14960 14961 return false; 14962 } 14963 14964 /** 14965 * @hide 14966 */ 14967 @UnsupportedAppUsage isInScrollingContainer()14968 public boolean isInScrollingContainer() { 14969 ViewParent p = getParent(); 14970 while (p != null && p instanceof ViewGroup) { 14971 if (((ViewGroup) p).shouldDelayChildPressedState()) { 14972 return true; 14973 } 14974 p = p.getParent(); 14975 } 14976 return false; 14977 } 14978 14979 /** 14980 * Remove the longpress detection timer. 14981 */ removeLongPressCallback()14982 private void removeLongPressCallback() { 14983 if (mPendingCheckForLongPress != null) { 14984 removeCallbacks(mPendingCheckForLongPress); 14985 } 14986 } 14987 14988 /** 14989 * Return true if the long press callback is scheduled to run sometime in the future. 14990 * Return false if there is no scheduled long press callback at the moment. 14991 */ hasPendingLongPressCallback()14992 private boolean hasPendingLongPressCallback() { 14993 if (mPendingCheckForLongPress == null) { 14994 return false; 14995 } 14996 final AttachInfo attachInfo = mAttachInfo; 14997 if (attachInfo == null) { 14998 return false; 14999 } 15000 return attachInfo.mHandler.hasCallbacks(mPendingCheckForLongPress); 15001 } 15002 15003 /** 15004 * Remove the pending click action 15005 */ 15006 @UnsupportedAppUsage removePerformClickCallback()15007 private void removePerformClickCallback() { 15008 if (mPerformClick != null) { 15009 removeCallbacks(mPerformClick); 15010 } 15011 } 15012 15013 /** 15014 * Remove the prepress detection timer. 15015 */ removeUnsetPressCallback()15016 private void removeUnsetPressCallback() { 15017 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 15018 setPressed(false); 15019 removeCallbacks(mUnsetPressedState); 15020 } 15021 } 15022 15023 /** 15024 * Remove the tap detection timer. 15025 */ removeTapCallback()15026 private void removeTapCallback() { 15027 if (mPendingCheckForTap != null) { 15028 mPrivateFlags &= ~PFLAG_PREPRESSED; 15029 removeCallbacks(mPendingCheckForTap); 15030 } 15031 } 15032 15033 /** 15034 * Cancels a pending long press. Your subclass can use this if you 15035 * want the context menu to come up if the user presses and holds 15036 * at the same place, but you don't want it to come up if they press 15037 * and then move around enough to cause scrolling. 15038 */ cancelLongPress()15039 public void cancelLongPress() { 15040 removeLongPressCallback(); 15041 15042 /* 15043 * The prepressed state handled by the tap callback is a display 15044 * construct, but the tap callback will post a long press callback 15045 * less its own timeout. Remove it here. 15046 */ 15047 removeTapCallback(); 15048 } 15049 15050 /** 15051 * Sets the TouchDelegate for this View. 15052 */ setTouchDelegate(TouchDelegate delegate)15053 public void setTouchDelegate(TouchDelegate delegate) { 15054 mTouchDelegate = delegate; 15055 } 15056 15057 /** 15058 * Gets the TouchDelegate for this View. 15059 */ getTouchDelegate()15060 public TouchDelegate getTouchDelegate() { 15061 return mTouchDelegate; 15062 } 15063 15064 /** 15065 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 15066 * 15067 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 15068 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 15069 * available. This method should only be called for touch events. 15070 * 15071 * <p class="note">This api is not intended for most applications. Buffered dispatch 15072 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 15073 * streams will not improve your input latency. Side effects include: increased latency, 15074 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 15075 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 15076 * you.</p> 15077 */ requestUnbufferedDispatch(MotionEvent event)15078 public final void requestUnbufferedDispatch(MotionEvent event) { 15079 final int action = event.getAction(); 15080 if (mAttachInfo == null 15081 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 15082 || !event.isTouchEvent()) { 15083 return; 15084 } 15085 mAttachInfo.mUnbufferedDispatchRequested = true; 15086 } 15087 hasSize()15088 private boolean hasSize() { 15089 return (mBottom > mTop) && (mRight > mLeft); 15090 } 15091 canTakeFocus()15092 private boolean canTakeFocus() { 15093 return ((mViewFlags & VISIBILITY_MASK) == VISIBLE) 15094 && ((mViewFlags & FOCUSABLE) == FOCUSABLE) 15095 && ((mViewFlags & ENABLED_MASK) == ENABLED) 15096 && (sCanFocusZeroSized || !isLayoutValid() || hasSize()); 15097 } 15098 15099 /** 15100 * Set flags controlling behavior of this view. 15101 * 15102 * @param flags Constant indicating the value which should be set 15103 * @param mask Constant indicating the bit range that should be changed 15104 */ 15105 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) setFlags(int flags, int mask)15106 void setFlags(int flags, int mask) { 15107 final boolean accessibilityEnabled = 15108 AccessibilityManager.getInstance(mContext).isEnabled(); 15109 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 15110 15111 int old = mViewFlags; 15112 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 15113 15114 int changed = mViewFlags ^ old; 15115 if (changed == 0) { 15116 return; 15117 } 15118 int privateFlags = mPrivateFlags; 15119 boolean shouldNotifyFocusableAvailable = false; 15120 15121 // If focusable is auto, update the FOCUSABLE bit. 15122 int focusableChangedByAuto = 0; 15123 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 15124 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 15125 // Heuristic only takes into account whether view is clickable. 15126 final int newFocus; 15127 if ((mViewFlags & CLICKABLE) != 0) { 15128 newFocus = FOCUSABLE; 15129 } else { 15130 newFocus = NOT_FOCUSABLE; 15131 } 15132 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 15133 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 15134 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 15135 } 15136 15137 /* Check if the FOCUSABLE bit has changed */ 15138 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 15139 if (((old & FOCUSABLE) == FOCUSABLE) 15140 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 15141 /* Give up focus if we are no longer focusable */ 15142 clearFocus(); 15143 if (mParent instanceof ViewGroup) { 15144 ((ViewGroup) mParent).clearFocusedInCluster(); 15145 } 15146 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 15147 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 15148 /* 15149 * Tell the view system that we are now available to take focus 15150 * if no one else already has it. 15151 */ 15152 if (mParent != null) { 15153 ViewRootImpl viewRootImpl = getViewRootImpl(); 15154 if (!sAutoFocusableOffUIThreadWontNotifyParents 15155 || focusableChangedByAuto == 0 15156 || viewRootImpl == null 15157 || viewRootImpl.mThread == Thread.currentThread()) { 15158 shouldNotifyFocusableAvailable = canTakeFocus(); 15159 } 15160 } 15161 } 15162 } 15163 15164 final int newVisibility = flags & VISIBILITY_MASK; 15165 if (newVisibility == VISIBLE) { 15166 if ((changed & VISIBILITY_MASK) != 0) { 15167 /* 15168 * If this view is becoming visible, invalidate it in case it changed while 15169 * it was not visible. Marking it drawn ensures that the invalidation will 15170 * go through. 15171 */ 15172 mPrivateFlags |= PFLAG_DRAWN; 15173 invalidate(true); 15174 15175 needGlobalAttributesUpdate(true); 15176 15177 // a view becoming visible is worth notifying the parent about in case nothing has 15178 // focus. Even if this specific view isn't focusable, it may contain something that 15179 // is, so let the root view try to give this focus if nothing else does. 15180 shouldNotifyFocusableAvailable = hasSize(); 15181 } 15182 } 15183 15184 if ((changed & ENABLED_MASK) != 0) { 15185 if ((mViewFlags & ENABLED_MASK) == ENABLED) { 15186 // a view becoming enabled should notify the parent as long as the view is also 15187 // visible and the parent wasn't already notified by becoming visible during this 15188 // setFlags invocation. 15189 shouldNotifyFocusableAvailable = canTakeFocus(); 15190 } else { 15191 if (isFocused()) clearFocus(); 15192 } 15193 } 15194 15195 if (shouldNotifyFocusableAvailable && mParent != null) { 15196 mParent.focusableViewAvailable(this); 15197 } 15198 15199 /* Check if the GONE bit has changed */ 15200 if ((changed & GONE) != 0) { 15201 needGlobalAttributesUpdate(false); 15202 requestLayout(); 15203 15204 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 15205 if (hasFocus()) { 15206 clearFocus(); 15207 if (mParent instanceof ViewGroup) { 15208 ((ViewGroup) mParent).clearFocusedInCluster(); 15209 } 15210 } 15211 clearAccessibilityFocus(); 15212 destroyDrawingCache(); 15213 if (mParent instanceof View) { 15214 // GONE views noop invalidation, so invalidate the parent 15215 ((View) mParent).invalidate(true); 15216 } 15217 // Mark the view drawn to ensure that it gets invalidated properly the next 15218 // time it is visible and gets invalidated 15219 mPrivateFlags |= PFLAG_DRAWN; 15220 } 15221 if (mAttachInfo != null) { 15222 mAttachInfo.mViewVisibilityChanged = true; 15223 } 15224 } 15225 15226 /* Check if the VISIBLE bit has changed */ 15227 if ((changed & INVISIBLE) != 0) { 15228 needGlobalAttributesUpdate(false); 15229 /* 15230 * If this view is becoming invisible, set the DRAWN flag so that 15231 * the next invalidate() will not be skipped. 15232 */ 15233 mPrivateFlags |= PFLAG_DRAWN; 15234 15235 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 15236 // root view becoming invisible shouldn't clear focus and accessibility focus 15237 if (getRootView() != this) { 15238 if (hasFocus()) { 15239 clearFocus(); 15240 if (mParent instanceof ViewGroup) { 15241 ((ViewGroup) mParent).clearFocusedInCluster(); 15242 } 15243 } 15244 clearAccessibilityFocus(); 15245 } 15246 } 15247 if (mAttachInfo != null) { 15248 mAttachInfo.mViewVisibilityChanged = true; 15249 } 15250 } 15251 15252 if ((changed & VISIBILITY_MASK) != 0) { 15253 // If the view is invisible, cleanup its display list to free up resources 15254 if (newVisibility != VISIBLE && mAttachInfo != null) { 15255 cleanupDraw(); 15256 } 15257 15258 if (mParent instanceof ViewGroup) { 15259 ViewGroup parent = (ViewGroup) mParent; 15260 parent.onChildVisibilityChanged(this, (changed & VISIBILITY_MASK), 15261 newVisibility); 15262 parent.invalidate(true); 15263 } else if (mParent != null) { 15264 mParent.invalidateChild(this, null); 15265 } 15266 15267 if (mAttachInfo != null) { 15268 dispatchVisibilityChanged(this, newVisibility); 15269 15270 // Aggregated visibility changes are dispatched to attached views 15271 // in visible windows where the parent is currently shown/drawn 15272 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 15273 // discounting clipping or overlapping. This makes it a good place 15274 // to change animation states. 15275 if (mParent != null && getWindowVisibility() == VISIBLE && 15276 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 15277 dispatchVisibilityAggregated(newVisibility == VISIBLE); 15278 } 15279 notifySubtreeAccessibilityStateChangedIfNeeded(); 15280 } 15281 } 15282 15283 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 15284 destroyDrawingCache(); 15285 } 15286 15287 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 15288 destroyDrawingCache(); 15289 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 15290 invalidateParentCaches(); 15291 } 15292 15293 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 15294 destroyDrawingCache(); 15295 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 15296 } 15297 15298 if ((changed & DRAW_MASK) != 0) { 15299 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 15300 if (mBackground != null 15301 || mDefaultFocusHighlight != null 15302 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 15303 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 15304 } else { 15305 mPrivateFlags |= PFLAG_SKIP_DRAW; 15306 } 15307 } else { 15308 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 15309 } 15310 requestLayout(); 15311 invalidate(true); 15312 } 15313 15314 if ((changed & KEEP_SCREEN_ON) != 0) { 15315 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 15316 mParent.recomputeViewAttributes(this); 15317 } 15318 } 15319 15320 if (accessibilityEnabled) { 15321 // If we're an accessibility pane and the visibility changed, we already have sent 15322 // a state change, so we really don't need to report other changes. 15323 if (isAccessibilityPane()) { 15324 changed &= ~VISIBILITY_MASK; 15325 } 15326 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 15327 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 15328 || (changed & CONTEXT_CLICKABLE) != 0) { 15329 if (oldIncludeForAccessibility != includeForAccessibility()) { 15330 notifySubtreeAccessibilityStateChangedIfNeeded(); 15331 } else { 15332 notifyViewAccessibilityStateChangedIfNeeded( 15333 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 15334 } 15335 } else if ((changed & ENABLED_MASK) != 0) { 15336 notifyViewAccessibilityStateChangedIfNeeded( 15337 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 15338 } 15339 } 15340 } 15341 15342 /** 15343 * Change the view's z order in the tree, so it's on top of other sibling 15344 * views. This ordering change may affect layout, if the parent container 15345 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 15346 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 15347 * method should be followed by calls to {@link #requestLayout()} and 15348 * {@link View#invalidate()} on the view's parent to force the parent to redraw 15349 * with the new child ordering. 15350 * 15351 * @see ViewGroup#bringChildToFront(View) 15352 */ bringToFront()15353 public void bringToFront() { 15354 if (mParent != null) { 15355 mParent.bringChildToFront(this); 15356 } 15357 } 15358 15359 /** 15360 * This is called in response to an internal scroll in this view (i.e., the 15361 * view scrolled its own contents). This is typically as a result of 15362 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 15363 * called. 15364 * 15365 * @param l Current horizontal scroll origin. 15366 * @param t Current vertical scroll origin. 15367 * @param oldl Previous horizontal scroll origin. 15368 * @param oldt Previous vertical scroll origin. 15369 */ onScrollChanged(int l, int t, int oldl, int oldt)15370 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 15371 notifySubtreeAccessibilityStateChangedIfNeeded(); 15372 15373 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 15374 postSendViewScrolledAccessibilityEventCallback(l - oldl, t - oldt); 15375 } 15376 15377 mBackgroundSizeChanged = true; 15378 mDefaultFocusHighlightSizeChanged = true; 15379 if (mForegroundInfo != null) { 15380 mForegroundInfo.mBoundsChanged = true; 15381 } 15382 15383 final AttachInfo ai = mAttachInfo; 15384 if (ai != null) { 15385 ai.mViewScrollChanged = true; 15386 } 15387 15388 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 15389 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 15390 } 15391 } 15392 15393 /** 15394 * Interface definition for a callback to be invoked when the scroll 15395 * X or Y positions of a view change. 15396 * <p> 15397 * <b>Note:</b> Some views handle scrolling independently from View and may 15398 * have their own separate listeners for scroll-type events. For example, 15399 * {@link android.widget.ListView ListView} allows clients to register an 15400 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 15401 * to listen for changes in list scroll position. 15402 * 15403 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 15404 */ 15405 public interface OnScrollChangeListener { 15406 /** 15407 * Called when the scroll position of a view changes. 15408 * 15409 * @param v The view whose scroll position has changed. 15410 * @param scrollX Current horizontal scroll origin. 15411 * @param scrollY Current vertical scroll origin. 15412 * @param oldScrollX Previous horizontal scroll origin. 15413 * @param oldScrollY Previous vertical scroll origin. 15414 */ onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY)15415 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 15416 } 15417 15418 /** 15419 * Interface definition for a callback to be invoked when the layout bounds of a view 15420 * changes due to layout processing. 15421 */ 15422 public interface OnLayoutChangeListener { 15423 /** 15424 * Called when the layout bounds of a view changes due to layout processing. 15425 * 15426 * @param v The view whose bounds have changed. 15427 * @param left The new value of the view's left property. 15428 * @param top The new value of the view's top property. 15429 * @param right The new value of the view's right property. 15430 * @param bottom The new value of the view's bottom property. 15431 * @param oldLeft The previous value of the view's left property. 15432 * @param oldTop The previous value of the view's top property. 15433 * @param oldRight The previous value of the view's right property. 15434 * @param oldBottom The previous value of the view's bottom property. 15435 */ onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)15436 void onLayoutChange(View v, int left, int top, int right, int bottom, 15437 int oldLeft, int oldTop, int oldRight, int oldBottom); 15438 } 15439 15440 /** 15441 * This is called during layout when the size of this view has changed. If 15442 * you were just added to the view hierarchy, you're called with the old 15443 * values of 0. 15444 * 15445 * @param w Current width of this view. 15446 * @param h Current height of this view. 15447 * @param oldw Old width of this view. 15448 * @param oldh Old height of this view. 15449 */ onSizeChanged(int w, int h, int oldw, int oldh)15450 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 15451 } 15452 15453 /** 15454 * Called by draw to draw the child views. This may be overridden 15455 * by derived classes to gain control just before its children are drawn 15456 * (but after its own view has been drawn). 15457 * @param canvas the canvas on which to draw the view 15458 */ dispatchDraw(Canvas canvas)15459 protected void dispatchDraw(Canvas canvas) { 15460 15461 } 15462 15463 /** 15464 * Gets the parent of this view. Note that the parent is a 15465 * ViewParent and not necessarily a View. 15466 * 15467 * @return Parent of this view. 15468 */ getParent()15469 public final ViewParent getParent() { 15470 return mParent; 15471 } 15472 15473 /** 15474 * Set the horizontal scrolled position of your view. This will cause a call to 15475 * {@link #onScrollChanged(int, int, int, int)} and the view will be 15476 * invalidated. 15477 * @param value the x position to scroll to 15478 */ setScrollX(int value)15479 public void setScrollX(int value) { 15480 scrollTo(value, mScrollY); 15481 } 15482 15483 /** 15484 * Set the vertical scrolled position of your view. This will cause a call to 15485 * {@link #onScrollChanged(int, int, int, int)} and the view will be 15486 * invalidated. 15487 * @param value the y position to scroll to 15488 */ setScrollY(int value)15489 public void setScrollY(int value) { 15490 scrollTo(mScrollX, value); 15491 } 15492 15493 /** 15494 * Return the scrolled left position of this view. This is the left edge of 15495 * the displayed part of your view. You do not need to draw any pixels 15496 * farther left, since those are outside of the frame of your view on 15497 * screen. 15498 * 15499 * @return The left edge of the displayed part of your view, in pixels. 15500 */ 15501 @InspectableProperty getScrollX()15502 public final int getScrollX() { 15503 return mScrollX; 15504 } 15505 15506 /** 15507 * Return the scrolled top position of this view. This is the top edge of 15508 * the displayed part of your view. You do not need to draw any pixels above 15509 * it, since those are outside of the frame of your view on screen. 15510 * 15511 * @return The top edge of the displayed part of your view, in pixels. 15512 */ 15513 @InspectableProperty getScrollY()15514 public final int getScrollY() { 15515 return mScrollY; 15516 } 15517 15518 /** 15519 * Return the width of your view. 15520 * 15521 * @return The width of your view, in pixels. 15522 */ 15523 @ViewDebug.ExportedProperty(category = "layout") getWidth()15524 public final int getWidth() { 15525 return mRight - mLeft; 15526 } 15527 15528 /** 15529 * Return the height of your view. 15530 * 15531 * @return The height of your view, in pixels. 15532 */ 15533 @ViewDebug.ExportedProperty(category = "layout") getHeight()15534 public final int getHeight() { 15535 return mBottom - mTop; 15536 } 15537 15538 /** 15539 * Return the visible drawing bounds of your view. Fills in the output 15540 * rectangle with the values from getScrollX(), getScrollY(), 15541 * getWidth(), and getHeight(). These bounds do not account for any 15542 * transformation properties currently set on the view, such as 15543 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 15544 * 15545 * @param outRect The (scrolled) drawing bounds of the view. 15546 */ getDrawingRect(Rect outRect)15547 public void getDrawingRect(Rect outRect) { 15548 outRect.left = mScrollX; 15549 outRect.top = mScrollY; 15550 outRect.right = mScrollX + (mRight - mLeft); 15551 outRect.bottom = mScrollY + (mBottom - mTop); 15552 } 15553 15554 /** 15555 * Like {@link #getMeasuredWidthAndState()}, but only returns the 15556 * raw width component (that is the result is masked by 15557 * {@link #MEASURED_SIZE_MASK}). 15558 * 15559 * @return The raw measured width of this view. 15560 */ getMeasuredWidth()15561 public final int getMeasuredWidth() { 15562 return mMeasuredWidth & MEASURED_SIZE_MASK; 15563 } 15564 15565 /** 15566 * Return the full width measurement information for this view as computed 15567 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 15568 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 15569 * This should be used during measurement and layout calculations only. Use 15570 * {@link #getWidth()} to see how wide a view is after layout. 15571 * 15572 * @return The measured width of this view as a bit mask. 15573 */ 15574 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 15575 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 15576 name = "MEASURED_STATE_TOO_SMALL"), 15577 }) getMeasuredWidthAndState()15578 public final int getMeasuredWidthAndState() { 15579 return mMeasuredWidth; 15580 } 15581 15582 /** 15583 * Like {@link #getMeasuredHeightAndState()}, but only returns the 15584 * raw height component (that is the result is masked by 15585 * {@link #MEASURED_SIZE_MASK}). 15586 * 15587 * @return The raw measured height of this view. 15588 */ getMeasuredHeight()15589 public final int getMeasuredHeight() { 15590 return mMeasuredHeight & MEASURED_SIZE_MASK; 15591 } 15592 15593 /** 15594 * Return the full height measurement information for this view as computed 15595 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 15596 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 15597 * This should be used during measurement and layout calculations only. Use 15598 * {@link #getHeight()} to see how wide a view is after layout. 15599 * 15600 * @return The measured height of this view as a bit mask. 15601 */ 15602 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 15603 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 15604 name = "MEASURED_STATE_TOO_SMALL"), 15605 }) getMeasuredHeightAndState()15606 public final int getMeasuredHeightAndState() { 15607 return mMeasuredHeight; 15608 } 15609 15610 /** 15611 * Return only the state bits of {@link #getMeasuredWidthAndState()} 15612 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 15613 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 15614 * and the height component is at the shifted bits 15615 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 15616 */ getMeasuredState()15617 public final int getMeasuredState() { 15618 return (mMeasuredWidth&MEASURED_STATE_MASK) 15619 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 15620 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 15621 } 15622 15623 /** 15624 * The transform matrix of this view, which is calculated based on the current 15625 * rotation, scale, and pivot properties. 15626 * 15627 * @see #getRotation() 15628 * @see #getScaleX() 15629 * @see #getScaleY() 15630 * @see #getPivotX() 15631 * @see #getPivotY() 15632 * @return The current transform matrix for the view 15633 */ getMatrix()15634 public Matrix getMatrix() { 15635 ensureTransformationInfo(); 15636 final Matrix matrix = mTransformationInfo.mMatrix; 15637 mRenderNode.getMatrix(matrix); 15638 return matrix; 15639 } 15640 15641 /** 15642 * Returns true if the transform matrix is the identity matrix. 15643 * Recomputes the matrix if necessary. 15644 * 15645 * @return True if the transform matrix is the identity matrix, false otherwise. 15646 * @hide 15647 */ 15648 @UnsupportedAppUsage hasIdentityMatrix()15649 public final boolean hasIdentityMatrix() { 15650 return mRenderNode.hasIdentityMatrix(); 15651 } 15652 15653 @UnsupportedAppUsage ensureTransformationInfo()15654 void ensureTransformationInfo() { 15655 if (mTransformationInfo == null) { 15656 mTransformationInfo = new TransformationInfo(); 15657 } 15658 } 15659 15660 /** 15661 * Utility method to retrieve the inverse of the current mMatrix property. 15662 * We cache the matrix to avoid recalculating it when transform properties 15663 * have not changed. 15664 * 15665 * @return The inverse of the current matrix of this view. 15666 * @hide 15667 */ 15668 @UnsupportedAppUsage getInverseMatrix()15669 public final Matrix getInverseMatrix() { 15670 ensureTransformationInfo(); 15671 if (mTransformationInfo.mInverseMatrix == null) { 15672 mTransformationInfo.mInverseMatrix = new Matrix(); 15673 } 15674 final Matrix matrix = mTransformationInfo.mInverseMatrix; 15675 mRenderNode.getInverseMatrix(matrix); 15676 return matrix; 15677 } 15678 15679 /** 15680 * Gets the distance along the Z axis from the camera to this view. 15681 * 15682 * @see #setCameraDistance(float) 15683 * 15684 * @return The distance along the Z axis. 15685 */ getCameraDistance()15686 public float getCameraDistance() { 15687 final float dpi = mResources.getDisplayMetrics().densityDpi; 15688 return mRenderNode.getCameraDistance() * dpi; 15689 } 15690 15691 /** 15692 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 15693 * views are drawn) from the camera to this view. The camera's distance 15694 * affects 3D transformations, for instance rotations around the X and Y 15695 * axis. If the rotationX or rotationY properties are changed and this view is 15696 * large (more than half the size of the screen), it is recommended to always 15697 * use a camera distance that's greater than the height (X axis rotation) or 15698 * the width (Y axis rotation) of this view.</p> 15699 * 15700 * <p>The distance of the camera from the view plane can have an affect on the 15701 * perspective distortion of the view when it is rotated around the x or y axis. 15702 * For example, a large distance will result in a large viewing angle, and there 15703 * will not be much perspective distortion of the view as it rotates. A short 15704 * distance may cause much more perspective distortion upon rotation, and can 15705 * also result in some drawing artifacts if the rotated view ends up partially 15706 * behind the camera (which is why the recommendation is to use a distance at 15707 * least as far as the size of the view, if the view is to be rotated.)</p> 15708 * 15709 * <p>The distance is expressed in "depth pixels." The default distance depends 15710 * on the screen density. For instance, on a medium density display, the 15711 * default distance is 1280. On a high density display, the default distance 15712 * is 1920.</p> 15713 * 15714 * <p>If you want to specify a distance that leads to visually consistent 15715 * results across various densities, use the following formula:</p> 15716 * <pre> 15717 * float scale = context.getResources().getDisplayMetrics().density; 15718 * view.setCameraDistance(distance * scale); 15719 * </pre> 15720 * 15721 * <p>The density scale factor of a high density display is 1.5, 15722 * and 1920 = 1280 * 1.5.</p> 15723 * 15724 * @param distance The distance in "depth pixels", if negative the opposite 15725 * value is used 15726 * 15727 * @see #setRotationX(float) 15728 * @see #setRotationY(float) 15729 */ setCameraDistance(float distance)15730 public void setCameraDistance(float distance) { 15731 final float dpi = mResources.getDisplayMetrics().densityDpi; 15732 15733 invalidateViewProperty(true, false); 15734 mRenderNode.setCameraDistance(Math.abs(distance) / dpi); 15735 invalidateViewProperty(false, false); 15736 15737 invalidateParentIfNeededAndWasQuickRejected(); 15738 } 15739 15740 /** 15741 * The degrees that the view is rotated around the pivot point. 15742 * 15743 * @see #setRotation(float) 15744 * @see #getPivotX() 15745 * @see #getPivotY() 15746 * 15747 * @return The degrees of rotation. 15748 */ 15749 @ViewDebug.ExportedProperty(category = "drawing") 15750 @InspectableProperty getRotation()15751 public float getRotation() { 15752 return mRenderNode.getRotationZ(); 15753 } 15754 15755 /** 15756 * Sets the degrees that the view is rotated around the pivot point. Increasing values 15757 * result in clockwise rotation. 15758 * 15759 * @param rotation The degrees of rotation. 15760 * 15761 * @see #getRotation() 15762 * @see #getPivotX() 15763 * @see #getPivotY() 15764 * @see #setRotationX(float) 15765 * @see #setRotationY(float) 15766 * 15767 * @attr ref android.R.styleable#View_rotation 15768 */ setRotation(float rotation)15769 public void setRotation(float rotation) { 15770 if (rotation != getRotation()) { 15771 // Double-invalidation is necessary to capture view's old and new areas 15772 invalidateViewProperty(true, false); 15773 mRenderNode.setRotationZ(rotation); 15774 invalidateViewProperty(false, true); 15775 15776 invalidateParentIfNeededAndWasQuickRejected(); 15777 notifySubtreeAccessibilityStateChangedIfNeeded(); 15778 } 15779 } 15780 15781 /** 15782 * The degrees that the view is rotated around the vertical axis through the pivot point. 15783 * 15784 * @see #getPivotX() 15785 * @see #getPivotY() 15786 * @see #setRotationY(float) 15787 * 15788 * @return The degrees of Y rotation. 15789 */ 15790 @ViewDebug.ExportedProperty(category = "drawing") 15791 @InspectableProperty getRotationY()15792 public float getRotationY() { 15793 return mRenderNode.getRotationY(); 15794 } 15795 15796 /** 15797 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 15798 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 15799 * down the y axis. 15800 * 15801 * When rotating large views, it is recommended to adjust the camera distance 15802 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 15803 * 15804 * @param rotationY The degrees of Y rotation. 15805 * 15806 * @see #getRotationY() 15807 * @see #getPivotX() 15808 * @see #getPivotY() 15809 * @see #setRotation(float) 15810 * @see #setRotationX(float) 15811 * @see #setCameraDistance(float) 15812 * 15813 * @attr ref android.R.styleable#View_rotationY 15814 */ setRotationY(float rotationY)15815 public void setRotationY(float rotationY) { 15816 if (rotationY != getRotationY()) { 15817 invalidateViewProperty(true, false); 15818 mRenderNode.setRotationY(rotationY); 15819 invalidateViewProperty(false, true); 15820 15821 invalidateParentIfNeededAndWasQuickRejected(); 15822 notifySubtreeAccessibilityStateChangedIfNeeded(); 15823 } 15824 } 15825 15826 /** 15827 * The degrees that the view is rotated around the horizontal axis through the pivot point. 15828 * 15829 * @see #getPivotX() 15830 * @see #getPivotY() 15831 * @see #setRotationX(float) 15832 * 15833 * @return The degrees of X rotation. 15834 */ 15835 @ViewDebug.ExportedProperty(category = "drawing") 15836 @InspectableProperty getRotationX()15837 public float getRotationX() { 15838 return mRenderNode.getRotationX(); 15839 } 15840 15841 /** 15842 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 15843 * Increasing values result in clockwise rotation from the viewpoint of looking down the 15844 * x axis. 15845 * 15846 * When rotating large views, it is recommended to adjust the camera distance 15847 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 15848 * 15849 * @param rotationX The degrees of X rotation. 15850 * 15851 * @see #getRotationX() 15852 * @see #getPivotX() 15853 * @see #getPivotY() 15854 * @see #setRotation(float) 15855 * @see #setRotationY(float) 15856 * @see #setCameraDistance(float) 15857 * 15858 * @attr ref android.R.styleable#View_rotationX 15859 */ setRotationX(float rotationX)15860 public void setRotationX(float rotationX) { 15861 if (rotationX != getRotationX()) { 15862 invalidateViewProperty(true, false); 15863 mRenderNode.setRotationX(rotationX); 15864 invalidateViewProperty(false, true); 15865 15866 invalidateParentIfNeededAndWasQuickRejected(); 15867 notifySubtreeAccessibilityStateChangedIfNeeded(); 15868 } 15869 } 15870 15871 /** 15872 * The amount that the view is scaled in x around the pivot point, as a proportion of 15873 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 15874 * 15875 * <p>By default, this is 1.0f. 15876 * 15877 * @see #getPivotX() 15878 * @see #getPivotY() 15879 * @return The scaling factor. 15880 */ 15881 @ViewDebug.ExportedProperty(category = "drawing") 15882 @InspectableProperty getScaleX()15883 public float getScaleX() { 15884 return mRenderNode.getScaleX(); 15885 } 15886 15887 /** 15888 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 15889 * the view's unscaled width. A value of 1 means that no scaling is applied. 15890 * 15891 * @param scaleX The scaling factor. 15892 * @see #getPivotX() 15893 * @see #getPivotY() 15894 * 15895 * @attr ref android.R.styleable#View_scaleX 15896 */ setScaleX(float scaleX)15897 public void setScaleX(float scaleX) { 15898 if (scaleX != getScaleX()) { 15899 scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX"); 15900 invalidateViewProperty(true, false); 15901 mRenderNode.setScaleX(scaleX); 15902 invalidateViewProperty(false, true); 15903 15904 invalidateParentIfNeededAndWasQuickRejected(); 15905 notifySubtreeAccessibilityStateChangedIfNeeded(); 15906 } 15907 } 15908 15909 /** 15910 * The amount that the view is scaled in y around the pivot point, as a proportion of 15911 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 15912 * 15913 * <p>By default, this is 1.0f. 15914 * 15915 * @see #getPivotX() 15916 * @see #getPivotY() 15917 * @return The scaling factor. 15918 */ 15919 @ViewDebug.ExportedProperty(category = "drawing") 15920 @InspectableProperty getScaleY()15921 public float getScaleY() { 15922 return mRenderNode.getScaleY(); 15923 } 15924 15925 /** 15926 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 15927 * the view's unscaled width. A value of 1 means that no scaling is applied. 15928 * 15929 * @param scaleY The scaling factor. 15930 * @see #getPivotX() 15931 * @see #getPivotY() 15932 * 15933 * @attr ref android.R.styleable#View_scaleY 15934 */ setScaleY(float scaleY)15935 public void setScaleY(float scaleY) { 15936 if (scaleY != getScaleY()) { 15937 scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY"); 15938 invalidateViewProperty(true, false); 15939 mRenderNode.setScaleY(scaleY); 15940 invalidateViewProperty(false, true); 15941 15942 invalidateParentIfNeededAndWasQuickRejected(); 15943 notifySubtreeAccessibilityStateChangedIfNeeded(); 15944 } 15945 } 15946 15947 /** 15948 * The x location of the point around which the view is {@link #setRotation(float) rotated} 15949 * and {@link #setScaleX(float) scaled}. 15950 * 15951 * @see #getRotation() 15952 * @see #getScaleX() 15953 * @see #getScaleY() 15954 * @see #getPivotY() 15955 * @return The x location of the pivot point. 15956 * 15957 * @attr ref android.R.styleable#View_transformPivotX 15958 */ 15959 @ViewDebug.ExportedProperty(category = "drawing") 15960 @InspectableProperty(name = "transformPivotX") getPivotX()15961 public float getPivotX() { 15962 return mRenderNode.getPivotX(); 15963 } 15964 15965 /** 15966 * Sets the x location of the point around which the view is 15967 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 15968 * By default, the pivot point is centered on the object. 15969 * Setting this property disables this behavior and causes the view to use only the 15970 * explicitly set pivotX and pivotY values. 15971 * 15972 * @param pivotX The x location of the pivot point. 15973 * @see #getRotation() 15974 * @see #getScaleX() 15975 * @see #getScaleY() 15976 * @see #getPivotY() 15977 * 15978 * @attr ref android.R.styleable#View_transformPivotX 15979 */ setPivotX(float pivotX)15980 public void setPivotX(float pivotX) { 15981 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 15982 invalidateViewProperty(true, false); 15983 mRenderNode.setPivotX(pivotX); 15984 invalidateViewProperty(false, true); 15985 15986 invalidateParentIfNeededAndWasQuickRejected(); 15987 } 15988 } 15989 15990 /** 15991 * The y location of the point around which the view is {@link #setRotation(float) rotated} 15992 * and {@link #setScaleY(float) scaled}. 15993 * 15994 * @see #getRotation() 15995 * @see #getScaleX() 15996 * @see #getScaleY() 15997 * @see #getPivotY() 15998 * @return The y location of the pivot point. 15999 * 16000 * @attr ref android.R.styleable#View_transformPivotY 16001 */ 16002 @ViewDebug.ExportedProperty(category = "drawing") 16003 @InspectableProperty(name = "transformPivotY") getPivotY()16004 public float getPivotY() { 16005 return mRenderNode.getPivotY(); 16006 } 16007 16008 /** 16009 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 16010 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 16011 * Setting this property disables this behavior and causes the view to use only the 16012 * explicitly set pivotX and pivotY values. 16013 * 16014 * @param pivotY The y location of the pivot point. 16015 * @see #getRotation() 16016 * @see #getScaleX() 16017 * @see #getScaleY() 16018 * @see #getPivotY() 16019 * 16020 * @attr ref android.R.styleable#View_transformPivotY 16021 */ setPivotY(float pivotY)16022 public void setPivotY(float pivotY) { 16023 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 16024 invalidateViewProperty(true, false); 16025 mRenderNode.setPivotY(pivotY); 16026 invalidateViewProperty(false, true); 16027 16028 invalidateParentIfNeededAndWasQuickRejected(); 16029 } 16030 } 16031 16032 /** 16033 * Returns whether or not a pivot has been set by a call to {@link #setPivotX(float)} or 16034 * {@link #setPivotY(float)}. If no pivot has been set then the pivot will be the center 16035 * of the view. 16036 * 16037 * @return True if a pivot has been set, false if the default pivot is being used 16038 */ isPivotSet()16039 public boolean isPivotSet() { 16040 return mRenderNode.isPivotExplicitlySet(); 16041 } 16042 16043 /** 16044 * Clears any pivot previously set by a call to {@link #setPivotX(float)} or 16045 * {@link #setPivotY(float)}. After calling this {@link #isPivotSet()} will be false 16046 * and the pivot used for rotation will return to default of being centered on the view. 16047 */ resetPivot()16048 public void resetPivot() { 16049 if (mRenderNode.resetPivot()) { 16050 invalidateViewProperty(false, false); 16051 } 16052 } 16053 16054 /** 16055 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 16056 * completely transparent and 1 means the view is completely opaque. 16057 * 16058 * <p>By default this is 1.0f. 16059 * @return The opacity of the view. 16060 */ 16061 @ViewDebug.ExportedProperty(category = "drawing") 16062 @InspectableProperty getAlpha()16063 public float getAlpha() { 16064 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 16065 } 16066 16067 /** 16068 * Sets the behavior for overlapping rendering for this view (see {@link 16069 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 16070 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 16071 * providing the value which is then used internally. That is, when {@link 16072 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 16073 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 16074 * instead. 16075 * 16076 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 16077 * instead of that returned by {@link #hasOverlappingRendering()}. 16078 * 16079 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 16080 */ forceHasOverlappingRendering(boolean hasOverlappingRendering)16081 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 16082 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 16083 if (hasOverlappingRendering) { 16084 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 16085 } else { 16086 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 16087 } 16088 } 16089 16090 /** 16091 * Returns the value for overlapping rendering that is used internally. This is either 16092 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 16093 * the return value of {@link #hasOverlappingRendering()}, otherwise. 16094 * 16095 * @return The value for overlapping rendering being used internally. 16096 */ getHasOverlappingRendering()16097 public final boolean getHasOverlappingRendering() { 16098 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 16099 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 16100 hasOverlappingRendering(); 16101 } 16102 16103 /** 16104 * Returns whether this View has content which overlaps. 16105 * 16106 * <p>This function, intended to be overridden by specific View types, is an optimization when 16107 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 16108 * an offscreen buffer and then composited into place, which can be expensive. If the view has 16109 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 16110 * directly. An example of overlapping rendering is a TextView with a background image, such as 16111 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 16112 * ImageView with only the foreground image. The default implementation returns true; subclasses 16113 * should override if they have cases which can be optimized.</p> 16114 * 16115 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 16116 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 16117 * 16118 * @return true if the content in this view might overlap, false otherwise. 16119 */ 16120 @ViewDebug.ExportedProperty(category = "drawing") hasOverlappingRendering()16121 public boolean hasOverlappingRendering() { 16122 return true; 16123 } 16124 16125 /** 16126 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 16127 * completely transparent and 1 means the view is completely opaque. 16128 * 16129 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 16130 * can have significant performance implications, especially for large views. It is best to use 16131 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 16132 * 16133 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 16134 * strongly recommended for performance reasons to either override 16135 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 16136 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 16137 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 16138 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 16139 * of rendering cost, even for simple or small views. Starting with 16140 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 16141 * applied to the view at the rendering level.</p> 16142 * 16143 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 16144 * responsible for applying the opacity itself.</p> 16145 * 16146 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 16147 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 16148 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 16149 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 16150 * 16151 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 16152 * value will clip a View to its bounds, unless the View returns <code>false</code> from 16153 * {@link #hasOverlappingRendering}.</p> 16154 * 16155 * @param alpha The opacity of the view. 16156 * 16157 * @see #hasOverlappingRendering() 16158 * @see #setLayerType(int, android.graphics.Paint) 16159 * 16160 * @attr ref android.R.styleable#View_alpha 16161 */ setAlpha(@loatRangefrom=0.0, to=1.0) float alpha)16162 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 16163 ensureTransformationInfo(); 16164 if (mTransformationInfo.mAlpha != alpha) { 16165 setAlphaInternal(alpha); 16166 if (onSetAlpha((int) (alpha * 255))) { 16167 mPrivateFlags |= PFLAG_ALPHA_SET; 16168 // subclass is handling alpha - don't optimize rendering cache invalidation 16169 invalidateParentCaches(); 16170 invalidate(true); 16171 } else { 16172 mPrivateFlags &= ~PFLAG_ALPHA_SET; 16173 invalidateViewProperty(true, false); 16174 mRenderNode.setAlpha(getFinalAlpha()); 16175 } 16176 } 16177 } 16178 16179 /** 16180 * Faster version of setAlpha() which performs the same steps except there are 16181 * no calls to invalidate(). The caller of this function should perform proper invalidation 16182 * on the parent and this object. The return value indicates whether the subclass handles 16183 * alpha (the return value for onSetAlpha()). 16184 * 16185 * @param alpha The new value for the alpha property 16186 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 16187 * the new value for the alpha property is different from the old value 16188 */ 16189 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768435) setAlphaNoInvalidation(float alpha)16190 boolean setAlphaNoInvalidation(float alpha) { 16191 ensureTransformationInfo(); 16192 if (mTransformationInfo.mAlpha != alpha) { 16193 setAlphaInternal(alpha); 16194 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 16195 if (subclassHandlesAlpha) { 16196 mPrivateFlags |= PFLAG_ALPHA_SET; 16197 return true; 16198 } else { 16199 mPrivateFlags &= ~PFLAG_ALPHA_SET; 16200 mRenderNode.setAlpha(getFinalAlpha()); 16201 } 16202 } 16203 return false; 16204 } 16205 setAlphaInternal(float alpha)16206 void setAlphaInternal(float alpha) { 16207 float oldAlpha = mTransformationInfo.mAlpha; 16208 mTransformationInfo.mAlpha = alpha; 16209 // Report visibility changes, which can affect children, to accessibility 16210 if ((alpha == 0) ^ (oldAlpha == 0)) { 16211 notifySubtreeAccessibilityStateChangedIfNeeded(); 16212 } 16213 } 16214 16215 /** 16216 * This property is intended only for use by the Fade transition, which animates it 16217 * to produce a visual translucency that does not side-effect (or get affected by) 16218 * the real alpha property. This value is composited with the other alpha value 16219 * (and the AlphaAnimation value, when that is present) to produce a final visual 16220 * translucency result, which is what is passed into the DisplayList. 16221 */ setTransitionAlpha(float alpha)16222 public void setTransitionAlpha(float alpha) { 16223 ensureTransformationInfo(); 16224 if (mTransformationInfo.mTransitionAlpha != alpha) { 16225 mTransformationInfo.mTransitionAlpha = alpha; 16226 mPrivateFlags &= ~PFLAG_ALPHA_SET; 16227 invalidateViewProperty(true, false); 16228 mRenderNode.setAlpha(getFinalAlpha()); 16229 } 16230 } 16231 16232 /** 16233 * Calculates the visual alpha of this view, which is a combination of the actual 16234 * alpha value and the transitionAlpha value (if set). 16235 */ getFinalAlpha()16236 private float getFinalAlpha() { 16237 if (mTransformationInfo != null) { 16238 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 16239 } 16240 return 1; 16241 } 16242 16243 /** 16244 * This property is intended only for use by the Fade transition, which animates 16245 * it to produce a visual translucency that does not side-effect (or get affected 16246 * by) the real alpha property. This value is composited with the other alpha 16247 * value (and the AlphaAnimation value, when that is present) to produce a final 16248 * visual translucency result, which is what is passed into the DisplayList. 16249 */ 16250 @ViewDebug.ExportedProperty(category = "drawing") getTransitionAlpha()16251 public float getTransitionAlpha() { 16252 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 16253 } 16254 16255 /** 16256 * Sets whether or not to allow force dark to apply to this view. 16257 * 16258 * Setting this to false will disable the auto-dark feature on everything this view 16259 * draws, including any descendants. 16260 * 16261 * Setting this to true will allow this view to be automatically made dark, however 16262 * a value of 'true' will not override any 'false' value in its parent chain nor will 16263 * it prevent any 'false' in any of its children. 16264 * 16265 * The default behavior of force dark is also influenced by the Theme's 16266 * {@link android.R.styleable#Theme_isLightTheme isLightTheme} attribute. 16267 * If a theme is isLightTheme="false", then force dark is globally disabled for that theme. 16268 * 16269 * @param allow Whether or not to allow force dark. 16270 */ setForceDarkAllowed(boolean allow)16271 public void setForceDarkAllowed(boolean allow) { 16272 if (mRenderNode.setForceDarkAllowed(allow)) { 16273 // Currently toggling force-dark requires a new display list push to apply 16274 // TODO: Make it not clobber the display list so this is just a damageSelf() instead 16275 invalidate(); 16276 } 16277 } 16278 16279 /** 16280 * See {@link #setForceDarkAllowed(boolean)} 16281 * 16282 * @return true if force dark is allowed (default), false if it is disabled 16283 */ 16284 @ViewDebug.ExportedProperty(category = "drawing") 16285 @InspectableProperty isForceDarkAllowed()16286 public boolean isForceDarkAllowed() { 16287 return mRenderNode.isForceDarkAllowed(); 16288 } 16289 16290 /** 16291 * Top position of this view relative to its parent. 16292 * 16293 * @return The top of this view, in pixels. 16294 */ 16295 @ViewDebug.CapturedViewProperty getTop()16296 public final int getTop() { 16297 return mTop; 16298 } 16299 16300 /** 16301 * Sets the top position of this view relative to its parent. This method is meant to be called 16302 * by the layout system and should not generally be called otherwise, because the property 16303 * may be changed at any time by the layout. 16304 * 16305 * @param top The top of this view, in pixels. 16306 */ setTop(int top)16307 public final void setTop(int top) { 16308 if (top != mTop) { 16309 final boolean matrixIsIdentity = hasIdentityMatrix(); 16310 if (matrixIsIdentity) { 16311 if (mAttachInfo != null) { 16312 int minTop; 16313 int yLoc; 16314 if (top < mTop) { 16315 minTop = top; 16316 yLoc = top - mTop; 16317 } else { 16318 minTop = mTop; 16319 yLoc = 0; 16320 } 16321 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 16322 } 16323 } else { 16324 // Double-invalidation is necessary to capture view's old and new areas 16325 invalidate(true); 16326 } 16327 16328 int width = mRight - mLeft; 16329 int oldHeight = mBottom - mTop; 16330 16331 mTop = top; 16332 mRenderNode.setTop(mTop); 16333 16334 sizeChange(width, mBottom - mTop, width, oldHeight); 16335 16336 if (!matrixIsIdentity) { 16337 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 16338 invalidate(true); 16339 } 16340 mBackgroundSizeChanged = true; 16341 mDefaultFocusHighlightSizeChanged = true; 16342 if (mForegroundInfo != null) { 16343 mForegroundInfo.mBoundsChanged = true; 16344 } 16345 invalidateParentIfNeeded(); 16346 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 16347 // View was rejected last time it was drawn by its parent; this may have changed 16348 invalidateParentIfNeeded(); 16349 } 16350 } 16351 } 16352 16353 /** 16354 * Bottom position of this view relative to its parent. 16355 * 16356 * @return The bottom of this view, in pixels. 16357 */ 16358 @ViewDebug.CapturedViewProperty getBottom()16359 public final int getBottom() { 16360 return mBottom; 16361 } 16362 16363 /** 16364 * True if this view has changed since the last time being drawn. 16365 * 16366 * @return The dirty state of this view. 16367 */ isDirty()16368 public boolean isDirty() { 16369 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 16370 } 16371 16372 /** 16373 * Sets the bottom position of this view relative to its parent. This method is meant to be 16374 * called by the layout system and should not generally be called otherwise, because the 16375 * property may be changed at any time by the layout. 16376 * 16377 * @param bottom The bottom of this view, in pixels. 16378 */ setBottom(int bottom)16379 public final void setBottom(int bottom) { 16380 if (bottom != mBottom) { 16381 final boolean matrixIsIdentity = hasIdentityMatrix(); 16382 if (matrixIsIdentity) { 16383 if (mAttachInfo != null) { 16384 int maxBottom; 16385 if (bottom < mBottom) { 16386 maxBottom = mBottom; 16387 } else { 16388 maxBottom = bottom; 16389 } 16390 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 16391 } 16392 } else { 16393 // Double-invalidation is necessary to capture view's old and new areas 16394 invalidate(true); 16395 } 16396 16397 int width = mRight - mLeft; 16398 int oldHeight = mBottom - mTop; 16399 16400 mBottom = bottom; 16401 mRenderNode.setBottom(mBottom); 16402 16403 sizeChange(width, mBottom - mTop, width, oldHeight); 16404 16405 if (!matrixIsIdentity) { 16406 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 16407 invalidate(true); 16408 } 16409 mBackgroundSizeChanged = true; 16410 mDefaultFocusHighlightSizeChanged = true; 16411 if (mForegroundInfo != null) { 16412 mForegroundInfo.mBoundsChanged = true; 16413 } 16414 invalidateParentIfNeeded(); 16415 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 16416 // View was rejected last time it was drawn by its parent; this may have changed 16417 invalidateParentIfNeeded(); 16418 } 16419 } 16420 } 16421 16422 /** 16423 * Left position of this view relative to its parent. 16424 * 16425 * @return The left edge of this view, in pixels. 16426 */ 16427 @ViewDebug.CapturedViewProperty getLeft()16428 public final int getLeft() { 16429 return mLeft; 16430 } 16431 16432 /** 16433 * Sets the left position of this view relative to its parent. This method is meant to be called 16434 * by the layout system and should not generally be called otherwise, because the property 16435 * may be changed at any time by the layout. 16436 * 16437 * @param left The left of this view, in pixels. 16438 */ setLeft(int left)16439 public final void setLeft(int left) { 16440 if (left != mLeft) { 16441 final boolean matrixIsIdentity = hasIdentityMatrix(); 16442 if (matrixIsIdentity) { 16443 if (mAttachInfo != null) { 16444 int minLeft; 16445 int xLoc; 16446 if (left < mLeft) { 16447 minLeft = left; 16448 xLoc = left - mLeft; 16449 } else { 16450 minLeft = mLeft; 16451 xLoc = 0; 16452 } 16453 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 16454 } 16455 } else { 16456 // Double-invalidation is necessary to capture view's old and new areas 16457 invalidate(true); 16458 } 16459 16460 int oldWidth = mRight - mLeft; 16461 int height = mBottom - mTop; 16462 16463 mLeft = left; 16464 mRenderNode.setLeft(left); 16465 16466 sizeChange(mRight - mLeft, height, oldWidth, height); 16467 16468 if (!matrixIsIdentity) { 16469 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 16470 invalidate(true); 16471 } 16472 mBackgroundSizeChanged = true; 16473 mDefaultFocusHighlightSizeChanged = true; 16474 if (mForegroundInfo != null) { 16475 mForegroundInfo.mBoundsChanged = true; 16476 } 16477 invalidateParentIfNeeded(); 16478 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 16479 // View was rejected last time it was drawn by its parent; this may have changed 16480 invalidateParentIfNeeded(); 16481 } 16482 } 16483 } 16484 16485 /** 16486 * Right position of this view relative to its parent. 16487 * 16488 * @return The right edge of this view, in pixels. 16489 */ 16490 @ViewDebug.CapturedViewProperty getRight()16491 public final int getRight() { 16492 return mRight; 16493 } 16494 16495 /** 16496 * Sets the right position of this view relative to its parent. This method is meant to be called 16497 * by the layout system and should not generally be called otherwise, because the property 16498 * may be changed at any time by the layout. 16499 * 16500 * @param right The right of this view, in pixels. 16501 */ setRight(int right)16502 public final void setRight(int right) { 16503 if (right != mRight) { 16504 final boolean matrixIsIdentity = hasIdentityMatrix(); 16505 if (matrixIsIdentity) { 16506 if (mAttachInfo != null) { 16507 int maxRight; 16508 if (right < mRight) { 16509 maxRight = mRight; 16510 } else { 16511 maxRight = right; 16512 } 16513 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 16514 } 16515 } else { 16516 // Double-invalidation is necessary to capture view's old and new areas 16517 invalidate(true); 16518 } 16519 16520 int oldWidth = mRight - mLeft; 16521 int height = mBottom - mTop; 16522 16523 mRight = right; 16524 mRenderNode.setRight(mRight); 16525 16526 sizeChange(mRight - mLeft, height, oldWidth, height); 16527 16528 if (!matrixIsIdentity) { 16529 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 16530 invalidate(true); 16531 } 16532 mBackgroundSizeChanged = true; 16533 mDefaultFocusHighlightSizeChanged = true; 16534 if (mForegroundInfo != null) { 16535 mForegroundInfo.mBoundsChanged = true; 16536 } 16537 invalidateParentIfNeeded(); 16538 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 16539 // View was rejected last time it was drawn by its parent; this may have changed 16540 invalidateParentIfNeeded(); 16541 } 16542 } 16543 } 16544 sanitizeFloatPropertyValue(float value, String propertyName)16545 private static float sanitizeFloatPropertyValue(float value, String propertyName) { 16546 return sanitizeFloatPropertyValue(value, propertyName, -Float.MAX_VALUE, Float.MAX_VALUE); 16547 } 16548 sanitizeFloatPropertyValue(float value, String propertyName, float min, float max)16549 private static float sanitizeFloatPropertyValue(float value, String propertyName, 16550 float min, float max) { 16551 // The expected "nothing bad happened" path 16552 if (value >= min && value <= max) return value; 16553 16554 if (value < min || value == Float.NEGATIVE_INFINITY) { 16555 if (sThrowOnInvalidFloatProperties) { 16556 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 16557 + value + ", the value must be >= " + min); 16558 } 16559 return min; 16560 } 16561 16562 if (value > max || value == Float.POSITIVE_INFINITY) { 16563 if (sThrowOnInvalidFloatProperties) { 16564 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 16565 + value + ", the value must be <= " + max); 16566 } 16567 return max; 16568 } 16569 16570 if (Float.isNaN(value)) { 16571 if (sThrowOnInvalidFloatProperties) { 16572 throw new IllegalArgumentException( 16573 "Cannot set '" + propertyName + "' to Float.NaN"); 16574 } 16575 return 0; // Unclear which direction this NaN went so... 0? 16576 } 16577 16578 // Shouldn't be possible to reach this. 16579 throw new IllegalStateException("How do you get here?? " + value); 16580 } 16581 16582 /** 16583 * The visual x position of this view, in pixels. This is equivalent to the 16584 * {@link #setTranslationX(float) translationX} property plus the current 16585 * {@link #getLeft() left} property. 16586 * 16587 * @return The visual x position of this view, in pixels. 16588 */ 16589 @ViewDebug.ExportedProperty(category = "drawing") getX()16590 public float getX() { 16591 return mLeft + getTranslationX(); 16592 } 16593 16594 /** 16595 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 16596 * {@link #setTranslationX(float) translationX} property to be the difference between 16597 * the x value passed in and the current {@link #getLeft() left} property. 16598 * 16599 * @param x The visual x position of this view, in pixels. 16600 */ setX(float x)16601 public void setX(float x) { 16602 setTranslationX(x - mLeft); 16603 } 16604 16605 /** 16606 * The visual y position of this view, in pixels. This is equivalent to the 16607 * {@link #setTranslationY(float) translationY} property plus the current 16608 * {@link #getTop() top} property. 16609 * 16610 * @return The visual y position of this view, in pixels. 16611 */ 16612 @ViewDebug.ExportedProperty(category = "drawing") getY()16613 public float getY() { 16614 return mTop + getTranslationY(); 16615 } 16616 16617 /** 16618 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 16619 * {@link #setTranslationY(float) translationY} property to be the difference between 16620 * the y value passed in and the current {@link #getTop() top} property. 16621 * 16622 * @param y The visual y position of this view, in pixels. 16623 */ setY(float y)16624 public void setY(float y) { 16625 setTranslationY(y - mTop); 16626 } 16627 16628 /** 16629 * The visual z position of this view, in pixels. This is equivalent to the 16630 * {@link #setTranslationZ(float) translationZ} property plus the current 16631 * {@link #getElevation() elevation} property. 16632 * 16633 * @return The visual z position of this view, in pixels. 16634 */ 16635 @ViewDebug.ExportedProperty(category = "drawing") getZ()16636 public float getZ() { 16637 return getElevation() + getTranslationZ(); 16638 } 16639 16640 /** 16641 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 16642 * {@link #setTranslationZ(float) translationZ} property to be the difference between 16643 * the z value passed in and the current {@link #getElevation() elevation} property. 16644 * 16645 * @param z The visual z position of this view, in pixels. 16646 */ setZ(float z)16647 public void setZ(float z) { 16648 setTranslationZ(z - getElevation()); 16649 } 16650 16651 /** 16652 * The base elevation of this view relative to its parent, in pixels. 16653 * 16654 * @return The base depth position of the view, in pixels. 16655 */ 16656 @ViewDebug.ExportedProperty(category = "drawing") 16657 @InspectableProperty getElevation()16658 public float getElevation() { 16659 return mRenderNode.getElevation(); 16660 } 16661 16662 /** 16663 * Sets the base elevation of this view, in pixels. 16664 * 16665 * @attr ref android.R.styleable#View_elevation 16666 */ setElevation(float elevation)16667 public void setElevation(float elevation) { 16668 if (elevation != getElevation()) { 16669 elevation = sanitizeFloatPropertyValue(elevation, "elevation"); 16670 invalidateViewProperty(true, false); 16671 mRenderNode.setElevation(elevation); 16672 invalidateViewProperty(false, true); 16673 16674 invalidateParentIfNeededAndWasQuickRejected(); 16675 } 16676 } 16677 16678 /** 16679 * The horizontal location of this view relative to its {@link #getLeft() left} position. 16680 * This position is post-layout, in addition to wherever the object's 16681 * layout placed it. 16682 * 16683 * @return The horizontal position of this view relative to its left position, in pixels. 16684 */ 16685 @ViewDebug.ExportedProperty(category = "drawing") 16686 @InspectableProperty getTranslationX()16687 public float getTranslationX() { 16688 return mRenderNode.getTranslationX(); 16689 } 16690 16691 /** 16692 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 16693 * This effectively positions the object post-layout, in addition to wherever the object's 16694 * layout placed it. 16695 * 16696 * @param translationX The horizontal position of this view relative to its left position, 16697 * in pixels. 16698 * 16699 * @attr ref android.R.styleable#View_translationX 16700 */ setTranslationX(float translationX)16701 public void setTranslationX(float translationX) { 16702 if (translationX != getTranslationX()) { 16703 invalidateViewProperty(true, false); 16704 mRenderNode.setTranslationX(translationX); 16705 invalidateViewProperty(false, true); 16706 16707 invalidateParentIfNeededAndWasQuickRejected(); 16708 notifySubtreeAccessibilityStateChangedIfNeeded(); 16709 } 16710 } 16711 16712 /** 16713 * The vertical location of this view relative to its {@link #getTop() top} position. 16714 * This position is post-layout, in addition to wherever the object's 16715 * layout placed it. 16716 * 16717 * @return The vertical position of this view relative to its top position, 16718 * in pixels. 16719 */ 16720 @ViewDebug.ExportedProperty(category = "drawing") 16721 @InspectableProperty getTranslationY()16722 public float getTranslationY() { 16723 return mRenderNode.getTranslationY(); 16724 } 16725 16726 /** 16727 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 16728 * This effectively positions the object post-layout, in addition to wherever the object's 16729 * layout placed it. 16730 * 16731 * @param translationY The vertical position of this view relative to its top position, 16732 * in pixels. 16733 * 16734 * @attr ref android.R.styleable#View_translationY 16735 */ setTranslationY(float translationY)16736 public void setTranslationY(float translationY) { 16737 if (translationY != getTranslationY()) { 16738 invalidateViewProperty(true, false); 16739 mRenderNode.setTranslationY(translationY); 16740 invalidateViewProperty(false, true); 16741 16742 invalidateParentIfNeededAndWasQuickRejected(); 16743 notifySubtreeAccessibilityStateChangedIfNeeded(); 16744 } 16745 } 16746 16747 /** 16748 * The depth location of this view relative to its {@link #getElevation() elevation}. 16749 * 16750 * @return The depth of this view relative to its elevation. 16751 */ 16752 @ViewDebug.ExportedProperty(category = "drawing") 16753 @InspectableProperty getTranslationZ()16754 public float getTranslationZ() { 16755 return mRenderNode.getTranslationZ(); 16756 } 16757 16758 /** 16759 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 16760 * 16761 * @attr ref android.R.styleable#View_translationZ 16762 */ setTranslationZ(float translationZ)16763 public void setTranslationZ(float translationZ) { 16764 if (translationZ != getTranslationZ()) { 16765 translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ"); 16766 invalidateViewProperty(true, false); 16767 mRenderNode.setTranslationZ(translationZ); 16768 invalidateViewProperty(false, true); 16769 16770 invalidateParentIfNeededAndWasQuickRejected(); 16771 } 16772 } 16773 16774 /** 16775 * Changes the transformation matrix on the view. This is used in animation frameworks, 16776 * such as {@link android.transition.Transition}. When the animation finishes, the matrix 16777 * should be cleared by calling this method with <code>null</code> as the matrix parameter. 16778 * Application developers should use transformation methods like {@link #setRotation(float)}, 16779 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 16780 * and {@link #setTranslationY(float)} (float)}} instead. 16781 * 16782 * @param matrix The matrix, null indicates that the matrix should be cleared. 16783 * @see #getAnimationMatrix() 16784 */ setAnimationMatrix(@ullable Matrix matrix)16785 public void setAnimationMatrix(@Nullable Matrix matrix) { 16786 invalidateViewProperty(true, false); 16787 mRenderNode.setAnimationMatrix(matrix); 16788 invalidateViewProperty(false, true); 16789 16790 invalidateParentIfNeededAndWasQuickRejected(); 16791 } 16792 16793 /** 16794 * Return the current transformation matrix of the view. This is used in animation frameworks, 16795 * such as {@link android.transition.Transition}. Returns <code>null</code> when there is no 16796 * transformation provided by {@link #setAnimationMatrix(Matrix)}. 16797 * Application developers should use transformation methods like {@link #setRotation(float)}, 16798 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 16799 * and {@link #setTranslationY(float)} (float)}} instead. 16800 * 16801 * @return the Matrix, null indicates there is no transformation 16802 * @see #setAnimationMatrix(Matrix) 16803 */ 16804 @Nullable getAnimationMatrix()16805 public Matrix getAnimationMatrix() { 16806 return mRenderNode.getAnimationMatrix(); 16807 } 16808 16809 /** 16810 * Returns the current StateListAnimator if exists. 16811 * 16812 * @return StateListAnimator or null if it does not exists 16813 * @see #setStateListAnimator(android.animation.StateListAnimator) 16814 */ 16815 @InspectableProperty getStateListAnimator()16816 public StateListAnimator getStateListAnimator() { 16817 return mStateListAnimator; 16818 } 16819 16820 /** 16821 * Attaches the provided StateListAnimator to this View. 16822 * <p> 16823 * Any previously attached StateListAnimator will be detached. 16824 * 16825 * @param stateListAnimator The StateListAnimator to update the view 16826 * @see android.animation.StateListAnimator 16827 */ setStateListAnimator(StateListAnimator stateListAnimator)16828 public void setStateListAnimator(StateListAnimator stateListAnimator) { 16829 if (mStateListAnimator == stateListAnimator) { 16830 return; 16831 } 16832 if (mStateListAnimator != null) { 16833 mStateListAnimator.setTarget(null); 16834 } 16835 mStateListAnimator = stateListAnimator; 16836 if (stateListAnimator != null) { 16837 stateListAnimator.setTarget(this); 16838 if (isAttachedToWindow()) { 16839 stateListAnimator.setState(getDrawableState()); 16840 } 16841 } 16842 } 16843 16844 /** 16845 * Returns whether the Outline should be used to clip the contents of the View. 16846 * <p> 16847 * Note that this flag will only be respected if the View's Outline returns true from 16848 * {@link Outline#canClip()}. 16849 * 16850 * @see #setOutlineProvider(ViewOutlineProvider) 16851 * @see #setClipToOutline(boolean) 16852 */ getClipToOutline()16853 public final boolean getClipToOutline() { 16854 return mRenderNode.getClipToOutline(); 16855 } 16856 16857 /** 16858 * Sets whether the View's Outline should be used to clip the contents of the View. 16859 * <p> 16860 * Only a single non-rectangular clip can be applied on a View at any time. 16861 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 16862 * circular reveal} animation take priority over Outline clipping, and 16863 * child Outline clipping takes priority over Outline clipping done by a 16864 * parent. 16865 * <p> 16866 * Note that this flag will only be respected if the View's Outline returns true from 16867 * {@link Outline#canClip()}. 16868 * 16869 * @see #setOutlineProvider(ViewOutlineProvider) 16870 * @see #getClipToOutline() 16871 */ setClipToOutline(boolean clipToOutline)16872 public void setClipToOutline(boolean clipToOutline) { 16873 damageInParent(); 16874 if (getClipToOutline() != clipToOutline) { 16875 mRenderNode.setClipToOutline(clipToOutline); 16876 } 16877 } 16878 16879 // correspond to the enum values of View_outlineProvider 16880 private static final int PROVIDER_BACKGROUND = 0; 16881 private static final int PROVIDER_NONE = 1; 16882 private static final int PROVIDER_BOUNDS = 2; 16883 private static final int PROVIDER_PADDED_BOUNDS = 3; setOutlineProviderFromAttribute(int providerInt)16884 private void setOutlineProviderFromAttribute(int providerInt) { 16885 switch (providerInt) { 16886 case PROVIDER_BACKGROUND: 16887 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 16888 break; 16889 case PROVIDER_NONE: 16890 setOutlineProvider(null); 16891 break; 16892 case PROVIDER_BOUNDS: 16893 setOutlineProvider(ViewOutlineProvider.BOUNDS); 16894 break; 16895 case PROVIDER_PADDED_BOUNDS: 16896 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 16897 break; 16898 } 16899 } 16900 16901 /** 16902 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 16903 * the shape of the shadow it casts, and enables outline clipping. 16904 * <p> 16905 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 16906 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 16907 * outline provider with this method allows this behavior to be overridden. 16908 * <p> 16909 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 16910 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 16911 * <p> 16912 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 16913 * 16914 * @see #setClipToOutline(boolean) 16915 * @see #getClipToOutline() 16916 * @see #getOutlineProvider() 16917 */ setOutlineProvider(ViewOutlineProvider provider)16918 public void setOutlineProvider(ViewOutlineProvider provider) { 16919 mOutlineProvider = provider; 16920 invalidateOutline(); 16921 } 16922 16923 /** 16924 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 16925 * that defines the shape of the shadow it casts, and enables outline clipping. 16926 * 16927 * @see #setOutlineProvider(ViewOutlineProvider) 16928 */ 16929 @InspectableProperty getOutlineProvider()16930 public ViewOutlineProvider getOutlineProvider() { 16931 return mOutlineProvider; 16932 } 16933 16934 /** 16935 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 16936 * 16937 * @see #setOutlineProvider(ViewOutlineProvider) 16938 */ invalidateOutline()16939 public void invalidateOutline() { 16940 rebuildOutline(); 16941 16942 notifySubtreeAccessibilityStateChangedIfNeeded(); 16943 invalidateViewProperty(false, false); 16944 } 16945 16946 /** 16947 * Internal version of {@link #invalidateOutline()} which invalidates the 16948 * outline without invalidating the view itself. This is intended to be called from 16949 * within methods in the View class itself which are the result of the view being 16950 * invalidated already. For example, when we are drawing the background of a View, 16951 * we invalidate the outline in case it changed in the meantime, but we do not 16952 * need to invalidate the view because we're already drawing the background as part 16953 * of drawing the view in response to an earlier invalidation of the view. 16954 */ rebuildOutline()16955 private void rebuildOutline() { 16956 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 16957 if (mAttachInfo == null) return; 16958 16959 if (mOutlineProvider == null) { 16960 // no provider, remove outline 16961 mRenderNode.setOutline(null); 16962 } else { 16963 final Outline outline = mAttachInfo.mTmpOutline; 16964 outline.setEmpty(); 16965 outline.setAlpha(1.0f); 16966 16967 mOutlineProvider.getOutline(this, outline); 16968 mRenderNode.setOutline(outline); 16969 } 16970 } 16971 16972 /** 16973 * HierarchyViewer only 16974 * 16975 * @hide 16976 */ 16977 @ViewDebug.ExportedProperty(category = "drawing") hasShadow()16978 public boolean hasShadow() { 16979 return mRenderNode.hasShadow(); 16980 } 16981 16982 /** 16983 * Sets the color of the spot shadow that is drawn when the view has a positive Z or 16984 * elevation value. 16985 * <p> 16986 * By default the shadow color is black. Generally, this color will be opaque so the intensity 16987 * of the shadow is consistent between different views with different colors. 16988 * <p> 16989 * The opacity of the final spot shadow is a function of the shadow caster height, the 16990 * alpha channel of the outlineSpotShadowColor (typically opaque), and the 16991 * {@link android.R.attr#spotShadowAlpha} theme attribute. 16992 * 16993 * @attr ref android.R.styleable#View_outlineSpotShadowColor 16994 * @param color The color this View will cast for its elevation spot shadow. 16995 */ setOutlineSpotShadowColor(@olorInt int color)16996 public void setOutlineSpotShadowColor(@ColorInt int color) { 16997 if (mRenderNode.setSpotShadowColor(color)) { 16998 invalidateViewProperty(true, true); 16999 } 17000 } 17001 17002 /** 17003 * @return The shadow color set by {@link #setOutlineSpotShadowColor(int)}, or black if nothing 17004 * was set 17005 */ 17006 @InspectableProperty getOutlineSpotShadowColor()17007 public @ColorInt int getOutlineSpotShadowColor() { 17008 return mRenderNode.getSpotShadowColor(); 17009 } 17010 17011 /** 17012 * Sets the color of the ambient shadow that is drawn when the view has a positive Z or 17013 * elevation value. 17014 * <p> 17015 * By default the shadow color is black. Generally, this color will be opaque so the intensity 17016 * of the shadow is consistent between different views with different colors. 17017 * <p> 17018 * The opacity of the final ambient shadow is a function of the shadow caster height, the 17019 * alpha channel of the outlineAmbientShadowColor (typically opaque), and the 17020 * {@link android.R.attr#ambientShadowAlpha} theme attribute. 17021 * 17022 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 17023 * @param color The color this View will cast for its elevation shadow. 17024 */ setOutlineAmbientShadowColor(@olorInt int color)17025 public void setOutlineAmbientShadowColor(@ColorInt int color) { 17026 if (mRenderNode.setAmbientShadowColor(color)) { 17027 invalidateViewProperty(true, true); 17028 } 17029 } 17030 17031 /** 17032 * @return The shadow color set by {@link #setOutlineAmbientShadowColor(int)}, or black if 17033 * nothing was set 17034 */ 17035 @InspectableProperty getOutlineAmbientShadowColor()17036 public @ColorInt int getOutlineAmbientShadowColor() { 17037 return mRenderNode.getAmbientShadowColor(); 17038 } 17039 17040 17041 /** @hide */ setRevealClip(boolean shouldClip, float x, float y, float radius)17042 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 17043 mRenderNode.setRevealClip(shouldClip, x, y, radius); 17044 invalidateViewProperty(false, false); 17045 } 17046 17047 /** 17048 * Hit rectangle in parent's coordinates 17049 * 17050 * @param outRect The hit rectangle of the view. 17051 */ getHitRect(Rect outRect)17052 public void getHitRect(Rect outRect) { 17053 if (hasIdentityMatrix() || mAttachInfo == null) { 17054 outRect.set(mLeft, mTop, mRight, mBottom); 17055 } else { 17056 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 17057 tmpRect.set(0, 0, getWidth(), getHeight()); 17058 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 17059 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 17060 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 17061 } 17062 } 17063 17064 /** 17065 * Determines whether the given point, in local coordinates is inside the view. 17066 */ pointInView(float localX, float localY)17067 /*package*/ final boolean pointInView(float localX, float localY) { 17068 return pointInView(localX, localY, 0); 17069 } 17070 17071 /** 17072 * Utility method to determine whether the given point, in local coordinates, 17073 * is inside the view, where the area of the view is expanded by the slop factor. 17074 * This method is called while processing touch-move events to determine if the event 17075 * is still within the view. 17076 * 17077 * @hide 17078 */ 17079 @UnsupportedAppUsage pointInView(float localX, float localY, float slop)17080 public boolean pointInView(float localX, float localY, float slop) { 17081 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 17082 localY < ((mBottom - mTop) + slop); 17083 } 17084 17085 /** 17086 * When a view has focus and the user navigates away from it, the next view is searched for 17087 * starting from the rectangle filled in by this method. 17088 * 17089 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 17090 * of the view. However, if your view maintains some idea of internal selection, 17091 * such as a cursor, or a selected row or column, you should override this method and 17092 * fill in a more specific rectangle. 17093 * 17094 * @param r The rectangle to fill in, in this view's coordinates. 17095 */ getFocusedRect(Rect r)17096 public void getFocusedRect(Rect r) { 17097 getDrawingRect(r); 17098 } 17099 17100 /** 17101 * If some part of this view is not clipped by any of its parents, then 17102 * return that area in r in global (root) coordinates. To convert r to local 17103 * coordinates (without taking possible View rotations into account), offset 17104 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 17105 * If the view is completely clipped or translated out, return false. 17106 * 17107 * @param r If true is returned, r holds the global coordinates of the 17108 * visible portion of this view. 17109 * @param globalOffset If true is returned, globalOffset holds the dx,dy 17110 * between this view and its root. globalOffet may be null. 17111 * @return true if r is non-empty (i.e. part of the view is visible at the 17112 * root level. 17113 */ getGlobalVisibleRect(Rect r, Point globalOffset)17114 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 17115 int width = mRight - mLeft; 17116 int height = mBottom - mTop; 17117 if (width > 0 && height > 0) { 17118 r.set(0, 0, width, height); 17119 if (globalOffset != null) { 17120 globalOffset.set(-mScrollX, -mScrollY); 17121 } 17122 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 17123 } 17124 return false; 17125 } 17126 getGlobalVisibleRect(Rect r)17127 public final boolean getGlobalVisibleRect(Rect r) { 17128 return getGlobalVisibleRect(r, null); 17129 } 17130 getLocalVisibleRect(Rect r)17131 public final boolean getLocalVisibleRect(Rect r) { 17132 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 17133 if (getGlobalVisibleRect(r, offset)) { 17134 r.offset(-offset.x, -offset.y); // make r local 17135 return true; 17136 } 17137 return false; 17138 } 17139 17140 /** 17141 * Offset this view's vertical location by the specified number of pixels. 17142 * 17143 * @param offset the number of pixels to offset the view by 17144 */ offsetTopAndBottom(int offset)17145 public void offsetTopAndBottom(int offset) { 17146 if (offset != 0) { 17147 final boolean matrixIsIdentity = hasIdentityMatrix(); 17148 if (matrixIsIdentity) { 17149 if (isHardwareAccelerated()) { 17150 invalidateViewProperty(false, false); 17151 } else { 17152 final ViewParent p = mParent; 17153 if (p != null && mAttachInfo != null) { 17154 final Rect r = mAttachInfo.mTmpInvalRect; 17155 int minTop; 17156 int maxBottom; 17157 int yLoc; 17158 if (offset < 0) { 17159 minTop = mTop + offset; 17160 maxBottom = mBottom; 17161 yLoc = offset; 17162 } else { 17163 minTop = mTop; 17164 maxBottom = mBottom + offset; 17165 yLoc = 0; 17166 } 17167 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 17168 p.invalidateChild(this, r); 17169 } 17170 } 17171 } else { 17172 invalidateViewProperty(false, false); 17173 } 17174 17175 mTop += offset; 17176 mBottom += offset; 17177 mRenderNode.offsetTopAndBottom(offset); 17178 if (isHardwareAccelerated()) { 17179 invalidateViewProperty(false, false); 17180 invalidateParentIfNeededAndWasQuickRejected(); 17181 } else { 17182 if (!matrixIsIdentity) { 17183 invalidateViewProperty(false, true); 17184 } 17185 invalidateParentIfNeeded(); 17186 } 17187 notifySubtreeAccessibilityStateChangedIfNeeded(); 17188 } 17189 } 17190 17191 /** 17192 * Offset this view's horizontal location by the specified amount of pixels. 17193 * 17194 * @param offset the number of pixels to offset the view by 17195 */ offsetLeftAndRight(int offset)17196 public void offsetLeftAndRight(int offset) { 17197 if (offset != 0) { 17198 final boolean matrixIsIdentity = hasIdentityMatrix(); 17199 if (matrixIsIdentity) { 17200 if (isHardwareAccelerated()) { 17201 invalidateViewProperty(false, false); 17202 } else { 17203 final ViewParent p = mParent; 17204 if (p != null && mAttachInfo != null) { 17205 final Rect r = mAttachInfo.mTmpInvalRect; 17206 int minLeft; 17207 int maxRight; 17208 if (offset < 0) { 17209 minLeft = mLeft + offset; 17210 maxRight = mRight; 17211 } else { 17212 minLeft = mLeft; 17213 maxRight = mRight + offset; 17214 } 17215 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 17216 p.invalidateChild(this, r); 17217 } 17218 } 17219 } else { 17220 invalidateViewProperty(false, false); 17221 } 17222 17223 mLeft += offset; 17224 mRight += offset; 17225 mRenderNode.offsetLeftAndRight(offset); 17226 if (isHardwareAccelerated()) { 17227 invalidateViewProperty(false, false); 17228 invalidateParentIfNeededAndWasQuickRejected(); 17229 } else { 17230 if (!matrixIsIdentity) { 17231 invalidateViewProperty(false, true); 17232 } 17233 invalidateParentIfNeeded(); 17234 } 17235 notifySubtreeAccessibilityStateChangedIfNeeded(); 17236 } 17237 } 17238 17239 /** 17240 * Get the LayoutParams associated with this view. All views should have 17241 * layout parameters. These supply parameters to the <i>parent</i> of this 17242 * view specifying how it should be arranged. There are many subclasses of 17243 * ViewGroup.LayoutParams, and these correspond to the different subclasses 17244 * of ViewGroup that are responsible for arranging their children. 17245 * 17246 * This method may return null if this View is not attached to a parent 17247 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 17248 * was not invoked successfully. When a View is attached to a parent 17249 * ViewGroup, this method must not return null. 17250 * 17251 * @return The LayoutParams associated with this view, or null if no 17252 * parameters have been set yet 17253 */ 17254 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") getLayoutParams()17255 public ViewGroup.LayoutParams getLayoutParams() { 17256 return mLayoutParams; 17257 } 17258 17259 /** 17260 * Set the layout parameters associated with this view. These supply 17261 * parameters to the <i>parent</i> of this view specifying how it should be 17262 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 17263 * correspond to the different subclasses of ViewGroup that are responsible 17264 * for arranging their children. 17265 * 17266 * @param params The layout parameters for this view, cannot be null 17267 */ setLayoutParams(ViewGroup.LayoutParams params)17268 public void setLayoutParams(ViewGroup.LayoutParams params) { 17269 if (params == null) { 17270 throw new NullPointerException("Layout parameters cannot be null"); 17271 } 17272 mLayoutParams = params; 17273 resolveLayoutParams(); 17274 if (mParent instanceof ViewGroup) { 17275 ((ViewGroup) mParent).onSetLayoutParams(this, params); 17276 } 17277 requestLayout(); 17278 } 17279 17280 /** 17281 * Resolve the layout parameters depending on the resolved layout direction 17282 * 17283 * @hide 17284 */ resolveLayoutParams()17285 public void resolveLayoutParams() { 17286 if (mLayoutParams != null) { 17287 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 17288 } 17289 } 17290 17291 /** 17292 * Set the scrolled position of your view. This will cause a call to 17293 * {@link #onScrollChanged(int, int, int, int)} and the view will be 17294 * invalidated. 17295 * @param x the x position to scroll to 17296 * @param y the y position to scroll to 17297 */ scrollTo(int x, int y)17298 public void scrollTo(int x, int y) { 17299 if (mScrollX != x || mScrollY != y) { 17300 int oldX = mScrollX; 17301 int oldY = mScrollY; 17302 mScrollX = x; 17303 mScrollY = y; 17304 invalidateParentCaches(); 17305 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 17306 if (!awakenScrollBars()) { 17307 postInvalidateOnAnimation(); 17308 } 17309 } 17310 } 17311 17312 /** 17313 * Move the scrolled position of your view. This will cause a call to 17314 * {@link #onScrollChanged(int, int, int, int)} and the view will be 17315 * invalidated. 17316 * @param x the amount of pixels to scroll by horizontally 17317 * @param y the amount of pixels to scroll by vertically 17318 */ scrollBy(int x, int y)17319 public void scrollBy(int x, int y) { 17320 scrollTo(mScrollX + x, mScrollY + y); 17321 } 17322 17323 /** 17324 * <p>Trigger the scrollbars to draw. When invoked this method starts an 17325 * animation to fade the scrollbars out after a default delay. If a subclass 17326 * provides animated scrolling, the start delay should equal the duration 17327 * of the scrolling animation.</p> 17328 * 17329 * <p>The animation starts only if at least one of the scrollbars is 17330 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 17331 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 17332 * this method returns true, and false otherwise. If the animation is 17333 * started, this method calls {@link #invalidate()}; in that case the 17334 * caller should not call {@link #invalidate()}.</p> 17335 * 17336 * <p>This method should be invoked every time a subclass directly updates 17337 * the scroll parameters.</p> 17338 * 17339 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 17340 * and {@link #scrollTo(int, int)}.</p> 17341 * 17342 * @return true if the animation is played, false otherwise 17343 * 17344 * @see #awakenScrollBars(int) 17345 * @see #scrollBy(int, int) 17346 * @see #scrollTo(int, int) 17347 * @see #isHorizontalScrollBarEnabled() 17348 * @see #isVerticalScrollBarEnabled() 17349 * @see #setHorizontalScrollBarEnabled(boolean) 17350 * @see #setVerticalScrollBarEnabled(boolean) 17351 */ awakenScrollBars()17352 protected boolean awakenScrollBars() { 17353 return mScrollCache != null && 17354 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 17355 } 17356 17357 /** 17358 * Trigger the scrollbars to draw. 17359 * This method differs from awakenScrollBars() only in its default duration. 17360 * initialAwakenScrollBars() will show the scroll bars for longer than 17361 * usual to give the user more of a chance to notice them. 17362 * 17363 * @return true if the animation is played, false otherwise. 17364 */ initialAwakenScrollBars()17365 private boolean initialAwakenScrollBars() { 17366 return mScrollCache != null && 17367 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 17368 } 17369 17370 /** 17371 * <p> 17372 * Trigger the scrollbars to draw. When invoked this method starts an 17373 * animation to fade the scrollbars out after a fixed delay. If a subclass 17374 * provides animated scrolling, the start delay should equal the duration of 17375 * the scrolling animation. 17376 * </p> 17377 * 17378 * <p> 17379 * The animation starts only if at least one of the scrollbars is enabled, 17380 * as specified by {@link #isHorizontalScrollBarEnabled()} and 17381 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 17382 * this method returns true, and false otherwise. If the animation is 17383 * started, this method calls {@link #invalidate()}; in that case the caller 17384 * should not call {@link #invalidate()}. 17385 * </p> 17386 * 17387 * <p> 17388 * This method should be invoked every time a subclass directly updates the 17389 * scroll parameters. 17390 * </p> 17391 * 17392 * @param startDelay the delay, in milliseconds, after which the animation 17393 * should start; when the delay is 0, the animation starts 17394 * immediately 17395 * @return true if the animation is played, false otherwise 17396 * 17397 * @see #scrollBy(int, int) 17398 * @see #scrollTo(int, int) 17399 * @see #isHorizontalScrollBarEnabled() 17400 * @see #isVerticalScrollBarEnabled() 17401 * @see #setHorizontalScrollBarEnabled(boolean) 17402 * @see #setVerticalScrollBarEnabled(boolean) 17403 */ awakenScrollBars(int startDelay)17404 protected boolean awakenScrollBars(int startDelay) { 17405 return awakenScrollBars(startDelay, true); 17406 } 17407 17408 /** 17409 * <p> 17410 * Trigger the scrollbars to draw. When invoked this method starts an 17411 * animation to fade the scrollbars out after a fixed delay. If a subclass 17412 * provides animated scrolling, the start delay should equal the duration of 17413 * the scrolling animation. 17414 * </p> 17415 * 17416 * <p> 17417 * The animation starts only if at least one of the scrollbars is enabled, 17418 * as specified by {@link #isHorizontalScrollBarEnabled()} and 17419 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 17420 * this method returns true, and false otherwise. If the animation is 17421 * started, this method calls {@link #invalidate()} if the invalidate parameter 17422 * is set to true; in that case the caller 17423 * should not call {@link #invalidate()}. 17424 * </p> 17425 * 17426 * <p> 17427 * This method should be invoked every time a subclass directly updates the 17428 * scroll parameters. 17429 * </p> 17430 * 17431 * @param startDelay the delay, in milliseconds, after which the animation 17432 * should start; when the delay is 0, the animation starts 17433 * immediately 17434 * 17435 * @param invalidate Whether this method should call invalidate 17436 * 17437 * @return true if the animation is played, false otherwise 17438 * 17439 * @see #scrollBy(int, int) 17440 * @see #scrollTo(int, int) 17441 * @see #isHorizontalScrollBarEnabled() 17442 * @see #isVerticalScrollBarEnabled() 17443 * @see #setHorizontalScrollBarEnabled(boolean) 17444 * @see #setVerticalScrollBarEnabled(boolean) 17445 */ awakenScrollBars(int startDelay, boolean invalidate)17446 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 17447 final ScrollabilityCache scrollCache = mScrollCache; 17448 17449 if (scrollCache == null || !scrollCache.fadeScrollBars) { 17450 return false; 17451 } 17452 17453 if (scrollCache.scrollBar == null) { 17454 scrollCache.scrollBar = new ScrollBarDrawable(); 17455 scrollCache.scrollBar.setState(getDrawableState()); 17456 scrollCache.scrollBar.setCallback(this); 17457 } 17458 17459 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 17460 17461 if (invalidate) { 17462 // Invalidate to show the scrollbars 17463 postInvalidateOnAnimation(); 17464 } 17465 17466 if (scrollCache.state == ScrollabilityCache.OFF) { 17467 // FIXME: this is copied from WindowManagerService. 17468 // We should get this value from the system when it 17469 // is possible to do so. 17470 final int KEY_REPEAT_FIRST_DELAY = 750; 17471 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 17472 } 17473 17474 // Tell mScrollCache when we should start fading. This may 17475 // extend the fade start time if one was already scheduled 17476 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 17477 scrollCache.fadeStartTime = fadeStartTime; 17478 scrollCache.state = ScrollabilityCache.ON; 17479 17480 // Schedule our fader to run, unscheduling any old ones first 17481 if (mAttachInfo != null) { 17482 mAttachInfo.mHandler.removeCallbacks(scrollCache); 17483 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 17484 } 17485 17486 return true; 17487 } 17488 17489 return false; 17490 } 17491 17492 /** 17493 * Do not invalidate views which are not visible and which are not running an animation. They 17494 * will not get drawn and they should not set dirty flags as if they will be drawn 17495 */ skipInvalidate()17496 private boolean skipInvalidate() { 17497 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 17498 (!(mParent instanceof ViewGroup) || 17499 !((ViewGroup) mParent).isViewTransitioning(this)); 17500 } 17501 17502 /** 17503 * Mark the area defined by dirty as needing to be drawn. If the view is 17504 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 17505 * point in the future. 17506 * <p> 17507 * This must be called from a UI thread. To call from a non-UI thread, call 17508 * {@link #postInvalidate()}. 17509 * <p> 17510 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 17511 * {@code dirty}. 17512 * 17513 * @param dirty the rectangle representing the bounds of the dirty region 17514 * 17515 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 17516 * the importance of the dirty rectangle. In API 21 the given rectangle is 17517 * ignored entirely in favor of an internally-calculated area instead. 17518 * Because of this, clients are encouraged to just call {@link #invalidate()}. 17519 */ 17520 @Deprecated invalidate(Rect dirty)17521 public void invalidate(Rect dirty) { 17522 final int scrollX = mScrollX; 17523 final int scrollY = mScrollY; 17524 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 17525 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 17526 } 17527 17528 /** 17529 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 17530 * coordinates of the dirty rect are relative to the view. If the view is 17531 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 17532 * point in the future. 17533 * <p> 17534 * This must be called from a UI thread. To call from a non-UI thread, call 17535 * {@link #postInvalidate()}. 17536 * 17537 * @param l the left position of the dirty region 17538 * @param t the top position of the dirty region 17539 * @param r the right position of the dirty region 17540 * @param b the bottom position of the dirty region 17541 * 17542 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 17543 * the importance of the dirty rectangle. In API 21 the given rectangle is 17544 * ignored entirely in favor of an internally-calculated area instead. 17545 * Because of this, clients are encouraged to just call {@link #invalidate()}. 17546 */ 17547 @Deprecated invalidate(int l, int t, int r, int b)17548 public void invalidate(int l, int t, int r, int b) { 17549 final int scrollX = mScrollX; 17550 final int scrollY = mScrollY; 17551 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 17552 } 17553 17554 /** 17555 * Invalidate the whole view. If the view is visible, 17556 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 17557 * the future. 17558 * <p> 17559 * This must be called from a UI thread. To call from a non-UI thread, call 17560 * {@link #postInvalidate()}. 17561 */ invalidate()17562 public void invalidate() { 17563 invalidate(true); 17564 } 17565 17566 /** 17567 * This is where the invalidate() work actually happens. A full invalidate() 17568 * causes the drawing cache to be invalidated, but this function can be 17569 * called with invalidateCache set to false to skip that invalidation step 17570 * for cases that do not need it (for example, a component that remains at 17571 * the same dimensions with the same content). 17572 * 17573 * @param invalidateCache Whether the drawing cache for this view should be 17574 * invalidated as well. This is usually true for a full 17575 * invalidate, but may be set to false if the View's contents or 17576 * dimensions have not changed. 17577 * @hide 17578 */ 17579 @UnsupportedAppUsage invalidate(boolean invalidateCache)17580 public void invalidate(boolean invalidateCache) { 17581 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 17582 } 17583 invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate)17584 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 17585 boolean fullInvalidate) { 17586 if (mGhostView != null) { 17587 mGhostView.invalidate(true); 17588 return; 17589 } 17590 17591 if (skipInvalidate()) { 17592 return; 17593 } 17594 17595 // Reset content capture caches 17596 mCachedContentCaptureSession = null; 17597 17598 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 17599 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 17600 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 17601 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 17602 if (fullInvalidate) { 17603 mLastIsOpaque = isOpaque(); 17604 mPrivateFlags &= ~PFLAG_DRAWN; 17605 } 17606 17607 mPrivateFlags |= PFLAG_DIRTY; 17608 17609 if (invalidateCache) { 17610 mPrivateFlags |= PFLAG_INVALIDATED; 17611 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 17612 } 17613 17614 // Propagate the damage rectangle to the parent view. 17615 final AttachInfo ai = mAttachInfo; 17616 final ViewParent p = mParent; 17617 if (p != null && ai != null && l < r && t < b) { 17618 final Rect damage = ai.mTmpInvalRect; 17619 damage.set(l, t, r, b); 17620 p.invalidateChild(this, damage); 17621 } 17622 17623 // Damage the entire projection receiver, if necessary. 17624 if (mBackground != null && mBackground.isProjected()) { 17625 final View receiver = getProjectionReceiver(); 17626 if (receiver != null) { 17627 receiver.damageInParent(); 17628 } 17629 } 17630 } 17631 } 17632 17633 /** 17634 * @return this view's projection receiver, or {@code null} if none exists 17635 */ getProjectionReceiver()17636 private View getProjectionReceiver() { 17637 ViewParent p = getParent(); 17638 while (p != null && p instanceof View) { 17639 final View v = (View) p; 17640 if (v.isProjectionReceiver()) { 17641 return v; 17642 } 17643 p = p.getParent(); 17644 } 17645 17646 return null; 17647 } 17648 17649 /** 17650 * @return whether the view is a projection receiver 17651 */ isProjectionReceiver()17652 private boolean isProjectionReceiver() { 17653 return mBackground != null; 17654 } 17655 17656 /** 17657 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 17658 * set any flags or handle all of the cases handled by the default invalidation methods. 17659 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 17660 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 17661 * walk up the hierarchy, transforming the dirty rect as necessary. 17662 * 17663 * The method also handles normal invalidation logic if display list properties are not 17664 * being used in this view. The invalidateParent and forceRedraw flags are used by that 17665 * backup approach, to handle these cases used in the various property-setting methods. 17666 * 17667 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 17668 * are not being used in this view 17669 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 17670 * list properties are not being used in this view 17671 */ 17672 @UnsupportedAppUsage invalidateViewProperty(boolean invalidateParent, boolean forceRedraw)17673 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 17674 if (!isHardwareAccelerated() 17675 || !mRenderNode.hasDisplayList() 17676 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 17677 if (invalidateParent) { 17678 invalidateParentCaches(); 17679 } 17680 if (forceRedraw) { 17681 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 17682 } 17683 invalidate(false); 17684 } else { 17685 damageInParent(); 17686 } 17687 } 17688 17689 /** 17690 * Tells the parent view to damage this view's bounds. 17691 * 17692 * @hide 17693 */ damageInParent()17694 protected void damageInParent() { 17695 if (mParent != null && mAttachInfo != null) { 17696 mParent.onDescendantInvalidated(this, this); 17697 } 17698 } 17699 17700 /** 17701 * Used to indicate that the parent of this view should clear its caches. This functionality 17702 * is used to force the parent to rebuild its display list (when hardware-accelerated), 17703 * which is necessary when various parent-managed properties of the view change, such as 17704 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 17705 * clears the parent caches and does not causes an invalidate event. 17706 * 17707 * @hide 17708 */ 17709 @UnsupportedAppUsage invalidateParentCaches()17710 protected void invalidateParentCaches() { 17711 if (mParent instanceof View) { 17712 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 17713 } 17714 } 17715 17716 /** 17717 * Used to indicate that the parent of this view should be invalidated. This functionality 17718 * is used to force the parent to rebuild its display list (when hardware-accelerated), 17719 * which is necessary when various parent-managed properties of the view change, such as 17720 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 17721 * an invalidation event to the parent. 17722 * 17723 * @hide 17724 */ 17725 @UnsupportedAppUsage invalidateParentIfNeeded()17726 protected void invalidateParentIfNeeded() { 17727 if (isHardwareAccelerated() && mParent instanceof View) { 17728 ((View) mParent).invalidate(true); 17729 } 17730 } 17731 17732 /** 17733 * @hide 17734 */ invalidateParentIfNeededAndWasQuickRejected()17735 protected void invalidateParentIfNeededAndWasQuickRejected() { 17736 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 17737 // View was rejected last time it was drawn by its parent; this may have changed 17738 invalidateParentIfNeeded(); 17739 } 17740 } 17741 17742 /** 17743 * Indicates whether this View is opaque. An opaque View guarantees that it will 17744 * draw all the pixels overlapping its bounds using a fully opaque color. 17745 * 17746 * Subclasses of View should override this method whenever possible to indicate 17747 * whether an instance is opaque. Opaque Views are treated in a special way by 17748 * the View hierarchy, possibly allowing it to perform optimizations during 17749 * invalidate/draw passes. 17750 * 17751 * @return True if this View is guaranteed to be fully opaque, false otherwise. 17752 */ 17753 @ViewDebug.ExportedProperty(category = "drawing") isOpaque()17754 public boolean isOpaque() { 17755 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 17756 getFinalAlpha() >= 1.0f; 17757 } 17758 17759 /** 17760 * @hide 17761 */ 17762 @UnsupportedAppUsage computeOpaqueFlags()17763 protected void computeOpaqueFlags() { 17764 // Opaque if: 17765 // - Has a background 17766 // - Background is opaque 17767 // - Doesn't have scrollbars or scrollbars overlay 17768 17769 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 17770 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 17771 } else { 17772 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 17773 } 17774 17775 final int flags = mViewFlags; 17776 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 17777 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 17778 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 17779 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 17780 } else { 17781 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 17782 } 17783 } 17784 17785 /** 17786 * @hide 17787 */ hasOpaqueScrollbars()17788 protected boolean hasOpaqueScrollbars() { 17789 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 17790 } 17791 17792 /** 17793 * @return A handler associated with the thread running the View. This 17794 * handler can be used to pump events in the UI events queue. 17795 */ getHandler()17796 public Handler getHandler() { 17797 final AttachInfo attachInfo = mAttachInfo; 17798 if (attachInfo != null) { 17799 return attachInfo.mHandler; 17800 } 17801 return null; 17802 } 17803 17804 /** 17805 * Returns the queue of runnable for this view. 17806 * 17807 * @return the queue of runnables for this view 17808 */ getRunQueue()17809 private HandlerActionQueue getRunQueue() { 17810 if (mRunQueue == null) { 17811 mRunQueue = new HandlerActionQueue(); 17812 } 17813 return mRunQueue; 17814 } 17815 17816 /** 17817 * Gets the view root associated with the View. 17818 * @return The view root, or null if none. 17819 * @hide 17820 */ 17821 @UnsupportedAppUsage getViewRootImpl()17822 public ViewRootImpl getViewRootImpl() { 17823 if (mAttachInfo != null) { 17824 return mAttachInfo.mViewRootImpl; 17825 } 17826 return null; 17827 } 17828 17829 /** 17830 * @hide 17831 */ 17832 @UnsupportedAppUsage getThreadedRenderer()17833 public ThreadedRenderer getThreadedRenderer() { 17834 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 17835 } 17836 17837 /** 17838 * <p>Causes the Runnable to be added to the message queue. 17839 * The runnable will be run on the user interface thread.</p> 17840 * 17841 * @param action The Runnable that will be executed. 17842 * 17843 * @return Returns true if the Runnable was successfully placed in to the 17844 * message queue. Returns false on failure, usually because the 17845 * looper processing the message queue is exiting. 17846 * 17847 * @see #postDelayed 17848 * @see #removeCallbacks 17849 */ post(Runnable action)17850 public boolean post(Runnable action) { 17851 final AttachInfo attachInfo = mAttachInfo; 17852 if (attachInfo != null) { 17853 return attachInfo.mHandler.post(action); 17854 } 17855 17856 // Postpone the runnable until we know on which thread it needs to run. 17857 // Assume that the runnable will be successfully placed after attach. 17858 getRunQueue().post(action); 17859 return true; 17860 } 17861 17862 /** 17863 * <p>Causes the Runnable to be added to the message queue, to be run 17864 * after the specified amount of time elapses. 17865 * The runnable will be run on the user interface thread.</p> 17866 * 17867 * @param action The Runnable that will be executed. 17868 * @param delayMillis The delay (in milliseconds) until the Runnable 17869 * will be executed. 17870 * 17871 * @return true if the Runnable was successfully placed in to the 17872 * message queue. Returns false on failure, usually because the 17873 * looper processing the message queue is exiting. Note that a 17874 * result of true does not mean the Runnable will be processed -- 17875 * if the looper is quit before the delivery time of the message 17876 * occurs then the message will be dropped. 17877 * 17878 * @see #post 17879 * @see #removeCallbacks 17880 */ postDelayed(Runnable action, long delayMillis)17881 public boolean postDelayed(Runnable action, long delayMillis) { 17882 final AttachInfo attachInfo = mAttachInfo; 17883 if (attachInfo != null) { 17884 return attachInfo.mHandler.postDelayed(action, delayMillis); 17885 } 17886 17887 // Postpone the runnable until we know on which thread it needs to run. 17888 // Assume that the runnable will be successfully placed after attach. 17889 getRunQueue().postDelayed(action, delayMillis); 17890 return true; 17891 } 17892 17893 /** 17894 * <p>Causes the Runnable to execute on the next animation time step. 17895 * The runnable will be run on the user interface thread.</p> 17896 * 17897 * @param action The Runnable that will be executed. 17898 * 17899 * @see #postOnAnimationDelayed 17900 * @see #removeCallbacks 17901 */ postOnAnimation(Runnable action)17902 public void postOnAnimation(Runnable action) { 17903 final AttachInfo attachInfo = mAttachInfo; 17904 if (attachInfo != null) { 17905 attachInfo.mViewRootImpl.mChoreographer.postCallback( 17906 Choreographer.CALLBACK_ANIMATION, action, null); 17907 } else { 17908 // Postpone the runnable until we know 17909 // on which thread it needs to run. 17910 getRunQueue().post(action); 17911 } 17912 } 17913 17914 /** 17915 * <p>Causes the Runnable to execute on the next animation time step, 17916 * after the specified amount of time elapses. 17917 * The runnable will be run on the user interface thread.</p> 17918 * 17919 * @param action The Runnable that will be executed. 17920 * @param delayMillis The delay (in milliseconds) until the Runnable 17921 * will be executed. 17922 * 17923 * @see #postOnAnimation 17924 * @see #removeCallbacks 17925 */ postOnAnimationDelayed(Runnable action, long delayMillis)17926 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 17927 final AttachInfo attachInfo = mAttachInfo; 17928 if (attachInfo != null) { 17929 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 17930 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 17931 } else { 17932 // Postpone the runnable until we know 17933 // on which thread it needs to run. 17934 getRunQueue().postDelayed(action, delayMillis); 17935 } 17936 } 17937 17938 /** 17939 * <p>Removes the specified Runnable from the message queue.</p> 17940 * 17941 * @param action The Runnable to remove from the message handling queue 17942 * 17943 * @return true if this view could ask the Handler to remove the Runnable, 17944 * false otherwise. When the returned value is true, the Runnable 17945 * may or may not have been actually removed from the message queue 17946 * (for instance, if the Runnable was not in the queue already.) 17947 * 17948 * @see #post 17949 * @see #postDelayed 17950 * @see #postOnAnimation 17951 * @see #postOnAnimationDelayed 17952 */ removeCallbacks(Runnable action)17953 public boolean removeCallbacks(Runnable action) { 17954 if (action != null) { 17955 final AttachInfo attachInfo = mAttachInfo; 17956 if (attachInfo != null) { 17957 attachInfo.mHandler.removeCallbacks(action); 17958 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 17959 Choreographer.CALLBACK_ANIMATION, action, null); 17960 } 17961 getRunQueue().removeCallbacks(action); 17962 } 17963 return true; 17964 } 17965 17966 /** 17967 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 17968 * Use this to invalidate the View from a non-UI thread.</p> 17969 * 17970 * <p>This method can be invoked from outside of the UI thread 17971 * only when this View is attached to a window.</p> 17972 * 17973 * @see #invalidate() 17974 * @see #postInvalidateDelayed(long) 17975 */ postInvalidate()17976 public void postInvalidate() { 17977 postInvalidateDelayed(0); 17978 } 17979 17980 /** 17981 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 17982 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 17983 * 17984 * <p>This method can be invoked from outside of the UI thread 17985 * only when this View is attached to a window.</p> 17986 * 17987 * @param left The left coordinate of the rectangle to invalidate. 17988 * @param top The top coordinate of the rectangle to invalidate. 17989 * @param right The right coordinate of the rectangle to invalidate. 17990 * @param bottom The bottom coordinate of the rectangle to invalidate. 17991 * 17992 * @see #invalidate(int, int, int, int) 17993 * @see #invalidate(Rect) 17994 * @see #postInvalidateDelayed(long, int, int, int, int) 17995 */ postInvalidate(int left, int top, int right, int bottom)17996 public void postInvalidate(int left, int top, int right, int bottom) { 17997 postInvalidateDelayed(0, left, top, right, bottom); 17998 } 17999 18000 /** 18001 * <p>Cause an invalidate to happen on a subsequent cycle through the event 18002 * loop. Waits for the specified amount of time.</p> 18003 * 18004 * <p>This method can be invoked from outside of the UI thread 18005 * only when this View is attached to a window.</p> 18006 * 18007 * @param delayMilliseconds the duration in milliseconds to delay the 18008 * invalidation by 18009 * 18010 * @see #invalidate() 18011 * @see #postInvalidate() 18012 */ postInvalidateDelayed(long delayMilliseconds)18013 public void postInvalidateDelayed(long delayMilliseconds) { 18014 // We try only with the AttachInfo because there's no point in invalidating 18015 // if we are not attached to our window 18016 final AttachInfo attachInfo = mAttachInfo; 18017 if (attachInfo != null) { 18018 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 18019 } 18020 } 18021 18022 /** 18023 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 18024 * through the event loop. Waits for the specified amount of time.</p> 18025 * 18026 * <p>This method can be invoked from outside of the UI thread 18027 * only when this View is attached to a window.</p> 18028 * 18029 * @param delayMilliseconds the duration in milliseconds to delay the 18030 * invalidation by 18031 * @param left The left coordinate of the rectangle to invalidate. 18032 * @param top The top coordinate of the rectangle to invalidate. 18033 * @param right The right coordinate of the rectangle to invalidate. 18034 * @param bottom The bottom coordinate of the rectangle to invalidate. 18035 * 18036 * @see #invalidate(int, int, int, int) 18037 * @see #invalidate(Rect) 18038 * @see #postInvalidate(int, int, int, int) 18039 */ postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom)18040 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 18041 int right, int bottom) { 18042 18043 // We try only with the AttachInfo because there's no point in invalidating 18044 // if we are not attached to our window 18045 final AttachInfo attachInfo = mAttachInfo; 18046 if (attachInfo != null) { 18047 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 18048 info.target = this; 18049 info.left = left; 18050 info.top = top; 18051 info.right = right; 18052 info.bottom = bottom; 18053 18054 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 18055 } 18056 } 18057 18058 /** 18059 * <p>Cause an invalidate to happen on the next animation time step, typically the 18060 * next display frame.</p> 18061 * 18062 * <p>This method can be invoked from outside of the UI thread 18063 * only when this View is attached to a window.</p> 18064 * 18065 * @see #invalidate() 18066 */ postInvalidateOnAnimation()18067 public void postInvalidateOnAnimation() { 18068 // We try only with the AttachInfo because there's no point in invalidating 18069 // if we are not attached to our window 18070 final AttachInfo attachInfo = mAttachInfo; 18071 if (attachInfo != null) { 18072 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 18073 } 18074 } 18075 18076 /** 18077 * <p>Cause an invalidate of the specified area to happen on the next animation 18078 * time step, typically the next display frame.</p> 18079 * 18080 * <p>This method can be invoked from outside of the UI thread 18081 * only when this View is attached to a window.</p> 18082 * 18083 * @param left The left coordinate of the rectangle to invalidate. 18084 * @param top The top coordinate of the rectangle to invalidate. 18085 * @param right The right coordinate of the rectangle to invalidate. 18086 * @param bottom The bottom coordinate of the rectangle to invalidate. 18087 * 18088 * @see #invalidate(int, int, int, int) 18089 * @see #invalidate(Rect) 18090 */ postInvalidateOnAnimation(int left, int top, int right, int bottom)18091 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 18092 // We try only with the AttachInfo because there's no point in invalidating 18093 // if we are not attached to our window 18094 final AttachInfo attachInfo = mAttachInfo; 18095 if (attachInfo != null) { 18096 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 18097 info.target = this; 18098 info.left = left; 18099 info.top = top; 18100 info.right = right; 18101 info.bottom = bottom; 18102 18103 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 18104 } 18105 } 18106 18107 /** 18108 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 18109 * This event is sent at most once every 18110 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 18111 */ postSendViewScrolledAccessibilityEventCallback(int dx, int dy)18112 private void postSendViewScrolledAccessibilityEventCallback(int dx, int dy) { 18113 if (mSendViewScrolledAccessibilityEvent == null) { 18114 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 18115 } 18116 mSendViewScrolledAccessibilityEvent.post(dx, dy); 18117 } 18118 18119 /** 18120 * Called by a parent to request that a child update its values for mScrollX 18121 * and mScrollY if necessary. This will typically be done if the child is 18122 * animating a scroll using a {@link android.widget.Scroller Scroller} 18123 * object. 18124 */ computeScroll()18125 public void computeScroll() { 18126 } 18127 18128 /** 18129 * <p>Indicate whether the horizontal edges are faded when the view is 18130 * scrolled horizontally.</p> 18131 * 18132 * @return true if the horizontal edges should are faded on scroll, false 18133 * otherwise 18134 * 18135 * @see #setHorizontalFadingEdgeEnabled(boolean) 18136 * 18137 * @attr ref android.R.styleable#View_requiresFadingEdge 18138 */ isHorizontalFadingEdgeEnabled()18139 public boolean isHorizontalFadingEdgeEnabled() { 18140 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 18141 } 18142 18143 /** 18144 * <p>Define whether the horizontal edges should be faded when this view 18145 * is scrolled horizontally.</p> 18146 * 18147 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 18148 * be faded when the view is scrolled 18149 * horizontally 18150 * 18151 * @see #isHorizontalFadingEdgeEnabled() 18152 * 18153 * @attr ref android.R.styleable#View_requiresFadingEdge 18154 */ setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled)18155 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 18156 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 18157 if (horizontalFadingEdgeEnabled) { 18158 initScrollCache(); 18159 } 18160 18161 mViewFlags ^= FADING_EDGE_HORIZONTAL; 18162 } 18163 } 18164 18165 /** 18166 * <p>Indicate whether the vertical edges are faded when the view is 18167 * scrolled horizontally.</p> 18168 * 18169 * @return true if the vertical edges should are faded on scroll, false 18170 * otherwise 18171 * 18172 * @see #setVerticalFadingEdgeEnabled(boolean) 18173 * 18174 * @attr ref android.R.styleable#View_requiresFadingEdge 18175 */ isVerticalFadingEdgeEnabled()18176 public boolean isVerticalFadingEdgeEnabled() { 18177 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 18178 } 18179 18180 /** 18181 * <p>Define whether the vertical edges should be faded when this view 18182 * is scrolled vertically.</p> 18183 * 18184 * @param verticalFadingEdgeEnabled true if the vertical edges should 18185 * be faded when the view is scrolled 18186 * vertically 18187 * 18188 * @see #isVerticalFadingEdgeEnabled() 18189 * 18190 * @attr ref android.R.styleable#View_requiresFadingEdge 18191 */ setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled)18192 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 18193 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 18194 if (verticalFadingEdgeEnabled) { 18195 initScrollCache(); 18196 } 18197 18198 mViewFlags ^= FADING_EDGE_VERTICAL; 18199 } 18200 } 18201 18202 /** 18203 * Get the fading edge flags, used for inspection. 18204 * 18205 * @return One of {@link #FADING_EDGE_NONE}, {@link #FADING_EDGE_VERTICAL}, 18206 * or {@link #FADING_EDGE_HORIZONTAL} 18207 * @hide 18208 */ 18209 @InspectableProperty(name = "requiresFadingEdge", flagMapping = { 18210 @FlagEntry(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"), 18211 @FlagEntry(target = FADING_EDGE_VERTICAL, name = "vertical"), 18212 @FlagEntry(target = FADING_EDGE_HORIZONTAL, name = "horizontal") 18213 }) getFadingEdge()18214 public int getFadingEdge() { 18215 return mViewFlags & FADING_EDGE_MASK; 18216 } 18217 18218 /** 18219 * Get the fading edge length, used for inspection 18220 * 18221 * @return The fading edge length or 0 18222 * @hide 18223 */ 18224 @InspectableProperty getFadingEdgeLength()18225 public int getFadingEdgeLength() { 18226 if (mScrollCache != null && (mViewFlags & FADING_EDGE_MASK) != FADING_EDGE_NONE) { 18227 return mScrollCache.fadingEdgeLength; 18228 } 18229 return 0; 18230 } 18231 18232 /** 18233 * Returns the strength, or intensity, of the top faded edge. The strength is 18234 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 18235 * returns 0.0 or 1.0 but no value in between. 18236 * 18237 * Subclasses should override this method to provide a smoother fade transition 18238 * when scrolling occurs. 18239 * 18240 * @return the intensity of the top fade as a float between 0.0f and 1.0f 18241 */ getTopFadingEdgeStrength()18242 protected float getTopFadingEdgeStrength() { 18243 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 18244 } 18245 18246 /** 18247 * Returns the strength, or intensity, of the bottom faded edge. The strength is 18248 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 18249 * returns 0.0 or 1.0 but no value in between. 18250 * 18251 * Subclasses should override this method to provide a smoother fade transition 18252 * when scrolling occurs. 18253 * 18254 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 18255 */ getBottomFadingEdgeStrength()18256 protected float getBottomFadingEdgeStrength() { 18257 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 18258 computeVerticalScrollRange() ? 1.0f : 0.0f; 18259 } 18260 18261 /** 18262 * Returns the strength, or intensity, of the left faded edge. The strength is 18263 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 18264 * returns 0.0 or 1.0 but no value in between. 18265 * 18266 * Subclasses should override this method to provide a smoother fade transition 18267 * when scrolling occurs. 18268 * 18269 * @return the intensity of the left fade as a float between 0.0f and 1.0f 18270 */ getLeftFadingEdgeStrength()18271 protected float getLeftFadingEdgeStrength() { 18272 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 18273 } 18274 18275 /** 18276 * Returns the strength, or intensity, of the right faded edge. The strength is 18277 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 18278 * returns 0.0 or 1.0 but no value in between. 18279 * 18280 * Subclasses should override this method to provide a smoother fade transition 18281 * when scrolling occurs. 18282 * 18283 * @return the intensity of the right fade as a float between 0.0f and 1.0f 18284 */ getRightFadingEdgeStrength()18285 protected float getRightFadingEdgeStrength() { 18286 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 18287 computeHorizontalScrollRange() ? 1.0f : 0.0f; 18288 } 18289 18290 /** 18291 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 18292 * scrollbar is not drawn by default.</p> 18293 * 18294 * @return true if the horizontal scrollbar should be painted, false 18295 * otherwise 18296 * 18297 * @see #setHorizontalScrollBarEnabled(boolean) 18298 */ isHorizontalScrollBarEnabled()18299 public boolean isHorizontalScrollBarEnabled() { 18300 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 18301 } 18302 18303 /** 18304 * <p>Define whether the horizontal scrollbar should be drawn or not. The 18305 * scrollbar is not drawn by default.</p> 18306 * 18307 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 18308 * be painted 18309 * 18310 * @see #isHorizontalScrollBarEnabled() 18311 */ setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled)18312 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 18313 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 18314 mViewFlags ^= SCROLLBARS_HORIZONTAL; 18315 computeOpaqueFlags(); 18316 resolvePadding(); 18317 } 18318 } 18319 18320 /** 18321 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 18322 * scrollbar is not drawn by default.</p> 18323 * 18324 * @return true if the vertical scrollbar should be painted, false 18325 * otherwise 18326 * 18327 * @see #setVerticalScrollBarEnabled(boolean) 18328 */ isVerticalScrollBarEnabled()18329 public boolean isVerticalScrollBarEnabled() { 18330 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 18331 } 18332 18333 /** 18334 * <p>Define whether the vertical scrollbar should be drawn or not. The 18335 * scrollbar is not drawn by default.</p> 18336 * 18337 * @param verticalScrollBarEnabled true if the vertical scrollbar should 18338 * be painted 18339 * 18340 * @see #isVerticalScrollBarEnabled() 18341 */ setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled)18342 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 18343 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 18344 mViewFlags ^= SCROLLBARS_VERTICAL; 18345 computeOpaqueFlags(); 18346 resolvePadding(); 18347 } 18348 } 18349 18350 /** 18351 * @hide 18352 */ 18353 @UnsupportedAppUsage recomputePadding()18354 protected void recomputePadding() { 18355 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 18356 } 18357 18358 /** 18359 * Define whether scrollbars will fade when the view is not scrolling. 18360 * 18361 * @param fadeScrollbars whether to enable fading 18362 * 18363 * @attr ref android.R.styleable#View_fadeScrollbars 18364 */ setScrollbarFadingEnabled(boolean fadeScrollbars)18365 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 18366 initScrollCache(); 18367 final ScrollabilityCache scrollabilityCache = mScrollCache; 18368 scrollabilityCache.fadeScrollBars = fadeScrollbars; 18369 if (fadeScrollbars) { 18370 scrollabilityCache.state = ScrollabilityCache.OFF; 18371 } else { 18372 scrollabilityCache.state = ScrollabilityCache.ON; 18373 } 18374 } 18375 18376 /** 18377 * 18378 * Returns true if scrollbars will fade when this view is not scrolling 18379 * 18380 * @return true if scrollbar fading is enabled 18381 * 18382 * @attr ref android.R.styleable#View_fadeScrollbars 18383 */ isScrollbarFadingEnabled()18384 public boolean isScrollbarFadingEnabled() { 18385 return mScrollCache != null && mScrollCache.fadeScrollBars; 18386 } 18387 18388 /** 18389 * 18390 * Returns the delay before scrollbars fade. 18391 * 18392 * @return the delay before scrollbars fade 18393 * 18394 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 18395 */ 18396 @InspectableProperty(name = "scrollbarDefaultDelayBeforeFade") getScrollBarDefaultDelayBeforeFade()18397 public int getScrollBarDefaultDelayBeforeFade() { 18398 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 18399 mScrollCache.scrollBarDefaultDelayBeforeFade; 18400 } 18401 18402 /** 18403 * Define the delay before scrollbars fade. 18404 * 18405 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 18406 * 18407 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 18408 */ setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade)18409 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 18410 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 18411 } 18412 18413 /** 18414 * 18415 * Returns the scrollbar fade duration. 18416 * 18417 * @return the scrollbar fade duration, in milliseconds 18418 * 18419 * @attr ref android.R.styleable#View_scrollbarFadeDuration 18420 */ 18421 @InspectableProperty(name = "scrollbarFadeDuration") getScrollBarFadeDuration()18422 public int getScrollBarFadeDuration() { 18423 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 18424 mScrollCache.scrollBarFadeDuration; 18425 } 18426 18427 /** 18428 * Define the scrollbar fade duration. 18429 * 18430 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 18431 * 18432 * @attr ref android.R.styleable#View_scrollbarFadeDuration 18433 */ setScrollBarFadeDuration(int scrollBarFadeDuration)18434 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 18435 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 18436 } 18437 18438 /** 18439 * 18440 * Returns the scrollbar size. 18441 * 18442 * @return the scrollbar size 18443 * 18444 * @attr ref android.R.styleable#View_scrollbarSize 18445 */ 18446 @InspectableProperty(name = "scrollbarSize") getScrollBarSize()18447 public int getScrollBarSize() { 18448 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 18449 mScrollCache.scrollBarSize; 18450 } 18451 18452 /** 18453 * Define the scrollbar size. 18454 * 18455 * @param scrollBarSize - the scrollbar size 18456 * 18457 * @attr ref android.R.styleable#View_scrollbarSize 18458 */ setScrollBarSize(int scrollBarSize)18459 public void setScrollBarSize(int scrollBarSize) { 18460 getScrollCache().scrollBarSize = scrollBarSize; 18461 } 18462 18463 /** 18464 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 18465 * inset. When inset, they add to the padding of the view. And the scrollbars 18466 * can be drawn inside the padding area or on the edge of the view. For example, 18467 * if a view has a background drawable and you want to draw the scrollbars 18468 * inside the padding specified by the drawable, you can use 18469 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 18470 * appear at the edge of the view, ignoring the padding, then you can use 18471 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 18472 * @param style the style of the scrollbars. Should be one of 18473 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 18474 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 18475 * @see #SCROLLBARS_INSIDE_OVERLAY 18476 * @see #SCROLLBARS_INSIDE_INSET 18477 * @see #SCROLLBARS_OUTSIDE_OVERLAY 18478 * @see #SCROLLBARS_OUTSIDE_INSET 18479 * 18480 * @attr ref android.R.styleable#View_scrollbarStyle 18481 */ setScrollBarStyle(@crollBarStyle int style)18482 public void setScrollBarStyle(@ScrollBarStyle int style) { 18483 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 18484 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 18485 computeOpaqueFlags(); 18486 resolvePadding(); 18487 } 18488 } 18489 18490 /** 18491 * <p>Returns the current scrollbar style.</p> 18492 * @return the current scrollbar style 18493 * @see #SCROLLBARS_INSIDE_OVERLAY 18494 * @see #SCROLLBARS_INSIDE_INSET 18495 * @see #SCROLLBARS_OUTSIDE_OVERLAY 18496 * @see #SCROLLBARS_OUTSIDE_INSET 18497 * 18498 * @attr ref android.R.styleable#View_scrollbarStyle 18499 */ 18500 @ViewDebug.ExportedProperty(mapping = { 18501 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 18502 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 18503 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 18504 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 18505 }) 18506 @InspectableProperty(name = "scrollbarStyle", enumMapping = { 18507 @EnumEntry(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"), 18508 @EnumEntry(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"), 18509 @EnumEntry(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"), 18510 @EnumEntry(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset") 18511 }) 18512 @ScrollBarStyle getScrollBarStyle()18513 public int getScrollBarStyle() { 18514 return mViewFlags & SCROLLBARS_STYLE_MASK; 18515 } 18516 18517 /** 18518 * <p>Compute the horizontal range that the horizontal scrollbar 18519 * represents.</p> 18520 * 18521 * <p>The range is expressed in arbitrary units that must be the same as the 18522 * units used by {@link #computeHorizontalScrollExtent()} and 18523 * {@link #computeHorizontalScrollOffset()}.</p> 18524 * 18525 * <p>The default range is the drawing width of this view.</p> 18526 * 18527 * @return the total horizontal range represented by the horizontal 18528 * scrollbar 18529 * 18530 * @see #computeHorizontalScrollExtent() 18531 * @see #computeHorizontalScrollOffset() 18532 */ computeHorizontalScrollRange()18533 protected int computeHorizontalScrollRange() { 18534 return getWidth(); 18535 } 18536 18537 /** 18538 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 18539 * within the horizontal range. This value is used to compute the position 18540 * of the thumb within the scrollbar's track.</p> 18541 * 18542 * <p>The range is expressed in arbitrary units that must be the same as the 18543 * units used by {@link #computeHorizontalScrollRange()} and 18544 * {@link #computeHorizontalScrollExtent()}.</p> 18545 * 18546 * <p>The default offset is the scroll offset of this view.</p> 18547 * 18548 * @return the horizontal offset of the scrollbar's thumb 18549 * 18550 * @see #computeHorizontalScrollRange() 18551 * @see #computeHorizontalScrollExtent() 18552 */ computeHorizontalScrollOffset()18553 protected int computeHorizontalScrollOffset() { 18554 return mScrollX; 18555 } 18556 18557 /** 18558 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 18559 * within the horizontal range. This value is used to compute the length 18560 * of the thumb within the scrollbar's track.</p> 18561 * 18562 * <p>The range is expressed in arbitrary units that must be the same as the 18563 * units used by {@link #computeHorizontalScrollRange()} and 18564 * {@link #computeHorizontalScrollOffset()}.</p> 18565 * 18566 * <p>The default extent is the drawing width of this view.</p> 18567 * 18568 * @return the horizontal extent of the scrollbar's thumb 18569 * 18570 * @see #computeHorizontalScrollRange() 18571 * @see #computeHorizontalScrollOffset() 18572 */ computeHorizontalScrollExtent()18573 protected int computeHorizontalScrollExtent() { 18574 return getWidth(); 18575 } 18576 18577 /** 18578 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 18579 * 18580 * <p>The range is expressed in arbitrary units that must be the same as the 18581 * units used by {@link #computeVerticalScrollExtent()} and 18582 * {@link #computeVerticalScrollOffset()}.</p> 18583 * 18584 * @return the total vertical range represented by the vertical scrollbar 18585 * 18586 * <p>The default range is the drawing height of this view.</p> 18587 * 18588 * @see #computeVerticalScrollExtent() 18589 * @see #computeVerticalScrollOffset() 18590 */ computeVerticalScrollRange()18591 protected int computeVerticalScrollRange() { 18592 return getHeight(); 18593 } 18594 18595 /** 18596 * <p>Compute the vertical offset of the vertical scrollbar's thumb 18597 * within the horizontal range. This value is used to compute the position 18598 * of the thumb within the scrollbar's track.</p> 18599 * 18600 * <p>The range is expressed in arbitrary units that must be the same as the 18601 * units used by {@link #computeVerticalScrollRange()} and 18602 * {@link #computeVerticalScrollExtent()}.</p> 18603 * 18604 * <p>The default offset is the scroll offset of this view.</p> 18605 * 18606 * @return the vertical offset of the scrollbar's thumb 18607 * 18608 * @see #computeVerticalScrollRange() 18609 * @see #computeVerticalScrollExtent() 18610 */ computeVerticalScrollOffset()18611 protected int computeVerticalScrollOffset() { 18612 return mScrollY; 18613 } 18614 18615 /** 18616 * <p>Compute the vertical extent of the vertical scrollbar's thumb 18617 * within the vertical range. This value is used to compute the length 18618 * of the thumb within the scrollbar's track.</p> 18619 * 18620 * <p>The range is expressed in arbitrary units that must be the same as the 18621 * units used by {@link #computeVerticalScrollRange()} and 18622 * {@link #computeVerticalScrollOffset()}.</p> 18623 * 18624 * <p>The default extent is the drawing height of this view.</p> 18625 * 18626 * @return the vertical extent of the scrollbar's thumb 18627 * 18628 * @see #computeVerticalScrollRange() 18629 * @see #computeVerticalScrollOffset() 18630 */ computeVerticalScrollExtent()18631 protected int computeVerticalScrollExtent() { 18632 return getHeight(); 18633 } 18634 18635 /** 18636 * Check if this view can be scrolled horizontally in a certain direction. 18637 * 18638 * @param direction Negative to check scrolling left, positive to check scrolling right. 18639 * @return true if this view can be scrolled in the specified direction, false otherwise. 18640 */ canScrollHorizontally(int direction)18641 public boolean canScrollHorizontally(int direction) { 18642 final int offset = computeHorizontalScrollOffset(); 18643 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 18644 if (range == 0) return false; 18645 if (direction < 0) { 18646 return offset > 0; 18647 } else { 18648 return offset < range - 1; 18649 } 18650 } 18651 18652 /** 18653 * Check if this view can be scrolled vertically in a certain direction. 18654 * 18655 * @param direction Negative to check scrolling up, positive to check scrolling down. 18656 * @return true if this view can be scrolled in the specified direction, false otherwise. 18657 */ canScrollVertically(int direction)18658 public boolean canScrollVertically(int direction) { 18659 final int offset = computeVerticalScrollOffset(); 18660 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 18661 if (range == 0) return false; 18662 if (direction < 0) { 18663 return offset > 0; 18664 } else { 18665 return offset < range - 1; 18666 } 18667 } 18668 getScrollIndicatorBounds(@onNull Rect out)18669 void getScrollIndicatorBounds(@NonNull Rect out) { 18670 out.left = mScrollX; 18671 out.right = mScrollX + mRight - mLeft; 18672 out.top = mScrollY; 18673 out.bottom = mScrollY + mBottom - mTop; 18674 } 18675 onDrawScrollIndicators(Canvas c)18676 private void onDrawScrollIndicators(Canvas c) { 18677 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 18678 // No scroll indicators enabled. 18679 return; 18680 } 18681 18682 final Drawable dr = mScrollIndicatorDrawable; 18683 if (dr == null) { 18684 // Scroll indicators aren't supported here. 18685 return; 18686 } 18687 18688 final int h = dr.getIntrinsicHeight(); 18689 final int w = dr.getIntrinsicWidth(); 18690 final Rect rect = mAttachInfo.mTmpInvalRect; 18691 getScrollIndicatorBounds(rect); 18692 18693 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 18694 final boolean canScrollUp = canScrollVertically(-1); 18695 if (canScrollUp) { 18696 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 18697 dr.draw(c); 18698 } 18699 } 18700 18701 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 18702 final boolean canScrollDown = canScrollVertically(1); 18703 if (canScrollDown) { 18704 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 18705 dr.draw(c); 18706 } 18707 } 18708 18709 final int leftRtl; 18710 final int rightRtl; 18711 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 18712 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 18713 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 18714 } else { 18715 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 18716 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 18717 } 18718 18719 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 18720 if ((mPrivateFlags3 & leftMask) != 0) { 18721 final boolean canScrollLeft = canScrollHorizontally(-1); 18722 if (canScrollLeft) { 18723 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 18724 dr.draw(c); 18725 } 18726 } 18727 18728 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 18729 if ((mPrivateFlags3 & rightMask) != 0) { 18730 final boolean canScrollRight = canScrollHorizontally(1); 18731 if (canScrollRight) { 18732 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 18733 dr.draw(c); 18734 } 18735 } 18736 } 18737 getHorizontalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)18738 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 18739 @Nullable Rect touchBounds) { 18740 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 18741 if (bounds == null) { 18742 return; 18743 } 18744 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 18745 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 18746 && !isVerticalScrollBarHidden(); 18747 final int size = getHorizontalScrollbarHeight(); 18748 final int verticalScrollBarGap = drawVerticalScrollBar ? 18749 getVerticalScrollbarWidth() : 0; 18750 final int width = mRight - mLeft; 18751 final int height = mBottom - mTop; 18752 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 18753 bounds.left = mScrollX + (mPaddingLeft & inside); 18754 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 18755 bounds.bottom = bounds.top + size; 18756 18757 if (touchBounds == null) { 18758 return; 18759 } 18760 if (touchBounds != bounds) { 18761 touchBounds.set(bounds); 18762 } 18763 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 18764 if (touchBounds.height() < minTouchTarget) { 18765 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 18766 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 18767 touchBounds.top = touchBounds.bottom - minTouchTarget; 18768 } 18769 if (touchBounds.width() < minTouchTarget) { 18770 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 18771 touchBounds.left -= adjust; 18772 touchBounds.right = touchBounds.left + minTouchTarget; 18773 } 18774 } 18775 getVerticalScrollBarBounds(@ullable Rect bounds, @Nullable Rect touchBounds)18776 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 18777 if (mRoundScrollbarRenderer == null) { 18778 getStraightVerticalScrollBarBounds(bounds, touchBounds); 18779 } else { 18780 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds); 18781 } 18782 } 18783 getRoundVerticalScrollBarBounds(Rect bounds)18784 private void getRoundVerticalScrollBarBounds(Rect bounds) { 18785 final int width = mRight - mLeft; 18786 final int height = mBottom - mTop; 18787 // Do not take padding into account as we always want the scrollbars 18788 // to hug the screen for round wearable devices. 18789 bounds.left = mScrollX; 18790 bounds.top = mScrollY; 18791 bounds.right = bounds.left + width; 18792 bounds.bottom = mScrollY + height; 18793 } 18794 getStraightVerticalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)18795 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 18796 @Nullable Rect touchBounds) { 18797 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 18798 if (bounds == null) { 18799 return; 18800 } 18801 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 18802 final int size = getVerticalScrollbarWidth(); 18803 int verticalScrollbarPosition = mVerticalScrollbarPosition; 18804 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 18805 verticalScrollbarPosition = isLayoutRtl() ? 18806 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 18807 } 18808 final int width = mRight - mLeft; 18809 final int height = mBottom - mTop; 18810 switch (verticalScrollbarPosition) { 18811 default: 18812 case SCROLLBAR_POSITION_RIGHT: 18813 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 18814 break; 18815 case SCROLLBAR_POSITION_LEFT: 18816 bounds.left = mScrollX + (mUserPaddingLeft & inside); 18817 break; 18818 } 18819 bounds.top = mScrollY + (mPaddingTop & inside); 18820 bounds.right = bounds.left + size; 18821 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 18822 18823 if (touchBounds == null) { 18824 return; 18825 } 18826 if (touchBounds != bounds) { 18827 touchBounds.set(bounds); 18828 } 18829 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 18830 if (touchBounds.width() < minTouchTarget) { 18831 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 18832 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 18833 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 18834 touchBounds.left = touchBounds.right - minTouchTarget; 18835 } else { 18836 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 18837 touchBounds.right = touchBounds.left + minTouchTarget; 18838 } 18839 } 18840 if (touchBounds.height() < minTouchTarget) { 18841 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 18842 touchBounds.top -= adjust; 18843 touchBounds.bottom = touchBounds.top + minTouchTarget; 18844 } 18845 } 18846 18847 /** 18848 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 18849 * scrollbars are painted only if they have been awakened first.</p> 18850 * 18851 * @param canvas the canvas on which to draw the scrollbars 18852 * 18853 * @see #awakenScrollBars(int) 18854 */ onDrawScrollBars(Canvas canvas)18855 protected final void onDrawScrollBars(Canvas canvas) { 18856 // scrollbars are drawn only when the animation is running 18857 final ScrollabilityCache cache = mScrollCache; 18858 18859 if (cache != null) { 18860 18861 int state = cache.state; 18862 18863 if (state == ScrollabilityCache.OFF) { 18864 return; 18865 } 18866 18867 boolean invalidate = false; 18868 18869 if (state == ScrollabilityCache.FADING) { 18870 // We're fading -- get our fade interpolation 18871 if (cache.interpolatorValues == null) { 18872 cache.interpolatorValues = new float[1]; 18873 } 18874 18875 float[] values = cache.interpolatorValues; 18876 18877 // Stops the animation if we're done 18878 if (cache.scrollBarInterpolator.timeToValues(values) == 18879 Interpolator.Result.FREEZE_END) { 18880 cache.state = ScrollabilityCache.OFF; 18881 } else { 18882 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 18883 } 18884 18885 // This will make the scroll bars inval themselves after 18886 // drawing. We only want this when we're fading so that 18887 // we prevent excessive redraws 18888 invalidate = true; 18889 } else { 18890 // We're just on -- but we may have been fading before so 18891 // reset alpha 18892 cache.scrollBar.mutate().setAlpha(255); 18893 } 18894 18895 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 18896 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 18897 && !isVerticalScrollBarHidden(); 18898 18899 // Fork out the scroll bar drawing for round wearable devices. 18900 if (mRoundScrollbarRenderer != null) { 18901 if (drawVerticalScrollBar) { 18902 final Rect bounds = cache.mScrollBarBounds; 18903 getVerticalScrollBarBounds(bounds, null); 18904 mRoundScrollbarRenderer.drawRoundScrollbars( 18905 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 18906 if (invalidate) { 18907 invalidate(); 18908 } 18909 } 18910 // Do not draw horizontal scroll bars for round wearable devices. 18911 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 18912 final ScrollBarDrawable scrollBar = cache.scrollBar; 18913 18914 if (drawHorizontalScrollBar) { 18915 scrollBar.setParameters(computeHorizontalScrollRange(), 18916 computeHorizontalScrollOffset(), 18917 computeHorizontalScrollExtent(), false); 18918 final Rect bounds = cache.mScrollBarBounds; 18919 getHorizontalScrollBarBounds(bounds, null); 18920 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 18921 bounds.right, bounds.bottom); 18922 if (invalidate) { 18923 invalidate(bounds); 18924 } 18925 } 18926 18927 if (drawVerticalScrollBar) { 18928 scrollBar.setParameters(computeVerticalScrollRange(), 18929 computeVerticalScrollOffset(), 18930 computeVerticalScrollExtent(), true); 18931 final Rect bounds = cache.mScrollBarBounds; 18932 getVerticalScrollBarBounds(bounds, null); 18933 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 18934 bounds.right, bounds.bottom); 18935 if (invalidate) { 18936 invalidate(bounds); 18937 } 18938 } 18939 } 18940 } 18941 } 18942 18943 /** 18944 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 18945 * FastScroller is visible. 18946 * @return whether to temporarily hide the vertical scrollbar 18947 * @hide 18948 */ isVerticalScrollBarHidden()18949 protected boolean isVerticalScrollBarHidden() { 18950 return false; 18951 } 18952 18953 /** 18954 * <p>Draw the horizontal scrollbar if 18955 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 18956 * 18957 * @param canvas the canvas on which to draw the scrollbar 18958 * @param scrollBar the scrollbar's drawable 18959 * 18960 * @see #isHorizontalScrollBarEnabled() 18961 * @see #computeHorizontalScrollRange() 18962 * @see #computeHorizontalScrollExtent() 18963 * @see #computeHorizontalScrollOffset() 18964 * @hide 18965 */ 18966 @UnsupportedAppUsage onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)18967 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 18968 int l, int t, int r, int b) { 18969 scrollBar.setBounds(l, t, r, b); 18970 scrollBar.draw(canvas); 18971 } 18972 18973 /** 18974 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 18975 * returns true.</p> 18976 * 18977 * @param canvas the canvas on which to draw the scrollbar 18978 * @param scrollBar the scrollbar's drawable 18979 * 18980 * @see #isVerticalScrollBarEnabled() 18981 * @see #computeVerticalScrollRange() 18982 * @see #computeVerticalScrollExtent() 18983 * @see #computeVerticalScrollOffset() 18984 * @hide 18985 */ 18986 @UnsupportedAppUsage onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)18987 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 18988 int l, int t, int r, int b) { 18989 scrollBar.setBounds(l, t, r, b); 18990 scrollBar.draw(canvas); 18991 } 18992 18993 /** 18994 * Implement this to do your drawing. 18995 * 18996 * @param canvas the canvas on which the background will be drawn 18997 */ onDraw(Canvas canvas)18998 protected void onDraw(Canvas canvas) { 18999 } 19000 19001 /* 19002 * Caller is responsible for calling requestLayout if necessary. 19003 * (This allows addViewInLayout to not request a new layout.) 19004 */ 19005 @UnsupportedAppUsage assignParent(ViewParent parent)19006 void assignParent(ViewParent parent) { 19007 if (mParent == null) { 19008 mParent = parent; 19009 } else if (parent == null) { 19010 mParent = null; 19011 } else { 19012 throw new RuntimeException("view " + this + " being added, but" 19013 + " it already has a parent"); 19014 } 19015 } 19016 19017 /** 19018 * This is called when the view is attached to a window. At this point it 19019 * has a Surface and will start drawing. Note that this function is 19020 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 19021 * however it may be called any time before the first onDraw -- including 19022 * before or after {@link #onMeasure(int, int)}. 19023 * 19024 * @see #onDetachedFromWindow() 19025 */ 19026 @CallSuper onAttachedToWindow()19027 protected void onAttachedToWindow() { 19028 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 19029 mParent.requestTransparentRegion(this); 19030 } 19031 19032 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 19033 19034 jumpDrawablesToCurrentState(); 19035 19036 AccessibilityNodeIdManager.getInstance().registerViewWithId(this, getAccessibilityViewId()); 19037 resetSubtreeAccessibilityStateChanged(); 19038 19039 // rebuild, since Outline not maintained while View is detached 19040 rebuildOutline(); 19041 19042 if (isFocused()) { 19043 notifyFocusChangeToInputMethodManager(true /* hasFocus */); 19044 } 19045 } 19046 19047 /** 19048 * Resolve all RTL related properties. 19049 * 19050 * @return true if resolution of RTL properties has been done 19051 * 19052 * @hide 19053 */ resolveRtlPropertiesIfNeeded()19054 public boolean resolveRtlPropertiesIfNeeded() { 19055 if (!needRtlPropertiesResolution()) return false; 19056 19057 // Order is important here: LayoutDirection MUST be resolved first 19058 if (!isLayoutDirectionResolved()) { 19059 resolveLayoutDirection(); 19060 resolveLayoutParams(); 19061 } 19062 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 19063 if (!isTextDirectionResolved()) { 19064 resolveTextDirection(); 19065 } 19066 if (!isTextAlignmentResolved()) { 19067 resolveTextAlignment(); 19068 } 19069 // Should resolve Drawables before Padding because we need the layout direction of the 19070 // Drawable to correctly resolve Padding. 19071 if (!areDrawablesResolved()) { 19072 resolveDrawables(); 19073 } 19074 if (!isPaddingResolved()) { 19075 resolvePadding(); 19076 } 19077 onRtlPropertiesChanged(getLayoutDirection()); 19078 return true; 19079 } 19080 19081 /** 19082 * Reset resolution of all RTL related properties. 19083 * 19084 * @hide 19085 */ 19086 @TestApi resetRtlProperties()19087 public void resetRtlProperties() { 19088 resetResolvedLayoutDirection(); 19089 resetResolvedTextDirection(); 19090 resetResolvedTextAlignment(); 19091 resetResolvedPadding(); 19092 resetResolvedDrawables(); 19093 } 19094 19095 /** 19096 * @see #onScreenStateChanged(int) 19097 */ dispatchScreenStateChanged(int screenState)19098 void dispatchScreenStateChanged(int screenState) { 19099 onScreenStateChanged(screenState); 19100 } 19101 19102 /** 19103 * This method is called whenever the state of the screen this view is 19104 * attached to changes. A state change will usually occurs when the screen 19105 * turns on or off (whether it happens automatically or the user does it 19106 * manually.) 19107 * 19108 * @param screenState The new state of the screen. Can be either 19109 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 19110 */ onScreenStateChanged(int screenState)19111 public void onScreenStateChanged(int screenState) { 19112 } 19113 19114 /** 19115 * @see #onMovedToDisplay(int, Configuration) 19116 */ dispatchMovedToDisplay(Display display, Configuration config)19117 void dispatchMovedToDisplay(Display display, Configuration config) { 19118 mAttachInfo.mDisplay = display; 19119 mAttachInfo.mDisplayState = display.getState(); 19120 onMovedToDisplay(display.getDisplayId(), config); 19121 } 19122 19123 /** 19124 * Called by the system when the hosting activity is moved from one display to another without 19125 * recreation. This means that the activity is declared to handle all changes to configuration 19126 * that happened when it was switched to another display, so it wasn't destroyed and created 19127 * again. 19128 * 19129 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 19130 * applied configuration actually changed. It is up to app developer to choose whether to handle 19131 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)} 19132 * call. 19133 * 19134 * <p>Use this callback to track changes to the displays if some functionality relies on an 19135 * association with some display properties. 19136 * 19137 * @param displayId The id of the display to which the view was moved. 19138 * @param config Configuration of the resources on new display after move. 19139 * 19140 * @see #onConfigurationChanged(Configuration) 19141 * @hide 19142 */ onMovedToDisplay(int displayId, Configuration config)19143 public void onMovedToDisplay(int displayId, Configuration config) { 19144 } 19145 19146 /** 19147 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 19148 */ 19149 @UnsupportedAppUsage hasRtlSupport()19150 private boolean hasRtlSupport() { 19151 return mContext.getApplicationInfo().hasRtlSupport(); 19152 } 19153 19154 /** 19155 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 19156 * RTL not supported) 19157 */ isRtlCompatibilityMode()19158 private boolean isRtlCompatibilityMode() { 19159 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 19160 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport(); 19161 } 19162 19163 /** 19164 * @return true if RTL properties need resolution. 19165 * 19166 */ needRtlPropertiesResolution()19167 private boolean needRtlPropertiesResolution() { 19168 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 19169 } 19170 19171 /** 19172 * Called when any RTL property (layout direction or text direction or text alignment) has 19173 * been changed. 19174 * 19175 * Subclasses need to override this method to take care of cached information that depends on the 19176 * resolved layout direction, or to inform child views that inherit their layout direction. 19177 * 19178 * The default implementation does nothing. 19179 * 19180 * @param layoutDirection the direction of the layout 19181 * 19182 * @see #LAYOUT_DIRECTION_LTR 19183 * @see #LAYOUT_DIRECTION_RTL 19184 */ onRtlPropertiesChanged(@esolvedLayoutDir int layoutDirection)19185 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 19186 } 19187 19188 /** 19189 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 19190 * that the parent directionality can and will be resolved before its children. 19191 * 19192 * @return true if resolution has been done, false otherwise. 19193 * 19194 * @hide 19195 */ resolveLayoutDirection()19196 public boolean resolveLayoutDirection() { 19197 // Clear any previous layout direction resolution 19198 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 19199 19200 if (hasRtlSupport()) { 19201 // Set resolved depending on layout direction 19202 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 19203 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 19204 case LAYOUT_DIRECTION_INHERIT: 19205 // We cannot resolve yet. LTR is by default and let the resolution happen again 19206 // later to get the correct resolved value 19207 if (!canResolveLayoutDirection()) return false; 19208 19209 // Parent has not yet resolved, LTR is still the default 19210 try { 19211 if (!mParent.isLayoutDirectionResolved()) return false; 19212 19213 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 19214 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 19215 } 19216 } catch (AbstractMethodError e) { 19217 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 19218 " does not fully implement ViewParent", e); 19219 } 19220 break; 19221 case LAYOUT_DIRECTION_RTL: 19222 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 19223 break; 19224 case LAYOUT_DIRECTION_LOCALE: 19225 if((LAYOUT_DIRECTION_RTL == 19226 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 19227 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 19228 } 19229 break; 19230 default: 19231 // Nothing to do, LTR by default 19232 } 19233 } 19234 19235 // Set to resolved 19236 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 19237 return true; 19238 } 19239 19240 /** 19241 * Check if layout direction resolution can be done. 19242 * 19243 * @return true if layout direction resolution can be done otherwise return false. 19244 */ canResolveLayoutDirection()19245 public boolean canResolveLayoutDirection() { 19246 switch (getRawLayoutDirection()) { 19247 case LAYOUT_DIRECTION_INHERIT: 19248 if (mParent != null) { 19249 try { 19250 return mParent.canResolveLayoutDirection(); 19251 } catch (AbstractMethodError e) { 19252 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 19253 " does not fully implement ViewParent", e); 19254 } 19255 } 19256 return false; 19257 19258 default: 19259 return true; 19260 } 19261 } 19262 19263 /** 19264 * Reset the resolved layout direction. Layout direction will be resolved during a call to 19265 * {@link #onMeasure(int, int)}. 19266 * 19267 * @hide 19268 */ 19269 @TestApi resetResolvedLayoutDirection()19270 public void resetResolvedLayoutDirection() { 19271 // Reset the current resolved bits 19272 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 19273 } 19274 19275 /** 19276 * @return true if the layout direction is inherited. 19277 * 19278 * @hide 19279 */ isLayoutDirectionInherited()19280 public boolean isLayoutDirectionInherited() { 19281 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 19282 } 19283 19284 /** 19285 * @return true if layout direction has been resolved. 19286 */ isLayoutDirectionResolved()19287 public boolean isLayoutDirectionResolved() { 19288 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 19289 } 19290 19291 /** 19292 * Return if padding has been resolved 19293 * 19294 * @hide 19295 */ 19296 @UnsupportedAppUsage isPaddingResolved()19297 boolean isPaddingResolved() { 19298 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 19299 } 19300 19301 /** 19302 * Resolves padding depending on layout direction, if applicable, and 19303 * recomputes internal padding values to adjust for scroll bars. 19304 * 19305 * @hide 19306 */ 19307 @UnsupportedAppUsage resolvePadding()19308 public void resolvePadding() { 19309 final int resolvedLayoutDirection = getLayoutDirection(); 19310 19311 if (!isRtlCompatibilityMode()) { 19312 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 19313 // If start / end padding are defined, they will be resolved (hence overriding) to 19314 // left / right or right / left depending on the resolved layout direction. 19315 // If start / end padding are not defined, use the left / right ones. 19316 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 19317 Rect padding = sThreadLocal.get(); 19318 if (padding == null) { 19319 padding = new Rect(); 19320 sThreadLocal.set(padding); 19321 } 19322 mBackground.getPadding(padding); 19323 if (!mLeftPaddingDefined) { 19324 mUserPaddingLeftInitial = padding.left; 19325 } 19326 if (!mRightPaddingDefined) { 19327 mUserPaddingRightInitial = padding.right; 19328 } 19329 } 19330 switch (resolvedLayoutDirection) { 19331 case LAYOUT_DIRECTION_RTL: 19332 if (mUserPaddingStart != UNDEFINED_PADDING) { 19333 mUserPaddingRight = mUserPaddingStart; 19334 } else { 19335 mUserPaddingRight = mUserPaddingRightInitial; 19336 } 19337 if (mUserPaddingEnd != UNDEFINED_PADDING) { 19338 mUserPaddingLeft = mUserPaddingEnd; 19339 } else { 19340 mUserPaddingLeft = mUserPaddingLeftInitial; 19341 } 19342 break; 19343 case LAYOUT_DIRECTION_LTR: 19344 default: 19345 if (mUserPaddingStart != UNDEFINED_PADDING) { 19346 mUserPaddingLeft = mUserPaddingStart; 19347 } else { 19348 mUserPaddingLeft = mUserPaddingLeftInitial; 19349 } 19350 if (mUserPaddingEnd != UNDEFINED_PADDING) { 19351 mUserPaddingRight = mUserPaddingEnd; 19352 } else { 19353 mUserPaddingRight = mUserPaddingRightInitial; 19354 } 19355 } 19356 19357 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 19358 } 19359 19360 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 19361 onRtlPropertiesChanged(resolvedLayoutDirection); 19362 19363 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 19364 } 19365 19366 /** 19367 * Reset the resolved layout direction. 19368 * 19369 * @hide 19370 */ 19371 @TestApi resetResolvedPadding()19372 public void resetResolvedPadding() { 19373 resetResolvedPaddingInternal(); 19374 } 19375 19376 /** 19377 * Used when we only want to reset *this* view's padding and not trigger overrides 19378 * in ViewGroup that reset children too. 19379 */ resetResolvedPaddingInternal()19380 void resetResolvedPaddingInternal() { 19381 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 19382 } 19383 19384 /** 19385 * This is called when the view is detached from a window. At this point it 19386 * no longer has a surface for drawing. 19387 * 19388 * @see #onAttachedToWindow() 19389 */ 19390 @CallSuper onDetachedFromWindow()19391 protected void onDetachedFromWindow() { 19392 } 19393 19394 /** 19395 * This is a framework-internal mirror of onDetachedFromWindow() that's called 19396 * after onDetachedFromWindow(). 19397 * 19398 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 19399 * The super method should be called at the end of the overridden method to ensure 19400 * subclasses are destroyed first 19401 * 19402 * @hide 19403 */ 19404 @CallSuper 19405 @UnsupportedAppUsage onDetachedFromWindowInternal()19406 protected void onDetachedFromWindowInternal() { 19407 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 19408 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 19409 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 19410 19411 removeUnsetPressCallback(); 19412 removeLongPressCallback(); 19413 removePerformClickCallback(); 19414 cancel(mSendViewScrolledAccessibilityEvent); 19415 stopNestedScroll(); 19416 19417 // Anything that started animating right before detach should already 19418 // be in its final state when re-attached. 19419 jumpDrawablesToCurrentState(); 19420 19421 destroyDrawingCache(); 19422 19423 cleanupDraw(); 19424 mCurrentAnimation = null; 19425 19426 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 19427 hideTooltip(); 19428 } 19429 19430 AccessibilityNodeIdManager.getInstance().unregisterViewWithId(getAccessibilityViewId()); 19431 } 19432 cleanupDraw()19433 private void cleanupDraw() { 19434 resetDisplayList(); 19435 if (mAttachInfo != null) { 19436 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 19437 } 19438 } 19439 invalidateInheritedLayoutMode(int layoutModeOfRoot)19440 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 19441 } 19442 19443 /** 19444 * @return The number of times this view has been attached to a window 19445 */ getWindowAttachCount()19446 protected int getWindowAttachCount() { 19447 return mWindowAttachCount; 19448 } 19449 19450 /** 19451 * Retrieve a unique token identifying the window this view is attached to. 19452 * @return Return the window's token for use in 19453 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 19454 */ getWindowToken()19455 public IBinder getWindowToken() { 19456 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 19457 } 19458 19459 /** 19460 * Retrieve the {@link WindowId} for the window this view is 19461 * currently attached to. 19462 */ getWindowId()19463 public WindowId getWindowId() { 19464 AttachInfo ai = mAttachInfo; 19465 if (ai == null) { 19466 return null; 19467 } 19468 if (ai.mWindowId == null) { 19469 try { 19470 ai.mIWindowId = ai.mSession.getWindowId(ai.mWindowToken); 19471 if (ai.mIWindowId != null) { 19472 ai.mWindowId = new WindowId(ai.mIWindowId); 19473 } 19474 } catch (RemoteException e) { 19475 } 19476 } 19477 return ai.mWindowId; 19478 } 19479 19480 /** 19481 * Retrieve a unique token identifying the top-level "real" window of 19482 * the window that this view is attached to. That is, this is like 19483 * {@link #getWindowToken}, except if the window this view in is a panel 19484 * window (attached to another containing window), then the token of 19485 * the containing window is returned instead. 19486 * 19487 * @return Returns the associated window token, either 19488 * {@link #getWindowToken()} or the containing window's token. 19489 */ getApplicationWindowToken()19490 public IBinder getApplicationWindowToken() { 19491 AttachInfo ai = mAttachInfo; 19492 if (ai != null) { 19493 IBinder appWindowToken = ai.mPanelParentWindowToken; 19494 if (appWindowToken == null) { 19495 appWindowToken = ai.mWindowToken; 19496 } 19497 return appWindowToken; 19498 } 19499 return null; 19500 } 19501 19502 /** 19503 * Gets the logical display to which the view's window has been attached. 19504 * 19505 * @return The logical display, or null if the view is not currently attached to a window. 19506 */ getDisplay()19507 public Display getDisplay() { 19508 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 19509 } 19510 19511 /** 19512 * Retrieve private session object this view hierarchy is using to 19513 * communicate with the window manager. 19514 * @return the session object to communicate with the window manager 19515 */ 19516 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) getWindowSession()19517 /*package*/ IWindowSession getWindowSession() { 19518 return mAttachInfo != null ? mAttachInfo.mSession : null; 19519 } 19520 19521 /** 19522 * Return the window this view is currently attached to. Used in 19523 * {@link android.app.ActivityView} to communicate with WM. 19524 * @hide 19525 */ getWindow()19526 protected IWindow getWindow() { 19527 return mAttachInfo != null ? mAttachInfo.mWindow : null; 19528 } 19529 19530 /** 19531 * Return the visibility value of the least visible component passed. 19532 */ combineVisibility(int vis1, int vis2)19533 int combineVisibility(int vis1, int vis2) { 19534 // This works because VISIBLE < INVISIBLE < GONE. 19535 return Math.max(vis1, vis2); 19536 } 19537 19538 /** 19539 * @param info the {@link android.view.View.AttachInfo} to associated with 19540 * this view 19541 */ 19542 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchAttachedToWindow(AttachInfo info, int visibility)19543 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 19544 mAttachInfo = info; 19545 if (mOverlay != null) { 19546 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 19547 } 19548 mWindowAttachCount++; 19549 // We will need to evaluate the drawable state at least once. 19550 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 19551 if (mFloatingTreeObserver != null) { 19552 info.mTreeObserver.merge(mFloatingTreeObserver); 19553 mFloatingTreeObserver = null; 19554 } 19555 19556 registerPendingFrameMetricsObservers(); 19557 19558 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 19559 mAttachInfo.mScrollContainers.add(this); 19560 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 19561 } 19562 // Transfer all pending runnables. 19563 if (mRunQueue != null) { 19564 mRunQueue.executeActions(info.mHandler); 19565 mRunQueue = null; 19566 } 19567 performCollectViewAttributes(mAttachInfo, visibility); 19568 onAttachedToWindow(); 19569 19570 ListenerInfo li = mListenerInfo; 19571 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 19572 li != null ? li.mOnAttachStateChangeListeners : null; 19573 if (listeners != null && listeners.size() > 0) { 19574 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 19575 // perform the dispatching. The iterator is a safe guard against listeners that 19576 // could mutate the list by calling the various add/remove methods. This prevents 19577 // the array from being modified while we iterate it. 19578 for (OnAttachStateChangeListener listener : listeners) { 19579 listener.onViewAttachedToWindow(this); 19580 } 19581 } 19582 19583 int vis = info.mWindowVisibility; 19584 if (vis != GONE) { 19585 onWindowVisibilityChanged(vis); 19586 if (isShown()) { 19587 // Calling onVisibilityAggregated directly here since the subtree will also 19588 // receive dispatchAttachedToWindow and this same call 19589 onVisibilityAggregated(vis == VISIBLE); 19590 } 19591 } 19592 19593 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 19594 // As all views in the subtree will already receive dispatchAttachedToWindow 19595 // traversing the subtree again here is not desired. 19596 onVisibilityChanged(this, visibility); 19597 19598 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 19599 // If nobody has evaluated the drawable state yet, then do it now. 19600 refreshDrawableState(); 19601 } 19602 needGlobalAttributesUpdate(false); 19603 19604 notifyEnterOrExitForAutoFillIfNeeded(true); 19605 } 19606 19607 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchDetachedFromWindow()19608 void dispatchDetachedFromWindow() { 19609 AttachInfo info = mAttachInfo; 19610 if (info != null) { 19611 int vis = info.mWindowVisibility; 19612 if (vis != GONE) { 19613 onWindowVisibilityChanged(GONE); 19614 if (isShown()) { 19615 // Invoking onVisibilityAggregated directly here since the subtree 19616 // will also receive detached from window 19617 onVisibilityAggregated(false); 19618 } 19619 } 19620 } 19621 19622 onDetachedFromWindow(); 19623 onDetachedFromWindowInternal(); 19624 19625 InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); 19626 if (imm != null) { 19627 imm.onViewDetachedFromWindow(this); 19628 } 19629 19630 ListenerInfo li = mListenerInfo; 19631 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 19632 li != null ? li.mOnAttachStateChangeListeners : null; 19633 if (listeners != null && listeners.size() > 0) { 19634 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 19635 // perform the dispatching. The iterator is a safe guard against listeners that 19636 // could mutate the list by calling the various add/remove methods. This prevents 19637 // the array from being modified while we iterate it. 19638 for (OnAttachStateChangeListener listener : listeners) { 19639 listener.onViewDetachedFromWindow(this); 19640 } 19641 } 19642 19643 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 19644 mAttachInfo.mScrollContainers.remove(this); 19645 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 19646 } 19647 19648 mAttachInfo = null; 19649 if (mOverlay != null) { 19650 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 19651 } 19652 19653 notifyEnterOrExitForAutoFillIfNeeded(false); 19654 } 19655 19656 /** 19657 * Cancel any deferred high-level input events that were previously posted to the event queue. 19658 * 19659 * <p>Many views post high-level events such as click handlers to the event queue 19660 * to run deferred in order to preserve a desired user experience - clearing visible 19661 * pressed states before executing, etc. This method will abort any events of this nature 19662 * that are currently in flight.</p> 19663 * 19664 * <p>Custom views that generate their own high-level deferred input events should override 19665 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 19666 * 19667 * <p>This will also cancel pending input events for any child views.</p> 19668 * 19669 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 19670 * This will not impact newer events posted after this call that may occur as a result of 19671 * lower-level input events still waiting in the queue. If you are trying to prevent 19672 * double-submitted events for the duration of some sort of asynchronous transaction 19673 * you should also take other steps to protect against unexpected double inputs e.g. calling 19674 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 19675 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 19676 */ cancelPendingInputEvents()19677 public final void cancelPendingInputEvents() { 19678 dispatchCancelPendingInputEvents(); 19679 } 19680 19681 /** 19682 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 19683 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 19684 */ dispatchCancelPendingInputEvents()19685 void dispatchCancelPendingInputEvents() { 19686 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 19687 onCancelPendingInputEvents(); 19688 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 19689 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 19690 " did not call through to super.onCancelPendingInputEvents()"); 19691 } 19692 } 19693 19694 /** 19695 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 19696 * a parent view. 19697 * 19698 * <p>This method is responsible for removing any pending high-level input events that were 19699 * posted to the event queue to run later. Custom view classes that post their own deferred 19700 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 19701 * {@link android.os.Handler} should override this method, call 19702 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 19703 * </p> 19704 */ onCancelPendingInputEvents()19705 public void onCancelPendingInputEvents() { 19706 removePerformClickCallback(); 19707 cancelLongPress(); 19708 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 19709 } 19710 19711 /** 19712 * Store this view hierarchy's frozen state into the given container. 19713 * 19714 * @param container The SparseArray in which to save the view's state. 19715 * 19716 * @see #restoreHierarchyState(android.util.SparseArray) 19717 * @see #dispatchSaveInstanceState(android.util.SparseArray) 19718 * @see #onSaveInstanceState() 19719 */ saveHierarchyState(SparseArray<Parcelable> container)19720 public void saveHierarchyState(SparseArray<Parcelable> container) { 19721 dispatchSaveInstanceState(container); 19722 } 19723 19724 /** 19725 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 19726 * this view and its children. May be overridden to modify how freezing happens to a 19727 * view's children; for example, some views may want to not store state for their children. 19728 * 19729 * @param container The SparseArray in which to save the view's state. 19730 * 19731 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 19732 * @see #saveHierarchyState(android.util.SparseArray) 19733 * @see #onSaveInstanceState() 19734 */ dispatchSaveInstanceState(SparseArray<Parcelable> container)19735 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 19736 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 19737 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 19738 Parcelable state = onSaveInstanceState(); 19739 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 19740 throw new IllegalStateException( 19741 "Derived class did not call super.onSaveInstanceState()"); 19742 } 19743 if (state != null) { 19744 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 19745 // + ": " + state); 19746 container.put(mID, state); 19747 } 19748 } 19749 } 19750 19751 /** 19752 * Hook allowing a view to generate a representation of its internal state 19753 * that can later be used to create a new instance with that same state. 19754 * This state should only contain information that is not persistent or can 19755 * not be reconstructed later. For example, you will never store your 19756 * current position on screen because that will be computed again when a 19757 * new instance of the view is placed in its view hierarchy. 19758 * <p> 19759 * Some examples of things you may store here: the current cursor position 19760 * in a text view (but usually not the text itself since that is stored in a 19761 * content provider or other persistent storage), the currently selected 19762 * item in a list view. 19763 * 19764 * @return Returns a Parcelable object containing the view's current dynamic 19765 * state, or null if there is nothing interesting to save. 19766 * @see #onRestoreInstanceState(Parcelable) 19767 * @see #saveHierarchyState(SparseArray) 19768 * @see #dispatchSaveInstanceState(SparseArray) 19769 * @see #setSaveEnabled(boolean) 19770 */ 19771 @CallSuper onSaveInstanceState()19772 @Nullable protected Parcelable onSaveInstanceState() { 19773 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 19774 if (mStartActivityRequestWho != null || isAutofilled() 19775 || mAutofillViewId > LAST_APP_AUTOFILL_ID) { 19776 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 19777 19778 if (mStartActivityRequestWho != null) { 19779 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; 19780 } 19781 19782 if (isAutofilled()) { 19783 state.mSavedData |= BaseSavedState.IS_AUTOFILLED; 19784 } 19785 19786 if (mAutofillViewId > LAST_APP_AUTOFILL_ID) { 19787 state.mSavedData |= BaseSavedState.AUTOFILL_ID; 19788 } 19789 19790 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 19791 state.mIsAutofilled = isAutofilled(); 19792 state.mAutofillViewId = mAutofillViewId; 19793 return state; 19794 } 19795 return BaseSavedState.EMPTY_STATE; 19796 } 19797 19798 /** 19799 * Restore this view hierarchy's frozen state from the given container. 19800 * 19801 * @param container The SparseArray which holds previously frozen states. 19802 * 19803 * @see #saveHierarchyState(android.util.SparseArray) 19804 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 19805 * @see #onRestoreInstanceState(android.os.Parcelable) 19806 */ restoreHierarchyState(SparseArray<Parcelable> container)19807 public void restoreHierarchyState(SparseArray<Parcelable> container) { 19808 dispatchRestoreInstanceState(container); 19809 } 19810 19811 /** 19812 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 19813 * state for this view and its children. May be overridden to modify how restoring 19814 * happens to a view's children; for example, some views may want to not store state 19815 * for their children. 19816 * 19817 * @param container The SparseArray which holds previously saved state. 19818 * 19819 * @see #dispatchSaveInstanceState(android.util.SparseArray) 19820 * @see #restoreHierarchyState(android.util.SparseArray) 19821 * @see #onRestoreInstanceState(android.os.Parcelable) 19822 */ dispatchRestoreInstanceState(SparseArray<Parcelable> container)19823 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 19824 if (mID != NO_ID) { 19825 Parcelable state = container.get(mID); 19826 if (state != null) { 19827 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 19828 // + ": " + state); 19829 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 19830 onRestoreInstanceState(state); 19831 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 19832 throw new IllegalStateException( 19833 "Derived class did not call super.onRestoreInstanceState()"); 19834 } 19835 } 19836 } 19837 } 19838 19839 /** 19840 * Hook allowing a view to re-apply a representation of its internal state that had previously 19841 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 19842 * null state. 19843 * 19844 * @param state The frozen state that had previously been returned by 19845 * {@link #onSaveInstanceState}. 19846 * 19847 * @see #onSaveInstanceState() 19848 * @see #restoreHierarchyState(android.util.SparseArray) 19849 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 19850 */ 19851 @CallSuper onRestoreInstanceState(Parcelable state)19852 protected void onRestoreInstanceState(Parcelable state) { 19853 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 19854 if (state != null && !(state instanceof AbsSavedState)) { 19855 throw new IllegalArgumentException("Wrong state class, expecting View State but " 19856 + "received " + state.getClass().toString() + " instead. This usually happens " 19857 + "when two views of different type have the same id in the same hierarchy. " 19858 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 19859 + "other views do not use the same id."); 19860 } 19861 if (state != null && state instanceof BaseSavedState) { 19862 BaseSavedState baseState = (BaseSavedState) state; 19863 19864 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { 19865 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; 19866 } 19867 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { 19868 setAutofilled(baseState.mIsAutofilled); 19869 } 19870 if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) { 19871 // It can happen that views have the same view id and the restoration path will not 19872 // be able to distinguish between them. The autofill id needs to be unique though. 19873 // Hence prevent the same autofill view id from being restored multiple times. 19874 ((BaseSavedState) state).mSavedData &= ~BaseSavedState.AUTOFILL_ID; 19875 19876 if ((mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) != 0) { 19877 // Ignore when view already set it through setAutofillId(); 19878 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.DEBUG)) { 19879 Log.d(AUTOFILL_LOG_TAG, "onRestoreInstanceState(): not setting autofillId " 19880 + "to " + baseState.mAutofillViewId + " because view explicitly set" 19881 + " it to " + mAutofillId); 19882 } 19883 } else { 19884 mAutofillViewId = baseState.mAutofillViewId; 19885 mAutofillId = null; // will be set on demand by getAutofillId() 19886 } 19887 } 19888 } 19889 } 19890 19891 /** 19892 * <p>Return the time at which the drawing of the view hierarchy started.</p> 19893 * 19894 * @return the drawing start time in milliseconds 19895 */ getDrawingTime()19896 public long getDrawingTime() { 19897 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 19898 } 19899 19900 /** 19901 * <p>Enables or disables the duplication of the parent's state into this view. When 19902 * duplication is enabled, this view gets its drawable state from its parent rather 19903 * than from its own internal properties.</p> 19904 * 19905 * <p>Note: in the current implementation, setting this property to true after the 19906 * view was added to a ViewGroup might have no effect at all. This property should 19907 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 19908 * 19909 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 19910 * property is enabled, an exception will be thrown.</p> 19911 * 19912 * <p>Note: if the child view uses and updates additional states which are unknown to the 19913 * parent, these states should not be affected by this method.</p> 19914 * 19915 * @param enabled True to enable duplication of the parent's drawable state, false 19916 * to disable it. 19917 * 19918 * @see #getDrawableState() 19919 * @see #isDuplicateParentStateEnabled() 19920 */ setDuplicateParentStateEnabled(boolean enabled)19921 public void setDuplicateParentStateEnabled(boolean enabled) { 19922 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 19923 } 19924 19925 /** 19926 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 19927 * 19928 * @return True if this view's drawable state is duplicated from the parent, 19929 * false otherwise 19930 * 19931 * @see #getDrawableState() 19932 * @see #setDuplicateParentStateEnabled(boolean) 19933 */ 19934 @InspectableProperty(name = "duplicateParentState") isDuplicateParentStateEnabled()19935 public boolean isDuplicateParentStateEnabled() { 19936 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 19937 } 19938 19939 /** 19940 * <p>Specifies the type of layer backing this view. The layer can be 19941 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 19942 * {@link #LAYER_TYPE_HARDWARE}.</p> 19943 * 19944 * <p>A layer is associated with an optional {@link android.graphics.Paint} 19945 * instance that controls how the layer is composed on screen. The following 19946 * properties of the paint are taken into account when composing the layer:</p> 19947 * <ul> 19948 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 19949 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 19950 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 19951 * </ul> 19952 * 19953 * <p>If this view has an alpha value set to < 1.0 by calling 19954 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 19955 * by this view's alpha value.</p> 19956 * 19957 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 19958 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 19959 * for more information on when and how to use layers.</p> 19960 * 19961 * @param layerType The type of layer to use with this view, must be one of 19962 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 19963 * {@link #LAYER_TYPE_HARDWARE} 19964 * @param paint The paint used to compose the layer. This argument is optional 19965 * and can be null. It is ignored when the layer type is 19966 * {@link #LAYER_TYPE_NONE} 19967 * 19968 * @see #getLayerType() 19969 * @see #LAYER_TYPE_NONE 19970 * @see #LAYER_TYPE_SOFTWARE 19971 * @see #LAYER_TYPE_HARDWARE 19972 * @see #setAlpha(float) 19973 * 19974 * @attr ref android.R.styleable#View_layerType 19975 */ setLayerType(@ayerType int layerType, @Nullable Paint paint)19976 public void setLayerType(@LayerType int layerType, @Nullable Paint paint) { 19977 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 19978 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 19979 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 19980 } 19981 19982 boolean typeChanged = mRenderNode.setLayerType(layerType); 19983 19984 if (!typeChanged) { 19985 setLayerPaint(paint); 19986 return; 19987 } 19988 19989 if (layerType != LAYER_TYPE_SOFTWARE) { 19990 // Destroy any previous software drawing cache if present 19991 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 19992 // drawing cache created in View#draw when drawing to a SW canvas. 19993 destroyDrawingCache(); 19994 } 19995 19996 mLayerType = layerType; 19997 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 19998 mRenderNode.setLayerPaint(mLayerPaint); 19999 20000 // draw() behaves differently if we are on a layer, so we need to 20001 // invalidate() here 20002 invalidateParentCaches(); 20003 invalidate(true); 20004 } 20005 20006 /** 20007 * Updates the {@link Paint} object used with the current layer (used only if the current 20008 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 20009 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 20010 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 20011 * ensure that the view gets redrawn immediately. 20012 * 20013 * <p>A layer is associated with an optional {@link android.graphics.Paint} 20014 * instance that controls how the layer is composed on screen. The following 20015 * properties of the paint are taken into account when composing the layer:</p> 20016 * <ul> 20017 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 20018 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 20019 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 20020 * </ul> 20021 * 20022 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 20023 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 20024 * 20025 * @param paint The paint used to compose the layer. This argument is optional 20026 * and can be null. It is ignored when the layer type is 20027 * {@link #LAYER_TYPE_NONE} 20028 * 20029 * @see #setLayerType(int, android.graphics.Paint) 20030 */ setLayerPaint(@ullable Paint paint)20031 public void setLayerPaint(@Nullable Paint paint) { 20032 int layerType = getLayerType(); 20033 if (layerType != LAYER_TYPE_NONE) { 20034 mLayerPaint = paint; 20035 if (layerType == LAYER_TYPE_HARDWARE) { 20036 if (mRenderNode.setLayerPaint(paint)) { 20037 invalidateViewProperty(false, false); 20038 } 20039 } else { 20040 invalidate(); 20041 } 20042 } 20043 } 20044 20045 /** 20046 * Indicates what type of layer is currently associated with this view. By default 20047 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 20048 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 20049 * for more information on the different types of layers. 20050 * 20051 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 20052 * {@link #LAYER_TYPE_HARDWARE} 20053 * 20054 * @see #setLayerType(int, android.graphics.Paint) 20055 * @see #buildLayer() 20056 * @see #LAYER_TYPE_NONE 20057 * @see #LAYER_TYPE_SOFTWARE 20058 * @see #LAYER_TYPE_HARDWARE 20059 */ 20060 @InspectableProperty(enumMapping = { 20061 @EnumEntry(value = LAYER_TYPE_NONE, name = "none"), 20062 @EnumEntry(value = LAYER_TYPE_SOFTWARE, name = "software"), 20063 @EnumEntry(value = LAYER_TYPE_HARDWARE, name = "hardware") 20064 }) 20065 @LayerType getLayerType()20066 public int getLayerType() { 20067 return mLayerType; 20068 } 20069 20070 /** 20071 * Forces this view's layer to be created and this view to be rendered 20072 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 20073 * invoking this method will have no effect. 20074 * 20075 * This method can for instance be used to render a view into its layer before 20076 * starting an animation. If this view is complex, rendering into the layer 20077 * before starting the animation will avoid skipping frames. 20078 * 20079 * @throws IllegalStateException If this view is not attached to a window 20080 * 20081 * @see #setLayerType(int, android.graphics.Paint) 20082 */ buildLayer()20083 public void buildLayer() { 20084 if (mLayerType == LAYER_TYPE_NONE) return; 20085 20086 final AttachInfo attachInfo = mAttachInfo; 20087 if (attachInfo == null) { 20088 throw new IllegalStateException("This view must be attached to a window first"); 20089 } 20090 20091 if (getWidth() == 0 || getHeight() == 0) { 20092 return; 20093 } 20094 20095 switch (mLayerType) { 20096 case LAYER_TYPE_HARDWARE: 20097 updateDisplayListIfDirty(); 20098 if (attachInfo.mThreadedRenderer != null && mRenderNode.hasDisplayList()) { 20099 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 20100 } 20101 break; 20102 case LAYER_TYPE_SOFTWARE: 20103 buildDrawingCache(true); 20104 break; 20105 } 20106 } 20107 20108 /** 20109 * Destroys all hardware rendering resources. This method is invoked 20110 * when the system needs to reclaim resources. Upon execution of this 20111 * method, you should free any OpenGL resources created by the view. 20112 * 20113 * Note: you <strong>must</strong> call 20114 * <code>super.destroyHardwareResources()</code> when overriding 20115 * this method. 20116 * 20117 * @hide 20118 */ 20119 @CallSuper 20120 @UnsupportedAppUsage destroyHardwareResources()20121 protected void destroyHardwareResources() { 20122 if (mOverlay != null) { 20123 mOverlay.getOverlayView().destroyHardwareResources(); 20124 } 20125 if (mGhostView != null) { 20126 mGhostView.destroyHardwareResources(); 20127 } 20128 } 20129 20130 /** 20131 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 20132 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 20133 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 20134 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 20135 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 20136 * null.</p> 20137 * 20138 * <p>Enabling the drawing cache is similar to 20139 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 20140 * acceleration is turned off. When hardware acceleration is turned on, enabling the 20141 * drawing cache has no effect on rendering because the system uses a different mechanism 20142 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 20143 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 20144 * for information on how to enable software and hardware layers.</p> 20145 * 20146 * <p>This API can be used to manually generate 20147 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 20148 * {@link #getDrawingCache()}.</p> 20149 * 20150 * @param enabled true to enable the drawing cache, false otherwise 20151 * 20152 * @see #isDrawingCacheEnabled() 20153 * @see #getDrawingCache() 20154 * @see #buildDrawingCache() 20155 * @see #setLayerType(int, android.graphics.Paint) 20156 * 20157 * @deprecated The view drawing cache was largely made obsolete with the introduction of 20158 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 20159 * layers are largely unnecessary and can easily result in a net loss in performance due to the 20160 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 20161 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 20162 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 20163 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 20164 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 20165 * software-rendered usages are discouraged and have compatibility issues with hardware-only 20166 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 20167 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 20168 * reports or unit testing the {@link PixelCopy} API is recommended. 20169 */ 20170 @Deprecated setDrawingCacheEnabled(boolean enabled)20171 public void setDrawingCacheEnabled(boolean enabled) { 20172 mCachingFailed = false; 20173 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 20174 } 20175 20176 /** 20177 * <p>Indicates whether the drawing cache is enabled for this view.</p> 20178 * 20179 * @return true if the drawing cache is enabled 20180 * 20181 * @see #setDrawingCacheEnabled(boolean) 20182 * @see #getDrawingCache() 20183 * 20184 * @deprecated The view drawing cache was largely made obsolete with the introduction of 20185 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 20186 * layers are largely unnecessary and can easily result in a net loss in performance due to the 20187 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 20188 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 20189 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 20190 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 20191 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 20192 * software-rendered usages are discouraged and have compatibility issues with hardware-only 20193 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 20194 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 20195 * reports or unit testing the {@link PixelCopy} API is recommended. 20196 */ 20197 @Deprecated 20198 @ViewDebug.ExportedProperty(category = "drawing") isDrawingCacheEnabled()20199 public boolean isDrawingCacheEnabled() { 20200 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 20201 } 20202 20203 /** 20204 * Debugging utility which recursively outputs the dirty state of a view and its 20205 * descendants. 20206 * 20207 * @hide 20208 */ 20209 @SuppressWarnings({"UnusedDeclaration"}) outputDirtyFlags(String indent, boolean clear, int clearMask)20210 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 20211 Log.d(VIEW_LOG_TAG, indent + this + " DIRTY(" 20212 + (mPrivateFlags & View.PFLAG_DIRTY_MASK) 20213 + ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" 20214 + (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) 20215 + ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 20216 if (clear) { 20217 mPrivateFlags &= clearMask; 20218 } 20219 if (this instanceof ViewGroup) { 20220 ViewGroup parent = (ViewGroup) this; 20221 final int count = parent.getChildCount(); 20222 for (int i = 0; i < count; i++) { 20223 final View child = parent.getChildAt(i); 20224 child.outputDirtyFlags(indent + " ", clear, clearMask); 20225 } 20226 } 20227 } 20228 20229 /** 20230 * This method is used by ViewGroup to cause its children to restore or recreate their 20231 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 20232 * to recreate its own display list, which would happen if it went through the normal 20233 * draw/dispatchDraw mechanisms. 20234 * 20235 * @hide 20236 */ dispatchGetDisplayList()20237 protected void dispatchGetDisplayList() {} 20238 20239 /** 20240 * A view that is not attached or hardware accelerated cannot create a display list. 20241 * This method checks these conditions and returns the appropriate result. 20242 * 20243 * @return true if view has the ability to create a display list, false otherwise. 20244 * 20245 * @hide 20246 */ canHaveDisplayList()20247 public boolean canHaveDisplayList() { 20248 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 20249 } 20250 20251 /** 20252 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 20253 * @hide 20254 */ 20255 @NonNull 20256 @UnsupportedAppUsage updateDisplayListIfDirty()20257 public RenderNode updateDisplayListIfDirty() { 20258 final RenderNode renderNode = mRenderNode; 20259 if (!canHaveDisplayList()) { 20260 // can't populate RenderNode, don't try 20261 return renderNode; 20262 } 20263 20264 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 20265 || !renderNode.hasDisplayList() 20266 || (mRecreateDisplayList)) { 20267 // Don't need to recreate the display list, just need to tell our 20268 // children to restore/recreate theirs 20269 if (renderNode.hasDisplayList() 20270 && !mRecreateDisplayList) { 20271 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 20272 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 20273 dispatchGetDisplayList(); 20274 20275 return renderNode; // no work needed 20276 } 20277 20278 // If we got here, we're recreating it. Mark it as such to ensure that 20279 // we copy in child display lists into ours in drawChild() 20280 mRecreateDisplayList = true; 20281 20282 int width = mRight - mLeft; 20283 int height = mBottom - mTop; 20284 int layerType = getLayerType(); 20285 20286 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 20287 20288 try { 20289 if (layerType == LAYER_TYPE_SOFTWARE) { 20290 buildDrawingCache(true); 20291 Bitmap cache = getDrawingCache(true); 20292 if (cache != null) { 20293 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 20294 } 20295 } else { 20296 computeScroll(); 20297 20298 canvas.translate(-mScrollX, -mScrollY); 20299 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 20300 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 20301 20302 // Fast path for layouts with no backgrounds 20303 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 20304 dispatchDraw(canvas); 20305 drawAutofilledHighlight(canvas); 20306 if (mOverlay != null && !mOverlay.isEmpty()) { 20307 mOverlay.getOverlayView().draw(canvas); 20308 } 20309 if (debugDraw()) { 20310 debugDrawFocus(canvas); 20311 } 20312 } else { 20313 draw(canvas); 20314 } 20315 } 20316 } finally { 20317 renderNode.endRecording(); 20318 setDisplayListProperties(renderNode); 20319 } 20320 } else { 20321 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 20322 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 20323 } 20324 return renderNode; 20325 } 20326 20327 @UnsupportedAppUsage resetDisplayList()20328 private void resetDisplayList() { 20329 mRenderNode.discardDisplayList(); 20330 if (mBackgroundRenderNode != null) { 20331 mBackgroundRenderNode.discardDisplayList(); 20332 } 20333 } 20334 20335 /** 20336 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 20337 * 20338 * @return A non-scaled bitmap representing this view or null if cache is disabled. 20339 * 20340 * @see #getDrawingCache(boolean) 20341 * 20342 * @deprecated The view drawing cache was largely made obsolete with the introduction of 20343 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 20344 * layers are largely unnecessary and can easily result in a net loss in performance due to the 20345 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 20346 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 20347 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 20348 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 20349 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 20350 * software-rendered usages are discouraged and have compatibility issues with hardware-only 20351 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 20352 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 20353 * reports or unit testing the {@link PixelCopy} API is recommended. 20354 */ 20355 @Deprecated getDrawingCache()20356 public Bitmap getDrawingCache() { 20357 return getDrawingCache(false); 20358 } 20359 20360 /** 20361 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 20362 * is null when caching is disabled. If caching is enabled and the cache is not ready, 20363 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 20364 * draw from the cache when the cache is enabled. To benefit from the cache, you must 20365 * request the drawing cache by calling this method and draw it on screen if the 20366 * returned bitmap is not null.</p> 20367 * 20368 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 20369 * this method will create a bitmap of the same size as this view. Because this bitmap 20370 * will be drawn scaled by the parent ViewGroup, the result on screen might show 20371 * scaling artifacts. To avoid such artifacts, you should call this method by setting 20372 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 20373 * size than the view. This implies that your application must be able to handle this 20374 * size.</p> 20375 * 20376 * @param autoScale Indicates whether the generated bitmap should be scaled based on 20377 * the current density of the screen when the application is in compatibility 20378 * mode. 20379 * 20380 * @return A bitmap representing this view or null if cache is disabled. 20381 * 20382 * @see #setDrawingCacheEnabled(boolean) 20383 * @see #isDrawingCacheEnabled() 20384 * @see #buildDrawingCache(boolean) 20385 * @see #destroyDrawingCache() 20386 * 20387 * @deprecated The view drawing cache was largely made obsolete with the introduction of 20388 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 20389 * layers are largely unnecessary and can easily result in a net loss in performance due to the 20390 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 20391 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 20392 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 20393 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 20394 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 20395 * software-rendered usages are discouraged and have compatibility issues with hardware-only 20396 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 20397 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 20398 * reports or unit testing the {@link PixelCopy} API is recommended. 20399 */ 20400 @Deprecated getDrawingCache(boolean autoScale)20401 public Bitmap getDrawingCache(boolean autoScale) { 20402 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 20403 return null; 20404 } 20405 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 20406 buildDrawingCache(autoScale); 20407 } 20408 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 20409 } 20410 20411 /** 20412 * <p>Frees the resources used by the drawing cache. If you call 20413 * {@link #buildDrawingCache()} manually without calling 20414 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 20415 * should cleanup the cache with this method afterwards.</p> 20416 * 20417 * @see #setDrawingCacheEnabled(boolean) 20418 * @see #buildDrawingCache() 20419 * @see #getDrawingCache() 20420 * 20421 * @deprecated The view drawing cache was largely made obsolete with the introduction of 20422 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 20423 * layers are largely unnecessary and can easily result in a net loss in performance due to the 20424 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 20425 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 20426 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 20427 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 20428 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 20429 * software-rendered usages are discouraged and have compatibility issues with hardware-only 20430 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 20431 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 20432 * reports or unit testing the {@link PixelCopy} API is recommended. 20433 */ 20434 @Deprecated destroyDrawingCache()20435 public void destroyDrawingCache() { 20436 if (mDrawingCache != null) { 20437 mDrawingCache.recycle(); 20438 mDrawingCache = null; 20439 } 20440 if (mUnscaledDrawingCache != null) { 20441 mUnscaledDrawingCache.recycle(); 20442 mUnscaledDrawingCache = null; 20443 } 20444 } 20445 20446 /** 20447 * Setting a solid background color for the drawing cache's bitmaps will improve 20448 * performance and memory usage. Note, though that this should only be used if this 20449 * view will always be drawn on top of a solid color. 20450 * 20451 * @param color The background color to use for the drawing cache's bitmap 20452 * 20453 * @see #setDrawingCacheEnabled(boolean) 20454 * @see #buildDrawingCache() 20455 * @see #getDrawingCache() 20456 * 20457 * @deprecated The view drawing cache was largely made obsolete with the introduction of 20458 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 20459 * layers are largely unnecessary and can easily result in a net loss in performance due to the 20460 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 20461 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 20462 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 20463 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 20464 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 20465 * software-rendered usages are discouraged and have compatibility issues with hardware-only 20466 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 20467 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 20468 * reports or unit testing the {@link PixelCopy} API is recommended. 20469 */ 20470 @Deprecated setDrawingCacheBackgroundColor(@olorInt int color)20471 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 20472 if (color != mDrawingCacheBackgroundColor) { 20473 mDrawingCacheBackgroundColor = color; 20474 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 20475 } 20476 } 20477 20478 /** 20479 * @see #setDrawingCacheBackgroundColor(int) 20480 * 20481 * @return The background color to used for the drawing cache's bitmap 20482 * 20483 * @deprecated The view drawing cache was largely made obsolete with the introduction of 20484 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 20485 * layers are largely unnecessary and can easily result in a net loss in performance due to the 20486 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 20487 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 20488 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 20489 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 20490 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 20491 * software-rendered usages are discouraged and have compatibility issues with hardware-only 20492 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 20493 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 20494 * reports or unit testing the {@link PixelCopy} API is recommended. 20495 */ 20496 @Deprecated 20497 @ColorInt getDrawingCacheBackgroundColor()20498 public int getDrawingCacheBackgroundColor() { 20499 return mDrawingCacheBackgroundColor; 20500 } 20501 20502 /** 20503 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 20504 * 20505 * @see #buildDrawingCache(boolean) 20506 * 20507 * @deprecated The view drawing cache was largely made obsolete with the introduction of 20508 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 20509 * layers are largely unnecessary and can easily result in a net loss in performance due to the 20510 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 20511 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 20512 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 20513 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 20514 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 20515 * software-rendered usages are discouraged and have compatibility issues with hardware-only 20516 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 20517 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 20518 * reports or unit testing the {@link PixelCopy} API is recommended. 20519 */ 20520 @Deprecated buildDrawingCache()20521 public void buildDrawingCache() { 20522 buildDrawingCache(false); 20523 } 20524 20525 /** 20526 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 20527 * 20528 * <p>If you call {@link #buildDrawingCache()} manually without calling 20529 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 20530 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 20531 * 20532 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 20533 * this method will create a bitmap of the same size as this view. Because this bitmap 20534 * will be drawn scaled by the parent ViewGroup, the result on screen might show 20535 * scaling artifacts. To avoid such artifacts, you should call this method by setting 20536 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 20537 * size than the view. This implies that your application must be able to handle this 20538 * size.</p> 20539 * 20540 * <p>You should avoid calling this method when hardware acceleration is enabled. If 20541 * you do not need the drawing cache bitmap, calling this method will increase memory 20542 * usage and cause the view to be rendered in software once, thus negatively impacting 20543 * performance.</p> 20544 * 20545 * @see #getDrawingCache() 20546 * @see #destroyDrawingCache() 20547 * 20548 * @deprecated The view drawing cache was largely made obsolete with the introduction of 20549 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 20550 * layers are largely unnecessary and can easily result in a net loss in performance due to the 20551 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 20552 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 20553 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 20554 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 20555 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 20556 * software-rendered usages are discouraged and have compatibility issues with hardware-only 20557 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 20558 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 20559 * reports or unit testing the {@link PixelCopy} API is recommended. 20560 */ 20561 @Deprecated buildDrawingCache(boolean autoScale)20562 public void buildDrawingCache(boolean autoScale) { 20563 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 20564 mDrawingCache == null : mUnscaledDrawingCache == null)) { 20565 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 20566 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 20567 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 20568 } 20569 try { 20570 buildDrawingCacheImpl(autoScale); 20571 } finally { 20572 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 20573 } 20574 } 20575 } 20576 20577 /** 20578 * private, internal implementation of buildDrawingCache, used to enable tracing 20579 */ buildDrawingCacheImpl(boolean autoScale)20580 private void buildDrawingCacheImpl(boolean autoScale) { 20581 mCachingFailed = false; 20582 20583 int width = mRight - mLeft; 20584 int height = mBottom - mTop; 20585 20586 final AttachInfo attachInfo = mAttachInfo; 20587 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 20588 20589 if (autoScale && scalingRequired) { 20590 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 20591 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 20592 } 20593 20594 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 20595 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 20596 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 20597 20598 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 20599 final long drawingCacheSize = 20600 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 20601 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 20602 if (width > 0 && height > 0) { 20603 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 20604 + " too large to fit into a software layer (or drawing cache), needs " 20605 + projectedBitmapSize + " bytes, only " 20606 + drawingCacheSize + " available"); 20607 } 20608 destroyDrawingCache(); 20609 mCachingFailed = true; 20610 return; 20611 } 20612 20613 boolean clear = true; 20614 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 20615 20616 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 20617 Bitmap.Config quality; 20618 if (!opaque) { 20619 // Never pick ARGB_4444 because it looks awful 20620 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 20621 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 20622 case DRAWING_CACHE_QUALITY_AUTO: 20623 case DRAWING_CACHE_QUALITY_LOW: 20624 case DRAWING_CACHE_QUALITY_HIGH: 20625 default: 20626 quality = Bitmap.Config.ARGB_8888; 20627 break; 20628 } 20629 } else { 20630 // Optimization for translucent windows 20631 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 20632 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 20633 } 20634 20635 // Try to cleanup memory 20636 if (bitmap != null) bitmap.recycle(); 20637 20638 try { 20639 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 20640 width, height, quality); 20641 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 20642 if (autoScale) { 20643 mDrawingCache = bitmap; 20644 } else { 20645 mUnscaledDrawingCache = bitmap; 20646 } 20647 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 20648 } catch (OutOfMemoryError e) { 20649 // If there is not enough memory to create the bitmap cache, just 20650 // ignore the issue as bitmap caches are not required to draw the 20651 // view hierarchy 20652 if (autoScale) { 20653 mDrawingCache = null; 20654 } else { 20655 mUnscaledDrawingCache = null; 20656 } 20657 mCachingFailed = true; 20658 return; 20659 } 20660 20661 clear = drawingCacheBackgroundColor != 0; 20662 } 20663 20664 Canvas canvas; 20665 if (attachInfo != null) { 20666 canvas = attachInfo.mCanvas; 20667 if (canvas == null) { 20668 canvas = new Canvas(); 20669 } 20670 canvas.setBitmap(bitmap); 20671 // Temporarily clobber the cached Canvas in case one of our children 20672 // is also using a drawing cache. Without this, the children would 20673 // steal the canvas by attaching their own bitmap to it and bad, bad 20674 // thing would happen (invisible views, corrupted drawings, etc.) 20675 attachInfo.mCanvas = null; 20676 } else { 20677 // This case should hopefully never or seldom happen 20678 canvas = new Canvas(bitmap); 20679 } 20680 20681 if (clear) { 20682 bitmap.eraseColor(drawingCacheBackgroundColor); 20683 } 20684 20685 computeScroll(); 20686 final int restoreCount = canvas.save(); 20687 20688 if (autoScale && scalingRequired) { 20689 final float scale = attachInfo.mApplicationScale; 20690 canvas.scale(scale, scale); 20691 } 20692 20693 canvas.translate(-mScrollX, -mScrollY); 20694 20695 mPrivateFlags |= PFLAG_DRAWN; 20696 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 20697 mLayerType != LAYER_TYPE_NONE) { 20698 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 20699 } 20700 20701 // Fast path for layouts with no backgrounds 20702 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 20703 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 20704 dispatchDraw(canvas); 20705 drawAutofilledHighlight(canvas); 20706 if (mOverlay != null && !mOverlay.isEmpty()) { 20707 mOverlay.getOverlayView().draw(canvas); 20708 } 20709 } else { 20710 draw(canvas); 20711 } 20712 20713 canvas.restoreToCount(restoreCount); 20714 canvas.setBitmap(null); 20715 20716 if (attachInfo != null) { 20717 // Restore the cached Canvas for our siblings 20718 attachInfo.mCanvas = canvas; 20719 } 20720 } 20721 20722 /** 20723 * Create a snapshot of the view into a bitmap. We should probably make 20724 * some form of this public, but should think about the API. 20725 * 20726 * @hide 20727 */ 20728 @UnsupportedAppUsage createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren)20729 public Bitmap createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren) { 20730 int width = mRight - mLeft; 20731 int height = mBottom - mTop; 20732 20733 final AttachInfo attachInfo = mAttachInfo; 20734 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 20735 width = (int) ((width * scale) + 0.5f); 20736 height = (int) ((height * scale) + 0.5f); 20737 20738 Canvas oldCanvas = null; 20739 try { 20740 Canvas canvas = canvasProvider.getCanvas(this, 20741 width > 0 ? width : 1, height > 0 ? height : 1); 20742 20743 if (attachInfo != null) { 20744 oldCanvas = attachInfo.mCanvas; 20745 // Temporarily clobber the cached Canvas in case one of our children 20746 // is also using a drawing cache. Without this, the children would 20747 // steal the canvas by attaching their own bitmap to it and bad, bad 20748 // things would happen (invisible views, corrupted drawings, etc.) 20749 attachInfo.mCanvas = null; 20750 } 20751 20752 computeScroll(); 20753 final int restoreCount = canvas.save(); 20754 canvas.scale(scale, scale); 20755 canvas.translate(-mScrollX, -mScrollY); 20756 20757 // Temporarily remove the dirty mask 20758 int flags = mPrivateFlags; 20759 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 20760 20761 // Fast path for layouts with no backgrounds 20762 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 20763 dispatchDraw(canvas); 20764 drawAutofilledHighlight(canvas); 20765 if (mOverlay != null && !mOverlay.isEmpty()) { 20766 mOverlay.getOverlayView().draw(canvas); 20767 } 20768 } else { 20769 draw(canvas); 20770 } 20771 20772 mPrivateFlags = flags; 20773 canvas.restoreToCount(restoreCount); 20774 return canvasProvider.createBitmap(); 20775 } finally { 20776 if (oldCanvas != null) { 20777 attachInfo.mCanvas = oldCanvas; 20778 } 20779 } 20780 } 20781 20782 /** 20783 * Indicates whether this View is currently in edit mode. A View is usually 20784 * in edit mode when displayed within a developer tool. For instance, if 20785 * this View is being drawn by a visual user interface builder, this method 20786 * should return true. 20787 * 20788 * Subclasses should check the return value of this method to provide 20789 * different behaviors if their normal behavior might interfere with the 20790 * host environment. For instance: the class spawns a thread in its 20791 * constructor, the drawing code relies on device-specific features, etc. 20792 * 20793 * This method is usually checked in the drawing code of custom widgets. 20794 * 20795 * @return True if this View is in edit mode, false otherwise. 20796 */ isInEditMode()20797 public boolean isInEditMode() { 20798 return false; 20799 } 20800 20801 /** 20802 * If the View draws content inside its padding and enables fading edges, 20803 * it needs to support padding offsets. Padding offsets are added to the 20804 * fading edges to extend the length of the fade so that it covers pixels 20805 * drawn inside the padding. 20806 * 20807 * Subclasses of this class should override this method if they need 20808 * to draw content inside the padding. 20809 * 20810 * @return True if padding offset must be applied, false otherwise. 20811 * 20812 * @see #getLeftPaddingOffset() 20813 * @see #getRightPaddingOffset() 20814 * @see #getTopPaddingOffset() 20815 * @see #getBottomPaddingOffset() 20816 * 20817 * @since CURRENT 20818 */ isPaddingOffsetRequired()20819 protected boolean isPaddingOffsetRequired() { 20820 return false; 20821 } 20822 20823 /** 20824 * Amount by which to extend the left fading region. Called only when 20825 * {@link #isPaddingOffsetRequired()} returns true. 20826 * 20827 * @return The left padding offset in pixels. 20828 * 20829 * @see #isPaddingOffsetRequired() 20830 * 20831 * @since CURRENT 20832 */ getLeftPaddingOffset()20833 protected int getLeftPaddingOffset() { 20834 return 0; 20835 } 20836 20837 /** 20838 * Amount by which to extend the right fading region. Called only when 20839 * {@link #isPaddingOffsetRequired()} returns true. 20840 * 20841 * @return The right padding offset in pixels. 20842 * 20843 * @see #isPaddingOffsetRequired() 20844 * 20845 * @since CURRENT 20846 */ getRightPaddingOffset()20847 protected int getRightPaddingOffset() { 20848 return 0; 20849 } 20850 20851 /** 20852 * Amount by which to extend the top fading region. Called only when 20853 * {@link #isPaddingOffsetRequired()} returns true. 20854 * 20855 * @return The top padding offset in pixels. 20856 * 20857 * @see #isPaddingOffsetRequired() 20858 * 20859 * @since CURRENT 20860 */ getTopPaddingOffset()20861 protected int getTopPaddingOffset() { 20862 return 0; 20863 } 20864 20865 /** 20866 * Amount by which to extend the bottom fading region. Called only when 20867 * {@link #isPaddingOffsetRequired()} returns true. 20868 * 20869 * @return The bottom padding offset in pixels. 20870 * 20871 * @see #isPaddingOffsetRequired() 20872 * 20873 * @since CURRENT 20874 */ getBottomPaddingOffset()20875 protected int getBottomPaddingOffset() { 20876 return 0; 20877 } 20878 20879 /** 20880 * @hide 20881 * @param offsetRequired 20882 */ getFadeTop(boolean offsetRequired)20883 protected int getFadeTop(boolean offsetRequired) { 20884 int top = mPaddingTop; 20885 if (offsetRequired) top += getTopPaddingOffset(); 20886 return top; 20887 } 20888 20889 /** 20890 * @hide 20891 * @param offsetRequired 20892 */ getFadeHeight(boolean offsetRequired)20893 protected int getFadeHeight(boolean offsetRequired) { 20894 int padding = mPaddingTop; 20895 if (offsetRequired) padding += getTopPaddingOffset(); 20896 return mBottom - mTop - mPaddingBottom - padding; 20897 } 20898 20899 /** 20900 * <p>Indicates whether this view is attached to a hardware accelerated 20901 * window or not.</p> 20902 * 20903 * <p>Even if this method returns true, it does not mean that every call 20904 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 20905 * accelerated {@link android.graphics.Canvas}. For instance, if this view 20906 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 20907 * window is hardware accelerated, 20908 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 20909 * return false, and this method will return true.</p> 20910 * 20911 * @return True if the view is attached to a window and the window is 20912 * hardware accelerated; false in any other case. 20913 */ 20914 @ViewDebug.ExportedProperty(category = "drawing") isHardwareAccelerated()20915 public boolean isHardwareAccelerated() { 20916 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 20917 } 20918 20919 /** 20920 * Sets a rectangular area on this view to which the view will be clipped 20921 * when it is drawn. Setting the value to null will remove the clip bounds 20922 * and the view will draw normally, using its full bounds. 20923 * 20924 * @param clipBounds The rectangular area, in the local coordinates of 20925 * this view, to which future drawing operations will be clipped. 20926 */ setClipBounds(Rect clipBounds)20927 public void setClipBounds(Rect clipBounds) { 20928 if (clipBounds == mClipBounds 20929 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 20930 return; 20931 } 20932 if (clipBounds != null) { 20933 if (mClipBounds == null) { 20934 mClipBounds = new Rect(clipBounds); 20935 } else { 20936 mClipBounds.set(clipBounds); 20937 } 20938 } else { 20939 mClipBounds = null; 20940 } 20941 mRenderNode.setClipRect(mClipBounds); 20942 invalidateViewProperty(false, false); 20943 } 20944 20945 /** 20946 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 20947 * 20948 * @return A copy of the current clip bounds if clip bounds are set, 20949 * otherwise null. 20950 */ getClipBounds()20951 public Rect getClipBounds() { 20952 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 20953 } 20954 20955 20956 /** 20957 * Populates an output rectangle with the clip bounds of the view, 20958 * returning {@code true} if successful or {@code false} if the view's 20959 * clip bounds are {@code null}. 20960 * 20961 * @param outRect rectangle in which to place the clip bounds of the view 20962 * @return {@code true} if successful or {@code false} if the view's 20963 * clip bounds are {@code null} 20964 */ getClipBounds(Rect outRect)20965 public boolean getClipBounds(Rect outRect) { 20966 if (mClipBounds != null) { 20967 outRect.set(mClipBounds); 20968 return true; 20969 } 20970 return false; 20971 } 20972 20973 /** 20974 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 20975 * case of an active Animation being run on the view. 20976 */ applyLegacyAnimation(ViewGroup parent, long drawingTime, Animation a, boolean scalingRequired)20977 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 20978 Animation a, boolean scalingRequired) { 20979 Transformation invalidationTransform; 20980 final int flags = parent.mGroupFlags; 20981 final boolean initialized = a.isInitialized(); 20982 if (!initialized) { 20983 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 20984 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 20985 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 20986 onAnimationStart(); 20987 } 20988 20989 final Transformation t = parent.getChildTransformation(); 20990 boolean more = a.getTransformation(drawingTime, t, 1f); 20991 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 20992 if (parent.mInvalidationTransformation == null) { 20993 parent.mInvalidationTransformation = new Transformation(); 20994 } 20995 invalidationTransform = parent.mInvalidationTransformation; 20996 a.getTransformation(drawingTime, invalidationTransform, 1f); 20997 } else { 20998 invalidationTransform = t; 20999 } 21000 21001 if (more) { 21002 if (!a.willChangeBounds()) { 21003 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 21004 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 21005 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 21006 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 21007 // The child need to draw an animation, potentially offscreen, so 21008 // make sure we do not cancel invalidate requests 21009 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 21010 parent.invalidate(mLeft, mTop, mRight, mBottom); 21011 } 21012 } else { 21013 if (parent.mInvalidateRegion == null) { 21014 parent.mInvalidateRegion = new RectF(); 21015 } 21016 final RectF region = parent.mInvalidateRegion; 21017 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 21018 invalidationTransform); 21019 21020 // The child need to draw an animation, potentially offscreen, so 21021 // make sure we do not cancel invalidate requests 21022 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 21023 21024 final int left = mLeft + (int) region.left; 21025 final int top = mTop + (int) region.top; 21026 parent.invalidate(left, top, left + (int) (region.width() + .5f), 21027 top + (int) (region.height() + .5f)); 21028 } 21029 } 21030 return more; 21031 } 21032 21033 /** 21034 * This method is called by getDisplayList() when a display list is recorded for a View. 21035 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 21036 */ setDisplayListProperties(RenderNode renderNode)21037 void setDisplayListProperties(RenderNode renderNode) { 21038 if (renderNode != null) { 21039 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 21040 renderNode.setClipToBounds(mParent instanceof ViewGroup 21041 && ((ViewGroup) mParent).getClipChildren()); 21042 21043 float alpha = 1; 21044 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 21045 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 21046 ViewGroup parentVG = (ViewGroup) mParent; 21047 final Transformation t = parentVG.getChildTransformation(); 21048 if (parentVG.getChildStaticTransformation(this, t)) { 21049 final int transformType = t.getTransformationType(); 21050 if (transformType != Transformation.TYPE_IDENTITY) { 21051 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 21052 alpha = t.getAlpha(); 21053 } 21054 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 21055 renderNode.setStaticMatrix(t.getMatrix()); 21056 } 21057 } 21058 } 21059 } 21060 if (mTransformationInfo != null) { 21061 alpha *= getFinalAlpha(); 21062 if (alpha < 1) { 21063 final int multipliedAlpha = (int) (255 * alpha); 21064 if (onSetAlpha(multipliedAlpha)) { 21065 alpha = 1; 21066 } 21067 } 21068 renderNode.setAlpha(alpha); 21069 } else if (alpha < 1) { 21070 renderNode.setAlpha(alpha); 21071 } 21072 } 21073 } 21074 21075 /** 21076 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 21077 * 21078 * This is where the View specializes rendering behavior based on layer type, 21079 * and hardware acceleration. 21080 */ draw(Canvas canvas, ViewGroup parent, long drawingTime)21081 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 21082 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 21083 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 21084 * 21085 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 21086 * HW accelerated, it can't handle drawing RenderNodes. 21087 */ 21088 boolean drawingWithRenderNode = mAttachInfo != null 21089 && mAttachInfo.mHardwareAccelerated 21090 && hardwareAcceleratedCanvas; 21091 21092 boolean more = false; 21093 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 21094 final int parentFlags = parent.mGroupFlags; 21095 21096 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 21097 parent.getChildTransformation().clear(); 21098 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 21099 } 21100 21101 Transformation transformToApply = null; 21102 boolean concatMatrix = false; 21103 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 21104 final Animation a = getAnimation(); 21105 if (a != null) { 21106 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 21107 concatMatrix = a.willChangeTransformationMatrix(); 21108 if (concatMatrix) { 21109 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 21110 } 21111 transformToApply = parent.getChildTransformation(); 21112 } else { 21113 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 21114 // No longer animating: clear out old animation matrix 21115 mRenderNode.setAnimationMatrix(null); 21116 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 21117 } 21118 if (!drawingWithRenderNode 21119 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 21120 final Transformation t = parent.getChildTransformation(); 21121 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 21122 if (hasTransform) { 21123 final int transformType = t.getTransformationType(); 21124 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 21125 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 21126 } 21127 } 21128 } 21129 21130 concatMatrix |= !childHasIdentityMatrix; 21131 21132 // Sets the flag as early as possible to allow draw() implementations 21133 // to call invalidate() successfully when doing animations 21134 mPrivateFlags |= PFLAG_DRAWN; 21135 21136 if (!concatMatrix && 21137 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 21138 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 21139 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 21140 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 21141 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 21142 return more; 21143 } 21144 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 21145 21146 if (hardwareAcceleratedCanvas) { 21147 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 21148 // retain the flag's value temporarily in the mRecreateDisplayList flag 21149 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 21150 mPrivateFlags &= ~PFLAG_INVALIDATED; 21151 } 21152 21153 RenderNode renderNode = null; 21154 Bitmap cache = null; 21155 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 21156 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 21157 if (layerType != LAYER_TYPE_NONE) { 21158 // If not drawing with RenderNode, treat HW layers as SW 21159 layerType = LAYER_TYPE_SOFTWARE; 21160 buildDrawingCache(true); 21161 } 21162 cache = getDrawingCache(true); 21163 } 21164 21165 if (drawingWithRenderNode) { 21166 // Delay getting the display list until animation-driven alpha values are 21167 // set up and possibly passed on to the view 21168 renderNode = updateDisplayListIfDirty(); 21169 if (!renderNode.hasDisplayList()) { 21170 // Uncommon, but possible. If a view is removed from the hierarchy during the call 21171 // to getDisplayList(), the display list will be marked invalid and we should not 21172 // try to use it again. 21173 renderNode = null; 21174 drawingWithRenderNode = false; 21175 } 21176 } 21177 21178 int sx = 0; 21179 int sy = 0; 21180 if (!drawingWithRenderNode) { 21181 computeScroll(); 21182 sx = mScrollX; 21183 sy = mScrollY; 21184 } 21185 21186 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 21187 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 21188 21189 int restoreTo = -1; 21190 if (!drawingWithRenderNode || transformToApply != null) { 21191 restoreTo = canvas.save(); 21192 } 21193 if (offsetForScroll) { 21194 canvas.translate(mLeft - sx, mTop - sy); 21195 } else { 21196 if (!drawingWithRenderNode) { 21197 canvas.translate(mLeft, mTop); 21198 } 21199 if (scalingRequired) { 21200 if (drawingWithRenderNode) { 21201 // TODO: Might not need this if we put everything inside the DL 21202 restoreTo = canvas.save(); 21203 } 21204 // mAttachInfo cannot be null, otherwise scalingRequired == false 21205 final float scale = 1.0f / mAttachInfo.mApplicationScale; 21206 canvas.scale(scale, scale); 21207 } 21208 } 21209 21210 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 21211 if (transformToApply != null 21212 || alpha < 1 21213 || !hasIdentityMatrix() 21214 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 21215 if (transformToApply != null || !childHasIdentityMatrix) { 21216 int transX = 0; 21217 int transY = 0; 21218 21219 if (offsetForScroll) { 21220 transX = -sx; 21221 transY = -sy; 21222 } 21223 21224 if (transformToApply != null) { 21225 if (concatMatrix) { 21226 if (drawingWithRenderNode) { 21227 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 21228 } else { 21229 // Undo the scroll translation, apply the transformation matrix, 21230 // then redo the scroll translate to get the correct result. 21231 canvas.translate(-transX, -transY); 21232 canvas.concat(transformToApply.getMatrix()); 21233 canvas.translate(transX, transY); 21234 } 21235 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 21236 } 21237 21238 float transformAlpha = transformToApply.getAlpha(); 21239 if (transformAlpha < 1) { 21240 alpha *= transformAlpha; 21241 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 21242 } 21243 } 21244 21245 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 21246 canvas.translate(-transX, -transY); 21247 canvas.concat(getMatrix()); 21248 canvas.translate(transX, transY); 21249 } 21250 } 21251 21252 // Deal with alpha if it is or used to be <1 21253 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 21254 if (alpha < 1) { 21255 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 21256 } else { 21257 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 21258 } 21259 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 21260 if (!drawingWithDrawingCache) { 21261 final int multipliedAlpha = (int) (255 * alpha); 21262 if (!onSetAlpha(multipliedAlpha)) { 21263 if (drawingWithRenderNode) { 21264 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 21265 } else if (layerType == LAYER_TYPE_NONE) { 21266 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 21267 multipliedAlpha); 21268 } 21269 } else { 21270 // Alpha is handled by the child directly, clobber the layer's alpha 21271 mPrivateFlags |= PFLAG_ALPHA_SET; 21272 } 21273 } 21274 } 21275 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 21276 onSetAlpha(255); 21277 mPrivateFlags &= ~PFLAG_ALPHA_SET; 21278 } 21279 21280 if (!drawingWithRenderNode) { 21281 // apply clips directly, since RenderNode won't do it for this draw 21282 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 21283 if (offsetForScroll) { 21284 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 21285 } else { 21286 if (!scalingRequired || cache == null) { 21287 canvas.clipRect(0, 0, getWidth(), getHeight()); 21288 } else { 21289 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 21290 } 21291 } 21292 } 21293 21294 if (mClipBounds != null) { 21295 // clip bounds ignore scroll 21296 canvas.clipRect(mClipBounds); 21297 } 21298 } 21299 21300 if (!drawingWithDrawingCache) { 21301 if (drawingWithRenderNode) { 21302 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21303 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 21304 } else { 21305 // Fast path for layouts with no backgrounds 21306 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 21307 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21308 dispatchDraw(canvas); 21309 } else { 21310 draw(canvas); 21311 } 21312 } 21313 } else if (cache != null) { 21314 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21315 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 21316 // no layer paint, use temporary paint to draw bitmap 21317 Paint cachePaint = parent.mCachePaint; 21318 if (cachePaint == null) { 21319 cachePaint = new Paint(); 21320 cachePaint.setDither(false); 21321 parent.mCachePaint = cachePaint; 21322 } 21323 cachePaint.setAlpha((int) (alpha * 255)); 21324 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 21325 } else { 21326 // use layer paint to draw the bitmap, merging the two alphas, but also restore 21327 int layerPaintAlpha = mLayerPaint.getAlpha(); 21328 if (alpha < 1) { 21329 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 21330 } 21331 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 21332 if (alpha < 1) { 21333 mLayerPaint.setAlpha(layerPaintAlpha); 21334 } 21335 } 21336 } 21337 21338 if (restoreTo >= 0) { 21339 canvas.restoreToCount(restoreTo); 21340 } 21341 21342 if (a != null && !more) { 21343 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 21344 onSetAlpha(255); 21345 } 21346 parent.finishAnimatingView(this, a); 21347 } 21348 21349 if (more && hardwareAcceleratedCanvas) { 21350 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 21351 // alpha animations should cause the child to recreate its display list 21352 invalidate(true); 21353 } 21354 } 21355 21356 mRecreateDisplayList = false; 21357 21358 return more; 21359 } 21360 getDebugPaint()21361 static Paint getDebugPaint() { 21362 if (sDebugPaint == null) { 21363 sDebugPaint = new Paint(); 21364 sDebugPaint.setAntiAlias(false); 21365 } 21366 return sDebugPaint; 21367 } 21368 dipsToPixels(int dips)21369 final int dipsToPixels(int dips) { 21370 float scale = getContext().getResources().getDisplayMetrics().density; 21371 return (int) (dips * scale + 0.5f); 21372 } 21373 debugDrawFocus(Canvas canvas)21374 final private void debugDrawFocus(Canvas canvas) { 21375 if (isFocused()) { 21376 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 21377 final int l = mScrollX; 21378 final int r = l + mRight - mLeft; 21379 final int t = mScrollY; 21380 final int b = t + mBottom - mTop; 21381 21382 final Paint paint = getDebugPaint(); 21383 paint.setColor(DEBUG_CORNERS_COLOR); 21384 21385 // Draw squares in corners. 21386 paint.setStyle(Paint.Style.FILL); 21387 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 21388 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 21389 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 21390 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 21391 21392 // Draw big X across the view. 21393 paint.setStyle(Paint.Style.STROKE); 21394 canvas.drawLine(l, t, r, b, paint); 21395 canvas.drawLine(l, b, r, t, paint); 21396 } 21397 } 21398 21399 /** 21400 * Manually render this view (and all of its children) to the given Canvas. 21401 * The view must have already done a full layout before this function is 21402 * called. When implementing a view, implement 21403 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 21404 * If you do need to override this method, call the superclass version. 21405 * 21406 * @param canvas The Canvas to which the View is rendered. 21407 */ 21408 @CallSuper draw(Canvas canvas)21409 public void draw(Canvas canvas) { 21410 final int privateFlags = mPrivateFlags; 21411 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 21412 21413 /* 21414 * Draw traversal performs several drawing steps which must be executed 21415 * in the appropriate order: 21416 * 21417 * 1. Draw the background 21418 * 2. If necessary, save the canvas' layers to prepare for fading 21419 * 3. Draw view's content 21420 * 4. Draw children 21421 * 5. If necessary, draw the fading edges and restore layers 21422 * 6. Draw decorations (scrollbars for instance) 21423 */ 21424 21425 // Step 1, draw the background, if needed 21426 int saveCount; 21427 21428 drawBackground(canvas); 21429 21430 // skip step 2 & 5 if possible (common case) 21431 final int viewFlags = mViewFlags; 21432 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 21433 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 21434 if (!verticalEdges && !horizontalEdges) { 21435 // Step 3, draw the content 21436 onDraw(canvas); 21437 21438 // Step 4, draw the children 21439 dispatchDraw(canvas); 21440 21441 drawAutofilledHighlight(canvas); 21442 21443 // Overlay is part of the content and draws beneath Foreground 21444 if (mOverlay != null && !mOverlay.isEmpty()) { 21445 mOverlay.getOverlayView().dispatchDraw(canvas); 21446 } 21447 21448 // Step 6, draw decorations (foreground, scrollbars) 21449 onDrawForeground(canvas); 21450 21451 // Step 7, draw the default focus highlight 21452 drawDefaultFocusHighlight(canvas); 21453 21454 if (debugDraw()) { 21455 debugDrawFocus(canvas); 21456 } 21457 21458 // we're done... 21459 return; 21460 } 21461 21462 /* 21463 * Here we do the full fledged routine... 21464 * (this is an uncommon case where speed matters less, 21465 * this is why we repeat some of the tests that have been 21466 * done above) 21467 */ 21468 21469 boolean drawTop = false; 21470 boolean drawBottom = false; 21471 boolean drawLeft = false; 21472 boolean drawRight = false; 21473 21474 float topFadeStrength = 0.0f; 21475 float bottomFadeStrength = 0.0f; 21476 float leftFadeStrength = 0.0f; 21477 float rightFadeStrength = 0.0f; 21478 21479 // Step 2, save the canvas' layers 21480 int paddingLeft = mPaddingLeft; 21481 21482 final boolean offsetRequired = isPaddingOffsetRequired(); 21483 if (offsetRequired) { 21484 paddingLeft += getLeftPaddingOffset(); 21485 } 21486 21487 int left = mScrollX + paddingLeft; 21488 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 21489 int top = mScrollY + getFadeTop(offsetRequired); 21490 int bottom = top + getFadeHeight(offsetRequired); 21491 21492 if (offsetRequired) { 21493 right += getRightPaddingOffset(); 21494 bottom += getBottomPaddingOffset(); 21495 } 21496 21497 final ScrollabilityCache scrollabilityCache = mScrollCache; 21498 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 21499 int length = (int) fadeHeight; 21500 21501 // clip the fade length if top and bottom fades overlap 21502 // overlapping fades produce odd-looking artifacts 21503 if (verticalEdges && (top + length > bottom - length)) { 21504 length = (bottom - top) / 2; 21505 } 21506 21507 // also clip horizontal fades if necessary 21508 if (horizontalEdges && (left + length > right - length)) { 21509 length = (right - left) / 2; 21510 } 21511 21512 if (verticalEdges) { 21513 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 21514 drawTop = topFadeStrength * fadeHeight > 1.0f; 21515 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 21516 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 21517 } 21518 21519 if (horizontalEdges) { 21520 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 21521 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 21522 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 21523 drawRight = rightFadeStrength * fadeHeight > 1.0f; 21524 } 21525 21526 saveCount = canvas.getSaveCount(); 21527 int topSaveCount = -1; 21528 int bottomSaveCount = -1; 21529 int leftSaveCount = -1; 21530 int rightSaveCount = -1; 21531 21532 int solidColor = getSolidColor(); 21533 if (solidColor == 0) { 21534 if (drawTop) { 21535 topSaveCount = canvas.saveUnclippedLayer(left, top, right, top + length); 21536 } 21537 21538 if (drawBottom) { 21539 bottomSaveCount = canvas.saveUnclippedLayer(left, bottom - length, right, bottom); 21540 } 21541 21542 if (drawLeft) { 21543 leftSaveCount = canvas.saveUnclippedLayer(left, top, left + length, bottom); 21544 } 21545 21546 if (drawRight) { 21547 rightSaveCount = canvas.saveUnclippedLayer(right - length, top, right, bottom); 21548 } 21549 } else { 21550 scrollabilityCache.setFadeColor(solidColor); 21551 } 21552 21553 // Step 3, draw the content 21554 onDraw(canvas); 21555 21556 // Step 4, draw the children 21557 dispatchDraw(canvas); 21558 21559 // Step 5, draw the fade effect and restore layers 21560 final Paint p = scrollabilityCache.paint; 21561 final Matrix matrix = scrollabilityCache.matrix; 21562 final Shader fade = scrollabilityCache.shader; 21563 21564 // must be restored in the reverse order that they were saved 21565 if (drawRight) { 21566 matrix.setScale(1, fadeHeight * rightFadeStrength); 21567 matrix.postRotate(90); 21568 matrix.postTranslate(right, top); 21569 fade.setLocalMatrix(matrix); 21570 p.setShader(fade); 21571 if (solidColor == 0) { 21572 canvas.restoreUnclippedLayer(rightSaveCount, p); 21573 21574 } else { 21575 canvas.drawRect(right - length, top, right, bottom, p); 21576 } 21577 } 21578 21579 if (drawLeft) { 21580 matrix.setScale(1, fadeHeight * leftFadeStrength); 21581 matrix.postRotate(-90); 21582 matrix.postTranslate(left, top); 21583 fade.setLocalMatrix(matrix); 21584 p.setShader(fade); 21585 if (solidColor == 0) { 21586 canvas.restoreUnclippedLayer(leftSaveCount, p); 21587 } else { 21588 canvas.drawRect(left, top, left + length, bottom, p); 21589 } 21590 } 21591 21592 if (drawBottom) { 21593 matrix.setScale(1, fadeHeight * bottomFadeStrength); 21594 matrix.postRotate(180); 21595 matrix.postTranslate(left, bottom); 21596 fade.setLocalMatrix(matrix); 21597 p.setShader(fade); 21598 if (solidColor == 0) { 21599 canvas.restoreUnclippedLayer(bottomSaveCount, p); 21600 } else { 21601 canvas.drawRect(left, bottom - length, right, bottom, p); 21602 } 21603 } 21604 21605 if (drawTop) { 21606 matrix.setScale(1, fadeHeight * topFadeStrength); 21607 matrix.postTranslate(left, top); 21608 fade.setLocalMatrix(matrix); 21609 p.setShader(fade); 21610 if (solidColor == 0) { 21611 canvas.restoreUnclippedLayer(topSaveCount, p); 21612 } else { 21613 canvas.drawRect(left, top, right, top + length, p); 21614 } 21615 } 21616 21617 canvas.restoreToCount(saveCount); 21618 21619 drawAutofilledHighlight(canvas); 21620 21621 // Overlay is part of the content and draws beneath Foreground 21622 if (mOverlay != null && !mOverlay.isEmpty()) { 21623 mOverlay.getOverlayView().dispatchDraw(canvas); 21624 } 21625 21626 // Step 6, draw decorations (foreground, scrollbars) 21627 onDrawForeground(canvas); 21628 21629 if (debugDraw()) { 21630 debugDrawFocus(canvas); 21631 } 21632 } 21633 21634 /** 21635 * Draws the background onto the specified canvas. 21636 * 21637 * @param canvas Canvas on which to draw the background 21638 */ 21639 @UnsupportedAppUsage drawBackground(Canvas canvas)21640 private void drawBackground(Canvas canvas) { 21641 final Drawable background = mBackground; 21642 if (background == null) { 21643 return; 21644 } 21645 21646 setBackgroundBounds(); 21647 21648 // Attempt to use a display list if requested. 21649 if (canvas.isHardwareAccelerated() && mAttachInfo != null 21650 && mAttachInfo.mThreadedRenderer != null) { 21651 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 21652 21653 final RenderNode renderNode = mBackgroundRenderNode; 21654 if (renderNode != null && renderNode.hasDisplayList()) { 21655 setBackgroundRenderNodeProperties(renderNode); 21656 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 21657 return; 21658 } 21659 } 21660 21661 final int scrollX = mScrollX; 21662 final int scrollY = mScrollY; 21663 if ((scrollX | scrollY) == 0) { 21664 background.draw(canvas); 21665 } else { 21666 canvas.translate(scrollX, scrollY); 21667 background.draw(canvas); 21668 canvas.translate(-scrollX, -scrollY); 21669 } 21670 } 21671 21672 /** 21673 * Sets the correct background bounds and rebuilds the outline, if needed. 21674 * <p/> 21675 * This is called by LayoutLib. 21676 */ setBackgroundBounds()21677 void setBackgroundBounds() { 21678 if (mBackgroundSizeChanged && mBackground != null) { 21679 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 21680 mBackgroundSizeChanged = false; 21681 rebuildOutline(); 21682 } 21683 } 21684 setBackgroundRenderNodeProperties(RenderNode renderNode)21685 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 21686 renderNode.setTranslationX(mScrollX); 21687 renderNode.setTranslationY(mScrollY); 21688 } 21689 21690 /** 21691 * Creates a new display list or updates the existing display list for the 21692 * specified Drawable. 21693 * 21694 * @param drawable Drawable for which to create a display list 21695 * @param renderNode Existing RenderNode, or {@code null} 21696 * @return A valid display list for the specified drawable 21697 */ getDrawableRenderNode(Drawable drawable, RenderNode renderNode)21698 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 21699 if (renderNode == null) { 21700 renderNode = RenderNode.create(drawable.getClass().getName(), 21701 new ViewAnimationHostBridge(this)); 21702 renderNode.setUsageHint(RenderNode.USAGE_BACKGROUND); 21703 } 21704 21705 final Rect bounds = drawable.getBounds(); 21706 final int width = bounds.width(); 21707 final int height = bounds.height(); 21708 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 21709 21710 // Reverse left/top translation done by drawable canvas, which will 21711 // instead be applied by rendernode's LTRB bounds below. This way, the 21712 // drawable's bounds match with its rendernode bounds and its content 21713 // will lie within those bounds in the rendernode tree. 21714 canvas.translate(-bounds.left, -bounds.top); 21715 21716 try { 21717 drawable.draw(canvas); 21718 } finally { 21719 renderNode.endRecording(); 21720 } 21721 21722 // Set up drawable properties that are view-independent. 21723 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 21724 renderNode.setProjectBackwards(drawable.isProjected()); 21725 renderNode.setProjectionReceiver(true); 21726 renderNode.setClipToBounds(false); 21727 return renderNode; 21728 } 21729 21730 /** 21731 * Returns the overlay for this view, creating it if it does not yet exist. 21732 * Adding drawables to the overlay will cause them to be displayed whenever 21733 * the view itself is redrawn. Objects in the overlay should be actively 21734 * managed: remove them when they should not be displayed anymore. The 21735 * overlay will always have the same size as its host view. 21736 * 21737 * <p>Note: Overlays do not currently work correctly with {@link 21738 * SurfaceView} or {@link TextureView}; contents in overlays for these 21739 * types of views may not display correctly.</p> 21740 * 21741 * @return The ViewOverlay object for this view. 21742 * @see ViewOverlay 21743 */ getOverlay()21744 public ViewOverlay getOverlay() { 21745 if (mOverlay == null) { 21746 mOverlay = new ViewOverlay(mContext, this); 21747 } 21748 return mOverlay; 21749 } 21750 21751 /** 21752 * Override this if your view is known to always be drawn on top of a solid color background, 21753 * and needs to draw fading edges. Returning a non-zero color enables the view system to 21754 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 21755 * should be set to 0xFF. 21756 * 21757 * @see #setVerticalFadingEdgeEnabled(boolean) 21758 * @see #setHorizontalFadingEdgeEnabled(boolean) 21759 * 21760 * @return The known solid color background for this view, or 0 if the color may vary 21761 */ 21762 @ViewDebug.ExportedProperty(category = "drawing") 21763 @InspectableProperty 21764 @ColorInt getSolidColor()21765 public int getSolidColor() { 21766 return 0; 21767 } 21768 21769 /** 21770 * Build a human readable string representation of the specified view flags. 21771 * 21772 * @param flags the view flags to convert to a string 21773 * @return a String representing the supplied flags 21774 */ printFlags(int flags)21775 private static String printFlags(int flags) { 21776 String output = ""; 21777 int numFlags = 0; 21778 if ((flags & FOCUSABLE) == FOCUSABLE) { 21779 output += "TAKES_FOCUS"; 21780 numFlags++; 21781 } 21782 21783 switch (flags & VISIBILITY_MASK) { 21784 case INVISIBLE: 21785 if (numFlags > 0) { 21786 output += " "; 21787 } 21788 output += "INVISIBLE"; 21789 // USELESS HERE numFlags++; 21790 break; 21791 case GONE: 21792 if (numFlags > 0) { 21793 output += " "; 21794 } 21795 output += "GONE"; 21796 // USELESS HERE numFlags++; 21797 break; 21798 default: 21799 break; 21800 } 21801 return output; 21802 } 21803 21804 /** 21805 * Build a human readable string representation of the specified private 21806 * view flags. 21807 * 21808 * @param privateFlags the private view flags to convert to a string 21809 * @return a String representing the supplied flags 21810 */ printPrivateFlags(int privateFlags)21811 private static String printPrivateFlags(int privateFlags) { 21812 String output = ""; 21813 int numFlags = 0; 21814 21815 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 21816 output += "WANTS_FOCUS"; 21817 numFlags++; 21818 } 21819 21820 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 21821 if (numFlags > 0) { 21822 output += " "; 21823 } 21824 output += "FOCUSED"; 21825 numFlags++; 21826 } 21827 21828 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 21829 if (numFlags > 0) { 21830 output += " "; 21831 } 21832 output += "SELECTED"; 21833 numFlags++; 21834 } 21835 21836 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 21837 if (numFlags > 0) { 21838 output += " "; 21839 } 21840 output += "IS_ROOT_NAMESPACE"; 21841 numFlags++; 21842 } 21843 21844 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 21845 if (numFlags > 0) { 21846 output += " "; 21847 } 21848 output += "HAS_BOUNDS"; 21849 numFlags++; 21850 } 21851 21852 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 21853 if (numFlags > 0) { 21854 output += " "; 21855 } 21856 output += "DRAWN"; 21857 // USELESS HERE numFlags++; 21858 } 21859 return output; 21860 } 21861 21862 /** 21863 * <p>Indicates whether or not this view's layout will be requested during 21864 * the next hierarchy layout pass.</p> 21865 * 21866 * @return true if the layout will be forced during next layout pass 21867 */ isLayoutRequested()21868 public boolean isLayoutRequested() { 21869 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 21870 } 21871 21872 /** 21873 * Return true if o is a ViewGroup that is laying out using optical bounds. 21874 * @hide 21875 */ isLayoutModeOptical(Object o)21876 public static boolean isLayoutModeOptical(Object o) { 21877 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 21878 } 21879 setOpticalFrame(int left, int top, int right, int bottom)21880 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 21881 Insets parentInsets = mParent instanceof View ? 21882 ((View) mParent).getOpticalInsets() : Insets.NONE; 21883 Insets childInsets = getOpticalInsets(); 21884 return setFrame( 21885 left + parentInsets.left - childInsets.left, 21886 top + parentInsets.top - childInsets.top, 21887 right + parentInsets.left + childInsets.right, 21888 bottom + parentInsets.top + childInsets.bottom); 21889 } 21890 21891 /** 21892 * Assign a size and position to a view and all of its 21893 * descendants 21894 * 21895 * <p>This is the second phase of the layout mechanism. 21896 * (The first is measuring). In this phase, each parent calls 21897 * layout on all of its children to position them. 21898 * This is typically done using the child measurements 21899 * that were stored in the measure pass().</p> 21900 * 21901 * <p>Derived classes should not override this method. 21902 * Derived classes with children should override 21903 * onLayout. In that method, they should 21904 * call layout on each of their children.</p> 21905 * 21906 * @param l Left position, relative to parent 21907 * @param t Top position, relative to parent 21908 * @param r Right position, relative to parent 21909 * @param b Bottom position, relative to parent 21910 */ 21911 @SuppressWarnings({"unchecked"}) layout(int l, int t, int r, int b)21912 public void layout(int l, int t, int r, int b) { 21913 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 21914 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 21915 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 21916 } 21917 21918 int oldL = mLeft; 21919 int oldT = mTop; 21920 int oldB = mBottom; 21921 int oldR = mRight; 21922 21923 boolean changed = isLayoutModeOptical(mParent) ? 21924 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 21925 21926 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 21927 onLayout(changed, l, t, r, b); 21928 21929 if (shouldDrawRoundScrollbar()) { 21930 if(mRoundScrollbarRenderer == null) { 21931 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 21932 } 21933 } else { 21934 mRoundScrollbarRenderer = null; 21935 } 21936 21937 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 21938 21939 ListenerInfo li = mListenerInfo; 21940 if (li != null && li.mOnLayoutChangeListeners != null) { 21941 ArrayList<OnLayoutChangeListener> listenersCopy = 21942 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 21943 int numListeners = listenersCopy.size(); 21944 for (int i = 0; i < numListeners; ++i) { 21945 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 21946 } 21947 } 21948 } 21949 21950 final boolean wasLayoutValid = isLayoutValid(); 21951 21952 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 21953 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 21954 21955 if (!wasLayoutValid && isFocused()) { 21956 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 21957 if (canTakeFocus()) { 21958 // We have a robust focus, so parents should no longer be wanting focus. 21959 clearParentsWantFocus(); 21960 } else if (getViewRootImpl() == null || !getViewRootImpl().isInLayout()) { 21961 // This is a weird case. Most-likely the user, rather than ViewRootImpl, called 21962 // layout. In this case, there's no guarantee that parent layouts will be evaluated 21963 // and thus the safest action is to clear focus here. 21964 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 21965 clearParentsWantFocus(); 21966 } else if (!hasParentWantsFocus()) { 21967 // original requestFocus was likely on this view directly, so just clear focus 21968 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 21969 } 21970 // otherwise, we let parents handle re-assigning focus during their layout passes. 21971 } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 21972 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 21973 View focused = findFocus(); 21974 if (focused != null) { 21975 // Try to restore focus as close as possible to our starting focus. 21976 if (!restoreDefaultFocus() && !hasParentWantsFocus()) { 21977 // Give up and clear focus once we've reached the top-most parent which wants 21978 // focus. 21979 focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 21980 } 21981 } 21982 } 21983 21984 if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { 21985 mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 21986 notifyEnterOrExitForAutoFillIfNeeded(true); 21987 } 21988 } 21989 hasParentWantsFocus()21990 private boolean hasParentWantsFocus() { 21991 ViewParent parent = mParent; 21992 while (parent instanceof ViewGroup) { 21993 ViewGroup pv = (ViewGroup) parent; 21994 if ((pv.mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 21995 return true; 21996 } 21997 parent = pv.mParent; 21998 } 21999 return false; 22000 } 22001 22002 /** 22003 * Called from layout when this view should 22004 * assign a size and position to each of its children. 22005 * 22006 * Derived classes with children should override 22007 * this method and call layout on each of 22008 * their children. 22009 * @param changed This is a new size or position for this view 22010 * @param left Left position, relative to parent 22011 * @param top Top position, relative to parent 22012 * @param right Right position, relative to parent 22013 * @param bottom Bottom position, relative to parent 22014 */ onLayout(boolean changed, int left, int top, int right, int bottom)22015 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 22016 } 22017 22018 /** 22019 * Assign a size and position to this view. 22020 * 22021 * This is called from layout. 22022 * 22023 * @param left Left position, relative to parent 22024 * @param top Top position, relative to parent 22025 * @param right Right position, relative to parent 22026 * @param bottom Bottom position, relative to parent 22027 * @return true if the new size and position are different than the 22028 * previous ones 22029 * {@hide} 22030 */ 22031 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) setFrame(int left, int top, int right, int bottom)22032 protected boolean setFrame(int left, int top, int right, int bottom) { 22033 boolean changed = false; 22034 22035 if (DBG) { 22036 Log.d(VIEW_LOG_TAG, this + " View.setFrame(" + left + "," + top + "," 22037 + right + "," + bottom + ")"); 22038 } 22039 22040 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 22041 changed = true; 22042 22043 // Remember our drawn bit 22044 int drawn = mPrivateFlags & PFLAG_DRAWN; 22045 22046 int oldWidth = mRight - mLeft; 22047 int oldHeight = mBottom - mTop; 22048 int newWidth = right - left; 22049 int newHeight = bottom - top; 22050 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 22051 22052 // Invalidate our old position 22053 invalidate(sizeChanged); 22054 22055 mLeft = left; 22056 mTop = top; 22057 mRight = right; 22058 mBottom = bottom; 22059 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 22060 22061 mPrivateFlags |= PFLAG_HAS_BOUNDS; 22062 22063 22064 if (sizeChanged) { 22065 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 22066 } 22067 22068 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 22069 // If we are visible, force the DRAWN bit to on so that 22070 // this invalidate will go through (at least to our parent). 22071 // This is because someone may have invalidated this view 22072 // before this call to setFrame came in, thereby clearing 22073 // the DRAWN bit. 22074 mPrivateFlags |= PFLAG_DRAWN; 22075 invalidate(sizeChanged); 22076 // parent display list may need to be recreated based on a change in the bounds 22077 // of any child 22078 invalidateParentCaches(); 22079 } 22080 22081 // Reset drawn bit to original value (invalidate turns it off) 22082 mPrivateFlags |= drawn; 22083 22084 mBackgroundSizeChanged = true; 22085 mDefaultFocusHighlightSizeChanged = true; 22086 if (mForegroundInfo != null) { 22087 mForegroundInfo.mBoundsChanged = true; 22088 } 22089 22090 notifySubtreeAccessibilityStateChangedIfNeeded(); 22091 } 22092 return changed; 22093 } 22094 22095 /** 22096 * Assign a size and position to this view. 22097 * 22098 * This method is meant to be used in animations only as it applies this position and size 22099 * for the view only temporary and it can be changed back at any time by the layout. 22100 * 22101 * @param left Left position, relative to parent 22102 * @param top Top position, relative to parent 22103 * @param right Right position, relative to parent 22104 * @param bottom Bottom position, relative to parent 22105 * 22106 * @see #setLeft(int), #setRight(int), #setTop(int), #setBottom(int) 22107 */ setLeftTopRightBottom(int left, int top, int right, int bottom)22108 public final void setLeftTopRightBottom(int left, int top, int right, int bottom) { 22109 setFrame(left, top, right, bottom); 22110 } 22111 sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight)22112 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 22113 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 22114 if (mOverlay != null) { 22115 mOverlay.getOverlayView().setRight(newWidth); 22116 mOverlay.getOverlayView().setBottom(newHeight); 22117 } 22118 // If this isn't laid out yet, focus assignment will be handled during the "deferment/ 22119 // backtracking" of requestFocus during layout, so don't touch focus here. 22120 if (!sCanFocusZeroSized && isLayoutValid() 22121 // Don't touch focus if animating 22122 && !(mParent instanceof ViewGroup && ((ViewGroup) mParent).isLayoutSuppressed())) { 22123 if (newWidth <= 0 || newHeight <= 0) { 22124 if (hasFocus()) { 22125 clearFocus(); 22126 if (mParent instanceof ViewGroup) { 22127 ((ViewGroup) mParent).clearFocusedInCluster(); 22128 } 22129 } 22130 clearAccessibilityFocus(); 22131 } else if (oldWidth <= 0 || oldHeight <= 0) { 22132 if (mParent != null && canTakeFocus()) { 22133 mParent.focusableViewAvailable(this); 22134 } 22135 } 22136 } 22137 rebuildOutline(); 22138 } 22139 22140 /** 22141 * Finalize inflating a view from XML. This is called as the last phase 22142 * of inflation, after all child views have been added. 22143 * 22144 * <p>Even if the subclass overrides onFinishInflate, they should always be 22145 * sure to call the super method, so that we get called. 22146 */ 22147 @CallSuper onFinishInflate()22148 protected void onFinishInflate() { 22149 } 22150 22151 /** 22152 * Returns the resources associated with this view. 22153 * 22154 * @return Resources object. 22155 */ getResources()22156 public Resources getResources() { 22157 return mResources; 22158 } 22159 22160 /** 22161 * Invalidates the specified Drawable. 22162 * 22163 * @param drawable the drawable to invalidate 22164 */ 22165 @Override invalidateDrawable(@onNull Drawable drawable)22166 public void invalidateDrawable(@NonNull Drawable drawable) { 22167 if (verifyDrawable(drawable)) { 22168 final Rect dirty = drawable.getDirtyBounds(); 22169 final int scrollX = mScrollX; 22170 final int scrollY = mScrollY; 22171 22172 invalidate(dirty.left + scrollX, dirty.top + scrollY, 22173 dirty.right + scrollX, dirty.bottom + scrollY); 22174 rebuildOutline(); 22175 } 22176 } 22177 22178 /** 22179 * Schedules an action on a drawable to occur at a specified time. 22180 * 22181 * @param who the recipient of the action 22182 * @param what the action to run on the drawable 22183 * @param when the time at which the action must occur. Uses the 22184 * {@link SystemClock#uptimeMillis} timebase. 22185 */ 22186 @Override scheduleDrawable(@onNull Drawable who, @NonNull Runnable what, long when)22187 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 22188 if (verifyDrawable(who) && what != null) { 22189 final long delay = when - SystemClock.uptimeMillis(); 22190 if (mAttachInfo != null) { 22191 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 22192 Choreographer.CALLBACK_ANIMATION, what, who, 22193 Choreographer.subtractFrameDelay(delay)); 22194 } else { 22195 // Postpone the runnable until we know 22196 // on which thread it needs to run. 22197 getRunQueue().postDelayed(what, delay); 22198 } 22199 } 22200 } 22201 22202 /** 22203 * Cancels a scheduled action on a drawable. 22204 * 22205 * @param who the recipient of the action 22206 * @param what the action to cancel 22207 */ 22208 @Override unscheduleDrawable(@onNull Drawable who, @NonNull Runnable what)22209 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 22210 if (verifyDrawable(who) && what != null) { 22211 if (mAttachInfo != null) { 22212 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 22213 Choreographer.CALLBACK_ANIMATION, what, who); 22214 } 22215 getRunQueue().removeCallbacks(what); 22216 } 22217 } 22218 22219 /** 22220 * Unschedule any events associated with the given Drawable. This can be 22221 * used when selecting a new Drawable into a view, so that the previous 22222 * one is completely unscheduled. 22223 * 22224 * @param who The Drawable to unschedule. 22225 * 22226 * @see #drawableStateChanged 22227 */ unscheduleDrawable(Drawable who)22228 public void unscheduleDrawable(Drawable who) { 22229 if (mAttachInfo != null && who != null) { 22230 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 22231 Choreographer.CALLBACK_ANIMATION, null, who); 22232 } 22233 } 22234 22235 /** 22236 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 22237 * that the View directionality can and will be resolved before its Drawables. 22238 * 22239 * Will call {@link View#onResolveDrawables} when resolution is done. 22240 * 22241 * @hide 22242 */ resolveDrawables()22243 protected void resolveDrawables() { 22244 // Drawables resolution may need to happen before resolving the layout direction (which is 22245 // done only during the measure() call). 22246 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 22247 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 22248 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 22249 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 22250 // direction to be resolved as its resolved value will be the same as its raw value. 22251 if (!isLayoutDirectionResolved() && 22252 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 22253 return; 22254 } 22255 22256 final int layoutDirection = isLayoutDirectionResolved() ? 22257 getLayoutDirection() : getRawLayoutDirection(); 22258 22259 if (mBackground != null) { 22260 mBackground.setLayoutDirection(layoutDirection); 22261 } 22262 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 22263 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 22264 } 22265 if (mDefaultFocusHighlight != null) { 22266 mDefaultFocusHighlight.setLayoutDirection(layoutDirection); 22267 } 22268 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 22269 onResolveDrawables(layoutDirection); 22270 } 22271 areDrawablesResolved()22272 boolean areDrawablesResolved() { 22273 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 22274 } 22275 22276 /** 22277 * Called when layout direction has been resolved. 22278 * 22279 * The default implementation does nothing. 22280 * 22281 * @param layoutDirection The resolved layout direction. 22282 * 22283 * @see #LAYOUT_DIRECTION_LTR 22284 * @see #LAYOUT_DIRECTION_RTL 22285 * 22286 * @hide 22287 */ onResolveDrawables(@esolvedLayoutDir int layoutDirection)22288 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 22289 } 22290 22291 /** 22292 * @hide 22293 */ 22294 @TestApi resetResolvedDrawables()22295 protected void resetResolvedDrawables() { 22296 resetResolvedDrawablesInternal(); 22297 } 22298 resetResolvedDrawablesInternal()22299 void resetResolvedDrawablesInternal() { 22300 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 22301 } 22302 22303 /** 22304 * If your view subclass is displaying its own Drawable objects, it should 22305 * override this function and return true for any Drawable it is 22306 * displaying. This allows animations for those drawables to be 22307 * scheduled. 22308 * 22309 * <p>Be sure to call through to the super class when overriding this 22310 * function. 22311 * 22312 * @param who The Drawable to verify. Return true if it is one you are 22313 * displaying, else return the result of calling through to the 22314 * super class. 22315 * 22316 * @return boolean If true than the Drawable is being displayed in the 22317 * view; else false and it is not allowed to animate. 22318 * 22319 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 22320 * @see #drawableStateChanged() 22321 */ 22322 @CallSuper verifyDrawable(@onNull Drawable who)22323 protected boolean verifyDrawable(@NonNull Drawable who) { 22324 // Avoid verifying the scroll bar drawable so that we don't end up in 22325 // an invalidation loop. This effectively prevents the scroll bar 22326 // drawable from triggering invalidations and scheduling runnables. 22327 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) 22328 || (mDefaultFocusHighlight == who); 22329 } 22330 22331 /** 22332 * This function is called whenever the state of the view changes in such 22333 * a way that it impacts the state of drawables being shown. 22334 * <p> 22335 * If the View has a StateListAnimator, it will also be called to run necessary state 22336 * change animations. 22337 * <p> 22338 * Be sure to call through to the superclass when overriding this function. 22339 * 22340 * @see Drawable#setState(int[]) 22341 */ 22342 @CallSuper drawableStateChanged()22343 protected void drawableStateChanged() { 22344 final int[] state = getDrawableState(); 22345 boolean changed = false; 22346 22347 final Drawable bg = mBackground; 22348 if (bg != null && bg.isStateful()) { 22349 changed |= bg.setState(state); 22350 } 22351 22352 final Drawable hl = mDefaultFocusHighlight; 22353 if (hl != null && hl.isStateful()) { 22354 changed |= hl.setState(state); 22355 } 22356 22357 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 22358 if (fg != null && fg.isStateful()) { 22359 changed |= fg.setState(state); 22360 } 22361 22362 if (mScrollCache != null) { 22363 final Drawable scrollBar = mScrollCache.scrollBar; 22364 if (scrollBar != null && scrollBar.isStateful()) { 22365 changed |= scrollBar.setState(state) 22366 && mScrollCache.state != ScrollabilityCache.OFF; 22367 } 22368 } 22369 22370 if (mStateListAnimator != null) { 22371 mStateListAnimator.setState(state); 22372 } 22373 22374 if (changed) { 22375 invalidate(); 22376 } 22377 } 22378 22379 /** 22380 * This function is called whenever the view hotspot changes and needs to 22381 * be propagated to drawables or child views managed by the view. 22382 * <p> 22383 * Dispatching to child views is handled by 22384 * {@link #dispatchDrawableHotspotChanged(float, float)}. 22385 * <p> 22386 * Be sure to call through to the superclass when overriding this function. 22387 * 22388 * @param x hotspot x coordinate 22389 * @param y hotspot y coordinate 22390 */ 22391 @CallSuper drawableHotspotChanged(float x, float y)22392 public void drawableHotspotChanged(float x, float y) { 22393 if (mBackground != null) { 22394 mBackground.setHotspot(x, y); 22395 } 22396 if (mDefaultFocusHighlight != null) { 22397 mDefaultFocusHighlight.setHotspot(x, y); 22398 } 22399 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 22400 mForegroundInfo.mDrawable.setHotspot(x, y); 22401 } 22402 22403 dispatchDrawableHotspotChanged(x, y); 22404 } 22405 22406 /** 22407 * Dispatches drawableHotspotChanged to all of this View's children. 22408 * 22409 * @param x hotspot x coordinate 22410 * @param y hotspot y coordinate 22411 * @see #drawableHotspotChanged(float, float) 22412 */ dispatchDrawableHotspotChanged(float x, float y)22413 public void dispatchDrawableHotspotChanged(float x, float y) { 22414 } 22415 22416 /** 22417 * Call this to force a view to update its drawable state. This will cause 22418 * drawableStateChanged to be called on this view. Views that are interested 22419 * in the new state should call getDrawableState. 22420 * 22421 * @see #drawableStateChanged 22422 * @see #getDrawableState 22423 */ refreshDrawableState()22424 public void refreshDrawableState() { 22425 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 22426 drawableStateChanged(); 22427 22428 ViewParent parent = mParent; 22429 if (parent != null) { 22430 parent.childDrawableStateChanged(this); 22431 } 22432 } 22433 22434 /** 22435 * Create a default focus highlight if it doesn't exist. 22436 * @return a default focus highlight. 22437 */ getDefaultFocusHighlightDrawable()22438 private Drawable getDefaultFocusHighlightDrawable() { 22439 if (mDefaultFocusHighlightCache == null) { 22440 if (mContext != null) { 22441 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; 22442 final TypedArray ta = mContext.obtainStyledAttributes(attrs); 22443 mDefaultFocusHighlightCache = ta.getDrawable(0); 22444 ta.recycle(); 22445 } 22446 } 22447 return mDefaultFocusHighlightCache; 22448 } 22449 22450 /** 22451 * Set the current default focus highlight. 22452 * @param highlight the highlight drawable, or {@code null} if it's no longer needed. 22453 */ setDefaultFocusHighlight(Drawable highlight)22454 private void setDefaultFocusHighlight(Drawable highlight) { 22455 mDefaultFocusHighlight = highlight; 22456 mDefaultFocusHighlightSizeChanged = true; 22457 if (highlight != null) { 22458 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 22459 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 22460 } 22461 highlight.setLayoutDirection(getLayoutDirection()); 22462 if (highlight.isStateful()) { 22463 highlight.setState(getDrawableState()); 22464 } 22465 if (isAttachedToWindow()) { 22466 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 22467 } 22468 // Set callback last, since the view may still be initializing. 22469 highlight.setCallback(this); 22470 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 22471 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 22472 mPrivateFlags |= PFLAG_SKIP_DRAW; 22473 } 22474 invalidate(); 22475 } 22476 22477 /** 22478 * Check whether we need to draw a default focus highlight when this view gets focused, 22479 * which requires: 22480 * <ul> 22481 * <li>In both background and foreground, {@link android.R.attr#state_focused} 22482 * is not defined.</li> 22483 * <li>This view is not in touch mode.</li> 22484 * <li>This view doesn't opt out for a default focus highlight, via 22485 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li> 22486 * <li>This view is attached to window.</li> 22487 * </ul> 22488 * @return {@code true} if a default focus highlight is needed. 22489 * @hide 22490 */ 22491 @TestApi isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground)22492 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { 22493 final boolean lackFocusState = (background == null || !background.isStateful() 22494 || !background.hasFocusStateSpecified()) 22495 && (foreground == null || !foreground.isStateful() 22496 || !foreground.hasFocusStateSpecified()); 22497 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState 22498 && isAttachedToWindow() && sUseDefaultFocusHighlight; 22499 } 22500 22501 /** 22502 * When this view is focused, switches on/off the default focused highlight. 22503 * <p> 22504 * This always happens when this view is focused, and only at this moment the default focus 22505 * highlight can be visible. 22506 */ switchDefaultFocusHighlight()22507 private void switchDefaultFocusHighlight() { 22508 if (isFocused()) { 22509 final boolean needed = isDefaultFocusHighlightNeeded(mBackground, 22510 mForegroundInfo == null ? null : mForegroundInfo.mDrawable); 22511 final boolean active = mDefaultFocusHighlight != null; 22512 if (needed && !active) { 22513 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); 22514 } else if (!needed && active) { 22515 // The highlight is no longer needed, so tear it down. 22516 setDefaultFocusHighlight(null); 22517 } 22518 } 22519 } 22520 22521 /** 22522 * Draw the default focus highlight onto the canvas. 22523 * @param canvas the canvas where we're drawing the highlight. 22524 */ drawDefaultFocusHighlight(Canvas canvas)22525 private void drawDefaultFocusHighlight(Canvas canvas) { 22526 if (mDefaultFocusHighlight != null) { 22527 if (mDefaultFocusHighlightSizeChanged) { 22528 mDefaultFocusHighlightSizeChanged = false; 22529 final int l = mScrollX; 22530 final int r = l + mRight - mLeft; 22531 final int t = mScrollY; 22532 final int b = t + mBottom - mTop; 22533 mDefaultFocusHighlight.setBounds(l, t, r, b); 22534 } 22535 mDefaultFocusHighlight.draw(canvas); 22536 } 22537 } 22538 22539 /** 22540 * Return an array of resource IDs of the drawable states representing the 22541 * current state of the view. 22542 * 22543 * @return The current drawable state 22544 * 22545 * @see Drawable#setState(int[]) 22546 * @see #drawableStateChanged() 22547 * @see #onCreateDrawableState(int) 22548 */ getDrawableState()22549 public final int[] getDrawableState() { 22550 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 22551 return mDrawableState; 22552 } else { 22553 mDrawableState = onCreateDrawableState(0); 22554 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 22555 return mDrawableState; 22556 } 22557 } 22558 22559 /** 22560 * Generate the new {@link android.graphics.drawable.Drawable} state for 22561 * this view. This is called by the view 22562 * system when the cached Drawable state is determined to be invalid. To 22563 * retrieve the current state, you should use {@link #getDrawableState}. 22564 * 22565 * @param extraSpace if non-zero, this is the number of extra entries you 22566 * would like in the returned array in which you can place your own 22567 * states. 22568 * 22569 * @return Returns an array holding the current {@link Drawable} state of 22570 * the view. 22571 * 22572 * @see #mergeDrawableStates(int[], int[]) 22573 */ onCreateDrawableState(int extraSpace)22574 protected int[] onCreateDrawableState(int extraSpace) { 22575 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 22576 mParent instanceof View) { 22577 return ((View) mParent).onCreateDrawableState(extraSpace); 22578 } 22579 22580 int[] drawableState; 22581 22582 int privateFlags = mPrivateFlags; 22583 22584 int viewStateIndex = 0; 22585 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 22586 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 22587 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 22588 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 22589 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 22590 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 22591 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 22592 ThreadedRenderer.isAvailable()) { 22593 // This is set if HW acceleration is requested, even if the current 22594 // process doesn't allow it. This is just to allow app preview 22595 // windows to better match their app. 22596 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 22597 } 22598 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 22599 22600 final int privateFlags2 = mPrivateFlags2; 22601 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 22602 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 22603 } 22604 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 22605 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 22606 } 22607 22608 drawableState = StateSet.get(viewStateIndex); 22609 22610 //noinspection ConstantIfStatement 22611 if (false) { 22612 Log.i("View", "drawableStateIndex=" + viewStateIndex); 22613 Log.i("View", toString() 22614 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 22615 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 22616 + " fo=" + hasFocus() 22617 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 22618 + " wf=" + hasWindowFocus() 22619 + ": " + Arrays.toString(drawableState)); 22620 } 22621 22622 if (extraSpace == 0) { 22623 return drawableState; 22624 } 22625 22626 final int[] fullState; 22627 if (drawableState != null) { 22628 fullState = new int[drawableState.length + extraSpace]; 22629 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 22630 } else { 22631 fullState = new int[extraSpace]; 22632 } 22633 22634 return fullState; 22635 } 22636 22637 /** 22638 * Merge your own state values in <var>additionalState</var> into the base 22639 * state values <var>baseState</var> that were returned by 22640 * {@link #onCreateDrawableState(int)}. 22641 * 22642 * @param baseState The base state values returned by 22643 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 22644 * own additional state values. 22645 * 22646 * @param additionalState The additional state values you would like 22647 * added to <var>baseState</var>; this array is not modified. 22648 * 22649 * @return As a convenience, the <var>baseState</var> array you originally 22650 * passed into the function is returned. 22651 * 22652 * @see #onCreateDrawableState(int) 22653 */ mergeDrawableStates(int[] baseState, int[] additionalState)22654 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 22655 final int N = baseState.length; 22656 int i = N - 1; 22657 while (i >= 0 && baseState[i] == 0) { 22658 i--; 22659 } 22660 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 22661 return baseState; 22662 } 22663 22664 /** 22665 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 22666 * on all Drawable objects associated with this view. 22667 * <p> 22668 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 22669 * attached to this view. 22670 */ 22671 @CallSuper jumpDrawablesToCurrentState()22672 public void jumpDrawablesToCurrentState() { 22673 if (mBackground != null) { 22674 mBackground.jumpToCurrentState(); 22675 } 22676 if (mStateListAnimator != null) { 22677 mStateListAnimator.jumpToCurrentState(); 22678 } 22679 if (mDefaultFocusHighlight != null) { 22680 mDefaultFocusHighlight.jumpToCurrentState(); 22681 } 22682 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 22683 mForegroundInfo.mDrawable.jumpToCurrentState(); 22684 } 22685 } 22686 22687 /** 22688 * Sets the background color for this view. 22689 * @param color the color of the background 22690 */ 22691 @RemotableViewMethod setBackgroundColor(@olorInt int color)22692 public void setBackgroundColor(@ColorInt int color) { 22693 if (mBackground instanceof ColorDrawable) { 22694 ((ColorDrawable) mBackground.mutate()).setColor(color); 22695 computeOpaqueFlags(); 22696 mBackgroundResource = 0; 22697 } else { 22698 setBackground(new ColorDrawable(color)); 22699 } 22700 } 22701 22702 /** 22703 * Set the background to a given resource. The resource should refer to 22704 * a Drawable object or 0 to remove the background. 22705 * @param resid The identifier of the resource. 22706 * 22707 * @attr ref android.R.styleable#View_background 22708 */ 22709 @RemotableViewMethod setBackgroundResource(@rawableRes int resid)22710 public void setBackgroundResource(@DrawableRes int resid) { 22711 if (resid != 0 && resid == mBackgroundResource) { 22712 return; 22713 } 22714 22715 Drawable d = null; 22716 if (resid != 0) { 22717 d = mContext.getDrawable(resid); 22718 } 22719 setBackground(d); 22720 22721 mBackgroundResource = resid; 22722 } 22723 22724 /** 22725 * Set the background to a given Drawable, or remove the background. If the 22726 * background has padding, this View's padding is set to the background's 22727 * padding. However, when a background is removed, this View's padding isn't 22728 * touched. If setting the padding is desired, please use 22729 * {@link #setPadding(int, int, int, int)}. 22730 * 22731 * @param background The Drawable to use as the background, or null to remove the 22732 * background 22733 */ setBackground(Drawable background)22734 public void setBackground(Drawable background) { 22735 //noinspection deprecation 22736 setBackgroundDrawable(background); 22737 } 22738 22739 /** 22740 * @deprecated use {@link #setBackground(Drawable)} instead 22741 */ 22742 @Deprecated setBackgroundDrawable(Drawable background)22743 public void setBackgroundDrawable(Drawable background) { 22744 computeOpaqueFlags(); 22745 22746 if (background == mBackground) { 22747 return; 22748 } 22749 22750 boolean requestLayout = false; 22751 22752 mBackgroundResource = 0; 22753 22754 /* 22755 * Regardless of whether we're setting a new background or not, we want 22756 * to clear the previous drawable. setVisible first while we still have the callback set. 22757 */ 22758 if (mBackground != null) { 22759 if (isAttachedToWindow()) { 22760 mBackground.setVisible(false, false); 22761 } 22762 mBackground.setCallback(null); 22763 unscheduleDrawable(mBackground); 22764 } 22765 22766 if (background != null) { 22767 Rect padding = sThreadLocal.get(); 22768 if (padding == null) { 22769 padding = new Rect(); 22770 sThreadLocal.set(padding); 22771 } 22772 resetResolvedDrawablesInternal(); 22773 background.setLayoutDirection(getLayoutDirection()); 22774 if (background.getPadding(padding)) { 22775 resetResolvedPaddingInternal(); 22776 switch (background.getLayoutDirection()) { 22777 case LAYOUT_DIRECTION_RTL: 22778 mUserPaddingLeftInitial = padding.right; 22779 mUserPaddingRightInitial = padding.left; 22780 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 22781 break; 22782 case LAYOUT_DIRECTION_LTR: 22783 default: 22784 mUserPaddingLeftInitial = padding.left; 22785 mUserPaddingRightInitial = padding.right; 22786 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 22787 } 22788 mLeftPaddingDefined = false; 22789 mRightPaddingDefined = false; 22790 } 22791 22792 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 22793 // if it has a different minimum size, we should layout again 22794 if (mBackground == null 22795 || mBackground.getMinimumHeight() != background.getMinimumHeight() 22796 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 22797 requestLayout = true; 22798 } 22799 22800 // Set mBackground before we set this as the callback and start making other 22801 // background drawable state change calls. In particular, the setVisible call below 22802 // can result in drawables attempting to start animations or otherwise invalidate, 22803 // which requires the view set as the callback (us) to recognize the drawable as 22804 // belonging to it as per verifyDrawable. 22805 mBackground = background; 22806 if (background.isStateful()) { 22807 background.setState(getDrawableState()); 22808 } 22809 if (isAttachedToWindow()) { 22810 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 22811 } 22812 22813 applyBackgroundTint(); 22814 22815 // Set callback last, since the view may still be initializing. 22816 background.setCallback(this); 22817 22818 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 22819 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 22820 requestLayout = true; 22821 } 22822 } else { 22823 /* Remove the background */ 22824 mBackground = null; 22825 if ((mViewFlags & WILL_NOT_DRAW) != 0 22826 && (mDefaultFocusHighlight == null) 22827 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 22828 mPrivateFlags |= PFLAG_SKIP_DRAW; 22829 } 22830 22831 /* 22832 * When the background is set, we try to apply its padding to this 22833 * View. When the background is removed, we don't touch this View's 22834 * padding. This is noted in the Javadocs. Hence, we don't need to 22835 * requestLayout(), the invalidate() below is sufficient. 22836 */ 22837 22838 // The old background's minimum size could have affected this 22839 // View's layout, so let's requestLayout 22840 requestLayout = true; 22841 } 22842 22843 computeOpaqueFlags(); 22844 22845 if (requestLayout) { 22846 requestLayout(); 22847 } 22848 22849 mBackgroundSizeChanged = true; 22850 invalidate(true); 22851 invalidateOutline(); 22852 } 22853 22854 /** 22855 * Gets the background drawable 22856 * 22857 * @return The drawable used as the background for this view, if any. 22858 * 22859 * @see #setBackground(Drawable) 22860 * 22861 * @attr ref android.R.styleable#View_background 22862 */ 22863 @InspectableProperty getBackground()22864 public Drawable getBackground() { 22865 return mBackground; 22866 } 22867 22868 /** 22869 * Applies a tint to the background drawable. Does not modify the current tint 22870 * mode, which is {@link BlendMode#SRC_IN} by default. 22871 * <p> 22872 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 22873 * mutate the drawable and apply the specified tint and tint mode using 22874 * {@link Drawable#setTintList(ColorStateList)}. 22875 * 22876 * @param tint the tint to apply, may be {@code null} to clear tint 22877 * 22878 * @attr ref android.R.styleable#View_backgroundTint 22879 * @see #getBackgroundTintList() 22880 * @see Drawable#setTintList(ColorStateList) 22881 */ setBackgroundTintList(@ullable ColorStateList tint)22882 public void setBackgroundTintList(@Nullable ColorStateList tint) { 22883 if (mBackgroundTint == null) { 22884 mBackgroundTint = new TintInfo(); 22885 } 22886 mBackgroundTint.mTintList = tint; 22887 mBackgroundTint.mHasTintList = true; 22888 22889 applyBackgroundTint(); 22890 } 22891 22892 /** 22893 * Return the tint applied to the background drawable, if specified. 22894 * 22895 * @return the tint applied to the background drawable 22896 * @attr ref android.R.styleable#View_backgroundTint 22897 * @see #setBackgroundTintList(ColorStateList) 22898 */ 22899 @InspectableProperty(name = "backgroundTint") 22900 @Nullable getBackgroundTintList()22901 public ColorStateList getBackgroundTintList() { 22902 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 22903 } 22904 22905 /** 22906 * Specifies the blending mode used to apply the tint specified by 22907 * {@link #setBackgroundTintList(ColorStateList)}} to the background 22908 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 22909 * 22910 * @param tintMode the blending mode used to apply the tint, may be 22911 * {@code null} to clear tint 22912 * @attr ref android.R.styleable#View_backgroundTintMode 22913 * @see #getBackgroundTintMode() 22914 * @see Drawable#setTintMode(PorterDuff.Mode) 22915 */ setBackgroundTintMode(@ullable PorterDuff.Mode tintMode)22916 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 22917 BlendMode mode = null; 22918 if (tintMode != null) { 22919 mode = BlendMode.fromValue(tintMode.nativeInt); 22920 } 22921 22922 setBackgroundTintBlendMode(mode); 22923 } 22924 22925 /** 22926 * Specifies the blending mode used to apply the tint specified by 22927 * {@link #setBackgroundTintList(ColorStateList)}} to the background 22928 * drawable. The default mode is {@link BlendMode#SRC_IN}. 22929 * 22930 * @param blendMode the blending mode used to apply the tint, may be 22931 * {@code null} to clear tint 22932 * @attr ref android.R.styleable#View_backgroundTintMode 22933 * @see #getBackgroundTintMode() 22934 * @see Drawable#setTintBlendMode(BlendMode) 22935 */ setBackgroundTintBlendMode(@ullable BlendMode blendMode)22936 public void setBackgroundTintBlendMode(@Nullable BlendMode blendMode) { 22937 if (mBackgroundTint == null) { 22938 mBackgroundTint = new TintInfo(); 22939 } 22940 22941 mBackgroundTint.mBlendMode = blendMode; 22942 mBackgroundTint.mHasTintMode = true; 22943 22944 applyBackgroundTint(); 22945 } 22946 22947 /** 22948 * Return the blending mode used to apply the tint to the background 22949 * drawable, if specified. 22950 * 22951 * @return the blending mode used to apply the tint to the background 22952 * drawable 22953 * @attr ref android.R.styleable#View_backgroundTintMode 22954 * @see #setBackgroundTintBlendMode(BlendMode) 22955 * 22956 */ 22957 @Nullable 22958 @InspectableProperty getBackgroundTintMode()22959 public PorterDuff.Mode getBackgroundTintMode() { 22960 PorterDuff.Mode porterDuffMode; 22961 if (mBackgroundTint != null && mBackgroundTint.mBlendMode != null) { 22962 porterDuffMode = BlendMode.blendModeToPorterDuffMode(mBackgroundTint.mBlendMode); 22963 } else { 22964 porterDuffMode = null; 22965 } 22966 return porterDuffMode; 22967 } 22968 22969 /** 22970 * Return the blending mode used to apply the tint to the background 22971 * drawable, if specified. 22972 * 22973 * @return the blending mode used to apply the tint to the background 22974 * drawable, null if no blend has previously been configured 22975 * @attr ref android.R.styleable#View_backgroundTintMode 22976 * @see #setBackgroundTintBlendMode(BlendMode) 22977 */ getBackgroundTintBlendMode()22978 public @Nullable BlendMode getBackgroundTintBlendMode() { 22979 return mBackgroundTint != null ? mBackgroundTint.mBlendMode : null; 22980 } 22981 applyBackgroundTint()22982 private void applyBackgroundTint() { 22983 if (mBackground != null && mBackgroundTint != null) { 22984 final TintInfo tintInfo = mBackgroundTint; 22985 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 22986 mBackground = mBackground.mutate(); 22987 22988 if (tintInfo.mHasTintList) { 22989 mBackground.setTintList(tintInfo.mTintList); 22990 } 22991 22992 if (tintInfo.mHasTintMode) { 22993 mBackground.setTintBlendMode(tintInfo.mBlendMode); 22994 } 22995 22996 // The drawable (or one of its children) may not have been 22997 // stateful before applying the tint, so let's try again. 22998 if (mBackground.isStateful()) { 22999 mBackground.setState(getDrawableState()); 23000 } 23001 } 23002 } 23003 } 23004 23005 /** 23006 * Returns the drawable used as the foreground of this View. The 23007 * foreground drawable, if non-null, is always drawn on top of the view's content. 23008 * 23009 * @return a Drawable or null if no foreground was set 23010 * 23011 * @see #onDrawForeground(Canvas) 23012 */ 23013 @InspectableProperty getForeground()23014 public Drawable getForeground() { 23015 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 23016 } 23017 23018 /** 23019 * Supply a Drawable that is to be rendered on top of all of the content in the view. 23020 * 23021 * @param foreground the Drawable to be drawn on top of the children 23022 * 23023 * @attr ref android.R.styleable#View_foreground 23024 */ setForeground(Drawable foreground)23025 public void setForeground(Drawable foreground) { 23026 if (mForegroundInfo == null) { 23027 if (foreground == null) { 23028 // Nothing to do. 23029 return; 23030 } 23031 mForegroundInfo = new ForegroundInfo(); 23032 } 23033 23034 if (foreground == mForegroundInfo.mDrawable) { 23035 // Nothing to do 23036 return; 23037 } 23038 23039 if (mForegroundInfo.mDrawable != null) { 23040 if (isAttachedToWindow()) { 23041 mForegroundInfo.mDrawable.setVisible(false, false); 23042 } 23043 mForegroundInfo.mDrawable.setCallback(null); 23044 unscheduleDrawable(mForegroundInfo.mDrawable); 23045 } 23046 23047 mForegroundInfo.mDrawable = foreground; 23048 mForegroundInfo.mBoundsChanged = true; 23049 if (foreground != null) { 23050 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 23051 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 23052 } 23053 foreground.setLayoutDirection(getLayoutDirection()); 23054 if (foreground.isStateful()) { 23055 foreground.setState(getDrawableState()); 23056 } 23057 applyForegroundTint(); 23058 if (isAttachedToWindow()) { 23059 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 23060 } 23061 // Set callback last, since the view may still be initializing. 23062 foreground.setCallback(this); 23063 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 23064 && (mDefaultFocusHighlight == null)) { 23065 mPrivateFlags |= PFLAG_SKIP_DRAW; 23066 } 23067 requestLayout(); 23068 invalidate(); 23069 } 23070 23071 /** 23072 * Magic bit used to support features of framework-internal window decor implementation details. 23073 * This used to live exclusively in FrameLayout. 23074 * 23075 * @return true if the foreground should draw inside the padding region or false 23076 * if it should draw inset by the view's padding 23077 * @hide internal use only; only used by FrameLayout and internal screen layouts. 23078 */ isForegroundInsidePadding()23079 public boolean isForegroundInsidePadding() { 23080 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 23081 } 23082 23083 /** 23084 * Describes how the foreground is positioned. 23085 * 23086 * @return foreground gravity. 23087 * 23088 * @see #setForegroundGravity(int) 23089 * 23090 * @attr ref android.R.styleable#View_foregroundGravity 23091 */ 23092 @InspectableProperty(valueType = InspectableProperty.ValueType.GRAVITY) getForegroundGravity()23093 public int getForegroundGravity() { 23094 return mForegroundInfo != null ? mForegroundInfo.mGravity 23095 : Gravity.START | Gravity.TOP; 23096 } 23097 23098 /** 23099 * Describes how the foreground is positioned. Defaults to START and TOP. 23100 * 23101 * @param gravity see {@link android.view.Gravity} 23102 * 23103 * @see #getForegroundGravity() 23104 * 23105 * @attr ref android.R.styleable#View_foregroundGravity 23106 */ setForegroundGravity(int gravity)23107 public void setForegroundGravity(int gravity) { 23108 if (mForegroundInfo == null) { 23109 mForegroundInfo = new ForegroundInfo(); 23110 } 23111 23112 if (mForegroundInfo.mGravity != gravity) { 23113 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 23114 gravity |= Gravity.START; 23115 } 23116 23117 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 23118 gravity |= Gravity.TOP; 23119 } 23120 23121 mForegroundInfo.mGravity = gravity; 23122 requestLayout(); 23123 } 23124 } 23125 23126 /** 23127 * Applies a tint to the foreground drawable. Does not modify the current tint 23128 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 23129 * <p> 23130 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 23131 * mutate the drawable and apply the specified tint and tint mode using 23132 * {@link Drawable#setTintList(ColorStateList)}. 23133 * 23134 * @param tint the tint to apply, may be {@code null} to clear tint 23135 * 23136 * @attr ref android.R.styleable#View_foregroundTint 23137 * @see #getForegroundTintList() 23138 * @see Drawable#setTintList(ColorStateList) 23139 */ setForegroundTintList(@ullable ColorStateList tint)23140 public void setForegroundTintList(@Nullable ColorStateList tint) { 23141 if (mForegroundInfo == null) { 23142 mForegroundInfo = new ForegroundInfo(); 23143 } 23144 if (mForegroundInfo.mTintInfo == null) { 23145 mForegroundInfo.mTintInfo = new TintInfo(); 23146 } 23147 mForegroundInfo.mTintInfo.mTintList = tint; 23148 mForegroundInfo.mTintInfo.mHasTintList = true; 23149 23150 applyForegroundTint(); 23151 } 23152 23153 /** 23154 * Return the tint applied to the foreground drawable, if specified. 23155 * 23156 * @return the tint applied to the foreground drawable 23157 * @attr ref android.R.styleable#View_foregroundTint 23158 * @see #setForegroundTintList(ColorStateList) 23159 */ 23160 @InspectableProperty(name = "foregroundTint") 23161 @Nullable getForegroundTintList()23162 public ColorStateList getForegroundTintList() { 23163 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 23164 ? mForegroundInfo.mTintInfo.mTintList : null; 23165 } 23166 23167 /** 23168 * Specifies the blending mode used to apply the tint specified by 23169 * {@link #setForegroundTintList(ColorStateList)}} to the background 23170 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 23171 * 23172 * @param tintMode the blending mode used to apply the tint, may be 23173 * {@code null} to clear tint 23174 * @attr ref android.R.styleable#View_foregroundTintMode 23175 * @see #getForegroundTintMode() 23176 * @see Drawable#setTintMode(PorterDuff.Mode) 23177 * 23178 */ setForegroundTintMode(@ullable PorterDuff.Mode tintMode)23179 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 23180 BlendMode mode = null; 23181 if (tintMode != null) { 23182 mode = BlendMode.fromValue(tintMode.nativeInt); 23183 } 23184 setForegroundTintBlendMode(mode); 23185 } 23186 23187 /** 23188 * Specifies the blending mode used to apply the tint specified by 23189 * {@link #setForegroundTintList(ColorStateList)}} to the background 23190 * drawable. The default mode is {@link BlendMode#SRC_IN}. 23191 * 23192 * @param blendMode the blending mode used to apply the tint, may be 23193 * {@code null} to clear tint 23194 * @attr ref android.R.styleable#View_foregroundTintMode 23195 * @see #getForegroundTintMode() 23196 * @see Drawable#setTintBlendMode(BlendMode) 23197 */ setForegroundTintBlendMode(@ullable BlendMode blendMode)23198 public void setForegroundTintBlendMode(@Nullable BlendMode blendMode) { 23199 if (mForegroundInfo == null) { 23200 mForegroundInfo = new ForegroundInfo(); 23201 } 23202 if (mForegroundInfo.mTintInfo == null) { 23203 mForegroundInfo.mTintInfo = new TintInfo(); 23204 } 23205 mForegroundInfo.mTintInfo.mBlendMode = blendMode; 23206 mForegroundInfo.mTintInfo.mHasTintMode = true; 23207 23208 applyForegroundTint(); 23209 } 23210 23211 /** 23212 * Return the blending mode used to apply the tint to the foreground 23213 * drawable, if specified. 23214 * 23215 * @return the blending mode used to apply the tint to the foreground 23216 * drawable 23217 * @attr ref android.R.styleable#View_foregroundTintMode 23218 * @see #setForegroundTintMode(PorterDuff.Mode) 23219 */ 23220 @InspectableProperty 23221 @Nullable getForegroundTintMode()23222 public PorterDuff.Mode getForegroundTintMode() { 23223 BlendMode blendMode = mForegroundInfo != null && mForegroundInfo.mTintInfo != null 23224 ? mForegroundInfo.mTintInfo.mBlendMode : null; 23225 if (blendMode != null) { 23226 return BlendMode.blendModeToPorterDuffMode(blendMode); 23227 } else { 23228 return null; 23229 } 23230 } 23231 23232 /** 23233 * Return the blending mode used to apply the tint to the foreground 23234 * drawable, if specified. 23235 * 23236 * @return the blending mode used to apply the tint to the foreground 23237 * drawable 23238 * @attr ref android.R.styleable#View_foregroundTintMode 23239 * @see #setForegroundTintBlendMode(BlendMode) 23240 * 23241 */ getForegroundTintBlendMode()23242 public @Nullable BlendMode getForegroundTintBlendMode() { 23243 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 23244 ? mForegroundInfo.mTintInfo.mBlendMode : null; 23245 } 23246 applyForegroundTint()23247 private void applyForegroundTint() { 23248 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 23249 && mForegroundInfo.mTintInfo != null) { 23250 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 23251 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 23252 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 23253 23254 if (tintInfo.mHasTintList) { 23255 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 23256 } 23257 23258 if (tintInfo.mHasTintMode) { 23259 mForegroundInfo.mDrawable.setTintBlendMode(tintInfo.mBlendMode); 23260 } 23261 23262 // The drawable (or one of its children) may not have been 23263 // stateful before applying the tint, so let's try again. 23264 if (mForegroundInfo.mDrawable.isStateful()) { 23265 mForegroundInfo.mDrawable.setState(getDrawableState()); 23266 } 23267 } 23268 } 23269 } 23270 23271 /** 23272 * Get the drawable to be overlayed when a view is autofilled 23273 * 23274 * @return The drawable 23275 * 23276 * @throws IllegalStateException if the drawable could not be found. 23277 */ getAutofilledDrawable()23278 @Nullable private Drawable getAutofilledDrawable() { 23279 if (mAttachInfo == null) { 23280 return null; 23281 } 23282 // Lazily load the isAutofilled drawable. 23283 if (mAttachInfo.mAutofilledDrawable == null) { 23284 Context rootContext = getRootView().getContext(); 23285 TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR); 23286 int attributeResourceId = a.getResourceId(0, 0); 23287 mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId); 23288 a.recycle(); 23289 } 23290 23291 return mAttachInfo.mAutofilledDrawable; 23292 } 23293 23294 /** 23295 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled. 23296 * 23297 * @param canvas The canvas to draw on 23298 */ drawAutofilledHighlight(@onNull Canvas canvas)23299 private void drawAutofilledHighlight(@NonNull Canvas canvas) { 23300 if (isAutofilled()) { 23301 Drawable autofilledHighlight = getAutofilledDrawable(); 23302 23303 if (autofilledHighlight != null) { 23304 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); 23305 autofilledHighlight.draw(canvas); 23306 } 23307 } 23308 } 23309 23310 /** 23311 * Draw any foreground content for this view. 23312 * 23313 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 23314 * drawable or other view-specific decorations. The foreground is drawn on top of the 23315 * primary view content.</p> 23316 * 23317 * @param canvas canvas to draw into 23318 */ onDrawForeground(Canvas canvas)23319 public void onDrawForeground(Canvas canvas) { 23320 onDrawScrollIndicators(canvas); 23321 onDrawScrollBars(canvas); 23322 23323 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 23324 if (foreground != null) { 23325 if (mForegroundInfo.mBoundsChanged) { 23326 mForegroundInfo.mBoundsChanged = false; 23327 final Rect selfBounds = mForegroundInfo.mSelfBounds; 23328 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 23329 23330 if (mForegroundInfo.mInsidePadding) { 23331 selfBounds.set(0, 0, getWidth(), getHeight()); 23332 } else { 23333 selfBounds.set(getPaddingLeft(), getPaddingTop(), 23334 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 23335 } 23336 23337 final int ld = getLayoutDirection(); 23338 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 23339 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 23340 foreground.setBounds(overlayBounds); 23341 } 23342 23343 foreground.draw(canvas); 23344 } 23345 } 23346 23347 /** 23348 * Sets the padding. The view may add on the space required to display 23349 * the scrollbars, depending on the style and visibility of the scrollbars. 23350 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 23351 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 23352 * from the values set in this call. 23353 * 23354 * @attr ref android.R.styleable#View_padding 23355 * @attr ref android.R.styleable#View_paddingBottom 23356 * @attr ref android.R.styleable#View_paddingLeft 23357 * @attr ref android.R.styleable#View_paddingRight 23358 * @attr ref android.R.styleable#View_paddingTop 23359 * @param left the left padding in pixels 23360 * @param top the top padding in pixels 23361 * @param right the right padding in pixels 23362 * @param bottom the bottom padding in pixels 23363 */ setPadding(int left, int top, int right, int bottom)23364 public void setPadding(int left, int top, int right, int bottom) { 23365 resetResolvedPaddingInternal(); 23366 23367 mUserPaddingStart = UNDEFINED_PADDING; 23368 mUserPaddingEnd = UNDEFINED_PADDING; 23369 23370 mUserPaddingLeftInitial = left; 23371 mUserPaddingRightInitial = right; 23372 23373 mLeftPaddingDefined = true; 23374 mRightPaddingDefined = true; 23375 23376 internalSetPadding(left, top, right, bottom); 23377 } 23378 23379 /** 23380 * @hide 23381 */ 23382 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768420) internalSetPadding(int left, int top, int right, int bottom)23383 protected void internalSetPadding(int left, int top, int right, int bottom) { 23384 mUserPaddingLeft = left; 23385 mUserPaddingRight = right; 23386 mUserPaddingBottom = bottom; 23387 23388 final int viewFlags = mViewFlags; 23389 boolean changed = false; 23390 23391 // Common case is there are no scroll bars. 23392 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 23393 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 23394 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 23395 ? 0 : getVerticalScrollbarWidth(); 23396 switch (mVerticalScrollbarPosition) { 23397 case SCROLLBAR_POSITION_DEFAULT: 23398 if (isLayoutRtl()) { 23399 left += offset; 23400 } else { 23401 right += offset; 23402 } 23403 break; 23404 case SCROLLBAR_POSITION_RIGHT: 23405 right += offset; 23406 break; 23407 case SCROLLBAR_POSITION_LEFT: 23408 left += offset; 23409 break; 23410 } 23411 } 23412 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 23413 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 23414 ? 0 : getHorizontalScrollbarHeight(); 23415 } 23416 } 23417 23418 if (mPaddingLeft != left) { 23419 changed = true; 23420 mPaddingLeft = left; 23421 } 23422 if (mPaddingTop != top) { 23423 changed = true; 23424 mPaddingTop = top; 23425 } 23426 if (mPaddingRight != right) { 23427 changed = true; 23428 mPaddingRight = right; 23429 } 23430 if (mPaddingBottom != bottom) { 23431 changed = true; 23432 mPaddingBottom = bottom; 23433 } 23434 23435 if (changed) { 23436 requestLayout(); 23437 invalidateOutline(); 23438 } 23439 } 23440 23441 /** 23442 * Sets the relative padding. The view may add on the space required to display 23443 * the scrollbars, depending on the style and visibility of the scrollbars. 23444 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 23445 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 23446 * from the values set in this call. 23447 * 23448 * @attr ref android.R.styleable#View_padding 23449 * @attr ref android.R.styleable#View_paddingBottom 23450 * @attr ref android.R.styleable#View_paddingStart 23451 * @attr ref android.R.styleable#View_paddingEnd 23452 * @attr ref android.R.styleable#View_paddingTop 23453 * @param start the start padding in pixels 23454 * @param top the top padding in pixels 23455 * @param end the end padding in pixels 23456 * @param bottom the bottom padding in pixels 23457 */ setPaddingRelative(int start, int top, int end, int bottom)23458 public void setPaddingRelative(int start, int top, int end, int bottom) { 23459 resetResolvedPaddingInternal(); 23460 23461 mUserPaddingStart = start; 23462 mUserPaddingEnd = end; 23463 mLeftPaddingDefined = true; 23464 mRightPaddingDefined = true; 23465 23466 switch(getLayoutDirection()) { 23467 case LAYOUT_DIRECTION_RTL: 23468 mUserPaddingLeftInitial = end; 23469 mUserPaddingRightInitial = start; 23470 internalSetPadding(end, top, start, bottom); 23471 break; 23472 case LAYOUT_DIRECTION_LTR: 23473 default: 23474 mUserPaddingLeftInitial = start; 23475 mUserPaddingRightInitial = end; 23476 internalSetPadding(start, top, end, bottom); 23477 } 23478 } 23479 23480 /** 23481 * A {@link View} can be inflated from an XML layout. For such Views this method returns the 23482 * resource ID of the source layout. 23483 * 23484 * @return The layout resource id if this view was inflated from XML, otherwise 23485 * {@link Resources#ID_NULL}. 23486 */ 23487 @LayoutRes getSourceLayoutResId()23488 public int getSourceLayoutResId() { 23489 return mSourceLayoutId; 23490 } 23491 23492 /** 23493 * Returns the top padding of this view. 23494 * 23495 * @return the top padding in pixels 23496 */ 23497 @InspectableProperty getPaddingTop()23498 public int getPaddingTop() { 23499 return mPaddingTop; 23500 } 23501 23502 /** 23503 * Returns the bottom padding of this view. If there are inset and enabled 23504 * scrollbars, this value may include the space required to display the 23505 * scrollbars as well. 23506 * 23507 * @return the bottom padding in pixels 23508 */ 23509 @InspectableProperty getPaddingBottom()23510 public int getPaddingBottom() { 23511 return mPaddingBottom; 23512 } 23513 23514 /** 23515 * Returns the left padding of this view. If there are inset and enabled 23516 * scrollbars, this value may include the space required to display the 23517 * scrollbars as well. 23518 * 23519 * @return the left padding in pixels 23520 */ 23521 @InspectableProperty getPaddingLeft()23522 public int getPaddingLeft() { 23523 if (!isPaddingResolved()) { 23524 resolvePadding(); 23525 } 23526 return mPaddingLeft; 23527 } 23528 23529 /** 23530 * Returns the start padding of this view depending on its resolved layout direction. 23531 * If there are inset and enabled scrollbars, this value may include the space 23532 * required to display the scrollbars as well. 23533 * 23534 * @return the start padding in pixels 23535 */ getPaddingStart()23536 public int getPaddingStart() { 23537 if (!isPaddingResolved()) { 23538 resolvePadding(); 23539 } 23540 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 23541 mPaddingRight : mPaddingLeft; 23542 } 23543 23544 /** 23545 * Returns the right padding of this view. If there are inset and enabled 23546 * scrollbars, this value may include the space required to display the 23547 * scrollbars as well. 23548 * 23549 * @return the right padding in pixels 23550 */ 23551 @InspectableProperty getPaddingRight()23552 public int getPaddingRight() { 23553 if (!isPaddingResolved()) { 23554 resolvePadding(); 23555 } 23556 return mPaddingRight; 23557 } 23558 23559 /** 23560 * Returns the end padding of this view depending on its resolved layout direction. 23561 * If there are inset and enabled scrollbars, this value may include the space 23562 * required to display the scrollbars as well. 23563 * 23564 * @return the end padding in pixels 23565 */ getPaddingEnd()23566 public int getPaddingEnd() { 23567 if (!isPaddingResolved()) { 23568 resolvePadding(); 23569 } 23570 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 23571 mPaddingLeft : mPaddingRight; 23572 } 23573 23574 /** 23575 * Return if the padding has been set through relative values 23576 * {@link #setPaddingRelative(int, int, int, int)} or through 23577 * @attr ref android.R.styleable#View_paddingStart or 23578 * @attr ref android.R.styleable#View_paddingEnd 23579 * 23580 * @return true if the padding is relative or false if it is not. 23581 */ isPaddingRelative()23582 public boolean isPaddingRelative() { 23583 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 23584 } 23585 computeOpticalInsets()23586 Insets computeOpticalInsets() { 23587 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 23588 } 23589 23590 /** 23591 * @hide 23592 */ 23593 @UnsupportedAppUsage resetPaddingToInitialValues()23594 public void resetPaddingToInitialValues() { 23595 if (isRtlCompatibilityMode()) { 23596 mPaddingLeft = mUserPaddingLeftInitial; 23597 mPaddingRight = mUserPaddingRightInitial; 23598 return; 23599 } 23600 if (isLayoutRtl()) { 23601 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 23602 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 23603 } else { 23604 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 23605 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 23606 } 23607 } 23608 23609 /** 23610 * @hide 23611 */ getOpticalInsets()23612 public Insets getOpticalInsets() { 23613 if (mLayoutInsets == null) { 23614 mLayoutInsets = computeOpticalInsets(); 23615 } 23616 return mLayoutInsets; 23617 } 23618 23619 /** 23620 * Set this view's optical insets. 23621 * 23622 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 23623 * property. Views that compute their own optical insets should call it as part of measurement. 23624 * This method does not request layout. If you are setting optical insets outside of 23625 * measure/layout itself you will want to call requestLayout() yourself. 23626 * </p> 23627 * @hide 23628 */ setOpticalInsets(Insets insets)23629 public void setOpticalInsets(Insets insets) { 23630 mLayoutInsets = insets; 23631 } 23632 23633 /** 23634 * Changes the selection state of this view. A view can be selected or not. 23635 * Note that selection is not the same as focus. Views are typically 23636 * selected in the context of an AdapterView like ListView or GridView; 23637 * the selected view is the view that is highlighted. 23638 * 23639 * @param selected true if the view must be selected, false otherwise 23640 */ setSelected(boolean selected)23641 public void setSelected(boolean selected) { 23642 //noinspection DoubleNegation 23643 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 23644 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 23645 if (!selected) resetPressedState(); 23646 invalidate(true); 23647 refreshDrawableState(); 23648 dispatchSetSelected(selected); 23649 if (selected) { 23650 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 23651 } else { 23652 notifyViewAccessibilityStateChangedIfNeeded( 23653 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 23654 } 23655 } 23656 } 23657 23658 /** 23659 * Dispatch setSelected to all of this View's children. 23660 * 23661 * @see #setSelected(boolean) 23662 * 23663 * @param selected The new selected state 23664 */ dispatchSetSelected(boolean selected)23665 protected void dispatchSetSelected(boolean selected) { 23666 } 23667 23668 /** 23669 * Indicates the selection state of this view. 23670 * 23671 * @return true if the view is selected, false otherwise 23672 */ 23673 @ViewDebug.ExportedProperty 23674 @InspectableProperty(hasAttributeId = false) isSelected()23675 public boolean isSelected() { 23676 return (mPrivateFlags & PFLAG_SELECTED) != 0; 23677 } 23678 23679 /** 23680 * Changes the activated state of this view. A view can be activated or not. 23681 * Note that activation is not the same as selection. Selection is 23682 * a transient property, representing the view (hierarchy) the user is 23683 * currently interacting with. Activation is a longer-term state that the 23684 * user can move views in and out of. For example, in a list view with 23685 * single or multiple selection enabled, the views in the current selection 23686 * set are activated. (Um, yeah, we are deeply sorry about the terminology 23687 * here.) The activated state is propagated down to children of the view it 23688 * is set on. 23689 * 23690 * @param activated true if the view must be activated, false otherwise 23691 */ setActivated(boolean activated)23692 public void setActivated(boolean activated) { 23693 //noinspection DoubleNegation 23694 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 23695 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 23696 invalidate(true); 23697 refreshDrawableState(); 23698 dispatchSetActivated(activated); 23699 } 23700 } 23701 23702 /** 23703 * Dispatch setActivated to all of this View's children. 23704 * 23705 * @see #setActivated(boolean) 23706 * 23707 * @param activated The new activated state 23708 */ dispatchSetActivated(boolean activated)23709 protected void dispatchSetActivated(boolean activated) { 23710 } 23711 23712 /** 23713 * Indicates the activation state of this view. 23714 * 23715 * @return true if the view is activated, false otherwise 23716 */ 23717 @ViewDebug.ExportedProperty 23718 @InspectableProperty(hasAttributeId = false) isActivated()23719 public boolean isActivated() { 23720 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 23721 } 23722 23723 /** 23724 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 23725 * observer can be used to get notifications when global events, like 23726 * layout, happen. 23727 * 23728 * The returned ViewTreeObserver observer is not guaranteed to remain 23729 * valid for the lifetime of this View. If the caller of this method keeps 23730 * a long-lived reference to ViewTreeObserver, it should always check for 23731 * the return value of {@link ViewTreeObserver#isAlive()}. 23732 * 23733 * @return The ViewTreeObserver for this view's hierarchy. 23734 */ getViewTreeObserver()23735 public ViewTreeObserver getViewTreeObserver() { 23736 if (mAttachInfo != null) { 23737 return mAttachInfo.mTreeObserver; 23738 } 23739 if (mFloatingTreeObserver == null) { 23740 mFloatingTreeObserver = new ViewTreeObserver(mContext); 23741 } 23742 return mFloatingTreeObserver; 23743 } 23744 23745 /** 23746 * <p>Finds the topmost view in the current view hierarchy.</p> 23747 * 23748 * @return the topmost view containing this view 23749 */ getRootView()23750 public View getRootView() { 23751 if (mAttachInfo != null) { 23752 final View v = mAttachInfo.mRootView; 23753 if (v != null) { 23754 return v; 23755 } 23756 } 23757 23758 View parent = this; 23759 23760 while (parent.mParent != null && parent.mParent instanceof View) { 23761 parent = (View) parent.mParent; 23762 } 23763 23764 return parent; 23765 } 23766 23767 /** 23768 * Transforms a motion event from view-local coordinates to on-screen 23769 * coordinates. 23770 * 23771 * @param ev the view-local motion event 23772 * @return false if the transformation could not be applied 23773 * @hide 23774 */ 23775 @UnsupportedAppUsage toGlobalMotionEvent(MotionEvent ev)23776 public boolean toGlobalMotionEvent(MotionEvent ev) { 23777 final AttachInfo info = mAttachInfo; 23778 if (info == null) { 23779 return false; 23780 } 23781 23782 final Matrix m = info.mTmpMatrix; 23783 m.set(Matrix.IDENTITY_MATRIX); 23784 transformMatrixToGlobal(m); 23785 ev.transform(m); 23786 return true; 23787 } 23788 23789 /** 23790 * Transforms a motion event from on-screen coordinates to view-local 23791 * coordinates. 23792 * 23793 * @param ev the on-screen motion event 23794 * @return false if the transformation could not be applied 23795 * @hide 23796 */ 23797 @UnsupportedAppUsage toLocalMotionEvent(MotionEvent ev)23798 public boolean toLocalMotionEvent(MotionEvent ev) { 23799 final AttachInfo info = mAttachInfo; 23800 if (info == null) { 23801 return false; 23802 } 23803 23804 final Matrix m = info.mTmpMatrix; 23805 m.set(Matrix.IDENTITY_MATRIX); 23806 transformMatrixToLocal(m); 23807 ev.transform(m); 23808 return true; 23809 } 23810 23811 /** 23812 * Modifies the input matrix such that it maps view-local coordinates to 23813 * on-screen coordinates. 23814 * 23815 * @param matrix input matrix to modify 23816 */ transformMatrixToGlobal(@onNull Matrix matrix)23817 public void transformMatrixToGlobal(@NonNull Matrix matrix) { 23818 final ViewParent parent = mParent; 23819 if (parent instanceof View) { 23820 final View vp = (View) parent; 23821 vp.transformMatrixToGlobal(matrix); 23822 matrix.preTranslate(-vp.mScrollX, -vp.mScrollY); 23823 } else if (parent instanceof ViewRootImpl) { 23824 final ViewRootImpl vr = (ViewRootImpl) parent; 23825 vr.transformMatrixToGlobal(matrix); 23826 matrix.preTranslate(0, -vr.mCurScrollY); 23827 } 23828 23829 matrix.preTranslate(mLeft, mTop); 23830 23831 if (!hasIdentityMatrix()) { 23832 matrix.preConcat(getMatrix()); 23833 } 23834 } 23835 23836 /** 23837 * Modifies the input matrix such that it maps on-screen coordinates to 23838 * view-local coordinates. 23839 * 23840 * @param matrix input matrix to modify 23841 */ transformMatrixToLocal(@onNull Matrix matrix)23842 public void transformMatrixToLocal(@NonNull Matrix matrix) { 23843 final ViewParent parent = mParent; 23844 if (parent instanceof View) { 23845 final View vp = (View) parent; 23846 vp.transformMatrixToLocal(matrix); 23847 matrix.postTranslate(vp.mScrollX, vp.mScrollY); 23848 } else if (parent instanceof ViewRootImpl) { 23849 final ViewRootImpl vr = (ViewRootImpl) parent; 23850 vr.transformMatrixToLocal(matrix); 23851 matrix.postTranslate(0, vr.mCurScrollY); 23852 } 23853 23854 matrix.postTranslate(-mLeft, -mTop); 23855 23856 if (!hasIdentityMatrix()) { 23857 matrix.postConcat(getInverseMatrix()); 23858 } 23859 } 23860 23861 /** 23862 * @hide 23863 */ 23864 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 23865 @ViewDebug.IntToString(from = 0, to = "x"), 23866 @ViewDebug.IntToString(from = 1, to = "y") 23867 }) 23868 @UnsupportedAppUsage getLocationOnScreen()23869 public int[] getLocationOnScreen() { 23870 int[] location = new int[2]; 23871 getLocationOnScreen(location); 23872 return location; 23873 } 23874 23875 /** 23876 * <p>Computes the coordinates of this view on the screen. The argument 23877 * must be an array of two integers. After the method returns, the array 23878 * contains the x and y location in that order.</p> 23879 * 23880 * @param outLocation an array of two integers in which to hold the coordinates 23881 */ getLocationOnScreen(@ize2) int[] outLocation)23882 public void getLocationOnScreen(@Size(2) int[] outLocation) { 23883 getLocationInWindow(outLocation); 23884 23885 final AttachInfo info = mAttachInfo; 23886 if (info != null) { 23887 outLocation[0] += info.mWindowLeft; 23888 outLocation[1] += info.mWindowTop; 23889 } 23890 } 23891 23892 /** 23893 * <p>Computes the coordinates of this view in its window. The argument 23894 * must be an array of two integers. After the method returns, the array 23895 * contains the x and y location in that order.</p> 23896 * 23897 * @param outLocation an array of two integers in which to hold the coordinates 23898 */ getLocationInWindow(@ize2) int[] outLocation)23899 public void getLocationInWindow(@Size(2) int[] outLocation) { 23900 if (outLocation == null || outLocation.length < 2) { 23901 throw new IllegalArgumentException("outLocation must be an array of two integers"); 23902 } 23903 23904 outLocation[0] = 0; 23905 outLocation[1] = 0; 23906 23907 transformFromViewToWindowSpace(outLocation); 23908 } 23909 23910 /** @hide */ transformFromViewToWindowSpace(@ize2) int[] inOutLocation)23911 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 23912 if (inOutLocation == null || inOutLocation.length < 2) { 23913 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 23914 } 23915 23916 if (mAttachInfo == null) { 23917 // When the view is not attached to a window, this method does not make sense 23918 inOutLocation[0] = inOutLocation[1] = 0; 23919 return; 23920 } 23921 23922 float position[] = mAttachInfo.mTmpTransformLocation; 23923 position[0] = inOutLocation[0]; 23924 position[1] = inOutLocation[1]; 23925 23926 if (!hasIdentityMatrix()) { 23927 getMatrix().mapPoints(position); 23928 } 23929 23930 position[0] += mLeft; 23931 position[1] += mTop; 23932 23933 ViewParent viewParent = mParent; 23934 while (viewParent instanceof View) { 23935 final View view = (View) viewParent; 23936 23937 position[0] -= view.mScrollX; 23938 position[1] -= view.mScrollY; 23939 23940 if (!view.hasIdentityMatrix()) { 23941 view.getMatrix().mapPoints(position); 23942 } 23943 23944 position[0] += view.mLeft; 23945 position[1] += view.mTop; 23946 23947 viewParent = view.mParent; 23948 } 23949 23950 if (viewParent instanceof ViewRootImpl) { 23951 // *cough* 23952 final ViewRootImpl vr = (ViewRootImpl) viewParent; 23953 position[1] -= vr.mCurScrollY; 23954 } 23955 23956 inOutLocation[0] = Math.round(position[0]); 23957 inOutLocation[1] = Math.round(position[1]); 23958 } 23959 23960 /** 23961 * @param id the id of the view to be found 23962 * @return the view of the specified id, null if cannot be found 23963 * @hide 23964 */ findViewTraversal(@dRes int id)23965 protected <T extends View> T findViewTraversal(@IdRes int id) { 23966 if (id == mID) { 23967 return (T) this; 23968 } 23969 return null; 23970 } 23971 23972 /** 23973 * @param tag the tag of the view to be found 23974 * @return the view of specified tag, null if cannot be found 23975 * @hide 23976 */ findViewWithTagTraversal(Object tag)23977 protected <T extends View> T findViewWithTagTraversal(Object tag) { 23978 if (tag != null && tag.equals(mTag)) { 23979 return (T) this; 23980 } 23981 return null; 23982 } 23983 23984 /** 23985 * @param predicate The predicate to evaluate. 23986 * @param childToSkip If not null, ignores this child during the recursive traversal. 23987 * @return The first view that matches the predicate or null. 23988 * @hide 23989 */ findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip)23990 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 23991 View childToSkip) { 23992 if (predicate.test(this)) { 23993 return (T) this; 23994 } 23995 return null; 23996 } 23997 23998 /** 23999 * Finds the first descendant view with the given ID, the view itself if 24000 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid 24001 * (< 0) or there is no matching view in the hierarchy. 24002 * <p> 24003 * <strong>Note:</strong> In most cases -- depending on compiler support -- 24004 * the resulting view is automatically cast to the target class type. If 24005 * the target class type is unconstrained, an explicit cast may be 24006 * necessary. 24007 * 24008 * @param id the ID to search for 24009 * @return a view with given ID if found, or {@code null} otherwise 24010 * @see View#requireViewById(int) 24011 */ 24012 @Nullable findViewById(@dRes int id)24013 public final <T extends View> T findViewById(@IdRes int id) { 24014 if (id == NO_ID) { 24015 return null; 24016 } 24017 return findViewTraversal(id); 24018 } 24019 24020 /** 24021 * Finds the first descendant view with the given ID, the view itself if the ID matches 24022 * {@link #getId()}, or throws an IllegalArgumentException if the ID is invalid or there is no 24023 * matching view in the hierarchy. 24024 * <p> 24025 * <strong>Note:</strong> In most cases -- depending on compiler support -- 24026 * the resulting view is automatically cast to the target class type. If 24027 * the target class type is unconstrained, an explicit cast may be 24028 * necessary. 24029 * 24030 * @param id the ID to search for 24031 * @return a view with given ID 24032 * @see View#findViewById(int) 24033 */ 24034 @NonNull requireViewById(@dRes int id)24035 public final <T extends View> T requireViewById(@IdRes int id) { 24036 T view = findViewById(id); 24037 if (view == null) { 24038 throw new IllegalArgumentException("ID does not reference a View inside this View"); 24039 } 24040 return view; 24041 } 24042 24043 /** 24044 * Performs the traversal to find a view by its unique and stable accessibility id. 24045 * 24046 * <strong>Note:</strong>This method does not stop at the root namespace 24047 * boundary since the user can touch the screen at an arbitrary location 24048 * potentially crossing the root namespace boundary which will send an 24049 * accessibility event to accessibility services and they should be able 24050 * to obtain the event source. Also accessibility ids are guaranteed to be 24051 * unique in the window. 24052 * 24053 * @param accessibilityId The accessibility id. 24054 * @return The found view. 24055 * @hide 24056 */ findViewByAccessibilityIdTraversal(int accessibilityId)24057 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 24058 if (getAccessibilityViewId() == accessibilityId) { 24059 return (T) this; 24060 } 24061 return null; 24062 } 24063 24064 /** 24065 * Performs the traversal to find a view by its autofill id. 24066 * 24067 * <strong>Note:</strong>This method does not stop at the root namespace 24068 * boundary. 24069 * 24070 * @param autofillId The autofill id. 24071 * @return The found view. 24072 * @hide 24073 */ findViewByAutofillIdTraversal(int autofillId)24074 public <T extends View> T findViewByAutofillIdTraversal(int autofillId) { 24075 if (getAutofillViewId() == autofillId) { 24076 return (T) this; 24077 } 24078 return null; 24079 } 24080 24081 /** 24082 * Look for a child view with the given tag. If this view has the given 24083 * tag, return this view. 24084 * 24085 * @param tag The tag to search for, using "tag.equals(getTag())". 24086 * @return The View that has the given tag in the hierarchy or null 24087 */ findViewWithTag(Object tag)24088 public final <T extends View> T findViewWithTag(Object tag) { 24089 if (tag == null) { 24090 return null; 24091 } 24092 return findViewWithTagTraversal(tag); 24093 } 24094 24095 /** 24096 * Look for a child view that matches the specified predicate. 24097 * If this view matches the predicate, return this view. 24098 * 24099 * @param predicate The predicate to evaluate. 24100 * @return The first view that matches the predicate or null. 24101 * @hide 24102 */ findViewByPredicate(Predicate<View> predicate)24103 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 24104 return findViewByPredicateTraversal(predicate, null); 24105 } 24106 24107 /** 24108 * Look for a child view that matches the specified predicate, 24109 * starting with the specified view and its descendents and then 24110 * recusively searching the ancestors and siblings of that view 24111 * until this view is reached. 24112 * 24113 * This method is useful in cases where the predicate does not match 24114 * a single unique view (perhaps multiple views use the same id) 24115 * and we are trying to find the view that is "closest" in scope to the 24116 * starting view. 24117 * 24118 * @param start The view to start from. 24119 * @param predicate The predicate to evaluate. 24120 * @return The first view that matches the predicate or null. 24121 * @hide 24122 */ findViewByPredicateInsideOut( View start, Predicate<View> predicate)24123 public final <T extends View> T findViewByPredicateInsideOut( 24124 View start, Predicate<View> predicate) { 24125 View childToSkip = null; 24126 for (;;) { 24127 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 24128 if (view != null || start == this) { 24129 return view; 24130 } 24131 24132 ViewParent parent = start.getParent(); 24133 if (parent == null || !(parent instanceof View)) { 24134 return null; 24135 } 24136 24137 childToSkip = start; 24138 start = (View) parent; 24139 } 24140 } 24141 24142 /** 24143 * Sets the identifier for this view. The identifier does not have to be 24144 * unique in this view's hierarchy. The identifier should be a positive 24145 * number. 24146 * 24147 * @see #NO_ID 24148 * @see #getId() 24149 * @see #findViewById(int) 24150 * 24151 * @param id a number used to identify the view 24152 * 24153 * @attr ref android.R.styleable#View_id 24154 */ setId(@dRes int id)24155 public void setId(@IdRes int id) { 24156 mID = id; 24157 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 24158 mID = generateViewId(); 24159 } 24160 } 24161 24162 /** 24163 * {@hide} 24164 * 24165 * @param isRoot true if the view belongs to the root namespace, false 24166 * otherwise 24167 */ 24168 @TestApi setIsRootNamespace(boolean isRoot)24169 public void setIsRootNamespace(boolean isRoot) { 24170 if (isRoot) { 24171 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 24172 } else { 24173 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 24174 } 24175 } 24176 24177 /** 24178 * {@hide} 24179 * 24180 * @return true if the view belongs to the root namespace, false otherwise 24181 */ 24182 @UnsupportedAppUsage isRootNamespace()24183 public boolean isRootNamespace() { 24184 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 24185 } 24186 24187 /** 24188 * Returns this view's identifier. 24189 * 24190 * @return a positive integer used to identify the view or {@link #NO_ID} 24191 * if the view has no ID 24192 * 24193 * @see #setId(int) 24194 * @see #findViewById(int) 24195 * @attr ref android.R.styleable#View_id 24196 */ 24197 @IdRes 24198 @ViewDebug.CapturedViewProperty 24199 @InspectableProperty getId()24200 public int getId() { 24201 return mID; 24202 } 24203 24204 /** 24205 * Get the identifier used for this view by the drawing system. 24206 * 24207 * @see RenderNode#getUniqueId() 24208 * @return A long that uniquely identifies this view's drawing component 24209 */ getUniqueDrawingId()24210 public long getUniqueDrawingId() { 24211 return mRenderNode.getUniqueId(); 24212 } 24213 24214 /** 24215 * Returns this view's tag. 24216 * 24217 * @return the Object stored in this view as a tag, or {@code null} if not 24218 * set 24219 * 24220 * @see #setTag(Object) 24221 * @see #getTag(int) 24222 */ 24223 @ViewDebug.ExportedProperty 24224 @InspectableProperty getTag()24225 public Object getTag() { 24226 return mTag; 24227 } 24228 24229 /** 24230 * Sets the tag associated with this view. A tag can be used to mark 24231 * a view in its hierarchy and does not have to be unique within the 24232 * hierarchy. Tags can also be used to store data within a view without 24233 * resorting to another data structure. 24234 * 24235 * @param tag an Object to tag the view with 24236 * 24237 * @see #getTag() 24238 * @see #setTag(int, Object) 24239 */ setTag(final Object tag)24240 public void setTag(final Object tag) { 24241 mTag = tag; 24242 } 24243 24244 /** 24245 * Returns the tag associated with this view and the specified key. 24246 * 24247 * @param key The key identifying the tag 24248 * 24249 * @return the Object stored in this view as a tag, or {@code null} if not 24250 * set 24251 * 24252 * @see #setTag(int, Object) 24253 * @see #getTag() 24254 */ getTag(int key)24255 public Object getTag(int key) { 24256 if (mKeyedTags != null) return mKeyedTags.get(key); 24257 return null; 24258 } 24259 24260 /** 24261 * Sets a tag associated with this view and a key. A tag can be used 24262 * to mark a view in its hierarchy and does not have to be unique within 24263 * the hierarchy. Tags can also be used to store data within a view 24264 * without resorting to another data structure. 24265 * 24266 * The specified key should be an id declared in the resources of the 24267 * application to ensure it is unique (see the <a 24268 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 24269 * Keys identified as belonging to 24270 * the Android framework or not associated with any package will cause 24271 * an {@link IllegalArgumentException} to be thrown. 24272 * 24273 * @param key The key identifying the tag 24274 * @param tag An Object to tag the view with 24275 * 24276 * @throws IllegalArgumentException If they specified key is not valid 24277 * 24278 * @see #setTag(Object) 24279 * @see #getTag(int) 24280 */ setTag(int key, final Object tag)24281 public void setTag(int key, final Object tag) { 24282 // If the package id is 0x00 or 0x01, it's either an undefined package 24283 // or a framework id 24284 if ((key >>> 24) < 2) { 24285 throw new IllegalArgumentException("The key must be an application-specific " 24286 + "resource id."); 24287 } 24288 24289 setKeyedTag(key, tag); 24290 } 24291 24292 /** 24293 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 24294 * framework id. 24295 * 24296 * @hide 24297 */ 24298 @UnsupportedAppUsage setTagInternal(int key, Object tag)24299 public void setTagInternal(int key, Object tag) { 24300 if ((key >>> 24) != 0x1) { 24301 throw new IllegalArgumentException("The key must be a framework-specific " 24302 + "resource id."); 24303 } 24304 24305 setKeyedTag(key, tag); 24306 } 24307 setKeyedTag(int key, Object tag)24308 private void setKeyedTag(int key, Object tag) { 24309 if (mKeyedTags == null) { 24310 mKeyedTags = new SparseArray<Object>(2); 24311 } 24312 24313 mKeyedTags.put(key, tag); 24314 } 24315 24316 /** 24317 * Prints information about this view in the log output, with the tag 24318 * {@link #VIEW_LOG_TAG}. 24319 * 24320 * @hide 24321 */ 24322 @UnsupportedAppUsage debug()24323 public void debug() { 24324 debug(0); 24325 } 24326 24327 /** 24328 * Prints information about this view in the log output, with the tag 24329 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 24330 * indentation defined by the <code>depth</code>. 24331 * 24332 * @param depth the indentation level 24333 * 24334 * @hide 24335 */ 24336 @UnsupportedAppUsage debug(int depth)24337 protected void debug(int depth) { 24338 String output = debugIndent(depth - 1); 24339 24340 output += "+ " + this; 24341 int id = getId(); 24342 if (id != -1) { 24343 output += " (id=" + id + ")"; 24344 } 24345 Object tag = getTag(); 24346 if (tag != null) { 24347 output += " (tag=" + tag + ")"; 24348 } 24349 Log.d(VIEW_LOG_TAG, output); 24350 24351 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 24352 output = debugIndent(depth) + " FOCUSED"; 24353 Log.d(VIEW_LOG_TAG, output); 24354 } 24355 24356 output = debugIndent(depth); 24357 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 24358 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 24359 + "} "; 24360 Log.d(VIEW_LOG_TAG, output); 24361 24362 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 24363 || mPaddingBottom != 0) { 24364 output = debugIndent(depth); 24365 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 24366 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 24367 Log.d(VIEW_LOG_TAG, output); 24368 } 24369 24370 output = debugIndent(depth); 24371 output += "mMeasureWidth=" + mMeasuredWidth + 24372 " mMeasureHeight=" + mMeasuredHeight; 24373 Log.d(VIEW_LOG_TAG, output); 24374 24375 output = debugIndent(depth); 24376 if (mLayoutParams == null) { 24377 output += "BAD! no layout params"; 24378 } else { 24379 output = mLayoutParams.debug(output); 24380 } 24381 Log.d(VIEW_LOG_TAG, output); 24382 24383 output = debugIndent(depth); 24384 output += "flags={"; 24385 output += View.printFlags(mViewFlags); 24386 output += "}"; 24387 Log.d(VIEW_LOG_TAG, output); 24388 24389 output = debugIndent(depth); 24390 output += "privateFlags={"; 24391 output += View.printPrivateFlags(mPrivateFlags); 24392 output += "}"; 24393 Log.d(VIEW_LOG_TAG, output); 24394 } 24395 24396 /** 24397 * Creates a string of whitespaces used for indentation. 24398 * 24399 * @param depth the indentation level 24400 * @return a String containing (depth * 2 + 3) * 2 white spaces 24401 * 24402 * @hide 24403 */ debugIndent(int depth)24404 protected static String debugIndent(int depth) { 24405 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 24406 for (int i = 0; i < (depth * 2) + 3; i++) { 24407 spaces.append(' ').append(' '); 24408 } 24409 return spaces.toString(); 24410 } 24411 24412 /** 24413 * <p>Return the offset of the widget's text baseline from the widget's top 24414 * boundary. If this widget does not support baseline alignment, this 24415 * method returns -1. </p> 24416 * 24417 * @return the offset of the baseline within the widget's bounds or -1 24418 * if baseline alignment is not supported 24419 */ 24420 @ViewDebug.ExportedProperty(category = "layout") 24421 @InspectableProperty getBaseline()24422 public int getBaseline() { 24423 return -1; 24424 } 24425 24426 /** 24427 * Returns whether the view hierarchy is currently undergoing a layout pass. This 24428 * information is useful to avoid situations such as calling {@link #requestLayout()} during 24429 * a layout pass. 24430 * 24431 * @return whether the view hierarchy is currently undergoing a layout pass 24432 */ isInLayout()24433 public boolean isInLayout() { 24434 ViewRootImpl viewRoot = getViewRootImpl(); 24435 return (viewRoot != null && viewRoot.isInLayout()); 24436 } 24437 24438 /** 24439 * Call this when something has changed which has invalidated the 24440 * layout of this view. This will schedule a layout pass of the view 24441 * tree. This should not be called while the view hierarchy is currently in a layout 24442 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 24443 * end of the current layout pass (and then layout will run again) or after the current 24444 * frame is drawn and the next layout occurs. 24445 * 24446 * <p>Subclasses which override this method should call the superclass method to 24447 * handle possible request-during-layout errors correctly.</p> 24448 */ 24449 @CallSuper requestLayout()24450 public void requestLayout() { 24451 if (mMeasureCache != null) mMeasureCache.clear(); 24452 24453 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 24454 // Only trigger request-during-layout logic if this is the view requesting it, 24455 // not the views in its parent hierarchy 24456 ViewRootImpl viewRoot = getViewRootImpl(); 24457 if (viewRoot != null && viewRoot.isInLayout()) { 24458 if (!viewRoot.requestLayoutDuringLayout(this)) { 24459 return; 24460 } 24461 } 24462 mAttachInfo.mViewRequestingLayout = this; 24463 } 24464 24465 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 24466 mPrivateFlags |= PFLAG_INVALIDATED; 24467 24468 if (mParent != null && !mParent.isLayoutRequested()) { 24469 mParent.requestLayout(); 24470 } 24471 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 24472 mAttachInfo.mViewRequestingLayout = null; 24473 } 24474 } 24475 24476 /** 24477 * Forces this view to be laid out during the next layout pass. 24478 * This method does not call requestLayout() or forceLayout() 24479 * on the parent. 24480 */ forceLayout()24481 public void forceLayout() { 24482 if (mMeasureCache != null) mMeasureCache.clear(); 24483 24484 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 24485 mPrivateFlags |= PFLAG_INVALIDATED; 24486 } 24487 24488 /** 24489 * <p> 24490 * This is called to find out how big a view should be. The parent 24491 * supplies constraint information in the width and height parameters. 24492 * </p> 24493 * 24494 * <p> 24495 * The actual measurement work of a view is performed in 24496 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 24497 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 24498 * </p> 24499 * 24500 * 24501 * @param widthMeasureSpec Horizontal space requirements as imposed by the 24502 * parent 24503 * @param heightMeasureSpec Vertical space requirements as imposed by the 24504 * parent 24505 * 24506 * @see #onMeasure(int, int) 24507 */ measure(int widthMeasureSpec, int heightMeasureSpec)24508 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 24509 boolean optical = isLayoutModeOptical(this); 24510 if (optical != isLayoutModeOptical(mParent)) { 24511 Insets insets = getOpticalInsets(); 24512 int oWidth = insets.left + insets.right; 24513 int oHeight = insets.top + insets.bottom; 24514 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 24515 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 24516 } 24517 24518 // Suppress sign extension for the low bytes 24519 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 24520 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 24521 24522 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 24523 24524 // Optimize layout by avoiding an extra EXACTLY pass when the view is 24525 // already measured as the correct size. In API 23 and below, this 24526 // extra pass is required to make LinearLayout re-distribute weight. 24527 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 24528 || heightMeasureSpec != mOldHeightMeasureSpec; 24529 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 24530 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 24531 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 24532 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 24533 final boolean needsLayout = specChanged 24534 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 24535 24536 if (forceLayout || needsLayout) { 24537 // first clears the measured dimension flag 24538 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 24539 24540 resolveRtlPropertiesIfNeeded(); 24541 24542 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 24543 if (cacheIndex < 0 || sIgnoreMeasureCache) { 24544 // measure ourselves, this should set the measured dimension flag back 24545 onMeasure(widthMeasureSpec, heightMeasureSpec); 24546 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 24547 } else { 24548 long value = mMeasureCache.valueAt(cacheIndex); 24549 // Casting a long to int drops the high 32 bits, no mask needed 24550 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 24551 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 24552 } 24553 24554 // flag not set, setMeasuredDimension() was not invoked, we raise 24555 // an exception to warn the developer 24556 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 24557 throw new IllegalStateException("View with id " + getId() + ": " 24558 + getClass().getName() + "#onMeasure() did not set the" 24559 + " measured dimension by calling" 24560 + " setMeasuredDimension()"); 24561 } 24562 24563 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 24564 } 24565 24566 mOldWidthMeasureSpec = widthMeasureSpec; 24567 mOldHeightMeasureSpec = heightMeasureSpec; 24568 24569 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 24570 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 24571 } 24572 24573 /** 24574 * <p> 24575 * Measure the view and its content to determine the measured width and the 24576 * measured height. This method is invoked by {@link #measure(int, int)} and 24577 * should be overridden by subclasses to provide accurate and efficient 24578 * measurement of their contents. 24579 * </p> 24580 * 24581 * <p> 24582 * <strong>CONTRACT:</strong> When overriding this method, you 24583 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 24584 * measured width and height of this view. Failure to do so will trigger an 24585 * <code>IllegalStateException</code>, thrown by 24586 * {@link #measure(int, int)}. Calling the superclass' 24587 * {@link #onMeasure(int, int)} is a valid use. 24588 * </p> 24589 * 24590 * <p> 24591 * The base class implementation of measure defaults to the background size, 24592 * unless a larger size is allowed by the MeasureSpec. Subclasses should 24593 * override {@link #onMeasure(int, int)} to provide better measurements of 24594 * their content. 24595 * </p> 24596 * 24597 * <p> 24598 * If this method is overridden, it is the subclass's responsibility to make 24599 * sure the measured height and width are at least the view's minimum height 24600 * and width ({@link #getSuggestedMinimumHeight()} and 24601 * {@link #getSuggestedMinimumWidth()}). 24602 * </p> 24603 * 24604 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 24605 * The requirements are encoded with 24606 * {@link android.view.View.MeasureSpec}. 24607 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 24608 * The requirements are encoded with 24609 * {@link android.view.View.MeasureSpec}. 24610 * 24611 * @see #getMeasuredWidth() 24612 * @see #getMeasuredHeight() 24613 * @see #setMeasuredDimension(int, int) 24614 * @see #getSuggestedMinimumHeight() 24615 * @see #getSuggestedMinimumWidth() 24616 * @see android.view.View.MeasureSpec#getMode(int) 24617 * @see android.view.View.MeasureSpec#getSize(int) 24618 */ onMeasure(int widthMeasureSpec, int heightMeasureSpec)24619 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 24620 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 24621 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 24622 } 24623 24624 /** 24625 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 24626 * measured width and measured height. Failing to do so will trigger an 24627 * exception at measurement time.</p> 24628 * 24629 * @param measuredWidth The measured width of this view. May be a complex 24630 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 24631 * {@link #MEASURED_STATE_TOO_SMALL}. 24632 * @param measuredHeight The measured height of this view. May be a complex 24633 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 24634 * {@link #MEASURED_STATE_TOO_SMALL}. 24635 */ setMeasuredDimension(int measuredWidth, int measuredHeight)24636 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 24637 boolean optical = isLayoutModeOptical(this); 24638 if (optical != isLayoutModeOptical(mParent)) { 24639 Insets insets = getOpticalInsets(); 24640 int opticalWidth = insets.left + insets.right; 24641 int opticalHeight = insets.top + insets.bottom; 24642 24643 measuredWidth += optical ? opticalWidth : -opticalWidth; 24644 measuredHeight += optical ? opticalHeight : -opticalHeight; 24645 } 24646 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 24647 } 24648 24649 /** 24650 * Sets the measured dimension without extra processing for things like optical bounds. 24651 * Useful for reapplying consistent values that have already been cooked with adjustments 24652 * for optical bounds, etc. such as those from the measurement cache. 24653 * 24654 * @param measuredWidth The measured width of this view. May be a complex 24655 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 24656 * {@link #MEASURED_STATE_TOO_SMALL}. 24657 * @param measuredHeight The measured height of this view. May be a complex 24658 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 24659 * {@link #MEASURED_STATE_TOO_SMALL}. 24660 */ setMeasuredDimensionRaw(int measuredWidth, int measuredHeight)24661 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 24662 mMeasuredWidth = measuredWidth; 24663 mMeasuredHeight = measuredHeight; 24664 24665 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 24666 } 24667 24668 /** 24669 * Merge two states as returned by {@link #getMeasuredState()}. 24670 * @param curState The current state as returned from a view or the result 24671 * of combining multiple views. 24672 * @param newState The new view state to combine. 24673 * @return Returns a new integer reflecting the combination of the two 24674 * states. 24675 */ combineMeasuredStates(int curState, int newState)24676 public static int combineMeasuredStates(int curState, int newState) { 24677 return curState | newState; 24678 } 24679 24680 /** 24681 * Version of {@link #resolveSizeAndState(int, int, int)} 24682 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 24683 */ resolveSize(int size, int measureSpec)24684 public static int resolveSize(int size, int measureSpec) { 24685 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 24686 } 24687 24688 /** 24689 * Utility to reconcile a desired size and state, with constraints imposed 24690 * by a MeasureSpec. Will take the desired size, unless a different size 24691 * is imposed by the constraints. The returned value is a compound integer, 24692 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 24693 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 24694 * resulting size is smaller than the size the view wants to be. 24695 * 24696 * @param size How big the view wants to be. 24697 * @param measureSpec Constraints imposed by the parent. 24698 * @param childMeasuredState Size information bit mask for the view's 24699 * children. 24700 * @return Size information bit mask as defined by 24701 * {@link #MEASURED_SIZE_MASK} and 24702 * {@link #MEASURED_STATE_TOO_SMALL}. 24703 */ resolveSizeAndState(int size, int measureSpec, int childMeasuredState)24704 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 24705 final int specMode = MeasureSpec.getMode(measureSpec); 24706 final int specSize = MeasureSpec.getSize(measureSpec); 24707 final int result; 24708 switch (specMode) { 24709 case MeasureSpec.AT_MOST: 24710 if (specSize < size) { 24711 result = specSize | MEASURED_STATE_TOO_SMALL; 24712 } else { 24713 result = size; 24714 } 24715 break; 24716 case MeasureSpec.EXACTLY: 24717 result = specSize; 24718 break; 24719 case MeasureSpec.UNSPECIFIED: 24720 default: 24721 result = size; 24722 } 24723 return result | (childMeasuredState & MEASURED_STATE_MASK); 24724 } 24725 24726 /** 24727 * Utility to return a default size. Uses the supplied size if the 24728 * MeasureSpec imposed no constraints. Will get larger if allowed 24729 * by the MeasureSpec. 24730 * 24731 * @param size Default size for this view 24732 * @param measureSpec Constraints imposed by the parent 24733 * @return The size this view should be. 24734 */ getDefaultSize(int size, int measureSpec)24735 public static int getDefaultSize(int size, int measureSpec) { 24736 int result = size; 24737 int specMode = MeasureSpec.getMode(measureSpec); 24738 int specSize = MeasureSpec.getSize(measureSpec); 24739 24740 switch (specMode) { 24741 case MeasureSpec.UNSPECIFIED: 24742 result = size; 24743 break; 24744 case MeasureSpec.AT_MOST: 24745 case MeasureSpec.EXACTLY: 24746 result = specSize; 24747 break; 24748 } 24749 return result; 24750 } 24751 24752 /** 24753 * Returns the suggested minimum height that the view should use. This 24754 * returns the maximum of the view's minimum height 24755 * and the background's minimum height 24756 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 24757 * <p> 24758 * When being used in {@link #onMeasure(int, int)}, the caller should still 24759 * ensure the returned height is within the requirements of the parent. 24760 * 24761 * @return The suggested minimum height of the view. 24762 */ getSuggestedMinimumHeight()24763 protected int getSuggestedMinimumHeight() { 24764 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 24765 24766 } 24767 24768 /** 24769 * Returns the suggested minimum width that the view should use. This 24770 * returns the maximum of the view's minimum width 24771 * and the background's minimum width 24772 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 24773 * <p> 24774 * When being used in {@link #onMeasure(int, int)}, the caller should still 24775 * ensure the returned width is within the requirements of the parent. 24776 * 24777 * @return The suggested minimum width of the view. 24778 */ getSuggestedMinimumWidth()24779 protected int getSuggestedMinimumWidth() { 24780 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 24781 } 24782 24783 /** 24784 * Returns the minimum height of the view. 24785 * 24786 * @return the minimum height the view will try to be, in pixels 24787 * 24788 * @see #setMinimumHeight(int) 24789 * 24790 * @attr ref android.R.styleable#View_minHeight 24791 */ 24792 @InspectableProperty(name = "minHeight") getMinimumHeight()24793 public int getMinimumHeight() { 24794 return mMinHeight; 24795 } 24796 24797 /** 24798 * Sets the minimum height of the view. It is not guaranteed the view will 24799 * be able to achieve this minimum height (for example, if its parent layout 24800 * constrains it with less available height). 24801 * 24802 * @param minHeight The minimum height the view will try to be, in pixels 24803 * 24804 * @see #getMinimumHeight() 24805 * 24806 * @attr ref android.R.styleable#View_minHeight 24807 */ 24808 @RemotableViewMethod setMinimumHeight(int minHeight)24809 public void setMinimumHeight(int minHeight) { 24810 mMinHeight = minHeight; 24811 requestLayout(); 24812 } 24813 24814 /** 24815 * Returns the minimum width of the view. 24816 * 24817 * @return the minimum width the view will try to be, in pixels 24818 * 24819 * @see #setMinimumWidth(int) 24820 * 24821 * @attr ref android.R.styleable#View_minWidth 24822 */ 24823 @InspectableProperty(name = "minWidth") getMinimumWidth()24824 public int getMinimumWidth() { 24825 return mMinWidth; 24826 } 24827 24828 /** 24829 * Sets the minimum width of the view. It is not guaranteed the view will 24830 * be able to achieve this minimum width (for example, if its parent layout 24831 * constrains it with less available width). 24832 * 24833 * @param minWidth The minimum width the view will try to be, in pixels 24834 * 24835 * @see #getMinimumWidth() 24836 * 24837 * @attr ref android.R.styleable#View_minWidth 24838 */ setMinimumWidth(int minWidth)24839 public void setMinimumWidth(int minWidth) { 24840 mMinWidth = minWidth; 24841 requestLayout(); 24842 24843 } 24844 24845 /** 24846 * Get the animation currently associated with this view. 24847 * 24848 * @return The animation that is currently playing or 24849 * scheduled to play for this view. 24850 */ getAnimation()24851 public Animation getAnimation() { 24852 return mCurrentAnimation; 24853 } 24854 24855 /** 24856 * Start the specified animation now. 24857 * 24858 * @param animation the animation to start now 24859 */ startAnimation(Animation animation)24860 public void startAnimation(Animation animation) { 24861 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 24862 setAnimation(animation); 24863 invalidateParentCaches(); 24864 invalidate(true); 24865 } 24866 24867 /** 24868 * Cancels any animations for this view. 24869 */ clearAnimation()24870 public void clearAnimation() { 24871 if (mCurrentAnimation != null) { 24872 mCurrentAnimation.detach(); 24873 } 24874 mCurrentAnimation = null; 24875 invalidateParentIfNeeded(); 24876 } 24877 24878 /** 24879 * Sets the next animation to play for this view. 24880 * If you want the animation to play immediately, use 24881 * {@link #startAnimation(android.view.animation.Animation)} instead. 24882 * This method provides allows fine-grained 24883 * control over the start time and invalidation, but you 24884 * must make sure that 1) the animation has a start time set, and 24885 * 2) the view's parent (which controls animations on its children) 24886 * will be invalidated when the animation is supposed to 24887 * start. 24888 * 24889 * @param animation The next animation, or null. 24890 */ setAnimation(Animation animation)24891 public void setAnimation(Animation animation) { 24892 mCurrentAnimation = animation; 24893 24894 if (animation != null) { 24895 // If the screen is off assume the animation start time is now instead of 24896 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 24897 // would cause the animation to start when the screen turns back on 24898 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 24899 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 24900 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 24901 } 24902 animation.reset(); 24903 } 24904 } 24905 24906 /** 24907 * Invoked by a parent ViewGroup to notify the start of the animation 24908 * currently associated with this view. If you override this method, 24909 * always call super.onAnimationStart(); 24910 * 24911 * @see #setAnimation(android.view.animation.Animation) 24912 * @see #getAnimation() 24913 */ 24914 @CallSuper onAnimationStart()24915 protected void onAnimationStart() { 24916 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 24917 } 24918 24919 /** 24920 * Invoked by a parent ViewGroup to notify the end of the animation 24921 * currently associated with this view. If you override this method, 24922 * always call super.onAnimationEnd(); 24923 * 24924 * @see #setAnimation(android.view.animation.Animation) 24925 * @see #getAnimation() 24926 */ 24927 @CallSuper onAnimationEnd()24928 protected void onAnimationEnd() { 24929 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 24930 } 24931 24932 /** 24933 * Invoked if there is a Transform that involves alpha. Subclass that can 24934 * draw themselves with the specified alpha should return true, and then 24935 * respect that alpha when their onDraw() is called. If this returns false 24936 * then the view may be redirected to draw into an offscreen buffer to 24937 * fulfill the request, which will look fine, but may be slower than if the 24938 * subclass handles it internally. The default implementation returns false. 24939 * 24940 * @param alpha The alpha (0..255) to apply to the view's drawing 24941 * @return true if the view can draw with the specified alpha. 24942 */ onSetAlpha(int alpha)24943 protected boolean onSetAlpha(int alpha) { 24944 return false; 24945 } 24946 24947 /** 24948 * This is used by the RootView to perform an optimization when 24949 * the view hierarchy contains one or several SurfaceView. 24950 * SurfaceView is always considered transparent, but its children are not, 24951 * therefore all View objects remove themselves from the global transparent 24952 * region (passed as a parameter to this function). 24953 * 24954 * @param region The transparent region for this ViewAncestor (window). 24955 * 24956 * @return Returns true if the effective visibility of the view at this 24957 * point is opaque, regardless of the transparent region; returns false 24958 * if it is possible for underlying windows to be seen behind the view. 24959 * 24960 * {@hide} 24961 */ 24962 @UnsupportedAppUsage gatherTransparentRegion(Region region)24963 public boolean gatherTransparentRegion(Region region) { 24964 final AttachInfo attachInfo = mAttachInfo; 24965 if (region != null && attachInfo != null) { 24966 final int pflags = mPrivateFlags; 24967 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 24968 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 24969 // remove it from the transparent region. 24970 final int[] location = attachInfo.mTransparentLocation; 24971 getLocationInWindow(location); 24972 // When a view has Z value, then it will be better to leave some area below the view 24973 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 24974 // the bottom part needs more offset than the left, top and right parts due to the 24975 // spot light effects. 24976 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 24977 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 24978 location[0] + mRight - mLeft + shadowOffset, 24979 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 24980 } else { 24981 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 24982 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 24983 // the background drawable's non-transparent parts from this transparent region. 24984 applyDrawableToTransparentRegion(mBackground, region); 24985 } 24986 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 24987 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 24988 // Similarly, we remove the foreground drawable's non-transparent parts. 24989 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 24990 } 24991 if (mDefaultFocusHighlight != null 24992 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { 24993 // Similarly, we remove the default focus highlight's non-transparent parts. 24994 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); 24995 } 24996 } 24997 } 24998 return true; 24999 } 25000 25001 /** 25002 * Play a sound effect for this view. 25003 * 25004 * <p>The framework will play sound effects for some built in actions, such as 25005 * clicking, but you may wish to play these effects in your widget, 25006 * for instance, for internal navigation. 25007 * 25008 * <p>The sound effect will only be played if sound effects are enabled by the user, and 25009 * {@link #isSoundEffectsEnabled()} is true. 25010 * 25011 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 25012 */ playSoundEffect(int soundConstant)25013 public void playSoundEffect(int soundConstant) { 25014 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 25015 return; 25016 } 25017 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 25018 } 25019 25020 /** 25021 * BZZZTT!!1! 25022 * 25023 * <p>Provide haptic feedback to the user for this view. 25024 * 25025 * <p>The framework will provide haptic feedback for some built in actions, 25026 * such as long presses, but you may wish to provide feedback for your 25027 * own widget. 25028 * 25029 * <p>The feedback will only be performed if 25030 * {@link #isHapticFeedbackEnabled()} is true. 25031 * 25032 * @param feedbackConstant One of the constants defined in 25033 * {@link HapticFeedbackConstants} 25034 */ performHapticFeedback(int feedbackConstant)25035 public boolean performHapticFeedback(int feedbackConstant) { 25036 return performHapticFeedback(feedbackConstant, 0); 25037 } 25038 25039 /** 25040 * BZZZTT!!1! 25041 * 25042 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 25043 * 25044 * @param feedbackConstant One of the constants defined in 25045 * {@link HapticFeedbackConstants} 25046 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 25047 */ performHapticFeedback(int feedbackConstant, int flags)25048 public boolean performHapticFeedback(int feedbackConstant, int flags) { 25049 if (mAttachInfo == null) { 25050 return false; 25051 } 25052 //noinspection SimplifiableIfStatement 25053 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 25054 && !isHapticFeedbackEnabled()) { 25055 return false; 25056 } 25057 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 25058 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 25059 } 25060 25061 /** 25062 * Request that the visibility of the status bar or other screen/window 25063 * decorations be changed. 25064 * 25065 * <p>This method is used to put the over device UI into temporary modes 25066 * where the user's attention is focused more on the application content, 25067 * by dimming or hiding surrounding system affordances. This is typically 25068 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 25069 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 25070 * to be placed behind the action bar (and with these flags other system 25071 * affordances) so that smooth transitions between hiding and showing them 25072 * can be done. 25073 * 25074 * <p>Two representative examples of the use of system UI visibility is 25075 * implementing a content browsing application (like a magazine reader) 25076 * and a video playing application. 25077 * 25078 * <p>The first code shows a typical implementation of a View in a content 25079 * browsing application. In this implementation, the application goes 25080 * into a content-oriented mode by hiding the status bar and action bar, 25081 * and putting the navigation elements into lights out mode. The user can 25082 * then interact with content while in this mode. Such an application should 25083 * provide an easy way for the user to toggle out of the mode (such as to 25084 * check information in the status bar or access notifications). In the 25085 * implementation here, this is done simply by tapping on the content. 25086 * 25087 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 25088 * content} 25089 * 25090 * <p>This second code sample shows a typical implementation of a View 25091 * in a video playing application. In this situation, while the video is 25092 * playing the application would like to go into a complete full-screen mode, 25093 * to use as much of the display as possible for the video. When in this state 25094 * the user can not interact with the application; the system intercepts 25095 * touching on the screen to pop the UI out of full screen mode. See 25096 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 25097 * 25098 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 25099 * content} 25100 * 25101 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 25102 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 25103 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 25104 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 25105 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 25106 */ setSystemUiVisibility(int visibility)25107 public void setSystemUiVisibility(int visibility) { 25108 if (visibility != mSystemUiVisibility) { 25109 mSystemUiVisibility = visibility; 25110 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 25111 mParent.recomputeViewAttributes(this); 25112 } 25113 } 25114 } 25115 25116 /** 25117 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 25118 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 25119 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 25120 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 25121 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 25122 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 25123 */ getSystemUiVisibility()25124 public int getSystemUiVisibility() { 25125 return mSystemUiVisibility; 25126 } 25127 25128 /** 25129 * Returns the current system UI visibility that is currently set for 25130 * the entire window. This is the combination of the 25131 * {@link #setSystemUiVisibility(int)} values supplied by all of the 25132 * views in the window. 25133 */ getWindowSystemUiVisibility()25134 public int getWindowSystemUiVisibility() { 25135 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 25136 } 25137 25138 /** 25139 * Override to find out when the window's requested system UI visibility 25140 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 25141 * This is different from the callbacks received through 25142 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 25143 * in that this is only telling you about the local request of the window, 25144 * not the actual values applied by the system. 25145 */ onWindowSystemUiVisibilityChanged(int visible)25146 public void onWindowSystemUiVisibilityChanged(int visible) { 25147 } 25148 25149 /** 25150 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 25151 * the view hierarchy. 25152 */ dispatchWindowSystemUiVisiblityChanged(int visible)25153 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 25154 onWindowSystemUiVisibilityChanged(visible); 25155 } 25156 25157 /** 25158 * Set a listener to receive callbacks when the visibility of the system bar changes. 25159 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 25160 */ setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l)25161 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 25162 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 25163 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 25164 mParent.recomputeViewAttributes(this); 25165 } 25166 } 25167 25168 /** 25169 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 25170 * the view hierarchy. 25171 */ dispatchSystemUiVisibilityChanged(int visibility)25172 public void dispatchSystemUiVisibilityChanged(int visibility) { 25173 ListenerInfo li = mListenerInfo; 25174 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 25175 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 25176 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 25177 } 25178 } 25179 updateLocalSystemUiVisibility(int localValue, int localChanges)25180 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 25181 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 25182 if (val != mSystemUiVisibility) { 25183 setSystemUiVisibility(val); 25184 return true; 25185 } 25186 return false; 25187 } 25188 25189 /** @hide */ 25190 @UnsupportedAppUsage setDisabledSystemUiVisibility(int flags)25191 public void setDisabledSystemUiVisibility(int flags) { 25192 if (mAttachInfo != null) { 25193 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 25194 mAttachInfo.mDisabledSystemUiVisibility = flags; 25195 if (mParent != null) { 25196 mParent.recomputeViewAttributes(this); 25197 } 25198 } 25199 } 25200 } 25201 25202 /** 25203 * Creates an image that the system displays during the drag and drop 25204 * operation. This is called a "drag shadow". The default implementation 25205 * for a DragShadowBuilder based on a View returns an image that has exactly the same 25206 * appearance as the given View. The default also positions the center of the drag shadow 25207 * directly under the touch point. If no View is provided (the constructor with no parameters 25208 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 25209 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 25210 * default is an invisible drag shadow. 25211 * <p> 25212 * You are not required to use the View you provide to the constructor as the basis of the 25213 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 25214 * anything you want as the drag shadow. 25215 * </p> 25216 * <p> 25217 * You pass a DragShadowBuilder object to the system when you start the drag. The system 25218 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 25219 * size and position of the drag shadow. It uses this data to construct a 25220 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 25221 * so that your application can draw the shadow image in the Canvas. 25222 * </p> 25223 * 25224 * <div class="special reference"> 25225 * <h3>Developer Guides</h3> 25226 * <p>For a guide to implementing drag and drop features, read the 25227 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 25228 * </div> 25229 */ 25230 public static class DragShadowBuilder { 25231 @UnsupportedAppUsage 25232 private final WeakReference<View> mView; 25233 25234 /** 25235 * Constructs a shadow image builder based on a View. By default, the resulting drag 25236 * shadow will have the same appearance and dimensions as the View, with the touch point 25237 * over the center of the View. 25238 * @param view A View. Any View in scope can be used. 25239 */ DragShadowBuilder(View view)25240 public DragShadowBuilder(View view) { 25241 mView = new WeakReference<View>(view); 25242 } 25243 25244 /** 25245 * Construct a shadow builder object with no associated View. This 25246 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 25247 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 25248 * to supply the drag shadow's dimensions and appearance without 25249 * reference to any View object. 25250 */ DragShadowBuilder()25251 public DragShadowBuilder() { 25252 mView = new WeakReference<View>(null); 25253 } 25254 25255 /** 25256 * Returns the View object that had been passed to the 25257 * {@link #View.DragShadowBuilder(View)} 25258 * constructor. If that View parameter was {@code null} or if the 25259 * {@link #View.DragShadowBuilder()} 25260 * constructor was used to instantiate the builder object, this method will return 25261 * null. 25262 * 25263 * @return The View object associate with this builder object. 25264 */ 25265 @SuppressWarnings({"JavadocReference"}) getView()25266 final public View getView() { 25267 return mView.get(); 25268 } 25269 25270 /** 25271 * Provides the metrics for the shadow image. These include the dimensions of 25272 * the shadow image, and the point within that shadow that should 25273 * be centered under the touch location while dragging. 25274 * <p> 25275 * The default implementation sets the dimensions of the shadow to be the 25276 * same as the dimensions of the View itself and centers the shadow under 25277 * the touch point. 25278 * </p> 25279 * 25280 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 25281 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 25282 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 25283 * image. Since Android P, the width and height must be positive values. 25284 * 25285 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 25286 * shadow image that should be underneath the touch point during the drag and drop 25287 * operation. Your application must set {@link android.graphics.Point#x} to the 25288 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 25289 */ onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint)25290 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 25291 final View view = mView.get(); 25292 if (view != null) { 25293 outShadowSize.set(view.getWidth(), view.getHeight()); 25294 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 25295 } else { 25296 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 25297 } 25298 } 25299 25300 /** 25301 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 25302 * based on the dimensions it received from the 25303 * {@link #onProvideShadowMetrics(Point, Point)} callback. 25304 * 25305 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 25306 */ onDrawShadow(Canvas canvas)25307 public void onDrawShadow(Canvas canvas) { 25308 final View view = mView.get(); 25309 if (view != null) { 25310 view.draw(canvas); 25311 } else { 25312 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 25313 } 25314 } 25315 } 25316 25317 /** 25318 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 25319 * startDragAndDrop()} for newer platform versions. 25320 */ 25321 @Deprecated startDrag(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)25322 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 25323 Object myLocalState, int flags) { 25324 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 25325 } 25326 25327 /** 25328 * Starts a drag and drop operation. When your application calls this method, it passes a 25329 * {@link android.view.View.DragShadowBuilder} object to the system. The 25330 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 25331 * to get metrics for the drag shadow, and then calls the object's 25332 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 25333 * <p> 25334 * Once the system has the drag shadow, it begins the drag and drop operation by sending 25335 * drag events to all the View objects in your application that are currently visible. It does 25336 * this either by calling the View object's drag listener (an implementation of 25337 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 25338 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 25339 * Both are passed a {@link android.view.DragEvent} object that has a 25340 * {@link android.view.DragEvent#getAction()} value of 25341 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 25342 * </p> 25343 * <p> 25344 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 25345 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 25346 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 25347 * to the View the user selected for dragging. 25348 * </p> 25349 * @param data A {@link android.content.ClipData} object pointing to the data to be 25350 * transferred by the drag and drop operation. 25351 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 25352 * drag shadow. 25353 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 25354 * drop operation. When dispatching drag events to views in the same activity this object 25355 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 25356 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 25357 * will return null). 25358 * <p> 25359 * myLocalState is a lightweight mechanism for the sending information from the dragged View 25360 * to the target Views. For example, it can contain flags that differentiate between a 25361 * a copy operation and a move operation. 25362 * </p> 25363 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 25364 * flags, or any combination of the following: 25365 * <ul> 25366 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 25367 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 25368 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 25369 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 25370 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 25371 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 25372 * </ul> 25373 * @return {@code true} if the method completes successfully, or 25374 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 25375 * do a drag because of another ongoing operation or some other reasons. 25376 */ startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)25377 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 25378 Object myLocalState, int flags) { 25379 if (ViewDebug.DEBUG_DRAG) { 25380 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 25381 } 25382 if (mAttachInfo == null) { 25383 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 25384 return false; 25385 } 25386 if (!mAttachInfo.mViewRootImpl.mSurface.isValid()) { 25387 Log.w(VIEW_LOG_TAG, "startDragAndDrop called with an invalid surface."); 25388 return false; 25389 } 25390 25391 if (data != null) { 25392 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 25393 } 25394 25395 Point shadowSize = new Point(); 25396 Point shadowTouchPoint = new Point(); 25397 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 25398 25399 if ((shadowSize.x < 0) || (shadowSize.y < 0) 25400 || (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 25401 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 25402 } 25403 25404 // Create 1x1 surface when zero surface size is specified because SurfaceControl.Builder 25405 // does not accept zero size surface. 25406 if (shadowSize.x == 0 || shadowSize.y == 0) { 25407 if (!sAcceptZeroSizeDragShadow) { 25408 throw new IllegalStateException("Drag shadow dimensions must be positive"); 25409 } 25410 shadowSize.x = 1; 25411 shadowSize.y = 1; 25412 } 25413 25414 if (ViewDebug.DEBUG_DRAG) { 25415 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 25416 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 25417 } 25418 25419 final ViewRootImpl root = mAttachInfo.mViewRootImpl; 25420 final SurfaceSession session = new SurfaceSession(); 25421 final SurfaceControl surfaceControl = new SurfaceControl.Builder(session) 25422 .setName("drag surface") 25423 .setParent(root.getSurfaceControl()) 25424 .setBufferSize(shadowSize.x, shadowSize.y) 25425 .setFormat(PixelFormat.TRANSLUCENT) 25426 .build(); 25427 final Surface surface = new Surface(); 25428 surface.copyFrom(surfaceControl); 25429 IBinder token = null; 25430 try { 25431 final Canvas canvas = surface.lockCanvas(null); 25432 try { 25433 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 25434 shadowBuilder.onDrawShadow(canvas); 25435 } finally { 25436 surface.unlockCanvasAndPost(canvas); 25437 } 25438 25439 // repurpose 'shadowSize' for the last touch point 25440 root.getLastTouchPoint(shadowSize); 25441 25442 token = mAttachInfo.mSession.performDrag( 25443 mAttachInfo.mWindow, flags, surfaceControl, root.getLastTouchSource(), 25444 shadowSize.x, shadowSize.y, shadowTouchPoint.x, shadowTouchPoint.y, data); 25445 if (ViewDebug.DEBUG_DRAG) { 25446 Log.d(VIEW_LOG_TAG, "performDrag returned " + token); 25447 } 25448 if (token != null) { 25449 if (mAttachInfo.mDragSurface != null) { 25450 mAttachInfo.mDragSurface.release(); 25451 } 25452 mAttachInfo.mDragSurface = surface; 25453 mAttachInfo.mDragToken = token; 25454 // Cache the local state object for delivery with DragEvents 25455 root.setLocalDragState(myLocalState); 25456 } 25457 return token != null; 25458 } catch (Exception e) { 25459 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 25460 return false; 25461 } finally { 25462 if (token == null) { 25463 surface.destroy(); 25464 } 25465 session.kill(); 25466 } 25467 } 25468 25469 /** 25470 * Cancels an ongoing drag and drop operation. 25471 * <p> 25472 * A {@link android.view.DragEvent} object with 25473 * {@link android.view.DragEvent#getAction()} value of 25474 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 25475 * {@link android.view.DragEvent#getResult()} value of {@code false} 25476 * will be sent to every 25477 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 25478 * even if they are not currently visible. 25479 * </p> 25480 * <p> 25481 * This method can be called on any View in the same window as the View on which 25482 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 25483 * was called. 25484 * </p> 25485 */ cancelDragAndDrop()25486 public final void cancelDragAndDrop() { 25487 if (ViewDebug.DEBUG_DRAG) { 25488 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 25489 } 25490 if (mAttachInfo == null) { 25491 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 25492 return; 25493 } 25494 if (mAttachInfo.mDragToken != null) { 25495 try { 25496 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken, false); 25497 } catch (Exception e) { 25498 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 25499 } 25500 mAttachInfo.mDragToken = null; 25501 } else { 25502 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 25503 } 25504 } 25505 25506 /** 25507 * Updates the drag shadow for the ongoing drag and drop operation. 25508 * 25509 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 25510 * new drag shadow. 25511 */ updateDragShadow(DragShadowBuilder shadowBuilder)25512 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 25513 if (ViewDebug.DEBUG_DRAG) { 25514 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 25515 } 25516 if (mAttachInfo == null) { 25517 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 25518 return; 25519 } 25520 if (mAttachInfo.mDragToken != null) { 25521 try { 25522 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 25523 try { 25524 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 25525 shadowBuilder.onDrawShadow(canvas); 25526 } finally { 25527 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 25528 } 25529 } catch (Exception e) { 25530 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 25531 } 25532 } else { 25533 Log.e(VIEW_LOG_TAG, "No active drag"); 25534 } 25535 } 25536 25537 /** 25538 * Starts a move from {startX, startY}, the amount of the movement will be the offset 25539 * between {startX, startY} and the new cursor positon. 25540 * @param startX horizontal coordinate where the move started. 25541 * @param startY vertical coordinate where the move started. 25542 * @return whether moving was started successfully. 25543 * @hide 25544 */ startMovingTask(float startX, float startY)25545 public final boolean startMovingTask(float startX, float startY) { 25546 if (ViewDebug.DEBUG_POSITIONING) { 25547 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 25548 } 25549 try { 25550 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 25551 } catch (RemoteException e) { 25552 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 25553 } 25554 return false; 25555 } 25556 25557 /** 25558 * Finish a window move task. 25559 * @hide 25560 */ finishMovingTask()25561 public void finishMovingTask() { 25562 if (ViewDebug.DEBUG_POSITIONING) { 25563 Log.d(VIEW_LOG_TAG, "finishMovingTask"); 25564 } 25565 try { 25566 mAttachInfo.mSession.finishMovingTask(mAttachInfo.mWindow); 25567 } catch (RemoteException e) { 25568 Log.e(VIEW_LOG_TAG, "Unable to finish moving", e); 25569 } 25570 } 25571 25572 /** 25573 * Handles drag events sent by the system following a call to 25574 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 25575 * startDragAndDrop()}. 25576 *<p> 25577 * When the system calls this method, it passes a 25578 * {@link android.view.DragEvent} object. A call to 25579 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 25580 * in DragEvent. The method uses these to determine what is happening in the drag and drop 25581 * operation. 25582 * @param event The {@link android.view.DragEvent} sent by the system. 25583 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 25584 * in DragEvent, indicating the type of drag event represented by this object. 25585 * @return {@code true} if the method was successful, otherwise {@code false}. 25586 * <p> 25587 * The method should return {@code true} in response to an action type of 25588 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 25589 * operation. 25590 * </p> 25591 * <p> 25592 * The method should also return {@code true} in response to an action type of 25593 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 25594 * {@code false} if it didn't. 25595 * </p> 25596 * <p> 25597 * For all other events, the return value is ignored. 25598 * </p> 25599 */ onDragEvent(DragEvent event)25600 public boolean onDragEvent(DragEvent event) { 25601 return false; 25602 } 25603 25604 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. dispatchDragEnterExitInPreN(DragEvent event)25605 boolean dispatchDragEnterExitInPreN(DragEvent event) { 25606 return callDragEventHandler(event); 25607 } 25608 25609 /** 25610 * Detects if this View is enabled and has a drag event listener. 25611 * If both are true, then it calls the drag event listener with the 25612 * {@link android.view.DragEvent} it received. If the drag event listener returns 25613 * {@code true}, then dispatchDragEvent() returns {@code true}. 25614 * <p> 25615 * For all other cases, the method calls the 25616 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 25617 * method and returns its result. 25618 * </p> 25619 * <p> 25620 * This ensures that a drag event is always consumed, even if the View does not have a drag 25621 * event listener. However, if the View has a listener and the listener returns true, then 25622 * onDragEvent() is not called. 25623 * </p> 25624 */ dispatchDragEvent(DragEvent event)25625 public boolean dispatchDragEvent(DragEvent event) { 25626 event.mEventHandlerWasCalled = true; 25627 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 25628 event.mAction == DragEvent.ACTION_DROP) { 25629 // About to deliver an event with coordinates to this view. Notify that now this view 25630 // has drag focus. This will send exit/enter events as needed. 25631 getViewRootImpl().setDragFocus(this, event); 25632 } 25633 return callDragEventHandler(event); 25634 } 25635 callDragEventHandler(DragEvent event)25636 final boolean callDragEventHandler(DragEvent event) { 25637 final boolean result; 25638 25639 ListenerInfo li = mListenerInfo; 25640 //noinspection SimplifiableIfStatement 25641 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 25642 && li.mOnDragListener.onDrag(this, event)) { 25643 result = true; 25644 } else { 25645 result = onDragEvent(event); 25646 } 25647 25648 switch (event.mAction) { 25649 case DragEvent.ACTION_DRAG_ENTERED: { 25650 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 25651 refreshDrawableState(); 25652 } break; 25653 case DragEvent.ACTION_DRAG_EXITED: { 25654 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 25655 refreshDrawableState(); 25656 } break; 25657 case DragEvent.ACTION_DRAG_ENDED: { 25658 mPrivateFlags2 &= ~View.DRAG_MASK; 25659 refreshDrawableState(); 25660 } break; 25661 } 25662 25663 return result; 25664 } 25665 canAcceptDrag()25666 boolean canAcceptDrag() { 25667 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 25668 } 25669 25670 /** 25671 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 25672 * it is ever exposed at all. 25673 * @hide 25674 */ 25675 @UnsupportedAppUsage onCloseSystemDialogs(String reason)25676 public void onCloseSystemDialogs(String reason) { 25677 } 25678 25679 /** 25680 * Given a Drawable whose bounds have been set to draw into this view, 25681 * update a Region being computed for 25682 * {@link #gatherTransparentRegion(android.graphics.Region)} so 25683 * that any non-transparent parts of the Drawable are removed from the 25684 * given transparent region. 25685 * 25686 * @param dr The Drawable whose transparency is to be applied to the region. 25687 * @param region A Region holding the current transparency information, 25688 * where any parts of the region that are set are considered to be 25689 * transparent. On return, this region will be modified to have the 25690 * transparency information reduced by the corresponding parts of the 25691 * Drawable that are not transparent. 25692 * {@hide} 25693 */ 25694 @UnsupportedAppUsage applyDrawableToTransparentRegion(Drawable dr, Region region)25695 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 25696 if (DBG) { 25697 Log.i("View", "Getting transparent region for: " + this); 25698 } 25699 final Region r = dr.getTransparentRegion(); 25700 final Rect db = dr.getBounds(); 25701 final AttachInfo attachInfo = mAttachInfo; 25702 if (r != null && attachInfo != null) { 25703 final int w = getRight()-getLeft(); 25704 final int h = getBottom()-getTop(); 25705 if (db.left > 0) { 25706 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 25707 r.op(0, 0, db.left, h, Region.Op.UNION); 25708 } 25709 if (db.right < w) { 25710 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 25711 r.op(db.right, 0, w, h, Region.Op.UNION); 25712 } 25713 if (db.top > 0) { 25714 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 25715 r.op(0, 0, w, db.top, Region.Op.UNION); 25716 } 25717 if (db.bottom < h) { 25718 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 25719 r.op(0, db.bottom, w, h, Region.Op.UNION); 25720 } 25721 final int[] location = attachInfo.mTransparentLocation; 25722 getLocationInWindow(location); 25723 r.translate(location[0], location[1]); 25724 region.op(r, Region.Op.INTERSECT); 25725 } else { 25726 region.op(db, Region.Op.DIFFERENCE); 25727 } 25728 } 25729 checkForLongClick(long delay, float x, float y, int classification)25730 private void checkForLongClick(long delay, float x, float y, int classification) { 25731 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 25732 mHasPerformedLongPress = false; 25733 25734 if (mPendingCheckForLongPress == null) { 25735 mPendingCheckForLongPress = new CheckForLongPress(); 25736 } 25737 mPendingCheckForLongPress.setAnchor(x, y); 25738 mPendingCheckForLongPress.rememberWindowAttachCount(); 25739 mPendingCheckForLongPress.rememberPressedState(); 25740 mPendingCheckForLongPress.setClassification(classification); 25741 postDelayed(mPendingCheckForLongPress, delay); 25742 } 25743 } 25744 25745 /** 25746 * Inflate a view from an XML resource. This convenience method wraps the {@link 25747 * LayoutInflater} class, which provides a full range of options for view inflation. 25748 * 25749 * @param context The Context object for your activity or application. 25750 * @param resource The resource ID to inflate 25751 * @param root A view group that will be the parent. Used to properly inflate the 25752 * layout_* parameters. 25753 * @see LayoutInflater 25754 */ inflate(Context context, @LayoutRes int resource, ViewGroup root)25755 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 25756 LayoutInflater factory = LayoutInflater.from(context); 25757 return factory.inflate(resource, root); 25758 } 25759 25760 /** 25761 * Scroll the view with standard behavior for scrolling beyond the normal 25762 * content boundaries. Views that call this method should override 25763 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 25764 * results of an over-scroll operation. 25765 * 25766 * Views can use this method to handle any touch or fling-based scrolling. 25767 * 25768 * @param deltaX Change in X in pixels 25769 * @param deltaY Change in Y in pixels 25770 * @param scrollX Current X scroll value in pixels before applying deltaX 25771 * @param scrollY Current Y scroll value in pixels before applying deltaY 25772 * @param scrollRangeX Maximum content scroll range along the X axis 25773 * @param scrollRangeY Maximum content scroll range along the Y axis 25774 * @param maxOverScrollX Number of pixels to overscroll by in either direction 25775 * along the X axis. 25776 * @param maxOverScrollY Number of pixels to overscroll by in either direction 25777 * along the Y axis. 25778 * @param isTouchEvent true if this scroll operation is the result of a touch event. 25779 * @return true if scrolling was clamped to an over-scroll boundary along either 25780 * axis, false otherwise. 25781 */ 25782 @SuppressWarnings({"UnusedParameters"}) overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent)25783 protected boolean overScrollBy(int deltaX, int deltaY, 25784 int scrollX, int scrollY, 25785 int scrollRangeX, int scrollRangeY, 25786 int maxOverScrollX, int maxOverScrollY, 25787 boolean isTouchEvent) { 25788 final int overScrollMode = mOverScrollMode; 25789 final boolean canScrollHorizontal = 25790 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 25791 final boolean canScrollVertical = 25792 computeVerticalScrollRange() > computeVerticalScrollExtent(); 25793 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 25794 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 25795 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 25796 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 25797 25798 int newScrollX = scrollX + deltaX; 25799 if (!overScrollHorizontal) { 25800 maxOverScrollX = 0; 25801 } 25802 25803 int newScrollY = scrollY + deltaY; 25804 if (!overScrollVertical) { 25805 maxOverScrollY = 0; 25806 } 25807 25808 // Clamp values if at the limits and record 25809 final int left = -maxOverScrollX; 25810 final int right = maxOverScrollX + scrollRangeX; 25811 final int top = -maxOverScrollY; 25812 final int bottom = maxOverScrollY + scrollRangeY; 25813 25814 boolean clampedX = false; 25815 if (newScrollX > right) { 25816 newScrollX = right; 25817 clampedX = true; 25818 } else if (newScrollX < left) { 25819 newScrollX = left; 25820 clampedX = true; 25821 } 25822 25823 boolean clampedY = false; 25824 if (newScrollY > bottom) { 25825 newScrollY = bottom; 25826 clampedY = true; 25827 } else if (newScrollY < top) { 25828 newScrollY = top; 25829 clampedY = true; 25830 } 25831 25832 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 25833 25834 return clampedX || clampedY; 25835 } 25836 25837 /** 25838 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 25839 * respond to the results of an over-scroll operation. 25840 * 25841 * @param scrollX New X scroll value in pixels 25842 * @param scrollY New Y scroll value in pixels 25843 * @param clampedX True if scrollX was clamped to an over-scroll boundary 25844 * @param clampedY True if scrollY was clamped to an over-scroll boundary 25845 */ onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY)25846 protected void onOverScrolled(int scrollX, int scrollY, 25847 boolean clampedX, boolean clampedY) { 25848 // Intentionally empty. 25849 } 25850 25851 /** 25852 * Returns the over-scroll mode for this view. The result will be 25853 * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 25854 * (allow over-scrolling only if the view content is larger than the container), 25855 * or {@link #OVER_SCROLL_NEVER}. 25856 * 25857 * @return This view's over-scroll mode. 25858 */ 25859 @InspectableProperty(enumMapping = { 25860 @EnumEntry(value = OVER_SCROLL_ALWAYS, name = "always"), 25861 @EnumEntry(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"), 25862 @EnumEntry(value = OVER_SCROLL_NEVER, name = "never") 25863 }) getOverScrollMode()25864 public int getOverScrollMode() { 25865 return mOverScrollMode; 25866 } 25867 25868 /** 25869 * Set the over-scroll mode for this view. Valid over-scroll modes are 25870 * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 25871 * (allow over-scrolling only if the view content is larger than the container), 25872 * or {@link #OVER_SCROLL_NEVER}. 25873 * 25874 * Setting the over-scroll mode of a view will have an effect only if the 25875 * view is capable of scrolling. 25876 * 25877 * @param overScrollMode The new over-scroll mode for this view. 25878 */ setOverScrollMode(int overScrollMode)25879 public void setOverScrollMode(int overScrollMode) { 25880 if (overScrollMode != OVER_SCROLL_ALWAYS && 25881 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 25882 overScrollMode != OVER_SCROLL_NEVER) { 25883 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 25884 } 25885 mOverScrollMode = overScrollMode; 25886 } 25887 25888 /** 25889 * Enable or disable nested scrolling for this view. 25890 * 25891 * <p>If this property is set to true the view will be permitted to initiate nested 25892 * scrolling operations with a compatible parent view in the current hierarchy. If this 25893 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 25894 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 25895 * the nested scroll.</p> 25896 * 25897 * @param enabled true to enable nested scrolling, false to disable 25898 * 25899 * @see #isNestedScrollingEnabled() 25900 */ setNestedScrollingEnabled(boolean enabled)25901 public void setNestedScrollingEnabled(boolean enabled) { 25902 if (enabled) { 25903 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 25904 } else { 25905 stopNestedScroll(); 25906 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 25907 } 25908 } 25909 25910 /** 25911 * Returns true if nested scrolling is enabled for this view. 25912 * 25913 * <p>If nested scrolling is enabled and this View class implementation supports it, 25914 * this view will act as a nested scrolling child view when applicable, forwarding data 25915 * about the scroll operation in progress to a compatible and cooperating nested scrolling 25916 * parent.</p> 25917 * 25918 * @return true if nested scrolling is enabled 25919 * 25920 * @see #setNestedScrollingEnabled(boolean) 25921 */ 25922 @InspectableProperty isNestedScrollingEnabled()25923 public boolean isNestedScrollingEnabled() { 25924 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 25925 PFLAG3_NESTED_SCROLLING_ENABLED; 25926 } 25927 25928 /** 25929 * Begin a nestable scroll operation along the given axes. 25930 * 25931 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 25932 * 25933 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 25934 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 25935 * In the case of touch scrolling the nested scroll will be terminated automatically in 25936 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 25937 * In the event of programmatic scrolling the caller must explicitly call 25938 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 25939 * 25940 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 25941 * If it returns false the caller may ignore the rest of this contract until the next scroll. 25942 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 25943 * 25944 * <p>At each incremental step of the scroll the caller should invoke 25945 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 25946 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 25947 * parent at least partially consumed the scroll and the caller should adjust the amount it 25948 * scrolls by.</p> 25949 * 25950 * <p>After applying the remainder of the scroll delta the caller should invoke 25951 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 25952 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 25953 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 25954 * </p> 25955 * 25956 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 25957 * {@link #SCROLL_AXIS_VERTICAL}. 25958 * @return true if a cooperative parent was found and nested scrolling has been enabled for 25959 * the current gesture. 25960 * 25961 * @see #stopNestedScroll() 25962 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 25963 * @see #dispatchNestedScroll(int, int, int, int, int[]) 25964 */ startNestedScroll(int axes)25965 public boolean startNestedScroll(int axes) { 25966 if (hasNestedScrollingParent()) { 25967 // Already in progress 25968 return true; 25969 } 25970 if (isNestedScrollingEnabled()) { 25971 ViewParent p = getParent(); 25972 View child = this; 25973 while (p != null) { 25974 try { 25975 if (p.onStartNestedScroll(child, this, axes)) { 25976 mNestedScrollingParent = p; 25977 p.onNestedScrollAccepted(child, this, axes); 25978 return true; 25979 } 25980 } catch (AbstractMethodError e) { 25981 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 25982 "method onStartNestedScroll", e); 25983 // Allow the search upward to continue 25984 } 25985 if (p instanceof View) { 25986 child = (View) p; 25987 } 25988 p = p.getParent(); 25989 } 25990 } 25991 return false; 25992 } 25993 25994 /** 25995 * Stop a nested scroll in progress. 25996 * 25997 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 25998 * 25999 * @see #startNestedScroll(int) 26000 */ stopNestedScroll()26001 public void stopNestedScroll() { 26002 if (mNestedScrollingParent != null) { 26003 mNestedScrollingParent.onStopNestedScroll(this); 26004 mNestedScrollingParent = null; 26005 } 26006 } 26007 26008 /** 26009 * Returns true if this view has a nested scrolling parent. 26010 * 26011 * <p>The presence of a nested scrolling parent indicates that this view has initiated 26012 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 26013 * 26014 * @return whether this view has a nested scrolling parent 26015 */ hasNestedScrollingParent()26016 public boolean hasNestedScrollingParent() { 26017 return mNestedScrollingParent != null; 26018 } 26019 26020 /** 26021 * Dispatch one step of a nested scroll in progress. 26022 * 26023 * <p>Implementations of views that support nested scrolling should call this to report 26024 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 26025 * is not currently in progress or nested scrolling is not 26026 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 26027 * 26028 * <p>Compatible View implementations should also call 26029 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 26030 * consuming a component of the scroll event themselves.</p> 26031 * 26032 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 26033 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 26034 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 26035 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 26036 * @param offsetInWindow Optional. If not null, on return this will contain the offset 26037 * in local view coordinates of this view from before this operation 26038 * to after it completes. View implementations may use this to adjust 26039 * expected input coordinate tracking. 26040 * @return true if the event was dispatched, false if it could not be dispatched. 26041 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 26042 */ dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow)26043 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 26044 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 26045 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 26046 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 26047 int startX = 0; 26048 int startY = 0; 26049 if (offsetInWindow != null) { 26050 getLocationInWindow(offsetInWindow); 26051 startX = offsetInWindow[0]; 26052 startY = offsetInWindow[1]; 26053 } 26054 26055 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 26056 dxUnconsumed, dyUnconsumed); 26057 26058 if (offsetInWindow != null) { 26059 getLocationInWindow(offsetInWindow); 26060 offsetInWindow[0] -= startX; 26061 offsetInWindow[1] -= startY; 26062 } 26063 return true; 26064 } else if (offsetInWindow != null) { 26065 // No motion, no dispatch. Keep offsetInWindow up to date. 26066 offsetInWindow[0] = 0; 26067 offsetInWindow[1] = 0; 26068 } 26069 } 26070 return false; 26071 } 26072 26073 /** 26074 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 26075 * 26076 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 26077 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 26078 * scrolling operation to consume some or all of the scroll operation before the child view 26079 * consumes it.</p> 26080 * 26081 * @param dx Horizontal scroll distance in pixels 26082 * @param dy Vertical scroll distance in pixels 26083 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 26084 * and consumed[1] the consumed dy. 26085 * @param offsetInWindow Optional. If not null, on return this will contain the offset 26086 * in local view coordinates of this view from before this operation 26087 * to after it completes. View implementations may use this to adjust 26088 * expected input coordinate tracking. 26089 * @return true if the parent consumed some or all of the scroll delta 26090 * @see #dispatchNestedScroll(int, int, int, int, int[]) 26091 */ dispatchNestedPreScroll(int dx, int dy, @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow)26092 public boolean dispatchNestedPreScroll(int dx, int dy, 26093 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 26094 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 26095 if (dx != 0 || dy != 0) { 26096 int startX = 0; 26097 int startY = 0; 26098 if (offsetInWindow != null) { 26099 getLocationInWindow(offsetInWindow); 26100 startX = offsetInWindow[0]; 26101 startY = offsetInWindow[1]; 26102 } 26103 26104 if (consumed == null) { 26105 if (mTempNestedScrollConsumed == null) { 26106 mTempNestedScrollConsumed = new int[2]; 26107 } 26108 consumed = mTempNestedScrollConsumed; 26109 } 26110 consumed[0] = 0; 26111 consumed[1] = 0; 26112 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 26113 26114 if (offsetInWindow != null) { 26115 getLocationInWindow(offsetInWindow); 26116 offsetInWindow[0] -= startX; 26117 offsetInWindow[1] -= startY; 26118 } 26119 return consumed[0] != 0 || consumed[1] != 0; 26120 } else if (offsetInWindow != null) { 26121 offsetInWindow[0] = 0; 26122 offsetInWindow[1] = 0; 26123 } 26124 } 26125 return false; 26126 } 26127 26128 /** 26129 * Dispatch a fling to a nested scrolling parent. 26130 * 26131 * <p>This method should be used to indicate that a nested scrolling child has detected 26132 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 26133 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 26134 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 26135 * along a scrollable axis.</p> 26136 * 26137 * <p>If a nested scrolling child view would normally fling but it is at the edge of 26138 * its own content, it can use this method to delegate the fling to its nested scrolling 26139 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 26140 * 26141 * @param velocityX Horizontal fling velocity in pixels per second 26142 * @param velocityY Vertical fling velocity in pixels per second 26143 * @param consumed true if the child consumed the fling, false otherwise 26144 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 26145 */ dispatchNestedFling(float velocityX, float velocityY, boolean consumed)26146 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 26147 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 26148 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 26149 } 26150 return false; 26151 } 26152 26153 /** 26154 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 26155 * 26156 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 26157 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 26158 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 26159 * before the child view consumes it. If this method returns <code>true</code>, a nested 26160 * parent view consumed the fling and this view should not scroll as a result.</p> 26161 * 26162 * <p>For a better user experience, only one view in a nested scrolling chain should consume 26163 * the fling at a time. If a parent view consumed the fling this method will return false. 26164 * Custom view implementations should account for this in two ways:</p> 26165 * 26166 * <ul> 26167 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 26168 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 26169 * position regardless.</li> 26170 * <li>If a nested parent does consume the fling, this view should not scroll at all, 26171 * even to settle back to a valid idle position.</li> 26172 * </ul> 26173 * 26174 * <p>Views should also not offer fling velocities to nested parent views along an axis 26175 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 26176 * should not offer a horizontal fling velocity to its parents since scrolling along that 26177 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 26178 * 26179 * @param velocityX Horizontal fling velocity in pixels per second 26180 * @param velocityY Vertical fling velocity in pixels per second 26181 * @return true if a nested scrolling parent consumed the fling 26182 */ dispatchNestedPreFling(float velocityX, float velocityY)26183 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 26184 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 26185 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 26186 } 26187 return false; 26188 } 26189 26190 /** 26191 * Gets a scale factor that determines the distance the view should scroll 26192 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 26193 * @return The vertical scroll scale factor. 26194 * @hide 26195 */ 26196 @UnsupportedAppUsage getVerticalScrollFactor()26197 protected float getVerticalScrollFactor() { 26198 if (mVerticalScrollFactor == 0) { 26199 TypedValue outValue = new TypedValue(); 26200 if (!mContext.getTheme().resolveAttribute( 26201 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 26202 throw new IllegalStateException( 26203 "Expected theme to define listPreferredItemHeight."); 26204 } 26205 mVerticalScrollFactor = outValue.getDimension( 26206 mContext.getResources().getDisplayMetrics()); 26207 } 26208 return mVerticalScrollFactor; 26209 } 26210 26211 /** 26212 * Gets a scale factor that determines the distance the view should scroll 26213 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 26214 * @return The horizontal scroll scale factor. 26215 * @hide 26216 */ 26217 @UnsupportedAppUsage getHorizontalScrollFactor()26218 protected float getHorizontalScrollFactor() { 26219 // TODO: Should use something else. 26220 return getVerticalScrollFactor(); 26221 } 26222 26223 /** 26224 * Return the value specifying the text direction or policy that was set with 26225 * {@link #setTextDirection(int)}. 26226 * 26227 * @return the defined text direction. It can be one of: 26228 * 26229 * {@link #TEXT_DIRECTION_INHERIT}, 26230 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 26231 * {@link #TEXT_DIRECTION_ANY_RTL}, 26232 * {@link #TEXT_DIRECTION_LTR}, 26233 * {@link #TEXT_DIRECTION_RTL}, 26234 * {@link #TEXT_DIRECTION_LOCALE}, 26235 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 26236 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 26237 * 26238 * @attr ref android.R.styleable#View_textDirection 26239 * 26240 * @hide 26241 */ 26242 @ViewDebug.ExportedProperty(category = "text", mapping = { 26243 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 26244 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 26245 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 26246 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 26247 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 26248 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 26249 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 26250 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 26251 }) 26252 @InspectableProperty(hasAttributeId = false, enumMapping = { 26253 @EnumEntry(value = TEXT_DIRECTION_INHERIT, name = "inherit"), 26254 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 26255 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 26256 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 26257 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 26258 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 26259 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 26260 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 26261 }) 26262 @UnsupportedAppUsage getRawTextDirection()26263 public int getRawTextDirection() { 26264 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 26265 } 26266 26267 /** 26268 * Set the text direction. 26269 * 26270 * @param textDirection the direction to set. Should be one of: 26271 * 26272 * {@link #TEXT_DIRECTION_INHERIT}, 26273 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 26274 * {@link #TEXT_DIRECTION_ANY_RTL}, 26275 * {@link #TEXT_DIRECTION_LTR}, 26276 * {@link #TEXT_DIRECTION_RTL}, 26277 * {@link #TEXT_DIRECTION_LOCALE} 26278 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 26279 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 26280 * 26281 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 26282 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 26283 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 26284 * 26285 * @attr ref android.R.styleable#View_textDirection 26286 */ setTextDirection(int textDirection)26287 public void setTextDirection(int textDirection) { 26288 if (getRawTextDirection() != textDirection) { 26289 // Reset the current text direction and the resolved one 26290 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 26291 resetResolvedTextDirection(); 26292 // Set the new text direction 26293 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 26294 // Do resolution 26295 resolveTextDirection(); 26296 // Notify change 26297 onRtlPropertiesChanged(getLayoutDirection()); 26298 // Refresh 26299 requestLayout(); 26300 invalidate(true); 26301 } 26302 } 26303 26304 /** 26305 * Return the resolved text direction. 26306 * 26307 * @return the resolved text direction. Returns one of: 26308 * 26309 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 26310 * {@link #TEXT_DIRECTION_ANY_RTL}, 26311 * {@link #TEXT_DIRECTION_LTR}, 26312 * {@link #TEXT_DIRECTION_RTL}, 26313 * {@link #TEXT_DIRECTION_LOCALE}, 26314 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 26315 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 26316 * 26317 * @attr ref android.R.styleable#View_textDirection 26318 */ 26319 @ViewDebug.ExportedProperty(category = "text", mapping = { 26320 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 26321 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 26322 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 26323 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 26324 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 26325 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 26326 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 26327 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 26328 }) 26329 @InspectableProperty(hasAttributeId = false, enumMapping = { 26330 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 26331 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 26332 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 26333 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 26334 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 26335 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 26336 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 26337 }) getTextDirection()26338 public int getTextDirection() { 26339 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 26340 } 26341 26342 /** 26343 * Resolve the text direction. 26344 * 26345 * @return true if resolution has been done, false otherwise. 26346 * 26347 * @hide 26348 */ resolveTextDirection()26349 public boolean resolveTextDirection() { 26350 // Reset any previous text direction resolution 26351 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 26352 26353 if (hasRtlSupport()) { 26354 // Set resolved text direction flag depending on text direction flag 26355 final int textDirection = getRawTextDirection(); 26356 switch(textDirection) { 26357 case TEXT_DIRECTION_INHERIT: 26358 if (!canResolveTextDirection()) { 26359 // We cannot do the resolution if there is no parent, so use the default one 26360 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 26361 // Resolution will need to happen again later 26362 return false; 26363 } 26364 26365 // Parent has not yet resolved, so we still return the default 26366 try { 26367 if (!mParent.isTextDirectionResolved()) { 26368 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 26369 // Resolution will need to happen again later 26370 return false; 26371 } 26372 } catch (AbstractMethodError e) { 26373 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 26374 " does not fully implement ViewParent", e); 26375 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 26376 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 26377 return true; 26378 } 26379 26380 // Set current resolved direction to the same value as the parent's one 26381 int parentResolvedDirection; 26382 try { 26383 parentResolvedDirection = mParent.getTextDirection(); 26384 } catch (AbstractMethodError e) { 26385 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 26386 " does not fully implement ViewParent", e); 26387 parentResolvedDirection = TEXT_DIRECTION_LTR; 26388 } 26389 switch (parentResolvedDirection) { 26390 case TEXT_DIRECTION_FIRST_STRONG: 26391 case TEXT_DIRECTION_ANY_RTL: 26392 case TEXT_DIRECTION_LTR: 26393 case TEXT_DIRECTION_RTL: 26394 case TEXT_DIRECTION_LOCALE: 26395 case TEXT_DIRECTION_FIRST_STRONG_LTR: 26396 case TEXT_DIRECTION_FIRST_STRONG_RTL: 26397 mPrivateFlags2 |= 26398 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 26399 break; 26400 default: 26401 // Default resolved direction is "first strong" heuristic 26402 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 26403 } 26404 break; 26405 case TEXT_DIRECTION_FIRST_STRONG: 26406 case TEXT_DIRECTION_ANY_RTL: 26407 case TEXT_DIRECTION_LTR: 26408 case TEXT_DIRECTION_RTL: 26409 case TEXT_DIRECTION_LOCALE: 26410 case TEXT_DIRECTION_FIRST_STRONG_LTR: 26411 case TEXT_DIRECTION_FIRST_STRONG_RTL: 26412 // Resolved direction is the same as text direction 26413 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 26414 break; 26415 default: 26416 // Default resolved direction is "first strong" heuristic 26417 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 26418 } 26419 } else { 26420 // Default resolved direction is "first strong" heuristic 26421 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 26422 } 26423 26424 // Set to resolved 26425 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 26426 return true; 26427 } 26428 26429 /** 26430 * Check if text direction resolution can be done. 26431 * 26432 * @return true if text direction resolution can be done otherwise return false. 26433 */ canResolveTextDirection()26434 public boolean canResolveTextDirection() { 26435 switch (getRawTextDirection()) { 26436 case TEXT_DIRECTION_INHERIT: 26437 if (mParent != null) { 26438 try { 26439 return mParent.canResolveTextDirection(); 26440 } catch (AbstractMethodError e) { 26441 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 26442 " does not fully implement ViewParent", e); 26443 } 26444 } 26445 return false; 26446 26447 default: 26448 return true; 26449 } 26450 } 26451 26452 /** 26453 * Reset resolved text direction. Text direction will be resolved during a call to 26454 * {@link #onMeasure(int, int)}. 26455 * 26456 * @hide 26457 */ 26458 @TestApi resetResolvedTextDirection()26459 public void resetResolvedTextDirection() { 26460 // Reset any previous text direction resolution 26461 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 26462 // Set to default value 26463 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 26464 } 26465 26466 /** 26467 * @return true if text direction is inherited. 26468 * 26469 * @hide 26470 */ isTextDirectionInherited()26471 public boolean isTextDirectionInherited() { 26472 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 26473 } 26474 26475 /** 26476 * @return true if text direction is resolved. 26477 */ isTextDirectionResolved()26478 public boolean isTextDirectionResolved() { 26479 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 26480 } 26481 26482 /** 26483 * Return the value specifying the text alignment or policy that was set with 26484 * {@link #setTextAlignment(int)}. 26485 * 26486 * @return the defined text alignment. It can be one of: 26487 * 26488 * {@link #TEXT_ALIGNMENT_INHERIT}, 26489 * {@link #TEXT_ALIGNMENT_GRAVITY}, 26490 * {@link #TEXT_ALIGNMENT_CENTER}, 26491 * {@link #TEXT_ALIGNMENT_TEXT_START}, 26492 * {@link #TEXT_ALIGNMENT_TEXT_END}, 26493 * {@link #TEXT_ALIGNMENT_VIEW_START}, 26494 * {@link #TEXT_ALIGNMENT_VIEW_END} 26495 * 26496 * @attr ref android.R.styleable#View_textAlignment 26497 * 26498 * @hide 26499 */ 26500 @ViewDebug.ExportedProperty(category = "text", mapping = { 26501 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 26502 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 26503 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 26504 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 26505 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 26506 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 26507 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 26508 }) 26509 @InspectableProperty(hasAttributeId = false, enumMapping = { 26510 @EnumEntry(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"), 26511 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 26512 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 26513 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 26514 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 26515 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 26516 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 26517 }) 26518 @TextAlignment 26519 @UnsupportedAppUsage getRawTextAlignment()26520 public int getRawTextAlignment() { 26521 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 26522 } 26523 26524 /** 26525 * Set the text alignment. 26526 * 26527 * @param textAlignment The text alignment to set. Should be one of 26528 * 26529 * {@link #TEXT_ALIGNMENT_INHERIT}, 26530 * {@link #TEXT_ALIGNMENT_GRAVITY}, 26531 * {@link #TEXT_ALIGNMENT_CENTER}, 26532 * {@link #TEXT_ALIGNMENT_TEXT_START}, 26533 * {@link #TEXT_ALIGNMENT_TEXT_END}, 26534 * {@link #TEXT_ALIGNMENT_VIEW_START}, 26535 * {@link #TEXT_ALIGNMENT_VIEW_END} 26536 * 26537 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 26538 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 26539 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 26540 * 26541 * @attr ref android.R.styleable#View_textAlignment 26542 */ setTextAlignment(@extAlignment int textAlignment)26543 public void setTextAlignment(@TextAlignment int textAlignment) { 26544 if (textAlignment != getRawTextAlignment()) { 26545 // Reset the current and resolved text alignment 26546 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 26547 resetResolvedTextAlignment(); 26548 // Set the new text alignment 26549 mPrivateFlags2 |= 26550 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 26551 // Do resolution 26552 resolveTextAlignment(); 26553 // Notify change 26554 onRtlPropertiesChanged(getLayoutDirection()); 26555 // Refresh 26556 requestLayout(); 26557 invalidate(true); 26558 } 26559 } 26560 26561 /** 26562 * Return the resolved text alignment. 26563 * 26564 * @return the resolved text alignment. Returns one of: 26565 * 26566 * {@link #TEXT_ALIGNMENT_GRAVITY}, 26567 * {@link #TEXT_ALIGNMENT_CENTER}, 26568 * {@link #TEXT_ALIGNMENT_TEXT_START}, 26569 * {@link #TEXT_ALIGNMENT_TEXT_END}, 26570 * {@link #TEXT_ALIGNMENT_VIEW_START}, 26571 * {@link #TEXT_ALIGNMENT_VIEW_END} 26572 * 26573 * @attr ref android.R.styleable#View_textAlignment 26574 */ 26575 @ViewDebug.ExportedProperty(category = "text", mapping = { 26576 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 26577 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 26578 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 26579 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 26580 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 26581 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 26582 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 26583 }) 26584 @InspectableProperty(enumMapping = { 26585 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 26586 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 26587 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 26588 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 26589 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 26590 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 26591 }) 26592 @TextAlignment getTextAlignment()26593 public int getTextAlignment() { 26594 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 26595 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 26596 } 26597 26598 /** 26599 * Resolve the text alignment. 26600 * 26601 * @return true if resolution has been done, false otherwise. 26602 * 26603 * @hide 26604 */ resolveTextAlignment()26605 public boolean resolveTextAlignment() { 26606 // Reset any previous text alignment resolution 26607 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 26608 26609 if (hasRtlSupport()) { 26610 // Set resolved text alignment flag depending on text alignment flag 26611 final int textAlignment = getRawTextAlignment(); 26612 switch (textAlignment) { 26613 case TEXT_ALIGNMENT_INHERIT: 26614 // Check if we can resolve the text alignment 26615 if (!canResolveTextAlignment()) { 26616 // We cannot do the resolution if there is no parent so use the default 26617 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 26618 // Resolution will need to happen again later 26619 return false; 26620 } 26621 26622 // Parent has not yet resolved, so we still return the default 26623 try { 26624 if (!mParent.isTextAlignmentResolved()) { 26625 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 26626 // Resolution will need to happen again later 26627 return false; 26628 } 26629 } catch (AbstractMethodError e) { 26630 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 26631 " does not fully implement ViewParent", e); 26632 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 26633 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 26634 return true; 26635 } 26636 26637 int parentResolvedTextAlignment; 26638 try { 26639 parentResolvedTextAlignment = mParent.getTextAlignment(); 26640 } catch (AbstractMethodError e) { 26641 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 26642 " does not fully implement ViewParent", e); 26643 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 26644 } 26645 switch (parentResolvedTextAlignment) { 26646 case TEXT_ALIGNMENT_GRAVITY: 26647 case TEXT_ALIGNMENT_TEXT_START: 26648 case TEXT_ALIGNMENT_TEXT_END: 26649 case TEXT_ALIGNMENT_CENTER: 26650 case TEXT_ALIGNMENT_VIEW_START: 26651 case TEXT_ALIGNMENT_VIEW_END: 26652 // Resolved text alignment is the same as the parent resolved 26653 // text alignment 26654 mPrivateFlags2 |= 26655 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 26656 break; 26657 default: 26658 // Use default resolved text alignment 26659 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 26660 } 26661 break; 26662 case TEXT_ALIGNMENT_GRAVITY: 26663 case TEXT_ALIGNMENT_TEXT_START: 26664 case TEXT_ALIGNMENT_TEXT_END: 26665 case TEXT_ALIGNMENT_CENTER: 26666 case TEXT_ALIGNMENT_VIEW_START: 26667 case TEXT_ALIGNMENT_VIEW_END: 26668 // Resolved text alignment is the same as text alignment 26669 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 26670 break; 26671 default: 26672 // Use default resolved text alignment 26673 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 26674 } 26675 } else { 26676 // Use default resolved text alignment 26677 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 26678 } 26679 26680 // Set the resolved 26681 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 26682 return true; 26683 } 26684 26685 /** 26686 * Check if text alignment resolution can be done. 26687 * 26688 * @return true if text alignment resolution can be done otherwise return false. 26689 */ canResolveTextAlignment()26690 public boolean canResolveTextAlignment() { 26691 switch (getRawTextAlignment()) { 26692 case TEXT_DIRECTION_INHERIT: 26693 if (mParent != null) { 26694 try { 26695 return mParent.canResolveTextAlignment(); 26696 } catch (AbstractMethodError e) { 26697 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 26698 " does not fully implement ViewParent", e); 26699 } 26700 } 26701 return false; 26702 26703 default: 26704 return true; 26705 } 26706 } 26707 26708 /** 26709 * Reset resolved text alignment. Text alignment will be resolved during a call to 26710 * {@link #onMeasure(int, int)}. 26711 * 26712 * @hide 26713 */ 26714 @TestApi resetResolvedTextAlignment()26715 public void resetResolvedTextAlignment() { 26716 // Reset any previous text alignment resolution 26717 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 26718 // Set to default 26719 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 26720 } 26721 26722 /** 26723 * @return true if text alignment is inherited. 26724 * 26725 * @hide 26726 */ isTextAlignmentInherited()26727 public boolean isTextAlignmentInherited() { 26728 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 26729 } 26730 26731 /** 26732 * @return true if text alignment is resolved. 26733 */ isTextAlignmentResolved()26734 public boolean isTextAlignmentResolved() { 26735 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 26736 } 26737 26738 /** 26739 * Generate a value suitable for use in {@link #setId(int)}. 26740 * This value will not collide with ID values generated at build time by aapt for R.id. 26741 * 26742 * @return a generated ID value 26743 */ generateViewId()26744 public static int generateViewId() { 26745 for (;;) { 26746 final int result = sNextGeneratedId.get(); 26747 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 26748 int newValue = result + 1; 26749 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 26750 if (sNextGeneratedId.compareAndSet(result, newValue)) { 26751 return result; 26752 } 26753 } 26754 } 26755 isViewIdGenerated(int id)26756 private static boolean isViewIdGenerated(int id) { 26757 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 26758 } 26759 26760 /** 26761 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 26762 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 26763 * a normal View or a ViewGroup with 26764 * {@link android.view.ViewGroup#isTransitionGroup()} true. 26765 * @hide 26766 */ captureTransitioningViews(List<View> transitioningViews)26767 public void captureTransitioningViews(List<View> transitioningViews) { 26768 if (getVisibility() == View.VISIBLE) { 26769 transitioningViews.add(this); 26770 } 26771 } 26772 26773 /** 26774 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 26775 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 26776 * @hide 26777 */ findNamedViews(Map<String, View> namedElements)26778 public void findNamedViews(Map<String, View> namedElements) { 26779 if (getVisibility() == VISIBLE || mGhostView != null) { 26780 String transitionName = getTransitionName(); 26781 if (transitionName != null) { 26782 namedElements.put(transitionName, this); 26783 } 26784 } 26785 } 26786 26787 /** 26788 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 26789 * The default implementation does not care the location or event types, but some subclasses 26790 * may use it (such as WebViews). 26791 * @param event The MotionEvent from a mouse 26792 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 26793 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 26794 * @see PointerIcon 26795 */ onResolvePointerIcon(MotionEvent event, int pointerIndex)26796 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 26797 final float x = event.getX(pointerIndex); 26798 final float y = event.getY(pointerIndex); 26799 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 26800 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 26801 } 26802 return mPointerIcon; 26803 } 26804 26805 /** 26806 * Set the pointer icon for the current view. 26807 * Passing {@code null} will restore the pointer icon to its default value. 26808 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 26809 */ setPointerIcon(PointerIcon pointerIcon)26810 public void setPointerIcon(PointerIcon pointerIcon) { 26811 mPointerIcon = pointerIcon; 26812 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 26813 return; 26814 } 26815 try { 26816 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 26817 } catch (RemoteException e) { 26818 } 26819 } 26820 26821 /** 26822 * Gets the pointer icon for the current view. 26823 */ 26824 @InspectableProperty getPointerIcon()26825 public PointerIcon getPointerIcon() { 26826 return mPointerIcon; 26827 } 26828 26829 /** 26830 * Checks pointer capture status. 26831 * 26832 * @return true if the view has pointer capture. 26833 * @see #requestPointerCapture() 26834 * @see #hasPointerCapture() 26835 */ hasPointerCapture()26836 public boolean hasPointerCapture() { 26837 final ViewRootImpl viewRootImpl = getViewRootImpl(); 26838 if (viewRootImpl == null) { 26839 return false; 26840 } 26841 return viewRootImpl.hasPointerCapture(); 26842 } 26843 26844 /** 26845 * Requests pointer capture mode. 26846 * <p> 26847 * When the window has pointer capture, the mouse pointer icon will disappear and will not 26848 * change its position. Further mouse will be dispatched with the source 26849 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be available 26850 * through {@link MotionEvent#getX} and {@link MotionEvent#getY}. Non-mouse events 26851 * (touchscreens, or stylus) will not be affected. 26852 * <p> 26853 * If the window already has pointer capture, this call does nothing. 26854 * <p> 26855 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 26856 * automatically when the window loses focus. 26857 * 26858 * @see #releasePointerCapture() 26859 * @see #hasPointerCapture() 26860 */ requestPointerCapture()26861 public void requestPointerCapture() { 26862 final ViewRootImpl viewRootImpl = getViewRootImpl(); 26863 if (viewRootImpl != null) { 26864 viewRootImpl.requestPointerCapture(true); 26865 } 26866 } 26867 26868 26869 /** 26870 * Releases the pointer capture. 26871 * <p> 26872 * If the window does not have pointer capture, this call will do nothing. 26873 * @see #requestPointerCapture() 26874 * @see #hasPointerCapture() 26875 */ releasePointerCapture()26876 public void releasePointerCapture() { 26877 final ViewRootImpl viewRootImpl = getViewRootImpl(); 26878 if (viewRootImpl != null) { 26879 viewRootImpl.requestPointerCapture(false); 26880 } 26881 } 26882 26883 /** 26884 * Called when the window has just acquired or lost pointer capture. 26885 * 26886 * @param hasCapture True if the view now has pointerCapture, false otherwise. 26887 */ 26888 @CallSuper onPointerCaptureChange(boolean hasCapture)26889 public void onPointerCaptureChange(boolean hasCapture) { 26890 } 26891 26892 /** 26893 * @see #onPointerCaptureChange 26894 */ dispatchPointerCaptureChanged(boolean hasCapture)26895 public void dispatchPointerCaptureChanged(boolean hasCapture) { 26896 onPointerCaptureChange(hasCapture); 26897 } 26898 26899 /** 26900 * Implement this method to handle captured pointer events 26901 * 26902 * @param event The captured pointer event. 26903 * @return True if the event was handled, false otherwise. 26904 * @see #requestPointerCapture() 26905 */ onCapturedPointerEvent(MotionEvent event)26906 public boolean onCapturedPointerEvent(MotionEvent event) { 26907 return false; 26908 } 26909 26910 /** 26911 * Interface definition for a callback to be invoked when a captured pointer event 26912 * is being dispatched this view. The callback will be invoked before the event is 26913 * given to the view. 26914 */ 26915 public interface OnCapturedPointerListener { 26916 /** 26917 * Called when a captured pointer event is dispatched to a view. 26918 * @param view The view this event has been dispatched to. 26919 * @param event The captured event. 26920 * @return True if the listener has consumed the event, false otherwise. 26921 */ onCapturedPointer(View view, MotionEvent event)26922 boolean onCapturedPointer(View view, MotionEvent event); 26923 } 26924 26925 /** 26926 * Set a listener to receive callbacks when the pointer capture state of a view changes. 26927 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 26928 */ setOnCapturedPointerListener(OnCapturedPointerListener l)26929 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 26930 getListenerInfo().mOnCapturedPointerListener = l; 26931 } 26932 26933 // Properties 26934 // 26935 /** 26936 * A Property wrapper around the <code>alpha</code> functionality handled by the 26937 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 26938 */ 26939 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 26940 @Override 26941 public void setValue(View object, float value) { 26942 object.setAlpha(value); 26943 } 26944 26945 @Override 26946 public Float get(View object) { 26947 return object.getAlpha(); 26948 } 26949 }; 26950 26951 /** 26952 * A Property wrapper around the <code>translationX</code> functionality handled by the 26953 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 26954 */ 26955 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 26956 @Override 26957 public void setValue(View object, float value) { 26958 object.setTranslationX(value); 26959 } 26960 26961 @Override 26962 public Float get(View object) { 26963 return object.getTranslationX(); 26964 } 26965 }; 26966 26967 /** 26968 * A Property wrapper around the <code>translationY</code> functionality handled by the 26969 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 26970 */ 26971 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 26972 @Override 26973 public void setValue(View object, float value) { 26974 object.setTranslationY(value); 26975 } 26976 26977 @Override 26978 public Float get(View object) { 26979 return object.getTranslationY(); 26980 } 26981 }; 26982 26983 /** 26984 * A Property wrapper around the <code>translationZ</code> functionality handled by the 26985 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 26986 */ 26987 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 26988 @Override 26989 public void setValue(View object, float value) { 26990 object.setTranslationZ(value); 26991 } 26992 26993 @Override 26994 public Float get(View object) { 26995 return object.getTranslationZ(); 26996 } 26997 }; 26998 26999 /** 27000 * A Property wrapper around the <code>x</code> functionality handled by the 27001 * {@link View#setX(float)} and {@link View#getX()} methods. 27002 */ 27003 public static final Property<View, Float> X = new FloatProperty<View>("x") { 27004 @Override 27005 public void setValue(View object, float value) { 27006 object.setX(value); 27007 } 27008 27009 @Override 27010 public Float get(View object) { 27011 return object.getX(); 27012 } 27013 }; 27014 27015 /** 27016 * A Property wrapper around the <code>y</code> functionality handled by the 27017 * {@link View#setY(float)} and {@link View#getY()} methods. 27018 */ 27019 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 27020 @Override 27021 public void setValue(View object, float value) { 27022 object.setY(value); 27023 } 27024 27025 @Override 27026 public Float get(View object) { 27027 return object.getY(); 27028 } 27029 }; 27030 27031 /** 27032 * A Property wrapper around the <code>z</code> functionality handled by the 27033 * {@link View#setZ(float)} and {@link View#getZ()} methods. 27034 */ 27035 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 27036 @Override 27037 public void setValue(View object, float value) { 27038 object.setZ(value); 27039 } 27040 27041 @Override 27042 public Float get(View object) { 27043 return object.getZ(); 27044 } 27045 }; 27046 27047 /** 27048 * A Property wrapper around the <code>rotation</code> functionality handled by the 27049 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 27050 */ 27051 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 27052 @Override 27053 public void setValue(View object, float value) { 27054 object.setRotation(value); 27055 } 27056 27057 @Override 27058 public Float get(View object) { 27059 return object.getRotation(); 27060 } 27061 }; 27062 27063 /** 27064 * A Property wrapper around the <code>rotationX</code> functionality handled by the 27065 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 27066 */ 27067 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 27068 @Override 27069 public void setValue(View object, float value) { 27070 object.setRotationX(value); 27071 } 27072 27073 @Override 27074 public Float get(View object) { 27075 return object.getRotationX(); 27076 } 27077 }; 27078 27079 /** 27080 * A Property wrapper around the <code>rotationY</code> functionality handled by the 27081 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 27082 */ 27083 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 27084 @Override 27085 public void setValue(View object, float value) { 27086 object.setRotationY(value); 27087 } 27088 27089 @Override 27090 public Float get(View object) { 27091 return object.getRotationY(); 27092 } 27093 }; 27094 27095 /** 27096 * A Property wrapper around the <code>scaleX</code> functionality handled by the 27097 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 27098 */ 27099 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 27100 @Override 27101 public void setValue(View object, float value) { 27102 object.setScaleX(value); 27103 } 27104 27105 @Override 27106 public Float get(View object) { 27107 return object.getScaleX(); 27108 } 27109 }; 27110 27111 /** 27112 * A Property wrapper around the <code>scaleY</code> functionality handled by the 27113 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 27114 */ 27115 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 27116 @Override 27117 public void setValue(View object, float value) { 27118 object.setScaleY(value); 27119 } 27120 27121 @Override 27122 public Float get(View object) { 27123 return object.getScaleY(); 27124 } 27125 }; 27126 27127 /** 27128 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 27129 * Each MeasureSpec represents a requirement for either the width or the height. 27130 * A MeasureSpec is comprised of a size and a mode. There are three possible 27131 * modes: 27132 * <dl> 27133 * <dt>UNSPECIFIED</dt> 27134 * <dd> 27135 * The parent has not imposed any constraint on the child. It can be whatever size 27136 * it wants. 27137 * </dd> 27138 * 27139 * <dt>EXACTLY</dt> 27140 * <dd> 27141 * The parent has determined an exact size for the child. The child is going to be 27142 * given those bounds regardless of how big it wants to be. 27143 * </dd> 27144 * 27145 * <dt>AT_MOST</dt> 27146 * <dd> 27147 * The child can be as large as it wants up to the specified size. 27148 * </dd> 27149 * </dl> 27150 * 27151 * MeasureSpecs are implemented as ints to reduce object allocation. This class 27152 * is provided to pack and unpack the <size, mode> tuple into the int. 27153 */ 27154 public static class MeasureSpec { 27155 private static final int MODE_SHIFT = 30; 27156 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 27157 27158 /** @hide */ 27159 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 27160 @Retention(RetentionPolicy.SOURCE) 27161 public @interface MeasureSpecMode {} 27162 27163 /** 27164 * Measure specification mode: The parent has not imposed any constraint 27165 * on the child. It can be whatever size it wants. 27166 */ 27167 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 27168 27169 /** 27170 * Measure specification mode: The parent has determined an exact size 27171 * for the child. The child is going to be given those bounds regardless 27172 * of how big it wants to be. 27173 */ 27174 public static final int EXACTLY = 1 << MODE_SHIFT; 27175 27176 /** 27177 * Measure specification mode: The child can be as large as it wants up 27178 * to the specified size. 27179 */ 27180 public static final int AT_MOST = 2 << MODE_SHIFT; 27181 27182 /** 27183 * Creates a measure specification based on the supplied size and mode. 27184 * 27185 * The mode must always be one of the following: 27186 * <ul> 27187 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 27188 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 27189 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 27190 * </ul> 27191 * 27192 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 27193 * implementation was such that the order of arguments did not matter 27194 * and overflow in either value could impact the resulting MeasureSpec. 27195 * {@link android.widget.RelativeLayout} was affected by this bug. 27196 * Apps targeting API levels greater than 17 will get the fixed, more strict 27197 * behavior.</p> 27198 * 27199 * @param size the size of the measure specification 27200 * @param mode the mode of the measure specification 27201 * @return the measure specification based on size and mode 27202 */ makeMeasureSpec(@ntRangefrom = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode)27203 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 27204 @MeasureSpecMode int mode) { 27205 if (sUseBrokenMakeMeasureSpec) { 27206 return size + mode; 27207 } else { 27208 return (size & ~MODE_MASK) | (mode & MODE_MASK); 27209 } 27210 } 27211 27212 /** 27213 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 27214 * will automatically get a size of 0. Older apps expect this. 27215 * 27216 * @hide internal use only for compatibility with system widgets and older apps 27217 */ 27218 @UnsupportedAppUsage makeSafeMeasureSpec(int size, int mode)27219 public static int makeSafeMeasureSpec(int size, int mode) { 27220 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 27221 return 0; 27222 } 27223 return makeMeasureSpec(size, mode); 27224 } 27225 27226 /** 27227 * Extracts the mode from the supplied measure specification. 27228 * 27229 * @param measureSpec the measure specification to extract the mode from 27230 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 27231 * {@link android.view.View.MeasureSpec#AT_MOST} or 27232 * {@link android.view.View.MeasureSpec#EXACTLY} 27233 */ 27234 @MeasureSpecMode getMode(int measureSpec)27235 public static int getMode(int measureSpec) { 27236 //noinspection ResourceType 27237 return (measureSpec & MODE_MASK); 27238 } 27239 27240 /** 27241 * Extracts the size from the supplied measure specification. 27242 * 27243 * @param measureSpec the measure specification to extract the size from 27244 * @return the size in pixels defined in the supplied measure specification 27245 */ getSize(int measureSpec)27246 public static int getSize(int measureSpec) { 27247 return (measureSpec & ~MODE_MASK); 27248 } 27249 adjust(int measureSpec, int delta)27250 static int adjust(int measureSpec, int delta) { 27251 final int mode = getMode(measureSpec); 27252 int size = getSize(measureSpec); 27253 if (mode == UNSPECIFIED) { 27254 // No need to adjust size for UNSPECIFIED mode. 27255 return makeMeasureSpec(size, UNSPECIFIED); 27256 } 27257 size += delta; 27258 if (size < 0) { 27259 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 27260 ") spec: " + toString(measureSpec) + " delta: " + delta); 27261 size = 0; 27262 } 27263 return makeMeasureSpec(size, mode); 27264 } 27265 27266 /** 27267 * Returns a String representation of the specified measure 27268 * specification. 27269 * 27270 * @param measureSpec the measure specification to convert to a String 27271 * @return a String with the following format: "MeasureSpec: MODE SIZE" 27272 */ toString(int measureSpec)27273 public static String toString(int measureSpec) { 27274 int mode = getMode(measureSpec); 27275 int size = getSize(measureSpec); 27276 27277 StringBuilder sb = new StringBuilder("MeasureSpec: "); 27278 27279 if (mode == UNSPECIFIED) 27280 sb.append("UNSPECIFIED "); 27281 else if (mode == EXACTLY) 27282 sb.append("EXACTLY "); 27283 else if (mode == AT_MOST) 27284 sb.append("AT_MOST "); 27285 else 27286 sb.append(mode).append(" "); 27287 27288 sb.append(size); 27289 return sb.toString(); 27290 } 27291 } 27292 27293 private final class CheckForLongPress implements Runnable { 27294 private int mOriginalWindowAttachCount; 27295 private float mX; 27296 private float mY; 27297 private boolean mOriginalPressedState; 27298 /** 27299 * The classification of the long click being checked: one of the 27300 * StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__* constants. 27301 */ 27302 private int mClassification; 27303 27304 @Override run()27305 public void run() { 27306 if ((mOriginalPressedState == isPressed()) && (mParent != null) 27307 && mOriginalWindowAttachCount == mWindowAttachCount) { 27308 recordGestureClassification(mClassification); 27309 if (performLongClick(mX, mY)) { 27310 mHasPerformedLongPress = true; 27311 } 27312 } 27313 } 27314 setAnchor(float x, float y)27315 public void setAnchor(float x, float y) { 27316 mX = x; 27317 mY = y; 27318 } 27319 rememberWindowAttachCount()27320 public void rememberWindowAttachCount() { 27321 mOriginalWindowAttachCount = mWindowAttachCount; 27322 } 27323 rememberPressedState()27324 public void rememberPressedState() { 27325 mOriginalPressedState = isPressed(); 27326 } 27327 setClassification(int classification)27328 public void setClassification(int classification) { 27329 mClassification = classification; 27330 } 27331 } 27332 27333 private final class CheckForTap implements Runnable { 27334 public float x; 27335 public float y; 27336 27337 @Override run()27338 public void run() { 27339 mPrivateFlags &= ~PFLAG_PREPRESSED; 27340 setPressed(true, x, y); 27341 final long delay = 27342 ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout(); 27343 checkForLongClick(delay, x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 27344 } 27345 } 27346 27347 private final class PerformClick implements Runnable { 27348 @Override run()27349 public void run() { 27350 recordGestureClassification(TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP); 27351 performClickInternal(); 27352 } 27353 } 27354 27355 /** Records a classification for the current event stream. */ recordGestureClassification(int classification)27356 private void recordGestureClassification(int classification) { 27357 if (classification == TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION) { 27358 return; 27359 } 27360 // To avoid negatively impacting View performance, the latency and displacement metrics 27361 // are omitted. 27362 StatsLog.write(StatsLog.TOUCH_GESTURE_CLASSIFIED, getClass().getName(), classification); 27363 } 27364 27365 /** 27366 * This method returns a ViewPropertyAnimator object, which can be used to animate 27367 * specific properties on this View. 27368 * 27369 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 27370 */ animate()27371 public ViewPropertyAnimator animate() { 27372 if (mAnimator == null) { 27373 mAnimator = new ViewPropertyAnimator(this); 27374 } 27375 return mAnimator; 27376 } 27377 27378 /** 27379 * Sets the name of the View to be used to identify Views in Transitions. 27380 * Names should be unique in the View hierarchy. 27381 * 27382 * @param transitionName The name of the View to uniquely identify it for Transitions. 27383 */ setTransitionName(String transitionName)27384 public final void setTransitionName(String transitionName) { 27385 mTransitionName = transitionName; 27386 } 27387 27388 /** 27389 * Returns the name of the View to be used to identify Views in Transitions. 27390 * Names should be unique in the View hierarchy. 27391 * 27392 * <p>This returns null if the View has not been given a name.</p> 27393 * 27394 * @return The name used of the View to be used to identify Views in Transitions or null 27395 * if no name has been given. 27396 */ 27397 @ViewDebug.ExportedProperty 27398 @InspectableProperty getTransitionName()27399 public String getTransitionName() { 27400 return mTransitionName; 27401 } 27402 27403 /** 27404 * @hide 27405 */ requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId)27406 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 27407 // Do nothing. 27408 } 27409 27410 /** 27411 * Interface definition for a callback to be invoked when a hardware key event is 27412 * dispatched to this view. The callback will be invoked before the key event is 27413 * given to the view. This is only useful for hardware keyboards; a software input 27414 * method has no obligation to trigger this listener. 27415 */ 27416 public interface OnKeyListener { 27417 /** 27418 * Called when a hardware key is dispatched to a view. This allows listeners to 27419 * get a chance to respond before the target view. 27420 * <p>Key presses in software keyboards will generally NOT trigger this method, 27421 * although some may elect to do so in some situations. Do not assume a 27422 * software input method has to be key-based; even if it is, it may use key presses 27423 * in a different way than you expect, so there is no way to reliably catch soft 27424 * input key presses. 27425 * 27426 * @param v The view the key has been dispatched to. 27427 * @param keyCode The code for the physical key that was pressed 27428 * @param event The KeyEvent object containing full information about 27429 * the event. 27430 * @return True if the listener has consumed the event, false otherwise. 27431 */ onKey(View v, int keyCode, KeyEvent event)27432 boolean onKey(View v, int keyCode, KeyEvent event); 27433 } 27434 27435 /** 27436 * Interface definition for a callback to be invoked when a hardware key event hasn't 27437 * been handled by the view hierarchy. 27438 */ 27439 public interface OnUnhandledKeyEventListener { 27440 /** 27441 * Called when a hardware key is dispatched to a view after being unhandled during normal 27442 * {@link KeyEvent} dispatch. 27443 * 27444 * @param v The view the key has been dispatched to. 27445 * @param event The KeyEvent object containing information about the event. 27446 * @return {@code true} if the listener has consumed the event, {@code false} otherwise. 27447 */ onUnhandledKeyEvent(View v, KeyEvent event)27448 boolean onUnhandledKeyEvent(View v, KeyEvent event); 27449 } 27450 27451 /** 27452 * Interface definition for a callback to be invoked when a touch event is 27453 * dispatched to this view. The callback will be invoked before the touch 27454 * event is given to the view. 27455 */ 27456 public interface OnTouchListener { 27457 /** 27458 * Called when a touch event is dispatched to a view. This allows listeners to 27459 * get a chance to respond before the target view. 27460 * 27461 * @param v The view the touch event has been dispatched to. 27462 * @param event The MotionEvent object containing full information about 27463 * the event. 27464 * @return True if the listener has consumed the event, false otherwise. 27465 */ onTouch(View v, MotionEvent event)27466 boolean onTouch(View v, MotionEvent event); 27467 } 27468 27469 /** 27470 * Interface definition for a callback to be invoked when a hover event is 27471 * dispatched to this view. The callback will be invoked before the hover 27472 * event is given to the view. 27473 */ 27474 public interface OnHoverListener { 27475 /** 27476 * Called when a hover event is dispatched to a view. This allows listeners to 27477 * get a chance to respond before the target view. 27478 * 27479 * @param v The view the hover event has been dispatched to. 27480 * @param event The MotionEvent object containing full information about 27481 * the event. 27482 * @return True if the listener has consumed the event, false otherwise. 27483 */ onHover(View v, MotionEvent event)27484 boolean onHover(View v, MotionEvent event); 27485 } 27486 27487 /** 27488 * Interface definition for a callback to be invoked when a generic motion event is 27489 * dispatched to this view. The callback will be invoked before the generic motion 27490 * event is given to the view. 27491 */ 27492 public interface OnGenericMotionListener { 27493 /** 27494 * Called when a generic motion event is dispatched to a view. This allows listeners to 27495 * get a chance to respond before the target view. 27496 * 27497 * @param v The view the generic motion event has been dispatched to. 27498 * @param event The MotionEvent object containing full information about 27499 * the event. 27500 * @return True if the listener has consumed the event, false otherwise. 27501 */ onGenericMotion(View v, MotionEvent event)27502 boolean onGenericMotion(View v, MotionEvent event); 27503 } 27504 27505 /** 27506 * Interface definition for a callback to be invoked when a view has been clicked and held. 27507 */ 27508 public interface OnLongClickListener { 27509 /** 27510 * Called when a view has been clicked and held. 27511 * 27512 * @param v The view that was clicked and held. 27513 * 27514 * @return true if the callback consumed the long click, false otherwise. 27515 */ onLongClick(View v)27516 boolean onLongClick(View v); 27517 } 27518 27519 /** 27520 * Interface definition for a callback to be invoked when a drag is being dispatched 27521 * to this view. The callback will be invoked before the hosting view's own 27522 * onDrag(event) method. If the listener wants to fall back to the hosting view's 27523 * onDrag(event) behavior, it should return 'false' from this callback. 27524 * 27525 * <div class="special reference"> 27526 * <h3>Developer Guides</h3> 27527 * <p>For a guide to implementing drag and drop features, read the 27528 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 27529 * </div> 27530 */ 27531 public interface OnDragListener { 27532 /** 27533 * Called when a drag event is dispatched to a view. This allows listeners 27534 * to get a chance to override base View behavior. 27535 * 27536 * @param v The View that received the drag event. 27537 * @param event The {@link android.view.DragEvent} object for the drag event. 27538 * @return {@code true} if the drag event was handled successfully, or {@code false} 27539 * if the drag event was not handled. Note that {@code false} will trigger the View 27540 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 27541 */ onDrag(View v, DragEvent event)27542 boolean onDrag(View v, DragEvent event); 27543 } 27544 27545 /** 27546 * Interface definition for a callback to be invoked when the focus state of 27547 * a view changed. 27548 */ 27549 public interface OnFocusChangeListener { 27550 /** 27551 * Called when the focus state of a view has changed. 27552 * 27553 * @param v The view whose state has changed. 27554 * @param hasFocus The new focus state of v. 27555 */ onFocusChange(View v, boolean hasFocus)27556 void onFocusChange(View v, boolean hasFocus); 27557 } 27558 27559 /** 27560 * Interface definition for a callback to be invoked when a view is clicked. 27561 */ 27562 public interface OnClickListener { 27563 /** 27564 * Called when a view has been clicked. 27565 * 27566 * @param v The view that was clicked. 27567 */ onClick(View v)27568 void onClick(View v); 27569 } 27570 27571 /** 27572 * Interface definition for a callback to be invoked when a view is context clicked. 27573 */ 27574 public interface OnContextClickListener { 27575 /** 27576 * Called when a view is context clicked. 27577 * 27578 * @param v The view that has been context clicked. 27579 * @return true if the callback consumed the context click, false otherwise. 27580 */ onContextClick(View v)27581 boolean onContextClick(View v); 27582 } 27583 27584 /** 27585 * Interface definition for a callback to be invoked when the context menu 27586 * for this view is being built. 27587 */ 27588 public interface OnCreateContextMenuListener { 27589 /** 27590 * Called when the context menu for this view is being built. It is not 27591 * safe to hold onto the menu after this method returns. 27592 * 27593 * @param menu The context menu that is being built 27594 * @param v The view for which the context menu is being built 27595 * @param menuInfo Extra information about the item for which the 27596 * context menu should be shown. This information will vary 27597 * depending on the class of v. 27598 */ onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)27599 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 27600 } 27601 27602 /** 27603 * Interface definition for a callback to be invoked when the status bar changes 27604 * visibility. This reports <strong>global</strong> changes to the system UI 27605 * state, not what the application is requesting. 27606 * 27607 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 27608 */ 27609 public interface OnSystemUiVisibilityChangeListener { 27610 /** 27611 * Called when the status bar changes visibility because of a call to 27612 * {@link View#setSystemUiVisibility(int)}. 27613 * 27614 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 27615 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 27616 * This tells you the <strong>global</strong> state of these UI visibility 27617 * flags, not what your app is currently applying. 27618 */ onSystemUiVisibilityChange(int visibility)27619 public void onSystemUiVisibilityChange(int visibility); 27620 } 27621 27622 /** 27623 * Interface definition for a callback to be invoked when this view is attached 27624 * or detached from its window. 27625 */ 27626 public interface OnAttachStateChangeListener { 27627 /** 27628 * Called when the view is attached to a window. 27629 * @param v The view that was attached 27630 */ onViewAttachedToWindow(View v)27631 public void onViewAttachedToWindow(View v); 27632 /** 27633 * Called when the view is detached from a window. 27634 * @param v The view that was detached 27635 */ onViewDetachedFromWindow(View v)27636 public void onViewDetachedFromWindow(View v); 27637 } 27638 27639 /** 27640 * Listener for applying window insets on a view in a custom way. 27641 * 27642 * <p>Apps may choose to implement this interface if they want to apply custom policy 27643 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 27644 * is set, its 27645 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 27646 * method will be called instead of the View's own 27647 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 27648 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 27649 * the View's normal behavior as part of its own.</p> 27650 */ 27651 public interface OnApplyWindowInsetsListener { 27652 /** 27653 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 27654 * on a View, this listener method will be called instead of the view's own 27655 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 27656 * 27657 * @param v The view applying window insets 27658 * @param insets The insets to apply 27659 * @return The insets supplied, minus any insets that were consumed 27660 */ onApplyWindowInsets(View v, WindowInsets insets)27661 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 27662 } 27663 27664 private final class UnsetPressedState implements Runnable { 27665 @Override run()27666 public void run() { 27667 setPressed(false); 27668 } 27669 } 27670 27671 /** 27672 * When a view becomes invisible checks if autofill considers the view invisible too. This 27673 * happens after the regular removal operation to make sure the operation is finished by the 27674 * time this is called. 27675 */ 27676 private static class VisibilityChangeForAutofillHandler extends Handler { 27677 private final AutofillManager mAfm; 27678 private final View mView; 27679 VisibilityChangeForAutofillHandler(@onNull AutofillManager afm, @NonNull View view)27680 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, 27681 @NonNull View view) { 27682 mAfm = afm; 27683 mView = view; 27684 } 27685 27686 @Override handleMessage(Message msg)27687 public void handleMessage(Message msg) { 27688 mAfm.notifyViewVisibilityChanged(mView, mView.isShown()); 27689 } 27690 } 27691 27692 /** 27693 * Base class for derived classes that want to save and restore their own 27694 * state in {@link android.view.View#onSaveInstanceState()}. 27695 */ 27696 public static class BaseSavedState extends AbsSavedState { 27697 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; 27698 static final int IS_AUTOFILLED = 0b10; 27699 static final int AUTOFILL_ID = 0b100; 27700 27701 // Flags that describe what data in this state is valid 27702 int mSavedData; 27703 String mStartActivityRequestWhoSaved; 27704 boolean mIsAutofilled; 27705 int mAutofillViewId; 27706 27707 /** 27708 * Constructor used when reading from a parcel. Reads the state of the superclass. 27709 * 27710 * @param source parcel to read from 27711 */ BaseSavedState(Parcel source)27712 public BaseSavedState(Parcel source) { 27713 this(source, null); 27714 } 27715 27716 /** 27717 * Constructor used when reading from a parcel using a given class loader. 27718 * Reads the state of the superclass. 27719 * 27720 * @param source parcel to read from 27721 * @param loader ClassLoader to use for reading 27722 */ BaseSavedState(Parcel source, ClassLoader loader)27723 public BaseSavedState(Parcel source, ClassLoader loader) { 27724 super(source, loader); 27725 mSavedData = source.readInt(); 27726 mStartActivityRequestWhoSaved = source.readString(); 27727 mIsAutofilled = source.readBoolean(); 27728 mAutofillViewId = source.readInt(); 27729 } 27730 27731 /** 27732 * Constructor called by derived classes when creating their SavedState objects 27733 * 27734 * @param superState The state of the superclass of this view 27735 */ BaseSavedState(Parcelable superState)27736 public BaseSavedState(Parcelable superState) { 27737 super(superState); 27738 } 27739 27740 @Override writeToParcel(Parcel out, int flags)27741 public void writeToParcel(Parcel out, int flags) { 27742 super.writeToParcel(out, flags); 27743 27744 out.writeInt(mSavedData); 27745 out.writeString(mStartActivityRequestWhoSaved); 27746 out.writeBoolean(mIsAutofilled); 27747 out.writeInt(mAutofillViewId); 27748 } 27749 27750 public static final @android.annotation.NonNull Parcelable.Creator<BaseSavedState> CREATOR 27751 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 27752 @Override 27753 public BaseSavedState createFromParcel(Parcel in) { 27754 return new BaseSavedState(in); 27755 } 27756 27757 @Override 27758 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 27759 return new BaseSavedState(in, loader); 27760 } 27761 27762 @Override 27763 public BaseSavedState[] newArray(int size) { 27764 return new BaseSavedState[size]; 27765 } 27766 }; 27767 } 27768 27769 /** 27770 * A set of information given to a view when it is attached to its parent 27771 * window. 27772 */ 27773 final static class AttachInfo { 27774 interface Callbacks { playSoundEffect(int effectId)27775 void playSoundEffect(int effectId); performHapticFeedback(int effectId, boolean always)27776 boolean performHapticFeedback(int effectId, boolean always); 27777 } 27778 27779 /** 27780 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 27781 * to a Handler. This class contains the target (View) to invalidate and 27782 * the coordinates of the dirty rectangle. 27783 * 27784 * For performance purposes, this class also implements a pool of up to 27785 * POOL_LIMIT objects that get reused. This reduces memory allocations 27786 * whenever possible. 27787 */ 27788 static class InvalidateInfo { 27789 private static final int POOL_LIMIT = 10; 27790 27791 private static final SynchronizedPool<InvalidateInfo> sPool = 27792 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 27793 27794 @UnsupportedAppUsage 27795 View target; 27796 27797 @UnsupportedAppUsage 27798 int left; 27799 @UnsupportedAppUsage 27800 int top; 27801 @UnsupportedAppUsage 27802 int right; 27803 @UnsupportedAppUsage 27804 int bottom; 27805 obtain()27806 public static InvalidateInfo obtain() { 27807 InvalidateInfo instance = sPool.acquire(); 27808 return (instance != null) ? instance : new InvalidateInfo(); 27809 } 27810 recycle()27811 public void recycle() { 27812 target = null; 27813 sPool.release(this); 27814 } 27815 } 27816 27817 @UnsupportedAppUsage 27818 final IWindowSession mSession; 27819 27820 @UnsupportedAppUsage 27821 final IWindow mWindow; 27822 27823 final IBinder mWindowToken; 27824 27825 Display mDisplay; 27826 27827 final Callbacks mRootCallbacks; 27828 27829 IWindowId mIWindowId; 27830 WindowId mWindowId; 27831 27832 /** 27833 * The top view of the hierarchy. 27834 */ 27835 View mRootView; 27836 27837 IBinder mPanelParentWindowToken; 27838 27839 boolean mHardwareAccelerated; 27840 boolean mHardwareAccelerationRequested; 27841 ThreadedRenderer mThreadedRenderer; 27842 List<RenderNode> mPendingAnimatingRenderNodes; 27843 27844 /** 27845 * The state of the display to which the window is attached, as reported 27846 * by {@link Display#getState()}. Note that the display state constants 27847 * declared by {@link Display} do not exactly line up with the screen state 27848 * constants declared by {@link View} (there are more display states than 27849 * screen states). 27850 */ 27851 @UnsupportedAppUsage 27852 int mDisplayState = Display.STATE_UNKNOWN; 27853 27854 /** 27855 * Scale factor used by the compatibility mode 27856 */ 27857 @UnsupportedAppUsage 27858 float mApplicationScale; 27859 27860 /** 27861 * Indicates whether the application is in compatibility mode 27862 */ 27863 @UnsupportedAppUsage 27864 boolean mScalingRequired; 27865 27866 /** 27867 * Left position of this view's window 27868 */ 27869 int mWindowLeft; 27870 27871 /** 27872 * Top position of this view's window 27873 */ 27874 int mWindowTop; 27875 27876 /** 27877 * Indicates whether views need to use 32-bit drawing caches 27878 */ 27879 boolean mUse32BitDrawingCache; 27880 27881 /** 27882 * For windows that are full-screen but using insets to layout inside 27883 * of the screen areas, these are the current insets to appear inside 27884 * the overscan area of the display. 27885 */ 27886 final Rect mOverscanInsets = new Rect(); 27887 27888 /** 27889 * For windows that are full-screen but using insets to layout inside 27890 * of the screen decorations, these are the current insets for the 27891 * content of the window. 27892 */ 27893 @UnsupportedAppUsage 27894 final Rect mContentInsets = new Rect(); 27895 27896 /** 27897 * For windows that are full-screen but using insets to layout inside 27898 * of the screen decorations, these are the current insets for the 27899 * actual visible parts of the window. 27900 */ 27901 @UnsupportedAppUsage 27902 final Rect mVisibleInsets = new Rect(); 27903 27904 /** 27905 * For windows that are full-screen but using insets to layout inside 27906 * of the screen decorations, these are the current insets for the 27907 * stable system windows. 27908 */ 27909 @UnsupportedAppUsage 27910 final Rect mStableInsets = new Rect(); 27911 27912 final DisplayCutout.ParcelableWrapper mDisplayCutout = 27913 new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT); 27914 27915 /** 27916 * For windows that include areas that are not covered by real surface these are the outsets 27917 * for real surface. 27918 */ 27919 final Rect mOutsets = new Rect(); 27920 27921 /** 27922 * In multi-window we force show the system bars. Because we don't want that the surface 27923 * size changes in this mode, we instead have a flag whether the system bars sizes should 27924 * always be consumed, so the app is treated like there are no virtual system bars at all. 27925 */ 27926 boolean mAlwaysConsumeSystemBars; 27927 27928 /** 27929 * The internal insets given by this window. This value is 27930 * supplied by the client (through 27931 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 27932 * be given to the window manager when changed to be used in laying 27933 * out windows behind it. 27934 */ 27935 @UnsupportedAppUsage 27936 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 27937 = new ViewTreeObserver.InternalInsetsInfo(); 27938 27939 /** 27940 * Set to true when mGivenInternalInsets is non-empty. 27941 */ 27942 boolean mHasNonEmptyGivenInternalInsets; 27943 27944 /** 27945 * All views in the window's hierarchy that serve as scroll containers, 27946 * used to determine if the window can be resized or must be panned 27947 * to adjust for a soft input area. 27948 */ 27949 @UnsupportedAppUsage 27950 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 27951 27952 @UnsupportedAppUsage 27953 final KeyEvent.DispatcherState mKeyDispatchState 27954 = new KeyEvent.DispatcherState(); 27955 27956 /** 27957 * Indicates whether the view's window currently has the focus. 27958 */ 27959 @UnsupportedAppUsage 27960 boolean mHasWindowFocus; 27961 27962 /** 27963 * The current visibility of the window. 27964 */ 27965 int mWindowVisibility; 27966 27967 /** 27968 * Indicates the time at which drawing started to occur. 27969 */ 27970 @UnsupportedAppUsage 27971 long mDrawingTime; 27972 27973 /** 27974 * Indicates whether the view's window is currently in touch mode. 27975 */ 27976 @UnsupportedAppUsage 27977 boolean mInTouchMode; 27978 27979 /** 27980 * Indicates whether the view has requested unbuffered input dispatching for the current 27981 * event stream. 27982 */ 27983 boolean mUnbufferedDispatchRequested; 27984 27985 /** 27986 * Indicates that ViewAncestor should trigger a global layout change 27987 * the next time it performs a traversal 27988 */ 27989 @UnsupportedAppUsage 27990 boolean mRecomputeGlobalAttributes; 27991 27992 /** 27993 * Always report new attributes at next traversal. 27994 */ 27995 boolean mForceReportNewAttributes; 27996 27997 /** 27998 * Set during a traveral if any views want to keep the screen on. 27999 */ 28000 @UnsupportedAppUsage 28001 boolean mKeepScreenOn; 28002 28003 /** 28004 * Set during a traveral if the light center needs to be updated. 28005 */ 28006 boolean mNeedsUpdateLightCenter; 28007 28008 /** 28009 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 28010 */ 28011 int mSystemUiVisibility; 28012 28013 /** 28014 * Hack to force certain system UI visibility flags to be cleared. 28015 */ 28016 int mDisabledSystemUiVisibility; 28017 28018 /** 28019 * Last global system UI visibility reported by the window manager. 28020 */ 28021 int mGlobalSystemUiVisibility = -1; 28022 28023 /** 28024 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 28025 * attached. 28026 */ 28027 boolean mHasSystemUiListeners; 28028 28029 /** 28030 * Set if the window has requested to extend into the overscan region 28031 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 28032 */ 28033 boolean mOverscanRequested; 28034 28035 /** 28036 * Set if the visibility of any views has changed. 28037 */ 28038 @UnsupportedAppUsage 28039 boolean mViewVisibilityChanged; 28040 28041 /** 28042 * Set to true if a view has been scrolled. 28043 */ 28044 @UnsupportedAppUsage 28045 boolean mViewScrollChanged; 28046 28047 /** 28048 * Set to true if a pointer event is currently being handled. 28049 */ 28050 boolean mHandlingPointerEvent; 28051 28052 /** 28053 * Global to the view hierarchy used as a temporary for dealing with 28054 * x/y points in the transparent region computations. 28055 */ 28056 final int[] mTransparentLocation = new int[2]; 28057 28058 /** 28059 * Global to the view hierarchy used as a temporary for dealing with 28060 * x/y points in the ViewGroup.invalidateChild implementation. 28061 */ 28062 final int[] mInvalidateChildLocation = new int[2]; 28063 28064 /** 28065 * Global to the view hierarchy used as a temporary for dealing with 28066 * computing absolute on-screen location. 28067 */ 28068 final int[] mTmpLocation = new int[2]; 28069 28070 /** 28071 * Global to the view hierarchy used as a temporary for dealing with 28072 * x/y location when view is transformed. 28073 */ 28074 final float[] mTmpTransformLocation = new float[2]; 28075 28076 /** 28077 * The view tree observer used to dispatch global events like 28078 * layout, pre-draw, touch mode change, etc. 28079 */ 28080 @UnsupportedAppUsage 28081 final ViewTreeObserver mTreeObserver; 28082 28083 /** 28084 * A Canvas used by the view hierarchy to perform bitmap caching. 28085 */ 28086 Canvas mCanvas; 28087 28088 /** 28089 * The view root impl. 28090 */ 28091 final ViewRootImpl mViewRootImpl; 28092 28093 /** 28094 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 28095 * handler can be used to pump events in the UI events queue. 28096 */ 28097 @UnsupportedAppUsage 28098 final Handler mHandler; 28099 28100 /** 28101 * Temporary for use in computing invalidate rectangles while 28102 * calling up the hierarchy. 28103 */ 28104 final Rect mTmpInvalRect = new Rect(); 28105 28106 /** 28107 * Temporary for use in computing hit areas with transformed views 28108 */ 28109 final RectF mTmpTransformRect = new RectF(); 28110 28111 /** 28112 * Temporary for use in computing hit areas with transformed views 28113 */ 28114 final RectF mTmpTransformRect1 = new RectF(); 28115 28116 /** 28117 * Temporary list of rectanges. 28118 */ 28119 final List<RectF> mTmpRectList = new ArrayList<>(); 28120 28121 /** 28122 * Temporary for use in transforming invalidation rect 28123 */ 28124 final Matrix mTmpMatrix = new Matrix(); 28125 28126 /** 28127 * Temporary for use in transforming invalidation rect 28128 */ 28129 final Transformation mTmpTransformation = new Transformation(); 28130 28131 /** 28132 * Temporary for use in querying outlines from OutlineProviders 28133 */ 28134 final Outline mTmpOutline = new Outline(); 28135 28136 /** 28137 * Temporary list for use in collecting focusable descendents of a view. 28138 */ 28139 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 28140 28141 /** 28142 * The id of the window for accessibility purposes. 28143 */ 28144 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 28145 28146 /** 28147 * Flags related to accessibility processing. 28148 * 28149 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 28150 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 28151 */ 28152 int mAccessibilityFetchFlags; 28153 28154 /** 28155 * The drawable for highlighting accessibility focus. 28156 */ 28157 Drawable mAccessibilityFocusDrawable; 28158 28159 /** 28160 * The drawable for highlighting autofilled views. 28161 * 28162 * @see #isAutofilled() 28163 */ 28164 Drawable mAutofilledDrawable; 28165 28166 /** 28167 * Show where the margins, bounds and layout bounds are for each view. 28168 */ 28169 boolean mDebugLayout = DisplayProperties.debug_layout().orElse(false); 28170 28171 /** 28172 * Point used to compute visible regions. 28173 */ 28174 final Point mPoint = new Point(); 28175 28176 /** 28177 * Used to track which View originated a requestLayout() call, used when 28178 * requestLayout() is called during layout. 28179 */ 28180 View mViewRequestingLayout; 28181 28182 /** 28183 * Used to track the identity of the current drag operation. 28184 */ 28185 IBinder mDragToken; 28186 28187 /** 28188 * The drag shadow surface for the current drag operation. 28189 */ 28190 public Surface mDragSurface; 28191 28192 28193 /** 28194 * The view that currently has a tooltip displayed. 28195 */ 28196 View mTooltipHost; 28197 28198 /** 28199 * Creates a new set of attachment information with the specified 28200 * events handler and thread. 28201 * 28202 * @param handler the events handler the view must use 28203 */ AttachInfo(IWindowSession session, IWindow window, Display display, ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, Context context)28204 AttachInfo(IWindowSession session, IWindow window, Display display, 28205 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 28206 Context context) { 28207 mSession = session; 28208 mWindow = window; 28209 mWindowToken = window.asBinder(); 28210 mDisplay = display; 28211 mViewRootImpl = viewRootImpl; 28212 mHandler = handler; 28213 mRootCallbacks = effectPlayer; 28214 mTreeObserver = new ViewTreeObserver(context); 28215 } 28216 } 28217 28218 /** 28219 * <p>ScrollabilityCache holds various fields used by a View when scrolling 28220 * is supported. This avoids keeping too many unused fields in most 28221 * instances of View.</p> 28222 */ 28223 private static class ScrollabilityCache implements Runnable { 28224 28225 /** 28226 * Scrollbars are not visible 28227 */ 28228 public static final int OFF = 0; 28229 28230 /** 28231 * Scrollbars are visible 28232 */ 28233 public static final int ON = 1; 28234 28235 /** 28236 * Scrollbars are fading away 28237 */ 28238 public static final int FADING = 2; 28239 28240 public boolean fadeScrollBars; 28241 28242 public int fadingEdgeLength; 28243 public int scrollBarDefaultDelayBeforeFade; 28244 public int scrollBarFadeDuration; 28245 28246 public int scrollBarSize; 28247 public int scrollBarMinTouchTarget; 28248 @UnsupportedAppUsage 28249 public ScrollBarDrawable scrollBar; 28250 public float[] interpolatorValues; 28251 @UnsupportedAppUsage 28252 public View host; 28253 28254 public final Paint paint; 28255 public final Matrix matrix; 28256 public Shader shader; 28257 28258 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 28259 28260 private static final float[] OPAQUE = { 255 }; 28261 private static final float[] TRANSPARENT = { 0.0f }; 28262 28263 /** 28264 * When fading should start. This time moves into the future every time 28265 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 28266 */ 28267 public long fadeStartTime; 28268 28269 28270 /** 28271 * The current state of the scrollbars: ON, OFF, or FADING 28272 */ 28273 @UnsupportedAppUsage 28274 public int state = OFF; 28275 28276 private int mLastColor; 28277 28278 public final Rect mScrollBarBounds = new Rect(); 28279 public final Rect mScrollBarTouchBounds = new Rect(); 28280 28281 public static final int NOT_DRAGGING = 0; 28282 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 28283 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 28284 public int mScrollBarDraggingState = NOT_DRAGGING; 28285 28286 public float mScrollBarDraggingPos = 0; 28287 ScrollabilityCache(ViewConfiguration configuration, View host)28288 public ScrollabilityCache(ViewConfiguration configuration, View host) { 28289 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 28290 scrollBarSize = configuration.getScaledScrollBarSize(); 28291 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 28292 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 28293 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 28294 28295 paint = new Paint(); 28296 matrix = new Matrix(); 28297 // use use a height of 1, and then wack the matrix each time we 28298 // actually use it. 28299 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 28300 paint.setShader(shader); 28301 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 28302 28303 this.host = host; 28304 } 28305 setFadeColor(int color)28306 public void setFadeColor(int color) { 28307 if (color != mLastColor) { 28308 mLastColor = color; 28309 28310 if (color != 0) { 28311 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 28312 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 28313 paint.setShader(shader); 28314 // Restore the default transfer mode (src_over) 28315 paint.setXfermode(null); 28316 } else { 28317 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 28318 paint.setShader(shader); 28319 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 28320 } 28321 } 28322 } 28323 run()28324 public void run() { 28325 long now = AnimationUtils.currentAnimationTimeMillis(); 28326 if (now >= fadeStartTime) { 28327 28328 // the animation fades the scrollbars out by changing 28329 // the opacity (alpha) from fully opaque to fully 28330 // transparent 28331 int nextFrame = (int) now; 28332 int framesCount = 0; 28333 28334 Interpolator interpolator = scrollBarInterpolator; 28335 28336 // Start opaque 28337 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 28338 28339 // End transparent 28340 nextFrame += scrollBarFadeDuration; 28341 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 28342 28343 state = FADING; 28344 28345 // Kick off the fade animation 28346 host.invalidate(true); 28347 } 28348 } 28349 } 28350 28351 /** 28352 * Resuable callback for sending 28353 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 28354 */ 28355 private class SendViewScrolledAccessibilityEvent implements Runnable { 28356 public volatile boolean mIsPending; 28357 public int mDeltaX; 28358 public int mDeltaY; 28359 post(int dx, int dy)28360 public void post(int dx, int dy) { 28361 mDeltaX += dx; 28362 mDeltaY += dy; 28363 if (!mIsPending) { 28364 mIsPending = true; 28365 postDelayed(this, ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 28366 } 28367 } 28368 28369 @Override run()28370 public void run() { 28371 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 28372 AccessibilityEvent event = AccessibilityEvent.obtain( 28373 AccessibilityEvent.TYPE_VIEW_SCROLLED); 28374 event.setScrollDeltaX(mDeltaX); 28375 event.setScrollDeltaY(mDeltaY); 28376 sendAccessibilityEventUnchecked(event); 28377 } 28378 reset(); 28379 } 28380 reset()28381 private void reset() { 28382 mIsPending = false; 28383 mDeltaX = 0; 28384 mDeltaY = 0; 28385 } 28386 } 28387 28388 /** 28389 * Remove the pending callback for sending a 28390 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 28391 */ 28392 @UnsupportedAppUsage cancel(@ullable SendViewScrolledAccessibilityEvent callback)28393 private void cancel(@Nullable SendViewScrolledAccessibilityEvent callback) { 28394 if (callback == null || !callback.mIsPending) return; 28395 removeCallbacks(callback); 28396 callback.reset(); 28397 } 28398 28399 /** 28400 * <p> 28401 * This class represents a delegate that can be registered in a {@link View} 28402 * to enhance accessibility support via composition rather via inheritance. 28403 * It is specifically targeted to widget developers that extend basic View 28404 * classes i.e. classes in package android.view, that would like their 28405 * applications to be backwards compatible. 28406 * </p> 28407 * <div class="special reference"> 28408 * <h3>Developer Guides</h3> 28409 * <p>For more information about making applications accessible, read the 28410 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 28411 * developer guide.</p> 28412 * </div> 28413 * <p> 28414 * A scenario in which a developer would like to use an accessibility delegate 28415 * is overriding a method introduced in a later API version than the minimal API 28416 * version supported by the application. For example, the method 28417 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 28418 * in API version 4 when the accessibility APIs were first introduced. If a 28419 * developer would like their application to run on API version 4 devices (assuming 28420 * all other APIs used by the application are version 4 or lower) and take advantage 28421 * of this method, instead of overriding the method which would break the application's 28422 * backwards compatibility, they can override the corresponding method in this 28423 * delegate and register the delegate in the target View if the API version of 28424 * the system is high enough, i.e. the API version is the same as or higher than the API 28425 * version that introduced 28426 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 28427 * </p> 28428 * <p> 28429 * Here is an example implementation: 28430 * </p> 28431 * <code><pre><p> 28432 * if (Build.VERSION.SDK_INT >= 14) { 28433 * // If the API version is equal of higher than the version in 28434 * // which onInitializeAccessibilityNodeInfo was introduced we 28435 * // register a delegate with a customized implementation. 28436 * View view = findViewById(R.id.view_id); 28437 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 28438 * public void onInitializeAccessibilityNodeInfo(View host, 28439 * AccessibilityNodeInfo info) { 28440 * // Let the default implementation populate the info. 28441 * super.onInitializeAccessibilityNodeInfo(host, info); 28442 * // Set some other information. 28443 * info.setEnabled(host.isEnabled()); 28444 * } 28445 * }); 28446 * } 28447 * </code></pre></p> 28448 * <p> 28449 * This delegate contains methods that correspond to the accessibility methods 28450 * in View. If a delegate has been specified the implementation in View hands 28451 * off handling to the corresponding method in this delegate. The default 28452 * implementation the delegate methods behaves exactly as the corresponding 28453 * method in View for the case of no accessibility delegate been set. Hence, 28454 * to customize the behavior of a View method, clients can override only the 28455 * corresponding delegate method without altering the behavior of the rest 28456 * accessibility related methods of the host view. 28457 * </p> 28458 * <p> 28459 * <strong>Note:</strong> On platform versions prior to 28460 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 28461 * views in the {@code android.widget.*} package are called <i>before</i> 28462 * host methods. This prevents certain properties such as class name from 28463 * being modified by overriding 28464 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 28465 * as any changes will be overwritten by the host class. 28466 * <p> 28467 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 28468 * methods are called <i>after</i> host methods, which all properties to be 28469 * modified without being overwritten by the host class. 28470 */ 28471 public static class AccessibilityDelegate { 28472 28473 /** 28474 * Sends an accessibility event of the given type. If accessibility is not 28475 * enabled this method has no effect. 28476 * <p> 28477 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 28478 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 28479 * been set. 28480 * </p> 28481 * 28482 * @param host The View hosting the delegate. 28483 * @param eventType The type of the event to send. 28484 * 28485 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 28486 */ sendAccessibilityEvent(View host, int eventType)28487 public void sendAccessibilityEvent(View host, int eventType) { 28488 host.sendAccessibilityEventInternal(eventType); 28489 } 28490 28491 /** 28492 * Performs the specified accessibility action on the view. For 28493 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 28494 * <p> 28495 * The default implementation behaves as 28496 * {@link View#performAccessibilityAction(int, Bundle) 28497 * View#performAccessibilityAction(int, Bundle)} for the case of 28498 * no accessibility delegate been set. 28499 * </p> 28500 * 28501 * @param action The action to perform. 28502 * @return Whether the action was performed. 28503 * 28504 * @see View#performAccessibilityAction(int, Bundle) 28505 * View#performAccessibilityAction(int, Bundle) 28506 */ performAccessibilityAction(View host, int action, Bundle args)28507 public boolean performAccessibilityAction(View host, int action, Bundle args) { 28508 return host.performAccessibilityActionInternal(action, args); 28509 } 28510 28511 /** 28512 * Sends an accessibility event. This method behaves exactly as 28513 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 28514 * empty {@link AccessibilityEvent} and does not perform a check whether 28515 * accessibility is enabled. 28516 * <p> 28517 * The default implementation behaves as 28518 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 28519 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 28520 * the case of no accessibility delegate been set. 28521 * </p> 28522 * 28523 * @param host The View hosting the delegate. 28524 * @param event The event to send. 28525 * 28526 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 28527 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 28528 */ sendAccessibilityEventUnchecked(View host, AccessibilityEvent event)28529 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 28530 host.sendAccessibilityEventUncheckedInternal(event); 28531 } 28532 28533 /** 28534 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 28535 * to its children for adding their text content to the event. 28536 * <p> 28537 * The default implementation behaves as 28538 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 28539 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 28540 * the case of no accessibility delegate been set. 28541 * </p> 28542 * 28543 * @param host The View hosting the delegate. 28544 * @param event The event. 28545 * @return True if the event population was completed. 28546 * 28547 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 28548 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 28549 */ dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event)28550 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 28551 return host.dispatchPopulateAccessibilityEventInternal(event); 28552 } 28553 28554 /** 28555 * Gives a chance to the host View to populate the accessibility event with its 28556 * text content. 28557 * <p> 28558 * The default implementation behaves as 28559 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 28560 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 28561 * the case of no accessibility delegate been set. 28562 * </p> 28563 * 28564 * @param host The View hosting the delegate. 28565 * @param event The accessibility event which to populate. 28566 * 28567 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 28568 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 28569 */ onPopulateAccessibilityEvent(View host, AccessibilityEvent event)28570 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 28571 host.onPopulateAccessibilityEventInternal(event); 28572 } 28573 28574 /** 28575 * Initializes an {@link AccessibilityEvent} with information about the 28576 * the host View which is the event source. 28577 * <p> 28578 * The default implementation behaves as 28579 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 28580 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 28581 * the case of no accessibility delegate been set. 28582 * </p> 28583 * 28584 * @param host The View hosting the delegate. 28585 * @param event The event to initialize. 28586 * 28587 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 28588 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 28589 */ onInitializeAccessibilityEvent(View host, AccessibilityEvent event)28590 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 28591 host.onInitializeAccessibilityEventInternal(event); 28592 } 28593 28594 /** 28595 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 28596 * <p> 28597 * The default implementation behaves as 28598 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 28599 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 28600 * the case of no accessibility delegate been set. 28601 * </p> 28602 * 28603 * @param host The View hosting the delegate. 28604 * @param info The instance to initialize. 28605 * 28606 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 28607 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 28608 */ onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info)28609 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 28610 host.onInitializeAccessibilityNodeInfoInternal(info); 28611 } 28612 28613 /** 28614 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 28615 * additional data. 28616 * <p> 28617 * This method only needs to be implemented if the View offers to provide additional data. 28618 * </p> 28619 * <p> 28620 * The default implementation behaves as 28621 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle) 28622 * for the case where no accessibility delegate is set. 28623 * </p> 28624 * 28625 * @param host The View hosting the delegate. Never {@code null}. 28626 * @param info The info to which to add the extra data. Never {@code null}. 28627 * @param extraDataKey A key specifying the type of extra data to add to the info. The 28628 * extra data should be added to the {@link Bundle} returned by 28629 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 28630 * {@code null}. 28631 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 28632 * May be {@code null} if the if the service provided no arguments. 28633 * 28634 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 28635 */ addExtraDataToAccessibilityNodeInfo(@onNull View host, @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, @Nullable Bundle arguments)28636 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 28637 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 28638 @Nullable Bundle arguments) { 28639 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 28640 } 28641 28642 /** 28643 * Called when a child of the host View has requested sending an 28644 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 28645 * to augment the event. 28646 * <p> 28647 * The default implementation behaves as 28648 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 28649 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 28650 * the case of no accessibility delegate been set. 28651 * </p> 28652 * 28653 * @param host The View hosting the delegate. 28654 * @param child The child which requests sending the event. 28655 * @param event The event to be sent. 28656 * @return True if the event should be sent 28657 * 28658 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 28659 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 28660 */ onRequestSendAccessibilityEvent(ViewGroup host, View child, AccessibilityEvent event)28661 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 28662 AccessibilityEvent event) { 28663 return host.onRequestSendAccessibilityEventInternal(child, event); 28664 } 28665 28666 /** 28667 * Gets the provider for managing a virtual view hierarchy rooted at this View 28668 * and reported to {@link android.accessibilityservice.AccessibilityService}s 28669 * that explore the window content. 28670 * <p> 28671 * The default implementation behaves as 28672 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 28673 * the case of no accessibility delegate been set. 28674 * </p> 28675 * 28676 * @return The provider. 28677 * 28678 * @see AccessibilityNodeProvider 28679 */ getAccessibilityNodeProvider(View host)28680 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 28681 return null; 28682 } 28683 28684 /** 28685 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 28686 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 28687 * This method is responsible for obtaining an accessibility node info from a 28688 * pool of reusable instances and calling 28689 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 28690 * view to initialize the former. 28691 * <p> 28692 * <strong>Note:</strong> The client is responsible for recycling the obtained 28693 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 28694 * creation. 28695 * </p> 28696 * <p> 28697 * The default implementation behaves as 28698 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 28699 * the case of no accessibility delegate been set. 28700 * </p> 28701 * @return A populated {@link AccessibilityNodeInfo}. 28702 * 28703 * @see AccessibilityNodeInfo 28704 * 28705 * @hide 28706 */ 28707 @UnsupportedAppUsage createAccessibilityNodeInfo(View host)28708 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 28709 return host.createAccessibilityNodeInfoInternal(); 28710 } 28711 } 28712 28713 private static class MatchIdPredicate implements Predicate<View> { 28714 public int mId; 28715 28716 @Override test(View view)28717 public boolean test(View view) { 28718 return (view.mID == mId); 28719 } 28720 } 28721 28722 private static class MatchLabelForPredicate implements Predicate<View> { 28723 private int mLabeledId; 28724 28725 @Override test(View view)28726 public boolean test(View view) { 28727 return (view.mLabelForId == mLabeledId); 28728 } 28729 } 28730 28731 /** 28732 * Dump all private flags in readable format, useful for documentation and 28733 * sanity checking. 28734 */ dumpFlags()28735 private static void dumpFlags() { 28736 final HashMap<String, String> found = Maps.newHashMap(); 28737 try { 28738 for (Field field : View.class.getDeclaredFields()) { 28739 final int modifiers = field.getModifiers(); 28740 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 28741 if (field.getType().equals(int.class)) { 28742 final int value = field.getInt(null); 28743 dumpFlag(found, field.getName(), value); 28744 } else if (field.getType().equals(int[].class)) { 28745 final int[] values = (int[]) field.get(null); 28746 for (int i = 0; i < values.length; i++) { 28747 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 28748 } 28749 } 28750 } 28751 } 28752 } catch (IllegalAccessException e) { 28753 throw new RuntimeException(e); 28754 } 28755 28756 final ArrayList<String> keys = Lists.newArrayList(); 28757 keys.addAll(found.keySet()); 28758 Collections.sort(keys); 28759 for (String key : keys) { 28760 Log.d(VIEW_LOG_TAG, found.get(key)); 28761 } 28762 } 28763 dumpFlag(HashMap<String, String> found, String name, int value)28764 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 28765 // Sort flags by prefix, then by bits, always keeping unique keys 28766 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 28767 final int prefix = name.indexOf('_'); 28768 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 28769 final String output = bits + " " + name; 28770 found.put(key, output); 28771 } 28772 28773 /** {@hide} */ encode(@onNull ViewHierarchyEncoder stream)28774 public void encode(@NonNull ViewHierarchyEncoder stream) { 28775 stream.beginObject(this); 28776 encodeProperties(stream); 28777 stream.endObject(); 28778 } 28779 28780 /** {@hide} */ 28781 @CallSuper encodeProperties(@onNull ViewHierarchyEncoder stream)28782 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 28783 Object resolveId = ViewDebug.resolveId(getContext(), mID); 28784 if (resolveId instanceof String) { 28785 stream.addProperty("id", (String) resolveId); 28786 } else { 28787 stream.addProperty("id", mID); 28788 } 28789 28790 stream.addProperty("misc:transformation.alpha", 28791 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 28792 stream.addProperty("misc:transitionName", getTransitionName()); 28793 28794 // layout 28795 stream.addProperty("layout:left", mLeft); 28796 stream.addProperty("layout:right", mRight); 28797 stream.addProperty("layout:top", mTop); 28798 stream.addProperty("layout:bottom", mBottom); 28799 stream.addProperty("layout:width", getWidth()); 28800 stream.addProperty("layout:height", getHeight()); 28801 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 28802 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 28803 stream.addProperty("layout:hasTransientState", hasTransientState()); 28804 stream.addProperty("layout:baseline", getBaseline()); 28805 28806 // layout params 28807 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 28808 if (layoutParams != null) { 28809 stream.addPropertyKey("layoutParams"); 28810 layoutParams.encode(stream); 28811 } 28812 28813 // scrolling 28814 stream.addProperty("scrolling:scrollX", mScrollX); 28815 stream.addProperty("scrolling:scrollY", mScrollY); 28816 28817 // padding 28818 stream.addProperty("padding:paddingLeft", mPaddingLeft); 28819 stream.addProperty("padding:paddingRight", mPaddingRight); 28820 stream.addProperty("padding:paddingTop", mPaddingTop); 28821 stream.addProperty("padding:paddingBottom", mPaddingBottom); 28822 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 28823 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 28824 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 28825 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 28826 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 28827 28828 // measurement 28829 stream.addProperty("measurement:minHeight", mMinHeight); 28830 stream.addProperty("measurement:minWidth", mMinWidth); 28831 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 28832 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 28833 28834 // drawing 28835 stream.addProperty("drawing:elevation", getElevation()); 28836 stream.addProperty("drawing:translationX", getTranslationX()); 28837 stream.addProperty("drawing:translationY", getTranslationY()); 28838 stream.addProperty("drawing:translationZ", getTranslationZ()); 28839 stream.addProperty("drawing:rotation", getRotation()); 28840 stream.addProperty("drawing:rotationX", getRotationX()); 28841 stream.addProperty("drawing:rotationY", getRotationY()); 28842 stream.addProperty("drawing:scaleX", getScaleX()); 28843 stream.addProperty("drawing:scaleY", getScaleY()); 28844 stream.addProperty("drawing:pivotX", getPivotX()); 28845 stream.addProperty("drawing:pivotY", getPivotY()); 28846 stream.addProperty("drawing:clipBounds", 28847 mClipBounds == null ? null : mClipBounds.toString()); 28848 stream.addProperty("drawing:opaque", isOpaque()); 28849 stream.addProperty("drawing:alpha", getAlpha()); 28850 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 28851 stream.addProperty("drawing:shadow", hasShadow()); 28852 stream.addProperty("drawing:solidColor", getSolidColor()); 28853 stream.addProperty("drawing:layerType", mLayerType); 28854 stream.addProperty("drawing:willNotDraw", willNotDraw()); 28855 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 28856 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 28857 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 28858 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 28859 stream.addProperty("drawing:outlineAmbientShadowColor", getOutlineAmbientShadowColor()); 28860 stream.addProperty("drawing:outlineSpotShadowColor", getOutlineSpotShadowColor()); 28861 28862 // focus 28863 stream.addProperty("focus:hasFocus", hasFocus()); 28864 stream.addProperty("focus:isFocused", isFocused()); 28865 stream.addProperty("focus:focusable", getFocusable()); 28866 stream.addProperty("focus:isFocusable", isFocusable()); 28867 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 28868 28869 stream.addProperty("misc:clickable", isClickable()); 28870 stream.addProperty("misc:pressed", isPressed()); 28871 stream.addProperty("misc:selected", isSelected()); 28872 stream.addProperty("misc:touchMode", isInTouchMode()); 28873 stream.addProperty("misc:hovered", isHovered()); 28874 stream.addProperty("misc:activated", isActivated()); 28875 28876 stream.addProperty("misc:visibility", getVisibility()); 28877 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 28878 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 28879 28880 stream.addProperty("misc:enabled", isEnabled()); 28881 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 28882 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 28883 28884 // theme attributes 28885 Resources.Theme theme = getContext().getTheme(); 28886 if (theme != null) { 28887 stream.addPropertyKey("theme"); 28888 theme.encode(stream); 28889 } 28890 28891 // view attribute information 28892 int n = mAttributes != null ? mAttributes.length : 0; 28893 stream.addProperty("meta:__attrCount__", n/2); 28894 for (int i = 0; i < n; i += 2) { 28895 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 28896 } 28897 28898 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 28899 28900 // text 28901 stream.addProperty("text:textDirection", getTextDirection()); 28902 stream.addProperty("text:textAlignment", getTextAlignment()); 28903 28904 // accessibility 28905 CharSequence contentDescription = getContentDescription(); 28906 stream.addProperty("accessibility:contentDescription", 28907 contentDescription == null ? "" : contentDescription.toString()); 28908 stream.addProperty("accessibility:labelFor", getLabelFor()); 28909 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 28910 } 28911 28912 /** 28913 * Determine if this view is rendered on a round wearable device and is the main view 28914 * on the screen. 28915 */ shouldDrawRoundScrollbar()28916 boolean shouldDrawRoundScrollbar() { 28917 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 28918 return false; 28919 } 28920 28921 final View rootView = getRootView(); 28922 final WindowInsets insets = getRootWindowInsets(); 28923 28924 int height = getHeight(); 28925 int width = getWidth(); 28926 int displayHeight = rootView.getHeight(); 28927 int displayWidth = rootView.getWidth(); 28928 28929 if (height != displayHeight || width != displayWidth) { 28930 return false; 28931 } 28932 28933 getLocationInWindow(mAttachInfo.mTmpLocation); 28934 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 28935 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 28936 } 28937 28938 /** 28939 * Sets the tooltip text which will be displayed in a small popup next to the view. 28940 * <p> 28941 * The tooltip will be displayed: 28942 * <ul> 28943 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context 28944 * menu). </li> 28945 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 28946 * </ul> 28947 * <p> 28948 * <strong>Note:</strong> Do not override this method, as it will have no 28949 * effect on the text displayed in the tooltip. 28950 * 28951 * @param tooltipText the tooltip text, or null if no tooltip is required 28952 * @see #getTooltipText() 28953 * @attr ref android.R.styleable#View_tooltipText 28954 */ setTooltipText(@ullable CharSequence tooltipText)28955 public void setTooltipText(@Nullable CharSequence tooltipText) { 28956 if (TextUtils.isEmpty(tooltipText)) { 28957 setFlags(0, TOOLTIP); 28958 hideTooltip(); 28959 mTooltipInfo = null; 28960 } else { 28961 setFlags(TOOLTIP, TOOLTIP); 28962 if (mTooltipInfo == null) { 28963 mTooltipInfo = new TooltipInfo(); 28964 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 28965 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 28966 mTooltipInfo.mHoverSlop = ViewConfiguration.get(mContext).getScaledHoverSlop(); 28967 mTooltipInfo.clearAnchorPos(); 28968 } 28969 mTooltipInfo.mTooltipText = tooltipText; 28970 } 28971 } 28972 28973 /** 28974 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 28975 */ 28976 @UnsupportedAppUsage setTooltip(@ullable CharSequence tooltipText)28977 public void setTooltip(@Nullable CharSequence tooltipText) { 28978 setTooltipText(tooltipText); 28979 } 28980 28981 /** 28982 * Returns the view's tooltip text. 28983 * 28984 * <strong>Note:</strong> Do not override this method, as it will have no 28985 * effect on the text displayed in the tooltip. You must call 28986 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 28987 * 28988 * @return the tooltip text 28989 * @see #setTooltipText(CharSequence) 28990 * @attr ref android.R.styleable#View_tooltipText 28991 */ 28992 @InspectableProperty 28993 @Nullable getTooltipText()28994 public CharSequence getTooltipText() { 28995 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 28996 } 28997 28998 /** 28999 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 29000 */ 29001 @Nullable getTooltip()29002 public CharSequence getTooltip() { 29003 return getTooltipText(); 29004 } 29005 showTooltip(int x, int y, boolean fromLongClick)29006 private boolean showTooltip(int x, int y, boolean fromLongClick) { 29007 if (mAttachInfo == null || mTooltipInfo == null) { 29008 return false; 29009 } 29010 if (fromLongClick && (mViewFlags & ENABLED_MASK) != ENABLED) { 29011 return false; 29012 } 29013 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 29014 return false; 29015 } 29016 hideTooltip(); 29017 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 29018 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 29019 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 29020 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 29021 mAttachInfo.mTooltipHost = this; 29022 // The available accessibility actions have changed 29023 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 29024 return true; 29025 } 29026 29027 @UnsupportedAppUsage hideTooltip()29028 void hideTooltip() { 29029 if (mTooltipInfo == null) { 29030 return; 29031 } 29032 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 29033 if (mTooltipInfo.mTooltipPopup == null) { 29034 return; 29035 } 29036 mTooltipInfo.mTooltipPopup.hide(); 29037 mTooltipInfo.mTooltipPopup = null; 29038 mTooltipInfo.mTooltipFromLongClick = false; 29039 mTooltipInfo.clearAnchorPos(); 29040 if (mAttachInfo != null) { 29041 mAttachInfo.mTooltipHost = null; 29042 } 29043 // The available accessibility actions have changed 29044 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 29045 } 29046 showLongClickTooltip(int x, int y)29047 private boolean showLongClickTooltip(int x, int y) { 29048 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 29049 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 29050 return showTooltip(x, y, true); 29051 } 29052 showHoverTooltip()29053 private boolean showHoverTooltip() { 29054 return showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 29055 } 29056 dispatchTooltipHoverEvent(MotionEvent event)29057 boolean dispatchTooltipHoverEvent(MotionEvent event) { 29058 if (mTooltipInfo == null) { 29059 return false; 29060 } 29061 switch(event.getAction()) { 29062 case MotionEvent.ACTION_HOVER_MOVE: 29063 if ((mViewFlags & TOOLTIP) != TOOLTIP) { 29064 break; 29065 } 29066 if (!mTooltipInfo.mTooltipFromLongClick && mTooltipInfo.updateAnchorPos(event)) { 29067 if (mTooltipInfo.mTooltipPopup == null) { 29068 // Schedule showing the tooltip after a timeout. 29069 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 29070 postDelayed(mTooltipInfo.mShowTooltipRunnable, 29071 ViewConfiguration.getHoverTooltipShowTimeout()); 29072 } 29073 29074 // Hide hover-triggered tooltip after a period of inactivity. 29075 // Match the timeout used by NativeInputManager to hide the mouse pointer 29076 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 29077 final int timeout; 29078 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 29079 == SYSTEM_UI_FLAG_LOW_PROFILE) { 29080 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 29081 } else { 29082 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 29083 } 29084 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 29085 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 29086 } 29087 return true; 29088 29089 case MotionEvent.ACTION_HOVER_EXIT: 29090 mTooltipInfo.clearAnchorPos(); 29091 if (!mTooltipInfo.mTooltipFromLongClick) { 29092 hideTooltip(); 29093 } 29094 break; 29095 } 29096 return false; 29097 } 29098 handleTooltipKey(KeyEvent event)29099 void handleTooltipKey(KeyEvent event) { 29100 switch (event.getAction()) { 29101 case KeyEvent.ACTION_DOWN: 29102 if (event.getRepeatCount() == 0) { 29103 hideTooltip(); 29104 } 29105 break; 29106 29107 case KeyEvent.ACTION_UP: 29108 handleTooltipUp(); 29109 break; 29110 } 29111 } 29112 handleTooltipUp()29113 private void handleTooltipUp() { 29114 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 29115 return; 29116 } 29117 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 29118 postDelayed(mTooltipInfo.mHideTooltipRunnable, 29119 ViewConfiguration.getLongPressTooltipHideTimeout()); 29120 } 29121 getFocusableAttribute(TypedArray attributes)29122 private int getFocusableAttribute(TypedArray attributes) { 29123 TypedValue val = new TypedValue(); 29124 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 29125 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 29126 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 29127 } else { 29128 return val.data; 29129 } 29130 } else { 29131 return FOCUSABLE_AUTO; 29132 } 29133 } 29134 29135 /** 29136 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 29137 * is not showing. 29138 * @hide 29139 */ 29140 @TestApi getTooltipView()29141 public View getTooltipView() { 29142 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 29143 return null; 29144 } 29145 return mTooltipInfo.mTooltipPopup.getContentView(); 29146 } 29147 29148 /** 29149 * @return {@code true} if the default focus highlight is enabled, {@code false} otherwies. 29150 * @hide 29151 */ 29152 @TestApi isDefaultFocusHighlightEnabled()29153 public static boolean isDefaultFocusHighlightEnabled() { 29154 return sUseDefaultFocusHighlight; 29155 } 29156 29157 /** 29158 * Dispatch a previously unhandled {@link KeyEvent} to this view. Unlike normal key dispatch, 29159 * this dispatches to ALL child views until it is consumed. The dispatch order is z-order 29160 * (visually on-top views first). 29161 * 29162 * @param evt the previously unhandled {@link KeyEvent}. 29163 * @return the {@link View} which consumed the event or {@code null} if not consumed. 29164 */ dispatchUnhandledKeyEvent(KeyEvent evt)29165 View dispatchUnhandledKeyEvent(KeyEvent evt) { 29166 if (onUnhandledKeyEvent(evt)) { 29167 return this; 29168 } 29169 return null; 29170 } 29171 29172 /** 29173 * Allows this view to handle {@link KeyEvent}s which weren't handled by normal dispatch. This 29174 * occurs after the normal view hierarchy dispatch, but before the window callback. By default, 29175 * this will dispatch into all the listeners registered via 29176 * {@link #addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener)} in last-in-first-out 29177 * order (most recently added will receive events first). 29178 * 29179 * @param event An unhandled event. 29180 * @return {@code true} if the event was handled, {@code false} otherwise. 29181 * @see #addOnUnhandledKeyEventListener 29182 */ onUnhandledKeyEvent(@onNull KeyEvent event)29183 boolean onUnhandledKeyEvent(@NonNull KeyEvent event) { 29184 if (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null) { 29185 for (int i = mListenerInfo.mUnhandledKeyListeners.size() - 1; i >= 0; --i) { 29186 if (mListenerInfo.mUnhandledKeyListeners.get(i).onUnhandledKeyEvent(this, event)) { 29187 return true; 29188 } 29189 } 29190 } 29191 return false; 29192 } 29193 hasUnhandledKeyListener()29194 boolean hasUnhandledKeyListener() { 29195 return (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null 29196 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()); 29197 } 29198 29199 /** 29200 * Adds a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 29201 * UI thread. 29202 * 29203 * @param listener a receiver of unhandled {@link KeyEvent}s. 29204 * @see #removeOnUnhandledKeyEventListener 29205 */ addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)29206 public void addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 29207 ArrayList<OnUnhandledKeyEventListener> listeners = getListenerInfo().mUnhandledKeyListeners; 29208 if (listeners == null) { 29209 listeners = new ArrayList<>(); 29210 getListenerInfo().mUnhandledKeyListeners = listeners; 29211 } 29212 listeners.add(listener); 29213 if (listeners.size() == 1 && mParent instanceof ViewGroup) { 29214 ((ViewGroup) mParent).incrementChildUnhandledKeyListeners(); 29215 } 29216 } 29217 29218 /** 29219 * Removes a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 29220 * UI thread. 29221 * 29222 * @param listener a receiver of unhandled {@link KeyEvent}s. 29223 * @see #addOnUnhandledKeyEventListener 29224 */ removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)29225 public void removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 29226 if (mListenerInfo != null) { 29227 if (mListenerInfo.mUnhandledKeyListeners != null 29228 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 29229 mListenerInfo.mUnhandledKeyListeners.remove(listener); 29230 if (mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 29231 mListenerInfo.mUnhandledKeyListeners = null; 29232 if (mParent instanceof ViewGroup) { 29233 ((ViewGroup) mParent).decrementChildUnhandledKeyListeners(); 29234 } 29235 } 29236 } 29237 } 29238 } 29239 } 29240