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.compat.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 it 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 1x1 surface instead. 946 */ 947 private static boolean sAcceptZeroSizeDragShadow; 948 949 /** 950 * Prior to Q, {@link #dispatchApplyWindowInsets} had some issues: 951 * <ul> 952 * <li>The modified insets changed by {@link #onApplyWindowInsets} were passed to the 953 * entire view hierarchy in prefix order, including siblings as well as siblings of parents 954 * further down the hierarchy. This violates the basic concepts of the view hierarchy, and 955 * thus, the hierarchical dispatching mechanism was hard to use for apps.</li> 956 * 957 * <li>Dispatch was stopped after the insets were fully consumed. This is somewhat confusing 958 * for developers, but more importantly, by adding more granular information to 959 * {@link WindowInsets} it becomes really cumbersome to define what consumed actually means 960 * </li> 961 * </ul> 962 * 963 * In order to make window inset dispatching work properly, we dispatch window insets 964 * in the view hierarchy in a proper hierarchical manner and don't stop dispatching if the 965 * insets are consumed if this flag is set to {@code false}. 966 */ 967 static boolean sBrokenInsetsDispatch; 968 969 /** 970 * Prior to Q, calling 971 * {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} 972 * did not call update the window format so the opacity of the background was not correctly 973 * applied to the window. Some applications rely on this misbehavior to work properly. 974 * <p> 975 * From Q, {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} is 976 * the same as {@link com.android.internal.policy.DecorView#setWindowBackground(Drawable)} 977 * which updates the window format. 978 * @hide 979 */ 980 protected static boolean sBrokenWindowBackground; 981 982 /** @hide */ 983 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 984 @Retention(RetentionPolicy.SOURCE) 985 public @interface Focusable {} 986 987 /** 988 * This view does not want keystrokes. 989 * <p> 990 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 991 * android:focusable}. 992 */ 993 public static final int NOT_FOCUSABLE = 0x00000000; 994 995 /** 996 * This view wants keystrokes. 997 * <p> 998 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 999 * android:focusable}. 1000 */ 1001 public static final int FOCUSABLE = 0x00000001; 1002 1003 /** 1004 * This view determines focusability automatically. This is the default. 1005 * <p> 1006 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1007 * android:focusable}. 1008 */ 1009 public static final int FOCUSABLE_AUTO = 0x00000010; 1010 1011 /** 1012 * Mask for use with setFlags indicating bits used for focus. 1013 */ 1014 private static final int FOCUSABLE_MASK = 0x00000011; 1015 1016 /** 1017 * This view will adjust its padding to fit sytem windows (e.g. status bar) 1018 */ 1019 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 1020 1021 /** @hide */ 1022 @IntDef({VISIBLE, INVISIBLE, GONE}) 1023 @Retention(RetentionPolicy.SOURCE) 1024 public @interface Visibility {} 1025 1026 /** 1027 * This view is visible. 1028 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1029 * android:visibility}. 1030 */ 1031 public static final int VISIBLE = 0x00000000; 1032 1033 /** 1034 * This view is invisible, but it still takes up space for layout purposes. 1035 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1036 * android:visibility}. 1037 */ 1038 public static final int INVISIBLE = 0x00000004; 1039 1040 /** 1041 * This view is invisible, and it doesn't take any space for layout 1042 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1043 * android:visibility}. 1044 */ 1045 public static final int GONE = 0x00000008; 1046 1047 /** 1048 * Mask for use with setFlags indicating bits used for visibility. 1049 * {@hide} 1050 */ 1051 static final int VISIBILITY_MASK = 0x0000000C; 1052 1053 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 1054 1055 /** 1056 * Hint indicating that this view can be autofilled with an email address. 1057 * 1058 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1059 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1060 * value should be <code>{@value #AUTOFILL_HINT_EMAIL_ADDRESS}</code>). 1061 * 1062 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1063 */ 1064 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 1065 1066 /** 1067 * Hint indicating that this view can be autofilled with a user's real name. 1068 * 1069 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1070 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1071 * value should be <code>{@value #AUTOFILL_HINT_NAME}</code>). 1072 * 1073 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1074 */ 1075 public static final String AUTOFILL_HINT_NAME = "name"; 1076 1077 /** 1078 * Hint indicating that this view can be autofilled with a username. 1079 * 1080 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1081 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1082 * value should be <code>{@value #AUTOFILL_HINT_USERNAME}</code>). 1083 * 1084 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1085 */ 1086 public static final String AUTOFILL_HINT_USERNAME = "username"; 1087 1088 /** 1089 * Hint indicating that this view can be autofilled with a password. 1090 * 1091 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1092 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1093 * value should be <code>{@value #AUTOFILL_HINT_PASSWORD}</code>). 1094 * 1095 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1096 */ 1097 public static final String AUTOFILL_HINT_PASSWORD = "password"; 1098 1099 /** 1100 * Hint indicating that this view can be autofilled with a phone number. 1101 * 1102 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1103 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1104 * value should be <code>{@value #AUTOFILL_HINT_PHONE}</code>). 1105 * 1106 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1107 */ 1108 public static final String AUTOFILL_HINT_PHONE = "phone"; 1109 1110 /** 1111 * Hint indicating that this view can be autofilled with a postal address. 1112 * 1113 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1114 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1115 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_ADDRESS}</code>). 1116 * 1117 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1118 */ 1119 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1120 1121 /** 1122 * Hint indicating that this view can be autofilled with a postal code. 1123 * 1124 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1125 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1126 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_CODE}</code>). 1127 * 1128 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1129 */ 1130 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1131 1132 /** 1133 * Hint indicating that this view can be autofilled with a credit card number. 1134 * 1135 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1136 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1137 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_NUMBER}</code>). 1138 * 1139 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1140 */ 1141 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1142 1143 /** 1144 * Hint indicating that this view can be autofilled with a credit card security code. 1145 * 1146 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1147 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1148 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}</code>). 1149 * 1150 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1151 */ 1152 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1153 1154 /** 1155 * Hint indicating that this view can be autofilled with a credit card expiration date. 1156 * 1157 * <p>It should be used when the credit card expiration date is represented by just one view; 1158 * if it is represented by more than one (for example, one view for the month and another view 1159 * for the year), then each of these views should use the hint specific for the unit 1160 * ({@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 1161 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 1162 * or {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}). 1163 * 1164 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1165 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1166 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}</code>). 1167 * 1168 * <p>When annotating a view with this hint, it's recommended to use a date autofill value to 1169 * avoid ambiguity when the autofill service provides a value for it. To understand why a 1170 * value can be ambiguous, consider "April of 2020", which could be represented as either of 1171 * the following options: 1172 * 1173 * <ul> 1174 * <li>{@code "04/2020"} 1175 * <li>{@code "4/2020"} 1176 * <li>{@code "2020/04"} 1177 * <li>{@code "2020/4"} 1178 * <li>{@code "April/2020"} 1179 * <li>{@code "Apr/2020"} 1180 * </ul> 1181 * 1182 * <p>You define a date autofill value for the view by overriding the following methods: 1183 * 1184 * <ol> 1185 * <li>{@link #getAutofillType()} to return {@link #AUTOFILL_TYPE_DATE}. 1186 * <li>{@link #getAutofillValue()} to return a 1187 * {@link AutofillValue#forDate(long) date autofillvalue}. 1188 * <li>{@link #autofill(AutofillValue)} to expect a data autofillvalue. 1189 * </ol> 1190 * 1191 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1192 */ 1193 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1194 "creditCardExpirationDate"; 1195 1196 /** 1197 * Hint indicating that this view can be autofilled with a credit card expiration month. 1198 * 1199 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1200 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1201 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}</code>). 1202 * 1203 * <p>When annotating a view with this hint, it's recommended to use a text autofill value 1204 * whose value is the numerical representation of the month, starting on {@code 1} to avoid 1205 * ambiguity when the autofill service provides a value for it. To understand why a 1206 * value can be ambiguous, consider "January", which could be represented as either of 1207 * 1208 * <ul> 1209 * <li>{@code "1"}: recommended way. 1210 * <li>{@code "0"}: if following the {@link Calendar#MONTH} convention. 1211 * <li>{@code "January"}: full name, in English. 1212 * <li>{@code "jan"}: abbreviated name, in English. 1213 * <li>{@code "Janeiro"}: full name, in another language. 1214 * </ul> 1215 * 1216 * <p>Another recommended approach is to use a date autofill value - see 1217 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE} for more details. 1218 * 1219 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1220 */ 1221 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1222 "creditCardExpirationMonth"; 1223 1224 /** 1225 * Hint indicating that this view can be autofilled with a credit card expiration year. 1226 * 1227 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1228 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1229 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}</code>). 1230 * 1231 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1232 */ 1233 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1234 "creditCardExpirationYear"; 1235 1236 /** 1237 * Hint indicating that this view can be autofilled with a credit card expiration day. 1238 * 1239 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1240 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1241 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}</code>). 1242 * 1243 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1244 */ 1245 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1246 1247 /** 1248 * Hints for the autofill services that describes the content of the view. 1249 */ 1250 private @Nullable String[] mAutofillHints; 1251 1252 /** 1253 * Autofill id, lazily created on calls to {@link #getAutofillId()}. 1254 */ 1255 private AutofillId mAutofillId; 1256 1257 /** @hide */ 1258 @IntDef(prefix = { "AUTOFILL_TYPE_" }, value = { 1259 AUTOFILL_TYPE_NONE, 1260 AUTOFILL_TYPE_TEXT, 1261 AUTOFILL_TYPE_TOGGLE, 1262 AUTOFILL_TYPE_LIST, 1263 AUTOFILL_TYPE_DATE 1264 }) 1265 @Retention(RetentionPolicy.SOURCE) 1266 public @interface AutofillType {} 1267 1268 /** 1269 * Autofill type for views that cannot be autofilled. 1270 * 1271 * <p>Typically used when the view is read-only; for example, a text label. 1272 * 1273 * @see #getAutofillType() 1274 */ 1275 public static final int AUTOFILL_TYPE_NONE = 0; 1276 1277 /** 1278 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1279 * 1280 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1281 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1282 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1283 * 1284 * @see #getAutofillType() 1285 */ 1286 public static final int AUTOFILL_TYPE_TEXT = 1; 1287 1288 /** 1289 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1290 * 1291 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1292 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1293 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1294 * 1295 * @see #getAutofillType() 1296 */ 1297 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1298 1299 /** 1300 * Autofill type for a selection list field, which is filled by an {@code int} 1301 * representing the element index inside the list (starting at {@code 0}). 1302 * 1303 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1304 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1305 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1306 * 1307 * <p>The available options in the selection list are typically provided by 1308 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1309 * 1310 * @see #getAutofillType() 1311 */ 1312 public static final int AUTOFILL_TYPE_LIST = 3; 1313 1314 1315 /** 1316 * Autofill type for a field that contains a date, which is represented by a long representing 1317 * the number of milliseconds since the standard base time known as "the epoch", namely 1318 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1319 * 1320 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1321 * {@link AutofillValue#forDate(long)}, and the values passed to 1322 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1323 * 1324 * @see #getAutofillType() 1325 */ 1326 public static final int AUTOFILL_TYPE_DATE = 4; 1327 1328 /** @hide */ 1329 @IntDef(prefix = { "IMPORTANT_FOR_AUTOFILL_" }, value = { 1330 IMPORTANT_FOR_AUTOFILL_AUTO, 1331 IMPORTANT_FOR_AUTOFILL_YES, 1332 IMPORTANT_FOR_AUTOFILL_NO, 1333 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 1334 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 1335 }) 1336 @Retention(RetentionPolicy.SOURCE) 1337 public @interface AutofillImportance {} 1338 1339 /** 1340 * Automatically determine whether a view is important for autofill. 1341 * 1342 * @see #isImportantForAutofill() 1343 * @see #setImportantForAutofill(int) 1344 */ 1345 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1346 1347 /** 1348 * The view is important for autofill, and its children (if any) will be traversed. 1349 * 1350 * @see #isImportantForAutofill() 1351 * @see #setImportantForAutofill(int) 1352 */ 1353 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1354 1355 /** 1356 * The view is not important for autofill, but its children (if any) will be traversed. 1357 * 1358 * @see #isImportantForAutofill() 1359 * @see #setImportantForAutofill(int) 1360 */ 1361 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1362 1363 /** 1364 * The view is important for autofill, but its children (if any) will not be traversed. 1365 * 1366 * @see #isImportantForAutofill() 1367 * @see #setImportantForAutofill(int) 1368 */ 1369 public static final int IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS = 0x4; 1370 1371 /** 1372 * The view is not important for autofill, and its children (if any) will not be traversed. 1373 * 1374 * @see #isImportantForAutofill() 1375 * @see #setImportantForAutofill(int) 1376 */ 1377 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; 1378 1379 /** @hide */ 1380 @IntDef(flag = true, prefix = { "AUTOFILL_FLAG_" }, value = { 1381 AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 1382 }) 1383 @Retention(RetentionPolicy.SOURCE) 1384 public @interface AutofillFlags {} 1385 1386 /** 1387 * Flag requesting you to add views that are marked as not important for autofill 1388 * (see {@link #setImportantForAutofill(int)}) to a {@link ViewStructure}. 1389 */ 1390 public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; 1391 1392 /** @hide */ 1393 @IntDef(prefix = { "IMPORTANT_FOR_CONTENT_CAPTURE_" }, value = { 1394 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, 1395 IMPORTANT_FOR_CONTENT_CAPTURE_YES, 1396 IMPORTANT_FOR_CONTENT_CAPTURE_NO, 1397 IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 1398 IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 1399 }) 1400 @Retention(RetentionPolicy.SOURCE) 1401 public @interface ContentCaptureImportance {} 1402 1403 /** 1404 * Automatically determine whether a view is important for content capture. 1405 * 1406 * @see #isImportantForContentCapture() 1407 * @see #setImportantForContentCapture(int) 1408 * 1409 * @hide 1410 */ 1411 @TestApi 1412 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0x0; 1413 1414 /** 1415 * The view is important for content capture, and its children (if any) will be traversed. 1416 * 1417 * @see #isImportantForContentCapture() 1418 * @see #setImportantForContentCapture(int) 1419 * 1420 * @hide 1421 */ 1422 @TestApi 1423 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 0x1; 1424 1425 /** 1426 * The view is not important for content capture, but its children (if any) will be traversed. 1427 * 1428 * @see #isImportantForContentCapture() 1429 * @see #setImportantForContentCapture(int) 1430 * 1431 * @hide 1432 */ 1433 @TestApi 1434 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 0x2; 1435 1436 /** 1437 * The view is important for content capture, but its children (if any) will not be traversed. 1438 * 1439 * @see #isImportantForContentCapture() 1440 * @see #setImportantForContentCapture(int) 1441 * 1442 * @hide 1443 */ 1444 @TestApi 1445 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 0x4; 1446 1447 /** 1448 * The view is not important for content capture, and its children (if any) will not be 1449 * traversed. 1450 * 1451 * @see #isImportantForContentCapture() 1452 * @see #setImportantForContentCapture(int) 1453 * 1454 * @hide 1455 */ 1456 @TestApi 1457 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 0x8; 1458 1459 1460 /** 1461 * This view is enabled. Interpretation varies by subclass. 1462 * Use with ENABLED_MASK when calling setFlags. 1463 * {@hide} 1464 */ 1465 static final int ENABLED = 0x00000000; 1466 1467 /** 1468 * This view is disabled. Interpretation varies by subclass. 1469 * Use with ENABLED_MASK when calling setFlags. 1470 * {@hide} 1471 */ 1472 static final int DISABLED = 0x00000020; 1473 1474 /** 1475 * Mask for use with setFlags indicating bits used for indicating whether 1476 * this view is enabled 1477 * {@hide} 1478 */ 1479 static final int ENABLED_MASK = 0x00000020; 1480 1481 /** 1482 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1483 * called and further optimizations will be performed. It is okay to have 1484 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1485 * {@hide} 1486 */ 1487 static final int WILL_NOT_DRAW = 0x00000080; 1488 1489 /** 1490 * Mask for use with setFlags indicating bits used for indicating whether 1491 * this view is will draw 1492 * {@hide} 1493 */ 1494 static final int DRAW_MASK = 0x00000080; 1495 1496 /** 1497 * <p>This view doesn't show scrollbars.</p> 1498 * {@hide} 1499 */ 1500 static final int SCROLLBARS_NONE = 0x00000000; 1501 1502 /** 1503 * <p>This view shows horizontal scrollbars.</p> 1504 * {@hide} 1505 */ 1506 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1507 1508 /** 1509 * <p>This view shows vertical scrollbars.</p> 1510 * {@hide} 1511 */ 1512 static final int SCROLLBARS_VERTICAL = 0x00000200; 1513 1514 /** 1515 * <p>Mask for use with setFlags indicating bits used for indicating which 1516 * scrollbars are enabled.</p> 1517 * {@hide} 1518 */ 1519 static final int SCROLLBARS_MASK = 0x00000300; 1520 1521 /** 1522 * Indicates that the view should filter touches when its window is obscured. 1523 * Refer to the class comments for more information about this security feature. 1524 * {@hide} 1525 */ 1526 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1527 1528 /** 1529 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1530 * that they are optional and should be skipped if the window has 1531 * requested system UI flags that ignore those insets for layout. 1532 */ 1533 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1534 1535 /** 1536 * <p>This view doesn't show fading edges.</p> 1537 * {@hide} 1538 */ 1539 static final int FADING_EDGE_NONE = 0x00000000; 1540 1541 /** 1542 * <p>This view shows horizontal fading edges.</p> 1543 * {@hide} 1544 */ 1545 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1546 1547 /** 1548 * <p>This view shows vertical fading edges.</p> 1549 * {@hide} 1550 */ 1551 static final int FADING_EDGE_VERTICAL = 0x00002000; 1552 1553 /** 1554 * <p>Mask for use with setFlags indicating bits used for indicating which 1555 * fading edges are enabled.</p> 1556 * {@hide} 1557 */ 1558 static final int FADING_EDGE_MASK = 0x00003000; 1559 1560 /** 1561 * <p>Indicates this view can be clicked. When clickable, a View reacts 1562 * to clicks by notifying the OnClickListener.<p> 1563 * {@hide} 1564 */ 1565 static final int CLICKABLE = 0x00004000; 1566 1567 /** 1568 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1569 * {@hide} 1570 */ 1571 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1572 1573 /** 1574 * <p>Indicates that no icicle should be saved for this view.<p> 1575 * {@hide} 1576 */ 1577 static final int SAVE_DISABLED = 0x000010000; 1578 1579 /** 1580 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1581 * property.</p> 1582 * {@hide} 1583 */ 1584 static final int SAVE_DISABLED_MASK = 0x000010000; 1585 1586 /** 1587 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1588 * {@hide} 1589 */ 1590 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1591 1592 /** 1593 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1594 * {@hide} 1595 */ 1596 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1597 1598 /** @hide */ 1599 @Retention(RetentionPolicy.SOURCE) 1600 @IntDef(prefix = { "DRAWING_CACHE_QUALITY_" }, value = { 1601 DRAWING_CACHE_QUALITY_LOW, 1602 DRAWING_CACHE_QUALITY_HIGH, 1603 DRAWING_CACHE_QUALITY_AUTO 1604 }) 1605 public @interface DrawingCacheQuality {} 1606 1607 /** 1608 * <p>Enables low quality mode for the drawing cache.</p> 1609 * 1610 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1611 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1612 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1613 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1614 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1615 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1616 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1617 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1618 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1619 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1620 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1621 * reports or unit testing the {@link PixelCopy} API is recommended. 1622 */ 1623 @Deprecated 1624 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1625 1626 /** 1627 * <p>Enables high quality mode for the drawing cache.</p> 1628 * 1629 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1630 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1631 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1632 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1633 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1634 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1635 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1636 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1637 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1638 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1639 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1640 * reports or unit testing the {@link PixelCopy} API is recommended. 1641 */ 1642 @Deprecated 1643 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1644 1645 /** 1646 * <p>Enables automatic quality mode for the drawing cache.</p> 1647 * 1648 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1649 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1650 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1651 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1652 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1653 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1654 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1655 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1656 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1657 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1658 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1659 * reports or unit testing the {@link PixelCopy} API is recommended. 1660 */ 1661 @Deprecated 1662 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1663 1664 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1665 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1666 }; 1667 1668 /** 1669 * <p>Mask for use with setFlags indicating bits used for the cache 1670 * quality property.</p> 1671 * {@hide} 1672 */ 1673 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1674 1675 /** 1676 * <p> 1677 * Indicates this view can be long clicked. When long clickable, a View 1678 * reacts to long clicks by notifying the OnLongClickListener or showing a 1679 * context menu. 1680 * </p> 1681 * {@hide} 1682 */ 1683 static final int LONG_CLICKABLE = 0x00200000; 1684 1685 /** 1686 * <p>Indicates that this view gets its drawable states from its direct parent 1687 * and ignores its original internal states.</p> 1688 * 1689 * @hide 1690 */ 1691 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1692 1693 /** 1694 * <p> 1695 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1696 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1697 * OnContextClickListener. 1698 * </p> 1699 * {@hide} 1700 */ 1701 static final int CONTEXT_CLICKABLE = 0x00800000; 1702 1703 /** @hide */ 1704 @IntDef(prefix = { "SCROLLBARS_" }, value = { 1705 SCROLLBARS_INSIDE_OVERLAY, 1706 SCROLLBARS_INSIDE_INSET, 1707 SCROLLBARS_OUTSIDE_OVERLAY, 1708 SCROLLBARS_OUTSIDE_INSET 1709 }) 1710 @Retention(RetentionPolicy.SOURCE) 1711 public @interface ScrollBarStyle {} 1712 1713 /** 1714 * The scrollbar style to display the scrollbars inside the content area, 1715 * without increasing the padding. The scrollbars will be overlaid with 1716 * translucency on the view's content. 1717 */ 1718 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1719 1720 /** 1721 * The scrollbar style to display the scrollbars inside the padded area, 1722 * increasing the padding of the view. The scrollbars will not overlap the 1723 * content area of the view. 1724 */ 1725 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1726 1727 /** 1728 * The scrollbar style to display the scrollbars at the edge of the view, 1729 * without increasing the padding. The scrollbars will be overlaid with 1730 * translucency. 1731 */ 1732 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1733 1734 /** 1735 * The scrollbar style to display the scrollbars at the edge of the view, 1736 * increasing the padding of the view. The scrollbars will only overlap the 1737 * background, if any. 1738 */ 1739 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1740 1741 /** 1742 * Mask to check if the scrollbar style is overlay or inset. 1743 * {@hide} 1744 */ 1745 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1746 1747 /** 1748 * Mask to check if the scrollbar style is inside or outside. 1749 * {@hide} 1750 */ 1751 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1752 1753 /** 1754 * Mask for scrollbar style. 1755 * {@hide} 1756 */ 1757 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1758 1759 /** 1760 * View flag indicating that the screen should remain on while the 1761 * window containing this view is visible to the user. This effectively 1762 * takes care of automatically setting the WindowManager's 1763 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1764 */ 1765 public static final int KEEP_SCREEN_ON = 0x04000000; 1766 1767 /** 1768 * View flag indicating whether this view should have sound effects enabled 1769 * for events such as clicking and touching. 1770 */ 1771 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1772 1773 /** 1774 * View flag indicating whether this view should have haptic feedback 1775 * enabled for events such as long presses. 1776 */ 1777 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1778 1779 /** 1780 * <p>Indicates that the view hierarchy should stop saving state when 1781 * it reaches this view. If state saving is initiated immediately at 1782 * the view, it will be allowed. 1783 * {@hide} 1784 */ 1785 static final int PARENT_SAVE_DISABLED = 0x20000000; 1786 1787 /** 1788 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1789 * {@hide} 1790 */ 1791 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1792 1793 private static Paint sDebugPaint; 1794 1795 /** 1796 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1797 * {@hide} 1798 */ 1799 static final int TOOLTIP = 0x40000000; 1800 1801 /** @hide */ 1802 @IntDef(flag = true, prefix = { "FOCUSABLES_" }, value = { 1803 FOCUSABLES_ALL, 1804 FOCUSABLES_TOUCH_MODE 1805 }) 1806 @Retention(RetentionPolicy.SOURCE) 1807 public @interface FocusableMode {} 1808 1809 /** 1810 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1811 * should add all focusable Views regardless if they are focusable in touch mode. 1812 */ 1813 public static final int FOCUSABLES_ALL = 0x00000000; 1814 1815 /** 1816 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1817 * should add only Views focusable in touch mode. 1818 */ 1819 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1820 1821 /** @hide */ 1822 @IntDef(prefix = { "FOCUS_" }, value = { 1823 FOCUS_BACKWARD, 1824 FOCUS_FORWARD, 1825 FOCUS_LEFT, 1826 FOCUS_UP, 1827 FOCUS_RIGHT, 1828 FOCUS_DOWN 1829 }) 1830 @Retention(RetentionPolicy.SOURCE) 1831 public @interface FocusDirection {} 1832 1833 /** @hide */ 1834 @IntDef(prefix = { "FOCUS_" }, value = { 1835 FOCUS_LEFT, 1836 FOCUS_UP, 1837 FOCUS_RIGHT, 1838 FOCUS_DOWN 1839 }) 1840 @Retention(RetentionPolicy.SOURCE) 1841 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1842 1843 /** 1844 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1845 * item. 1846 */ 1847 public static final int FOCUS_BACKWARD = 0x00000001; 1848 1849 /** 1850 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1851 * item. 1852 */ 1853 public static final int FOCUS_FORWARD = 0x00000002; 1854 1855 /** 1856 * Use with {@link #focusSearch(int)}. Move focus to the left. 1857 */ 1858 public static final int FOCUS_LEFT = 0x00000011; 1859 1860 /** 1861 * Use with {@link #focusSearch(int)}. Move focus up. 1862 */ 1863 public static final int FOCUS_UP = 0x00000021; 1864 1865 /** 1866 * Use with {@link #focusSearch(int)}. Move focus to the right. 1867 */ 1868 public static final int FOCUS_RIGHT = 0x00000042; 1869 1870 /** 1871 * Use with {@link #focusSearch(int)}. Move focus down. 1872 */ 1873 public static final int FOCUS_DOWN = 0x00000082; 1874 1875 /** 1876 * Bits of {@link #getMeasuredWidthAndState()} and 1877 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1878 */ 1879 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1880 1881 /** 1882 * Bits of {@link #getMeasuredWidthAndState()} and 1883 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1884 */ 1885 public static final int MEASURED_STATE_MASK = 0xff000000; 1886 1887 /** 1888 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1889 * for functions that combine both width and height into a single int, 1890 * such as {@link #getMeasuredState()} and the childState argument of 1891 * {@link #resolveSizeAndState(int, int, int)}. 1892 */ 1893 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1894 1895 /** 1896 * Bit of {@link #getMeasuredWidthAndState()} and 1897 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1898 * is smaller that the space the view would like to have. 1899 */ 1900 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1901 1902 /** 1903 * Base View state sets 1904 */ 1905 // Singles 1906 /** 1907 * Indicates the view has no states set. States are used with 1908 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1909 * view depending on its state. 1910 * 1911 * @see android.graphics.drawable.Drawable 1912 * @see #getDrawableState() 1913 */ 1914 protected static final int[] EMPTY_STATE_SET; 1915 /** 1916 * Indicates the view is enabled. States are used with 1917 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1918 * view depending on its state. 1919 * 1920 * @see android.graphics.drawable.Drawable 1921 * @see #getDrawableState() 1922 */ 1923 protected static final int[] ENABLED_STATE_SET; 1924 /** 1925 * Indicates the view is focused. States are used with 1926 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1927 * view depending on its state. 1928 * 1929 * @see android.graphics.drawable.Drawable 1930 * @see #getDrawableState() 1931 */ 1932 protected static final int[] FOCUSED_STATE_SET; 1933 /** 1934 * Indicates the view is selected. States are used with 1935 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1936 * view depending on its state. 1937 * 1938 * @see android.graphics.drawable.Drawable 1939 * @see #getDrawableState() 1940 */ 1941 protected static final int[] SELECTED_STATE_SET; 1942 /** 1943 * Indicates the view is pressed. States are used with 1944 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1945 * view depending on its state. 1946 * 1947 * @see android.graphics.drawable.Drawable 1948 * @see #getDrawableState() 1949 */ 1950 protected static final int[] PRESSED_STATE_SET; 1951 /** 1952 * Indicates the view's window has focus. States are used with 1953 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1954 * view depending on its state. 1955 * 1956 * @see android.graphics.drawable.Drawable 1957 * @see #getDrawableState() 1958 */ 1959 protected static final int[] WINDOW_FOCUSED_STATE_SET; 1960 // Doubles 1961 /** 1962 * Indicates the view is enabled and has the focus. 1963 * 1964 * @see #ENABLED_STATE_SET 1965 * @see #FOCUSED_STATE_SET 1966 */ 1967 protected static final int[] ENABLED_FOCUSED_STATE_SET; 1968 /** 1969 * Indicates the view is enabled and selected. 1970 * 1971 * @see #ENABLED_STATE_SET 1972 * @see #SELECTED_STATE_SET 1973 */ 1974 protected static final int[] ENABLED_SELECTED_STATE_SET; 1975 /** 1976 * Indicates the view is enabled and that its window has focus. 1977 * 1978 * @see #ENABLED_STATE_SET 1979 * @see #WINDOW_FOCUSED_STATE_SET 1980 */ 1981 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 1982 /** 1983 * Indicates the view is focused and selected. 1984 * 1985 * @see #FOCUSED_STATE_SET 1986 * @see #SELECTED_STATE_SET 1987 */ 1988 protected static final int[] FOCUSED_SELECTED_STATE_SET; 1989 /** 1990 * Indicates the view has the focus and that its window has the focus. 1991 * 1992 * @see #FOCUSED_STATE_SET 1993 * @see #WINDOW_FOCUSED_STATE_SET 1994 */ 1995 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 1996 /** 1997 * Indicates the view is selected and that its window has the focus. 1998 * 1999 * @see #SELECTED_STATE_SET 2000 * @see #WINDOW_FOCUSED_STATE_SET 2001 */ 2002 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 2003 // Triples 2004 /** 2005 * Indicates the view is enabled, focused and selected. 2006 * 2007 * @see #ENABLED_STATE_SET 2008 * @see #FOCUSED_STATE_SET 2009 * @see #SELECTED_STATE_SET 2010 */ 2011 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 2012 /** 2013 * Indicates the view is enabled, focused and its window has the focus. 2014 * 2015 * @see #ENABLED_STATE_SET 2016 * @see #FOCUSED_STATE_SET 2017 * @see #WINDOW_FOCUSED_STATE_SET 2018 */ 2019 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2020 /** 2021 * Indicates the view is enabled, selected and its window has the focus. 2022 * 2023 * @see #ENABLED_STATE_SET 2024 * @see #SELECTED_STATE_SET 2025 * @see #WINDOW_FOCUSED_STATE_SET 2026 */ 2027 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2028 /** 2029 * Indicates the view is focused, selected and its window has the focus. 2030 * 2031 * @see #FOCUSED_STATE_SET 2032 * @see #SELECTED_STATE_SET 2033 * @see #WINDOW_FOCUSED_STATE_SET 2034 */ 2035 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2036 /** 2037 * Indicates the view is enabled, focused, selected and its window 2038 * has the focus. 2039 * 2040 * @see #ENABLED_STATE_SET 2041 * @see #FOCUSED_STATE_SET 2042 * @see #SELECTED_STATE_SET 2043 * @see #WINDOW_FOCUSED_STATE_SET 2044 */ 2045 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2046 /** 2047 * Indicates the view is pressed and its window has the focus. 2048 * 2049 * @see #PRESSED_STATE_SET 2050 * @see #WINDOW_FOCUSED_STATE_SET 2051 */ 2052 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 2053 /** 2054 * Indicates the view is pressed and selected. 2055 * 2056 * @see #PRESSED_STATE_SET 2057 * @see #SELECTED_STATE_SET 2058 */ 2059 protected static final int[] PRESSED_SELECTED_STATE_SET; 2060 /** 2061 * Indicates the view is pressed, selected and its window has the focus. 2062 * 2063 * @see #PRESSED_STATE_SET 2064 * @see #SELECTED_STATE_SET 2065 * @see #WINDOW_FOCUSED_STATE_SET 2066 */ 2067 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2068 /** 2069 * Indicates the view is pressed and focused. 2070 * 2071 * @see #PRESSED_STATE_SET 2072 * @see #FOCUSED_STATE_SET 2073 */ 2074 protected static final int[] PRESSED_FOCUSED_STATE_SET; 2075 /** 2076 * Indicates the view is pressed, focused and its window has the focus. 2077 * 2078 * @see #PRESSED_STATE_SET 2079 * @see #FOCUSED_STATE_SET 2080 * @see #WINDOW_FOCUSED_STATE_SET 2081 */ 2082 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2083 /** 2084 * Indicates the view is pressed, focused and selected. 2085 * 2086 * @see #PRESSED_STATE_SET 2087 * @see #SELECTED_STATE_SET 2088 * @see #FOCUSED_STATE_SET 2089 */ 2090 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 2091 /** 2092 * Indicates the view is pressed, focused, selected and its window has the focus. 2093 * 2094 * @see #PRESSED_STATE_SET 2095 * @see #FOCUSED_STATE_SET 2096 * @see #SELECTED_STATE_SET 2097 * @see #WINDOW_FOCUSED_STATE_SET 2098 */ 2099 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2100 /** 2101 * Indicates the view is pressed and enabled. 2102 * 2103 * @see #PRESSED_STATE_SET 2104 * @see #ENABLED_STATE_SET 2105 */ 2106 protected static final int[] PRESSED_ENABLED_STATE_SET; 2107 /** 2108 * Indicates the view is pressed, enabled and its window has the focus. 2109 * 2110 * @see #PRESSED_STATE_SET 2111 * @see #ENABLED_STATE_SET 2112 * @see #WINDOW_FOCUSED_STATE_SET 2113 */ 2114 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 2115 /** 2116 * Indicates the view is pressed, enabled and selected. 2117 * 2118 * @see #PRESSED_STATE_SET 2119 * @see #ENABLED_STATE_SET 2120 * @see #SELECTED_STATE_SET 2121 */ 2122 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 2123 /** 2124 * Indicates the view is pressed, enabled, selected and its window has the 2125 * focus. 2126 * 2127 * @see #PRESSED_STATE_SET 2128 * @see #ENABLED_STATE_SET 2129 * @see #SELECTED_STATE_SET 2130 * @see #WINDOW_FOCUSED_STATE_SET 2131 */ 2132 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2133 /** 2134 * Indicates the view is pressed, enabled and focused. 2135 * 2136 * @see #PRESSED_STATE_SET 2137 * @see #ENABLED_STATE_SET 2138 * @see #FOCUSED_STATE_SET 2139 */ 2140 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 2141 /** 2142 * Indicates the view is pressed, enabled, focused and its window has the 2143 * focus. 2144 * 2145 * @see #PRESSED_STATE_SET 2146 * @see #ENABLED_STATE_SET 2147 * @see #FOCUSED_STATE_SET 2148 * @see #WINDOW_FOCUSED_STATE_SET 2149 */ 2150 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2151 /** 2152 * Indicates the view is pressed, enabled, focused and selected. 2153 * 2154 * @see #PRESSED_STATE_SET 2155 * @see #ENABLED_STATE_SET 2156 * @see #SELECTED_STATE_SET 2157 * @see #FOCUSED_STATE_SET 2158 */ 2159 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 2160 /** 2161 * Indicates the view is pressed, enabled, focused, selected and its window 2162 * has the focus. 2163 * 2164 * @see #PRESSED_STATE_SET 2165 * @see #ENABLED_STATE_SET 2166 * @see #SELECTED_STATE_SET 2167 * @see #FOCUSED_STATE_SET 2168 * @see #WINDOW_FOCUSED_STATE_SET 2169 */ 2170 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2171 2172 static { 2173 EMPTY_STATE_SET = StateSet.get(0); 2174 2175 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 2176 2177 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 2178 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2179 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 2180 2181 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 2182 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2183 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 2184 FOCUSED_SELECTED_STATE_SET = StateSet.get( 2185 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 2186 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2187 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2188 | StateSet.VIEW_STATE_FOCUSED); 2189 2190 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 2191 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2192 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2193 ENABLED_SELECTED_STATE_SET = StateSet.get( 2194 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 2195 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2196 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2197 | StateSet.VIEW_STATE_ENABLED); 2198 ENABLED_FOCUSED_STATE_SET = StateSet.get( 2199 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2200 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2201 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2202 | StateSet.VIEW_STATE_ENABLED); 2203 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2204 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2205 | StateSet.VIEW_STATE_ENABLED); 2206 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2207 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2208 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 2209 2210 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 2211 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2212 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2213 PRESSED_SELECTED_STATE_SET = StateSet.get( 2214 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 2215 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2216 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2217 | StateSet.VIEW_STATE_PRESSED); 2218 PRESSED_FOCUSED_STATE_SET = StateSet.get( 2219 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2220 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2221 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2222 | StateSet.VIEW_STATE_PRESSED); 2223 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2224 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2225 | StateSet.VIEW_STATE_PRESSED); 2226 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2227 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2228 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2229 PRESSED_ENABLED_STATE_SET = StateSet.get( 2230 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2231 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2232 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 2233 | StateSet.VIEW_STATE_PRESSED); 2234 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 2235 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 2236 | StateSet.VIEW_STATE_PRESSED); 2237 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2238 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2239 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2240 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 2241 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 2242 | StateSet.VIEW_STATE_PRESSED); 2243 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2244 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2245 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2246 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2247 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2248 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2249 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2250 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2251 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 2252 | StateSet.VIEW_STATE_PRESSED); 2253 } 2254 2255 /** 2256 * Accessibility event types that are dispatched for text population. 2257 */ 2258 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 2259 AccessibilityEvent.TYPE_VIEW_CLICKED 2260 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 2261 | AccessibilityEvent.TYPE_VIEW_SELECTED 2262 | AccessibilityEvent.TYPE_VIEW_FOCUSED 2263 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 2264 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 2265 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 2266 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 2267 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 2268 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 2269 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 2270 2271 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 2272 2273 static final int DEBUG_CORNERS_SIZE_DIP = 8; 2274 2275 /** 2276 * Temporary Rect currently for use in setBackground(). This will probably 2277 * be extended in the future to hold our own class with more than just 2278 * a Rect. :) 2279 */ 2280 static final ThreadLocal<Rect> sThreadLocal = new ThreadLocal<Rect>(); 2281 2282 /** 2283 * Map used to store views' tags. 2284 */ 2285 @UnsupportedAppUsage 2286 private SparseArray<Object> mKeyedTags; 2287 2288 /** 2289 * The next available accessibility id. 2290 */ 2291 private static int sNextAccessibilityViewId; 2292 2293 /** 2294 * The animation currently associated with this view. 2295 * @hide 2296 */ 2297 protected Animation mCurrentAnimation = null; 2298 2299 /** 2300 * Width as measured during measure pass. 2301 * {@hide} 2302 */ 2303 @ViewDebug.ExportedProperty(category = "measurement") 2304 @UnsupportedAppUsage 2305 int mMeasuredWidth; 2306 2307 /** 2308 * Height as measured during measure pass. 2309 * {@hide} 2310 */ 2311 @ViewDebug.ExportedProperty(category = "measurement") 2312 @UnsupportedAppUsage 2313 int mMeasuredHeight; 2314 2315 /** 2316 * Flag to indicate that this view was marked INVALIDATED, or had its display list 2317 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 2318 * its display list. This flag, used only when hw accelerated, allows us to clear the 2319 * flag while retaining this information until it's needed (at getDisplayList() time and 2320 * in drawChild(), when we decide to draw a view's children's display lists into our own). 2321 * 2322 * {@hide} 2323 */ 2324 @UnsupportedAppUsage 2325 boolean mRecreateDisplayList = false; 2326 2327 /** 2328 * The view's identifier. 2329 * {@hide} 2330 * 2331 * @see #setId(int) 2332 * @see #getId() 2333 */ 2334 @IdRes 2335 @ViewDebug.ExportedProperty(resolveId = true) 2336 int mID = NO_ID; 2337 2338 /** The ID of this view for autofill purposes. 2339 * <ul> 2340 * <li>== {@link #NO_ID}: ID has not been assigned yet 2341 * <li>≤ {@link #LAST_APP_AUTOFILL_ID}: View is not part of a activity. The ID is 2342 * unique in the process. This might change 2343 * over activity lifecycle events. 2344 * <li>> {@link #LAST_APP_AUTOFILL_ID}: View is part of a activity. The ID is 2345 * unique in the activity. This stays the same 2346 * over activity lifecycle events. 2347 */ 2348 private int mAutofillViewId = NO_ID; 2349 2350 // ID for accessibility purposes. This ID must be unique for every window 2351 @UnsupportedAppUsage 2352 private int mAccessibilityViewId = NO_ID; 2353 2354 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2355 2356 /** 2357 * The view's tag. 2358 * {@hide} 2359 * 2360 * @see #setTag(Object) 2361 * @see #getTag() 2362 */ 2363 @UnsupportedAppUsage 2364 protected Object mTag = null; 2365 2366 /* 2367 * Masks for mPrivateFlags, as generated by dumpFlags(): 2368 * 2369 * |-------|-------|-------|-------| 2370 * 1 PFLAG_WANTS_FOCUS 2371 * 1 PFLAG_FOCUSED 2372 * 1 PFLAG_SELECTED 2373 * 1 PFLAG_IS_ROOT_NAMESPACE 2374 * 1 PFLAG_HAS_BOUNDS 2375 * 1 PFLAG_DRAWN 2376 * 1 PFLAG_DRAW_ANIMATION 2377 * 1 PFLAG_SKIP_DRAW 2378 * 1 PFLAG_REQUEST_TRANSPARENT_REGIONS 2379 * 1 PFLAG_DRAWABLE_STATE_DIRTY 2380 * 1 PFLAG_MEASURED_DIMENSION_SET 2381 * 1 PFLAG_FORCE_LAYOUT 2382 * 1 PFLAG_LAYOUT_REQUIRED 2383 * 1 PFLAG_PRESSED 2384 * 1 PFLAG_DRAWING_CACHE_VALID 2385 * 1 PFLAG_ANIMATION_STARTED 2386 * 1 PFLAG_SAVE_STATE_CALLED 2387 * 1 PFLAG_ALPHA_SET 2388 * 1 PFLAG_SCROLL_CONTAINER 2389 * 1 PFLAG_SCROLL_CONTAINER_ADDED 2390 * 1 PFLAG_DIRTY 2391 * 1 PFLAG_DIRTY_MASK 2392 * 1 PFLAG_OPAQUE_BACKGROUND 2393 * 1 PFLAG_OPAQUE_SCROLLBARS 2394 * 11 PFLAG_OPAQUE_MASK 2395 * 1 PFLAG_PREPRESSED 2396 * 1 PFLAG_CANCEL_NEXT_UP_EVENT 2397 * 1 PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH 2398 * 1 PFLAG_HOVERED 2399 * 1 PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK 2400 * 1 PFLAG_ACTIVATED 2401 * 1 PFLAG_INVALIDATED 2402 * |-------|-------|-------|-------| 2403 */ 2404 /** {@hide} */ 2405 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2406 /** {@hide} */ 2407 static final int PFLAG_FOCUSED = 0x00000002; 2408 /** {@hide} */ 2409 static final int PFLAG_SELECTED = 0x00000004; 2410 /** {@hide} */ 2411 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2412 /** {@hide} */ 2413 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2414 /** {@hide} */ 2415 static final int PFLAG_DRAWN = 0x00000020; 2416 /** 2417 * When this flag is set, this view is running an animation on behalf of its 2418 * children and should therefore not cancel invalidate requests, even if they 2419 * lie outside of this view's bounds. 2420 * 2421 * {@hide} 2422 */ 2423 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2424 /** {@hide} */ 2425 static final int PFLAG_SKIP_DRAW = 0x00000080; 2426 /** {@hide} */ 2427 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2428 /** {@hide} */ 2429 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2430 /** {@hide} */ 2431 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2432 /** {@hide} */ 2433 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2434 /** {@hide} */ 2435 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2436 2437 private static final int PFLAG_PRESSED = 0x00004000; 2438 2439 /** {@hide} */ 2440 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2441 /** 2442 * Flag used to indicate that this view should be drawn once more (and only once 2443 * more) after its animation has completed. 2444 * {@hide} 2445 */ 2446 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2447 2448 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2449 2450 /** 2451 * Indicates that the View returned true when onSetAlpha() was called and that 2452 * the alpha must be restored. 2453 * {@hide} 2454 */ 2455 static final int PFLAG_ALPHA_SET = 0x00040000; 2456 2457 /** 2458 * Set by {@link #setScrollContainer(boolean)}. 2459 */ 2460 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2461 2462 /** 2463 * Set by {@link #setScrollContainer(boolean)}. 2464 */ 2465 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2466 2467 /** 2468 * View flag indicating whether this view was invalidated (fully or partially.) 2469 * 2470 * @hide 2471 */ 2472 static final int PFLAG_DIRTY = 0x00200000; 2473 2474 /** 2475 * Mask for {@link #PFLAG_DIRTY}. 2476 * 2477 * @hide 2478 */ 2479 static final int PFLAG_DIRTY_MASK = 0x00200000; 2480 2481 /** 2482 * Indicates whether the background is opaque. 2483 * 2484 * @hide 2485 */ 2486 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2487 2488 /** 2489 * Indicates whether the scrollbars are opaque. 2490 * 2491 * @hide 2492 */ 2493 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2494 2495 /** 2496 * Indicates whether the view is opaque. 2497 * 2498 * @hide 2499 */ 2500 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2501 2502 /** 2503 * Indicates a prepressed state; 2504 * the short time between ACTION_DOWN and recognizing 2505 * a 'real' press. Prepressed is used to recognize quick taps 2506 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2507 * 2508 * @hide 2509 */ 2510 private static final int PFLAG_PREPRESSED = 0x02000000; 2511 2512 /** 2513 * Indicates whether the view is temporarily detached. 2514 * 2515 * @hide 2516 */ 2517 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2518 2519 /** 2520 * Indicates that we should awaken scroll bars once attached 2521 * 2522 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2523 * during window attachment and it is no longer needed. Feel free to repurpose it. 2524 * 2525 * @hide 2526 */ 2527 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2528 2529 /** 2530 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2531 * @hide 2532 */ 2533 private static final int PFLAG_HOVERED = 0x10000000; 2534 2535 /** 2536 * Flag set by {@link AutofillManager} if it needs to be notified when this view is clicked. 2537 */ 2538 private static final int PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK = 0x20000000; 2539 2540 /** {@hide} */ 2541 static final int PFLAG_ACTIVATED = 0x40000000; 2542 2543 /** 2544 * Indicates that this view was specifically invalidated, not just dirtied because some 2545 * child view was invalidated. The flag is used to determine when we need to recreate 2546 * a view's display list (as opposed to just returning a reference to its existing 2547 * display list). 2548 * 2549 * @hide 2550 */ 2551 static final int PFLAG_INVALIDATED = 0x80000000; 2552 2553 /* End of masks for mPrivateFlags */ 2554 2555 /* 2556 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2557 * 2558 * |-------|-------|-------|-------| 2559 * 1 PFLAG2_DRAG_CAN_ACCEPT 2560 * 1 PFLAG2_DRAG_HOVERED 2561 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2562 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2563 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2564 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2565 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2566 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2567 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2568 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2569 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2570 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2571 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2572 * 111 PFLAG2_TEXT_DIRECTION_MASK 2573 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2574 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2575 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2576 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2577 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2578 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2579 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2580 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2581 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2582 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2583 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2584 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2585 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2586 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2587 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2588 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2589 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2590 * 1 PFLAG2_VIEW_QUICK_REJECTED 2591 * 1 PFLAG2_PADDING_RESOLVED 2592 * 1 PFLAG2_DRAWABLE_RESOLVED 2593 * 1 PFLAG2_HAS_TRANSIENT_STATE 2594 * |-------|-------|-------|-------| 2595 */ 2596 2597 /** 2598 * Indicates that this view has reported that it can accept the current drag's content. 2599 * Cleared when the drag operation concludes. 2600 * @hide 2601 */ 2602 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2603 2604 /** 2605 * Indicates that this view is currently directly under the drag location in a 2606 * drag-and-drop operation involving content that it can accept. Cleared when 2607 * the drag exits the view, or when the drag operation concludes. 2608 * @hide 2609 */ 2610 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2611 2612 /** @hide */ 2613 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2614 LAYOUT_DIRECTION_LTR, 2615 LAYOUT_DIRECTION_RTL, 2616 LAYOUT_DIRECTION_INHERIT, 2617 LAYOUT_DIRECTION_LOCALE 2618 }) 2619 @Retention(RetentionPolicy.SOURCE) 2620 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2621 public @interface LayoutDir {} 2622 2623 /** @hide */ 2624 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2625 LAYOUT_DIRECTION_LTR, 2626 LAYOUT_DIRECTION_RTL 2627 }) 2628 @Retention(RetentionPolicy.SOURCE) 2629 public @interface ResolvedLayoutDir {} 2630 2631 /** 2632 * A flag to indicate that the layout direction of this view has not been defined yet. 2633 * @hide 2634 */ 2635 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2636 2637 /** 2638 * Horizontal layout direction of this view is from Left to Right. 2639 * Use with {@link #setLayoutDirection}. 2640 */ 2641 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2642 2643 /** 2644 * Horizontal layout direction of this view is from Right to Left. 2645 * Use with {@link #setLayoutDirection}. 2646 */ 2647 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2648 2649 /** 2650 * Horizontal layout direction of this view is inherited from its parent. 2651 * Use with {@link #setLayoutDirection}. 2652 */ 2653 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2654 2655 /** 2656 * Horizontal layout direction of this view is from deduced from the default language 2657 * script for the locale. Use with {@link #setLayoutDirection}. 2658 */ 2659 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2660 2661 /** 2662 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2663 * @hide 2664 */ 2665 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2666 2667 /** 2668 * Mask for use with private flags indicating bits used for horizontal layout direction. 2669 * @hide 2670 */ 2671 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2672 2673 /** 2674 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2675 * right-to-left direction. 2676 * @hide 2677 */ 2678 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2679 2680 /** 2681 * Indicates whether the view horizontal layout direction has been resolved. 2682 * @hide 2683 */ 2684 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2685 2686 /** 2687 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2688 * @hide 2689 */ 2690 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2691 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2692 2693 /* 2694 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2695 * flag value. 2696 * @hide 2697 */ 2698 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2699 LAYOUT_DIRECTION_LTR, 2700 LAYOUT_DIRECTION_RTL, 2701 LAYOUT_DIRECTION_INHERIT, 2702 LAYOUT_DIRECTION_LOCALE 2703 }; 2704 2705 /** 2706 * Default horizontal layout direction. 2707 */ 2708 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2709 2710 /** 2711 * Default horizontal layout direction. 2712 * @hide 2713 */ 2714 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2715 2716 /** 2717 * Text direction is inherited through {@link ViewGroup} 2718 */ 2719 public static final int TEXT_DIRECTION_INHERIT = 0; 2720 2721 /** 2722 * Text direction is using "first strong algorithm". The first strong directional character 2723 * determines the paragraph direction. If there is no strong directional character, the 2724 * paragraph direction is the view's resolved layout direction. 2725 */ 2726 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2727 2728 /** 2729 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2730 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2731 * If there are neither, the paragraph direction is the view's resolved layout direction. 2732 */ 2733 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2734 2735 /** 2736 * Text direction is forced to LTR. 2737 */ 2738 public static final int TEXT_DIRECTION_LTR = 3; 2739 2740 /** 2741 * Text direction is forced to RTL. 2742 */ 2743 public static final int TEXT_DIRECTION_RTL = 4; 2744 2745 /** 2746 * Text direction is coming from the system Locale. 2747 */ 2748 public static final int TEXT_DIRECTION_LOCALE = 5; 2749 2750 /** 2751 * Text direction is using "first strong algorithm". The first strong directional character 2752 * determines the paragraph direction. If there is no strong directional character, the 2753 * paragraph direction is LTR. 2754 */ 2755 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2756 2757 /** 2758 * Text direction is using "first strong algorithm". The first strong directional character 2759 * determines the paragraph direction. If there is no strong directional character, the 2760 * paragraph direction is RTL. 2761 */ 2762 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2763 2764 /** 2765 * Default text direction is inherited 2766 */ 2767 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2768 2769 /** 2770 * Default resolved text direction 2771 * @hide 2772 */ 2773 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2774 2775 /** 2776 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2777 * @hide 2778 */ 2779 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2780 2781 /** 2782 * Mask for use with private flags indicating bits used for text direction. 2783 * @hide 2784 */ 2785 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2786 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2787 2788 /** 2789 * Array of text direction flags for mapping attribute "textDirection" to correct 2790 * flag value. 2791 * @hide 2792 */ 2793 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2794 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2795 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2796 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2797 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2798 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2799 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2800 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2801 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2802 }; 2803 2804 /** 2805 * Indicates whether the view text direction has been resolved. 2806 * @hide 2807 */ 2808 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2809 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2810 2811 /** 2812 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2813 * @hide 2814 */ 2815 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2816 2817 /** 2818 * Mask for use with private flags indicating bits used for resolved text direction. 2819 * @hide 2820 */ 2821 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2822 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2823 2824 /** 2825 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2826 * @hide 2827 */ 2828 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2829 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2830 2831 /** @hide */ 2832 @IntDef(prefix = { "TEXT_ALIGNMENT_" }, value = { 2833 TEXT_ALIGNMENT_INHERIT, 2834 TEXT_ALIGNMENT_GRAVITY, 2835 TEXT_ALIGNMENT_CENTER, 2836 TEXT_ALIGNMENT_TEXT_START, 2837 TEXT_ALIGNMENT_TEXT_END, 2838 TEXT_ALIGNMENT_VIEW_START, 2839 TEXT_ALIGNMENT_VIEW_END 2840 }) 2841 @Retention(RetentionPolicy.SOURCE) 2842 public @interface TextAlignment {} 2843 2844 /** 2845 * Default text alignment. The text alignment of this View is inherited from its parent. 2846 * Use with {@link #setTextAlignment(int)} 2847 */ 2848 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2849 2850 /** 2851 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2852 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph's text direction. 2853 * 2854 * Use with {@link #setTextAlignment(int)} 2855 */ 2856 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2857 2858 /** 2859 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2860 * 2861 * Use with {@link #setTextAlignment(int)} 2862 */ 2863 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2864 2865 /** 2866 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2867 * 2868 * Use with {@link #setTextAlignment(int)} 2869 */ 2870 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2871 2872 /** 2873 * Center the paragraph, e.g. ALIGN_CENTER. 2874 * 2875 * Use with {@link #setTextAlignment(int)} 2876 */ 2877 public static final int TEXT_ALIGNMENT_CENTER = 4; 2878 2879 /** 2880 * Align to the start of the view, which is ALIGN_LEFT if the view's resolved 2881 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2882 * 2883 * Use with {@link #setTextAlignment(int)} 2884 */ 2885 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2886 2887 /** 2888 * Align to the end of the view, which is ALIGN_RIGHT if the view's resolved 2889 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2890 * 2891 * Use with {@link #setTextAlignment(int)} 2892 */ 2893 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2894 2895 /** 2896 * Default text alignment is inherited 2897 */ 2898 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2899 2900 /** 2901 * Default resolved text alignment 2902 * @hide 2903 */ 2904 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2905 2906 /** 2907 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2908 * @hide 2909 */ 2910 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2911 2912 /** 2913 * Mask for use with private flags indicating bits used for text alignment. 2914 * @hide 2915 */ 2916 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2917 2918 /** 2919 * Array of text direction flags for mapping attribute "textAlignment" to correct 2920 * flag value. 2921 * @hide 2922 */ 2923 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2924 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2925 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2926 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2927 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2928 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2929 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2930 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2931 }; 2932 2933 /** 2934 * Indicates whether the view text alignment has been resolved. 2935 * @hide 2936 */ 2937 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2938 2939 /** 2940 * Bit shift to get the resolved text alignment. 2941 * @hide 2942 */ 2943 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2944 2945 /** 2946 * Mask for use with private flags indicating bits used for text alignment. 2947 * @hide 2948 */ 2949 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2950 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2951 2952 /** 2953 * Indicates whether if the view text alignment has been resolved to gravity 2954 */ 2955 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 2956 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 2957 2958 // Accessiblity constants for mPrivateFlags2 2959 2960 /** 2961 * Shift for the bits in {@link #mPrivateFlags2} related to the 2962 * "importantForAccessibility" attribute. 2963 */ 2964 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 2965 2966 /** 2967 * Automatically determine whether a view is important for accessibility. 2968 */ 2969 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 2970 2971 /** 2972 * The view is important for accessibility. 2973 */ 2974 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 2975 2976 /** 2977 * The view is not important for accessibility. 2978 */ 2979 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 2980 2981 /** 2982 * The view is not important for accessibility, nor are any of its 2983 * descendant views. 2984 */ 2985 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 2986 2987 /** 2988 * The default whether the view is important for accessibility. 2989 */ 2990 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 2991 2992 /** 2993 * Mask for obtaining the bits which specify how to determine 2994 * whether a view is important for accessibility. 2995 */ 2996 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 2997 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 2998 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 2999 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 3000 3001 /** 3002 * Shift for the bits in {@link #mPrivateFlags2} related to the 3003 * "accessibilityLiveRegion" attribute. 3004 */ 3005 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 3006 3007 /** 3008 * Live region mode specifying that accessibility services should not 3009 * automatically announce changes to this view. This is the default live 3010 * region mode for most views. 3011 * <p> 3012 * Use with {@link #setAccessibilityLiveRegion(int)}. 3013 */ 3014 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 3015 3016 /** 3017 * Live region mode specifying that accessibility services should announce 3018 * changes to this view. 3019 * <p> 3020 * Use with {@link #setAccessibilityLiveRegion(int)}. 3021 */ 3022 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 3023 3024 /** 3025 * Live region mode specifying that accessibility services should interrupt 3026 * ongoing speech to immediately announce changes to this view. 3027 * <p> 3028 * Use with {@link #setAccessibilityLiveRegion(int)}. 3029 */ 3030 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 3031 3032 /** 3033 * The default whether the view is important for accessibility. 3034 */ 3035 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 3036 3037 /** 3038 * Mask for obtaining the bits which specify a view's accessibility live 3039 * region mode. 3040 */ 3041 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 3042 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 3043 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 3044 3045 /** 3046 * Flag indicating whether a view has accessibility focus. 3047 */ 3048 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 3049 3050 /** 3051 * Flag whether the accessibility state of the subtree rooted at this view changed. 3052 */ 3053 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 3054 3055 /** 3056 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 3057 * is used to check whether later changes to the view's transform should invalidate the 3058 * view to force the quickReject test to run again. 3059 */ 3060 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 3061 3062 /** 3063 * Flag indicating that start/end padding has been resolved into left/right padding 3064 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 3065 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 3066 * during measurement. In some special cases this is required such as when an adapter-based 3067 * view measures prospective children without attaching them to a window. 3068 */ 3069 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 3070 3071 /** 3072 * Flag indicating that the start/end drawables has been resolved into left/right ones. 3073 */ 3074 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 3075 3076 /** 3077 * Indicates that the view is tracking some sort of transient state 3078 * that the app should not need to be aware of, but that the framework 3079 * should take special care to preserve. 3080 */ 3081 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 3082 3083 /** 3084 * Group of bits indicating that RTL properties resolution is done. 3085 */ 3086 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 3087 PFLAG2_TEXT_DIRECTION_RESOLVED | 3088 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 3089 PFLAG2_PADDING_RESOLVED | 3090 PFLAG2_DRAWABLE_RESOLVED; 3091 3092 // There are a couple of flags left in mPrivateFlags2 3093 3094 /* End of masks for mPrivateFlags2 */ 3095 3096 /* 3097 * Masks for mPrivateFlags3, as generated by dumpFlags(): 3098 * 3099 * |-------|-------|-------|-------| 3100 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 3101 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 3102 * 1 PFLAG3_IS_LAID_OUT 3103 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 3104 * 1 PFLAG3_CALLED_SUPER 3105 * 1 PFLAG3_APPLYING_INSETS 3106 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 3107 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 3108 * 1 PFLAG3_SCROLL_INDICATOR_TOP 3109 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 3110 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 3111 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 3112 * 1 PFLAG3_SCROLL_INDICATOR_START 3113 * 1 PFLAG3_SCROLL_INDICATOR_END 3114 * 1 PFLAG3_ASSIST_BLOCKED 3115 * 1 PFLAG3_CLUSTER 3116 * 1 PFLAG3_IS_AUTOFILLED 3117 * 1 PFLAG3_FINGER_DOWN 3118 * 1 PFLAG3_FOCUSED_BY_DEFAULT 3119 * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL 3120 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 3121 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 3122 * 1 PFLAG3_TEMPORARY_DETACH 3123 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 3124 * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT 3125 * 1 PFLAG3_SCREEN_READER_FOCUSABLE 3126 * 1 PFLAG3_AGGREGATED_VISIBLE 3127 * 1 PFLAG3_AUTOFILLID_EXPLICITLY_SET 3128 * 1 PFLAG3_ACCESSIBILITY_HEADING 3129 * |-------|-------|-------|-------| 3130 */ 3131 3132 /** 3133 * Flag indicating that view has a transform animation set on it. This is used to track whether 3134 * an animation is cleared between successive frames, in order to tell the associated 3135 * DisplayList to clear its animation matrix. 3136 */ 3137 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 3138 3139 /** 3140 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 3141 * animation is cleared between successive frames, in order to tell the associated 3142 * DisplayList to restore its alpha value. 3143 */ 3144 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 3145 3146 /** 3147 * Flag indicating that the view has been through at least one layout since it 3148 * was last attached to a window. 3149 */ 3150 static final int PFLAG3_IS_LAID_OUT = 0x4; 3151 3152 /** 3153 * Flag indicating that a call to measure() was skipped and should be done 3154 * instead when layout() is invoked. 3155 */ 3156 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 3157 3158 /** 3159 * Flag indicating that an overridden method correctly called down to 3160 * the superclass implementation as required by the API spec. 3161 */ 3162 static final int PFLAG3_CALLED_SUPER = 0x10; 3163 3164 /** 3165 * Flag indicating that we're in the process of applying window insets. 3166 */ 3167 static final int PFLAG3_APPLYING_INSETS = 0x20; 3168 3169 /** 3170 * Flag indicating that we're in the process of fitting system windows using the old method. 3171 */ 3172 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 3173 3174 /** 3175 * Flag indicating that nested scrolling is enabled for this view. 3176 * The view will optionally cooperate with views up its parent chain to allow for 3177 * integrated nested scrolling along the same axis. 3178 */ 3179 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 3180 3181 /** 3182 * Flag indicating that the bottom scroll indicator should be displayed 3183 * when this view can scroll up. 3184 */ 3185 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 3186 3187 /** 3188 * Flag indicating that the bottom scroll indicator should be displayed 3189 * when this view can scroll down. 3190 */ 3191 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 3192 3193 /** 3194 * Flag indicating that the left scroll indicator should be displayed 3195 * when this view can scroll left. 3196 */ 3197 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 3198 3199 /** 3200 * Flag indicating that the right scroll indicator should be displayed 3201 * when this view can scroll right. 3202 */ 3203 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 3204 3205 /** 3206 * Flag indicating that the start scroll indicator should be displayed 3207 * when this view can scroll in the start direction. 3208 */ 3209 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 3210 3211 /** 3212 * Flag indicating that the end scroll indicator should be displayed 3213 * when this view can scroll in the end direction. 3214 */ 3215 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 3216 3217 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 3218 3219 static final int SCROLL_INDICATORS_NONE = 0x0000; 3220 3221 /** 3222 * Mask for use with setFlags indicating bits used for indicating which 3223 * scroll indicators are enabled. 3224 */ 3225 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 3226 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 3227 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 3228 | PFLAG3_SCROLL_INDICATOR_END; 3229 3230 /** 3231 * Left-shift required to translate between public scroll indicator flags 3232 * and internal PFLAGS3 flags. When used as a right-shift, translates 3233 * PFLAGS3 flags to public flags. 3234 */ 3235 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 3236 3237 /** @hide */ 3238 @Retention(RetentionPolicy.SOURCE) 3239 @IntDef(flag = true, prefix = { "SCROLL_INDICATOR_" }, value = { 3240 SCROLL_INDICATOR_TOP, 3241 SCROLL_INDICATOR_BOTTOM, 3242 SCROLL_INDICATOR_LEFT, 3243 SCROLL_INDICATOR_RIGHT, 3244 SCROLL_INDICATOR_START, 3245 SCROLL_INDICATOR_END, 3246 }) 3247 public @interface ScrollIndicators {} 3248 3249 /** 3250 * Scroll indicator direction for the top edge of the view. 3251 * 3252 * @see #setScrollIndicators(int) 3253 * @see #setScrollIndicators(int, int) 3254 * @see #getScrollIndicators() 3255 */ 3256 public static final int SCROLL_INDICATOR_TOP = 3257 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3258 3259 /** 3260 * Scroll indicator direction for the bottom edge of the view. 3261 * 3262 * @see #setScrollIndicators(int) 3263 * @see #setScrollIndicators(int, int) 3264 * @see #getScrollIndicators() 3265 */ 3266 public static final int SCROLL_INDICATOR_BOTTOM = 3267 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3268 3269 /** 3270 * Scroll indicator direction for the left edge of the view. 3271 * 3272 * @see #setScrollIndicators(int) 3273 * @see #setScrollIndicators(int, int) 3274 * @see #getScrollIndicators() 3275 */ 3276 public static final int SCROLL_INDICATOR_LEFT = 3277 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3278 3279 /** 3280 * Scroll indicator direction for the right edge of the view. 3281 * 3282 * @see #setScrollIndicators(int) 3283 * @see #setScrollIndicators(int, int) 3284 * @see #getScrollIndicators() 3285 */ 3286 public static final int SCROLL_INDICATOR_RIGHT = 3287 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3288 3289 /** 3290 * Scroll indicator direction for the starting edge of the view. 3291 * <p> 3292 * Resolved according to the view's layout direction, see 3293 * {@link #getLayoutDirection()} for more information. 3294 * 3295 * @see #setScrollIndicators(int) 3296 * @see #setScrollIndicators(int, int) 3297 * @see #getScrollIndicators() 3298 */ 3299 public static final int SCROLL_INDICATOR_START = 3300 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3301 3302 /** 3303 * Scroll indicator direction for the ending edge of the view. 3304 * <p> 3305 * Resolved according to the view's layout direction, see 3306 * {@link #getLayoutDirection()} for more information. 3307 * 3308 * @see #setScrollIndicators(int) 3309 * @see #setScrollIndicators(int, int) 3310 * @see #getScrollIndicators() 3311 */ 3312 public static final int SCROLL_INDICATOR_END = 3313 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3314 3315 /** 3316 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 3317 * into this view.<p> 3318 */ 3319 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 3320 3321 /** 3322 * Flag indicating that the view is a root of a keyboard navigation cluster. 3323 * 3324 * @see #isKeyboardNavigationCluster() 3325 * @see #setKeyboardNavigationCluster(boolean) 3326 */ 3327 private static final int PFLAG3_CLUSTER = 0x8000; 3328 3329 /** 3330 * Flag indicating that the view is autofilled 3331 * 3332 * @see #isAutofilled() 3333 * @see #setAutofilled(boolean) 3334 */ 3335 private static final int PFLAG3_IS_AUTOFILLED = 0x10000; 3336 3337 /** 3338 * Indicates that the user is currently touching the screen. 3339 * Currently used for the tooltip positioning only. 3340 */ 3341 private static final int PFLAG3_FINGER_DOWN = 0x20000; 3342 3343 /** 3344 * Flag indicating that this view is the default-focus view. 3345 * 3346 * @see #isFocusedByDefault() 3347 * @see #setFocusedByDefault(boolean) 3348 */ 3349 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 3350 3351 /** 3352 * Shift for the bits in {@link #mPrivateFlags3} related to the 3353 * "importantForAutofill" attribute. 3354 */ 3355 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19; 3356 3357 /** 3358 * Mask for obtaining the bits which specify how to determine 3359 * whether a view is important for autofill. 3360 */ 3361 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 3362 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO 3363 | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 3364 | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS) 3365 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 3366 3367 /** 3368 * Whether this view has rendered elements that overlap (see {@link 3369 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 3370 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 3371 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 3372 * determined by whatever {@link #hasOverlappingRendering()} returns. 3373 */ 3374 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 3375 3376 /** 3377 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 3378 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 3379 */ 3380 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 3381 3382 /** 3383 * Flag indicating that the view is temporarily detached from the parent view. 3384 * 3385 * @see #onStartTemporaryDetach() 3386 * @see #onFinishTemporaryDetach() 3387 */ 3388 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3389 3390 /** 3391 * Flag indicating that the view does not wish to be revealed within its parent 3392 * hierarchy when it gains focus. Expressed in the negative since the historical 3393 * default behavior is to reveal on focus; this flag suppresses that behavior. 3394 * 3395 * @see #setRevealOnFocusHint(boolean) 3396 * @see #getRevealOnFocusHint() 3397 */ 3398 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3399 3400 /** 3401 * Flag indicating that when layout is completed we should notify 3402 * that the view was entered for autofill purposes. To minimize 3403 * showing autofill for views not visible to the user we evaluate 3404 * user visibility which cannot be done until the view is laid out. 3405 */ 3406 static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000; 3407 3408 /** 3409 * Works like focusable for screen readers, but without the side effects on input focus. 3410 * @see #setScreenReaderFocusable(boolean) 3411 */ 3412 private static final int PFLAG3_SCREEN_READER_FOCUSABLE = 0x10000000; 3413 3414 /** 3415 * The last aggregated visibility. Used to detect when it truly changes. 3416 */ 3417 private static final int PFLAG3_AGGREGATED_VISIBLE = 0x20000000; 3418 3419 /** 3420 * Used to indicate that {@link #mAutofillId} was explicitly set through 3421 * {@link #setAutofillId(AutofillId)}. 3422 */ 3423 private static final int PFLAG3_AUTOFILLID_EXPLICITLY_SET = 0x40000000; 3424 3425 /** 3426 * Indicates if the View is a heading for accessibility purposes 3427 */ 3428 private static final int PFLAG3_ACCESSIBILITY_HEADING = 0x80000000; 3429 3430 /* End of masks for mPrivateFlags3 */ 3431 3432 /* 3433 * Masks for mPrivateFlags4, as generated by dumpFlags(): 3434 * 3435 * |-------|-------|-------|-------| 3436 * 1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK 3437 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED 3438 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED 3439 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3440 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE 3441 * 11 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK 3442 * |-------|-------|-------|-------| 3443 */ 3444 3445 /** 3446 * Mask for obtaining the bits which specify how to determine 3447 * whether a view is important for autofill. 3448 * 3449 * <p>NOTE: the important for content capture values were the first flags added and are set in 3450 * the rightmost position, so we don't need to shift them 3451 */ 3452 private static final int PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK = 3453 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO | IMPORTANT_FOR_CONTENT_CAPTURE_YES 3454 | IMPORTANT_FOR_CONTENT_CAPTURE_NO 3455 | IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 3456 | IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS; 3457 3458 /* 3459 * Variables used to control when the IntelligenceManager.notifyNodeAdded()/removed() methods 3460 * should be called. 3461 * 3462 * The idea is to call notifyAppeared() after the view is layout and visible, then call 3463 * notifyDisappeared() when it's gone (without known when it was removed from the parent). 3464 */ 3465 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10; 3466 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20; 3467 3468 /* 3469 * Flags used to cache the value returned by isImportantForContentCapture while the view 3470 * hierarchy is being traversed. 3471 */ 3472 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED = 0x40; 3473 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE = 0x80; 3474 3475 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK = 3476 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3477 | PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 3478 3479 /* End of masks for mPrivateFlags4 */ 3480 3481 /** @hide */ 3482 protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0; 3483 /** @hide */ 3484 protected static final int VIEW_STRUCTURE_FOR_AUTOFILL = 1; 3485 /** @hide */ 3486 protected static final int VIEW_STRUCTURE_FOR_CONTENT_CAPTURE = 2; 3487 3488 /** @hide */ 3489 @IntDef(flag = true, prefix = { "VIEW_STRUCTURE_FOR" }, value = { 3490 VIEW_STRUCTURE_FOR_ASSIST, 3491 VIEW_STRUCTURE_FOR_AUTOFILL, 3492 VIEW_STRUCTURE_FOR_CONTENT_CAPTURE 3493 }) 3494 @Retention(RetentionPolicy.SOURCE) 3495 public @interface ViewStructureType {} 3496 3497 /** 3498 * Always allow a user to over-scroll this view, provided it is a 3499 * view that can scroll. 3500 * 3501 * @see #getOverScrollMode() 3502 * @see #setOverScrollMode(int) 3503 */ 3504 public static final int OVER_SCROLL_ALWAYS = 0; 3505 3506 /** 3507 * Allow a user to over-scroll this view only if the content is large 3508 * enough to meaningfully scroll, provided it is a view that can scroll. 3509 * 3510 * @see #getOverScrollMode() 3511 * @see #setOverScrollMode(int) 3512 */ 3513 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 3514 3515 /** 3516 * Never allow a user to over-scroll this view. 3517 * 3518 * @see #getOverScrollMode() 3519 * @see #setOverScrollMode(int) 3520 */ 3521 public static final int OVER_SCROLL_NEVER = 2; 3522 3523 /** 3524 * Special constant for {@link #setSystemUiVisibility(int)}: View has 3525 * requested the system UI (status bar) to be visible (the default). 3526 * 3527 * @see #setSystemUiVisibility(int) 3528 */ 3529 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 3530 3531 /** 3532 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 3533 * system UI to enter an unobtrusive "low profile" mode. 3534 * 3535 * <p>This is for use in games, book readers, video players, or any other 3536 * "immersive" application where the usual system chrome is deemed too distracting. 3537 * 3538 * <p>In low profile mode, the status bar and/or navigation icons may dim. 3539 * 3540 * @see #setSystemUiVisibility(int) 3541 */ 3542 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 3543 3544 /** 3545 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 3546 * system navigation be temporarily hidden. 3547 * 3548 * <p>This is an even less obtrusive state than that called for by 3549 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 3550 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 3551 * those to disappear. This is useful (in conjunction with the 3552 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 3553 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 3554 * window flags) for displaying content using every last pixel on the display. 3555 * 3556 * <p>There is a limitation: because navigation controls are so important, the least user 3557 * interaction will cause them to reappear immediately. When this happens, both 3558 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 3559 * so that both elements reappear at the same time. 3560 * 3561 * @see #setSystemUiVisibility(int) 3562 */ 3563 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 3564 3565 /** 3566 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 3567 * into the normal fullscreen mode so that its content can take over the screen 3568 * while still allowing the user to interact with the application. 3569 * 3570 * <p>This has the same visual effect as 3571 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 3572 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 3573 * meaning that non-critical screen decorations (such as the status bar) will be 3574 * hidden while the user is in the View's window, focusing the experience on 3575 * that content. Unlike the window flag, if you are using ActionBar in 3576 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3577 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 3578 * hide the action bar. 3579 * 3580 * <p>This approach to going fullscreen is best used over the window flag when 3581 * it is a transient state -- that is, the application does this at certain 3582 * points in its user interaction where it wants to allow the user to focus 3583 * on content, but not as a continuous state. For situations where the application 3584 * would like to simply stay full screen the entire time (such as a game that 3585 * wants to take over the screen), the 3586 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 3587 * is usually a better approach. The state set here will be removed by the system 3588 * in various situations (such as the user moving to another application) like 3589 * the other system UI states. 3590 * 3591 * <p>When using this flag, the application should provide some easy facility 3592 * for the user to go out of it. A common example would be in an e-book 3593 * reader, where tapping on the screen brings back whatever screen and UI 3594 * decorations that had been hidden while the user was immersed in reading 3595 * the book. 3596 * 3597 * @see #setSystemUiVisibility(int) 3598 */ 3599 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 3600 3601 /** 3602 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 3603 * flags, we would like a stable view of the content insets given to 3604 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 3605 * will always represent the worst case that the application can expect 3606 * as a continuous state. In the stock Android UI this is the space for 3607 * the system bar, nav bar, and status bar, but not more transient elements 3608 * such as an input method. 3609 * 3610 * The stable layout your UI sees is based on the system UI modes you can 3611 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 3612 * then you will get a stable layout for changes of the 3613 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 3614 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 3615 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 3616 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 3617 * with a stable layout. (Note that you should avoid using 3618 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 3619 * 3620 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 3621 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 3622 * then a hidden status bar will be considered a "stable" state for purposes 3623 * here. This allows your UI to continually hide the status bar, while still 3624 * using the system UI flags to hide the action bar while still retaining 3625 * a stable layout. Note that changing the window fullscreen flag will never 3626 * provide a stable layout for a clean transition. 3627 * 3628 * <p>If you are using ActionBar in 3629 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3630 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 3631 * insets it adds to those given to the application. 3632 */ 3633 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 3634 3635 /** 3636 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3637 * to be laid out as if it has requested 3638 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 3639 * allows it to avoid artifacts when switching in and out of that mode, at 3640 * the expense that some of its user interface may be covered by screen 3641 * decorations when they are shown. You can perform layout of your inner 3642 * UI elements to account for the navigation system UI through the 3643 * {@link #fitSystemWindows(Rect)} method. 3644 */ 3645 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 3646 3647 /** 3648 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3649 * to be laid out as if it has requested 3650 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 3651 * allows it to avoid artifacts when switching in and out of that mode, at 3652 * the expense that some of its user interface may be covered by screen 3653 * decorations when they are shown. You can perform layout of your inner 3654 * UI elements to account for non-fullscreen system UI through the 3655 * {@link #fitSystemWindows(Rect)} method. 3656 * 3657 * <p>Note: on displays that have a {@link DisplayCutout}, the window may still be placed 3658 * differently than if {@link #SYSTEM_UI_FLAG_FULLSCREEN} was set, if the 3659 * window's {@link WindowManager.LayoutParams#layoutInDisplayCutoutMode 3660 * layoutInDisplayCutoutMode} is 3661 * {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3662 * LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT}. To avoid this, use either of the other modes. 3663 * 3664 * @see WindowManager.LayoutParams#layoutInDisplayCutoutMode 3665 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3666 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 3667 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 3668 */ 3669 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 3670 3671 /** 3672 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3673 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 3674 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 3675 * user interaction. 3676 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 3677 * has an effect when used in combination with that flag.</p> 3678 */ 3679 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 3680 3681 /** 3682 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3683 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 3684 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 3685 * experience while also hiding the system bars. If this flag is not set, 3686 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 3687 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 3688 * if the user swipes from the top of the screen. 3689 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 3690 * system gestures, such as swiping from the top of the screen. These transient system bars 3691 * will overlay app's content, may have some degree of transparency, and will automatically 3692 * hide after a short timeout. 3693 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 3694 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 3695 * with one or both of those flags.</p> 3696 */ 3697 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 3698 3699 /** 3700 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 3701 * is compatible with light status bar backgrounds. 3702 * 3703 * <p>For this to take effect, the window must request 3704 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3705 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3706 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 3707 * FLAG_TRANSLUCENT_STATUS}. 3708 * 3709 * @see android.R.attr#windowLightStatusBar 3710 */ 3711 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 3712 3713 /** 3714 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3715 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3716 */ 3717 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 3718 3719 /** 3720 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3721 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3722 */ 3723 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 3724 3725 /** 3726 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 3727 * that is compatible with light navigation bar backgrounds. 3728 * 3729 * <p>For this to take effect, the window must request 3730 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3731 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3732 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 3733 * FLAG_TRANSLUCENT_NAVIGATION}. 3734 * 3735 * @see android.R.attr#windowLightNavigationBar 3736 */ 3737 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 3738 3739 /** 3740 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 3741 */ 3742 @Deprecated 3743 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 3744 3745 /** 3746 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3747 */ 3748 @Deprecated 3749 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 3750 3751 /** 3752 * @hide 3753 * 3754 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3755 * out of the public fields to keep the undefined bits out of the developer's way. 3756 * 3757 * Flag to make the status bar not expandable. Unless you also 3758 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3759 */ 3760 @UnsupportedAppUsage 3761 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3762 3763 /** 3764 * @hide 3765 * 3766 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3767 * out of the public fields to keep the undefined bits out of the developer's way. 3768 * 3769 * Flag to hide notification icons and scrolling ticker text. 3770 */ 3771 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3772 3773 /** 3774 * @hide 3775 * 3776 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3777 * out of the public fields to keep the undefined bits out of the developer's way. 3778 * 3779 * Flag to disable incoming notification alerts. This will not block 3780 * icons, but it will block sound, vibrating and other visual or aural notifications. 3781 */ 3782 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3783 3784 /** 3785 * @hide 3786 * 3787 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3788 * out of the public fields to keep the undefined bits out of the developer's way. 3789 * 3790 * Flag to hide only the scrolling ticker. Note that 3791 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3792 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3793 */ 3794 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3795 3796 /** 3797 * @hide 3798 * 3799 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3800 * out of the public fields to keep the undefined bits out of the developer's way. 3801 * 3802 * Flag to hide the center system info area. 3803 */ 3804 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3805 3806 /** 3807 * @hide 3808 * 3809 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3810 * out of the public fields to keep the undefined bits out of the developer's way. 3811 * 3812 * Flag to hide only the home button. Don't use this 3813 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3814 */ 3815 @UnsupportedAppUsage 3816 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3817 3818 /** 3819 * @hide 3820 * 3821 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3822 * out of the public fields to keep the undefined bits out of the developer's way. 3823 * 3824 * Flag to hide only the back button. Don't use this 3825 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3826 */ 3827 @UnsupportedAppUsage 3828 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3829 3830 /** 3831 * @hide 3832 * 3833 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3834 * out of the public fields to keep the undefined bits out of the developer's way. 3835 * 3836 * Flag to hide only the clock. You might use this if your activity has 3837 * its own clock making the status bar's clock redundant. 3838 */ 3839 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3840 3841 /** 3842 * @hide 3843 * 3844 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3845 * out of the public fields to keep the undefined bits out of the developer's way. 3846 * 3847 * Flag to hide only the recent apps button. Don't use this 3848 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3849 */ 3850 @UnsupportedAppUsage 3851 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3852 3853 /** 3854 * @hide 3855 * 3856 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3857 * out of the public fields to keep the undefined bits out of the developer's way. 3858 * 3859 * Flag to disable the global search gesture. Don't use this 3860 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3861 */ 3862 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3863 3864 /** 3865 * @hide 3866 * 3867 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3868 * out of the public fields to keep the undefined bits out of the developer's way. 3869 * 3870 * Flag to specify that the status bar is displayed in transient mode. 3871 */ 3872 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3873 3874 /** 3875 * @hide 3876 * 3877 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3878 * out of the public fields to keep the undefined bits out of the developer's way. 3879 * 3880 * Flag to specify that the navigation bar is displayed in transient mode. 3881 */ 3882 @UnsupportedAppUsage 3883 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3884 3885 /** 3886 * @hide 3887 * 3888 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3889 * out of the public fields to keep the undefined bits out of the developer's way. 3890 * 3891 * Flag to specify that the hidden status bar would like to be shown. 3892 */ 3893 public static final int STATUS_BAR_UNHIDE = 0x10000000; 3894 3895 /** 3896 * @hide 3897 * 3898 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3899 * out of the public fields to keep the undefined bits out of the developer's way. 3900 * 3901 * Flag to specify that the hidden navigation bar would like to be shown. 3902 */ 3903 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 3904 3905 /** 3906 * @hide 3907 * 3908 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3909 * out of the public fields to keep the undefined bits out of the developer's way. 3910 * 3911 * Flag to specify that the status bar is displayed in translucent mode. 3912 */ 3913 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 3914 3915 /** 3916 * @hide 3917 * 3918 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3919 * out of the public fields to keep the undefined bits out of the developer's way. 3920 * 3921 * Flag to specify that the navigation bar is displayed in translucent mode. 3922 */ 3923 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 3924 3925 /** 3926 * @hide 3927 * 3928 * Makes navigation bar transparent (but not the status bar). 3929 */ 3930 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 3931 3932 /** 3933 * @hide 3934 * 3935 * Makes status bar transparent (but not the navigation bar). 3936 */ 3937 public static final int STATUS_BAR_TRANSPARENT = 0x00000008; 3938 3939 /** 3940 * @hide 3941 * 3942 * Makes both status bar and navigation bar transparent. 3943 */ 3944 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 3945 | STATUS_BAR_TRANSPARENT; 3946 3947 /** 3948 * @hide 3949 */ 3950 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 3951 3952 /** 3953 * These are the system UI flags that can be cleared by events outside 3954 * of an application. Currently this is just the ability to tap on the 3955 * screen while hiding the navigation bar to have it return. 3956 * @hide 3957 */ 3958 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 3959 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 3960 | SYSTEM_UI_FLAG_FULLSCREEN; 3961 3962 /** 3963 * Flags that can impact the layout in relation to system UI. 3964 */ 3965 public static final int SYSTEM_UI_LAYOUT_FLAGS = 3966 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 3967 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 3968 3969 /** @hide */ 3970 @IntDef(flag = true, prefix = { "FIND_VIEWS_" }, value = { 3971 FIND_VIEWS_WITH_TEXT, 3972 FIND_VIEWS_WITH_CONTENT_DESCRIPTION 3973 }) 3974 @Retention(RetentionPolicy.SOURCE) 3975 public @interface FindViewFlags {} 3976 3977 /** 3978 * Find views that render the specified text. 3979 * 3980 * @see #findViewsWithText(ArrayList, CharSequence, int) 3981 */ 3982 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 3983 3984 /** 3985 * Find find views that contain the specified content description. 3986 * 3987 * @see #findViewsWithText(ArrayList, CharSequence, int) 3988 */ 3989 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 3990 3991 /** 3992 * Find views that contain {@link AccessibilityNodeProvider}. Such 3993 * a View is a root of virtual view hierarchy and may contain the searched 3994 * text. If this flag is set Views with providers are automatically 3995 * added and it is a responsibility of the client to call the APIs of 3996 * the provider to determine whether the virtual tree rooted at this View 3997 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 3998 * representing the virtual views with this text. 3999 * 4000 * @see #findViewsWithText(ArrayList, CharSequence, int) 4001 * 4002 * @hide 4003 */ 4004 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 4005 4006 /** 4007 * The undefined cursor position. 4008 * 4009 * @hide 4010 */ 4011 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 4012 4013 /** 4014 * Indicates that the screen has changed state and is now off. 4015 * 4016 * @see #onScreenStateChanged(int) 4017 */ 4018 public static final int SCREEN_STATE_OFF = 0x0; 4019 4020 /** 4021 * Indicates that the screen has changed state and is now on. 4022 * 4023 * @see #onScreenStateChanged(int) 4024 */ 4025 public static final int SCREEN_STATE_ON = 0x1; 4026 4027 /** 4028 * Indicates no axis of view scrolling. 4029 */ 4030 public static final int SCROLL_AXIS_NONE = 0; 4031 4032 /** 4033 * Indicates scrolling along the horizontal axis. 4034 */ 4035 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 4036 4037 /** 4038 * Indicates scrolling along the vertical axis. 4039 */ 4040 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 4041 4042 /** 4043 * Controls the over-scroll mode for this view. 4044 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 4045 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 4046 * and {@link #OVER_SCROLL_NEVER}. 4047 */ 4048 private int mOverScrollMode; 4049 4050 /** 4051 * The parent this view is attached to. 4052 * {@hide} 4053 * 4054 * @see #getParent() 4055 */ 4056 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4057 protected ViewParent mParent; 4058 4059 /** 4060 * {@hide} 4061 * 4062 * Not available for general use. If you need help, hang up and then dial one of the following 4063 * public APIs: 4064 * 4065 * @see #isAttachedToWindow() for current attach state 4066 * @see #onAttachedToWindow() for subclasses performing work when becoming attached 4067 * @see #onDetachedFromWindow() for subclasses performing work when becoming detached 4068 * @see OnAttachStateChangeListener for other code performing work on attach/detach 4069 * @see #getHandler() for posting messages to this view's UI thread/looper 4070 * @see #getParent() for interacting with the parent chain 4071 * @see #getWindowToken() for the current window token 4072 * @see #getRootView() for the view at the root of the attached hierarchy 4073 * @see #getDisplay() for the Display this view is presented on 4074 * @see #getRootWindowInsets() for the current insets applied to the whole attached window 4075 * @see #hasWindowFocus() for whether the attached window is currently focused 4076 * @see #getWindowVisibility() for checking the visibility of the attached window 4077 */ 4078 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4079 AttachInfo mAttachInfo; 4080 4081 /** 4082 * {@hide} 4083 */ 4084 @ViewDebug.ExportedProperty(flagMapping = { 4085 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 4086 name = "FORCE_LAYOUT"), 4087 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 4088 name = "LAYOUT_REQUIRED"), 4089 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 4090 name = "DRAWING_CACHE_INVALID", outputIf = false), 4091 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 4092 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 4093 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 4094 }, formatToHexString = true) 4095 4096 /* @hide */ 4097 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769414) 4098 public int mPrivateFlags; 4099 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768943) 4100 int mPrivateFlags2; 4101 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 129147060) 4102 int mPrivateFlags3; 4103 4104 private int mPrivateFlags4; 4105 4106 /** 4107 * This view's request for the visibility of the status bar. 4108 * @hide 4109 */ 4110 @ViewDebug.ExportedProperty(flagMapping = { 4111 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 4112 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 4113 name = "LOW_PROFILE"), 4114 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4115 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4116 name = "HIDE_NAVIGATION"), 4117 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_FULLSCREEN, 4118 equals = SYSTEM_UI_FLAG_FULLSCREEN, 4119 name = "FULLSCREEN"), 4120 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4121 equals = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4122 name = "LAYOUT_STABLE"), 4123 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4124 equals = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4125 name = "LAYOUT_HIDE_NAVIGATION"), 4126 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4127 equals = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4128 name = "LAYOUT_FULLSCREEN"), 4129 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE, 4130 equals = SYSTEM_UI_FLAG_IMMERSIVE, 4131 name = "IMMERSIVE"), 4132 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4133 equals = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4134 name = "IMMERSIVE_STICKY"), 4135 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4136 equals = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4137 name = "LIGHT_STATUS_BAR"), 4138 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4139 equals = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4140 name = "LIGHT_NAVIGATION_BAR"), 4141 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_EXPAND, 4142 equals = STATUS_BAR_DISABLE_EXPAND, 4143 name = "STATUS_BAR_DISABLE_EXPAND"), 4144 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4145 equals = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4146 name = "STATUS_BAR_DISABLE_NOTIFICATION_ICONS"), 4147 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4148 equals = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4149 name = "STATUS_BAR_DISABLE_NOTIFICATION_ALERTS"), 4150 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4151 equals = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4152 name = "STATUS_BAR_DISABLE_NOTIFICATION_TICKER"), 4153 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SYSTEM_INFO, 4154 equals = STATUS_BAR_DISABLE_SYSTEM_INFO, 4155 name = "STATUS_BAR_DISABLE_SYSTEM_INFO"), 4156 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_HOME, 4157 equals = STATUS_BAR_DISABLE_HOME, 4158 name = "STATUS_BAR_DISABLE_HOME"), 4159 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_BACK, 4160 equals = STATUS_BAR_DISABLE_BACK, 4161 name = "STATUS_BAR_DISABLE_BACK"), 4162 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_CLOCK, 4163 equals = STATUS_BAR_DISABLE_CLOCK, 4164 name = "STATUS_BAR_DISABLE_CLOCK"), 4165 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_RECENT, 4166 equals = STATUS_BAR_DISABLE_RECENT, 4167 name = "STATUS_BAR_DISABLE_RECENT"), 4168 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH, 4169 equals = STATUS_BAR_DISABLE_SEARCH, 4170 name = "STATUS_BAR_DISABLE_SEARCH"), 4171 @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSIENT, 4172 equals = STATUS_BAR_TRANSIENT, 4173 name = "STATUS_BAR_TRANSIENT"), 4174 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSIENT, 4175 equals = NAVIGATION_BAR_TRANSIENT, 4176 name = "NAVIGATION_BAR_TRANSIENT"), 4177 @ViewDebug.FlagToString(mask = STATUS_BAR_UNHIDE, 4178 equals = STATUS_BAR_UNHIDE, 4179 name = "STATUS_BAR_UNHIDE"), 4180 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_UNHIDE, 4181 equals = NAVIGATION_BAR_UNHIDE, 4182 name = "NAVIGATION_BAR_UNHIDE"), 4183 @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSLUCENT, 4184 equals = STATUS_BAR_TRANSLUCENT, 4185 name = "STATUS_BAR_TRANSLUCENT"), 4186 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSLUCENT, 4187 equals = NAVIGATION_BAR_TRANSLUCENT, 4188 name = "NAVIGATION_BAR_TRANSLUCENT"), 4189 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSPARENT, 4190 equals = NAVIGATION_BAR_TRANSPARENT, 4191 name = "NAVIGATION_BAR_TRANSPARENT"), 4192 @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSPARENT, 4193 equals = STATUS_BAR_TRANSPARENT, 4194 name = "STATUS_BAR_TRANSPARENT") 4195 }, formatToHexString = true) 4196 int mSystemUiVisibility; 4197 4198 /** 4199 * Reference count for transient state. 4200 * @see #setHasTransientState(boolean) 4201 */ 4202 int mTransientStateCount = 0; 4203 4204 /** 4205 * Count of how many windows this view has been attached to. 4206 */ 4207 int mWindowAttachCount; 4208 4209 /** 4210 * The layout parameters associated with this view and used by the parent 4211 * {@link android.view.ViewGroup} to determine how this view should be 4212 * laid out. 4213 * 4214 * The field should not be used directly. Instead {@link #getLayoutParams()} and {@link 4215 * #setLayoutParams(ViewGroup.LayoutParams)} should be used. The setter guarantees internal 4216 * state correctness of the class. 4217 * {@hide} 4218 */ 4219 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4220 protected ViewGroup.LayoutParams mLayoutParams; 4221 4222 /** 4223 * The view flags hold various views states. 4224 * 4225 * Use {@link #setTransitionVisibility(int)} to change the visibility of this view without 4226 * triggering updates. 4227 * {@hide} 4228 */ 4229 @ViewDebug.ExportedProperty(formatToHexString = true) 4230 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4231 int mViewFlags; 4232 4233 static class TransformationInfo { 4234 /** 4235 * The transform matrix for the View. This transform is calculated internally 4236 * based on the translation, rotation, and scale properties. 4237 * 4238 * Do *not* use this variable directly; instead call getMatrix(), which will 4239 * load the value from the View's RenderNode. 4240 */ 4241 private final Matrix mMatrix = new Matrix(); 4242 4243 /** 4244 * The inverse transform matrix for the View. This transform is calculated 4245 * internally based on the translation, rotation, and scale properties. 4246 * 4247 * Do *not* use this variable directly; instead call getInverseMatrix(), 4248 * which will load the value from the View's RenderNode. 4249 */ 4250 private Matrix mInverseMatrix; 4251 4252 /** 4253 * The opacity of the View. This is a value from 0 to 1, where 0 means 4254 * completely transparent and 1 means completely opaque. 4255 */ 4256 @ViewDebug.ExportedProperty 4257 private float mAlpha = 1f; 4258 4259 /** 4260 * The opacity of the view as manipulated by the Fade transition. This is a 4261 * property only used by transitions, which is composited with the other alpha 4262 * values to calculate the final visual alpha value. 4263 */ 4264 float mTransitionAlpha = 1f; 4265 } 4266 4267 /** @hide */ 4268 @UnsupportedAppUsage 4269 public TransformationInfo mTransformationInfo; 4270 4271 /** 4272 * Current clip bounds. to which all drawing of this view are constrained. 4273 */ 4274 @ViewDebug.ExportedProperty(category = "drawing") 4275 Rect mClipBounds = null; 4276 4277 private boolean mLastIsOpaque; 4278 4279 /** 4280 * The distance in pixels from the left edge of this view's parent 4281 * to the left edge of this view. 4282 * {@hide} 4283 */ 4284 @ViewDebug.ExportedProperty(category = "layout") 4285 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4286 protected int mLeft; 4287 /** 4288 * The distance in pixels from the left edge of this view's parent 4289 * to the right edge of this view. 4290 * {@hide} 4291 */ 4292 @ViewDebug.ExportedProperty(category = "layout") 4293 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4294 protected int mRight; 4295 /** 4296 * The distance in pixels from the top edge of this view's parent 4297 * to the top edge of this view. 4298 * {@hide} 4299 */ 4300 @ViewDebug.ExportedProperty(category = "layout") 4301 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4302 protected int mTop; 4303 /** 4304 * The distance in pixels from the top edge of this view's parent 4305 * to the bottom edge of this view. 4306 * {@hide} 4307 */ 4308 @ViewDebug.ExportedProperty(category = "layout") 4309 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4310 protected int mBottom; 4311 4312 /** 4313 * The offset, in pixels, by which the content of this view is scrolled 4314 * horizontally. 4315 * Please use {@link View#getScrollX()} and {@link View#setScrollX(int)} instead of 4316 * accessing these directly. 4317 * {@hide} 4318 */ 4319 @ViewDebug.ExportedProperty(category = "scrolling") 4320 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4321 protected int mScrollX; 4322 /** 4323 * The offset, in pixels, by which the content of this view is scrolled 4324 * vertically. 4325 * Please use {@link View#getScrollY()} and {@link View#setScrollY(int)} instead of 4326 * accessing these directly. 4327 * {@hide} 4328 */ 4329 @ViewDebug.ExportedProperty(category = "scrolling") 4330 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4331 protected int mScrollY; 4332 4333 /** 4334 * The final computed left padding in pixels that is used for drawing. This is the distance in 4335 * pixels between the left edge of this view and the left edge of its content. 4336 * {@hide} 4337 */ 4338 @ViewDebug.ExportedProperty(category = "padding") 4339 @UnsupportedAppUsage 4340 protected int mPaddingLeft = 0; 4341 /** 4342 * The final computed right padding in pixels that is used for drawing. This is the distance in 4343 * pixels between the right edge of this view and the right edge of its content. 4344 * {@hide} 4345 */ 4346 @ViewDebug.ExportedProperty(category = "padding") 4347 @UnsupportedAppUsage 4348 protected int mPaddingRight = 0; 4349 /** 4350 * The final computed top padding in pixels that is used for drawing. This is the distance in 4351 * pixels between the top edge of this view and the top edge of its content. 4352 * {@hide} 4353 */ 4354 @ViewDebug.ExportedProperty(category = "padding") 4355 @UnsupportedAppUsage 4356 protected int mPaddingTop; 4357 /** 4358 * The final computed bottom padding in pixels that is used for drawing. This is the distance in 4359 * pixels between the bottom edge of this view and the bottom edge of its content. 4360 * {@hide} 4361 */ 4362 @ViewDebug.ExportedProperty(category = "padding") 4363 @UnsupportedAppUsage 4364 protected int mPaddingBottom; 4365 4366 /** 4367 * The layout insets in pixels, that is the distance in pixels between the 4368 * visible edges of this view its bounds. 4369 */ 4370 private Insets mLayoutInsets; 4371 4372 /** 4373 * Briefly describes the view and is primarily used for accessibility support. 4374 */ 4375 private CharSequence mContentDescription; 4376 4377 /** 4378 * If this view represents a distinct part of the window, it can have a title that labels the 4379 * area. 4380 */ 4381 private CharSequence mAccessibilityPaneTitle; 4382 4383 /** 4384 * Specifies the id of a view for which this view serves as a label for 4385 * accessibility purposes. 4386 */ 4387 private int mLabelForId = View.NO_ID; 4388 4389 /** 4390 * Predicate for matching labeled view id with its label for 4391 * accessibility purposes. 4392 */ 4393 private MatchLabelForPredicate mMatchLabelForPredicate; 4394 4395 /** 4396 * Specifies a view before which this one is visited in accessibility traversal. 4397 */ 4398 private int mAccessibilityTraversalBeforeId = NO_ID; 4399 4400 /** 4401 * Specifies a view after which this one is visited in accessibility traversal. 4402 */ 4403 private int mAccessibilityTraversalAfterId = NO_ID; 4404 4405 /** 4406 * Predicate for matching a view by its id. 4407 */ 4408 private MatchIdPredicate mMatchIdPredicate; 4409 4410 /** 4411 * The right padding after RTL resolution, but before taking account of scroll bars. 4412 * 4413 * @hide 4414 */ 4415 @ViewDebug.ExportedProperty(category = "padding") 4416 protected int mUserPaddingRight; 4417 4418 /** 4419 * The resolved bottom padding before taking account of scroll bars. 4420 * 4421 * @hide 4422 */ 4423 @ViewDebug.ExportedProperty(category = "padding") 4424 protected int mUserPaddingBottom; 4425 4426 /** 4427 * The left padding after RTL resolution, but before taking account of scroll bars. 4428 * 4429 * @hide 4430 */ 4431 @ViewDebug.ExportedProperty(category = "padding") 4432 protected int mUserPaddingLeft; 4433 4434 /** 4435 * Cache the paddingStart set by the user to append to the scrollbar's size. 4436 * 4437 */ 4438 @ViewDebug.ExportedProperty(category = "padding") 4439 int mUserPaddingStart; 4440 4441 /** 4442 * Cache the paddingEnd set by the user to append to the scrollbar's size. 4443 * 4444 */ 4445 @ViewDebug.ExportedProperty(category = "padding") 4446 int mUserPaddingEnd; 4447 4448 /** 4449 * The left padding as set by a setter method, a background's padding, or via XML property 4450 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4451 * 4452 * @hide 4453 */ 4454 int mUserPaddingLeftInitial; 4455 4456 /** 4457 * The right padding as set by a setter method, a background's padding, or via XML property 4458 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4459 * 4460 * @hide 4461 */ 4462 int mUserPaddingRightInitial; 4463 4464 /** 4465 * Default undefined padding 4466 */ 4467 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 4468 4469 /** 4470 * Cache if a left padding has been defined explicitly via padding, horizontal padding, 4471 * or leftPadding in XML, or by setPadding(...) or setRelativePadding(...) 4472 */ 4473 private boolean mLeftPaddingDefined = false; 4474 4475 /** 4476 * Cache if a right padding has been defined explicitly via padding, horizontal padding, 4477 * or rightPadding in XML, or by setPadding(...) or setRelativePadding(...) 4478 */ 4479 private boolean mRightPaddingDefined = false; 4480 4481 /** 4482 * @hide 4483 */ 4484 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 4485 /** 4486 * @hide 4487 */ 4488 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 4489 4490 private LongSparseLongArray mMeasureCache; 4491 4492 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 4493 @UnsupportedAppUsage 4494 private Drawable mBackground; 4495 private TintInfo mBackgroundTint; 4496 4497 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 4498 private ForegroundInfo mForegroundInfo; 4499 4500 private Drawable mScrollIndicatorDrawable; 4501 4502 /** 4503 * RenderNode used for backgrounds. 4504 * <p> 4505 * When non-null and valid, this is expected to contain an up-to-date copy 4506 * of the background drawable. It is cleared on temporary detach, and reset 4507 * on cleanup. 4508 */ 4509 private RenderNode mBackgroundRenderNode; 4510 4511 @UnsupportedAppUsage 4512 private int mBackgroundResource; 4513 private boolean mBackgroundSizeChanged; 4514 4515 /** The default focus highlight. 4516 * @see #mDefaultFocusHighlightEnabled 4517 * @see Drawable#hasFocusStateSpecified() 4518 */ 4519 private Drawable mDefaultFocusHighlight; 4520 private Drawable mDefaultFocusHighlightCache; 4521 private boolean mDefaultFocusHighlightSizeChanged; 4522 /** 4523 * True if the default focus highlight is needed on the target device. 4524 */ 4525 private static boolean sUseDefaultFocusHighlight; 4526 4527 /** 4528 * True if zero-sized views can be focused. 4529 */ 4530 private static boolean sCanFocusZeroSized; 4531 4532 /** 4533 * Always assign focus if a focusable View is available. 4534 */ 4535 private static boolean sAlwaysAssignFocus; 4536 4537 private String mTransitionName; 4538 4539 static class TintInfo { 4540 ColorStateList mTintList; 4541 BlendMode mBlendMode; 4542 boolean mHasTintMode; 4543 boolean mHasTintList; 4544 } 4545 4546 private static class ForegroundInfo { 4547 private Drawable mDrawable; 4548 private TintInfo mTintInfo; 4549 private int mGravity = Gravity.FILL; 4550 private boolean mInsidePadding = true; 4551 private boolean mBoundsChanged = true; 4552 private final Rect mSelfBounds = new Rect(); 4553 private final Rect mOverlayBounds = new Rect(); 4554 } 4555 4556 static class ListenerInfo { 4557 4558 @UnsupportedAppUsage ListenerInfo()4559 ListenerInfo() { 4560 } 4561 4562 /** 4563 * Listener used to dispatch focus change events. 4564 * This field should be made private, so it is hidden from the SDK. 4565 * {@hide} 4566 */ 4567 @UnsupportedAppUsage 4568 protected OnFocusChangeListener mOnFocusChangeListener; 4569 4570 /** 4571 * Listeners for layout change events. 4572 */ 4573 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 4574 4575 protected OnScrollChangeListener mOnScrollChangeListener; 4576 4577 /** 4578 * Listeners for attach events. 4579 */ 4580 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 4581 4582 /** 4583 * Listener used to dispatch click events. 4584 * This field should be made private, so it is hidden from the SDK. 4585 * {@hide} 4586 */ 4587 @UnsupportedAppUsage 4588 public OnClickListener mOnClickListener; 4589 4590 /** 4591 * Listener used to dispatch long click events. 4592 * This field should be made private, so it is hidden from the SDK. 4593 * {@hide} 4594 */ 4595 @UnsupportedAppUsage 4596 protected OnLongClickListener mOnLongClickListener; 4597 4598 /** 4599 * Listener used to dispatch context click events. This field should be made private, so it 4600 * is hidden from the SDK. 4601 * {@hide} 4602 */ 4603 protected OnContextClickListener mOnContextClickListener; 4604 4605 /** 4606 * Listener used to build the context menu. 4607 * This field should be made private, so it is hidden from the SDK. 4608 * {@hide} 4609 */ 4610 @UnsupportedAppUsage 4611 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 4612 4613 @UnsupportedAppUsage 4614 private OnKeyListener mOnKeyListener; 4615 4616 @UnsupportedAppUsage 4617 private OnTouchListener mOnTouchListener; 4618 4619 @UnsupportedAppUsage 4620 private OnHoverListener mOnHoverListener; 4621 4622 @UnsupportedAppUsage 4623 private OnGenericMotionListener mOnGenericMotionListener; 4624 4625 @UnsupportedAppUsage 4626 private OnDragListener mOnDragListener; 4627 4628 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 4629 4630 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 4631 4632 OnCapturedPointerListener mOnCapturedPointerListener; 4633 4634 private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners; 4635 4636 private WindowInsetsAnimationListener mWindowInsetsAnimationListener; 4637 4638 /** 4639 * This lives here since it's only valid for interactive views. 4640 */ 4641 private List<Rect> mSystemGestureExclusionRects; 4642 4643 /** 4644 * Used to track {@link #mSystemGestureExclusionRects} 4645 */ 4646 public RenderNode.PositionUpdateListener mPositionUpdateListener; 4647 } 4648 4649 @UnsupportedAppUsage 4650 ListenerInfo mListenerInfo; 4651 4652 private static class TooltipInfo { 4653 /** 4654 * Text to be displayed in a tooltip popup. 4655 */ 4656 @Nullable 4657 CharSequence mTooltipText; 4658 4659 /** 4660 * View-relative position of the tooltip anchor point. 4661 */ 4662 int mAnchorX; 4663 int mAnchorY; 4664 4665 /** 4666 * The tooltip popup. 4667 */ 4668 @Nullable 4669 TooltipPopup mTooltipPopup; 4670 4671 /** 4672 * Set to true if the tooltip was shown as a result of a long click. 4673 */ 4674 boolean mTooltipFromLongClick; 4675 4676 /** 4677 * Keep these Runnables so that they can be used to reschedule. 4678 */ 4679 Runnable mShowTooltipRunnable; 4680 Runnable mHideTooltipRunnable; 4681 4682 /** 4683 * Hover move is ignored if it is within this distance in pixels from the previous one. 4684 */ 4685 int mHoverSlop; 4686 4687 /** 4688 * Update the anchor position if it significantly (that is by at least mHoverSlop) 4689 * different from the previously stored position. Ignoring insignificant changes 4690 * filters out the jitter which is typical for such input sources as stylus. 4691 * 4692 * @return True if the position has been updated. 4693 */ updateAnchorPos(MotionEvent event)4694 private boolean updateAnchorPos(MotionEvent event) { 4695 final int newAnchorX = (int) event.getX(); 4696 final int newAnchorY = (int) event.getY(); 4697 if (Math.abs(newAnchorX - mAnchorX) <= mHoverSlop 4698 && Math.abs(newAnchorY - mAnchorY) <= mHoverSlop) { 4699 return false; 4700 } 4701 mAnchorX = newAnchorX; 4702 mAnchorY = newAnchorY; 4703 return true; 4704 } 4705 4706 /** 4707 * Clear the anchor position to ensure that the next change is considered significant. 4708 */ clearAnchorPos()4709 private void clearAnchorPos() { 4710 mAnchorX = Integer.MAX_VALUE; 4711 mAnchorY = Integer.MAX_VALUE; 4712 } 4713 } 4714 4715 TooltipInfo mTooltipInfo; 4716 4717 // Temporary values used to hold (x,y) coordinates when delegating from the 4718 // two-arg performLongClick() method to the legacy no-arg version. 4719 private float mLongClickX = Float.NaN; 4720 private float mLongClickY = Float.NaN; 4721 4722 /** 4723 * The application environment this view lives in. 4724 * This field should be made private, so it is hidden from the SDK. 4725 * {@hide} 4726 */ 4727 @ViewDebug.ExportedProperty(deepExport = true) 4728 @UnsupportedAppUsage 4729 protected Context mContext; 4730 4731 @UnsupportedAppUsage 4732 private final Resources mResources; 4733 4734 @UnsupportedAppUsage 4735 private ScrollabilityCache mScrollCache; 4736 4737 private int[] mDrawableState = null; 4738 4739 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 4740 4741 /** 4742 * Animator that automatically runs based on state changes. 4743 */ 4744 private StateListAnimator mStateListAnimator; 4745 4746 /** 4747 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 4748 * the user may specify which view to go to next. 4749 */ 4750 private int mNextFocusLeftId = View.NO_ID; 4751 4752 /** 4753 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 4754 * the user may specify which view to go to next. 4755 */ 4756 private int mNextFocusRightId = View.NO_ID; 4757 4758 /** 4759 * When this view has focus and the next focus is {@link #FOCUS_UP}, 4760 * the user may specify which view to go to next. 4761 */ 4762 private int mNextFocusUpId = View.NO_ID; 4763 4764 /** 4765 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 4766 * the user may specify which view to go to next. 4767 */ 4768 private int mNextFocusDownId = View.NO_ID; 4769 4770 /** 4771 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 4772 * the user may specify which view to go to next. 4773 */ 4774 int mNextFocusForwardId = View.NO_ID; 4775 4776 /** 4777 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction. 4778 * 4779 * @see #findUserSetNextKeyboardNavigationCluster(View, int) 4780 */ 4781 int mNextClusterForwardId = View.NO_ID; 4782 4783 /** 4784 * Whether this View should use a default focus highlight when it gets focused but doesn't 4785 * have {@link android.R.attr#state_focused} defined in its background. 4786 */ 4787 boolean mDefaultFocusHighlightEnabled = true; 4788 4789 private CheckForLongPress mPendingCheckForLongPress; 4790 @UnsupportedAppUsage 4791 private CheckForTap mPendingCheckForTap = null; 4792 private PerformClick mPerformClick; 4793 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 4794 4795 private UnsetPressedState mUnsetPressedState; 4796 4797 /** 4798 * Whether the long press's action has been invoked. The tap's action is invoked on the 4799 * up event while a long press is invoked as soon as the long press duration is reached, so 4800 * a long press could be performed before the tap is checked, in which case the tap's action 4801 * should not be invoked. 4802 */ 4803 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 4804 private boolean mHasPerformedLongPress; 4805 4806 /** 4807 * Whether a context click button is currently pressed down. This is true when the stylus is 4808 * touching the screen and the primary button has been pressed, or if a mouse's right button is 4809 * pressed. This is false once the button is released or if the stylus has been lifted. 4810 */ 4811 private boolean mInContextButtonPress; 4812 4813 /** 4814 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 4815 * true after a stylus button press has occured, when the next up event should not be recognized 4816 * as a tap. 4817 */ 4818 private boolean mIgnoreNextUpEvent; 4819 4820 /** 4821 * The minimum height of the view. We'll try our best to have the height 4822 * of this view to at least this amount. 4823 */ 4824 @ViewDebug.ExportedProperty(category = "measurement") 4825 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4826 private int mMinHeight; 4827 4828 /** 4829 * The minimum width of the view. We'll try our best to have the width 4830 * of this view to at least this amount. 4831 */ 4832 @ViewDebug.ExportedProperty(category = "measurement") 4833 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4834 private int mMinWidth; 4835 4836 /** 4837 * The delegate to handle touch events that are physically in this view 4838 * but should be handled by another view. 4839 */ 4840 private TouchDelegate mTouchDelegate = null; 4841 4842 /** 4843 * While touch exploration is in use, set to true when hovering across boundaries and 4844 * inside the touch area of the delegate at receiving {@link MotionEvent#ACTION_HOVER_ENTER} 4845 * or {@link MotionEvent#ACTION_HOVER_MOVE}. False when leaving boundaries or receiving a 4846 * {@link MotionEvent#ACTION_HOVER_EXIT}. 4847 * Note that children of view group are excluded in the touch area. 4848 * @see #dispatchTouchExplorationHoverEvent 4849 */ 4850 private boolean mHoveringTouchDelegate = false; 4851 4852 /** 4853 * Solid color to use as a background when creating the drawing cache. Enables 4854 * the cache to use 16 bit bitmaps instead of 32 bit. 4855 */ 4856 private int mDrawingCacheBackgroundColor = 0; 4857 4858 /** 4859 * Special tree observer used when mAttachInfo is null. 4860 */ 4861 private ViewTreeObserver mFloatingTreeObserver; 4862 4863 /** 4864 * Cache the touch slop from the context that created the view. 4865 */ 4866 private int mTouchSlop; 4867 4868 /** 4869 * Object that handles automatic animation of view properties. 4870 */ 4871 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 4872 private ViewPropertyAnimator mAnimator = null; 4873 4874 /** 4875 * List of registered FrameMetricsObservers. 4876 */ 4877 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 4878 4879 /** 4880 * Flag indicating that a drag can cross window boundaries. When 4881 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4882 * with this flag set, all visible applications with targetSdkVersion >= 4883 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 4884 * in the drag operation and receive the dragged content. 4885 * 4886 * <p>If this is the only flag set, then the drag recipient will only have access to text data 4887 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 4888 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 4889 */ 4890 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 4891 4892 /** 4893 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4894 * request read access to the content URI(s) contained in the {@link ClipData} object. 4895 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION 4896 */ 4897 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 4898 4899 /** 4900 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 4901 * request write access to the content URI(s) contained in the {@link ClipData} object. 4902 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION 4903 */ 4904 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 4905 4906 /** 4907 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4908 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 4909 * reboots until explicitly revoked with 4910 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}. 4911 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION 4912 */ 4913 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 4914 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 4915 4916 /** 4917 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 4918 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 4919 * match against the original granted URI. 4920 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION 4921 */ 4922 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 4923 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 4924 4925 /** 4926 * Flag indicating that the drag shadow will be opaque. When 4927 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 4928 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 4929 */ 4930 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 4931 4932 /** 4933 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 4934 */ 4935 private float mVerticalScrollFactor; 4936 4937 /** 4938 * Position of the vertical scroll bar. 4939 */ 4940 @UnsupportedAppUsage 4941 private int mVerticalScrollbarPosition; 4942 4943 /** 4944 * Position the scroll bar at the default position as determined by the system. 4945 */ 4946 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 4947 4948 /** 4949 * Position the scroll bar along the left edge. 4950 */ 4951 public static final int SCROLLBAR_POSITION_LEFT = 1; 4952 4953 /** 4954 * Position the scroll bar along the right edge. 4955 */ 4956 public static final int SCROLLBAR_POSITION_RIGHT = 2; 4957 4958 /** 4959 * Indicates that the view does not have a layer. 4960 * 4961 * @see #getLayerType() 4962 * @see #setLayerType(int, android.graphics.Paint) 4963 * @see #LAYER_TYPE_SOFTWARE 4964 * @see #LAYER_TYPE_HARDWARE 4965 */ 4966 public static final int LAYER_TYPE_NONE = 0; 4967 4968 /** 4969 * <p>Indicates that the view has a software layer. A software layer is backed 4970 * by a bitmap and causes the view to be rendered using Android's software 4971 * rendering pipeline, even if hardware acceleration is enabled.</p> 4972 * 4973 * <p>Software layers have various usages:</p> 4974 * <p>When the application is not using hardware acceleration, a software layer 4975 * is useful to apply a specific color filter and/or blending mode and/or 4976 * translucency to a view and all its children.</p> 4977 * <p>When the application is using hardware acceleration, a software layer 4978 * is useful to render drawing primitives not supported by the hardware 4979 * accelerated pipeline. It can also be used to cache a complex view tree 4980 * into a texture and reduce the complexity of drawing operations. For instance, 4981 * when animating a complex view tree with a translation, a software layer can 4982 * be used to render the view tree only once.</p> 4983 * <p>Software layers should be avoided when the affected view tree updates 4984 * often. Every update will require to re-render the software layer, which can 4985 * potentially be slow (particularly when hardware acceleration is turned on 4986 * since the layer will have to be uploaded into a hardware texture after every 4987 * update.)</p> 4988 * 4989 * @see #getLayerType() 4990 * @see #setLayerType(int, android.graphics.Paint) 4991 * @see #LAYER_TYPE_NONE 4992 * @see #LAYER_TYPE_HARDWARE 4993 */ 4994 public static final int LAYER_TYPE_SOFTWARE = 1; 4995 4996 /** 4997 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 4998 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 4999 * OpenGL hardware) and causes the view to be rendered using Android's hardware 5000 * rendering pipeline, but only if hardware acceleration is turned on for the 5001 * view hierarchy. When hardware acceleration is turned off, hardware layers 5002 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 5003 * 5004 * <p>A hardware layer is useful to apply a specific color filter and/or 5005 * blending mode and/or translucency to a view and all its children.</p> 5006 * <p>A hardware layer can be used to cache a complex view tree into a 5007 * texture and reduce the complexity of drawing operations. For instance, 5008 * when animating a complex view tree with a translation, a hardware layer can 5009 * be used to render the view tree only once.</p> 5010 * <p>A hardware layer can also be used to increase the rendering quality when 5011 * rotation transformations are applied on a view. It can also be used to 5012 * prevent potential clipping issues when applying 3D transforms on a view.</p> 5013 * 5014 * @see #getLayerType() 5015 * @see #setLayerType(int, android.graphics.Paint) 5016 * @see #LAYER_TYPE_NONE 5017 * @see #LAYER_TYPE_SOFTWARE 5018 */ 5019 public static final int LAYER_TYPE_HARDWARE = 2; 5020 5021 /** @hide */ 5022 @IntDef(prefix = { "LAYER_TYPE_" }, value = { 5023 LAYER_TYPE_NONE, 5024 LAYER_TYPE_SOFTWARE, 5025 LAYER_TYPE_HARDWARE 5026 }) 5027 @Retention(RetentionPolicy.SOURCE) 5028 public @interface LayerType {} 5029 5030 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 5031 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 5032 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 5033 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 5034 }) 5035 int mLayerType = LAYER_TYPE_NONE; 5036 Paint mLayerPaint; 5037 5038 /** 5039 * Set to true when drawing cache is enabled and cannot be created. 5040 * 5041 * @hide 5042 */ 5043 @UnsupportedAppUsage 5044 public boolean mCachingFailed; 5045 @UnsupportedAppUsage 5046 private Bitmap mDrawingCache; 5047 @UnsupportedAppUsage 5048 private Bitmap mUnscaledDrawingCache; 5049 5050 /** 5051 * RenderNode holding View properties, potentially holding a DisplayList of View content. 5052 * <p> 5053 * When non-null and valid, this is expected to contain an up-to-date copy 5054 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 5055 * cleanup. 5056 */ 5057 @UnsupportedAppUsage 5058 final RenderNode mRenderNode; 5059 5060 /** 5061 * Set to true when the view is sending hover accessibility events because it 5062 * is the innermost hovered view. 5063 */ 5064 private boolean mSendingHoverAccessibilityEvents; 5065 5066 /** 5067 * Delegate for injecting accessibility functionality. 5068 */ 5069 @UnsupportedAppUsage 5070 AccessibilityDelegate mAccessibilityDelegate; 5071 5072 /** 5073 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 5074 * and add/remove objects to/from the overlay directly through the Overlay methods. 5075 */ 5076 ViewOverlay mOverlay; 5077 5078 /** 5079 * The currently active parent view for receiving delegated nested scrolling events. 5080 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 5081 * by {@link #stopNestedScroll()} at the same point where we clear 5082 * requestDisallowInterceptTouchEvent. 5083 */ 5084 private ViewParent mNestedScrollingParent; 5085 5086 /** 5087 * Consistency verifier for debugging purposes. 5088 * @hide 5089 */ 5090 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 5091 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 5092 new InputEventConsistencyVerifier(this, 0) : null; 5093 5094 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 5095 5096 private int[] mTempNestedScrollConsumed; 5097 5098 /** 5099 * An overlay is going to draw this View instead of being drawn as part of this 5100 * View's parent. mGhostView is the View in the Overlay that must be invalidated 5101 * when this view is invalidated. 5102 */ 5103 GhostView mGhostView; 5104 5105 /** 5106 * Holds pairs of adjacent attribute data: attribute name followed by its value. 5107 * @hide 5108 */ 5109 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 5110 public String[] mAttributes; 5111 5112 /** 5113 * Maps a Resource id to its name. 5114 */ 5115 private static SparseArray<String> mAttributeMap; 5116 5117 /** 5118 * Queue of pending runnables. Used to postpone calls to post() until this 5119 * view is attached and has a handler. 5120 */ 5121 private HandlerActionQueue mRunQueue; 5122 5123 /** 5124 * The pointer icon when the mouse hovers on this view. The default is null. 5125 */ 5126 private PointerIcon mPointerIcon; 5127 5128 /** 5129 * @hide 5130 */ 5131 @UnsupportedAppUsage 5132 String mStartActivityRequestWho; 5133 5134 @Nullable 5135 private RoundScrollbarRenderer mRoundScrollbarRenderer; 5136 5137 /** Used to delay visibility updates sent to the autofill manager */ 5138 private Handler mVisibilityChangeForAutofillHandler; 5139 5140 /** 5141 * Used when app developers explicitly set the {@link ContentCaptureSession} associated with the 5142 * view (through {@link #setContentCaptureSession(ContentCaptureSession)}. 5143 */ 5144 @Nullable 5145 private ContentCaptureSession mContentCaptureSession; 5146 5147 @LayoutRes 5148 private int mSourceLayoutId = ID_NULL; 5149 5150 @Nullable 5151 private SparseIntArray mAttributeSourceResId; 5152 5153 @Nullable 5154 private SparseArray<int[]> mAttributeResolutionStacks; 5155 5156 @StyleRes 5157 private int mExplicitStyle; 5158 5159 /** 5160 * Cached reference to the {@link ContentCaptureSession}, is reset on {@link #invalidate()}. 5161 */ 5162 private ContentCaptureSession mCachedContentCaptureSession; 5163 5164 /** 5165 * Simple constructor to use when creating a view from code. 5166 * 5167 * @param context The Context the view is running in, through which it can 5168 * access the current theme, resources, etc. 5169 */ View(Context context)5170 public View(Context context) { 5171 mContext = context; 5172 mResources = context != null ? context.getResources() : null; 5173 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 5174 // Set some flags defaults 5175 mPrivateFlags2 = 5176 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 5177 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 5178 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 5179 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 5180 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 5181 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 5182 mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 5183 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 5184 mUserPaddingStart = UNDEFINED_PADDING; 5185 mUserPaddingEnd = UNDEFINED_PADDING; 5186 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 5187 5188 if (!sCompatibilityDone && context != null) { 5189 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5190 5191 // Older apps may need this compatibility hack for measurement. 5192 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; 5193 5194 // Older apps expect onMeasure() to always be called on a layout pass, regardless 5195 // of whether a layout was requested on that View. 5196 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; 5197 5198 Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M; 5199 Canvas.sCompatibilitySetBitmap = targetSdkVersion < Build.VERSION_CODES.O; 5200 Canvas.setCompatibilityVersion(targetSdkVersion); 5201 5202 // In M and newer, our widgets can pass a "hint" value in the size 5203 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 5204 // know what the expected parent size is going to be, so e.g. list items can size 5205 // themselves at 1/3 the size of their container. It breaks older apps though, 5206 // specifically apps that use some popular open source libraries. 5207 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M; 5208 5209 // Old versions of the platform would give different results from 5210 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 5211 // modes, so we always need to run an additional EXACTLY pass. 5212 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 5213 5214 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 5215 // On N+, we throw, but that breaks compatibility with apps that use these methods. 5216 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 5217 5218 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 5219 // in apps so we target check it to avoid breaking existing apps. 5220 sPreserveMarginParamsInLayoutParamConversion = 5221 targetSdkVersion >= Build.VERSION_CODES.N; 5222 5223 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 5224 5225 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 5226 5227 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 5228 5229 sUseDefaultFocusHighlight = context.getResources().getBoolean( 5230 com.android.internal.R.bool.config_useDefaultFocusHighlight); 5231 5232 sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P; 5233 5234 sCanFocusZeroSized = targetSdkVersion < Build.VERSION_CODES.P; 5235 5236 sAlwaysAssignFocus = targetSdkVersion < Build.VERSION_CODES.P; 5237 5238 sAcceptZeroSizeDragShadow = targetSdkVersion < Build.VERSION_CODES.P; 5239 5240 sBrokenInsetsDispatch = ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL 5241 || targetSdkVersion < Build.VERSION_CODES.Q; 5242 5243 sBrokenWindowBackground = targetSdkVersion < Build.VERSION_CODES.Q; 5244 5245 sCompatibilityDone = true; 5246 } 5247 } 5248 5249 /** 5250 * Constructor that is called when inflating a view from XML. This is called 5251 * when a view is being constructed from an XML file, supplying attributes 5252 * that were specified in the XML file. This version uses a default style of 5253 * 0, so the only attribute values applied are those in the Context's Theme 5254 * and the given AttributeSet. 5255 * 5256 * <p> 5257 * The method onFinishInflate() will be called after all children have been 5258 * added. 5259 * 5260 * @param context The Context the view is running in, through which it can 5261 * access the current theme, resources, etc. 5262 * @param attrs The attributes of the XML tag that is inflating the view. 5263 * @see #View(Context, AttributeSet, int) 5264 */ 5265 public View(Context context, @Nullable AttributeSet attrs) { 5266 this(context, attrs, 0); 5267 } 5268 5269 /** 5270 * Perform inflation from XML and apply a class-specific base style from a 5271 * theme attribute. This constructor of View allows subclasses to use their 5272 * own base style when they are inflating. For example, a Button class's 5273 * constructor would call this version of the super class constructor and 5274 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 5275 * allows the theme's button style to modify all of the base view attributes 5276 * (in particular its background) as well as the Button class's attributes. 5277 * 5278 * @param context The Context the view is running in, through which it can 5279 * access the current theme, resources, etc. 5280 * @param attrs The attributes of the XML tag that is inflating the view. 5281 * @param defStyleAttr An attribute in the current theme that contains a 5282 * reference to a style resource that supplies default values for 5283 * the view. Can be 0 to not look for defaults. 5284 * @see #View(Context, AttributeSet) 5285 */ 5286 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 5287 this(context, attrs, defStyleAttr, 0); 5288 } 5289 5290 /** 5291 * Perform inflation from XML and apply a class-specific base style from a 5292 * theme attribute or style resource. This constructor of View allows 5293 * subclasses to use their own base style when they are inflating. 5294 * <p> 5295 * When determining the final value of a particular attribute, there are 5296 * four inputs that come into play: 5297 * <ol> 5298 * <li>Any attribute values in the given AttributeSet. 5299 * <li>The style resource specified in the AttributeSet (named "style"). 5300 * <li>The default style specified by <var>defStyleAttr</var>. 5301 * <li>The default style specified by <var>defStyleRes</var>. 5302 * <li>The base values in this theme. 5303 * </ol> 5304 * <p> 5305 * Each of these inputs is considered in-order, with the first listed taking 5306 * precedence over the following ones. In other words, if in the 5307 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 5308 * , then the button's text will <em>always</em> be black, regardless of 5309 * what is specified in any of the styles. 5310 * 5311 * @param context The Context the view is running in, through which it can 5312 * access the current theme, resources, etc. 5313 * @param attrs The attributes of the XML tag that is inflating the view. 5314 * @param defStyleAttr An attribute in the current theme that contains a 5315 * reference to a style resource that supplies default values for 5316 * the view. Can be 0 to not look for defaults. 5317 * @param defStyleRes A resource identifier of a style resource that 5318 * supplies default values for the view, used only if 5319 * defStyleAttr is 0 or can not be found in the theme. Can be 0 5320 * to not look for defaults. 5321 * @see #View(Context, AttributeSet, int) 5322 */ 5323 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 5324 this(context); 5325 5326 mSourceLayoutId = Resources.getAttributeSetSourceResId(attrs); 5327 5328 final TypedArray a = context.obtainStyledAttributes( 5329 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 5330 5331 retrieveExplicitStyle(context.getTheme(), attrs); 5332 saveAttributeDataForStyleable(context, com.android.internal.R.styleable.View, attrs, a, 5333 defStyleAttr, defStyleRes); 5334 5335 if (sDebugViewAttributes) { 5336 saveAttributeData(attrs, a); 5337 } 5338 5339 Drawable background = null; 5340 5341 int leftPadding = -1; 5342 int topPadding = -1; 5343 int rightPadding = -1; 5344 int bottomPadding = -1; 5345 int startPadding = UNDEFINED_PADDING; 5346 int endPadding = UNDEFINED_PADDING; 5347 5348 int padding = -1; 5349 int paddingHorizontal = -1; 5350 int paddingVertical = -1; 5351 5352 int viewFlagValues = 0; 5353 int viewFlagMasks = 0; 5354 5355 boolean setScrollContainer = false; 5356 5357 int x = 0; 5358 int y = 0; 5359 5360 float tx = 0; 5361 float ty = 0; 5362 float tz = 0; 5363 float elevation = 0; 5364 float rotation = 0; 5365 float rotationX = 0; 5366 float rotationY = 0; 5367 float sx = 1f; 5368 float sy = 1f; 5369 boolean transformSet = false; 5370 5371 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 5372 int overScrollMode = mOverScrollMode; 5373 boolean initializeScrollbars = false; 5374 boolean initializeScrollIndicators = false; 5375 5376 boolean startPaddingDefined = false; 5377 boolean endPaddingDefined = false; 5378 boolean leftPaddingDefined = false; 5379 boolean rightPaddingDefined = false; 5380 5381 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5382 5383 // Set default values. 5384 viewFlagValues |= FOCUSABLE_AUTO; 5385 viewFlagMasks |= FOCUSABLE_AUTO; 5386 5387 final int N = a.getIndexCount(); 5388 for (int i = 0; i < N; i++) { 5389 int attr = a.getIndex(i); 5390 switch (attr) { 5391 case com.android.internal.R.styleable.View_background: 5392 background = a.getDrawable(attr); 5393 break; 5394 case com.android.internal.R.styleable.View_padding: 5395 padding = a.getDimensionPixelSize(attr, -1); 5396 mUserPaddingLeftInitial = padding; 5397 mUserPaddingRightInitial = padding; 5398 leftPaddingDefined = true; 5399 rightPaddingDefined = true; 5400 break; 5401 case com.android.internal.R.styleable.View_paddingHorizontal: 5402 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 5403 mUserPaddingLeftInitial = paddingHorizontal; 5404 mUserPaddingRightInitial = paddingHorizontal; 5405 leftPaddingDefined = true; 5406 rightPaddingDefined = true; 5407 break; 5408 case com.android.internal.R.styleable.View_paddingVertical: 5409 paddingVertical = a.getDimensionPixelSize(attr, -1); 5410 break; 5411 case com.android.internal.R.styleable.View_paddingLeft: 5412 leftPadding = a.getDimensionPixelSize(attr, -1); 5413 mUserPaddingLeftInitial = leftPadding; 5414 leftPaddingDefined = true; 5415 break; 5416 case com.android.internal.R.styleable.View_paddingTop: 5417 topPadding = a.getDimensionPixelSize(attr, -1); 5418 break; 5419 case com.android.internal.R.styleable.View_paddingRight: 5420 rightPadding = a.getDimensionPixelSize(attr, -1); 5421 mUserPaddingRightInitial = rightPadding; 5422 rightPaddingDefined = true; 5423 break; 5424 case com.android.internal.R.styleable.View_paddingBottom: 5425 bottomPadding = a.getDimensionPixelSize(attr, -1); 5426 break; 5427 case com.android.internal.R.styleable.View_paddingStart: 5428 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5429 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 5430 break; 5431 case com.android.internal.R.styleable.View_paddingEnd: 5432 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5433 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 5434 break; 5435 case com.android.internal.R.styleable.View_scrollX: 5436 x = a.getDimensionPixelOffset(attr, 0); 5437 break; 5438 case com.android.internal.R.styleable.View_scrollY: 5439 y = a.getDimensionPixelOffset(attr, 0); 5440 break; 5441 case com.android.internal.R.styleable.View_alpha: 5442 setAlpha(a.getFloat(attr, 1f)); 5443 break; 5444 case com.android.internal.R.styleable.View_transformPivotX: 5445 setPivotX(a.getDimension(attr, 0)); 5446 break; 5447 case com.android.internal.R.styleable.View_transformPivotY: 5448 setPivotY(a.getDimension(attr, 0)); 5449 break; 5450 case com.android.internal.R.styleable.View_translationX: 5451 tx = a.getDimension(attr, 0); 5452 transformSet = true; 5453 break; 5454 case com.android.internal.R.styleable.View_translationY: 5455 ty = a.getDimension(attr, 0); 5456 transformSet = true; 5457 break; 5458 case com.android.internal.R.styleable.View_translationZ: 5459 tz = a.getDimension(attr, 0); 5460 transformSet = true; 5461 break; 5462 case com.android.internal.R.styleable.View_elevation: 5463 elevation = a.getDimension(attr, 0); 5464 transformSet = true; 5465 break; 5466 case com.android.internal.R.styleable.View_rotation: 5467 rotation = a.getFloat(attr, 0); 5468 transformSet = true; 5469 break; 5470 case com.android.internal.R.styleable.View_rotationX: 5471 rotationX = a.getFloat(attr, 0); 5472 transformSet = true; 5473 break; 5474 case com.android.internal.R.styleable.View_rotationY: 5475 rotationY = a.getFloat(attr, 0); 5476 transformSet = true; 5477 break; 5478 case com.android.internal.R.styleable.View_scaleX: 5479 sx = a.getFloat(attr, 1f); 5480 transformSet = true; 5481 break; 5482 case com.android.internal.R.styleable.View_scaleY: 5483 sy = a.getFloat(attr, 1f); 5484 transformSet = true; 5485 break; 5486 case com.android.internal.R.styleable.View_id: 5487 mID = a.getResourceId(attr, NO_ID); 5488 break; 5489 case com.android.internal.R.styleable.View_tag: 5490 mTag = a.getText(attr); 5491 break; 5492 case com.android.internal.R.styleable.View_fitsSystemWindows: 5493 if (a.getBoolean(attr, false)) { 5494 viewFlagValues |= FITS_SYSTEM_WINDOWS; 5495 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 5496 } 5497 break; 5498 case com.android.internal.R.styleable.View_focusable: 5499 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 5500 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 5501 viewFlagMasks |= FOCUSABLE_MASK; 5502 } 5503 break; 5504 case com.android.internal.R.styleable.View_focusableInTouchMode: 5505 if (a.getBoolean(attr, false)) { 5506 // unset auto focus since focusableInTouchMode implies explicit focusable 5507 viewFlagValues &= ~FOCUSABLE_AUTO; 5508 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 5509 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 5510 } 5511 break; 5512 case com.android.internal.R.styleable.View_clickable: 5513 if (a.getBoolean(attr, false)) { 5514 viewFlagValues |= CLICKABLE; 5515 viewFlagMasks |= CLICKABLE; 5516 } 5517 break; 5518 case com.android.internal.R.styleable.View_longClickable: 5519 if (a.getBoolean(attr, false)) { 5520 viewFlagValues |= LONG_CLICKABLE; 5521 viewFlagMasks |= LONG_CLICKABLE; 5522 } 5523 break; 5524 case com.android.internal.R.styleable.View_contextClickable: 5525 if (a.getBoolean(attr, false)) { 5526 viewFlagValues |= CONTEXT_CLICKABLE; 5527 viewFlagMasks |= CONTEXT_CLICKABLE; 5528 } 5529 break; 5530 case com.android.internal.R.styleable.View_saveEnabled: 5531 if (!a.getBoolean(attr, true)) { 5532 viewFlagValues |= SAVE_DISABLED; 5533 viewFlagMasks |= SAVE_DISABLED_MASK; 5534 } 5535 break; 5536 case com.android.internal.R.styleable.View_duplicateParentState: 5537 if (a.getBoolean(attr, false)) { 5538 viewFlagValues |= DUPLICATE_PARENT_STATE; 5539 viewFlagMasks |= DUPLICATE_PARENT_STATE; 5540 } 5541 break; 5542 case com.android.internal.R.styleable.View_visibility: 5543 final int visibility = a.getInt(attr, 0); 5544 if (visibility != 0) { 5545 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 5546 viewFlagMasks |= VISIBILITY_MASK; 5547 } 5548 break; 5549 case com.android.internal.R.styleable.View_layoutDirection: 5550 // Clear any layout direction flags (included resolved bits) already set 5551 mPrivateFlags2 &= 5552 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 5553 // Set the layout direction flags depending on the value of the attribute 5554 final int layoutDirection = a.getInt(attr, -1); 5555 final int value = (layoutDirection != -1) ? 5556 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 5557 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 5558 break; 5559 case com.android.internal.R.styleable.View_drawingCacheQuality: 5560 final int cacheQuality = a.getInt(attr, 0); 5561 if (cacheQuality != 0) { 5562 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 5563 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 5564 } 5565 break; 5566 case com.android.internal.R.styleable.View_contentDescription: 5567 setContentDescription(a.getString(attr)); 5568 break; 5569 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 5570 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 5571 break; 5572 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 5573 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 5574 break; 5575 case com.android.internal.R.styleable.View_labelFor: 5576 setLabelFor(a.getResourceId(attr, NO_ID)); 5577 break; 5578 case com.android.internal.R.styleable.View_soundEffectsEnabled: 5579 if (!a.getBoolean(attr, true)) { 5580 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 5581 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 5582 } 5583 break; 5584 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 5585 if (!a.getBoolean(attr, true)) { 5586 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 5587 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 5588 } 5589 break; 5590 case R.styleable.View_scrollbars: 5591 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 5592 if (scrollbars != SCROLLBARS_NONE) { 5593 viewFlagValues |= scrollbars; 5594 viewFlagMasks |= SCROLLBARS_MASK; 5595 initializeScrollbars = true; 5596 } 5597 break; 5598 //noinspection deprecation 5599 case R.styleable.View_fadingEdge: 5600 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 5601 // Ignore the attribute starting with ICS 5602 break; 5603 } 5604 // With builds < ICS, fall through and apply fading edges 5605 case R.styleable.View_requiresFadingEdge: 5606 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 5607 if (fadingEdge != FADING_EDGE_NONE) { 5608 viewFlagValues |= fadingEdge; 5609 viewFlagMasks |= FADING_EDGE_MASK; 5610 initializeFadingEdgeInternal(a); 5611 } 5612 break; 5613 case R.styleable.View_scrollbarStyle: 5614 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 5615 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5616 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 5617 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 5618 } 5619 break; 5620 case R.styleable.View_isScrollContainer: 5621 setScrollContainer = true; 5622 if (a.getBoolean(attr, false)) { 5623 setScrollContainer(true); 5624 } 5625 break; 5626 case com.android.internal.R.styleable.View_keepScreenOn: 5627 if (a.getBoolean(attr, false)) { 5628 viewFlagValues |= KEEP_SCREEN_ON; 5629 viewFlagMasks |= KEEP_SCREEN_ON; 5630 } 5631 break; 5632 case R.styleable.View_filterTouchesWhenObscured: 5633 if (a.getBoolean(attr, false)) { 5634 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 5635 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 5636 } 5637 break; 5638 case R.styleable.View_nextFocusLeft: 5639 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 5640 break; 5641 case R.styleable.View_nextFocusRight: 5642 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 5643 break; 5644 case R.styleable.View_nextFocusUp: 5645 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 5646 break; 5647 case R.styleable.View_nextFocusDown: 5648 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 5649 break; 5650 case R.styleable.View_nextFocusForward: 5651 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 5652 break; 5653 case R.styleable.View_nextClusterForward: 5654 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 5655 break; 5656 case R.styleable.View_minWidth: 5657 mMinWidth = a.getDimensionPixelSize(attr, 0); 5658 break; 5659 case R.styleable.View_minHeight: 5660 mMinHeight = a.getDimensionPixelSize(attr, 0); 5661 break; 5662 case R.styleable.View_onClick: 5663 if (context.isRestricted()) { 5664 throw new IllegalStateException("The android:onClick attribute cannot " 5665 + "be used within a restricted context"); 5666 } 5667 5668 final String handlerName = a.getString(attr); 5669 if (handlerName != null) { 5670 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 5671 } 5672 break; 5673 case R.styleable.View_overScrollMode: 5674 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 5675 break; 5676 case R.styleable.View_verticalScrollbarPosition: 5677 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 5678 break; 5679 case R.styleable.View_layerType: 5680 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 5681 break; 5682 case R.styleable.View_textDirection: 5683 // Clear any text direction flag already set 5684 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 5685 // Set the text direction flags depending on the value of the attribute 5686 final int textDirection = a.getInt(attr, -1); 5687 if (textDirection != -1) { 5688 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 5689 } 5690 break; 5691 case R.styleable.View_textAlignment: 5692 // Clear any text alignment flag already set 5693 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 5694 // Set the text alignment flag depending on the value of the attribute 5695 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 5696 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 5697 break; 5698 case R.styleable.View_importantForAccessibility: 5699 setImportantForAccessibility(a.getInt(attr, 5700 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 5701 break; 5702 case R.styleable.View_accessibilityLiveRegion: 5703 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 5704 break; 5705 case R.styleable.View_transitionName: 5706 setTransitionName(a.getString(attr)); 5707 break; 5708 case R.styleable.View_nestedScrollingEnabled: 5709 setNestedScrollingEnabled(a.getBoolean(attr, false)); 5710 break; 5711 case R.styleable.View_stateListAnimator: 5712 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 5713 a.getResourceId(attr, 0))); 5714 break; 5715 case R.styleable.View_backgroundTint: 5716 // This will get applied later during setBackground(). 5717 if (mBackgroundTint == null) { 5718 mBackgroundTint = new TintInfo(); 5719 } 5720 mBackgroundTint.mTintList = a.getColorStateList( 5721 R.styleable.View_backgroundTint); 5722 mBackgroundTint.mHasTintList = true; 5723 break; 5724 case R.styleable.View_backgroundTintMode: 5725 // This will get applied later during setBackground(). 5726 if (mBackgroundTint == null) { 5727 mBackgroundTint = new TintInfo(); 5728 } 5729 mBackgroundTint.mBlendMode = Drawable.parseBlendMode(a.getInt( 5730 R.styleable.View_backgroundTintMode, -1), null); 5731 mBackgroundTint.mHasTintMode = true; 5732 break; 5733 case R.styleable.View_outlineProvider: 5734 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 5735 PROVIDER_BACKGROUND)); 5736 break; 5737 case R.styleable.View_foreground: 5738 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5739 setForeground(a.getDrawable(attr)); 5740 } 5741 break; 5742 case R.styleable.View_foregroundGravity: 5743 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5744 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 5745 } 5746 break; 5747 case R.styleable.View_foregroundTintMode: 5748 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5749 setForegroundTintBlendMode( 5750 Drawable.parseBlendMode(a.getInt(attr, -1), 5751 null)); 5752 } 5753 break; 5754 case R.styleable.View_foregroundTint: 5755 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5756 setForegroundTintList(a.getColorStateList(attr)); 5757 } 5758 break; 5759 case R.styleable.View_foregroundInsidePadding: 5760 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5761 if (mForegroundInfo == null) { 5762 mForegroundInfo = new ForegroundInfo(); 5763 } 5764 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 5765 mForegroundInfo.mInsidePadding); 5766 } 5767 break; 5768 case R.styleable.View_scrollIndicators: 5769 final int scrollIndicators = 5770 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 5771 & SCROLL_INDICATORS_PFLAG3_MASK; 5772 if (scrollIndicators != 0) { 5773 mPrivateFlags3 |= scrollIndicators; 5774 initializeScrollIndicators = true; 5775 } 5776 break; 5777 case R.styleable.View_pointerIcon: 5778 final int resourceId = a.getResourceId(attr, 0); 5779 if (resourceId != 0) { 5780 setPointerIcon(PointerIcon.load( 5781 context.getResources(), resourceId)); 5782 } else { 5783 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 5784 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 5785 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 5786 } 5787 } 5788 break; 5789 case R.styleable.View_forceHasOverlappingRendering: 5790 if (a.peekValue(attr) != null) { 5791 forceHasOverlappingRendering(a.getBoolean(attr, true)); 5792 } 5793 break; 5794 case R.styleable.View_tooltipText: 5795 setTooltipText(a.getText(attr)); 5796 break; 5797 case R.styleable.View_keyboardNavigationCluster: 5798 if (a.peekValue(attr) != null) { 5799 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 5800 } 5801 break; 5802 case R.styleable.View_focusedByDefault: 5803 if (a.peekValue(attr) != null) { 5804 setFocusedByDefault(a.getBoolean(attr, true)); 5805 } 5806 break; 5807 case R.styleable.View_autofillHints: 5808 if (a.peekValue(attr) != null) { 5809 CharSequence[] rawHints = null; 5810 String rawString = null; 5811 5812 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 5813 int resId = a.getResourceId(attr, 0); 5814 5815 try { 5816 rawHints = a.getTextArray(attr); 5817 } catch (Resources.NotFoundException e) { 5818 rawString = getResources().getString(resId); 5819 } 5820 } else { 5821 rawString = a.getString(attr); 5822 } 5823 5824 if (rawHints == null) { 5825 if (rawString == null) { 5826 throw new IllegalArgumentException( 5827 "Could not resolve autofillHints"); 5828 } else { 5829 rawHints = rawString.split(","); 5830 } 5831 } 5832 5833 String[] hints = new String[rawHints.length]; 5834 5835 int numHints = rawHints.length; 5836 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 5837 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 5838 } 5839 setAutofillHints(hints); 5840 } 5841 break; 5842 case R.styleable.View_importantForAutofill: 5843 if (a.peekValue(attr) != null) { 5844 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 5845 } 5846 break; 5847 case R.styleable.View_defaultFocusHighlightEnabled: 5848 if (a.peekValue(attr) != null) { 5849 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); 5850 } 5851 break; 5852 case R.styleable.View_screenReaderFocusable: 5853 if (a.peekValue(attr) != null) { 5854 setScreenReaderFocusable(a.getBoolean(attr, false)); 5855 } 5856 break; 5857 case R.styleable.View_accessibilityPaneTitle: 5858 if (a.peekValue(attr) != null) { 5859 setAccessibilityPaneTitle(a.getString(attr)); 5860 } 5861 break; 5862 case R.styleable.View_outlineSpotShadowColor: 5863 setOutlineSpotShadowColor(a.getColor(attr, Color.BLACK)); 5864 break; 5865 case R.styleable.View_outlineAmbientShadowColor: 5866 setOutlineAmbientShadowColor(a.getColor(attr, Color.BLACK)); 5867 break; 5868 case com.android.internal.R.styleable.View_accessibilityHeading: 5869 setAccessibilityHeading(a.getBoolean(attr, false)); 5870 break; 5871 case R.styleable.View_forceDarkAllowed: 5872 mRenderNode.setForceDarkAllowed(a.getBoolean(attr, true)); 5873 break; 5874 } 5875 } 5876 5877 setOverScrollMode(overScrollMode); 5878 5879 // Cache start/end user padding as we cannot fully resolve padding here (we don't have yet 5880 // the resolved layout direction). Those cached values will be used later during padding 5881 // resolution. 5882 mUserPaddingStart = startPadding; 5883 mUserPaddingEnd = endPadding; 5884 5885 if (background != null) { 5886 setBackground(background); 5887 } 5888 5889 // setBackground above will record that padding is currently provided by the background. 5890 // If we have padding specified via xml, record that here instead and use it. 5891 mLeftPaddingDefined = leftPaddingDefined; 5892 mRightPaddingDefined = rightPaddingDefined; 5893 5894 // Valid paddingHorizontal/paddingVertical beats leftPadding, rightPadding, topPadding, 5895 // bottomPadding, and padding set by background. Valid padding beats everything. 5896 if (padding >= 0) { 5897 leftPadding = padding; 5898 topPadding = padding; 5899 rightPadding = padding; 5900 bottomPadding = padding; 5901 mUserPaddingLeftInitial = padding; 5902 mUserPaddingRightInitial = padding; 5903 } else { 5904 if (paddingHorizontal >= 0) { 5905 leftPadding = paddingHorizontal; 5906 rightPadding = paddingHorizontal; 5907 mUserPaddingLeftInitial = paddingHorizontal; 5908 mUserPaddingRightInitial = paddingHorizontal; 5909 } 5910 if (paddingVertical >= 0) { 5911 topPadding = paddingVertical; 5912 bottomPadding = paddingVertical; 5913 } 5914 } 5915 5916 if (isRtlCompatibilityMode()) { 5917 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 5918 // left / right padding are used if defined (meaning here nothing to do). If they are not 5919 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 5920 // start / end and resolve them as left / right (layout direction is not taken into account). 5921 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5922 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5923 // defined. 5924 if (!mLeftPaddingDefined && startPaddingDefined) { 5925 leftPadding = startPadding; 5926 } 5927 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 5928 if (!mRightPaddingDefined && endPaddingDefined) { 5929 rightPadding = endPadding; 5930 } 5931 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 5932 } else { 5933 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 5934 // values defined. Otherwise, left /right values are used. 5935 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 5936 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 5937 // defined. 5938 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 5939 5940 if (mLeftPaddingDefined && !hasRelativePadding) { 5941 mUserPaddingLeftInitial = leftPadding; 5942 } 5943 if (mRightPaddingDefined && !hasRelativePadding) { 5944 mUserPaddingRightInitial = rightPadding; 5945 } 5946 } 5947 5948 // mPaddingTop and mPaddingBottom may have been set by setBackground(Drawable) so must pass 5949 // them on if topPadding or bottomPadding are not valid. 5950 internalSetPadding( 5951 mUserPaddingLeftInitial, 5952 topPadding >= 0 ? topPadding : mPaddingTop, 5953 mUserPaddingRightInitial, 5954 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 5955 5956 if (viewFlagMasks != 0) { 5957 setFlags(viewFlagValues, viewFlagMasks); 5958 } 5959 5960 if (initializeScrollbars) { 5961 initializeScrollbarsInternal(a); 5962 } 5963 5964 if (initializeScrollIndicators) { 5965 initializeScrollIndicatorsInternal(); 5966 } 5967 5968 a.recycle(); 5969 5970 // Needs to be called after mViewFlags is set 5971 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5972 recomputePadding(); 5973 } 5974 5975 if (x != 0 || y != 0) { 5976 scrollTo(x, y); 5977 } 5978 5979 if (transformSet) { 5980 setTranslationX(tx); 5981 setTranslationY(ty); 5982 setTranslationZ(tz); 5983 setElevation(elevation); 5984 setRotation(rotation); 5985 setRotationX(rotationX); 5986 setRotationY(rotationY); 5987 setScaleX(sx); 5988 setScaleY(sy); 5989 } 5990 5991 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 5992 setScrollContainer(true); 5993 } 5994 5995 computeOpaqueFlags(); 5996 } 5997 5998 /** 5999 * Returns the ordered list of resource ID that are considered when resolving attribute values 6000 * for this {@link View}. The list will include layout resource ID if the View is inflated from 6001 * XML. It will also include a set of explicit styles if specified in XML using 6002 * {@code style="..."}. Finally, it will include the default styles resolved from the theme. 6003 * 6004 * <p> 6005 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6006 * is enabled in Android developer options. 6007 * 6008 * @param attribute Attribute resource ID for which the resolution stack should be returned. 6009 * @return ordered list of resource ID that are considered when resolving attribute values for 6010 * this {@link View}. 6011 */ 6012 @NonNull 6013 public int[] getAttributeResolutionStack(@AttrRes int attribute) { 6014 if (!sDebugViewAttributes 6015 || mAttributeResolutionStacks == null 6016 || mAttributeResolutionStacks.get(attribute) == null) { 6017 return new int[0]; 6018 } 6019 int[] attributeResolutionStack = mAttributeResolutionStacks.get(attribute); 6020 int stackSize = attributeResolutionStack.length; 6021 if (mSourceLayoutId != ID_NULL) { 6022 stackSize++; 6023 } 6024 6025 int currentIndex = 0; 6026 int[] stack = new int[stackSize]; 6027 6028 if (mSourceLayoutId != ID_NULL) { 6029 stack[currentIndex] = mSourceLayoutId; 6030 currentIndex++; 6031 } 6032 for (int i = 0; i < attributeResolutionStack.length; i++) { 6033 stack[currentIndex] = attributeResolutionStack[i]; 6034 currentIndex++; 6035 } 6036 return stack; 6037 } 6038 6039 /** 6040 * Returns the mapping of attribute resource ID to source resource ID where the attribute value 6041 * was set. Source resource ID can either be a layout resource ID, if the value was set in XML 6042 * within the View tag, or a style resource ID, if the attribute was set in a style. The source 6043 * resource value will be one of the resource IDs from {@link #getAttributeSourceResourceMap()}. 6044 * 6045 * <p> 6046 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6047 * is enabled in Android developer options. 6048 * 6049 * @return mapping of attribute resource ID to source resource ID where the attribute value 6050 * was set. 6051 */ 6052 @NonNull 6053 public Map<Integer, Integer> getAttributeSourceResourceMap() { 6054 HashMap<Integer, Integer> map = new HashMap<>(); 6055 if (!sDebugViewAttributes || mAttributeSourceResId == null) { 6056 return map; 6057 } 6058 for (int i = 0; i < mAttributeSourceResId.size(); i++) { 6059 map.put(mAttributeSourceResId.keyAt(i), mAttributeSourceResId.valueAt(i)); 6060 } 6061 return map; 6062 } 6063 6064 /** 6065 * Returns the resource ID for the style specified using {@code style="..."} in the 6066 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise if not 6067 * specified or otherwise not applicable. 6068 * <p> 6069 * Each {@link View} can have an explicit style specified in the layout file. 6070 * This style is used first during the {@link View} attribute resolution, then if an attribute 6071 * is not defined there the resource system looks at default style and theme as fallbacks. 6072 * 6073 * <p> 6074 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6075 * is enabled in Android developer options. 6076 * 6077 * @return The resource ID for the style specified using {@code style="..."} in the 6078 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise 6079 * if not specified or otherwise not applicable. 6080 */ 6081 @StyleRes 6082 public int getExplicitStyle() { 6083 if (!sDebugViewAttributes) { 6084 return ID_NULL; 6085 } 6086 return mExplicitStyle; 6087 } 6088 6089 /** 6090 * An implementation of OnClickListener that attempts to lazily load a 6091 * named click handling method from a parent or ancestor context. 6092 */ 6093 private static class DeclaredOnClickListener implements OnClickListener { 6094 private final View mHostView; 6095 private final String mMethodName; 6096 6097 private Method mResolvedMethod; 6098 private Context mResolvedContext; 6099 6100 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 6101 mHostView = hostView; 6102 mMethodName = methodName; 6103 } 6104 6105 @Override 6106 public void onClick(@NonNull View v) { 6107 if (mResolvedMethod == null) { 6108 resolveMethod(mHostView.getContext(), mMethodName); 6109 } 6110 6111 try { 6112 mResolvedMethod.invoke(mResolvedContext, v); 6113 } catch (IllegalAccessException e) { 6114 throw new IllegalStateException( 6115 "Could not execute non-public method for android:onClick", e); 6116 } catch (InvocationTargetException e) { 6117 throw new IllegalStateException( 6118 "Could not execute method for android:onClick", e); 6119 } 6120 } 6121 6122 @NonNull 6123 private void resolveMethod(@Nullable Context context, @NonNull String name) { 6124 while (context != null) { 6125 try { 6126 if (!context.isRestricted()) { 6127 final Method method = context.getClass().getMethod(mMethodName, View.class); 6128 if (method != null) { 6129 mResolvedMethod = method; 6130 mResolvedContext = context; 6131 return; 6132 } 6133 } 6134 } catch (NoSuchMethodException e) { 6135 // Failed to find method, keep searching up the hierarchy. 6136 } 6137 6138 if (context instanceof ContextWrapper) { 6139 context = ((ContextWrapper) context).getBaseContext(); 6140 } else { 6141 // Can't search up the hierarchy, null out and fail. 6142 context = null; 6143 } 6144 } 6145 6146 final int id = mHostView.getId(); 6147 final String idText = id == NO_ID ? "" : " with id '" 6148 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 6149 throw new IllegalStateException("Could not find method " + mMethodName 6150 + "(View) in a parent or ancestor Context for android:onClick " 6151 + "attribute defined on view " + mHostView.getClass() + idText); 6152 } 6153 } 6154 6155 /** 6156 * Non-public constructor for use in testing 6157 */ 6158 @UnsupportedAppUsage 6159 View() { 6160 mResources = null; 6161 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 6162 } 6163 6164 final boolean debugDraw() { 6165 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 6166 } 6167 6168 private static SparseArray<String> getAttributeMap() { 6169 if (mAttributeMap == null) { 6170 mAttributeMap = new SparseArray<>(); 6171 } 6172 return mAttributeMap; 6173 } 6174 6175 private void retrieveExplicitStyle(@NonNull Resources.Theme theme, 6176 @Nullable AttributeSet attrs) { 6177 if (!sDebugViewAttributes) { 6178 return; 6179 } 6180 mExplicitStyle = theme.getExplicitStyle(attrs); 6181 } 6182 6183 /** 6184 * Stores debugging information about attributes. This should be called in a constructor by 6185 * every custom {@link View} that uses a custom styleable. If the custom view does not call it, 6186 * then the custom attributes used by this view will not be visible in layout inspection tools. 6187 * 6188 * @param context Context under which this view is created. 6189 * @param styleable A reference to styleable array R.styleable.Foo 6190 * @param attrs AttributeSet used to construct this view. 6191 * @param t Resolved {@link TypedArray} returned by a call to 6192 * {@link Resources#obtainAttributes(AttributeSet, int[])}. 6193 * @param defStyleAttr Default style attribute passed into the view constructor. 6194 * @param defStyleRes Default style resource passed into the view constructor. 6195 */ 6196 public final void saveAttributeDataForStyleable(@NonNull Context context, 6197 @NonNull int[] styleable, @Nullable AttributeSet attrs, @NonNull TypedArray t, 6198 int defStyleAttr, int defStyleRes) { 6199 if (!sDebugViewAttributes) { 6200 return; 6201 } 6202 6203 int[] attributeResolutionStack = context.getTheme().getAttributeResolutionStack( 6204 defStyleAttr, defStyleRes, mExplicitStyle); 6205 6206 if (mAttributeResolutionStacks == null) { 6207 mAttributeResolutionStacks = new SparseArray<>(); 6208 } 6209 6210 if (mAttributeSourceResId == null) { 6211 mAttributeSourceResId = new SparseIntArray(); 6212 } 6213 6214 final int indexCount = t.getIndexCount(); 6215 for (int j = 0; j < indexCount; ++j) { 6216 final int index = t.getIndex(j); 6217 mAttributeSourceResId.append(styleable[index], t.getSourceResourceId(index, 0)); 6218 mAttributeResolutionStacks.append(styleable[index], attributeResolutionStack); 6219 } 6220 } 6221 6222 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 6223 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 6224 final int indexCount = t.getIndexCount(); 6225 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 6226 6227 int i = 0; 6228 6229 // Store raw XML attributes. 6230 for (int j = 0; j < attrsCount; ++j) { 6231 attributes[i] = attrs.getAttributeName(j); 6232 attributes[i + 1] = attrs.getAttributeValue(j); 6233 i += 2; 6234 } 6235 6236 // Store resolved styleable attributes. 6237 final Resources res = t.getResources(); 6238 final SparseArray<String> attributeMap = getAttributeMap(); 6239 for (int j = 0; j < indexCount; ++j) { 6240 final int index = t.getIndex(j); 6241 if (!t.hasValueOrEmpty(index)) { 6242 // Value is undefined. Skip it. 6243 continue; 6244 } 6245 6246 final int resourceId = t.getResourceId(index, 0); 6247 if (resourceId == 0) { 6248 // Value is not a reference. Skip it. 6249 continue; 6250 } 6251 6252 String resourceName = attributeMap.get(resourceId); 6253 if (resourceName == null) { 6254 try { 6255 resourceName = res.getResourceName(resourceId); 6256 } catch (Resources.NotFoundException e) { 6257 resourceName = "0x" + Integer.toHexString(resourceId); 6258 } 6259 attributeMap.put(resourceId, resourceName); 6260 } 6261 6262 attributes[i] = resourceName; 6263 attributes[i + 1] = t.getString(index); 6264 i += 2; 6265 } 6266 6267 // Trim to fit contents. 6268 final String[] trimmed = new String[i]; 6269 System.arraycopy(attributes, 0, trimmed, 0, i); 6270 mAttributes = trimmed; 6271 } 6272 6273 @Override 6274 public String toString() { 6275 StringBuilder out = new StringBuilder(128); 6276 out.append(getClass().getName()); 6277 out.append('{'); 6278 out.append(Integer.toHexString(System.identityHashCode(this))); 6279 out.append(' '); 6280 switch (mViewFlags&VISIBILITY_MASK) { 6281 case VISIBLE: out.append('V'); break; 6282 case INVISIBLE: out.append('I'); break; 6283 case GONE: out.append('G'); break; 6284 default: out.append('.'); break; 6285 } 6286 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 6287 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 6288 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 6289 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 6290 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 6291 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 6292 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 6293 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 6294 out.append(' '); 6295 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 6296 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 6297 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 6298 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 6299 out.append('p'); 6300 } else { 6301 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 6302 } 6303 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 6304 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 6305 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 6306 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 6307 out.append(' '); 6308 out.append(mLeft); 6309 out.append(','); 6310 out.append(mTop); 6311 out.append('-'); 6312 out.append(mRight); 6313 out.append(','); 6314 out.append(mBottom); 6315 final int id = getId(); 6316 if (id != NO_ID) { 6317 out.append(" #"); 6318 out.append(Integer.toHexString(id)); 6319 final Resources r = mResources; 6320 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 6321 try { 6322 String pkgname; 6323 switch (id&0xff000000) { 6324 case 0x7f000000: 6325 pkgname="app"; 6326 break; 6327 case 0x01000000: 6328 pkgname="android"; 6329 break; 6330 default: 6331 pkgname = r.getResourcePackageName(id); 6332 break; 6333 } 6334 String typename = r.getResourceTypeName(id); 6335 String entryname = r.getResourceEntryName(id); 6336 out.append(" "); 6337 out.append(pkgname); 6338 out.append(":"); 6339 out.append(typename); 6340 out.append("/"); 6341 out.append(entryname); 6342 } catch (Resources.NotFoundException e) { 6343 } 6344 } 6345 } 6346 if (mAutofillId != null) { 6347 out.append(" aid="); out.append(mAutofillId); 6348 } 6349 out.append("}"); 6350 return out.toString(); 6351 } 6352 6353 /** 6354 * <p> 6355 * Initializes the fading edges from a given set of styled attributes. This 6356 * method should be called by subclasses that need fading edges and when an 6357 * instance of these subclasses is created programmatically rather than 6358 * being inflated from XML. This method is automatically called when the XML 6359 * is inflated. 6360 * </p> 6361 * 6362 * @param a the styled attributes set to initialize the fading edges from 6363 * 6364 * @removed 6365 */ 6366 protected void initializeFadingEdge(TypedArray a) { 6367 // This method probably shouldn't have been included in the SDK to begin with. 6368 // It relies on 'a' having been initialized using an attribute filter array that is 6369 // not publicly available to the SDK. The old method has been renamed 6370 // to initializeFadingEdgeInternal and hidden for framework use only; 6371 // this one initializes using defaults to make it safe to call for apps. 6372 6373 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 6374 6375 initializeFadingEdgeInternal(arr); 6376 6377 arr.recycle(); 6378 } 6379 6380 /** 6381 * <p> 6382 * Initializes the fading edges from a given set of styled attributes. This 6383 * method should be called by subclasses that need fading edges and when an 6384 * instance of these subclasses is created programmatically rather than 6385 * being inflated from XML. This method is automatically called when the XML 6386 * is inflated. 6387 * </p> 6388 * 6389 * @param a the styled attributes set to initialize the fading edges from 6390 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 6391 */ 6392 protected void initializeFadingEdgeInternal(TypedArray a) { 6393 initScrollCache(); 6394 6395 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 6396 R.styleable.View_fadingEdgeLength, 6397 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 6398 } 6399 6400 /** 6401 * Returns the size of the vertical faded edges used to indicate that more 6402 * content in this view is visible. 6403 * 6404 * @return The size in pixels of the vertical faded edge or 0 if vertical 6405 * faded edges are not enabled for this view. 6406 * @attr ref android.R.styleable#View_fadingEdgeLength 6407 */ 6408 public int getVerticalFadingEdgeLength() { 6409 if (isVerticalFadingEdgeEnabled()) { 6410 ScrollabilityCache cache = mScrollCache; 6411 if (cache != null) { 6412 return cache.fadingEdgeLength; 6413 } 6414 } 6415 return 0; 6416 } 6417 6418 /** 6419 * Set the size of the faded edge used to indicate that more content in this 6420 * view is available. Will not change whether the fading edge is enabled; use 6421 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 6422 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 6423 * for the vertical or horizontal fading edges. 6424 * 6425 * @param length The size in pixels of the faded edge used to indicate that more 6426 * content in this view is visible. 6427 */ 6428 public void setFadingEdgeLength(int length) { 6429 initScrollCache(); 6430 mScrollCache.fadingEdgeLength = length; 6431 } 6432 6433 /** 6434 * Returns the size of the horizontal faded edges used to indicate that more 6435 * content in this view is visible. 6436 * 6437 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 6438 * faded edges are not enabled for this view. 6439 * @attr ref android.R.styleable#View_fadingEdgeLength 6440 */ 6441 public int getHorizontalFadingEdgeLength() { 6442 if (isHorizontalFadingEdgeEnabled()) { 6443 ScrollabilityCache cache = mScrollCache; 6444 if (cache != null) { 6445 return cache.fadingEdgeLength; 6446 } 6447 } 6448 return 0; 6449 } 6450 6451 /** 6452 * Returns the width of the vertical scrollbar. 6453 * 6454 * @return The width in pixels of the vertical scrollbar or 0 if there 6455 * is no vertical scrollbar. 6456 */ 6457 public int getVerticalScrollbarWidth() { 6458 ScrollabilityCache cache = mScrollCache; 6459 if (cache != null) { 6460 ScrollBarDrawable scrollBar = cache.scrollBar; 6461 if (scrollBar != null) { 6462 int size = scrollBar.getSize(true); 6463 if (size <= 0) { 6464 size = cache.scrollBarSize; 6465 } 6466 return size; 6467 } 6468 return 0; 6469 } 6470 return 0; 6471 } 6472 6473 /** 6474 * Returns the height of the horizontal scrollbar. 6475 * 6476 * @return The height in pixels of the horizontal scrollbar or 0 if 6477 * there is no horizontal scrollbar. 6478 */ 6479 protected int getHorizontalScrollbarHeight() { 6480 ScrollabilityCache cache = mScrollCache; 6481 if (cache != null) { 6482 ScrollBarDrawable scrollBar = cache.scrollBar; 6483 if (scrollBar != null) { 6484 int size = scrollBar.getSize(false); 6485 if (size <= 0) { 6486 size = cache.scrollBarSize; 6487 } 6488 return size; 6489 } 6490 return 0; 6491 } 6492 return 0; 6493 } 6494 6495 /** 6496 * <p> 6497 * Initializes the scrollbars from a given set of styled attributes. This 6498 * method should be called by subclasses that need scrollbars and when an 6499 * instance of these subclasses is created programmatically rather than 6500 * being inflated from XML. This method is automatically called when the XML 6501 * is inflated. 6502 * </p> 6503 * 6504 * @param a the styled attributes set to initialize the scrollbars from 6505 * 6506 * @removed 6507 */ 6508 protected void initializeScrollbars(TypedArray a) { 6509 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 6510 // using the View filter array which is not available to the SDK. As such, internal 6511 // framework usage now uses initializeScrollbarsInternal and we grab a default 6512 // TypedArray with the right filter instead here. 6513 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 6514 6515 initializeScrollbarsInternal(arr); 6516 6517 // We ignored the method parameter. Recycle the one we actually did use. 6518 arr.recycle(); 6519 } 6520 6521 private void initializeScrollBarDrawable() { 6522 initScrollCache(); 6523 6524 if (mScrollCache.scrollBar == null) { 6525 mScrollCache.scrollBar = new ScrollBarDrawable(); 6526 mScrollCache.scrollBar.setState(getDrawableState()); 6527 mScrollCache.scrollBar.setCallback(this); 6528 } 6529 } 6530 6531 /** 6532 * <p> 6533 * Initializes the scrollbars from a given set of styled attributes. This 6534 * method should be called by subclasses that need scrollbars and when an 6535 * instance of these subclasses is created programmatically rather than 6536 * being inflated from XML. This method is automatically called when the XML 6537 * is inflated. 6538 * </p> 6539 * 6540 * @param a the styled attributes set to initialize the scrollbars from 6541 * @hide 6542 */ 6543 @UnsupportedAppUsage 6544 protected void initializeScrollbarsInternal(TypedArray a) { 6545 initScrollCache(); 6546 6547 final ScrollabilityCache scrollabilityCache = mScrollCache; 6548 6549 if (scrollabilityCache.scrollBar == null) { 6550 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 6551 scrollabilityCache.scrollBar.setState(getDrawableState()); 6552 scrollabilityCache.scrollBar.setCallback(this); 6553 } 6554 6555 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 6556 6557 if (!fadeScrollbars) { 6558 scrollabilityCache.state = ScrollabilityCache.ON; 6559 } 6560 scrollabilityCache.fadeScrollBars = fadeScrollbars; 6561 6562 6563 scrollabilityCache.scrollBarFadeDuration = a.getInt( 6564 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 6565 .getScrollBarFadeDuration()); 6566 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 6567 R.styleable.View_scrollbarDefaultDelayBeforeFade, 6568 ViewConfiguration.getScrollDefaultDelay()); 6569 6570 6571 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 6572 com.android.internal.R.styleable.View_scrollbarSize, 6573 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 6574 6575 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 6576 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 6577 6578 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 6579 if (thumb != null) { 6580 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 6581 } 6582 6583 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 6584 false); 6585 if (alwaysDraw) { 6586 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 6587 } 6588 6589 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 6590 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 6591 6592 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 6593 if (thumb != null) { 6594 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 6595 } 6596 6597 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 6598 false); 6599 if (alwaysDraw) { 6600 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 6601 } 6602 6603 // Apply layout direction to the new Drawables if needed 6604 final int layoutDirection = getLayoutDirection(); 6605 if (track != null) { 6606 track.setLayoutDirection(layoutDirection); 6607 } 6608 if (thumb != null) { 6609 thumb.setLayoutDirection(layoutDirection); 6610 } 6611 6612 // Re-apply user/background padding so that scrollbar(s) get added 6613 resolvePadding(); 6614 } 6615 6616 /** 6617 * Defines the vertical scrollbar thumb drawable 6618 * @attr ref android.R.styleable#View_scrollbarThumbVertical 6619 * 6620 * @see #awakenScrollBars(int) 6621 * @see #isVerticalScrollBarEnabled() 6622 * @see #setVerticalScrollBarEnabled(boolean) 6623 */ 6624 public void setVerticalScrollbarThumbDrawable(@Nullable Drawable drawable) { 6625 initializeScrollBarDrawable(); 6626 mScrollCache.scrollBar.setVerticalThumbDrawable(drawable); 6627 } 6628 6629 /** 6630 * Defines the vertical scrollbar track drawable 6631 * @attr ref android.R.styleable#View_scrollbarTrackVertical 6632 * 6633 * @see #awakenScrollBars(int) 6634 * @see #isVerticalScrollBarEnabled() 6635 * @see #setVerticalScrollBarEnabled(boolean) 6636 */ 6637 public void setVerticalScrollbarTrackDrawable(@Nullable Drawable drawable) { 6638 initializeScrollBarDrawable(); 6639 mScrollCache.scrollBar.setVerticalTrackDrawable(drawable); 6640 } 6641 6642 /** 6643 * Defines the horizontal thumb drawable 6644 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 6645 * 6646 * @see #awakenScrollBars(int) 6647 * @see #isHorizontalScrollBarEnabled() 6648 * @see #setHorizontalScrollBarEnabled(boolean) 6649 */ 6650 public void setHorizontalScrollbarThumbDrawable(@Nullable Drawable drawable) { 6651 initializeScrollBarDrawable(); 6652 mScrollCache.scrollBar.setHorizontalThumbDrawable(drawable); 6653 } 6654 6655 /** 6656 * Defines the horizontal track drawable 6657 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 6658 * 6659 * @see #awakenScrollBars(int) 6660 * @see #isHorizontalScrollBarEnabled() 6661 * @see #setHorizontalScrollBarEnabled(boolean) 6662 */ 6663 public void setHorizontalScrollbarTrackDrawable(@Nullable Drawable drawable) { 6664 initializeScrollBarDrawable(); 6665 mScrollCache.scrollBar.setHorizontalTrackDrawable(drawable); 6666 } 6667 6668 /** 6669 * Returns the currently configured Drawable for the thumb of the vertical scroll bar if it 6670 * exists, null otherwise. 6671 * 6672 * @see #awakenScrollBars(int) 6673 * @see #isVerticalScrollBarEnabled() 6674 * @see #setVerticalScrollBarEnabled(boolean) 6675 */ 6676 public @Nullable Drawable getVerticalScrollbarThumbDrawable() { 6677 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalThumbDrawable() : null; 6678 } 6679 6680 /** 6681 * Returns the currently configured Drawable for the track of the vertical scroll bar if it 6682 * exists, null otherwise. 6683 * 6684 * @see #awakenScrollBars(int) 6685 * @see #isVerticalScrollBarEnabled() 6686 * @see #setVerticalScrollBarEnabled(boolean) 6687 */ 6688 public @Nullable Drawable getVerticalScrollbarTrackDrawable() { 6689 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalTrackDrawable() : null; 6690 } 6691 6692 /** 6693 * Returns the currently configured Drawable for the thumb of the horizontal scroll bar if it 6694 * exists, null otherwise. 6695 * 6696 * @see #awakenScrollBars(int) 6697 * @see #isHorizontalScrollBarEnabled() 6698 * @see #setHorizontalScrollBarEnabled(boolean) 6699 */ 6700 public @Nullable Drawable getHorizontalScrollbarThumbDrawable() { 6701 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalThumbDrawable() : null; 6702 } 6703 6704 /** 6705 * Returns the currently configured Drawable for the track of the horizontal scroll bar if it 6706 * exists, null otherwise. 6707 * 6708 * @see #awakenScrollBars(int) 6709 * @see #isHorizontalScrollBarEnabled() 6710 * @see #setHorizontalScrollBarEnabled(boolean) 6711 */ 6712 public @Nullable Drawable getHorizontalScrollbarTrackDrawable() { 6713 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalTrackDrawable() : null; 6714 } 6715 6716 private void initializeScrollIndicatorsInternal() { 6717 // Some day maybe we'll break this into top/left/start/etc. and let the 6718 // client control it. Until then, you can have any scroll indicator you 6719 // want as long as it's a 1dp foreground-colored rectangle. 6720 if (mScrollIndicatorDrawable == null) { 6721 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 6722 } 6723 } 6724 6725 /** 6726 * <p> 6727 * Initalizes the scrollability cache if necessary. 6728 * </p> 6729 */ 6730 private void initScrollCache() { 6731 if (mScrollCache == null) { 6732 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 6733 } 6734 } 6735 6736 @UnsupportedAppUsage 6737 private ScrollabilityCache getScrollCache() { 6738 initScrollCache(); 6739 return mScrollCache; 6740 } 6741 6742 /** 6743 * Set the position of the vertical scroll bar. Should be one of 6744 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 6745 * {@link #SCROLLBAR_POSITION_RIGHT}. 6746 * 6747 * @param position Where the vertical scroll bar should be positioned. 6748 */ 6749 public void setVerticalScrollbarPosition(int position) { 6750 if (mVerticalScrollbarPosition != position) { 6751 mVerticalScrollbarPosition = position; 6752 computeOpaqueFlags(); 6753 resolvePadding(); 6754 } 6755 } 6756 6757 /** 6758 * @return The position where the vertical scroll bar will show, if applicable. 6759 * @see #setVerticalScrollbarPosition(int) 6760 */ 6761 public int getVerticalScrollbarPosition() { 6762 return mVerticalScrollbarPosition; 6763 } 6764 6765 boolean isOnScrollbar(float x, float y) { 6766 if (mScrollCache == null) { 6767 return false; 6768 } 6769 x += getScrollX(); 6770 y += getScrollY(); 6771 final boolean canScrollVertically = 6772 computeVerticalScrollRange() > computeVerticalScrollExtent(); 6773 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden() && canScrollVertically) { 6774 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6775 getVerticalScrollBarBounds(null, touchBounds); 6776 if (touchBounds.contains((int) x, (int) y)) { 6777 return true; 6778 } 6779 } 6780 final boolean canScrollHorizontally = 6781 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 6782 if (isHorizontalScrollBarEnabled() && canScrollHorizontally) { 6783 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6784 getHorizontalScrollBarBounds(null, touchBounds); 6785 if (touchBounds.contains((int) x, (int) y)) { 6786 return true; 6787 } 6788 } 6789 return false; 6790 } 6791 6792 @UnsupportedAppUsage 6793 boolean isOnScrollbarThumb(float x, float y) { 6794 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 6795 } 6796 6797 private boolean isOnVerticalScrollbarThumb(float x, float y) { 6798 if (mScrollCache == null || !isVerticalScrollBarEnabled() || isVerticalScrollBarHidden()) { 6799 return false; 6800 } 6801 final int range = computeVerticalScrollRange(); 6802 final int extent = computeVerticalScrollExtent(); 6803 if (range > extent) { 6804 x += getScrollX(); 6805 y += getScrollY(); 6806 final Rect bounds = mScrollCache.mScrollBarBounds; 6807 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6808 getVerticalScrollBarBounds(bounds, touchBounds); 6809 final int offset = computeVerticalScrollOffset(); 6810 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 6811 extent, range); 6812 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 6813 extent, range, offset); 6814 final int thumbTop = bounds.top + thumbOffset; 6815 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 6816 if (x >= touchBounds.left && x <= touchBounds.right 6817 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 6818 return true; 6819 } 6820 } 6821 return false; 6822 } 6823 6824 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 6825 if (mScrollCache == null || !isHorizontalScrollBarEnabled()) { 6826 return false; 6827 } 6828 final int range = computeHorizontalScrollRange(); 6829 final int extent = computeHorizontalScrollExtent(); 6830 if (range > extent) { 6831 x += getScrollX(); 6832 y += getScrollY(); 6833 final Rect bounds = mScrollCache.mScrollBarBounds; 6834 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6835 getHorizontalScrollBarBounds(bounds, touchBounds); 6836 final int offset = computeHorizontalScrollOffset(); 6837 6838 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 6839 extent, range); 6840 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 6841 extent, range, offset); 6842 final int thumbLeft = bounds.left + thumbOffset; 6843 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 6844 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 6845 && y >= touchBounds.top && y <= touchBounds.bottom) { 6846 return true; 6847 } 6848 } 6849 return false; 6850 } 6851 6852 @UnsupportedAppUsage 6853 boolean isDraggingScrollBar() { 6854 return mScrollCache != null 6855 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 6856 } 6857 6858 /** 6859 * Sets the state of all scroll indicators. 6860 * <p> 6861 * See {@link #setScrollIndicators(int, int)} for usage information. 6862 * 6863 * @param indicators a bitmask of indicators that should be enabled, or 6864 * {@code 0} to disable all indicators 6865 * @see #setScrollIndicators(int, int) 6866 * @see #getScrollIndicators() 6867 * @attr ref android.R.styleable#View_scrollIndicators 6868 */ 6869 public void setScrollIndicators(@ScrollIndicators int indicators) { 6870 setScrollIndicators(indicators, 6871 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 6872 } 6873 6874 /** 6875 * Sets the state of the scroll indicators specified by the mask. To change 6876 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 6877 * <p> 6878 * When a scroll indicator is enabled, it will be displayed if the view 6879 * can scroll in the direction of the indicator. 6880 * <p> 6881 * Multiple indicator types may be enabled or disabled by passing the 6882 * logical OR of the desired types. If multiple types are specified, they 6883 * will all be set to the same enabled state. 6884 * <p> 6885 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 6886 * 6887 * @param indicators the indicator direction, or the logical OR of multiple 6888 * indicator directions. One or more of: 6889 * <ul> 6890 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 6891 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 6892 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 6893 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 6894 * <li>{@link #SCROLL_INDICATOR_START}</li> 6895 * <li>{@link #SCROLL_INDICATOR_END}</li> 6896 * </ul> 6897 * @see #setScrollIndicators(int) 6898 * @see #getScrollIndicators() 6899 * @attr ref android.R.styleable#View_scrollIndicators 6900 */ 6901 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 6902 // Shift and sanitize mask. 6903 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 6904 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 6905 6906 // Shift and mask indicators. 6907 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 6908 indicators &= mask; 6909 6910 // Merge with non-masked flags. 6911 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 6912 6913 if (mPrivateFlags3 != updatedFlags) { 6914 mPrivateFlags3 = updatedFlags; 6915 6916 if (indicators != 0) { 6917 initializeScrollIndicatorsInternal(); 6918 } 6919 invalidate(); 6920 } 6921 } 6922 6923 /** 6924 * Returns a bitmask representing the enabled scroll indicators. 6925 * <p> 6926 * For example, if the top and left scroll indicators are enabled and all 6927 * other indicators are disabled, the return value will be 6928 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 6929 * <p> 6930 * To check whether the bottom scroll indicator is enabled, use the value 6931 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 6932 * 6933 * @return a bitmask representing the enabled scroll indicators 6934 */ 6935 @InspectableProperty(flagMapping = { 6936 @FlagEntry(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"), 6937 @FlagEntry(target = SCROLL_INDICATOR_TOP, name = "top"), 6938 @FlagEntry(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"), 6939 @FlagEntry(target = SCROLL_INDICATOR_LEFT, name = "left"), 6940 @FlagEntry(target = SCROLL_INDICATOR_RIGHT, name = "right"), 6941 @FlagEntry(target = SCROLL_INDICATOR_START, name = "start"), 6942 @FlagEntry(target = SCROLL_INDICATOR_END, name = "end") 6943 }) 6944 @ScrollIndicators 6945 public int getScrollIndicators() { 6946 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 6947 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 6948 } 6949 6950 @UnsupportedAppUsage 6951 ListenerInfo getListenerInfo() { 6952 if (mListenerInfo != null) { 6953 return mListenerInfo; 6954 } 6955 mListenerInfo = new ListenerInfo(); 6956 return mListenerInfo; 6957 } 6958 6959 /** 6960 * Register a callback to be invoked when the scroll X or Y positions of 6961 * this view change. 6962 * <p> 6963 * <b>Note:</b> Some views handle scrolling independently from View and may 6964 * have their own separate listeners for scroll-type events. For example, 6965 * {@link android.widget.ListView ListView} allows clients to register an 6966 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 6967 * to listen for changes in list scroll position. 6968 * 6969 * @param l The listener to notify when the scroll X or Y position changes. 6970 * @see android.view.View#getScrollX() 6971 * @see android.view.View#getScrollY() 6972 */ 6973 public void setOnScrollChangeListener(OnScrollChangeListener l) { 6974 getListenerInfo().mOnScrollChangeListener = l; 6975 } 6976 6977 /** 6978 * Register a callback to be invoked when focus of this view changed. 6979 * 6980 * @param l The callback that will run. 6981 */ 6982 public void setOnFocusChangeListener(OnFocusChangeListener l) { 6983 getListenerInfo().mOnFocusChangeListener = l; 6984 } 6985 6986 /** 6987 * Add a listener that will be called when the bounds of the view change due to 6988 * layout processing. 6989 * 6990 * @param listener The listener that will be called when layout bounds change. 6991 */ 6992 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 6993 ListenerInfo li = getListenerInfo(); 6994 if (li.mOnLayoutChangeListeners == null) { 6995 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 6996 } 6997 if (!li.mOnLayoutChangeListeners.contains(listener)) { 6998 li.mOnLayoutChangeListeners.add(listener); 6999 } 7000 } 7001 7002 /** 7003 * Remove a listener for layout changes. 7004 * 7005 * @param listener The listener for layout bounds change. 7006 */ 7007 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 7008 ListenerInfo li = mListenerInfo; 7009 if (li == null || li.mOnLayoutChangeListeners == null) { 7010 return; 7011 } 7012 li.mOnLayoutChangeListeners.remove(listener); 7013 } 7014 7015 /** 7016 * Add a listener for attach state changes. 7017 * 7018 * This listener will be called whenever this view is attached or detached 7019 * from a window. Remove the listener using 7020 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 7021 * 7022 * @param listener Listener to attach 7023 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 7024 */ 7025 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7026 ListenerInfo li = getListenerInfo(); 7027 if (li.mOnAttachStateChangeListeners == null) { 7028 li.mOnAttachStateChangeListeners 7029 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 7030 } 7031 li.mOnAttachStateChangeListeners.add(listener); 7032 } 7033 7034 /** 7035 * Remove a listener for attach state changes. The listener will receive no further 7036 * notification of window attach/detach events. 7037 * 7038 * @param listener Listener to remove 7039 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 7040 */ 7041 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7042 ListenerInfo li = mListenerInfo; 7043 if (li == null || li.mOnAttachStateChangeListeners == null) { 7044 return; 7045 } 7046 li.mOnAttachStateChangeListeners.remove(listener); 7047 } 7048 7049 /** 7050 * Returns the focus-change callback registered for this view. 7051 * 7052 * @return The callback, or null if one is not registered. 7053 */ 7054 public OnFocusChangeListener getOnFocusChangeListener() { 7055 ListenerInfo li = mListenerInfo; 7056 return li != null ? li.mOnFocusChangeListener : null; 7057 } 7058 7059 /** 7060 * Register a callback to be invoked when this view is clicked. If this view is not 7061 * clickable, it becomes clickable. 7062 * 7063 * @param l The callback that will run 7064 * 7065 * @see #setClickable(boolean) 7066 */ 7067 public void setOnClickListener(@Nullable OnClickListener l) { 7068 if (!isClickable()) { 7069 setClickable(true); 7070 } 7071 getListenerInfo().mOnClickListener = l; 7072 } 7073 7074 /** 7075 * Return whether this view has an attached OnClickListener. Returns 7076 * true if there is a listener, false if there is none. 7077 */ 7078 public boolean hasOnClickListeners() { 7079 ListenerInfo li = mListenerInfo; 7080 return (li != null && li.mOnClickListener != null); 7081 } 7082 7083 /** 7084 * Register a callback to be invoked when this view is clicked and held. If this view is not 7085 * long clickable, it becomes long clickable. 7086 * 7087 * @param l The callback that will run 7088 * 7089 * @see #setLongClickable(boolean) 7090 */ 7091 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 7092 if (!isLongClickable()) { 7093 setLongClickable(true); 7094 } 7095 getListenerInfo().mOnLongClickListener = l; 7096 } 7097 7098 /** 7099 * Register a callback to be invoked when this view is context clicked. If the view is not 7100 * context clickable, it becomes context clickable. 7101 * 7102 * @param l The callback that will run 7103 * @see #setContextClickable(boolean) 7104 */ 7105 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 7106 if (!isContextClickable()) { 7107 setContextClickable(true); 7108 } 7109 getListenerInfo().mOnContextClickListener = l; 7110 } 7111 7112 /** 7113 * Register a callback to be invoked when the context menu for this view is 7114 * being built. If this view is not long clickable, it becomes long clickable. 7115 * 7116 * @param l The callback that will run 7117 * 7118 */ 7119 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 7120 if (!isLongClickable()) { 7121 setLongClickable(true); 7122 } 7123 getListenerInfo().mOnCreateContextMenuListener = l; 7124 } 7125 7126 /** 7127 * Set an observer to collect stats for each frame rendered for this view. 7128 * 7129 * @hide 7130 */ 7131 public void addFrameMetricsListener(Window window, 7132 Window.OnFrameMetricsAvailableListener listener, 7133 Handler handler) { 7134 if (mAttachInfo != null) { 7135 if (mAttachInfo.mThreadedRenderer != null) { 7136 if (mFrameMetricsObservers == null) { 7137 mFrameMetricsObservers = new ArrayList<>(); 7138 } 7139 7140 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 7141 handler.getLooper(), listener); 7142 mFrameMetricsObservers.add(fmo); 7143 mAttachInfo.mThreadedRenderer.addFrameMetricsObserver(fmo); 7144 } else { 7145 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7146 } 7147 } else { 7148 if (mFrameMetricsObservers == null) { 7149 mFrameMetricsObservers = new ArrayList<>(); 7150 } 7151 7152 FrameMetricsObserver fmo = new FrameMetricsObserver(window, 7153 handler.getLooper(), listener); 7154 mFrameMetricsObservers.add(fmo); 7155 } 7156 } 7157 7158 /** 7159 * Remove observer configured to collect frame stats for this view. 7160 * 7161 * @hide 7162 */ 7163 public void removeFrameMetricsListener( 7164 Window.OnFrameMetricsAvailableListener listener) { 7165 ThreadedRenderer renderer = getThreadedRenderer(); 7166 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 7167 if (fmo == null) { 7168 throw new IllegalArgumentException( 7169 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 7170 } 7171 7172 if (mFrameMetricsObservers != null) { 7173 mFrameMetricsObservers.remove(fmo); 7174 if (renderer != null) { 7175 renderer.removeFrameMetricsObserver(fmo); 7176 } 7177 } 7178 } 7179 7180 private void registerPendingFrameMetricsObservers() { 7181 if (mFrameMetricsObservers != null) { 7182 ThreadedRenderer renderer = getThreadedRenderer(); 7183 if (renderer != null) { 7184 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 7185 renderer.addFrameMetricsObserver(fmo); 7186 } 7187 } else { 7188 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7189 } 7190 } 7191 } 7192 7193 private FrameMetricsObserver findFrameMetricsObserver( 7194 Window.OnFrameMetricsAvailableListener listener) { 7195 if (mFrameMetricsObservers != null) { 7196 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 7197 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 7198 if (observer.mListener == listener) { 7199 return observer; 7200 } 7201 } 7202 } 7203 7204 return null; 7205 } 7206 7207 /** @hide */ 7208 public void setNotifyAutofillManagerOnClick(boolean notify) { 7209 if (notify) { 7210 mPrivateFlags |= PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7211 } else { 7212 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7213 } 7214 } 7215 7216 private void notifyAutofillManagerOnClick() { 7217 if ((mPrivateFlags & PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK) != 0) { 7218 try { 7219 getAutofillManager().notifyViewClicked(this); 7220 } finally { 7221 // Set it to already called so it's not called twice when called by 7222 // performClickInternal() 7223 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7224 } 7225 } 7226 } 7227 7228 /** 7229 * Entry point for {@link #performClick()} - other methods on View should call it instead of 7230 * {@code performClick()} directly to make sure the autofill manager is notified when 7231 * necessary (as subclasses could extend {@code performClick()} without calling the parent's 7232 * method). 7233 */ 7234 private boolean performClickInternal() { 7235 // Must notify autofill manager before performing the click actions to avoid scenarios where 7236 // the app has a click listener that changes the state of views the autofill service might 7237 // be interested on. 7238 notifyAutofillManagerOnClick(); 7239 7240 return performClick(); 7241 } 7242 7243 /** 7244 * Call this view's OnClickListener, if it is defined. Performs all normal 7245 * actions associated with clicking: reporting accessibility event, playing 7246 * a sound, etc. 7247 * 7248 * @return True there was an assigned OnClickListener that was called, false 7249 * otherwise is returned. 7250 */ 7251 // NOTE: other methods on View should not call this method directly, but performClickInternal() 7252 // instead, to guarantee that the autofill manager is notified when necessary (as subclasses 7253 // could extend this method without calling super.performClick()). 7254 public boolean performClick() { 7255 // We still need to call this method to handle the cases where performClick() was called 7256 // externally, instead of through performClickInternal() 7257 notifyAutofillManagerOnClick(); 7258 7259 final boolean result; 7260 final ListenerInfo li = mListenerInfo; 7261 if (li != null && li.mOnClickListener != null) { 7262 playSoundEffect(SoundEffectConstants.CLICK); 7263 li.mOnClickListener.onClick(this); 7264 result = true; 7265 } else { 7266 result = false; 7267 } 7268 7269 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 7270 7271 notifyEnterOrExitForAutoFillIfNeeded(true); 7272 7273 return result; 7274 } 7275 7276 /** 7277 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 7278 * this only calls the listener, and does not do any associated clicking 7279 * actions like reporting an accessibility event. 7280 * 7281 * @return True there was an assigned OnClickListener that was called, false 7282 * otherwise is returned. 7283 */ 7284 public boolean callOnClick() { 7285 ListenerInfo li = mListenerInfo; 7286 if (li != null && li.mOnClickListener != null) { 7287 li.mOnClickListener.onClick(this); 7288 return true; 7289 } 7290 return false; 7291 } 7292 7293 /** 7294 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7295 * context menu if the OnLongClickListener did not consume the event. 7296 * 7297 * @return {@code true} if one of the above receivers consumed the event, 7298 * {@code false} otherwise 7299 */ 7300 public boolean performLongClick() { 7301 return performLongClickInternal(mLongClickX, mLongClickY); 7302 } 7303 7304 /** 7305 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7306 * context menu if the OnLongClickListener did not consume the event, 7307 * anchoring it to an (x,y) coordinate. 7308 * 7309 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 7310 * to disable anchoring 7311 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 7312 * to disable anchoring 7313 * @return {@code true} if one of the above receivers consumed the event, 7314 * {@code false} otherwise 7315 */ 7316 public boolean performLongClick(float x, float y) { 7317 mLongClickX = x; 7318 mLongClickY = y; 7319 final boolean handled = performLongClick(); 7320 mLongClickX = Float.NaN; 7321 mLongClickY = Float.NaN; 7322 return handled; 7323 } 7324 7325 /** 7326 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7327 * context menu if the OnLongClickListener did not consume the event, 7328 * optionally anchoring it to an (x,y) coordinate. 7329 * 7330 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 7331 * to disable anchoring 7332 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 7333 * to disable anchoring 7334 * @return {@code true} if one of the above receivers consumed the event, 7335 * {@code false} otherwise 7336 */ 7337 private boolean performLongClickInternal(float x, float y) { 7338 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 7339 7340 boolean handled = false; 7341 final ListenerInfo li = mListenerInfo; 7342 if (li != null && li.mOnLongClickListener != null) { 7343 handled = li.mOnLongClickListener.onLongClick(View.this); 7344 } 7345 if (!handled) { 7346 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 7347 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 7348 } 7349 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 7350 if (!handled) { 7351 handled = showLongClickTooltip((int) x, (int) y); 7352 } 7353 } 7354 if (handled) { 7355 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 7356 } 7357 return handled; 7358 } 7359 7360 /** 7361 * Call this view's OnContextClickListener, if it is defined. 7362 * 7363 * @param x the x coordinate of the context click 7364 * @param y the y coordinate of the context click 7365 * @return True if there was an assigned OnContextClickListener that consumed the event, false 7366 * otherwise. 7367 */ 7368 public boolean performContextClick(float x, float y) { 7369 return performContextClick(); 7370 } 7371 7372 /** 7373 * Call this view's OnContextClickListener, if it is defined. 7374 * 7375 * @return True if there was an assigned OnContextClickListener that consumed the event, false 7376 * otherwise. 7377 */ 7378 public boolean performContextClick() { 7379 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 7380 7381 boolean handled = false; 7382 ListenerInfo li = mListenerInfo; 7383 if (li != null && li.mOnContextClickListener != null) { 7384 handled = li.mOnContextClickListener.onContextClick(View.this); 7385 } 7386 if (handled) { 7387 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 7388 } 7389 return handled; 7390 } 7391 7392 /** 7393 * Performs button-related actions during a touch down event. 7394 * 7395 * @param event The event. 7396 * @return True if the down was consumed. 7397 * 7398 * @hide 7399 */ 7400 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 7401 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 7402 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 7403 showContextMenu(event.getX(), event.getY()); 7404 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 7405 return true; 7406 } 7407 return false; 7408 } 7409 7410 /** 7411 * Shows the context menu for this view. 7412 * 7413 * @return {@code true} if the context menu was shown, {@code false} 7414 * otherwise 7415 * @see #showContextMenu(float, float) 7416 */ 7417 public boolean showContextMenu() { 7418 return getParent().showContextMenuForChild(this); 7419 } 7420 7421 /** 7422 * Shows the context menu for this view anchored to the specified 7423 * view-relative coordinate. 7424 * 7425 * @param x the X coordinate in pixels relative to the view to which the 7426 * menu should be anchored, or {@link Float#NaN} to disable anchoring 7427 * @param y the Y coordinate in pixels relative to the view to which the 7428 * menu should be anchored, or {@link Float#NaN} to disable anchoring 7429 * @return {@code true} if the context menu was shown, {@code false} 7430 * otherwise 7431 */ 7432 public boolean showContextMenu(float x, float y) { 7433 return getParent().showContextMenuForChild(this, x, y); 7434 } 7435 7436 /** 7437 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 7438 * 7439 * @param callback Callback that will control the lifecycle of the action mode 7440 * @return The new action mode if it is started, null otherwise 7441 * 7442 * @see ActionMode 7443 * @see #startActionMode(android.view.ActionMode.Callback, int) 7444 */ 7445 public ActionMode startActionMode(ActionMode.Callback callback) { 7446 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 7447 } 7448 7449 /** 7450 * Start an action mode with the given type. 7451 * 7452 * @param callback Callback that will control the lifecycle of the action mode 7453 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 7454 * @return The new action mode if it is started, null otherwise 7455 * 7456 * @see ActionMode 7457 */ 7458 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 7459 ViewParent parent = getParent(); 7460 if (parent == null) return null; 7461 try { 7462 return parent.startActionModeForChild(this, callback, type); 7463 } catch (AbstractMethodError ame) { 7464 // Older implementations of custom views might not implement this. 7465 return parent.startActionModeForChild(this, callback); 7466 } 7467 } 7468 7469 /** 7470 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 7471 * Context, creating a unique View identifier to retrieve the result. 7472 * 7473 * @param intent The Intent to be started. 7474 * @param requestCode The request code to use. 7475 * @hide 7476 */ 7477 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 7478 public void startActivityForResult(Intent intent, int requestCode) { 7479 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 7480 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 7481 } 7482 7483 /** 7484 * If this View corresponds to the calling who, dispatches the activity result. 7485 * @param who The identifier for the targeted View to receive the result. 7486 * @param requestCode The integer request code originally supplied to 7487 * startActivityForResult(), allowing you to identify who this 7488 * result came from. 7489 * @param resultCode The integer result code returned by the child activity 7490 * through its setResult(). 7491 * @param data An Intent, which can return result data to the caller 7492 * (various data can be attached to Intent "extras"). 7493 * @return {@code true} if the activity result was dispatched. 7494 * @hide 7495 */ 7496 public boolean dispatchActivityResult( 7497 String who, int requestCode, int resultCode, Intent data) { 7498 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 7499 onActivityResult(requestCode, resultCode, data); 7500 mStartActivityRequestWho = null; 7501 return true; 7502 } 7503 return false; 7504 } 7505 7506 /** 7507 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 7508 * 7509 * @param requestCode The integer request code originally supplied to 7510 * startActivityForResult(), allowing you to identify who this 7511 * result came from. 7512 * @param resultCode The integer result code returned by the child activity 7513 * through its setResult(). 7514 * @param data An Intent, which can return result data to the caller 7515 * (various data can be attached to Intent "extras"). 7516 * @hide 7517 */ 7518 public void onActivityResult(int requestCode, int resultCode, Intent data) { 7519 // Do nothing. 7520 } 7521 7522 /** 7523 * Register a callback to be invoked when a hardware key is pressed in this view. 7524 * Key presses in software input methods will generally not trigger the methods of 7525 * this listener. 7526 * @param l the key listener to attach to this view 7527 */ 7528 public void setOnKeyListener(OnKeyListener l) { 7529 getListenerInfo().mOnKeyListener = l; 7530 } 7531 7532 /** 7533 * Register a callback to be invoked when a touch event is sent to this view. 7534 * @param l the touch listener to attach to this view 7535 */ 7536 public void setOnTouchListener(OnTouchListener l) { 7537 getListenerInfo().mOnTouchListener = l; 7538 } 7539 7540 /** 7541 * Register a callback to be invoked when a generic motion event is sent to this view. 7542 * @param l the generic motion listener to attach to this view 7543 */ 7544 public void setOnGenericMotionListener(OnGenericMotionListener l) { 7545 getListenerInfo().mOnGenericMotionListener = l; 7546 } 7547 7548 /** 7549 * Register a callback to be invoked when a hover event is sent to this view. 7550 * @param l the hover listener to attach to this view 7551 */ 7552 public void setOnHoverListener(OnHoverListener l) { 7553 getListenerInfo().mOnHoverListener = l; 7554 } 7555 7556 /** 7557 * Register a drag event listener callback object for this View. The parameter is 7558 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 7559 * View, the system calls the 7560 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 7561 * @param l An implementation of {@link android.view.View.OnDragListener}. 7562 */ 7563 public void setOnDragListener(OnDragListener l) { 7564 getListenerInfo().mOnDragListener = l; 7565 } 7566 7567 /** 7568 * Give this view focus. This will cause 7569 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 7570 * 7571 * Note: this does not check whether this {@link View} should get focus, it just 7572 * gives it focus no matter what. It should only be called internally by framework 7573 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 7574 * 7575 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 7576 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 7577 * focus moved when requestFocus() is called. It may not always 7578 * apply, in which case use the default View.FOCUS_DOWN. 7579 * @param previouslyFocusedRect The rectangle of the view that had focus 7580 * prior in this View's coordinate system. 7581 */ 7582 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 7583 if (DBG) { 7584 System.out.println(this + " requestFocus()"); 7585 } 7586 7587 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 7588 mPrivateFlags |= PFLAG_FOCUSED; 7589 7590 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 7591 7592 if (mParent != null) { 7593 mParent.requestChildFocus(this, this); 7594 updateFocusedInCluster(oldFocus, direction); 7595 } 7596 7597 if (mAttachInfo != null) { 7598 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 7599 } 7600 7601 onFocusChanged(true, direction, previouslyFocusedRect); 7602 refreshDrawableState(); 7603 } 7604 } 7605 7606 /** 7607 * Sets this view's preference for reveal behavior when it gains focus. 7608 * 7609 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 7610 * this view would prefer to be brought fully into view when it gains focus. 7611 * For example, a text field that a user is meant to type into. Other views such 7612 * as scrolling containers may prefer to opt-out of this behavior.</p> 7613 * 7614 * <p>The default value for views is true, though subclasses may change this 7615 * based on their preferred behavior.</p> 7616 * 7617 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 7618 * 7619 * @see #getRevealOnFocusHint() 7620 */ 7621 public final void setRevealOnFocusHint(boolean revealOnFocus) { 7622 if (revealOnFocus) { 7623 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 7624 } else { 7625 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 7626 } 7627 } 7628 7629 /** 7630 * Returns this view's preference for reveal behavior when it gains focus. 7631 * 7632 * <p>When this method returns true for a child view requesting focus, ancestor 7633 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 7634 * should make a best effort to make the newly focused child fully visible to the user. 7635 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 7636 * other properties affecting visibility to the user as part of the focus change.</p> 7637 * 7638 * @return true if this view would prefer to become fully visible when it gains focus, 7639 * false if it would prefer not to disrupt scroll positioning 7640 * 7641 * @see #setRevealOnFocusHint(boolean) 7642 */ 7643 public final boolean getRevealOnFocusHint() { 7644 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 7645 } 7646 7647 /** 7648 * Populates <code>outRect</code> with the hotspot bounds. By default, 7649 * the hotspot bounds are identical to the screen bounds. 7650 * 7651 * @param outRect rect to populate with hotspot bounds 7652 * @hide Only for internal use by views and widgets. 7653 */ 7654 public void getHotspotBounds(Rect outRect) { 7655 final Drawable background = getBackground(); 7656 if (background != null) { 7657 background.getHotspotBounds(outRect); 7658 } else { 7659 getBoundsOnScreen(outRect); 7660 } 7661 } 7662 7663 /** 7664 * Request that a rectangle of this view be visible on the screen, 7665 * scrolling if necessary just enough. 7666 * 7667 * <p>A View should call this if it maintains some notion of which part 7668 * of its content is interesting. For example, a text editing view 7669 * should call this when its cursor moves. 7670 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 7671 * It should not be affected by which part of the View is currently visible or its scroll 7672 * position. 7673 * 7674 * @param rectangle The rectangle in the View's content coordinate space 7675 * @return Whether any parent scrolled. 7676 */ 7677 public boolean requestRectangleOnScreen(Rect rectangle) { 7678 return requestRectangleOnScreen(rectangle, false); 7679 } 7680 7681 /** 7682 * Request that a rectangle of this view be visible on the screen, 7683 * scrolling if necessary just enough. 7684 * 7685 * <p>A View should call this if it maintains some notion of which part 7686 * of its content is interesting. For example, a text editing view 7687 * should call this when its cursor moves. 7688 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 7689 * It should not be affected by which part of the View is currently visible or its scroll 7690 * position. 7691 * <p>When <code>immediate</code> is set to true, scrolling will not be 7692 * animated. 7693 * 7694 * @param rectangle The rectangle in the View's content coordinate space 7695 * @param immediate True to forbid animated scrolling, false otherwise 7696 * @return Whether any parent scrolled. 7697 */ 7698 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 7699 if (mParent == null) { 7700 return false; 7701 } 7702 7703 View child = this; 7704 7705 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 7706 position.set(rectangle); 7707 7708 ViewParent parent = mParent; 7709 boolean scrolled = false; 7710 while (parent != null) { 7711 rectangle.set((int) position.left, (int) position.top, 7712 (int) position.right, (int) position.bottom); 7713 7714 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 7715 7716 if (!(parent instanceof View)) { 7717 break; 7718 } 7719 7720 // move it from child's content coordinate space to parent's content coordinate space 7721 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 7722 7723 child = (View) parent; 7724 parent = child.getParent(); 7725 } 7726 7727 return scrolled; 7728 } 7729 7730 /** 7731 * Called when this view wants to give up focus. If focus is cleared 7732 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 7733 * <p> 7734 * <strong>Note:</strong> When not in touch-mode, the framework will try to give focus 7735 * to the first focusable View from the top after focus is cleared. Hence, if this 7736 * View is the first from the top that can take focus, then all callbacks 7737 * related to clearing focus will be invoked after which the framework will 7738 * give focus to this view. 7739 * </p> 7740 */ 7741 public void clearFocus() { 7742 if (DBG) { 7743 System.out.println(this + " clearFocus()"); 7744 } 7745 7746 final boolean refocus = sAlwaysAssignFocus || !isInTouchMode(); 7747 clearFocusInternal(null, true, refocus); 7748 } 7749 7750 /** 7751 * Clears focus from the view, optionally propagating the change up through 7752 * the parent hierarchy and requesting that the root view place new focus. 7753 * 7754 * @param propagate whether to propagate the change up through the parent 7755 * hierarchy 7756 * @param refocus when propagate is true, specifies whether to request the 7757 * root view place new focus 7758 */ 7759 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 7760 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 7761 mPrivateFlags &= ~PFLAG_FOCUSED; 7762 clearParentsWantFocus(); 7763 7764 if (propagate && mParent != null) { 7765 mParent.clearChildFocus(this); 7766 } 7767 7768 onFocusChanged(false, 0, null); 7769 refreshDrawableState(); 7770 7771 if (propagate && (!refocus || !rootViewRequestFocus())) { 7772 notifyGlobalFocusCleared(this); 7773 } 7774 } 7775 } 7776 7777 void notifyGlobalFocusCleared(View oldFocus) { 7778 if (oldFocus != null && mAttachInfo != null) { 7779 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 7780 } 7781 } 7782 7783 boolean rootViewRequestFocus() { 7784 final View root = getRootView(); 7785 return root != null && root.requestFocus(); 7786 } 7787 7788 /** 7789 * Called internally by the view system when a new view is getting focus. 7790 * This is what clears the old focus. 7791 * <p> 7792 * <b>NOTE:</b> The parent view's focused child must be updated manually 7793 * after calling this method. Otherwise, the view hierarchy may be left in 7794 * an inconstent state. 7795 */ 7796 void unFocus(View focused) { 7797 if (DBG) { 7798 System.out.println(this + " unFocus()"); 7799 } 7800 7801 clearFocusInternal(focused, false, false); 7802 } 7803 7804 /** 7805 * Returns true if this view has focus itself, or is the ancestor of the 7806 * view that has focus. 7807 * 7808 * @return True if this view has or contains focus, false otherwise. 7809 */ 7810 @ViewDebug.ExportedProperty(category = "focus") 7811 public boolean hasFocus() { 7812 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 7813 } 7814 7815 /** 7816 * Returns true if this view is focusable or if it contains a reachable View 7817 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 7818 * is a view whose parents do not block descendants focus. 7819 * Only {@link #VISIBLE} views are considered focusable. 7820 * 7821 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 7822 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 7823 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 7824 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 7825 * {@code false} for views not explicitly marked as focusable. 7826 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 7827 * behavior.</p> 7828 * 7829 * @return {@code true} if the view is focusable or if the view contains a focusable 7830 * view, {@code false} otherwise 7831 * 7832 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 7833 * @see ViewGroup#getTouchscreenBlocksFocus() 7834 * @see #hasExplicitFocusable() 7835 */ 7836 public boolean hasFocusable() { 7837 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 7838 } 7839 7840 /** 7841 * Returns true if this view is focusable or if it contains a reachable View 7842 * for which {@link #hasExplicitFocusable()} returns {@code true}. 7843 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 7844 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 7845 * {@link #FOCUSABLE} are considered focusable. 7846 * 7847 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 7848 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 7849 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 7850 * to focusable will not.</p> 7851 * 7852 * @return {@code true} if the view is focusable or if the view contains a focusable 7853 * view, {@code false} otherwise 7854 * 7855 * @see #hasFocusable() 7856 */ 7857 public boolean hasExplicitFocusable() { 7858 return hasFocusable(false, true); 7859 } 7860 7861 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 7862 if (!isFocusableInTouchMode()) { 7863 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 7864 final ViewGroup g = (ViewGroup) p; 7865 if (g.shouldBlockFocusForTouchscreen()) { 7866 return false; 7867 } 7868 } 7869 } 7870 7871 // Invisible, gone, or disabled views are never focusable. 7872 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE 7873 || (mViewFlags & ENABLED_MASK) != ENABLED) { 7874 return false; 7875 } 7876 7877 // Only use effective focusable value when allowed. 7878 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 7879 return true; 7880 } 7881 7882 return false; 7883 } 7884 7885 /** 7886 * Called by the view system when the focus state of this view changes. 7887 * When the focus change event is caused by directional navigation, direction 7888 * and previouslyFocusedRect provide insight into where the focus is coming from. 7889 * When overriding, be sure to call up through to the super class so that 7890 * the standard focus handling will occur. 7891 * 7892 * @param gainFocus True if the View has focus; false otherwise. 7893 * @param direction The direction focus has moved when requestFocus() 7894 * is called to give this view focus. Values are 7895 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 7896 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 7897 * It may not always apply, in which case use the default. 7898 * @param previouslyFocusedRect The rectangle, in this view's coordinate 7899 * system, of the previously focused view. If applicable, this will be 7900 * passed in as finer grained information about where the focus is coming 7901 * from (in addition to direction). Will be <code>null</code> otherwise. 7902 */ 7903 @CallSuper 7904 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 7905 @Nullable Rect previouslyFocusedRect) { 7906 if (gainFocus) { 7907 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 7908 } else { 7909 notifyViewAccessibilityStateChangedIfNeeded( 7910 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 7911 } 7912 7913 // Here we check whether we still need the default focus highlight, and switch it on/off. 7914 switchDefaultFocusHighlight(); 7915 7916 if (!gainFocus) { 7917 if (isPressed()) { 7918 setPressed(false); 7919 } 7920 if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 7921 notifyFocusChangeToInputMethodManager(false /* hasFocus */); 7922 } 7923 onFocusLost(); 7924 } else if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) { 7925 notifyFocusChangeToInputMethodManager(true /* hasFocus */); 7926 } 7927 7928 invalidate(true); 7929 ListenerInfo li = mListenerInfo; 7930 if (li != null && li.mOnFocusChangeListener != null) { 7931 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 7932 } 7933 7934 if (mAttachInfo != null) { 7935 mAttachInfo.mKeyDispatchState.reset(this); 7936 } 7937 7938 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 7939 } 7940 7941 /** 7942 * Notify {@link InputMethodManager} about the focus change of the {@link View}. 7943 * 7944 * <p>Does nothing when {@link InputMethodManager} is not available.</p> 7945 * 7946 * @param hasFocus {@code true} when the {@link View} is being focused. 7947 */ 7948 private void notifyFocusChangeToInputMethodManager(boolean hasFocus) { 7949 final InputMethodManager imm = 7950 getContext().getSystemService(InputMethodManager.class); 7951 if (imm == null) { 7952 return; 7953 } 7954 if (hasFocus) { 7955 imm.focusIn(this); 7956 } else { 7957 imm.focusOut(this); 7958 } 7959 } 7960 7961 /** @hide */ 7962 public void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 7963 if (canNotifyAutofillEnterExitEvent()) { 7964 AutofillManager afm = getAutofillManager(); 7965 if (afm != null) { 7966 if (enter && isFocused()) { 7967 // We have not been laid out yet, hence cannot evaluate 7968 // whether this view is visible to the user, we will do 7969 // the evaluation once layout is complete. 7970 if (!isLaidOut()) { 7971 mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 7972 } else if (isVisibleToUser()) { 7973 // TODO This is a potential problem that View gets focus before it's visible 7974 // to User. Ideally View should handle the event when isVisibleToUser() 7975 // becomes true where it should issue notifyViewEntered(). 7976 afm.notifyViewEntered(this); 7977 } 7978 } else if (!enter && !isFocused()) { 7979 afm.notifyViewExited(this); 7980 } 7981 } 7982 } 7983 } 7984 7985 /** 7986 * Visually distinct portion of a window with window-like semantics are considered panes for 7987 * accessibility purposes. One example is the content view of a fragment that is replaced. 7988 * In order for accessibility services to understand a pane's window-like behavior, panes 7989 * should have descriptive titles. Views with pane titles produce {@link AccessibilityEvent}s 7990 * when they appear, disappear, or change title. 7991 * 7992 * @param accessibilityPaneTitle The pane's title. Setting to {@code null} indicates that this 7993 * View is not a pane. 7994 * 7995 * {@see AccessibilityNodeInfo#setPaneTitle(CharSequence)} 7996 * 7997 * @attr ref android.R.styleable#View_accessibilityPaneTitle 7998 */ 7999 public void setAccessibilityPaneTitle(@Nullable CharSequence accessibilityPaneTitle) { 8000 if (!TextUtils.equals(accessibilityPaneTitle, mAccessibilityPaneTitle)) { 8001 mAccessibilityPaneTitle = accessibilityPaneTitle; 8002 notifyViewAccessibilityStateChangedIfNeeded( 8003 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE); 8004 } 8005 } 8006 8007 /** 8008 * Get the title of the pane for purposes of accessibility. 8009 * 8010 * @return The current pane title. 8011 * 8012 * {@see #setAccessibilityPaneTitle}. 8013 * 8014 * @attr ref android.R.styleable#View_accessibilityPaneTitle 8015 */ 8016 @InspectableProperty 8017 @Nullable 8018 public CharSequence getAccessibilityPaneTitle() { 8019 return mAccessibilityPaneTitle; 8020 } 8021 8022 private boolean isAccessibilityPane() { 8023 return mAccessibilityPaneTitle != null; 8024 } 8025 8026 /** 8027 * Sends an accessibility event of the given type. If accessibility is 8028 * not enabled this method has no effect. The default implementation calls 8029 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 8030 * to populate information about the event source (this View), then calls 8031 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 8032 * populate the text content of the event source including its descendants, 8033 * and last calls 8034 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 8035 * on its parent to request sending of the event to interested parties. 8036 * <p> 8037 * If an {@link AccessibilityDelegate} has been specified via calling 8038 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8039 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 8040 * responsible for handling this call. 8041 * </p> 8042 * 8043 * @param eventType The type of the event to send, as defined by several types from 8044 * {@link android.view.accessibility.AccessibilityEvent}, such as 8045 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 8046 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 8047 * 8048 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 8049 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8050 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 8051 * @see AccessibilityDelegate 8052 */ 8053 public void sendAccessibilityEvent(int eventType) { 8054 if (mAccessibilityDelegate != null) { 8055 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 8056 } else { 8057 sendAccessibilityEventInternal(eventType); 8058 } 8059 } 8060 8061 /** 8062 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 8063 * {@link AccessibilityEvent} to suggest that an accessibility service announce the 8064 * specified text to its users. 8065 * <p> 8066 * Note: The event generated with this API carries no semantic meaning, and is appropriate only 8067 * in exceptional situations. Apps can generally achieve correct behavior for accessibility by 8068 * accurately supplying the semantics of their UI. 8069 * They should not need to specify what exactly is announced to users. 8070 * 8071 * @param text The announcement text. 8072 */ 8073 public void announceForAccessibility(CharSequence text) { 8074 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 8075 AccessibilityEvent event = AccessibilityEvent.obtain( 8076 AccessibilityEvent.TYPE_ANNOUNCEMENT); 8077 onInitializeAccessibilityEvent(event); 8078 event.getText().add(text); 8079 event.setContentDescription(null); 8080 mParent.requestSendAccessibilityEvent(this, event); 8081 } 8082 } 8083 8084 /** 8085 * @see #sendAccessibilityEvent(int) 8086 * 8087 * Note: Called from the default {@link AccessibilityDelegate}. 8088 * 8089 * @hide 8090 */ 8091 public void sendAccessibilityEventInternal(int eventType) { 8092 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 8093 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 8094 } 8095 } 8096 8097 /** 8098 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 8099 * takes as an argument an empty {@link AccessibilityEvent} and does not 8100 * perform a check whether accessibility is enabled. 8101 * <p> 8102 * If an {@link AccessibilityDelegate} has been specified via calling 8103 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8104 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 8105 * is responsible for handling this call. 8106 * </p> 8107 * 8108 * @param event The event to send. 8109 * 8110 * @see #sendAccessibilityEvent(int) 8111 */ 8112 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 8113 if (mAccessibilityDelegate != null) { 8114 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 8115 } else { 8116 sendAccessibilityEventUncheckedInternal(event); 8117 } 8118 } 8119 8120 /** 8121 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 8122 * 8123 * Note: Called from the default {@link AccessibilityDelegate}. 8124 * 8125 * @hide 8126 */ 8127 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 8128 // Panes disappearing are relevant even if though the view is no longer visible. 8129 boolean isWindowStateChanged = 8130 (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 8131 boolean isWindowDisappearedEvent = isWindowStateChanged && ((event.getContentChangeTypes() 8132 & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) != 0); 8133 if (!isShown() && !isWindowDisappearedEvent) { 8134 return; 8135 } 8136 onInitializeAccessibilityEvent(event); 8137 // Only a subset of accessibility events populates text content. 8138 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 8139 dispatchPopulateAccessibilityEvent(event); 8140 } 8141 // In the beginning we called #isShown(), so we know that getParent() is not null. 8142 ViewParent parent = getParent(); 8143 if (parent != null) { 8144 getParent().requestSendAccessibilityEvent(this, event); 8145 } 8146 } 8147 8148 /** 8149 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 8150 * to its children for adding their text content to the event. Note that the 8151 * event text is populated in a separate dispatch path since we add to the 8152 * event not only the text of the source but also the text of all its descendants. 8153 * A typical implementation will call 8154 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 8155 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 8156 * on each child. Override this method if custom population of the event text 8157 * content is required. 8158 * <p> 8159 * If an {@link AccessibilityDelegate} has been specified via calling 8160 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8161 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 8162 * is responsible for handling this call. 8163 * </p> 8164 * <p> 8165 * <em>Note:</em> Accessibility events of certain types are not dispatched for 8166 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 8167 * </p> 8168 * 8169 * @param event The event. 8170 * 8171 * @return True if the event population was completed. 8172 */ 8173 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 8174 if (mAccessibilityDelegate != null) { 8175 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 8176 } else { 8177 return dispatchPopulateAccessibilityEventInternal(event); 8178 } 8179 } 8180 8181 /** 8182 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8183 * 8184 * Note: Called from the default {@link AccessibilityDelegate}. 8185 * 8186 * @hide 8187 */ 8188 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 8189 onPopulateAccessibilityEvent(event); 8190 return false; 8191 } 8192 8193 /** 8194 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 8195 * giving a chance to this View to populate the accessibility event with its 8196 * text content. While this method is free to modify event 8197 * attributes other than text content, doing so should normally be performed in 8198 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 8199 * <p> 8200 * Example: Adding formatted date string to an accessibility event in addition 8201 * to the text added by the super implementation: 8202 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 8203 * super.onPopulateAccessibilityEvent(event); 8204 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 8205 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 8206 * mCurrentDate.getTimeInMillis(), flags); 8207 * event.getText().add(selectedDateUtterance); 8208 * }</pre> 8209 * <p> 8210 * If an {@link AccessibilityDelegate} has been specified via calling 8211 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8212 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 8213 * is responsible for handling this call. 8214 * </p> 8215 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 8216 * information to the event, in case the default implementation has basic information to add. 8217 * </p> 8218 * 8219 * @param event The accessibility event which to populate. 8220 * 8221 * @see #sendAccessibilityEvent(int) 8222 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8223 */ 8224 @CallSuper 8225 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 8226 if (mAccessibilityDelegate != null) { 8227 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 8228 } else { 8229 onPopulateAccessibilityEventInternal(event); 8230 } 8231 } 8232 8233 /** 8234 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 8235 * 8236 * Note: Called from the default {@link AccessibilityDelegate}. 8237 * 8238 * @hide 8239 */ 8240 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 8241 if ((event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) 8242 && isAccessibilityPane()) { 8243 event.getText().add(getAccessibilityPaneTitle()); 8244 } 8245 } 8246 8247 /** 8248 * Initializes an {@link AccessibilityEvent} with information about 8249 * this View which is the event source. In other words, the source of 8250 * an accessibility event is the view whose state change triggered firing 8251 * the event. 8252 * <p> 8253 * Example: Setting the password property of an event in addition 8254 * to properties set by the super implementation: 8255 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 8256 * super.onInitializeAccessibilityEvent(event); 8257 * event.setPassword(true); 8258 * }</pre> 8259 * <p> 8260 * If an {@link AccessibilityDelegate} has been specified via calling 8261 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8262 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 8263 * is responsible for handling this call. 8264 * </p> 8265 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 8266 * information to the event, in case the default implementation has basic information to add. 8267 * </p> 8268 * @param event The event to initialize. 8269 * 8270 * @see #sendAccessibilityEvent(int) 8271 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8272 */ 8273 @CallSuper 8274 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 8275 if (mAccessibilityDelegate != null) { 8276 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 8277 } else { 8278 onInitializeAccessibilityEventInternal(event); 8279 } 8280 } 8281 8282 /** 8283 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 8284 * 8285 * Note: Called from the default {@link AccessibilityDelegate}. 8286 * 8287 * @hide 8288 */ 8289 @UnsupportedAppUsage 8290 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 8291 event.setSource(this); 8292 event.setClassName(getAccessibilityClassName()); 8293 event.setPackageName(getContext().getPackageName()); 8294 event.setEnabled(isEnabled()); 8295 event.setContentDescription(mContentDescription); 8296 8297 switch (event.getEventType()) { 8298 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 8299 ArrayList<View> focusablesTempList = (mAttachInfo != null) 8300 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 8301 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 8302 event.setItemCount(focusablesTempList.size()); 8303 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 8304 if (mAttachInfo != null) { 8305 focusablesTempList.clear(); 8306 } 8307 } break; 8308 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 8309 CharSequence text = getIterableTextForAccessibility(); 8310 if (text != null && text.length() > 0) { 8311 event.setFromIndex(getAccessibilitySelectionStart()); 8312 event.setToIndex(getAccessibilitySelectionEnd()); 8313 event.setItemCount(text.length()); 8314 } 8315 } break; 8316 } 8317 } 8318 8319 /** 8320 * Returns an {@link AccessibilityNodeInfo} representing this view from the 8321 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 8322 * This method is responsible for obtaining an accessibility node info from a 8323 * pool of reusable instances and calling 8324 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 8325 * initialize the former. 8326 * <p> 8327 * Note: The client is responsible for recycling the obtained instance by calling 8328 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 8329 * </p> 8330 * 8331 * @return A populated {@link AccessibilityNodeInfo}. 8332 * 8333 * @see AccessibilityNodeInfo 8334 */ 8335 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 8336 if (mAccessibilityDelegate != null) { 8337 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 8338 } else { 8339 return createAccessibilityNodeInfoInternal(); 8340 } 8341 } 8342 8343 /** 8344 * @see #createAccessibilityNodeInfo() 8345 * 8346 * @hide 8347 */ 8348 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 8349 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8350 if (provider != null) { 8351 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 8352 } else { 8353 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 8354 onInitializeAccessibilityNodeInfo(info); 8355 return info; 8356 } 8357 } 8358 8359 /** 8360 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 8361 * The base implementation sets: 8362 * <ul> 8363 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 8364 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 8365 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 8366 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 8367 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 8368 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 8369 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 8370 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 8371 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 8372 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 8373 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 8374 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 8375 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 8376 * </ul> 8377 * <p> 8378 * Subclasses should override this method, call the super implementation, 8379 * and set additional attributes. 8380 * </p> 8381 * <p> 8382 * If an {@link AccessibilityDelegate} has been specified via calling 8383 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8384 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 8385 * is responsible for handling this call. 8386 * </p> 8387 * 8388 * @param info The instance to initialize. 8389 */ 8390 @CallSuper 8391 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 8392 if (mAccessibilityDelegate != null) { 8393 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 8394 } else { 8395 onInitializeAccessibilityNodeInfoInternal(info); 8396 } 8397 } 8398 8399 /** 8400 * Gets the location of this view in screen coordinates. 8401 * 8402 * @param outRect The output location 8403 * @hide 8404 */ 8405 @UnsupportedAppUsage 8406 public void getBoundsOnScreen(Rect outRect) { 8407 getBoundsOnScreen(outRect, false); 8408 } 8409 8410 /** 8411 * Gets the location of this view in screen coordinates. 8412 * 8413 * @param outRect The output location 8414 * @param clipToParent Whether to clip child bounds to the parent ones. 8415 * @hide 8416 */ 8417 @UnsupportedAppUsage 8418 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 8419 if (mAttachInfo == null) { 8420 return; 8421 } 8422 8423 RectF position = mAttachInfo.mTmpTransformRect; 8424 position.set(0, 0, mRight - mLeft, mBottom - mTop); 8425 mapRectFromViewToScreenCoords(position, clipToParent); 8426 outRect.set(Math.round(position.left), Math.round(position.top), 8427 Math.round(position.right), Math.round(position.bottom)); 8428 } 8429 8430 /** 8431 * Map a rectangle from view-relative coordinates to screen-relative coordinates 8432 * 8433 * @param rect The rectangle to be mapped 8434 * @param clipToParent Whether to clip child bounds to the parent ones. 8435 * @hide 8436 */ 8437 public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { 8438 if (!hasIdentityMatrix()) { 8439 getMatrix().mapRect(rect); 8440 } 8441 8442 rect.offset(mLeft, mTop); 8443 8444 ViewParent parent = mParent; 8445 while (parent instanceof View) { 8446 View parentView = (View) parent; 8447 8448 rect.offset(-parentView.mScrollX, -parentView.mScrollY); 8449 8450 if (clipToParent) { 8451 rect.left = Math.max(rect.left, 0); 8452 rect.top = Math.max(rect.top, 0); 8453 rect.right = Math.min(rect.right, parentView.getWidth()); 8454 rect.bottom = Math.min(rect.bottom, parentView.getHeight()); 8455 } 8456 8457 if (!parentView.hasIdentityMatrix()) { 8458 parentView.getMatrix().mapRect(rect); 8459 } 8460 8461 rect.offset(parentView.mLeft, parentView.mTop); 8462 8463 parent = parentView.mParent; 8464 } 8465 8466 if (parent instanceof ViewRootImpl) { 8467 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 8468 rect.offset(0, -viewRootImpl.mCurScrollY); 8469 } 8470 8471 rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 8472 } 8473 8474 /** 8475 * Return the class name of this object to be used for accessibility purposes. 8476 * Subclasses should only override this if they are implementing something that 8477 * should be seen as a completely new class of view when used by accessibility, 8478 * unrelated to the class it is deriving from. This is used to fill in 8479 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 8480 */ 8481 public CharSequence getAccessibilityClassName() { 8482 return View.class.getName(); 8483 } 8484 8485 /** 8486 * Called when assist structure is being retrieved from a view as part of 8487 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 8488 * @param structure Fill in with structured view data. The default implementation 8489 * fills in all data that can be inferred from the view itself. 8490 */ 8491 public void onProvideStructure(ViewStructure structure) { 8492 onProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 8493 } 8494 8495 /** 8496 * Populates a {@link ViewStructure} to fullfil an autofill request. 8497 * 8498 * <p>The structure should contain at least the following properties: 8499 * <ul> 8500 * <li>Autofill id ({@link ViewStructure#setAutofillId(AutofillId, int)}). 8501 * <li>Autofill type ({@link ViewStructure#setAutofillType(int)}). 8502 * <li>Autofill value ({@link ViewStructure#setAutofillValue(AutofillValue)}). 8503 * <li>Whether the data is sensitive ({@link ViewStructure#setDataIsSensitive(boolean)}). 8504 * </ul> 8505 * 8506 * <p>It's also recommended to set the following properties - the more properties the structure 8507 * has, the higher the changes of an {@link android.service.autofill.AutofillService} properly 8508 * using the structure: 8509 * 8510 * <ul> 8511 * <li>Autofill hints ({@link ViewStructure#setAutofillHints(String[])}). 8512 * <li>Autofill options ({@link ViewStructure#setAutofillOptions(CharSequence[])}) when the 8513 * view can only be filled with predefined values (typically used when the autofill type 8514 * is {@link #AUTOFILL_TYPE_LIST}). 8515 * <li>Resource id ({@link ViewStructure#setId(int, String, String, String)}). 8516 * <li>Class name ({@link ViewStructure#setClassName(String)}). 8517 * <li>Content description ({@link ViewStructure#setContentDescription(CharSequence)}). 8518 * <li>Visual properties such as visibility ({@link ViewStructure#setVisibility(int)}), 8519 * dimensions ({@link ViewStructure#setDimens(int, int, int, int, int, int)}), and 8520 * opacity ({@link ViewStructure#setOpaque(boolean)}). 8521 * <li>For views representing text fields, text properties such as the text itself 8522 * ({@link ViewStructure#setText(CharSequence)}), text hints 8523 * ({@link ViewStructure#setHint(CharSequence)}, input type 8524 * ({@link ViewStructure#setInputType(int)}), 8525 * <li>For views representing HTML nodes, its web domain 8526 * ({@link ViewStructure#setWebDomain(String)}) and HTML properties 8527 * (({@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}). 8528 * </ul> 8529 * 8530 * <p>The default implementation of this method already sets most of these properties based on 8531 * related {@link View} methods (for example, the autofill id is set using 8532 * {@link #getAutofillId()}, the autofill type set using {@link #getAutofillType()}, etc.), 8533 * and views in the standard Android widgets library also override it to set their 8534 * relevant properties (for example, {@link android.widget.TextView} already sets the text 8535 * properties), so it's recommended to only override this method 8536 * (and call {@code super.onProvideAutofillStructure()}) when: 8537 * 8538 * <ul> 8539 * <li>The view contents does not include PII (Personally Identifiable Information), so it 8540 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 8541 * <li>The view can only be autofilled with predefined options, so it can call 8542 * {@link ViewStructure#setAutofillOptions(CharSequence[])}. 8543 * </ul> 8544 * 8545 * <p><b>Note:</b> The {@code left} and {@code top} values set in 8546 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the next 8547 * {@link ViewGroup#isImportantForAutofill()} predecessor view included in the structure. 8548 * 8549 * <p>Views support the Autofill Framework mainly by: 8550 * <ul> 8551 * <li>Providing the metadata defining what the view means and how it can be autofilled. 8552 * <li>Notifying the Android System when the view value changed by calling 8553 * {@link AutofillManager#notifyValueChanged(View)}. 8554 * <li>Implementing the methods that autofill the view. 8555 * </ul> 8556 * <p>This method is responsible for the former; {@link #autofill(AutofillValue)} is responsible 8557 * for the latter. 8558 * 8559 * @param structure fill in with structured view data for autofill purposes. 8560 * @param flags optional flags. 8561 * 8562 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 8563 */ 8564 public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) { 8565 onProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 8566 } 8567 8568 /** 8569 * Populates a {@link ViewStructure} for content capture. 8570 * 8571 * <p>This method is called after a view is that is eligible for content capture 8572 * (for example, if it {@link #isImportantForAutofill()}, an intelligence service is enabled for 8573 * the user, and the activity rendering the view is enabled for content capture) is laid out and 8574 * is visible. 8575 * 8576 * <p>The populated structure is then passed to the service through 8577 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}. 8578 * 8579 * <p><b>Note: </b>views that manage a virtual structure under this view must populate just 8580 * the node representing this view and return right away, then asynchronously report (not 8581 * necessarily in the UI thread) when the children nodes appear, disappear or have their text 8582 * changed by calling 8583 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}, 8584 * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and 8585 * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence)} 8586 * respectively. The structure for the a child must be created using 8587 * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, long)}, and the 8588 * {@code autofillId} for a child can be obtained either through 8589 * {@code childStructure.getAutofillId()} or 8590 * {@link ContentCaptureSession#newAutofillId(AutofillId, long)}. 8591 * 8592 * <p>When the virtual view hierarchy represents a web page, you should also: 8593 * 8594 * <ul> 8595 * <li>Call {@link ContentCaptureManager#getContentCaptureConditions()} to infer content 8596 * capture events should be generate for that URL. 8597 * <li>Create a new {@link ContentCaptureSession} child for every HTML element that 8598 * renders a new URL (like an {@code IFRAME}) and use that session to notify events from 8599 * that subtree. 8600 * </ul> 8601 * 8602 * <p><b>Note: </b>the following methods of the {@code structure} will be ignored: 8603 * <ul> 8604 * <li>{@link ViewStructure#setChildCount(int)} 8605 * <li>{@link ViewStructure#addChildCount(int)} 8606 * <li>{@link ViewStructure#getChildCount()} 8607 * <li>{@link ViewStructure#newChild(int)} 8608 * <li>{@link ViewStructure#asyncNewChild(int)} 8609 * <li>{@link ViewStructure#asyncCommit()} 8610 * <li>{@link ViewStructure#setWebDomain(String)} 8611 * <li>{@link ViewStructure#newHtmlInfoBuilder(String)} 8612 * <li>{@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)} 8613 * <li>{@link ViewStructure#setDataIsSensitive(boolean)} 8614 * <li>{@link ViewStructure#setAlpha(float)} 8615 * <li>{@link ViewStructure#setElevation(float)} 8616 * <li>{@link ViewStructure#setTransformation(Matrix)} 8617 * 8618 * </ul> 8619 * 8620 * @hide 8621 */ 8622 @TestApi 8623 public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) { 8624 onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags); 8625 } 8626 8627 /** @hide */ 8628 protected void onProvideStructure(@NonNull ViewStructure structure, 8629 @ViewStructureType int viewFor, int flags) { 8630 final int id = mID; 8631 if (id != NO_ID && !isViewIdGenerated(id)) { 8632 String pkg, type, entry; 8633 try { 8634 final Resources res = getResources(); 8635 entry = res.getResourceEntryName(id); 8636 type = res.getResourceTypeName(id); 8637 pkg = res.getResourcePackageName(id); 8638 } catch (Resources.NotFoundException e) { 8639 entry = type = pkg = null; 8640 } 8641 structure.setId(id, pkg, type, entry); 8642 } else { 8643 structure.setId(id, null, null, null); 8644 } 8645 8646 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 8647 || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { 8648 final @AutofillType int autofillType = getAutofillType(); 8649 // Don't need to fill autofill info if view does not support it. 8650 // For example, only TextViews that are editable support autofill 8651 if (autofillType != AUTOFILL_TYPE_NONE) { 8652 structure.setAutofillType(autofillType); 8653 structure.setAutofillHints(getAutofillHints()); 8654 structure.setAutofillValue(getAutofillValue()); 8655 } 8656 structure.setImportantForAutofill(getImportantForAutofill()); 8657 } 8658 8659 int ignoredParentLeft = 0; 8660 int ignoredParentTop = 0; 8661 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 8662 && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 8663 View parentGroup = null; 8664 8665 ViewParent viewParent = getParent(); 8666 if (viewParent instanceof View) { 8667 parentGroup = (View) viewParent; 8668 } 8669 8670 while (parentGroup != null && !parentGroup.isImportantForAutofill()) { 8671 ignoredParentLeft += parentGroup.mLeft; 8672 ignoredParentTop += parentGroup.mTop; 8673 8674 viewParent = parentGroup.getParent(); 8675 if (viewParent instanceof View) { 8676 parentGroup = (View) viewParent; 8677 } else { 8678 break; 8679 } 8680 } 8681 } 8682 8683 structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY, 8684 mRight - mLeft, mBottom - mTop); 8685 if (viewFor == VIEW_STRUCTURE_FOR_ASSIST) { 8686 if (!hasIdentityMatrix()) { 8687 structure.setTransformation(getMatrix()); 8688 } 8689 structure.setElevation(getZ()); 8690 } 8691 structure.setVisibility(getVisibility()); 8692 structure.setEnabled(isEnabled()); 8693 if (isClickable()) { 8694 structure.setClickable(true); 8695 } 8696 if (isFocusable()) { 8697 structure.setFocusable(true); 8698 } 8699 if (isFocused()) { 8700 structure.setFocused(true); 8701 } 8702 if (isAccessibilityFocused()) { 8703 structure.setAccessibilityFocused(true); 8704 } 8705 if (isSelected()) { 8706 structure.setSelected(true); 8707 } 8708 if (isActivated()) { 8709 structure.setActivated(true); 8710 } 8711 if (isLongClickable()) { 8712 structure.setLongClickable(true); 8713 } 8714 if (this instanceof Checkable) { 8715 structure.setCheckable(true); 8716 if (((Checkable)this).isChecked()) { 8717 structure.setChecked(true); 8718 } 8719 } 8720 if (isOpaque()) { 8721 structure.setOpaque(true); 8722 } 8723 if (isContextClickable()) { 8724 structure.setContextClickable(true); 8725 } 8726 structure.setClassName(getAccessibilityClassName().toString()); 8727 structure.setContentDescription(getContentDescription()); 8728 } 8729 8730 /** 8731 * Called when assist structure is being retrieved from a view as part of 8732 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 8733 * generate additional virtual structure under this view. The defaullt implementation 8734 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 8735 * view's virtual accessibility nodes, if any. You can override this for a more 8736 * optimal implementation providing this data. 8737 */ 8738 public void onProvideVirtualStructure(ViewStructure structure) { 8739 onProvideVirtualStructureCompat(structure, false); 8740 } 8741 8742 /** 8743 * Fallback implementation to populate a ViewStructure from accessibility state. 8744 * 8745 * @param structure The structure to populate. 8746 * @param forAutofill Whether the structure is needed for autofill. 8747 */ 8748 private void onProvideVirtualStructureCompat(ViewStructure structure, boolean forAutofill) { 8749 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8750 if (provider != null) { 8751 if (forAutofill && Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 8752 Log.v(AUTOFILL_LOG_TAG, "onProvideVirtualStructureCompat() for " + this); 8753 } 8754 final AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 8755 structure.setChildCount(1); 8756 final ViewStructure root = structure.newChild(0); 8757 populateVirtualStructure(root, provider, info, forAutofill); 8758 info.recycle(); 8759 } 8760 } 8761 8762 /** 8763 * Populates a {@link ViewStructure} containing virtual children to fullfil an autofill 8764 * request. 8765 * 8766 * <p>This method should be used when the view manages a virtual structure under this view. For 8767 * example, a view that draws input fields using {@link #draw(Canvas)}. 8768 * 8769 * <p>When implementing this method, subclasses must follow the rules below: 8770 * 8771 * <ul> 8772 * <li>Add virtual children by calling the {@link ViewStructure#newChild(int)} or 8773 * {@link ViewStructure#asyncNewChild(int)} methods, where the {@code id} is an unique id 8774 * identifying the children in the virtual structure. 8775 * <li>The children hierarchy can have multiple levels if necessary, but ideally it should 8776 * exclude intermediate levels that are irrelevant for autofill; that would improve the 8777 * autofill performance. 8778 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual 8779 * children. 8780 * <li>Set the autofill properties of the child structure as defined by 8781 * {@link #onProvideAutofillStructure(ViewStructure, int)}, using 8782 * {@link ViewStructure#setAutofillId(AutofillId, int)} to set its autofill id. 8783 * <li>Call {@link android.view.autofill.AutofillManager#notifyViewEntered(View, int, Rect)} 8784 * and/or {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} 8785 * when the focused virtual child changed. 8786 * <li>Override {@link #isVisibleToUserForAutofill(int)} to allow the platform to query 8787 * whether a given virtual view is visible to the user in order to support triggering 8788 * save when all views of interest go away. 8789 * <li>Call 8790 * {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, AutofillValue)} 8791 * when the value of a virtual child changed. 8792 * <li>Call {@link 8793 * android.view.autofill.AutofillManager#notifyViewVisibilityChanged(View, int, boolean)} 8794 * when the visibility of a virtual child changed. 8795 * <li>Call 8796 * {@link android.view.autofill.AutofillManager#notifyViewClicked(View, int)} when a virtual 8797 * child is clicked. 8798 * <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure 8799 * changed and the current context should be committed (for example, when the user tapped 8800 * a {@code SUBMIT} button in an HTML page). 8801 * <li>Call {@link AutofillManager#cancel()} when the autofill context of the view structure 8802 * changed and the current context should be canceled (for example, when the user tapped 8803 * a {@code CANCEL} button in an HTML page). 8804 * <li>Provide ways for users to manually request autofill by calling 8805 * {@link AutofillManager#requestAutofill(View, int, Rect)}. 8806 * <li>The {@code left} and {@code top} values set in 8807 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the 8808 * next {@link ViewGroup#isImportantForAutofill()} predecessor view included in the 8809 * structure. 8810 * </ul> 8811 * 8812 * <p>Views with virtual children support the Autofill Framework mainly by: 8813 * <ul> 8814 * <li>Providing the metadata defining what the virtual children mean and how they can be 8815 * autofilled. 8816 * <li>Implementing the methods that autofill the virtual children. 8817 * </ul> 8818 * <p>This method is responsible for the former; {@link #autofill(SparseArray)} is responsible 8819 * for the latter. 8820 * 8821 * @param structure fill in with virtual children data for autofill purposes. 8822 * @param flags optional flags. 8823 * 8824 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 8825 */ 8826 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 8827 if (mContext.isAutofillCompatibilityEnabled()) { 8828 onProvideVirtualStructureCompat(structure, true); 8829 } 8830 } 8831 8832 /** 8833 * Automatically fills the content of this view with the {@code value}. 8834 * 8835 * <p>Views support the Autofill Framework mainly by: 8836 * <ul> 8837 * <li>Providing the metadata defining what the view means and how it can be autofilled. 8838 * <li>Implementing the methods that autofill the view. 8839 * </ul> 8840 * <p>{@link #onProvideAutofillStructure(ViewStructure, int)} is responsible for the former, 8841 * this method is responsible for latter. 8842 * 8843 * <p>This method does nothing by default, but when overridden it typically: 8844 * <ol> 8845 * <li>Checks if the provided value matches the expected type (which is defined by 8846 * {@link #getAutofillType()}). 8847 * <li>Checks if the view is editable - if it isn't, it should return right away. 8848 * <li>Call the proper getter method on {@link AutofillValue} to fetch the actual value. 8849 * <li>Pass the actual value to the equivalent setter in the view. 8850 * </ol> 8851 * 8852 * <p>For example, a text-field view could implement the method this way: 8853 * 8854 * <pre class="prettyprint"> 8855 * @Override 8856 * public void autofill(AutofillValue value) { 8857 * if (!value.isText() || !this.isEditable()) { 8858 * return; 8859 * } 8860 * CharSequence text = value.getTextValue(); 8861 * if (text != null) { 8862 * this.setText(text); 8863 * } 8864 * } 8865 * </pre> 8866 * 8867 * <p>If the value is updated asynchronously, the next call to 8868 * {@link AutofillManager#notifyValueChanged(View)} must happen <b>after</b> the value was 8869 * changed to the autofilled value. If not, the view will not be considered autofilled. 8870 * 8871 * <p><b>Note:</b> After this method is called, the value returned by 8872 * {@link #getAutofillValue()} must be equal to the {@code value} passed to it, otherwise the 8873 * view will not be highlighted as autofilled. 8874 * 8875 * @param value value to be autofilled. 8876 */ 8877 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 8878 } 8879 8880 /** 8881 * Automatically fills the content of the virtual children within this view. 8882 * 8883 * <p>Views with virtual children support the Autofill Framework mainly by: 8884 * <ul> 8885 * <li>Providing the metadata defining what the virtual children mean and how they can be 8886 * autofilled. 8887 * <li>Implementing the methods that autofill the virtual children. 8888 * </ul> 8889 * <p>{@link #onProvideAutofillVirtualStructure(ViewStructure, int)} is responsible for the 8890 * former, this method is responsible for the latter - see {@link #autofill(AutofillValue)} and 8891 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info about autofill. 8892 * 8893 * <p>If a child value is updated asynchronously, the next call to 8894 * {@link AutofillManager#notifyValueChanged(View, int, AutofillValue)} must happen 8895 * <b>after</b> the value was changed to the autofilled value. If not, the child will not be 8896 * considered autofilled. 8897 * 8898 * <p><b>Note:</b> To indicate that a virtual view was autofilled, 8899 * <code>?android:attr/autofilledHighlight</code> should be drawn over it until the data 8900 * changes. 8901 * 8902 * @param values map of values to be autofilled, keyed by virtual child id. 8903 * 8904 * @attr ref android.R.styleable#Theme_autofilledHighlight 8905 */ 8906 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { 8907 if (!mContext.isAutofillCompatibilityEnabled()) { 8908 return; 8909 } 8910 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8911 if (provider == null) { 8912 return; 8913 } 8914 final int valueCount = values.size(); 8915 for (int i = 0; i < valueCount; i++) { 8916 final AutofillValue value = values.valueAt(i); 8917 if (value.isText()) { 8918 final int virtualId = values.keyAt(i); 8919 final CharSequence text = value.getTextValue(); 8920 final Bundle arguments = new Bundle(); 8921 arguments.putCharSequence( 8922 AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text); 8923 provider.performAction(virtualId, AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); 8924 } 8925 } 8926 } 8927 8928 /** 8929 * Gets the unique, logical identifier of this view in the activity, for autofill purposes. 8930 * 8931 * <p>The autofill id is created on demand, unless it is explicitly set by 8932 * {@link #setAutofillId(AutofillId)}. 8933 * 8934 * <p>See {@link #setAutofillId(AutofillId)} for more info. 8935 * 8936 * @return The View's autofill id. 8937 */ 8938 public final AutofillId getAutofillId() { 8939 if (mAutofillId == null) { 8940 // The autofill id needs to be unique, but its value doesn't matter, 8941 // so it's better to reuse the accessibility id to save space. 8942 mAutofillId = new AutofillId(getAutofillViewId()); 8943 } 8944 return mAutofillId; 8945 } 8946 8947 /** 8948 * Sets the unique, logical identifier of this view in the activity, for autofill purposes. 8949 * 8950 * <p>The autofill id is created on demand, and this method should only be called when a view is 8951 * reused after {@link #dispatchProvideAutofillStructure(ViewStructure, int)} is called, as 8952 * that method creates a snapshot of the view that is passed along to the autofill service. 8953 * 8954 * <p>This method is typically used when view subtrees are recycled to represent different 8955 * content* —in this case, the autofill id can be saved before the view content is swapped 8956 * out, and restored later when it's swapped back in. For example: 8957 * 8958 * <pre> 8959 * EditText reusableView = ...; 8960 * ViewGroup parentView = ...; 8961 * AutofillManager afm = ...; 8962 * 8963 * // Swap out the view and change its contents 8964 * AutofillId oldId = reusableView.getAutofillId(); 8965 * CharSequence oldText = reusableView.getText(); 8966 * parentView.removeView(reusableView); 8967 * AutofillId newId = afm.getNextAutofillId(); 8968 * reusableView.setText("New I am"); 8969 * reusableView.setAutofillId(newId); 8970 * parentView.addView(reusableView); 8971 * 8972 * // Later, swap the old content back in 8973 * parentView.removeView(reusableView); 8974 * reusableView.setAutofillId(oldId); 8975 * reusableView.setText(oldText); 8976 * parentView.addView(reusableView); 8977 * </pre> 8978 * 8979 * @param id an autofill ID that is unique in the {@link android.app.Activity} hosting the view, 8980 * or {@code null} to reset it. Usually it's an id previously allocated to another view (and 8981 * obtained through {@link #getAutofillId()}), or a new value obtained through 8982 * {@link AutofillManager#getNextAutofillId()}. 8983 * 8984 * @throws IllegalStateException if the view is already {@link #isAttachedToWindow() attached to 8985 * a window}. 8986 * 8987 * @throws IllegalArgumentException if the id is an autofill id associated with a virtual view. 8988 */ 8989 public void setAutofillId(@Nullable AutofillId id) { 8990 // TODO(b/37566627): add unit / CTS test for all possible combinations below 8991 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 8992 Log.v(AUTOFILL_LOG_TAG, "setAutofill(): from " + mAutofillId + " to " + id); 8993 } 8994 if (isAttachedToWindow()) { 8995 throw new IllegalStateException("Cannot set autofill id when view is attached"); 8996 } 8997 if (id != null && !id.isNonVirtual()) { 8998 throw new IllegalStateException("Cannot set autofill id assigned to virtual views"); 8999 } 9000 if (id == null && (mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) == 0) { 9001 // Ignore reset because it was never explicitly set before. 9002 return; 9003 } 9004 mAutofillId = id; 9005 if (id != null) { 9006 mAutofillViewId = id.getViewId(); 9007 mPrivateFlags3 |= PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9008 } else { 9009 mAutofillViewId = NO_ID; 9010 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9011 } 9012 } 9013 9014 /** 9015 * Describes the autofill type of this view, so an 9016 * {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue} 9017 * when autofilling the view. 9018 * 9019 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it to properly 9020 * support the Autofill Framework. 9021 * 9022 * @return either {@link #AUTOFILL_TYPE_NONE}, {@link #AUTOFILL_TYPE_TEXT}, 9023 * {@link #AUTOFILL_TYPE_LIST}, {@link #AUTOFILL_TYPE_DATE}, or {@link #AUTOFILL_TYPE_TOGGLE}. 9024 * 9025 * @see #onProvideAutofillStructure(ViewStructure, int) 9026 * @see #autofill(AutofillValue) 9027 */ 9028 public @AutofillType int getAutofillType() { 9029 return AUTOFILL_TYPE_NONE; 9030 } 9031 9032 /** 9033 * Gets the hints that help an {@link android.service.autofill.AutofillService} determine how 9034 * to autofill the view with the user's data. 9035 * 9036 * <p>See {@link #setAutofillHints(String...)} for more info about these hints. 9037 * 9038 * @return The hints set via the attribute or {@link #setAutofillHints(String...)}, or 9039 * {@code null} if no hints were set. 9040 * 9041 * @attr ref android.R.styleable#View_autofillHints 9042 */ 9043 @ViewDebug.ExportedProperty() 9044 @InspectableProperty 9045 @Nullable public String[] getAutofillHints() { 9046 return mAutofillHints; 9047 } 9048 9049 /** 9050 * @hide 9051 */ 9052 @TestApi 9053 public boolean isAutofilled() { 9054 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; 9055 } 9056 9057 /** 9058 * Gets the {@link View}'s current autofill value. 9059 * 9060 * <p>By default returns {@code null}, but subclasses should override it and return an 9061 * appropriate value to properly support the Autofill Framework. 9062 * 9063 * @see #onProvideAutofillStructure(ViewStructure, int) 9064 * @see #autofill(AutofillValue) 9065 */ 9066 @Nullable 9067 public AutofillValue getAutofillValue() { 9068 return null; 9069 } 9070 9071 /** 9072 * Gets the mode for determining whether this view is important for autofill. 9073 * 9074 * <p>See {@link #setImportantForAutofill(int)} and {@link #isImportantForAutofill()} for more 9075 * info about this mode. 9076 * 9077 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 9078 * {@link #setImportantForAutofill(int)}. 9079 * 9080 * @attr ref android.R.styleable#View_importantForAutofill 9081 */ 9082 @ViewDebug.ExportedProperty(mapping = { 9083 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 9084 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 9085 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), 9086 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 9087 to = "yesExcludeDescendants"), 9088 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 9089 to = "noExcludeDescendants")}) 9090 @InspectableProperty(enumMapping = { 9091 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"), 9092 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"), 9093 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"), 9094 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 9095 name = "yesExcludeDescendants"), 9096 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 9097 name = "noExcludeDescendants"), 9098 }) 9099 public @AutofillImportance int getImportantForAutofill() { 9100 return (mPrivateFlags3 9101 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 9102 } 9103 9104 /** 9105 * Sets the mode for determining whether this view is considered important for autofill. 9106 * 9107 * <p>The platform determines the importance for autofill automatically but you 9108 * can use this method to customize the behavior. For example: 9109 * 9110 * <ol> 9111 * <li>When the view contents is irrelevant for autofill (for example, a text field used in a 9112 * "Captcha" challenge), it should be {@link #IMPORTANT_FOR_AUTOFILL_NO}. 9113 * <li>When both the view and its children are irrelevant for autofill (for example, the root 9114 * view of an activity containing a spreadhseet editor), it should be 9115 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 9116 * <li>When the view content is relevant for autofill but its children aren't (for example, 9117 * a credit card expiration date represented by a custom view that overrides the proper 9118 * autofill methods and has 2 children representing the month and year), it should 9119 * be {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}. 9120 * </ol> 9121 * 9122 * <p><b>Note:</b> Setting the mode as {@link #IMPORTANT_FOR_AUTOFILL_NO} or 9123 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and its 9124 * children) will be always be considered not important; for example, when the user explicitly 9125 * makes an autofill request, all views are considered important. See 9126 * {@link #isImportantForAutofill()} for more details about how the View's importance for 9127 * autofill is used. 9128 * 9129 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 9130 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, 9131 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 9132 * 9133 * @attr ref android.R.styleable#View_importantForAutofill 9134 */ 9135 public void setImportantForAutofill(@AutofillImportance int mode) { 9136 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 9137 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 9138 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 9139 } 9140 9141 /** 9142 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 9143 * associated with this view is considered important for autofill purposes. 9144 * 9145 * <p>Generally speaking, a view is important for autofill if: 9146 * <ol> 9147 * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}. 9148 * <li>The view contents can help an {@link android.service.autofill.AutofillService} 9149 * determine how other views can be autofilled. 9150 * <ol> 9151 * 9152 * <p>For example, view containers should typically return {@code false} for performance reasons 9153 * (since the important info is provided by their children), but if its properties have relevant 9154 * information (for example, a resource id called {@code credentials}, it should return 9155 * {@code true}. On the other hand, views representing labels or editable fields should 9156 * typically return {@code true}, but in some cases they could return {@code false} 9157 * (for example, if they're part of a "Captcha" mechanism). 9158 * 9159 * <p>The value returned by this method depends on the value returned by 9160 * {@link #getImportantForAutofill()}: 9161 * 9162 * <ol> 9163 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_YES} or 9164 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, then it returns {@code true} 9165 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_NO} or 9166 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}, then it returns {@code false} 9167 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, then it uses some simple heuristics 9168 * that can return {@code true} in some cases (like a container with a resource id), 9169 * but {@code false} in most. 9170 * <li>otherwise, it returns {@code false}. 9171 * </ol> 9172 * 9173 * <p>When a view is considered important for autofill: 9174 * <ul> 9175 * <li>The view might automatically trigger an autofill request when focused on. 9176 * <li>The contents of the view are included in the {@link ViewStructure} used in an autofill 9177 * request. 9178 * </ul> 9179 * 9180 * <p>On the other hand, when a view is considered not important for autofill: 9181 * <ul> 9182 * <li>The view never automatically triggers autofill requests, but it can trigger a manual 9183 * request through {@link AutofillManager#requestAutofill(View)}. 9184 * <li>The contents of the view are not included in the {@link ViewStructure} used in an 9185 * autofill request, unless the request has the 9186 * {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag. 9187 * </ul> 9188 * 9189 * @return whether the view is considered important for autofill. 9190 * 9191 * @see #setImportantForAutofill(int) 9192 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 9193 * @see #IMPORTANT_FOR_AUTOFILL_YES 9194 * @see #IMPORTANT_FOR_AUTOFILL_NO 9195 * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 9196 * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9197 * @see AutofillManager#requestAutofill(View) 9198 */ 9199 public final boolean isImportantForAutofill() { 9200 // Check parent mode to ensure we're not hidden. 9201 ViewParent parent = mParent; 9202 while (parent instanceof View) { 9203 final int parentImportance = ((View) parent).getImportantForAutofill(); 9204 if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9205 || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) { 9206 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9207 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 9208 + "because parent " + parent + "'s importance is " + parentImportance); 9209 } 9210 return false; 9211 } 9212 parent = parent.getParent(); 9213 } 9214 9215 final int importance = getImportantForAutofill(); 9216 9217 // First, check the explicit states. 9218 if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 9219 || importance == IMPORTANT_FOR_AUTOFILL_YES) { 9220 return true; 9221 } 9222 if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9223 || importance == IMPORTANT_FOR_AUTOFILL_NO) { 9224 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9225 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 9226 + "because its importance is " + importance); 9227 } 9228 return false; 9229 } 9230 9231 // Then use some heuristics to handle AUTO. 9232 if (importance != IMPORTANT_FOR_AUTOFILL_AUTO) { 9233 Log.w(AUTOFILL_LOG_TAG, "invalid autofill importance (" + importance + " on view " 9234 + this); 9235 return false; 9236 } 9237 9238 // Always include views that have an explicit resource id. 9239 final int id = mID; 9240 if (id != NO_ID && !isViewIdGenerated(id)) { 9241 final Resources res = getResources(); 9242 String entry = null; 9243 String pkg = null; 9244 try { 9245 entry = res.getResourceEntryName(id); 9246 pkg = res.getResourcePackageName(id); 9247 } catch (Resources.NotFoundException e) { 9248 // ignore 9249 } 9250 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 9251 return true; 9252 } 9253 } 9254 9255 // If the app developer explicitly set hints for it, it's important. 9256 if (getAutofillHints() != null) { 9257 return true; 9258 } 9259 9260 // Otherwise, assume it's not important... 9261 return false; 9262 } 9263 9264 /** 9265 * Gets the mode for determining whether this view is important for content capture. 9266 * 9267 * <p>See {@link #setImportantForContentCapture(int)} and 9268 * {@link #isImportantForContentCapture()} for more info about this mode. 9269 * 9270 * @return {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO} by default, or value passed to 9271 * {@link #setImportantForContentCapture(int)}. 9272 * 9273 * @attr ref android.R.styleable#View_importantForContentCapture 9274 * 9275 * @hide 9276 */ 9277 @ViewDebug.ExportedProperty(mapping = { 9278 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to = "auto"), 9279 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES, to = "yes"), 9280 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO, to = "no"), 9281 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 9282 to = "yesExcludeDescendants"), 9283 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 9284 to = "noExcludeDescendants")}) 9285 // @InspectableProperty(enumMapping = { 9286 // @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"), 9287 // @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"), 9288 // @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"), 9289 // @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 9290 // name = "yesExcludeDescendants"), 9291 // @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 9292 // name = "noExcludeDescendants"), 9293 // }) 9294 @TestApi 9295 public @ContentCaptureImportance int getImportantForContentCapture() { 9296 // NOTE: the important for content capture values were the first flags added and are set in 9297 // the rightmost position, so we don't need to shift them 9298 return mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 9299 } 9300 9301 /** 9302 * Sets the mode for determining whether this view is considered important for content capture. 9303 * 9304 * <p>The platform determines the importance for autofill automatically but you 9305 * can use this method to customize the behavior. Typically, a view that provides text should 9306 * be marked as {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}. 9307 * 9308 * @param mode {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}, 9309 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}, {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO}, 9310 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS}, 9311 * or {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS}. 9312 * 9313 * @attr ref android.R.styleable#View_importantForContentCapture 9314 * 9315 * @hide 9316 */ 9317 @TestApi 9318 public void setImportantForContentCapture(@ContentCaptureImportance int mode) { 9319 // Reset first 9320 mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 9321 // Then set again 9322 // NOTE: the important for content capture values were the first flags added and are set in 9323 // the rightmost position, so we don't need to shift them 9324 mPrivateFlags4 |= (mode & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK); 9325 } 9326 9327 /** 9328 * Hints the Android System whether this view is considered important for content capture, based 9329 * on the value explicitly set by {@link #setImportantForContentCapture(int)} and heuristics 9330 * when it's {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}. 9331 * 9332 * <p>See {@link ContentCaptureManager} for more info about content capture. 9333 * 9334 * @return whether the view is considered important for content capture. 9335 * 9336 * @see #setImportantForContentCapture(int) 9337 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO 9338 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES 9339 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO 9340 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 9341 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 9342 * 9343 * @hide 9344 */ 9345 @TestApi 9346 public final boolean isImportantForContentCapture() { 9347 boolean isImportant; 9348 if ((mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED) != 0) { 9349 isImportant = (mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE) != 0; 9350 return isImportant; 9351 } 9352 9353 isImportant = calculateIsImportantForContentCapture(); 9354 9355 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 9356 if (isImportant) { 9357 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 9358 } 9359 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED; 9360 return isImportant; 9361 } 9362 9363 /** 9364 * Calculates whether the flag is important for content capture so it can be used by 9365 * {@link #isImportantForContentCapture()} while the tree is traversed. 9366 */ 9367 private boolean calculateIsImportantForContentCapture() { 9368 // Check parent mode to ensure we're important 9369 ViewParent parent = mParent; 9370 while (parent instanceof View) { 9371 final int parentImportance = ((View) parent).getImportantForContentCapture(); 9372 if (parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 9373 || parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS) { 9374 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 9375 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for " 9376 + "content capture because parent " + parent + "'s importance is " 9377 + parentImportance); 9378 } 9379 return false; 9380 } 9381 parent = parent.getParent(); 9382 } 9383 9384 final int importance = getImportantForContentCapture(); 9385 9386 // First, check the explicit states. 9387 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 9388 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES) { 9389 return true; 9390 } 9391 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 9392 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO) { 9393 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 9394 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for content " 9395 + "capture because its importance is " + importance); 9396 } 9397 return false; 9398 } 9399 9400 // Then use some heuristics to handle AUTO. 9401 if (importance != IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { 9402 Log.w(CONTENT_CAPTURE_LOG_TAG, "invalid content capture importance (" + importance 9403 + " on view " + this); 9404 return false; 9405 } 9406 9407 // View group is important if at least one children also is 9408 if (this instanceof ViewGroup) { 9409 final ViewGroup group = (ViewGroup) this; 9410 for (int i = 0; i < group.getChildCount(); i++) { 9411 final View child = group.getChildAt(i); 9412 if (child.isImportantForContentCapture()) { 9413 return true; 9414 } 9415 } 9416 } 9417 9418 // If the app developer explicitly set hints or autofill hintsfor it, it's important. 9419 if (getAutofillHints() != null) { 9420 return true; 9421 } 9422 9423 // Otherwise, assume it's not important... 9424 return false; 9425 } 9426 9427 /** 9428 * Helper used to notify the {@link ContentCaptureManager} when the view is removed or 9429 * added, based on whether it's laid out and visible, and without knowing if the parent removed 9430 * it from the view hierarchy. 9431 * 9432 * <p>This method is called from many places (visibility changed, view laid out, view attached 9433 * or detached to/from window, etc...) and hence must contain the logic to call the manager, as 9434 * described below: 9435 * 9436 * <ol> 9437 * <li>It should only be called when content capture is enabled for the view. 9438 * <li>It must call viewAppeared() before viewDisappeared() 9439 * <li>viewAppearead() can only be called when the view is visible and laidout 9440 * <li>It should not call the same event twice. 9441 * </ol> 9442 */ 9443 private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) { 9444 AttachInfo ai = mAttachInfo; 9445 // Skip it while the view is being laided out for the first time 9446 if (ai != null && !ai.mReadyForContentCaptureUpdates) return; 9447 9448 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 9449 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 9450 "notifyContentCapture(" + appeared + ") for " + getClass().getSimpleName()); 9451 } 9452 try { 9453 notifyAppearedOrDisappearedForContentCaptureIfNeededNoTrace(appeared); 9454 } finally { 9455 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 9456 } 9457 } 9458 9459 private void notifyAppearedOrDisappearedForContentCaptureIfNeededNoTrace(boolean appeared) { 9460 AttachInfo ai = mAttachInfo; 9461 9462 // First check if context has client, so it saves a service lookup when it doesn't 9463 if (mContext.getContentCaptureOptions() == null) return; 9464 9465 // Then check if it's enabled in the context... 9466 final ContentCaptureManager ccm = ai != null ? ai.getContentCaptureManager(mContext) 9467 : mContext.getSystemService(ContentCaptureManager.class); 9468 if (ccm == null || !ccm.isContentCaptureEnabled()) return; 9469 9470 // ... and finally at the view level 9471 // NOTE: isImportantForContentCapture() is more expensive than cm.isContentCaptureEnabled() 9472 if (!isImportantForContentCapture()) return; 9473 9474 ContentCaptureSession session = getContentCaptureSession(); 9475 if (session == null) return; 9476 9477 if (appeared) { 9478 if (!isLaidOut() || getVisibility() != VISIBLE 9479 || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) { 9480 if (DEBUG_CONTENT_CAPTURE) { 9481 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid=" 9482 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 9483 + ", visible=" + (getVisibility() == VISIBLE) 9484 + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4 9485 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) 9486 + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4 9487 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0)); 9488 } 9489 return; 9490 } 9491 setNotifiedContentCaptureAppeared(); 9492 9493 if (ai != null) { 9494 ai.delayNotifyContentCaptureEvent(session, this, appeared); 9495 } else { 9496 if (DEBUG_CONTENT_CAPTURE) { 9497 Log.w(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on appeared for " + this); 9498 } 9499 } 9500 } else { 9501 if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) == 0 9502 || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0) { 9503 if (DEBUG_CONTENT_CAPTURE) { 9504 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": laid=" 9505 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 9506 + ", visible=" + (getVisibility() == VISIBLE) 9507 + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4 9508 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) 9509 + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4 9510 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0)); 9511 } 9512 return; 9513 } 9514 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 9515 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 9516 9517 if (ai != null) { 9518 ai.delayNotifyContentCaptureEvent(session, this, appeared); 9519 } else { 9520 if (DEBUG_CONTENT_CAPTURE) { 9521 Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on disappeared for " + this); 9522 } 9523 } 9524 } 9525 } 9526 9527 private void setNotifiedContentCaptureAppeared() { 9528 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 9529 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 9530 } 9531 9532 /** @hide */ 9533 protected boolean getNotifiedContentCaptureAppeared() { 9534 return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0; 9535 } 9536 9537 9538 /** 9539 * Sets the (optional) {@link ContentCaptureSession} associated with this view. 9540 * 9541 * <p>This method should be called when you need to associate a {@link ContentCaptureContext} to 9542 * the content capture events associated with this view or its view hierarchy (if it's a 9543 * {@link ViewGroup}). 9544 * 9545 * <p>For example, if your activity is associated with a web domain, first you would need to 9546 * set the context for the main DOM: 9547 * 9548 * <pre> 9549 * ContentCaptureSession mainSession = rootView.getContentCaptureSession(); 9550 * mainSession.setContentCaptureContext(ContentCaptureContext.forLocusId(Uri.parse(myUrl)); 9551 * </pre> 9552 * 9553 * <p>Then if the page had an {@code IFRAME}, you would create a new session for it: 9554 * 9555 * <pre> 9556 * ContentCaptureSession iframeSession = mainSession.createContentCaptureSession( 9557 * ContentCaptureContext.forLocusId(Uri.parse(iframeUrl))); 9558 * iframeView.setContentCaptureSession(iframeSession); 9559 * </pre> 9560 * 9561 * @param contentCaptureSession a session created by 9562 * {@link ContentCaptureSession#createContentCaptureSession( 9563 * android.view.contentcapture.ContentCaptureContext)}. 9564 */ 9565 public void setContentCaptureSession(@Nullable ContentCaptureSession contentCaptureSession) { 9566 mContentCaptureSession = contentCaptureSession; 9567 } 9568 9569 /** 9570 * Gets the session used to notify content capture events. 9571 * 9572 * @return session explicitly set by {@link #setContentCaptureSession(ContentCaptureSession)}, 9573 * inherited by ancestors, default session or {@code null} if content capture is disabled for 9574 * this view. 9575 */ 9576 @Nullable 9577 public final ContentCaptureSession getContentCaptureSession() { 9578 if (mCachedContentCaptureSession != null) { 9579 return mCachedContentCaptureSession; 9580 } 9581 9582 mCachedContentCaptureSession = getAndCacheContentCaptureSession(); 9583 return mCachedContentCaptureSession; 9584 } 9585 9586 @Nullable 9587 private ContentCaptureSession getAndCacheContentCaptureSession() { 9588 // First try the session explicitly set by setContentCaptureSession() 9589 if (mContentCaptureSession != null) return mContentCaptureSession; 9590 9591 // Then the session explicitly set in an ancestor 9592 ContentCaptureSession session = null; 9593 if (mParent instanceof View) { 9594 session = ((View) mParent).getContentCaptureSession(); 9595 } 9596 9597 // Finally, if no session was explicitly set, use the context's default session. 9598 if (session == null) { 9599 final ContentCaptureManager ccm = mContext 9600 .getSystemService(ContentCaptureManager.class); 9601 return ccm == null ? null : ccm.getMainContentCaptureSession(); 9602 } 9603 return session; 9604 } 9605 9606 @Nullable 9607 private AutofillManager getAutofillManager() { 9608 return mContext.getSystemService(AutofillManager.class); 9609 } 9610 9611 private boolean isAutofillable() { 9612 if (getAutofillType() == AUTOFILL_TYPE_NONE) return false; 9613 9614 if (!isImportantForAutofill()) { 9615 // View is not important for "regular" autofill, so we must check if Augmented Autofill 9616 // is enabled for the activity 9617 final AutofillOptions options = mContext.getAutofillOptions(); 9618 if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { 9619 return false; 9620 } 9621 final AutofillManager afm = getAutofillManager(); 9622 if (afm == null) return false; 9623 afm.notifyViewEnteredForAugmentedAutofill(this); 9624 } 9625 9626 return getAutofillViewId() > LAST_APP_AUTOFILL_ID; 9627 } 9628 9629 /** @hide */ 9630 public boolean canNotifyAutofillEnterExitEvent() { 9631 return isAutofillable() && isAttachedToWindow(); 9632 } 9633 9634 private void populateVirtualStructure(ViewStructure structure, 9635 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, 9636 boolean forAutofill) { 9637 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 9638 null, null, info.getViewIdResourceName()); 9639 Rect rect = structure.getTempRect(); 9640 info.getBoundsInParent(rect); 9641 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 9642 structure.setVisibility(VISIBLE); 9643 structure.setEnabled(info.isEnabled()); 9644 if (info.isClickable()) { 9645 structure.setClickable(true); 9646 } 9647 if (info.isFocusable()) { 9648 structure.setFocusable(true); 9649 } 9650 if (info.isFocused()) { 9651 structure.setFocused(true); 9652 } 9653 if (info.isAccessibilityFocused()) { 9654 structure.setAccessibilityFocused(true); 9655 } 9656 if (info.isSelected()) { 9657 structure.setSelected(true); 9658 } 9659 if (info.isLongClickable()) { 9660 structure.setLongClickable(true); 9661 } 9662 if (info.isCheckable()) { 9663 structure.setCheckable(true); 9664 if (info.isChecked()) { 9665 structure.setChecked(true); 9666 } 9667 } 9668 if (info.isContextClickable()) { 9669 structure.setContextClickable(true); 9670 } 9671 if (forAutofill) { 9672 structure.setAutofillId(new AutofillId(getAutofillId(), 9673 AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()))); 9674 } 9675 CharSequence cname = info.getClassName(); 9676 structure.setClassName(cname != null ? cname.toString() : null); 9677 structure.setContentDescription(info.getContentDescription()); 9678 if (forAutofill) { 9679 final int maxTextLength = info.getMaxTextLength(); 9680 if (maxTextLength != -1) { 9681 structure.setMaxTextLength(maxTextLength); 9682 } 9683 structure.setHint(info.getHintText()); 9684 } 9685 CharSequence text = info.getText(); 9686 boolean hasText = text != null || info.getError() != null; 9687 if (hasText) { 9688 structure.setText(text, info.getTextSelectionStart(), info.getTextSelectionEnd()); 9689 } 9690 if (forAutofill) { 9691 if (info.isEditable()) { 9692 structure.setDataIsSensitive(true); 9693 if (hasText) { 9694 structure.setAutofillType(AUTOFILL_TYPE_TEXT); 9695 structure.setAutofillValue(AutofillValue.forText(text)); 9696 } 9697 int inputType = info.getInputType(); 9698 if (inputType == 0 && info.isPassword()) { 9699 inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD; 9700 } 9701 structure.setInputType(inputType); 9702 } else { 9703 structure.setDataIsSensitive(false); 9704 } 9705 } 9706 final int NCHILDREN = info.getChildCount(); 9707 if (NCHILDREN > 0) { 9708 structure.setChildCount(NCHILDREN); 9709 for (int i=0; i<NCHILDREN; i++) { 9710 if (AccessibilityNodeInfo.getVirtualDescendantId(info.getChildNodeIds().get(i)) 9711 == AccessibilityNodeProvider.HOST_VIEW_ID) { 9712 Log.e(VIEW_LOG_TAG, "Virtual view pointing to its host. Ignoring"); 9713 continue; 9714 } 9715 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 9716 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 9717 ViewStructure child = structure.newChild(i); 9718 populateVirtualStructure(child, provider, cinfo, forAutofill); 9719 cinfo.recycle(); 9720 } 9721 } 9722 } 9723 9724 /** 9725 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 9726 * implementation calls {@link #onProvideStructure} and 9727 * {@link #onProvideVirtualStructure}. 9728 */ 9729 public void dispatchProvideStructure(ViewStructure structure) { 9730 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 9731 } 9732 9733 /** 9734 * Dispatches creation of a {@link ViewStructure}s for autofill purposes down the hierarchy, 9735 * when an Assist structure is being created as part of an autofill request. 9736 * 9737 * <p>The default implementation does the following: 9738 * <ul> 9739 * <li>Sets the {@link AutofillId} in the structure. 9740 * <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}. 9741 * <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 9742 * </ul> 9743 * 9744 * <p>Typically, this method should only be overridden by subclasses that provide a view 9745 * hierarchy (such as {@link ViewGroup}) - other classes should override 9746 * {@link #onProvideAutofillStructure(ViewStructure, int)} or 9747 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} instead. 9748 * 9749 * <p>When overridden, it must: 9750 * 9751 * <ul> 9752 * <li>Either call 9753 * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly 9754 * set the {@link AutofillId} in the structure (for example, by calling 9755 * {@code structure.setAutofillId(getAutofillId())}). 9756 * <li>Decide how to handle the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag - when 9757 * set, all views in the structure should be considered important for autofill, 9758 * regardless of what {@link #isImportantForAutofill()} returns. We encourage you to 9759 * respect this flag to provide a better user experience - this flag is typically used 9760 * when an user explicitly requested autofill. If the flag is not set, 9761 * then only views marked as important for autofill should be included in the 9762 * structure - skipping non-important views optimizes the overall autofill performance. 9763 * </ul> 9764 * 9765 * @param structure fill in with structured view data for autofill purposes. 9766 * @param flags optional flags. 9767 * 9768 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 9769 */ 9770 public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, 9771 @AutofillFlags int flags) { 9772 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 9773 } 9774 9775 private void dispatchProvideStructure(@NonNull ViewStructure structure, 9776 @ViewStructureType int viewFor, @AutofillFlags int flags) { 9777 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { 9778 structure.setAutofillId(getAutofillId()); 9779 onProvideAutofillStructure(structure, flags); 9780 onProvideAutofillVirtualStructure(structure, flags); 9781 } else if (!isAssistBlocked()) { 9782 onProvideStructure(structure); 9783 onProvideVirtualStructure(structure); 9784 } else { 9785 structure.setClassName(getAccessibilityClassName().toString()); 9786 structure.setAssistBlocked(true); 9787 } 9788 } 9789 9790 /** 9791 * Dispatches the initial content capture events for a view structure. 9792 * 9793 * @hide 9794 */ 9795 public void dispatchInitialProvideContentCaptureStructure() { 9796 AttachInfo ai = mAttachInfo; 9797 if (ai == null) { 9798 Log.w(CONTENT_CAPTURE_LOG_TAG, 9799 "dispatchProvideContentCaptureStructure(): no AttachInfo for " + this); 9800 return; 9801 } 9802 ContentCaptureManager ccm = ai.mContentCaptureManager; 9803 if (ccm == null) { 9804 Log.w(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): " 9805 + "no ContentCaptureManager for " + this); 9806 return; 9807 } 9808 9809 // We must set it before checkign if the view itself is important, because it might 9810 // initially not be (for example, if it's empty), although that might change later (for 9811 // example, if important views are added) 9812 ai.mReadyForContentCaptureUpdates = true; 9813 9814 if (!isImportantForContentCapture()) { 9815 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 9816 Log.d(CONTENT_CAPTURE_LOG_TAG, 9817 "dispatchProvideContentCaptureStructure(): decorView is not important"); 9818 } 9819 return; 9820 } 9821 9822 ai.mContentCaptureManager = ccm; 9823 9824 ContentCaptureSession session = getContentCaptureSession(); 9825 if (session == null) { 9826 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 9827 Log.d(CONTENT_CAPTURE_LOG_TAG, 9828 "dispatchProvideContentCaptureStructure(): no session for " + this); 9829 } 9830 return; 9831 } 9832 9833 session.internalNotifyViewTreeEvent(/* started= */ true); 9834 try { 9835 dispatchProvideContentCaptureStructure(); 9836 } finally { 9837 session.internalNotifyViewTreeEvent(/* started= */ false); 9838 } 9839 } 9840 9841 /** @hide */ 9842 void dispatchProvideContentCaptureStructure() { 9843 ContentCaptureSession session = getContentCaptureSession(); 9844 if (session != null) { 9845 ViewStructure structure = session.newViewStructure(this); 9846 onProvideContentCaptureStructure(structure, /* flags= */ 0); 9847 setNotifiedContentCaptureAppeared(); 9848 session.notifyViewAppeared(structure); 9849 } 9850 } 9851 9852 /** 9853 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 9854 * 9855 * Note: Called from the default {@link AccessibilityDelegate}. 9856 * 9857 * @hide 9858 */ 9859 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 9860 if (mAttachInfo == null) { 9861 return; 9862 } 9863 9864 Rect bounds = mAttachInfo.mTmpInvalRect; 9865 9866 getDrawingRect(bounds); 9867 info.setBoundsInParent(bounds); 9868 9869 getBoundsOnScreen(bounds, true); 9870 info.setBoundsInScreen(bounds); 9871 9872 ViewParent parent = getParentForAccessibility(); 9873 if (parent instanceof View) { 9874 info.setParent((View) parent); 9875 } 9876 9877 if (mID != View.NO_ID) { 9878 View rootView = getRootView(); 9879 if (rootView == null) { 9880 rootView = this; 9881 } 9882 9883 View label = rootView.findLabelForView(this, mID); 9884 if (label != null) { 9885 info.setLabeledBy(label); 9886 } 9887 9888 if ((mAttachInfo.mAccessibilityFetchFlags 9889 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 9890 && Resources.resourceHasPackage(mID)) { 9891 try { 9892 String viewId = getResources().getResourceName(mID); 9893 info.setViewIdResourceName(viewId); 9894 } catch (Resources.NotFoundException nfe) { 9895 /* ignore */ 9896 } 9897 } 9898 } 9899 9900 if (mLabelForId != View.NO_ID) { 9901 View rootView = getRootView(); 9902 if (rootView == null) { 9903 rootView = this; 9904 } 9905 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 9906 if (labeled != null) { 9907 info.setLabelFor(labeled); 9908 } 9909 } 9910 9911 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 9912 View rootView = getRootView(); 9913 if (rootView == null) { 9914 rootView = this; 9915 } 9916 View next = rootView.findViewInsideOutShouldExist(this, 9917 mAccessibilityTraversalBeforeId); 9918 if (next != null && next.includeForAccessibility()) { 9919 info.setTraversalBefore(next); 9920 } 9921 } 9922 9923 if (mAccessibilityTraversalAfterId != View.NO_ID) { 9924 View rootView = getRootView(); 9925 if (rootView == null) { 9926 rootView = this; 9927 } 9928 View next = rootView.findViewInsideOutShouldExist(this, 9929 mAccessibilityTraversalAfterId); 9930 if (next != null && next.includeForAccessibility()) { 9931 info.setTraversalAfter(next); 9932 } 9933 } 9934 9935 info.setVisibleToUser(isVisibleToUser()); 9936 9937 info.setImportantForAccessibility(isImportantForAccessibility()); 9938 info.setPackageName(mContext.getPackageName()); 9939 info.setClassName(getAccessibilityClassName()); 9940 info.setContentDescription(getContentDescription()); 9941 9942 info.setEnabled(isEnabled()); 9943 info.setClickable(isClickable()); 9944 info.setFocusable(isFocusable()); 9945 info.setScreenReaderFocusable(isScreenReaderFocusable()); 9946 info.setFocused(isFocused()); 9947 info.setAccessibilityFocused(isAccessibilityFocused()); 9948 info.setSelected(isSelected()); 9949 info.setLongClickable(isLongClickable()); 9950 info.setContextClickable(isContextClickable()); 9951 info.setLiveRegion(getAccessibilityLiveRegion()); 9952 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipText != null)) { 9953 info.setTooltipText(mTooltipInfo.mTooltipText); 9954 info.addAction((mTooltipInfo.mTooltipPopup == null) 9955 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP 9956 : AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP); 9957 } 9958 9959 // TODO: These make sense only if we are in an AdapterView but all 9960 // views can be selected. Maybe from accessibility perspective 9961 // we should report as selectable view in an AdapterView. 9962 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 9963 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 9964 9965 if (isFocusable()) { 9966 if (isFocused()) { 9967 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 9968 } else { 9969 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 9970 } 9971 } 9972 9973 if (!isAccessibilityFocused()) { 9974 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 9975 } else { 9976 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 9977 } 9978 9979 if (isClickable() && isEnabled()) { 9980 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 9981 } 9982 9983 if (isLongClickable() && isEnabled()) { 9984 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 9985 } 9986 9987 if (isContextClickable() && isEnabled()) { 9988 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 9989 } 9990 9991 CharSequence text = getIterableTextForAccessibility(); 9992 if (text != null && text.length() > 0) { 9993 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 9994 9995 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 9996 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 9997 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 9998 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 9999 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 10000 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 10001 } 10002 10003 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 10004 populateAccessibilityNodeInfoDrawingOrderInParent(info); 10005 info.setPaneTitle(mAccessibilityPaneTitle); 10006 info.setHeading(isAccessibilityHeading()); 10007 10008 if (mTouchDelegate != null) { 10009 info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo()); 10010 } 10011 } 10012 10013 /** 10014 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 10015 * additional data. 10016 * <p> 10017 * This method only needs overloading if the node is marked as having extra data available. 10018 * </p> 10019 * 10020 * @param info The info to which to add the extra data. Never {@code null}. 10021 * @param extraDataKey A key specifying the type of extra data to add to the info. The 10022 * extra data should be added to the {@link Bundle} returned by 10023 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 10024 * {@code null}. 10025 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 10026 * {@code null} if the service provided no arguments. 10027 * 10028 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 10029 */ 10030 public void addExtraDataToAccessibilityNodeInfo( 10031 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 10032 @Nullable Bundle arguments) { 10033 } 10034 10035 /** 10036 * Determine the order in which this view will be drawn relative to its siblings for a11y 10037 * 10038 * @param info The info whose drawing order should be populated 10039 */ 10040 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 10041 /* 10042 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 10043 * drawing order may not be well-defined, and some Views with custom drawing order may 10044 * not be initialized sufficiently to respond properly getChildDrawingOrder. 10045 */ 10046 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 10047 info.setDrawingOrder(0); 10048 return; 10049 } 10050 int drawingOrderInParent = 1; 10051 // Iterate up the hierarchy if parents are not important for a11y 10052 View viewAtDrawingLevel = this; 10053 final ViewParent parent = getParentForAccessibility(); 10054 while (viewAtDrawingLevel != parent) { 10055 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 10056 if (!(currentParent instanceof ViewGroup)) { 10057 // Should only happen for the Decor 10058 drawingOrderInParent = 0; 10059 break; 10060 } else { 10061 final ViewGroup parentGroup = (ViewGroup) currentParent; 10062 final int childCount = parentGroup.getChildCount(); 10063 if (childCount > 1) { 10064 List<View> preorderedList = parentGroup.buildOrderedChildList(); 10065 if (preorderedList != null) { 10066 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 10067 for (int i = 0; i < childDrawIndex; i++) { 10068 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 10069 } 10070 } else { 10071 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 10072 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 10073 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 10074 .getChildDrawingOrder(childCount, childIndex) : childIndex; 10075 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 10076 if (childDrawIndex != 0) { 10077 for (int i = 0; i < numChildrenToIterate; i++) { 10078 final int otherDrawIndex = (customOrder ? 10079 parentGroup.getChildDrawingOrder(childCount, i) : i); 10080 if (otherDrawIndex < childDrawIndex) { 10081 drawingOrderInParent += 10082 numViewsForAccessibility(parentGroup.getChildAt(i)); 10083 } 10084 } 10085 } 10086 } 10087 } 10088 } 10089 viewAtDrawingLevel = (View) currentParent; 10090 } 10091 info.setDrawingOrder(drawingOrderInParent); 10092 } 10093 10094 private static int numViewsForAccessibility(View view) { 10095 if (view != null) { 10096 if (view.includeForAccessibility()) { 10097 return 1; 10098 } else if (view instanceof ViewGroup) { 10099 return ((ViewGroup) view).getNumChildrenForAccessibility(); 10100 } 10101 } 10102 return 0; 10103 } 10104 10105 private View findLabelForView(View view, int labeledId) { 10106 if (mMatchLabelForPredicate == null) { 10107 mMatchLabelForPredicate = new MatchLabelForPredicate(); 10108 } 10109 mMatchLabelForPredicate.mLabeledId = labeledId; 10110 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 10111 } 10112 10113 /** 10114 * Computes whether this virtual autofill view is visible to the user. 10115 * 10116 * <p><b>Note: </b>By default it returns {@code true}, but views providing a virtual hierarchy 10117 * view must override it. 10118 * 10119 * @return Whether the view is visible on the screen. 10120 */ 10121 public boolean isVisibleToUserForAutofill(int virtualId) { 10122 if (mContext.isAutofillCompatibilityEnabled()) { 10123 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 10124 if (provider != null) { 10125 final AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(virtualId); 10126 if (node != null) { 10127 return node.isVisibleToUser(); 10128 } 10129 // if node is null, assume it's not visible anymore 10130 } else { 10131 Log.w(VIEW_LOG_TAG, "isVisibleToUserForAutofill(" + virtualId + "): no provider"); 10132 } 10133 return false; 10134 } 10135 return true; 10136 } 10137 10138 /** 10139 * Computes whether this view is visible to the user. Such a view is 10140 * attached, visible, all its predecessors are visible, it is not clipped 10141 * entirely by its predecessors, and has an alpha greater than zero. 10142 * 10143 * @return Whether the view is visible on the screen. 10144 * 10145 * @hide 10146 */ 10147 @UnsupportedAppUsage 10148 public boolean isVisibleToUser() { 10149 return isVisibleToUser(null); 10150 } 10151 10152 /** 10153 * Computes whether the given portion of this view is visible to the user. 10154 * Such a view is attached, visible, all its predecessors are visible, 10155 * has an alpha greater than zero, and the specified portion is not 10156 * clipped entirely by its predecessors. 10157 * 10158 * @param boundInView the portion of the view to test; coordinates should be relative; may be 10159 * <code>null</code>, and the entire view will be tested in this case. 10160 * When <code>true</code> is returned by the function, the actual visible 10161 * region will be stored in this parameter; that is, if boundInView is fully 10162 * contained within the view, no modification will be made, otherwise regions 10163 * outside of the visible area of the view will be clipped. 10164 * 10165 * @return Whether the specified portion of the view is visible on the screen. 10166 * 10167 * @hide 10168 */ 10169 @UnsupportedAppUsage 10170 protected boolean isVisibleToUser(Rect boundInView) { 10171 if (mAttachInfo != null) { 10172 // Attached to invisible window means this view is not visible. 10173 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 10174 return false; 10175 } 10176 // An invisible predecessor or one with alpha zero means 10177 // that this view is not visible to the user. 10178 Object current = this; 10179 while (current instanceof View) { 10180 View view = (View) current; 10181 // We have attach info so this view is attached and there is no 10182 // need to check whether we reach to ViewRootImpl on the way up. 10183 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 10184 view.getVisibility() != VISIBLE) { 10185 return false; 10186 } 10187 current = view.mParent; 10188 } 10189 // Check if the view is entirely covered by its predecessors. 10190 Rect visibleRect = mAttachInfo.mTmpInvalRect; 10191 Point offset = mAttachInfo.mPoint; 10192 if (!getGlobalVisibleRect(visibleRect, offset)) { 10193 return false; 10194 } 10195 // Check if the visible portion intersects the rectangle of interest. 10196 if (boundInView != null) { 10197 visibleRect.offset(-offset.x, -offset.y); 10198 return boundInView.intersect(visibleRect); 10199 } 10200 return true; 10201 } 10202 return false; 10203 } 10204 10205 /** 10206 * Returns the delegate for implementing accessibility support via 10207 * composition. For more details see {@link AccessibilityDelegate}. 10208 * 10209 * @return The delegate, or null if none set. 10210 */ 10211 public AccessibilityDelegate getAccessibilityDelegate() { 10212 return mAccessibilityDelegate; 10213 } 10214 10215 /** 10216 * Sets a delegate for implementing accessibility support via composition 10217 * (as opposed to inheritance). For more details, see 10218 * {@link AccessibilityDelegate}. 10219 * <p> 10220 * <strong>Note:</strong> On platform versions prior to 10221 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 10222 * views in the {@code android.widget.*} package are called <i>before</i> 10223 * host methods. This prevents certain properties such as class name from 10224 * being modified by overriding 10225 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 10226 * as any changes will be overwritten by the host class. 10227 * <p> 10228 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 10229 * methods are called <i>after</i> host methods, which all properties to be 10230 * modified without being overwritten by the host class. 10231 * 10232 * @param delegate the object to which accessibility method calls should be 10233 * delegated 10234 * @see AccessibilityDelegate 10235 */ 10236 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 10237 mAccessibilityDelegate = delegate; 10238 } 10239 10240 /** 10241 * Gets the provider for managing a virtual view hierarchy rooted at this View 10242 * and reported to {@link android.accessibilityservice.AccessibilityService}s 10243 * that explore the window content. 10244 * <p> 10245 * If this method returns an instance, this instance is responsible for managing 10246 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 10247 * View including the one representing the View itself. Similarly the returned 10248 * instance is responsible for performing accessibility actions on any virtual 10249 * view or the root view itself. 10250 * </p> 10251 * <p> 10252 * If an {@link AccessibilityDelegate} has been specified via calling 10253 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 10254 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 10255 * is responsible for handling this call. 10256 * </p> 10257 * 10258 * @return The provider. 10259 * 10260 * @see AccessibilityNodeProvider 10261 */ 10262 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 10263 if (mAccessibilityDelegate != null) { 10264 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 10265 } else { 10266 return null; 10267 } 10268 } 10269 10270 /** 10271 * Gets the unique identifier of this view on the screen for accessibility purposes. 10272 * 10273 * @return The view accessibility id. 10274 * 10275 * @hide 10276 */ 10277 @UnsupportedAppUsage 10278 public int getAccessibilityViewId() { 10279 if (mAccessibilityViewId == NO_ID) { 10280 mAccessibilityViewId = sNextAccessibilityViewId++; 10281 } 10282 return mAccessibilityViewId; 10283 } 10284 10285 /** 10286 * Gets the unique identifier of this view on the screen for autofill purposes. 10287 * 10288 * @return The view autofill id. 10289 * 10290 * @hide 10291 */ 10292 public int getAutofillViewId() { 10293 if (mAutofillViewId == NO_ID) { 10294 mAutofillViewId = mContext.getNextAutofillId(); 10295 } 10296 return mAutofillViewId; 10297 } 10298 10299 /** 10300 * Gets the unique identifier of the window in which this View resides. 10301 * 10302 * @return The window accessibility id. 10303 * 10304 * @hide 10305 */ 10306 public int getAccessibilityWindowId() { 10307 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 10308 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 10309 } 10310 10311 /** 10312 * Returns the {@link View}'s content description. 10313 * <p> 10314 * <strong>Note:</strong> Do not override this method, as it will have no 10315 * effect on the content description presented to accessibility services. 10316 * You must call {@link #setContentDescription(CharSequence)} to modify the 10317 * content description. 10318 * 10319 * @return the content description 10320 * @see #setContentDescription(CharSequence) 10321 * @attr ref android.R.styleable#View_contentDescription 10322 */ 10323 @ViewDebug.ExportedProperty(category = "accessibility") 10324 @InspectableProperty 10325 public CharSequence getContentDescription() { 10326 return mContentDescription; 10327 } 10328 10329 /** 10330 * Sets the {@link View}'s content description. 10331 * <p> 10332 * A content description briefly describes the view and is primarily used 10333 * for accessibility support to determine how a view should be presented to 10334 * the user. In the case of a view with no textual representation, such as 10335 * {@link android.widget.ImageButton}, a useful content description 10336 * explains what the view does. For example, an image button with a phone 10337 * icon that is used to place a call may use "Call" as its content 10338 * description. An image of a floppy disk that is used to save a file may 10339 * use "Save". 10340 * 10341 * @param contentDescription The content description. 10342 * @see #getContentDescription() 10343 * @attr ref android.R.styleable#View_contentDescription 10344 */ 10345 @RemotableViewMethod 10346 public void setContentDescription(CharSequence contentDescription) { 10347 if (mContentDescription == null) { 10348 if (contentDescription == null) { 10349 return; 10350 } 10351 } else if (mContentDescription.equals(contentDescription)) { 10352 return; 10353 } 10354 mContentDescription = contentDescription; 10355 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 10356 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 10357 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 10358 notifySubtreeAccessibilityStateChangedIfNeeded(); 10359 } else { 10360 notifyViewAccessibilityStateChangedIfNeeded( 10361 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 10362 } 10363 } 10364 10365 /** 10366 * Sets the id of a view before which this one is visited in accessibility traversal. 10367 * A screen-reader must visit the content of this view before the content of the one 10368 * it precedes. For example, if view B is set to be before view A, then a screen-reader 10369 * will traverse the entire content of B before traversing the entire content of A, 10370 * regardles of what traversal strategy it is using. 10371 * <p> 10372 * Views that do not have specified before/after relationships are traversed in order 10373 * determined by the screen-reader. 10374 * </p> 10375 * <p> 10376 * Setting that this view is before a view that is not important for accessibility 10377 * or if this view is not important for accessibility will have no effect as the 10378 * screen-reader is not aware of unimportant views. 10379 * </p> 10380 * 10381 * @param beforeId The id of a view this one precedes in accessibility traversal. 10382 * 10383 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 10384 * 10385 * @see #setImportantForAccessibility(int) 10386 */ 10387 @RemotableViewMethod 10388 public void setAccessibilityTraversalBefore(@IdRes int beforeId) { 10389 if (mAccessibilityTraversalBeforeId == beforeId) { 10390 return; 10391 } 10392 mAccessibilityTraversalBeforeId = beforeId; 10393 notifyViewAccessibilityStateChangedIfNeeded( 10394 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10395 } 10396 10397 /** 10398 * Gets the id of a view before which this one is visited in accessibility traversal. 10399 * 10400 * @return The id of a view this one precedes in accessibility traversal if 10401 * specified, otherwise {@link #NO_ID}. 10402 * 10403 * @see #setAccessibilityTraversalBefore(int) 10404 */ 10405 @IdRes 10406 @InspectableProperty 10407 public int getAccessibilityTraversalBefore() { 10408 return mAccessibilityTraversalBeforeId; 10409 } 10410 10411 /** 10412 * Sets the id of a view after which this one is visited in accessibility traversal. 10413 * A screen-reader must visit the content of the other view before the content of this 10414 * one. For example, if view B is set to be after view A, then a screen-reader 10415 * will traverse the entire content of A before traversing the entire content of B, 10416 * regardles of what traversal strategy it is using. 10417 * <p> 10418 * Views that do not have specified before/after relationships are traversed in order 10419 * determined by the screen-reader. 10420 * </p> 10421 * <p> 10422 * Setting that this view is after a view that is not important for accessibility 10423 * or if this view is not important for accessibility will have no effect as the 10424 * screen-reader is not aware of unimportant views. 10425 * </p> 10426 * 10427 * @param afterId The id of a view this one succedees in accessibility traversal. 10428 * 10429 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 10430 * 10431 * @see #setImportantForAccessibility(int) 10432 */ 10433 @RemotableViewMethod 10434 public void setAccessibilityTraversalAfter(@IdRes int afterId) { 10435 if (mAccessibilityTraversalAfterId == afterId) { 10436 return; 10437 } 10438 mAccessibilityTraversalAfterId = afterId; 10439 notifyViewAccessibilityStateChangedIfNeeded( 10440 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10441 } 10442 10443 /** 10444 * Gets the id of a view after which this one is visited in accessibility traversal. 10445 * 10446 * @return The id of a view this one succeedes in accessibility traversal if 10447 * specified, otherwise {@link #NO_ID}. 10448 * 10449 * @see #setAccessibilityTraversalAfter(int) 10450 */ 10451 @IdRes 10452 @InspectableProperty 10453 public int getAccessibilityTraversalAfter() { 10454 return mAccessibilityTraversalAfterId; 10455 } 10456 10457 /** 10458 * Gets the id of a view for which this view serves as a label for 10459 * accessibility purposes. 10460 * 10461 * @return The labeled view id. 10462 */ 10463 @IdRes 10464 @ViewDebug.ExportedProperty(category = "accessibility") 10465 @InspectableProperty 10466 public int getLabelFor() { 10467 return mLabelForId; 10468 } 10469 10470 /** 10471 * Sets the id of a view for which this view serves as a label for 10472 * accessibility purposes. 10473 * 10474 * @param id The labeled view id. 10475 */ 10476 @RemotableViewMethod 10477 public void setLabelFor(@IdRes int id) { 10478 if (mLabelForId == id) { 10479 return; 10480 } 10481 mLabelForId = id; 10482 if (mLabelForId != View.NO_ID 10483 && mID == View.NO_ID) { 10484 mID = generateViewId(); 10485 } 10486 notifyViewAccessibilityStateChangedIfNeeded( 10487 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10488 } 10489 10490 /** 10491 * Invoked whenever this view loses focus, either by losing window focus or by losing 10492 * focus within its window. This method can be used to clear any state tied to the 10493 * focus. For instance, if a button is held pressed with the trackball and the window 10494 * loses focus, this method can be used to cancel the press. 10495 * 10496 * Subclasses of View overriding this method should always call super.onFocusLost(). 10497 * 10498 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 10499 * @see #onWindowFocusChanged(boolean) 10500 * 10501 * @hide pending API council approval 10502 */ 10503 @CallSuper 10504 @UnsupportedAppUsage 10505 protected void onFocusLost() { 10506 resetPressedState(); 10507 } 10508 10509 private void resetPressedState() { 10510 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 10511 return; 10512 } 10513 10514 if (isPressed()) { 10515 setPressed(false); 10516 10517 if (!mHasPerformedLongPress) { 10518 removeLongPressCallback(); 10519 } 10520 } 10521 } 10522 10523 /** 10524 * Returns true if this view has focus 10525 * 10526 * @return True if this view has focus, false otherwise. 10527 */ 10528 @ViewDebug.ExportedProperty(category = "focus") 10529 @InspectableProperty(hasAttributeId = false) 10530 public boolean isFocused() { 10531 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 10532 } 10533 10534 /** 10535 * Find the view in the hierarchy rooted at this view that currently has 10536 * focus. 10537 * 10538 * @return The view that currently has focus, or null if no focused view can 10539 * be found. 10540 */ 10541 public View findFocus() { 10542 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 10543 } 10544 10545 /** 10546 * Indicates whether this view is one of the set of scrollable containers in 10547 * its window. 10548 * 10549 * @return whether this view is one of the set of scrollable containers in 10550 * its window 10551 * 10552 * @attr ref android.R.styleable#View_isScrollContainer 10553 */ 10554 @InspectableProperty(name = "isScrollContainer") 10555 public boolean isScrollContainer() { 10556 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 10557 } 10558 10559 /** 10560 * Change whether this view is one of the set of scrollable containers in 10561 * its window. This will be used to determine whether the window can 10562 * resize or must pan when a soft input area is open -- scrollable 10563 * containers allow the window to use resize mode since the container 10564 * will appropriately shrink. 10565 * 10566 * @attr ref android.R.styleable#View_isScrollContainer 10567 */ 10568 public void setScrollContainer(boolean isScrollContainer) { 10569 if (isScrollContainer) { 10570 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 10571 mAttachInfo.mScrollContainers.add(this); 10572 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 10573 } 10574 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 10575 } else { 10576 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 10577 mAttachInfo.mScrollContainers.remove(this); 10578 } 10579 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 10580 } 10581 } 10582 10583 /** 10584 * Returns the quality of the drawing cache. 10585 * 10586 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 10587 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 10588 * 10589 * @see #setDrawingCacheQuality(int) 10590 * @see #setDrawingCacheEnabled(boolean) 10591 * @see #isDrawingCacheEnabled() 10592 * 10593 * @attr ref android.R.styleable#View_drawingCacheQuality 10594 * 10595 * @deprecated The view drawing cache was largely made obsolete with the introduction of 10596 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 10597 * layers are largely unnecessary and can easily result in a net loss in performance due to the 10598 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 10599 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 10600 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 10601 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 10602 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 10603 * software-rendered usages are discouraged and have compatibility issues with hardware-only 10604 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 10605 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 10606 * reports or unit testing the {@link PixelCopy} API is recommended. 10607 */ 10608 @Deprecated 10609 @DrawingCacheQuality 10610 @InspectableProperty(enumMapping = { 10611 @EnumEntry(value = DRAWING_CACHE_QUALITY_LOW, name = "low"), 10612 @EnumEntry(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"), 10613 @EnumEntry(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto") 10614 }) 10615 public int getDrawingCacheQuality() { 10616 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 10617 } 10618 10619 /** 10620 * Set the drawing cache quality of this view. This value is used only when the 10621 * drawing cache is enabled 10622 * 10623 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 10624 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 10625 * 10626 * @see #getDrawingCacheQuality() 10627 * @see #setDrawingCacheEnabled(boolean) 10628 * @see #isDrawingCacheEnabled() 10629 * 10630 * @attr ref android.R.styleable#View_drawingCacheQuality 10631 * 10632 * @deprecated The view drawing cache was largely made obsolete with the introduction of 10633 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 10634 * layers are largely unnecessary and can easily result in a net loss in performance due to the 10635 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 10636 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 10637 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 10638 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 10639 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 10640 * software-rendered usages are discouraged and have compatibility issues with hardware-only 10641 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 10642 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 10643 * reports or unit testing the {@link PixelCopy} API is recommended. 10644 */ 10645 @Deprecated 10646 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 10647 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 10648 } 10649 10650 /** 10651 * Returns whether the screen should remain on, corresponding to the current 10652 * value of {@link #KEEP_SCREEN_ON}. 10653 * 10654 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 10655 * 10656 * @see #setKeepScreenOn(boolean) 10657 * 10658 * @attr ref android.R.styleable#View_keepScreenOn 10659 */ 10660 @InspectableProperty 10661 public boolean getKeepScreenOn() { 10662 return (mViewFlags & KEEP_SCREEN_ON) != 0; 10663 } 10664 10665 /** 10666 * Controls whether the screen should remain on, modifying the 10667 * value of {@link #KEEP_SCREEN_ON}. 10668 * 10669 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 10670 * 10671 * @see #getKeepScreenOn() 10672 * 10673 * @attr ref android.R.styleable#View_keepScreenOn 10674 */ 10675 public void setKeepScreenOn(boolean keepScreenOn) { 10676 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 10677 } 10678 10679 /** 10680 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 10681 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 10682 * 10683 * @attr ref android.R.styleable#View_nextFocusLeft 10684 */ 10685 @IdRes 10686 @InspectableProperty(name = "nextFocusLeft") 10687 public int getNextFocusLeftId() { 10688 return mNextFocusLeftId; 10689 } 10690 10691 /** 10692 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 10693 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 10694 * decide automatically. 10695 * 10696 * @attr ref android.R.styleable#View_nextFocusLeft 10697 */ 10698 public void setNextFocusLeftId(@IdRes int nextFocusLeftId) { 10699 mNextFocusLeftId = nextFocusLeftId; 10700 } 10701 10702 /** 10703 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 10704 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 10705 * 10706 * @attr ref android.R.styleable#View_nextFocusRight 10707 */ 10708 @IdRes 10709 @InspectableProperty(name = "nextFocusRight") 10710 public int getNextFocusRightId() { 10711 return mNextFocusRightId; 10712 } 10713 10714 /** 10715 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 10716 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 10717 * decide automatically. 10718 * 10719 * @attr ref android.R.styleable#View_nextFocusRight 10720 */ 10721 public void setNextFocusRightId(@IdRes int nextFocusRightId) { 10722 mNextFocusRightId = nextFocusRightId; 10723 } 10724 10725 /** 10726 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 10727 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 10728 * 10729 * @attr ref android.R.styleable#View_nextFocusUp 10730 */ 10731 @IdRes 10732 @InspectableProperty(name = "nextFocusUp") 10733 public int getNextFocusUpId() { 10734 return mNextFocusUpId; 10735 } 10736 10737 /** 10738 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 10739 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 10740 * decide automatically. 10741 * 10742 * @attr ref android.R.styleable#View_nextFocusUp 10743 */ 10744 public void setNextFocusUpId(@IdRes int nextFocusUpId) { 10745 mNextFocusUpId = nextFocusUpId; 10746 } 10747 10748 /** 10749 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 10750 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 10751 * 10752 * @attr ref android.R.styleable#View_nextFocusDown 10753 */ 10754 @IdRes 10755 @InspectableProperty(name = "nextFocusDown") 10756 public int getNextFocusDownId() { 10757 return mNextFocusDownId; 10758 } 10759 10760 /** 10761 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 10762 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 10763 * decide automatically. 10764 * 10765 * @attr ref android.R.styleable#View_nextFocusDown 10766 */ 10767 public void setNextFocusDownId(@IdRes int nextFocusDownId) { 10768 mNextFocusDownId = nextFocusDownId; 10769 } 10770 10771 /** 10772 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 10773 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 10774 * 10775 * @attr ref android.R.styleable#View_nextFocusForward 10776 */ 10777 @IdRes 10778 @InspectableProperty(name = "nextFocusForward") 10779 public int getNextFocusForwardId() { 10780 return mNextFocusForwardId; 10781 } 10782 10783 /** 10784 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 10785 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 10786 * decide automatically. 10787 * 10788 * @attr ref android.R.styleable#View_nextFocusForward 10789 */ 10790 public void setNextFocusForwardId(@IdRes int nextFocusForwardId) { 10791 mNextFocusForwardId = nextFocusForwardId; 10792 } 10793 10794 /** 10795 * Gets the id of the root of the next keyboard navigation cluster. 10796 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 10797 * decide automatically. 10798 * 10799 * @attr ref android.R.styleable#View_nextClusterForward 10800 */ 10801 @IdRes 10802 @InspectableProperty(name = "nextClusterForward") 10803 public int getNextClusterForwardId() { 10804 return mNextClusterForwardId; 10805 } 10806 10807 /** 10808 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 10809 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 10810 * decide automatically. 10811 * 10812 * @attr ref android.R.styleable#View_nextClusterForward 10813 */ 10814 public void setNextClusterForwardId(@IdRes int nextClusterForwardId) { 10815 mNextClusterForwardId = nextClusterForwardId; 10816 } 10817 10818 /** 10819 * Returns the visibility of this view and all of its ancestors 10820 * 10821 * @return True if this view and all of its ancestors are {@link #VISIBLE} 10822 */ 10823 public boolean isShown() { 10824 View current = this; 10825 //noinspection ConstantConditions 10826 do { 10827 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 10828 return false; 10829 } 10830 ViewParent parent = current.mParent; 10831 if (parent == null) { 10832 return false; // We are not attached to the view root 10833 } 10834 if (!(parent instanceof View)) { 10835 return true; 10836 } 10837 current = (View) parent; 10838 } while (current != null); 10839 10840 return false; 10841 } 10842 10843 /** 10844 * Called by the view hierarchy when the content insets for a window have 10845 * changed, to allow it to adjust its content to fit within those windows. 10846 * The content insets tell you the space that the status bar, input method, 10847 * and other system windows infringe on the application's window. 10848 * 10849 * <p>You do not normally need to deal with this function, since the default 10850 * window decoration given to applications takes care of applying it to the 10851 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 10852 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 10853 * and your content can be placed under those system elements. You can then 10854 * use this method within your view hierarchy if you have parts of your UI 10855 * which you would like to ensure are not being covered. 10856 * 10857 * <p>The default implementation of this method simply applies the content 10858 * insets to the view's padding, consuming that content (modifying the 10859 * insets to be 0), and returning true. This behavior is off by default, but can 10860 * be enabled through {@link #setFitsSystemWindows(boolean)}. 10861 * 10862 * <p>This function's traversal down the hierarchy is depth-first. The same content 10863 * insets object is propagated down the hierarchy, so any changes made to it will 10864 * be seen by all following views (including potentially ones above in 10865 * the hierarchy since this is a depth-first traversal). The first view 10866 * that returns true will abort the entire traversal. 10867 * 10868 * <p>The default implementation works well for a situation where it is 10869 * used with a container that covers the entire window, allowing it to 10870 * apply the appropriate insets to its content on all edges. If you need 10871 * a more complicated layout (such as two different views fitting system 10872 * windows, one on the top of the window, and one on the bottom), 10873 * you can override the method and handle the insets however you would like. 10874 * Note that the insets provided by the framework are always relative to the 10875 * far edges of the window, not accounting for the location of the called view 10876 * within that window. (In fact when this method is called you do not yet know 10877 * where the layout will place the view, as it is done before layout happens.) 10878 * 10879 * <p>Note: unlike many View methods, there is no dispatch phase to this 10880 * call. If you are overriding it in a ViewGroup and want to allow the 10881 * call to continue to your children, you must be sure to call the super 10882 * implementation. 10883 * 10884 * <p>Here is a sample layout that makes use of fitting system windows 10885 * to have controls for a video view placed inside of the window decorations 10886 * that it hides and shows. This can be used with code like the second 10887 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 10888 * 10889 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 10890 * 10891 * @param insets Current content insets of the window. Prior to 10892 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 10893 * the insets or else you and Android will be unhappy. 10894 * 10895 * @return {@code true} if this view applied the insets and it should not 10896 * continue propagating further down the hierarchy, {@code false} otherwise. 10897 * @see #getFitsSystemWindows() 10898 * @see #setFitsSystemWindows(boolean) 10899 * @see #setSystemUiVisibility(int) 10900 * 10901 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 10902 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 10903 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 10904 * to implement handling their own insets. 10905 */ 10906 @Deprecated 10907 protected boolean fitSystemWindows(Rect insets) { 10908 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 10909 if (insets == null) { 10910 // Null insets by definition have already been consumed. 10911 // This call cannot apply insets since there are none to apply, 10912 // so return false. 10913 return false; 10914 } 10915 // If we're not in the process of dispatching the newer apply insets call, 10916 // that means we're not in the compatibility path. Dispatch into the newer 10917 // apply insets path and take things from there. 10918 try { 10919 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 10920 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 10921 } finally { 10922 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 10923 } 10924 } else { 10925 // We're being called from the newer apply insets path. 10926 // Perform the standard fallback behavior. 10927 return fitSystemWindowsInt(insets); 10928 } 10929 } 10930 10931 private boolean fitSystemWindowsInt(Rect insets) { 10932 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 10933 mUserPaddingStart = UNDEFINED_PADDING; 10934 mUserPaddingEnd = UNDEFINED_PADDING; 10935 Rect localInsets = sThreadLocal.get(); 10936 if (localInsets == null) { 10937 localInsets = new Rect(); 10938 sThreadLocal.set(localInsets); 10939 } 10940 boolean res = computeFitSystemWindows(insets, localInsets); 10941 mUserPaddingLeftInitial = localInsets.left; 10942 mUserPaddingRightInitial = localInsets.right; 10943 internalSetPadding(localInsets.left, localInsets.top, 10944 localInsets.right, localInsets.bottom); 10945 return res; 10946 } 10947 return false; 10948 } 10949 10950 /** 10951 * Called when the view should apply {@link WindowInsets} according to its internal policy. 10952 * 10953 * <p>This method should be overridden by views that wish to apply a policy different from or 10954 * in addition to the default behavior. Clients that wish to force a view subtree 10955 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 10956 * 10957 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 10958 * it will be called during dispatch instead of this method. The listener may optionally 10959 * call this method from its own implementation if it wishes to apply the view's default 10960 * insets policy in addition to its own.</p> 10961 * 10962 * <p>Implementations of this method should either return the insets parameter unchanged 10963 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 10964 * that this view applied itself. This allows new inset types added in future platform 10965 * versions to pass through existing implementations unchanged without being erroneously 10966 * consumed.</p> 10967 * 10968 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 10969 * property is set then the view will consume the system window insets and apply them 10970 * as padding for the view.</p> 10971 * 10972 * @param insets Insets to apply 10973 * @return The supplied insets with any applied insets consumed 10974 */ 10975 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 10976 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 10977 // We weren't called from within a direct call to fitSystemWindows, 10978 // call into it as a fallback in case we're in a class that overrides it 10979 // and has logic to perform. 10980 if (fitSystemWindows(insets.getSystemWindowInsetsAsRect())) { 10981 return insets.consumeSystemWindowInsets(); 10982 } 10983 } else { 10984 // We were called from within a direct call to fitSystemWindows. 10985 if (fitSystemWindowsInt(insets.getSystemWindowInsetsAsRect())) { 10986 return insets.consumeSystemWindowInsets(); 10987 } 10988 } 10989 return insets; 10990 } 10991 10992 /** 10993 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 10994 * window insets to this view. The listener's 10995 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 10996 * method will be called instead of the view's 10997 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 10998 * 10999 * @param listener Listener to set 11000 * 11001 * @see #onApplyWindowInsets(WindowInsets) 11002 */ 11003 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 11004 getListenerInfo().mOnApplyWindowInsetsListener = listener; 11005 } 11006 11007 /** 11008 * Request to apply the given window insets to this view or another view in its subtree. 11009 * 11010 * <p>This method should be called by clients wishing to apply insets corresponding to areas 11011 * obscured by window decorations or overlays. This can include the status and navigation bars, 11012 * action bars, input methods and more. New inset categories may be added in the future. 11013 * The method returns the insets provided minus any that were applied by this view or its 11014 * children.</p> 11015 * 11016 * <p>Clients wishing to provide custom behavior should override the 11017 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 11018 * {@link OnApplyWindowInsetsListener} via the 11019 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 11020 * method.</p> 11021 * 11022 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 11023 * </p> 11024 * 11025 * @param insets Insets to apply 11026 * @return The provided insets minus the insets that were consumed 11027 */ 11028 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 11029 try { 11030 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 11031 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 11032 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 11033 } else { 11034 return onApplyWindowInsets(insets); 11035 } 11036 } finally { 11037 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 11038 } 11039 } 11040 11041 /** 11042 * Sets a {@link WindowInsetsAnimationListener} to be notified about animations of windows that 11043 * cause insets. 11044 * 11045 * @param listener The listener to set. 11046 * @hide pending unhide 11047 */ 11048 public void setWindowInsetsAnimationListener(WindowInsetsAnimationListener listener) { 11049 getListenerInfo().mWindowInsetsAnimationListener = listener; 11050 } 11051 11052 void dispatchWindowInsetsAnimationStarted(InsetsAnimation animation) { 11053 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationListener != null) { 11054 mListenerInfo.mWindowInsetsAnimationListener.onStarted(animation); 11055 } 11056 } 11057 11058 WindowInsets dispatchWindowInsetsAnimationProgress(WindowInsets insets) { 11059 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationListener != null) { 11060 return mListenerInfo.mWindowInsetsAnimationListener.onProgress(insets); 11061 } else { 11062 return insets; 11063 } 11064 } 11065 11066 void dispatchWindowInsetsAnimationFinished(InsetsAnimation animation) { 11067 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationListener != null) { 11068 mListenerInfo.mWindowInsetsAnimationListener.onFinished(animation); 11069 } 11070 } 11071 11072 /** 11073 * Sets a list of areas within this view's post-layout coordinate space where the system 11074 * should not intercept touch or other pointing device gestures. <em>This method should 11075 * be called by {@link #onLayout(boolean, int, int, int, int)} or {@link #onDraw(Canvas)}.</em> 11076 * 11077 * <p>Use this to tell the system which specific sub-areas of a view need to receive gesture 11078 * input in order to function correctly in the presence of global system gestures that may 11079 * conflict. For example, if the system wishes to capture swipe-in-from-screen-edge gestures 11080 * to provide system-level navigation functionality, a view such as a navigation drawer 11081 * container can mark the left (or starting) edge of itself as requiring gesture capture 11082 * priority using this API. The system may then choose to relax its own gesture recognition 11083 * to allow the app to consume the user's gesture. It is not necessary for an app to register 11084 * exclusion rects for broadly spanning regions such as the entirety of a 11085 * <code>ScrollView</code> or for simple press and release click targets such as 11086 * <code>Button</code>. Mark an exclusion rect when interacting with a view requires 11087 * a precision touch gesture in a small area in either the X or Y dimension, such as 11088 * an edge swipe or dragging a <code>SeekBar</code> thumb.</p> 11089 * 11090 * <p>Do not modify the provided list after this method is called.</p> 11091 * 11092 * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the 11093 * exclusions it takes into account. The limit does not apply while the navigation 11094 * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the 11095 * {@link android.inputmethodservice.InputMethodService input method} and 11096 * {@link Intent#CATEGORY_HOME home activity}. 11097 * </p> 11098 * 11099 * @param rects A list of precision gesture regions that this view needs to function correctly 11100 */ 11101 public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) { 11102 if (rects.isEmpty() && mListenerInfo == null) return; 11103 11104 final ListenerInfo info = getListenerInfo(); 11105 if (rects.isEmpty()) { 11106 info.mSystemGestureExclusionRects = null; 11107 if (info.mPositionUpdateListener != null) { 11108 mRenderNode.removePositionUpdateListener(info.mPositionUpdateListener); 11109 } 11110 } else { 11111 info.mSystemGestureExclusionRects = rects; 11112 if (info.mPositionUpdateListener == null) { 11113 info.mPositionUpdateListener = new RenderNode.PositionUpdateListener() { 11114 @Override 11115 public void positionChanged(long n, int l, int t, int r, int b) { 11116 postUpdateSystemGestureExclusionRects(); 11117 } 11118 11119 @Override 11120 public void positionLost(long frameNumber) { 11121 postUpdateSystemGestureExclusionRects(); 11122 } 11123 }; 11124 mRenderNode.addPositionUpdateListener(info.mPositionUpdateListener); 11125 } 11126 } 11127 postUpdateSystemGestureExclusionRects(); 11128 } 11129 11130 /** 11131 * WARNING: this can be called by a hwui worker thread, not just the UI thread! 11132 */ 11133 void postUpdateSystemGestureExclusionRects() { 11134 // Potentially racey from a background thread. It's ok if it's not perfect. 11135 final Handler h = getHandler(); 11136 if (h != null) { 11137 h.postAtFrontOfQueue(this::updateSystemGestureExclusionRects); 11138 } 11139 } 11140 11141 void updateSystemGestureExclusionRects() { 11142 final AttachInfo ai = mAttachInfo; 11143 if (ai != null) { 11144 ai.mViewRootImpl.updateSystemGestureExclusionRectsForView(this); 11145 } 11146 } 11147 11148 /** 11149 * Retrieve the list of areas within this view's post-layout coordinate space where the system 11150 * should not intercept touch or other pointing device gestures. 11151 * 11152 * <p>Do not modify the returned list.</p> 11153 * 11154 * @return the list set by {@link #setSystemGestureExclusionRects(List)} 11155 */ 11156 @NonNull 11157 public List<Rect> getSystemGestureExclusionRects() { 11158 final ListenerInfo info = mListenerInfo; 11159 if (info != null) { 11160 final List<Rect> list = info.mSystemGestureExclusionRects; 11161 if (list != null) { 11162 return list; 11163 } 11164 } 11165 return Collections.emptyList(); 11166 } 11167 11168 /** 11169 * Compute the view's coordinate within the surface. 11170 * 11171 * <p>Computes the coordinates of this view in its surface. The argument 11172 * must be an array of two integers. After the method returns, the array 11173 * contains the x and y location in that order.</p> 11174 * 11175 * @param location an array of two integers in which to hold the coordinates 11176 */ 11177 public void getLocationInSurface(@NonNull @Size(2) int[] location) { 11178 getLocationInWindow(location); 11179 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 11180 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 11181 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 11182 } 11183 } 11184 11185 /** 11186 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 11187 * only available if the view is attached. 11188 * 11189 * @return WindowInsets from the top of the view hierarchy or null if View is detached 11190 */ 11191 public WindowInsets getRootWindowInsets() { 11192 if (mAttachInfo != null) { 11193 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 11194 } 11195 return null; 11196 } 11197 11198 /** 11199 * Retrieves the single {@link WindowInsetsController} of the window this view is attached to. 11200 * 11201 * @return The {@link WindowInsetsController} or {@code null} if the view isn't attached to a 11202 * a window. 11203 * @see Window#getInsetsController() 11204 * @hide pending unhide 11205 */ 11206 public @Nullable WindowInsetsController getWindowInsetsController() { 11207 if (mAttachInfo != null) { 11208 return mAttachInfo.mViewRootImpl.getInsetsController(); 11209 } 11210 return null; 11211 } 11212 11213 /** 11214 * @hide Compute the insets that should be consumed by this view and the ones 11215 * that should propagate to those under it. 11216 * 11217 * Note: This is used by appcompat's ActionBarOverlayLayout through reflection. 11218 * 11219 * @param inoutInsets the insets given to this view 11220 * @param outLocalInsets the insets that should be applied to this view 11221 * @deprecated use {@link #computeSystemWindowInsets} 11222 * @return 11223 */ 11224 @Deprecated 11225 @UnsupportedAppUsage 11226 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 11227 WindowInsets innerInsets = computeSystemWindowInsets(new WindowInsets(inoutInsets), 11228 outLocalInsets); 11229 inoutInsets.set(innerInsets.getSystemWindowInsetsAsRect()); 11230 return innerInsets.isSystemWindowInsetsConsumed(); 11231 } 11232 11233 /** 11234 * Compute insets that should be consumed by this view and the ones that should propagate 11235 * to those under it. 11236 * 11237 * @param in Insets currently being processed by this View, likely received as a parameter 11238 * to {@link #onApplyWindowInsets(WindowInsets)}. 11239 * @param outLocalInsets A Rect that will receive the insets that should be consumed 11240 * by this view 11241 * @return Insets that should be passed along to views under this one 11242 */ 11243 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 11244 if ((mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) == 0 11245 || mAttachInfo == null 11246 || ((mAttachInfo.mSystemUiVisibility & SYSTEM_UI_LAYOUT_FLAGS) == 0 11247 && !mAttachInfo.mOverscanRequested)) { 11248 outLocalInsets.set(in.getSystemWindowInsetsAsRect()); 11249 return in.consumeSystemWindowInsets().inset(outLocalInsets); 11250 } else { 11251 // The application wants to take care of fitting system window for 11252 // the content... however we still need to take care of any overscan here. 11253 final Rect overscan = mAttachInfo.mOverscanInsets; 11254 outLocalInsets.set(overscan); 11255 return in.inset(outLocalInsets); 11256 } 11257 } 11258 11259 /** 11260 * Sets whether or not this view should account for system screen decorations 11261 * such as the status bar and inset its content; that is, controlling whether 11262 * the default implementation of {@link #fitSystemWindows(Rect)} will be 11263 * executed. See that method for more details. 11264 * 11265 * <p>Note that if you are providing your own implementation of 11266 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 11267 * flag to true -- your implementation will be overriding the default 11268 * implementation that checks this flag. 11269 * 11270 * @param fitSystemWindows If true, then the default implementation of 11271 * {@link #fitSystemWindows(Rect)} will be executed. 11272 * 11273 * @attr ref android.R.styleable#View_fitsSystemWindows 11274 * @see #getFitsSystemWindows() 11275 * @see #fitSystemWindows(Rect) 11276 * @see #setSystemUiVisibility(int) 11277 */ 11278 public void setFitsSystemWindows(boolean fitSystemWindows) { 11279 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 11280 } 11281 11282 /** 11283 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 11284 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 11285 * will be executed. 11286 * 11287 * @return {@code true} if the default implementation of 11288 * {@link #fitSystemWindows(Rect)} will be executed. 11289 * 11290 * @attr ref android.R.styleable#View_fitsSystemWindows 11291 * @see #setFitsSystemWindows(boolean) 11292 * @see #fitSystemWindows(Rect) 11293 * @see #setSystemUiVisibility(int) 11294 */ 11295 @ViewDebug.ExportedProperty 11296 @InspectableProperty 11297 public boolean getFitsSystemWindows() { 11298 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 11299 } 11300 11301 /** @hide */ 11302 @UnsupportedAppUsage 11303 public boolean fitsSystemWindows() { 11304 return getFitsSystemWindows(); 11305 } 11306 11307 /** 11308 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 11309 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 11310 */ 11311 @Deprecated 11312 public void requestFitSystemWindows() { 11313 if (mParent != null) { 11314 mParent.requestFitSystemWindows(); 11315 } 11316 } 11317 11318 /** 11319 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 11320 */ 11321 public void requestApplyInsets() { 11322 requestFitSystemWindows(); 11323 } 11324 11325 /** 11326 * For use by PhoneWindow to make its own system window fitting optional. 11327 * @hide 11328 */ 11329 @UnsupportedAppUsage 11330 public void makeOptionalFitsSystemWindows() { 11331 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 11332 } 11333 11334 /** 11335 * Returns the outsets, which areas of the device that aren't a surface, but we would like to 11336 * treat them as such. 11337 * @hide 11338 */ 11339 public void getOutsets(Rect outOutsetRect) { 11340 if (mAttachInfo != null) { 11341 outOutsetRect.set(mAttachInfo.mOutsets); 11342 } else { 11343 outOutsetRect.setEmpty(); 11344 } 11345 } 11346 11347 /** 11348 * Returns the visibility status for this view. 11349 * 11350 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 11351 * @attr ref android.R.styleable#View_visibility 11352 */ 11353 @ViewDebug.ExportedProperty(mapping = { 11354 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 11355 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 11356 @ViewDebug.IntToString(from = GONE, to = "GONE") 11357 }) 11358 @InspectableProperty(enumMapping = { 11359 @EnumEntry(value = VISIBLE, name = "visible"), 11360 @EnumEntry(value = INVISIBLE, name = "invisible"), 11361 @EnumEntry(value = GONE, name = "gone") 11362 }) 11363 @Visibility 11364 public int getVisibility() { 11365 return mViewFlags & VISIBILITY_MASK; 11366 } 11367 11368 /** 11369 * Set the visibility state of this view. 11370 * 11371 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 11372 * @attr ref android.R.styleable#View_visibility 11373 */ 11374 @RemotableViewMethod 11375 public void setVisibility(@Visibility int visibility) { 11376 setFlags(visibility, VISIBILITY_MASK); 11377 } 11378 11379 /** 11380 * Returns the enabled status for this view. The interpretation of the 11381 * enabled state varies by subclass. 11382 * 11383 * @return True if this view is enabled, false otherwise. 11384 */ 11385 @ViewDebug.ExportedProperty 11386 @InspectableProperty 11387 public boolean isEnabled() { 11388 return (mViewFlags & ENABLED_MASK) == ENABLED; 11389 } 11390 11391 /** 11392 * Set the enabled state of this view. The interpretation of the enabled 11393 * state varies by subclass. 11394 * 11395 * @param enabled True if this view is enabled, false otherwise. 11396 */ 11397 @RemotableViewMethod 11398 public void setEnabled(boolean enabled) { 11399 if (enabled == isEnabled()) return; 11400 11401 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 11402 11403 /* 11404 * The View most likely has to change its appearance, so refresh 11405 * the drawable state. 11406 */ 11407 refreshDrawableState(); 11408 11409 // Invalidate too, since the default behavior for views is to be 11410 // be drawn at 50% alpha rather than to change the drawable. 11411 invalidate(true); 11412 11413 if (!enabled) { 11414 cancelPendingInputEvents(); 11415 } 11416 } 11417 11418 /** 11419 * Set whether this view can receive the focus. 11420 * <p> 11421 * Setting this to false will also ensure that this view is not focusable 11422 * in touch mode. 11423 * 11424 * @param focusable If true, this view can receive the focus. 11425 * 11426 * @see #setFocusableInTouchMode(boolean) 11427 * @see #setFocusable(int) 11428 * @attr ref android.R.styleable#View_focusable 11429 */ 11430 public void setFocusable(boolean focusable) { 11431 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 11432 } 11433 11434 /** 11435 * Sets whether this view can receive focus. 11436 * <p> 11437 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 11438 * automatically based on the view's interactivity. This is the default. 11439 * <p> 11440 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 11441 * in touch mode. 11442 * 11443 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 11444 * or {@link #FOCUSABLE_AUTO}. 11445 * @see #setFocusableInTouchMode(boolean) 11446 * @attr ref android.R.styleable#View_focusable 11447 */ 11448 public void setFocusable(@Focusable int focusable) { 11449 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 11450 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 11451 } 11452 setFlags(focusable, FOCUSABLE_MASK); 11453 } 11454 11455 /** 11456 * Set whether this view can receive focus while in touch mode. 11457 * 11458 * Setting this to true will also ensure that this view is focusable. 11459 * 11460 * @param focusableInTouchMode If true, this view can receive the focus while 11461 * in touch mode. 11462 * 11463 * @see #setFocusable(boolean) 11464 * @attr ref android.R.styleable#View_focusableInTouchMode 11465 */ 11466 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 11467 // Focusable in touch mode should always be set before the focusable flag 11468 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 11469 // which, in touch mode, will not successfully request focus on this view 11470 // because the focusable in touch mode flag is not set 11471 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 11472 11473 // Clear FOCUSABLE_AUTO if set. 11474 if (focusableInTouchMode) { 11475 // Clears FOCUSABLE_AUTO if set. 11476 setFlags(FOCUSABLE, FOCUSABLE_MASK); 11477 } 11478 } 11479 11480 /** 11481 * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how 11482 * to autofill the view with the user's data. 11483 * 11484 * <p>Typically, there is only one way to autofill a view, but there could be more than one. 11485 * For example, if the application accepts either an username or email address to identify 11486 * an user. 11487 * 11488 * <p>These hints are not validated by the Android System, but passed "as is" to the service. 11489 * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_} 11490 * constants such as: 11491 * {@link #AUTOFILL_HINT_USERNAME}, {@link #AUTOFILL_HINT_PASSWORD}, 11492 * {@link #AUTOFILL_HINT_EMAIL_ADDRESS}, 11493 * {@link #AUTOFILL_HINT_NAME}, 11494 * {@link #AUTOFILL_HINT_PHONE}, 11495 * {@link #AUTOFILL_HINT_POSTAL_ADDRESS}, {@link #AUTOFILL_HINT_POSTAL_CODE}, 11496 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 11497 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 11498 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 11499 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or 11500 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}. 11501 * 11502 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set. 11503 * @attr ref android.R.styleable#View_autofillHints 11504 */ 11505 public void setAutofillHints(@Nullable String... autofillHints) { 11506 if (autofillHints == null || autofillHints.length == 0) { 11507 mAutofillHints = null; 11508 } else { 11509 mAutofillHints = autofillHints; 11510 } 11511 } 11512 11513 /** 11514 * @hide 11515 */ 11516 @TestApi 11517 public void setAutofilled(boolean isAutofilled) { 11518 boolean wasChanged = isAutofilled != isAutofilled(); 11519 11520 if (wasChanged) { 11521 if (isAutofilled) { 11522 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; 11523 } else { 11524 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; 11525 } 11526 11527 invalidate(); 11528 } 11529 } 11530 11531 /** 11532 * Set whether this view should have sound effects enabled for events such as 11533 * clicking and touching. 11534 * 11535 * <p>You may wish to disable sound effects for a view if you already play sounds, 11536 * for instance, a dial key that plays dtmf tones. 11537 * 11538 * @param soundEffectsEnabled whether sound effects are enabled for this view. 11539 * @see #isSoundEffectsEnabled() 11540 * @see #playSoundEffect(int) 11541 * @attr ref android.R.styleable#View_soundEffectsEnabled 11542 */ 11543 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 11544 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 11545 } 11546 11547 /** 11548 * @return whether this view should have sound effects enabled for events such as 11549 * clicking and touching. 11550 * 11551 * @see #setSoundEffectsEnabled(boolean) 11552 * @see #playSoundEffect(int) 11553 * @attr ref android.R.styleable#View_soundEffectsEnabled 11554 */ 11555 @ViewDebug.ExportedProperty 11556 @InspectableProperty 11557 public boolean isSoundEffectsEnabled() { 11558 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 11559 } 11560 11561 /** 11562 * Set whether this view should have haptic feedback for events such as 11563 * long presses. 11564 * 11565 * <p>You may wish to disable haptic feedback if your view already controls 11566 * its own haptic feedback. 11567 * 11568 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 11569 * @see #isHapticFeedbackEnabled() 11570 * @see #performHapticFeedback(int) 11571 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 11572 */ 11573 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 11574 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 11575 } 11576 11577 /** 11578 * @return whether this view should have haptic feedback enabled for events 11579 * long presses. 11580 * 11581 * @see #setHapticFeedbackEnabled(boolean) 11582 * @see #performHapticFeedback(int) 11583 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 11584 */ 11585 @ViewDebug.ExportedProperty 11586 @InspectableProperty 11587 public boolean isHapticFeedbackEnabled() { 11588 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 11589 } 11590 11591 /** 11592 * Returns the layout direction for this view. 11593 * 11594 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 11595 * {@link #LAYOUT_DIRECTION_RTL}, 11596 * {@link #LAYOUT_DIRECTION_INHERIT} or 11597 * {@link #LAYOUT_DIRECTION_LOCALE}. 11598 * 11599 * @attr ref android.R.styleable#View_layoutDirection 11600 * 11601 * @hide 11602 */ 11603 @ViewDebug.ExportedProperty(category = "layout", mapping = { 11604 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 11605 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 11606 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 11607 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 11608 }) 11609 @InspectableProperty(hasAttributeId = false, enumMapping = { 11610 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 11611 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl"), 11612 @EnumEntry(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"), 11613 @EnumEntry(value = LAYOUT_DIRECTION_LOCALE, name = "locale") 11614 }) 11615 @LayoutDir 11616 public int getRawLayoutDirection() { 11617 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 11618 } 11619 11620 /** 11621 * Set the layout direction for this view. This will propagate a reset of layout direction 11622 * resolution to the view's children and resolve layout direction for this view. 11623 * 11624 * @param layoutDirection the layout direction to set. Should be one of: 11625 * 11626 * {@link #LAYOUT_DIRECTION_LTR}, 11627 * {@link #LAYOUT_DIRECTION_RTL}, 11628 * {@link #LAYOUT_DIRECTION_INHERIT}, 11629 * {@link #LAYOUT_DIRECTION_LOCALE}. 11630 * 11631 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 11632 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 11633 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 11634 * 11635 * @attr ref android.R.styleable#View_layoutDirection 11636 */ 11637 @RemotableViewMethod 11638 public void setLayoutDirection(@LayoutDir int layoutDirection) { 11639 if (getRawLayoutDirection() != layoutDirection) { 11640 // Reset the current layout direction and the resolved one 11641 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 11642 resetRtlProperties(); 11643 // Set the new layout direction (filtered) 11644 mPrivateFlags2 |= 11645 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 11646 // We need to resolve all RTL properties as they all depend on layout direction 11647 resolveRtlPropertiesIfNeeded(); 11648 requestLayout(); 11649 invalidate(true); 11650 } 11651 } 11652 11653 /** 11654 * Returns the resolved layout direction for this view. 11655 * 11656 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 11657 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 11658 * 11659 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 11660 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 11661 * 11662 * @attr ref android.R.styleable#View_layoutDirection 11663 */ 11664 @ViewDebug.ExportedProperty(category = "layout", mapping = { 11665 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 11666 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 11667 }) 11668 @InspectableProperty(enumMapping = { 11669 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 11670 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl") 11671 }) 11672 @ResolvedLayoutDir 11673 public int getLayoutDirection() { 11674 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 11675 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 11676 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 11677 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 11678 } 11679 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 11680 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 11681 } 11682 11683 /** 11684 * Indicates whether or not this view's layout is right-to-left. This is resolved from 11685 * layout attribute and/or the inherited value from the parent 11686 * 11687 * @return true if the layout is right-to-left. 11688 * 11689 * @hide 11690 */ 11691 @ViewDebug.ExportedProperty(category = "layout") 11692 @UnsupportedAppUsage 11693 public boolean isLayoutRtl() { 11694 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 11695 } 11696 11697 /** 11698 * Indicates whether the view is currently tracking transient state that the 11699 * app should not need to concern itself with saving and restoring, but that 11700 * the framework should take special note to preserve when possible. 11701 * 11702 * <p>A view with transient state cannot be trivially rebound from an external 11703 * data source, such as an adapter binding item views in a list. This may be 11704 * because the view is performing an animation, tracking user selection 11705 * of content, or similar.</p> 11706 * 11707 * @return true if the view has transient state 11708 */ 11709 @ViewDebug.ExportedProperty(category = "layout") 11710 public boolean hasTransientState() { 11711 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 11712 } 11713 11714 /** 11715 * Set whether this view is currently tracking transient state that the 11716 * framework should attempt to preserve when possible. This flag is reference counted, 11717 * so every call to setHasTransientState(true) should be paired with a later call 11718 * to setHasTransientState(false). 11719 * 11720 * <p>A view with transient state cannot be trivially rebound from an external 11721 * data source, such as an adapter binding item views in a list. This may be 11722 * because the view is performing an animation, tracking user selection 11723 * of content, or similar.</p> 11724 * 11725 * @param hasTransientState true if this view has transient state 11726 */ 11727 public void setHasTransientState(boolean hasTransientState) { 11728 final boolean oldHasTransientState = hasTransientState(); 11729 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 11730 mTransientStateCount - 1; 11731 if (mTransientStateCount < 0) { 11732 mTransientStateCount = 0; 11733 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 11734 "unmatched pair of setHasTransientState calls"); 11735 } else if ((hasTransientState && mTransientStateCount == 1) || 11736 (!hasTransientState && mTransientStateCount == 0)) { 11737 // update flag if we've just incremented up from 0 or decremented down to 0 11738 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 11739 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 11740 final boolean newHasTransientState = hasTransientState(); 11741 if (mParent != null && newHasTransientState != oldHasTransientState) { 11742 try { 11743 mParent.childHasTransientStateChanged(this, newHasTransientState); 11744 } catch (AbstractMethodError e) { 11745 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 11746 " does not fully implement ViewParent", e); 11747 } 11748 } 11749 } 11750 } 11751 11752 /** 11753 * Returns true if this view is currently attached to a window. 11754 */ 11755 public boolean isAttachedToWindow() { 11756 return mAttachInfo != null; 11757 } 11758 11759 /** 11760 * Returns true if this view has been through at least one layout since it 11761 * was last attached to or detached from a window. 11762 */ 11763 public boolean isLaidOut() { 11764 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 11765 } 11766 11767 /** 11768 * @return {@code true} if laid-out and not about to do another layout. 11769 */ 11770 boolean isLayoutValid() { 11771 return isLaidOut() && ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == 0); 11772 } 11773 11774 /** 11775 * If this view doesn't do any drawing on its own, set this flag to 11776 * allow further optimizations. By default, this flag is not set on 11777 * View, but could be set on some View subclasses such as ViewGroup. 11778 * 11779 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 11780 * you should clear this flag. 11781 * 11782 * @param willNotDraw whether or not this View draw on its own 11783 */ 11784 public void setWillNotDraw(boolean willNotDraw) { 11785 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 11786 } 11787 11788 /** 11789 * Returns whether or not this View draws on its own. 11790 * 11791 * @return true if this view has nothing to draw, false otherwise 11792 */ 11793 @ViewDebug.ExportedProperty(category = "drawing") 11794 public boolean willNotDraw() { 11795 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 11796 } 11797 11798 /** 11799 * When a View's drawing cache is enabled, drawing is redirected to an 11800 * offscreen bitmap. Some views, like an ImageView, must be able to 11801 * bypass this mechanism if they already draw a single bitmap, to avoid 11802 * unnecessary usage of the memory. 11803 * 11804 * @param willNotCacheDrawing true if this view does not cache its 11805 * drawing, false otherwise 11806 * 11807 * @deprecated The view drawing cache was largely made obsolete with the introduction of 11808 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 11809 * layers are largely unnecessary and can easily result in a net loss in performance due to the 11810 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 11811 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 11812 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 11813 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 11814 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 11815 * software-rendered usages are discouraged and have compatibility issues with hardware-only 11816 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 11817 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 11818 * reports or unit testing the {@link PixelCopy} API is recommended. 11819 */ 11820 @Deprecated 11821 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 11822 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 11823 } 11824 11825 /** 11826 * Returns whether or not this View can cache its drawing or not. 11827 * 11828 * @return true if this view does not cache its drawing, false otherwise 11829 * 11830 * @deprecated The view drawing cache was largely made obsolete with the introduction of 11831 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 11832 * layers are largely unnecessary and can easily result in a net loss in performance due to the 11833 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 11834 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 11835 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 11836 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 11837 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 11838 * software-rendered usages are discouraged and have compatibility issues with hardware-only 11839 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 11840 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 11841 * reports or unit testing the {@link PixelCopy} API is recommended. 11842 */ 11843 @ViewDebug.ExportedProperty(category = "drawing") 11844 @Deprecated 11845 public boolean willNotCacheDrawing() { 11846 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 11847 } 11848 11849 /** 11850 * Indicates whether this view reacts to click events or not. 11851 * 11852 * @return true if the view is clickable, false otherwise 11853 * 11854 * @see #setClickable(boolean) 11855 * @attr ref android.R.styleable#View_clickable 11856 */ 11857 @ViewDebug.ExportedProperty 11858 @InspectableProperty 11859 public boolean isClickable() { 11860 return (mViewFlags & CLICKABLE) == CLICKABLE; 11861 } 11862 11863 /** 11864 * Enables or disables click events for this view. When a view 11865 * is clickable it will change its state to "pressed" on every click. 11866 * Subclasses should set the view clickable to visually react to 11867 * user's clicks. 11868 * 11869 * @param clickable true to make the view clickable, false otherwise 11870 * 11871 * @see #isClickable() 11872 * @attr ref android.R.styleable#View_clickable 11873 */ 11874 public void setClickable(boolean clickable) { 11875 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 11876 } 11877 11878 /** 11879 * Indicates whether this view reacts to long click events or not. 11880 * 11881 * @return true if the view is long clickable, false otherwise 11882 * 11883 * @see #setLongClickable(boolean) 11884 * @attr ref android.R.styleable#View_longClickable 11885 */ 11886 @InspectableProperty 11887 public boolean isLongClickable() { 11888 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 11889 } 11890 11891 /** 11892 * Enables or disables long click events for this view. When a view is long 11893 * clickable it reacts to the user holding down the button for a longer 11894 * duration than a tap. This event can either launch the listener or a 11895 * context menu. 11896 * 11897 * @param longClickable true to make the view long clickable, false otherwise 11898 * @see #isLongClickable() 11899 * @attr ref android.R.styleable#View_longClickable 11900 */ 11901 public void setLongClickable(boolean longClickable) { 11902 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 11903 } 11904 11905 /** 11906 * Indicates whether this view reacts to context clicks or not. 11907 * 11908 * @return true if the view is context clickable, false otherwise 11909 * @see #setContextClickable(boolean) 11910 * @attr ref android.R.styleable#View_contextClickable 11911 */ 11912 @InspectableProperty 11913 public boolean isContextClickable() { 11914 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 11915 } 11916 11917 /** 11918 * Enables or disables context clicking for this view. This event can launch the listener. 11919 * 11920 * @param contextClickable true to make the view react to a context click, false otherwise 11921 * @see #isContextClickable() 11922 * @attr ref android.R.styleable#View_contextClickable 11923 */ 11924 public void setContextClickable(boolean contextClickable) { 11925 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 11926 } 11927 11928 /** 11929 * Sets the pressed state for this view and provides a touch coordinate for 11930 * animation hinting. 11931 * 11932 * @param pressed Pass true to set the View's internal state to "pressed", 11933 * or false to reverts the View's internal state from a 11934 * previously set "pressed" state. 11935 * @param x The x coordinate of the touch that caused the press 11936 * @param y The y coordinate of the touch that caused the press 11937 */ 11938 private void setPressed(boolean pressed, float x, float y) { 11939 if (pressed) { 11940 drawableHotspotChanged(x, y); 11941 } 11942 11943 setPressed(pressed); 11944 } 11945 11946 /** 11947 * Sets the pressed state for this view. 11948 * 11949 * @see #isClickable() 11950 * @see #setClickable(boolean) 11951 * 11952 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 11953 * the View's internal state from a previously set "pressed" state. 11954 */ 11955 public void setPressed(boolean pressed) { 11956 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 11957 11958 if (pressed) { 11959 mPrivateFlags |= PFLAG_PRESSED; 11960 } else { 11961 mPrivateFlags &= ~PFLAG_PRESSED; 11962 } 11963 11964 if (needsRefresh) { 11965 refreshDrawableState(); 11966 } 11967 dispatchSetPressed(pressed); 11968 } 11969 11970 /** 11971 * Dispatch setPressed to all of this View's children. 11972 * 11973 * @see #setPressed(boolean) 11974 * 11975 * @param pressed The new pressed state 11976 */ 11977 protected void dispatchSetPressed(boolean pressed) { 11978 } 11979 11980 /** 11981 * Indicates whether the view is currently in pressed state. Unless 11982 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 11983 * the pressed state. 11984 * 11985 * @see #setPressed(boolean) 11986 * @see #isClickable() 11987 * @see #setClickable(boolean) 11988 * 11989 * @return true if the view is currently pressed, false otherwise 11990 */ 11991 @ViewDebug.ExportedProperty 11992 @InspectableProperty(hasAttributeId = false) 11993 public boolean isPressed() { 11994 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 11995 } 11996 11997 /** 11998 * @hide 11999 * Indicates whether this view will participate in data collection through 12000 * {@link ViewStructure}. If true, it will not provide any data 12001 * for itself or its children. If false, the normal data collection will be allowed. 12002 * 12003 * @return Returns false if assist data collection is not blocked, else true. 12004 * 12005 * @see #setAssistBlocked(boolean) 12006 * @attr ref android.R.styleable#View_assistBlocked 12007 */ 12008 public boolean isAssistBlocked() { 12009 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 12010 } 12011 12012 /** 12013 * @hide 12014 * Controls whether assist data collection from this view and its children is enabled 12015 * (that is, whether {@link #onProvideStructure} and 12016 * {@link #onProvideVirtualStructure} will be called). The default value is false, 12017 * allowing normal assist collection. Setting this to false will disable assist collection. 12018 * 12019 * @param enabled Set to true to <em>disable</em> assist data collection, or false 12020 * (the default) to allow it. 12021 * 12022 * @see #isAssistBlocked() 12023 * @see #onProvideStructure 12024 * @see #onProvideVirtualStructure 12025 * @attr ref android.R.styleable#View_assistBlocked 12026 */ 12027 @UnsupportedAppUsage 12028 public void setAssistBlocked(boolean enabled) { 12029 if (enabled) { 12030 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 12031 } else { 12032 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 12033 } 12034 } 12035 12036 /** 12037 * Indicates whether this view will save its state (that is, 12038 * whether its {@link #onSaveInstanceState} method will be called). 12039 * 12040 * @return Returns true if the view state saving is enabled, else false. 12041 * 12042 * @see #setSaveEnabled(boolean) 12043 * @attr ref android.R.styleable#View_saveEnabled 12044 */ 12045 @InspectableProperty 12046 public boolean isSaveEnabled() { 12047 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 12048 } 12049 12050 /** 12051 * Controls whether the saving of this view's state is 12052 * enabled (that is, whether its {@link #onSaveInstanceState} method 12053 * will be called). Note that even if freezing is enabled, the 12054 * view still must have an id assigned to it (via {@link #setId(int)}) 12055 * for its state to be saved. This flag can only disable the 12056 * saving of this view; any child views may still have their state saved. 12057 * 12058 * @param enabled Set to false to <em>disable</em> state saving, or true 12059 * (the default) to allow it. 12060 * 12061 * @see #isSaveEnabled() 12062 * @see #setId(int) 12063 * @see #onSaveInstanceState() 12064 * @attr ref android.R.styleable#View_saveEnabled 12065 */ 12066 public void setSaveEnabled(boolean enabled) { 12067 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 12068 } 12069 12070 /** 12071 * Gets whether the framework should discard touches when the view's 12072 * window is obscured by another visible window. 12073 * Refer to the {@link View} security documentation for more details. 12074 * 12075 * @return True if touch filtering is enabled. 12076 * 12077 * @see #setFilterTouchesWhenObscured(boolean) 12078 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 12079 */ 12080 @ViewDebug.ExportedProperty 12081 @InspectableProperty 12082 public boolean getFilterTouchesWhenObscured() { 12083 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 12084 } 12085 12086 /** 12087 * Sets whether the framework should discard touches when the view's 12088 * window is obscured by another visible window. 12089 * Refer to the {@link View} security documentation for more details. 12090 * 12091 * @param enabled True if touch filtering should be enabled. 12092 * 12093 * @see #getFilterTouchesWhenObscured 12094 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 12095 */ 12096 public void setFilterTouchesWhenObscured(boolean enabled) { 12097 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 12098 FILTER_TOUCHES_WHEN_OBSCURED); 12099 } 12100 12101 /** 12102 * Indicates whether the entire hierarchy under this view will save its 12103 * state when a state saving traversal occurs from its parent. The default 12104 * is true; if false, these views will not be saved unless 12105 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 12106 * 12107 * @return Returns true if the view state saving from parent is enabled, else false. 12108 * 12109 * @see #setSaveFromParentEnabled(boolean) 12110 */ 12111 public boolean isSaveFromParentEnabled() { 12112 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 12113 } 12114 12115 /** 12116 * Controls whether the entire hierarchy under this view will save its 12117 * state when a state saving traversal occurs from its parent. The default 12118 * is true; if false, these views will not be saved unless 12119 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 12120 * 12121 * @param enabled Set to false to <em>disable</em> state saving, or true 12122 * (the default) to allow it. 12123 * 12124 * @see #isSaveFromParentEnabled() 12125 * @see #setId(int) 12126 * @see #onSaveInstanceState() 12127 */ 12128 public void setSaveFromParentEnabled(boolean enabled) { 12129 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 12130 } 12131 12132 12133 /** 12134 * Returns whether this View is currently able to take focus. 12135 * 12136 * @return True if this view can take focus, or false otherwise. 12137 */ 12138 @ViewDebug.ExportedProperty(category = "focus") 12139 public final boolean isFocusable() { 12140 return FOCUSABLE == (mViewFlags & FOCUSABLE); 12141 } 12142 12143 /** 12144 * Returns the focusable setting for this view. 12145 * 12146 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 12147 * @attr ref android.R.styleable#View_focusable 12148 */ 12149 @ViewDebug.ExportedProperty(mapping = { 12150 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 12151 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 12152 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 12153 }, category = "focus") 12154 @InspectableProperty(enumMapping = { 12155 @EnumEntry(value = NOT_FOCUSABLE, name = "false"), 12156 @EnumEntry(value = FOCUSABLE, name = "true"), 12157 @EnumEntry(value = FOCUSABLE_AUTO, name = "auto") 12158 }) 12159 @Focusable 12160 public int getFocusable() { 12161 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 12162 } 12163 12164 /** 12165 * When a view is focusable, it may not want to take focus when in touch mode. 12166 * For example, a button would like focus when the user is navigating via a D-pad 12167 * so that the user can click on it, but once the user starts touching the screen, 12168 * the button shouldn't take focus 12169 * @return Whether the view is focusable in touch mode. 12170 * @attr ref android.R.styleable#View_focusableInTouchMode 12171 */ 12172 @ViewDebug.ExportedProperty(category = "focus") 12173 @InspectableProperty 12174 public final boolean isFocusableInTouchMode() { 12175 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 12176 } 12177 12178 /** 12179 * Returns whether the view should be treated as a focusable unit by screen reader 12180 * accessibility tools. 12181 * @see #setScreenReaderFocusable(boolean) 12182 * 12183 * @return Whether the view should be treated as a focusable unit by screen reader. 12184 * 12185 * @attr ref android.R.styleable#View_screenReaderFocusable 12186 */ 12187 @InspectableProperty 12188 public boolean isScreenReaderFocusable() { 12189 return (mPrivateFlags3 & PFLAG3_SCREEN_READER_FOCUSABLE) != 0; 12190 } 12191 12192 /** 12193 * Sets whether this View should be a focusable element for screen readers 12194 * and include non-focusable Views from its subtree when providing feedback. 12195 * <p> 12196 * Note: this is similar to using <a href="#attr_android:focusable">{@code android:focusable}, 12197 * but does not impact input focus behavior. 12198 * 12199 * @param screenReaderFocusable Whether the view should be treated as a unit by screen reader 12200 * accessibility tools. 12201 * 12202 * @attr ref android.R.styleable#View_screenReaderFocusable 12203 */ 12204 public void setScreenReaderFocusable(boolean screenReaderFocusable) { 12205 updatePflags3AndNotifyA11yIfChanged(PFLAG3_SCREEN_READER_FOCUSABLE, screenReaderFocusable); 12206 } 12207 12208 /** 12209 * Gets whether this view is a heading for accessibility purposes. 12210 * 12211 * @return {@code true} if the view is a heading, {@code false} otherwise. 12212 * 12213 * @attr ref android.R.styleable#View_accessibilityHeading 12214 */ 12215 @InspectableProperty 12216 public boolean isAccessibilityHeading() { 12217 return (mPrivateFlags3 & PFLAG3_ACCESSIBILITY_HEADING) != 0; 12218 } 12219 12220 /** 12221 * Set if view is a heading for a section of content for accessibility purposes. 12222 * 12223 * @param isHeading {@code true} if the view is a heading, {@code false} otherwise. 12224 * 12225 * @attr ref android.R.styleable#View_accessibilityHeading 12226 */ 12227 public void setAccessibilityHeading(boolean isHeading) { 12228 updatePflags3AndNotifyA11yIfChanged(PFLAG3_ACCESSIBILITY_HEADING, isHeading); 12229 } 12230 12231 private void updatePflags3AndNotifyA11yIfChanged(int mask, boolean newValue) { 12232 int pflags3 = mPrivateFlags3; 12233 if (newValue) { 12234 pflags3 |= mask; 12235 } else { 12236 pflags3 &= ~mask; 12237 } 12238 12239 if (pflags3 != mPrivateFlags3) { 12240 mPrivateFlags3 = pflags3; 12241 notifyViewAccessibilityStateChangedIfNeeded( 12242 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12243 } 12244 } 12245 12246 /** 12247 * Find the nearest view in the specified direction that can take focus. 12248 * This does not actually give focus to that view. 12249 * 12250 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 12251 * 12252 * @return The nearest focusable in the specified direction, or null if none 12253 * can be found. 12254 */ 12255 public View focusSearch(@FocusRealDirection int direction) { 12256 if (mParent != null) { 12257 return mParent.focusSearch(this, direction); 12258 } else { 12259 return null; 12260 } 12261 } 12262 12263 /** 12264 * Returns whether this View is a root of a keyboard navigation cluster. 12265 * 12266 * @return True if this view is a root of a cluster, or false otherwise. 12267 * @attr ref android.R.styleable#View_keyboardNavigationCluster 12268 */ 12269 @ViewDebug.ExportedProperty(category = "focus") 12270 @InspectableProperty 12271 public final boolean isKeyboardNavigationCluster() { 12272 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 12273 } 12274 12275 /** 12276 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters 12277 * will be ignored. 12278 * 12279 * @return the keyboard navigation cluster that this view is in (can be this view) 12280 * or {@code null} if not in one 12281 */ 12282 View findKeyboardNavigationCluster() { 12283 if (mParent instanceof View) { 12284 View cluster = ((View) mParent).findKeyboardNavigationCluster(); 12285 if (cluster != null) { 12286 return cluster; 12287 } else if (isKeyboardNavigationCluster()) { 12288 return this; 12289 } 12290 } 12291 return null; 12292 } 12293 12294 /** 12295 * Set whether this view is a root of a keyboard navigation cluster. 12296 * 12297 * @param isCluster If true, this view is a root of a cluster. 12298 * 12299 * @attr ref android.R.styleable#View_keyboardNavigationCluster 12300 */ 12301 public void setKeyboardNavigationCluster(boolean isCluster) { 12302 if (isCluster) { 12303 mPrivateFlags3 |= PFLAG3_CLUSTER; 12304 } else { 12305 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 12306 } 12307 } 12308 12309 /** 12310 * Sets this View as the one which receives focus the next time cluster navigation jumps 12311 * to the cluster containing this View. This does NOT change focus even if the cluster 12312 * containing this view is current. 12313 * 12314 * @hide 12315 */ 12316 @TestApi 12317 public final void setFocusedInCluster() { 12318 setFocusedInCluster(findKeyboardNavigationCluster()); 12319 } 12320 12321 private void setFocusedInCluster(View cluster) { 12322 if (this instanceof ViewGroup) { 12323 ((ViewGroup) this).mFocusedInCluster = null; 12324 } 12325 if (cluster == this) { 12326 return; 12327 } 12328 ViewParent parent = mParent; 12329 View child = this; 12330 while (parent instanceof ViewGroup) { 12331 ((ViewGroup) parent).mFocusedInCluster = child; 12332 if (parent == cluster) { 12333 break; 12334 } 12335 child = (View) parent; 12336 parent = parent.getParent(); 12337 } 12338 } 12339 12340 private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) { 12341 if (oldFocus != null) { 12342 View oldCluster = oldFocus.findKeyboardNavigationCluster(); 12343 View cluster = findKeyboardNavigationCluster(); 12344 if (oldCluster != cluster) { 12345 // Going from one cluster to another, so save last-focused. 12346 // This covers cluster jumps because they are always FOCUS_DOWN 12347 oldFocus.setFocusedInCluster(oldCluster); 12348 if (!(oldFocus.mParent instanceof ViewGroup)) { 12349 return; 12350 } 12351 if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) { 12352 // This is a result of ordered navigation so consider navigation through 12353 // the previous cluster "complete" and clear its last-focused memory. 12354 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 12355 } else if (oldFocus instanceof ViewGroup 12356 && ((ViewGroup) oldFocus).getDescendantFocusability() 12357 == ViewGroup.FOCUS_AFTER_DESCENDANTS 12358 && ViewRootImpl.isViewDescendantOf(this, oldFocus)) { 12359 // This means oldFocus is not focusable since it obviously has a focusable 12360 // child (this). Don't restore focus to it in the future. 12361 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 12362 } 12363 } 12364 } 12365 } 12366 12367 /** 12368 * Returns whether this View should receive focus when the focus is restored for the view 12369 * hierarchy containing this view. 12370 * <p> 12371 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 12372 * window or serves as a target of cluster navigation. 12373 * 12374 * @see #restoreDefaultFocus() 12375 * 12376 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 12377 * @attr ref android.R.styleable#View_focusedByDefault 12378 */ 12379 @ViewDebug.ExportedProperty(category = "focus") 12380 @InspectableProperty 12381 public final boolean isFocusedByDefault() { 12382 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 12383 } 12384 12385 /** 12386 * Sets whether this View should receive focus when the focus is restored for the view 12387 * hierarchy containing this view. 12388 * <p> 12389 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 12390 * window or serves as a target of cluster navigation. 12391 * 12392 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 12393 * {@code false} otherwise. 12394 * 12395 * @see #restoreDefaultFocus() 12396 * 12397 * @attr ref android.R.styleable#View_focusedByDefault 12398 */ 12399 public void setFocusedByDefault(boolean isFocusedByDefault) { 12400 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 12401 return; 12402 } 12403 12404 if (isFocusedByDefault) { 12405 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 12406 } else { 12407 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 12408 } 12409 12410 if (mParent instanceof ViewGroup) { 12411 if (isFocusedByDefault) { 12412 ((ViewGroup) mParent).setDefaultFocus(this); 12413 } else { 12414 ((ViewGroup) mParent).clearDefaultFocus(this); 12415 } 12416 } 12417 } 12418 12419 /** 12420 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 12421 * 12422 * @return {@code true} if this view has default focus, {@code false} otherwise 12423 */ 12424 boolean hasDefaultFocus() { 12425 return isFocusedByDefault(); 12426 } 12427 12428 /** 12429 * Find the nearest keyboard navigation cluster in the specified direction. 12430 * This does not actually give focus to that cluster. 12431 * 12432 * @param currentCluster The starting point of the search. Null means the current cluster is not 12433 * found yet 12434 * @param direction Direction to look 12435 * 12436 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 12437 * can be found 12438 */ 12439 public View keyboardNavigationClusterSearch(View currentCluster, 12440 @FocusDirection int direction) { 12441 if (isKeyboardNavigationCluster()) { 12442 currentCluster = this; 12443 } 12444 if (isRootNamespace()) { 12445 // Root namespace means we should consider ourselves the top of the 12446 // tree for group searching; otherwise we could be group searching 12447 // into other tabs. see LocalActivityManager and TabHost for more info. 12448 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 12449 this, currentCluster, direction); 12450 } else if (mParent != null) { 12451 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 12452 } 12453 return null; 12454 } 12455 12456 /** 12457 * This method is the last chance for the focused view and its ancestors to 12458 * respond to an arrow key. This is called when the focused view did not 12459 * consume the key internally, nor could the view system find a new view in 12460 * the requested direction to give focus to. 12461 * 12462 * @param focused The currently focused view. 12463 * @param direction The direction focus wants to move. One of FOCUS_UP, 12464 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 12465 * @return True if the this view consumed this unhandled move. 12466 */ 12467 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 12468 return false; 12469 } 12470 12471 /** 12472 * Sets whether this View should use a default focus highlight when it gets focused but doesn't 12473 * have {@link android.R.attr#state_focused} defined in its background. 12474 * 12475 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus 12476 * highlight, {@code false} otherwise. 12477 * 12478 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 12479 */ 12480 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { 12481 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; 12482 } 12483 12484 /** 12485 12486 /** 12487 * Returns whether this View should use a default focus highlight when it gets focused but 12488 * doesn't have {@link android.R.attr#state_focused} defined in its background. 12489 * 12490 * @return True if this View should use a default focus highlight. 12491 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 12492 */ 12493 @ViewDebug.ExportedProperty(category = "focus") 12494 @InspectableProperty 12495 public final boolean getDefaultFocusHighlightEnabled() { 12496 return mDefaultFocusHighlightEnabled; 12497 } 12498 12499 /** 12500 * If a user manually specified the next view id for a particular direction, 12501 * use the root to look up the view. 12502 * @param root The root view of the hierarchy containing this view. 12503 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 12504 * or FOCUS_BACKWARD. 12505 * @return The user specified next view, or null if there is none. 12506 */ 12507 View findUserSetNextFocus(View root, @FocusDirection int direction) { 12508 switch (direction) { 12509 case FOCUS_LEFT: 12510 if (mNextFocusLeftId == View.NO_ID) return null; 12511 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 12512 case FOCUS_RIGHT: 12513 if (mNextFocusRightId == View.NO_ID) return null; 12514 return findViewInsideOutShouldExist(root, mNextFocusRightId); 12515 case FOCUS_UP: 12516 if (mNextFocusUpId == View.NO_ID) return null; 12517 return findViewInsideOutShouldExist(root, mNextFocusUpId); 12518 case FOCUS_DOWN: 12519 if (mNextFocusDownId == View.NO_ID) return null; 12520 return findViewInsideOutShouldExist(root, mNextFocusDownId); 12521 case FOCUS_FORWARD: 12522 if (mNextFocusForwardId == View.NO_ID) return null; 12523 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 12524 case FOCUS_BACKWARD: { 12525 if (mID == View.NO_ID) return null; 12526 final int id = mID; 12527 return root.findViewByPredicateInsideOut(this, new Predicate<View>() { 12528 @Override 12529 public boolean test(View t) { 12530 return t.mNextFocusForwardId == id; 12531 } 12532 }); 12533 } 12534 } 12535 return null; 12536 } 12537 12538 /** 12539 * If a user manually specified the next keyboard-navigation cluster for a particular direction, 12540 * use the root to look up the view. 12541 * 12542 * @param root the root view of the hierarchy containing this view 12543 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD} 12544 * @return the user-specified next cluster, or {@code null} if there is none 12545 */ 12546 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { 12547 switch (direction) { 12548 case FOCUS_FORWARD: 12549 if (mNextClusterForwardId == View.NO_ID) return null; 12550 return findViewInsideOutShouldExist(root, mNextClusterForwardId); 12551 case FOCUS_BACKWARD: { 12552 if (mID == View.NO_ID) return null; 12553 final int id = mID; 12554 return root.findViewByPredicateInsideOut(this, 12555 (Predicate<View>) t -> t.mNextClusterForwardId == id); 12556 } 12557 } 12558 return null; 12559 } 12560 12561 private View findViewInsideOutShouldExist(View root, int id) { 12562 if (mMatchIdPredicate == null) { 12563 mMatchIdPredicate = new MatchIdPredicate(); 12564 } 12565 mMatchIdPredicate.mId = id; 12566 View result = root.findViewByPredicateInsideOut(this, mMatchIdPredicate); 12567 if (result == null) { 12568 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 12569 } 12570 return result; 12571 } 12572 12573 /** 12574 * Find and return all focusable views that are descendants of this view, 12575 * possibly including this view if it is focusable itself. 12576 * 12577 * @param direction The direction of the focus 12578 * @return A list of focusable views 12579 */ 12580 public ArrayList<View> getFocusables(@FocusDirection int direction) { 12581 ArrayList<View> result = new ArrayList<View>(24); 12582 addFocusables(result, direction); 12583 return result; 12584 } 12585 12586 /** 12587 * Add any focusable views that are descendants of this view (possibly 12588 * including this view if it is focusable itself) to views. If we are in touch mode, 12589 * only add views that are also focusable in touch mode. 12590 * 12591 * @param views Focusable views found so far 12592 * @param direction The direction of the focus 12593 */ 12594 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 12595 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 12596 } 12597 12598 /** 12599 * Adds any focusable views that are descendants of this view (possibly 12600 * including this view if it is focusable itself) to views. This method 12601 * adds all focusable views regardless if we are in touch mode or 12602 * only views focusable in touch mode if we are in touch mode or 12603 * only views that can take accessibility focus if accessibility is enabled 12604 * depending on the focusable mode parameter. 12605 * 12606 * @param views Focusable views found so far or null if all we are interested is 12607 * the number of focusables. 12608 * @param direction The direction of the focus. 12609 * @param focusableMode The type of focusables to be added. 12610 * 12611 * @see #FOCUSABLES_ALL 12612 * @see #FOCUSABLES_TOUCH_MODE 12613 */ 12614 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 12615 @FocusableMode int focusableMode) { 12616 if (views == null) { 12617 return; 12618 } 12619 if (!canTakeFocus()) { 12620 return; 12621 } 12622 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 12623 && !isFocusableInTouchMode()) { 12624 return; 12625 } 12626 views.add(this); 12627 } 12628 12629 /** 12630 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 12631 * including this view if it is a cluster root itself) to views. 12632 * 12633 * @param views Keyboard navigation cluster roots found so far 12634 * @param direction Direction to look 12635 */ 12636 public void addKeyboardNavigationClusters( 12637 @NonNull Collection<View> views, 12638 int direction) { 12639 if (!isKeyboardNavigationCluster()) { 12640 return; 12641 } 12642 if (!hasFocusable()) { 12643 return; 12644 } 12645 views.add(this); 12646 } 12647 12648 /** 12649 * Finds the Views that contain given text. The containment is case insensitive. 12650 * The search is performed by either the text that the View renders or the content 12651 * description that describes the view for accessibility purposes and the view does 12652 * not render or both. Clients can specify how the search is to be performed via 12653 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 12654 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 12655 * 12656 * @param outViews The output list of matching Views. 12657 * @param searched The text to match against. 12658 * 12659 * @see #FIND_VIEWS_WITH_TEXT 12660 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 12661 * @see #setContentDescription(CharSequence) 12662 */ 12663 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 12664 @FindViewFlags int flags) { 12665 if (getAccessibilityNodeProvider() != null) { 12666 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 12667 outViews.add(this); 12668 } 12669 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 12670 && (searched != null && searched.length() > 0) 12671 && (mContentDescription != null && mContentDescription.length() > 0)) { 12672 String searchedLowerCase = searched.toString().toLowerCase(); 12673 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 12674 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 12675 outViews.add(this); 12676 } 12677 } 12678 } 12679 12680 /** 12681 * Find and return all touchable views that are descendants of this view, 12682 * possibly including this view if it is touchable itself. 12683 * 12684 * @return A list of touchable views 12685 */ 12686 public ArrayList<View> getTouchables() { 12687 ArrayList<View> result = new ArrayList<View>(); 12688 addTouchables(result); 12689 return result; 12690 } 12691 12692 /** 12693 * Add any touchable views that are descendants of this view (possibly 12694 * including this view if it is touchable itself) to views. 12695 * 12696 * @param views Touchable views found so far 12697 */ 12698 public void addTouchables(ArrayList<View> views) { 12699 final int viewFlags = mViewFlags; 12700 12701 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 12702 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 12703 && (viewFlags & ENABLED_MASK) == ENABLED) { 12704 views.add(this); 12705 } 12706 } 12707 12708 /** 12709 * Returns whether this View is accessibility focused. 12710 * 12711 * @return True if this View is accessibility focused. 12712 */ 12713 @InspectableProperty(hasAttributeId = false) 12714 public boolean isAccessibilityFocused() { 12715 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 12716 } 12717 12718 /** 12719 * Call this to try to give accessibility focus to this view. 12720 * 12721 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 12722 * returns false or the view is no visible or the view already has accessibility 12723 * focus. 12724 * 12725 * See also {@link #focusSearch(int)}, which is what you call to say that you 12726 * have focus, and you want your parent to look for the next one. 12727 * 12728 * @return Whether this view actually took accessibility focus. 12729 * 12730 * @hide 12731 */ 12732 @UnsupportedAppUsage 12733 public boolean requestAccessibilityFocus() { 12734 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 12735 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 12736 return false; 12737 } 12738 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 12739 return false; 12740 } 12741 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 12742 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 12743 ViewRootImpl viewRootImpl = getViewRootImpl(); 12744 if (viewRootImpl != null) { 12745 viewRootImpl.setAccessibilityFocus(this, null); 12746 } 12747 invalidate(); 12748 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 12749 return true; 12750 } 12751 return false; 12752 } 12753 12754 /** 12755 * Call this to try to clear accessibility focus of this view. 12756 * 12757 * See also {@link #focusSearch(int)}, which is what you call to say that you 12758 * have focus, and you want your parent to look for the next one. 12759 * 12760 * @hide 12761 */ 12762 @UnsupportedAppUsage 12763 public void clearAccessibilityFocus() { 12764 clearAccessibilityFocusNoCallbacks(0); 12765 12766 // Clear the global reference of accessibility focus if this view or 12767 // any of its descendants had accessibility focus. This will NOT send 12768 // an event or update internal state if focus is cleared from a 12769 // descendant view, which may leave views in inconsistent states. 12770 final ViewRootImpl viewRootImpl = getViewRootImpl(); 12771 if (viewRootImpl != null) { 12772 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 12773 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 12774 viewRootImpl.setAccessibilityFocus(null, null); 12775 } 12776 } 12777 } 12778 12779 private void sendAccessibilityHoverEvent(int eventType) { 12780 // Since we are not delivering to a client accessibility events from not 12781 // important views (unless the clinet request that) we need to fire the 12782 // event from the deepest view exposed to the client. As a consequence if 12783 // the user crosses a not exposed view the client will see enter and exit 12784 // of the exposed predecessor followed by and enter and exit of that same 12785 // predecessor when entering and exiting the not exposed descendant. This 12786 // is fine since the client has a clear idea which view is hovered at the 12787 // price of a couple more events being sent. This is a simple and 12788 // working solution. 12789 View source = this; 12790 while (true) { 12791 if (source.includeForAccessibility()) { 12792 source.sendAccessibilityEvent(eventType); 12793 return; 12794 } 12795 ViewParent parent = source.getParent(); 12796 if (parent instanceof View) { 12797 source = (View) parent; 12798 } else { 12799 return; 12800 } 12801 } 12802 } 12803 12804 /** 12805 * Clears accessibility focus without calling any callback methods 12806 * normally invoked in {@link #clearAccessibilityFocus()}. This method 12807 * is used separately from that one for clearing accessibility focus when 12808 * giving this focus to another view. 12809 * 12810 * @param action The action, if any, that led to focus being cleared. Set to 12811 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 12812 * the window. 12813 */ 12814 void clearAccessibilityFocusNoCallbacks(int action) { 12815 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 12816 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 12817 invalidate(); 12818 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 12819 AccessibilityEvent event = AccessibilityEvent.obtain( 12820 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 12821 event.setAction(action); 12822 if (mAccessibilityDelegate != null) { 12823 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 12824 } else { 12825 sendAccessibilityEventUnchecked(event); 12826 } 12827 } 12828 } 12829 } 12830 12831 /** 12832 * Call this to try to give focus to a specific view or to one of its 12833 * descendants. 12834 * 12835 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 12836 * false), or if it can't be focused due to other conditions (not focusable in touch mode 12837 * ({@link #isFocusableInTouchMode}) while the device is in touch mode, not visible, not 12838 * enabled, or has no size). 12839 * 12840 * See also {@link #focusSearch(int)}, which is what you call to say that you 12841 * have focus, and you want your parent to look for the next one. 12842 * 12843 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 12844 * {@link #FOCUS_DOWN} and <code>null</code>. 12845 * 12846 * @return Whether this view or one of its descendants actually took focus. 12847 */ 12848 public final boolean requestFocus() { 12849 return requestFocus(View.FOCUS_DOWN); 12850 } 12851 12852 /** 12853 * This will request focus for whichever View was last focused within this 12854 * cluster before a focus-jump out of it. 12855 * 12856 * @hide 12857 */ 12858 @TestApi 12859 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 12860 // Prioritize focusableByDefault over algorithmic focus selection. 12861 if (restoreDefaultFocus()) { 12862 return true; 12863 } 12864 return requestFocus(direction); 12865 } 12866 12867 /** 12868 * This will request focus for whichever View not in a cluster was last focused before a 12869 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 12870 * the "first" focusable view it finds. 12871 * 12872 * @hide 12873 */ 12874 @TestApi 12875 public boolean restoreFocusNotInCluster() { 12876 return requestFocus(View.FOCUS_DOWN); 12877 } 12878 12879 /** 12880 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 12881 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 12882 * 12883 * @return Whether this view or one of its descendants actually took focus 12884 */ 12885 public boolean restoreDefaultFocus() { 12886 return requestFocus(View.FOCUS_DOWN); 12887 } 12888 12889 /** 12890 * Call this to try to give focus to a specific view or to one of its 12891 * descendants and give it a hint about what direction focus is heading. 12892 * 12893 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 12894 * false), or if it is focusable and it is not focusable in touch mode 12895 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 12896 * 12897 * See also {@link #focusSearch(int)}, which is what you call to say that you 12898 * have focus, and you want your parent to look for the next one. 12899 * 12900 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 12901 * <code>null</code> set for the previously focused rectangle. 12902 * 12903 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 12904 * @return Whether this view or one of its descendants actually took focus. 12905 */ 12906 public final boolean requestFocus(int direction) { 12907 return requestFocus(direction, null); 12908 } 12909 12910 /** 12911 * Call this to try to give focus to a specific view or to one of its descendants 12912 * and give it hints about the direction and a specific rectangle that the focus 12913 * is coming from. The rectangle can help give larger views a finer grained hint 12914 * about where focus is coming from, and therefore, where to show selection, or 12915 * forward focus change internally. 12916 * 12917 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 12918 * false), or if it is focusable and it is not focusable in touch mode 12919 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 12920 * 12921 * A View will not take focus if it is not visible. 12922 * 12923 * A View will not take focus if one of its parents has 12924 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 12925 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 12926 * 12927 * See also {@link #focusSearch(int)}, which is what you call to say that you 12928 * have focus, and you want your parent to look for the next one. 12929 * 12930 * You may wish to override this method if your custom {@link View} has an internal 12931 * {@link View} that it wishes to forward the request to. 12932 * 12933 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 12934 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 12935 * to give a finer grained hint about where focus is coming from. May be null 12936 * if there is no hint. 12937 * @return Whether this view or one of its descendants actually took focus. 12938 */ 12939 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 12940 return requestFocusNoSearch(direction, previouslyFocusedRect); 12941 } 12942 12943 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 12944 // need to be focusable 12945 if (!canTakeFocus()) { 12946 return false; 12947 } 12948 12949 // need to be focusable in touch mode if in touch mode 12950 if (isInTouchMode() && 12951 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 12952 return false; 12953 } 12954 12955 // need to not have any parents blocking us 12956 if (hasAncestorThatBlocksDescendantFocus()) { 12957 return false; 12958 } 12959 12960 if (!isLayoutValid()) { 12961 mPrivateFlags |= PFLAG_WANTS_FOCUS; 12962 } else { 12963 clearParentsWantFocus(); 12964 } 12965 12966 handleFocusGainInternal(direction, previouslyFocusedRect); 12967 return true; 12968 } 12969 12970 void clearParentsWantFocus() { 12971 if (mParent instanceof View) { 12972 ((View) mParent).mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 12973 ((View) mParent).clearParentsWantFocus(); 12974 } 12975 } 12976 12977 /** 12978 * Call this to try to give focus to a specific view or to one of its descendants. This is a 12979 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 12980 * touch mode to request focus when they are touched. 12981 * 12982 * @return Whether this view or one of its descendants actually took focus. 12983 * 12984 * @see #isInTouchMode() 12985 * 12986 */ 12987 public final boolean requestFocusFromTouch() { 12988 // Leave touch mode if we need to 12989 if (isInTouchMode()) { 12990 ViewRootImpl viewRoot = getViewRootImpl(); 12991 if (viewRoot != null) { 12992 viewRoot.ensureTouchMode(false); 12993 } 12994 } 12995 return requestFocus(View.FOCUS_DOWN); 12996 } 12997 12998 /** 12999 * @return Whether any ancestor of this view blocks descendant focus. 13000 */ 13001 private boolean hasAncestorThatBlocksDescendantFocus() { 13002 final boolean focusableInTouchMode = isFocusableInTouchMode(); 13003 ViewParent ancestor = mParent; 13004 while (ancestor instanceof ViewGroup) { 13005 final ViewGroup vgAncestor = (ViewGroup) ancestor; 13006 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 13007 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 13008 return true; 13009 } else { 13010 ancestor = vgAncestor.getParent(); 13011 } 13012 } 13013 return false; 13014 } 13015 13016 /** 13017 * Gets the mode for determining whether this View is important for accessibility. 13018 * A view is important for accessibility if it fires accessibility events and if it 13019 * is reported to accessibility services that query the screen. 13020 * 13021 * @return The mode for determining whether a view is important for accessibility, one 13022 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 13023 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 13024 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 13025 * 13026 * @attr ref android.R.styleable#View_importantForAccessibility 13027 * 13028 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 13029 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 13030 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 13031 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 13032 */ 13033 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 13034 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 13035 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 13036 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 13037 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 13038 to = "noHideDescendants") 13039 }) 13040 @InspectableProperty(enumMapping = { 13041 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"), 13042 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"), 13043 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"), 13044 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 13045 name = "noHideDescendants"), 13046 }) 13047 public int getImportantForAccessibility() { 13048 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 13049 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 13050 } 13051 13052 /** 13053 * Sets the live region mode for this view. This indicates to accessibility 13054 * services whether they should automatically notify the user about changes 13055 * to the view's content description or text, or to the content descriptions 13056 * or text of the view's children (where applicable). 13057 * <p> 13058 * For example, in a login screen with a TextView that displays an "incorrect 13059 * password" notification, that view should be marked as a live region with 13060 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 13061 * <p> 13062 * To disable change notifications for this view, use 13063 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 13064 * mode for most views. 13065 * <p> 13066 * To indicate that the user should be notified of changes, use 13067 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 13068 * <p> 13069 * If the view's changes should interrupt ongoing speech and notify the user 13070 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 13071 * 13072 * @param mode The live region mode for this view, one of: 13073 * <ul> 13074 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 13075 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 13076 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 13077 * </ul> 13078 * @attr ref android.R.styleable#View_accessibilityLiveRegion 13079 */ 13080 public void setAccessibilityLiveRegion(int mode) { 13081 if (mode != getAccessibilityLiveRegion()) { 13082 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 13083 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 13084 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 13085 notifyViewAccessibilityStateChangedIfNeeded( 13086 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13087 } 13088 } 13089 13090 /** 13091 * Gets the live region mode for this View. 13092 * 13093 * @return The live region mode for the view. 13094 * 13095 * @attr ref android.R.styleable#View_accessibilityLiveRegion 13096 * 13097 * @see #setAccessibilityLiveRegion(int) 13098 */ 13099 @InspectableProperty(enumMapping = { 13100 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"), 13101 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"), 13102 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive") 13103 }) 13104 public int getAccessibilityLiveRegion() { 13105 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 13106 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 13107 } 13108 13109 /** 13110 * Sets how to determine whether this view is important for accessibility 13111 * which is if it fires accessibility events and if it is reported to 13112 * accessibility services that query the screen. 13113 * 13114 * @param mode How to determine whether this view is important for accessibility. 13115 * 13116 * @attr ref android.R.styleable#View_importantForAccessibility 13117 * 13118 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 13119 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 13120 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 13121 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 13122 */ 13123 public void setImportantForAccessibility(int mode) { 13124 final int oldMode = getImportantForAccessibility(); 13125 if (mode != oldMode) { 13126 final boolean hideDescendants = 13127 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 13128 13129 // If this node or its descendants are no longer important, try to 13130 // clear accessibility focus. 13131 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 13132 final View focusHost = findAccessibilityFocusHost(hideDescendants); 13133 if (focusHost != null) { 13134 focusHost.clearAccessibilityFocus(); 13135 } 13136 } 13137 13138 // If we're moving between AUTO and another state, we might not need 13139 // to send a subtree changed notification. We'll store the computed 13140 // importance, since we'll need to check it later to make sure. 13141 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 13142 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 13143 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 13144 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 13145 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 13146 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 13147 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 13148 notifySubtreeAccessibilityStateChangedIfNeeded(); 13149 } else { 13150 notifyViewAccessibilityStateChangedIfNeeded( 13151 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13152 } 13153 } 13154 } 13155 13156 /** 13157 * Returns the view within this view's hierarchy that is hosting 13158 * accessibility focus. 13159 * 13160 * @param searchDescendants whether to search for focus in descendant views 13161 * @return the view hosting accessibility focus, or {@code null} 13162 */ 13163 private View findAccessibilityFocusHost(boolean searchDescendants) { 13164 if (isAccessibilityFocusedViewOrHost()) { 13165 return this; 13166 } 13167 13168 if (searchDescendants) { 13169 final ViewRootImpl viewRoot = getViewRootImpl(); 13170 if (viewRoot != null) { 13171 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 13172 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 13173 return focusHost; 13174 } 13175 } 13176 } 13177 13178 return null; 13179 } 13180 13181 /** 13182 * Computes whether this view should be exposed for accessibility. In 13183 * general, views that are interactive or provide information are exposed 13184 * while views that serve only as containers are hidden. 13185 * <p> 13186 * If an ancestor of this view has importance 13187 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 13188 * returns <code>false</code>. 13189 * <p> 13190 * Otherwise, the value is computed according to the view's 13191 * {@link #getImportantForAccessibility()} value: 13192 * <ol> 13193 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 13194 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 13195 * </code> 13196 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 13197 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 13198 * view satisfies any of the following: 13199 * <ul> 13200 * <li>Is actionable, e.g. {@link #isClickable()}, 13201 * {@link #isLongClickable()}, or {@link #isFocusable()} 13202 * <li>Has an {@link AccessibilityDelegate} 13203 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 13204 * {@link OnKeyListener}, etc. 13205 * <li>Is an accessibility live region, e.g. 13206 * {@link #getAccessibilityLiveRegion()} is not 13207 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 13208 * </ul> 13209 * <li>Has an accessibility pane title, see {@link #setAccessibilityPaneTitle}</li> 13210 * </ol> 13211 * 13212 * @return Whether the view is exposed for accessibility. 13213 * @see #setImportantForAccessibility(int) 13214 * @see #getImportantForAccessibility() 13215 */ 13216 public boolean isImportantForAccessibility() { 13217 final int mode = (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 13218 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 13219 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 13220 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 13221 return false; 13222 } 13223 13224 // Check parent mode to ensure we're not hidden. 13225 ViewParent parent = mParent; 13226 while (parent instanceof View) { 13227 if (((View) parent).getImportantForAccessibility() 13228 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 13229 return false; 13230 } 13231 parent = parent.getParent(); 13232 } 13233 13234 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 13235 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 13236 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE 13237 || isAccessibilityPane(); 13238 } 13239 13240 /** 13241 * Gets the parent for accessibility purposes. Note that the parent for 13242 * accessibility is not necessary the immediate parent. It is the first 13243 * predecessor that is important for accessibility. 13244 * 13245 * @return The parent for accessibility purposes. 13246 */ 13247 public ViewParent getParentForAccessibility() { 13248 if (mParent instanceof View) { 13249 View parentView = (View) mParent; 13250 if (parentView.includeForAccessibility()) { 13251 return mParent; 13252 } else { 13253 return mParent.getParentForAccessibility(); 13254 } 13255 } 13256 return null; 13257 } 13258 13259 /** @hide */ 13260 View getSelfOrParentImportantForA11y() { 13261 if (isImportantForAccessibility()) return this; 13262 ViewParent parent = getParentForAccessibility(); 13263 if (parent instanceof View) return (View) parent; 13264 return null; 13265 } 13266 13267 /** 13268 * Adds the children of this View relevant for accessibility to the given list 13269 * as output. Since some Views are not important for accessibility the added 13270 * child views are not necessarily direct children of this view, rather they are 13271 * the first level of descendants important for accessibility. 13272 * 13273 * @param outChildren The output list that will receive children for accessibility. 13274 */ 13275 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 13276 13277 } 13278 13279 /** 13280 * Whether to regard this view for accessibility. A view is regarded for 13281 * accessibility if it is important for accessibility or the querying 13282 * accessibility service has explicitly requested that view not 13283 * important for accessibility are regarded. 13284 * 13285 * @return Whether to regard the view for accessibility. 13286 * 13287 * @hide 13288 */ 13289 @UnsupportedAppUsage 13290 public boolean includeForAccessibility() { 13291 if (mAttachInfo != null) { 13292 return (mAttachInfo.mAccessibilityFetchFlags 13293 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 13294 || isImportantForAccessibility(); 13295 } 13296 return false; 13297 } 13298 13299 /** 13300 * Returns whether the View is considered actionable from 13301 * accessibility perspective. Such view are important for 13302 * accessibility. 13303 * 13304 * @return True if the view is actionable for accessibility. 13305 * 13306 * @hide 13307 */ 13308 public boolean isActionableForAccessibility() { 13309 return (isClickable() || isLongClickable() || isFocusable()); 13310 } 13311 13312 /** 13313 * Returns whether the View has registered callbacks which makes it 13314 * important for accessibility. 13315 * 13316 * @return True if the view is actionable for accessibility. 13317 */ 13318 private boolean hasListenersForAccessibility() { 13319 ListenerInfo info = getListenerInfo(); 13320 return mTouchDelegate != null || info.mOnKeyListener != null 13321 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 13322 || info.mOnHoverListener != null || info.mOnDragListener != null; 13323 } 13324 13325 /** 13326 * Notifies that the accessibility state of this view changed. The change 13327 * is local to this view and does not represent structural changes such 13328 * as children and parent. For example, the view became focusable. The 13329 * notification is at at most once every 13330 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 13331 * to avoid unnecessary load to the system. Also once a view has a pending 13332 * notification this method is a NOP until the notification has been sent. 13333 * 13334 * @hide 13335 */ 13336 @UnsupportedAppUsage 13337 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 13338 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 13339 return; 13340 } 13341 13342 // Changes to views with a pane title count as window state changes, as the pane title 13343 // marks them as significant parts of the UI. 13344 if ((changeType != AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) 13345 && isAccessibilityPane()) { 13346 // If the pane isn't visible, content changed events are sufficient unless we're 13347 // reporting that the view just disappeared 13348 if ((getVisibility() == VISIBLE) 13349 || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)) { 13350 final AccessibilityEvent event = AccessibilityEvent.obtain(); 13351 onInitializeAccessibilityEvent(event); 13352 event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 13353 event.setContentChangeTypes(changeType); 13354 event.setSource(this); 13355 onPopulateAccessibilityEvent(event); 13356 if (mParent != null) { 13357 try { 13358 mParent.requestSendAccessibilityEvent(this, event); 13359 } catch (AbstractMethodError e) { 13360 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() 13361 + " does not fully implement ViewParent", e); 13362 } 13363 } 13364 return; 13365 } 13366 } 13367 13368 // If this is a live region, we should send a subtree change event 13369 // from this view immediately. Otherwise, we can let it propagate up. 13370 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) { 13371 final AccessibilityEvent event = AccessibilityEvent.obtain(); 13372 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 13373 event.setContentChangeTypes(changeType); 13374 sendAccessibilityEventUnchecked(event); 13375 } else if (mParent != null) { 13376 try { 13377 mParent.notifySubtreeAccessibilityStateChanged(this, this, changeType); 13378 } catch (AbstractMethodError e) { 13379 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 13380 " does not fully implement ViewParent", e); 13381 } 13382 } 13383 } 13384 13385 /** 13386 * Notifies that the accessibility state of this view changed. The change 13387 * is *not* local to this view and does represent structural changes such 13388 * as children and parent. For example, the view size changed. The 13389 * notification is at at most once every 13390 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 13391 * to avoid unnecessary load to the system. Also once a view has a pending 13392 * notification this method is a NOP until the notification has been sent. 13393 * 13394 * @hide 13395 */ 13396 @UnsupportedAppUsage 13397 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 13398 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 13399 return; 13400 } 13401 13402 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 13403 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 13404 if (mParent != null) { 13405 try { 13406 mParent.notifySubtreeAccessibilityStateChanged( 13407 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 13408 } catch (AbstractMethodError e) { 13409 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 13410 " does not fully implement ViewParent", e); 13411 } 13412 } 13413 } 13414 } 13415 13416 /** 13417 * Changes the visibility of this View without triggering any other changes. This should only 13418 * be used by animation frameworks, such as {@link android.transition.Transition}, where 13419 * visibility changes should not adjust focus or trigger a new layout. Application developers 13420 * should use {@link #setVisibility} instead to ensure that the hierarchy is correctly updated. 13421 * 13422 * <p>Only call this method when a temporary visibility must be applied during an 13423 * animation and the original visibility value is guaranteed to be reset after the 13424 * animation completes. Use {@link #setVisibility} in all other cases.</p> 13425 * 13426 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 13427 * @see #setVisibility(int) 13428 */ 13429 public void setTransitionVisibility(@Visibility int visibility) { 13430 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 13431 } 13432 13433 /** 13434 * Reset the flag indicating the accessibility state of the subtree rooted 13435 * at this view changed. 13436 */ 13437 void resetSubtreeAccessibilityStateChanged() { 13438 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 13439 } 13440 13441 /** 13442 * Report an accessibility action to this view's parents for delegated processing. 13443 * 13444 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 13445 * call this method to delegate an accessibility action to a supporting parent. If the parent 13446 * returns true from its 13447 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 13448 * method this method will return true to signify that the action was consumed.</p> 13449 * 13450 * <p>This method is useful for implementing nested scrolling child views. If 13451 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 13452 * a custom view implementation may invoke this method to allow a parent to consume the 13453 * scroll first. If this method returns true the custom view should skip its own scrolling 13454 * behavior.</p> 13455 * 13456 * @param action Accessibility action to delegate 13457 * @param arguments Optional action arguments 13458 * @return true if the action was consumed by a parent 13459 */ 13460 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 13461 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 13462 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 13463 return true; 13464 } 13465 } 13466 return false; 13467 } 13468 13469 /** 13470 * Performs the specified accessibility action on the view. For 13471 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 13472 * <p> 13473 * If an {@link AccessibilityDelegate} has been specified via calling 13474 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 13475 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 13476 * is responsible for handling this call. 13477 * </p> 13478 * 13479 * <p>The default implementation will delegate 13480 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 13481 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 13482 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 13483 * 13484 * @param action The action to perform. 13485 * @param arguments Optional action arguments. 13486 * @return Whether the action was performed. 13487 */ 13488 public boolean performAccessibilityAction(int action, Bundle arguments) { 13489 if (mAccessibilityDelegate != null) { 13490 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 13491 } else { 13492 return performAccessibilityActionInternal(action, arguments); 13493 } 13494 } 13495 13496 /** 13497 * @see #performAccessibilityAction(int, Bundle) 13498 * 13499 * Note: Called from the default {@link AccessibilityDelegate}. 13500 * 13501 * @hide 13502 */ 13503 @UnsupportedAppUsage 13504 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 13505 if (isNestedScrollingEnabled() 13506 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 13507 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 13508 || action == R.id.accessibilityActionScrollUp 13509 || action == R.id.accessibilityActionScrollLeft 13510 || action == R.id.accessibilityActionScrollDown 13511 || action == R.id.accessibilityActionScrollRight)) { 13512 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 13513 return true; 13514 } 13515 } 13516 13517 switch (action) { 13518 case AccessibilityNodeInfo.ACTION_CLICK: { 13519 if (isClickable()) { 13520 performClickInternal(); 13521 return true; 13522 } 13523 } break; 13524 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 13525 if (isLongClickable()) { 13526 performLongClick(); 13527 return true; 13528 } 13529 } break; 13530 case AccessibilityNodeInfo.ACTION_FOCUS: { 13531 if (!hasFocus()) { 13532 // Get out of touch mode since accessibility 13533 // wants to move focus around. 13534 getViewRootImpl().ensureTouchMode(false); 13535 return requestFocus(); 13536 } 13537 } break; 13538 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 13539 if (hasFocus()) { 13540 clearFocus(); 13541 return !isFocused(); 13542 } 13543 } break; 13544 case AccessibilityNodeInfo.ACTION_SELECT: { 13545 if (!isSelected()) { 13546 setSelected(true); 13547 return isSelected(); 13548 } 13549 } break; 13550 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 13551 if (isSelected()) { 13552 setSelected(false); 13553 return !isSelected(); 13554 } 13555 } break; 13556 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 13557 if (!isAccessibilityFocused()) { 13558 return requestAccessibilityFocus(); 13559 } 13560 } break; 13561 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 13562 if (isAccessibilityFocused()) { 13563 clearAccessibilityFocus(); 13564 return true; 13565 } 13566 } break; 13567 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 13568 if (arguments != null) { 13569 final int granularity = arguments.getInt( 13570 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 13571 final boolean extendSelection = arguments.getBoolean( 13572 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 13573 return traverseAtGranularity(granularity, true, extendSelection); 13574 } 13575 } break; 13576 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 13577 if (arguments != null) { 13578 final int granularity = arguments.getInt( 13579 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 13580 final boolean extendSelection = arguments.getBoolean( 13581 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 13582 return traverseAtGranularity(granularity, false, extendSelection); 13583 } 13584 } break; 13585 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 13586 CharSequence text = getIterableTextForAccessibility(); 13587 if (text == null) { 13588 return false; 13589 } 13590 final int start = (arguments != null) ? arguments.getInt( 13591 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 13592 final int end = (arguments != null) ? arguments.getInt( 13593 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 13594 // Only cursor position can be specified (selection length == 0) 13595 if ((getAccessibilitySelectionStart() != start 13596 || getAccessibilitySelectionEnd() != end) 13597 && (start == end)) { 13598 setAccessibilitySelection(start, end); 13599 notifyViewAccessibilityStateChangedIfNeeded( 13600 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13601 return true; 13602 } 13603 } break; 13604 case R.id.accessibilityActionShowOnScreen: { 13605 if (mAttachInfo != null) { 13606 final Rect r = mAttachInfo.mTmpInvalRect; 13607 getDrawingRect(r); 13608 return requestRectangleOnScreen(r, true); 13609 } 13610 } break; 13611 case R.id.accessibilityActionContextClick: { 13612 if (isContextClickable()) { 13613 performContextClick(); 13614 return true; 13615 } 13616 } break; 13617 case R.id.accessibilityActionShowTooltip: { 13618 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipPopup != null)) { 13619 // Tooltip already showing 13620 return false; 13621 } 13622 return showLongClickTooltip(0, 0); 13623 } 13624 case R.id.accessibilityActionHideTooltip: { 13625 if ((mTooltipInfo == null) || (mTooltipInfo.mTooltipPopup == null)) { 13626 // No tooltip showing 13627 return false; 13628 } 13629 hideTooltip(); 13630 return true; 13631 } 13632 } 13633 return false; 13634 } 13635 13636 private boolean traverseAtGranularity(int granularity, boolean forward, 13637 boolean extendSelection) { 13638 CharSequence text = getIterableTextForAccessibility(); 13639 if (text == null || text.length() == 0) { 13640 return false; 13641 } 13642 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 13643 if (iterator == null) { 13644 return false; 13645 } 13646 int current = getAccessibilitySelectionEnd(); 13647 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 13648 current = forward ? 0 : text.length(); 13649 } 13650 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 13651 if (range == null) { 13652 return false; 13653 } 13654 final int segmentStart = range[0]; 13655 final int segmentEnd = range[1]; 13656 int selectionStart; 13657 int selectionEnd; 13658 if (extendSelection && isAccessibilitySelectionExtendable()) { 13659 selectionStart = getAccessibilitySelectionStart(); 13660 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 13661 selectionStart = forward ? segmentStart : segmentEnd; 13662 } 13663 selectionEnd = forward ? segmentEnd : segmentStart; 13664 } else { 13665 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 13666 } 13667 setAccessibilitySelection(selectionStart, selectionEnd); 13668 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 13669 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 13670 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 13671 return true; 13672 } 13673 13674 /** 13675 * Gets the text reported for accessibility purposes. 13676 * 13677 * @return The accessibility text. 13678 * 13679 * @hide 13680 */ 13681 @UnsupportedAppUsage 13682 public CharSequence getIterableTextForAccessibility() { 13683 return getContentDescription(); 13684 } 13685 13686 /** 13687 * Gets whether accessibility selection can be extended. 13688 * 13689 * @return If selection is extensible. 13690 * 13691 * @hide 13692 */ 13693 public boolean isAccessibilitySelectionExtendable() { 13694 return false; 13695 } 13696 13697 /** 13698 * @hide 13699 */ 13700 public int getAccessibilitySelectionStart() { 13701 return mAccessibilityCursorPosition; 13702 } 13703 13704 /** 13705 * @hide 13706 */ 13707 public int getAccessibilitySelectionEnd() { 13708 return getAccessibilitySelectionStart(); 13709 } 13710 13711 /** 13712 * @hide 13713 */ 13714 public void setAccessibilitySelection(int start, int end) { 13715 if (start == end && end == mAccessibilityCursorPosition) { 13716 return; 13717 } 13718 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 13719 mAccessibilityCursorPosition = start; 13720 } else { 13721 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 13722 } 13723 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 13724 } 13725 13726 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 13727 int fromIndex, int toIndex) { 13728 if (mParent == null) { 13729 return; 13730 } 13731 AccessibilityEvent event = AccessibilityEvent.obtain( 13732 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 13733 onInitializeAccessibilityEvent(event); 13734 onPopulateAccessibilityEvent(event); 13735 event.setFromIndex(fromIndex); 13736 event.setToIndex(toIndex); 13737 event.setAction(action); 13738 event.setMovementGranularity(granularity); 13739 mParent.requestSendAccessibilityEvent(this, event); 13740 } 13741 13742 /** 13743 * @hide 13744 */ 13745 @UnsupportedAppUsage 13746 public TextSegmentIterator getIteratorForGranularity(int granularity) { 13747 switch (granularity) { 13748 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 13749 CharSequence text = getIterableTextForAccessibility(); 13750 if (text != null && text.length() > 0) { 13751 CharacterTextSegmentIterator iterator = 13752 CharacterTextSegmentIterator.getInstance( 13753 mContext.getResources().getConfiguration().locale); 13754 iterator.initialize(text.toString()); 13755 return iterator; 13756 } 13757 } break; 13758 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 13759 CharSequence text = getIterableTextForAccessibility(); 13760 if (text != null && text.length() > 0) { 13761 WordTextSegmentIterator iterator = 13762 WordTextSegmentIterator.getInstance( 13763 mContext.getResources().getConfiguration().locale); 13764 iterator.initialize(text.toString()); 13765 return iterator; 13766 } 13767 } break; 13768 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 13769 CharSequence text = getIterableTextForAccessibility(); 13770 if (text != null && text.length() > 0) { 13771 ParagraphTextSegmentIterator iterator = 13772 ParagraphTextSegmentIterator.getInstance(); 13773 iterator.initialize(text.toString()); 13774 return iterator; 13775 } 13776 } break; 13777 } 13778 return null; 13779 } 13780 13781 /** 13782 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 13783 * and {@link #onFinishTemporaryDetach()}. 13784 * 13785 * <p>This method always returns {@code true} when called directly or indirectly from 13786 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 13787 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 13788 * <ul> 13789 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 13790 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 13791 * </ul> 13792 * </p> 13793 * 13794 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 13795 * and {@link #onFinishTemporaryDetach()}. 13796 */ isTemporarilyDetached()13797 public final boolean isTemporarilyDetached() { 13798 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 13799 } 13800 13801 /** 13802 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 13803 * a container View. 13804 */ 13805 @CallSuper dispatchStartTemporaryDetach()13806 public void dispatchStartTemporaryDetach() { 13807 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 13808 notifyEnterOrExitForAutoFillIfNeeded(false); 13809 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 13810 onStartTemporaryDetach(); 13811 } 13812 13813 /** 13814 * This is called when a container is going to temporarily detach a child, with 13815 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 13816 * It will either be followed by {@link #onFinishTemporaryDetach()} or 13817 * {@link #onDetachedFromWindow()} when the container is done. 13818 */ onStartTemporaryDetach()13819 public void onStartTemporaryDetach() { 13820 removeUnsetPressCallback(); 13821 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 13822 } 13823 13824 /** 13825 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 13826 * a container View. 13827 */ 13828 @CallSuper dispatchFinishTemporaryDetach()13829 public void dispatchFinishTemporaryDetach() { 13830 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 13831 onFinishTemporaryDetach(); 13832 if (hasWindowFocus() && hasFocus()) { 13833 notifyFocusChangeToInputMethodManager(true /* hasFocus */); 13834 } 13835 notifyEnterOrExitForAutoFillIfNeeded(true); 13836 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 13837 } 13838 13839 /** 13840 * Called after {@link #onStartTemporaryDetach} when the container is done 13841 * changing the view. 13842 */ onFinishTemporaryDetach()13843 public void onFinishTemporaryDetach() { 13844 } 13845 13846 /** 13847 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 13848 * for this view's window. Returns null if the view is not currently attached 13849 * to the window. Normally you will not need to use this directly, but 13850 * just use the standard high-level event callbacks like 13851 * {@link #onKeyDown(int, KeyEvent)}. 13852 */ getKeyDispatcherState()13853 public KeyEvent.DispatcherState getKeyDispatcherState() { 13854 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 13855 } 13856 13857 /** 13858 * Dispatch a key event before it is processed by any input method 13859 * associated with the view hierarchy. This can be used to intercept 13860 * key events in special situations before the IME consumes them; a 13861 * typical example would be handling the BACK key to update the application's 13862 * UI instead of allowing the IME to see it and close itself. 13863 * 13864 * @param event The key event to be dispatched. 13865 * @return True if the event was handled, false otherwise. 13866 */ dispatchKeyEventPreIme(KeyEvent event)13867 public boolean dispatchKeyEventPreIme(KeyEvent event) { 13868 return onKeyPreIme(event.getKeyCode(), event); 13869 } 13870 13871 /** 13872 * Dispatch a key event to the next view on the focus path. This path runs 13873 * from the top of the view tree down to the currently focused view. If this 13874 * view has focus, it will dispatch to itself. Otherwise it will dispatch 13875 * the next node down the focus path. This method also fires any key 13876 * listeners. 13877 * 13878 * @param event The key event to be dispatched. 13879 * @return True if the event was handled, false otherwise. 13880 */ dispatchKeyEvent(KeyEvent event)13881 public boolean dispatchKeyEvent(KeyEvent event) { 13882 if (mInputEventConsistencyVerifier != null) { 13883 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 13884 } 13885 13886 // Give any attached key listener a first crack at the event. 13887 //noinspection SimplifiableIfStatement 13888 ListenerInfo li = mListenerInfo; 13889 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 13890 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 13891 return true; 13892 } 13893 13894 if (event.dispatch(this, mAttachInfo != null 13895 ? mAttachInfo.mKeyDispatchState : null, this)) { 13896 return true; 13897 } 13898 13899 if (mInputEventConsistencyVerifier != null) { 13900 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 13901 } 13902 return false; 13903 } 13904 13905 /** 13906 * Dispatches a key shortcut event. 13907 * 13908 * @param event The key event to be dispatched. 13909 * @return True if the event was handled by the view, false otherwise. 13910 */ dispatchKeyShortcutEvent(KeyEvent event)13911 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 13912 return onKeyShortcut(event.getKeyCode(), event); 13913 } 13914 13915 /** 13916 * Pass the touch screen motion event down to the target view, or this 13917 * view if it is the target. 13918 * 13919 * @param event The motion event to be dispatched. 13920 * @return True if the event was handled by the view, false otherwise. 13921 */ dispatchTouchEvent(MotionEvent event)13922 public boolean dispatchTouchEvent(MotionEvent event) { 13923 // If the event should be handled by accessibility focus first. 13924 if (event.isTargetAccessibilityFocus()) { 13925 // We don't have focus or no virtual descendant has it, do not handle the event. 13926 if (!isAccessibilityFocusedViewOrHost()) { 13927 return false; 13928 } 13929 // We have focus and got the event, then use normal event dispatch. 13930 event.setTargetAccessibilityFocus(false); 13931 } 13932 13933 boolean result = false; 13934 13935 if (mInputEventConsistencyVerifier != null) { 13936 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 13937 } 13938 13939 final int actionMasked = event.getActionMasked(); 13940 if (actionMasked == MotionEvent.ACTION_DOWN) { 13941 // Defensive cleanup for new gesture 13942 stopNestedScroll(); 13943 } 13944 13945 if (onFilterTouchEventForSecurity(event)) { 13946 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 13947 result = true; 13948 } 13949 //noinspection SimplifiableIfStatement 13950 ListenerInfo li = mListenerInfo; 13951 if (li != null && li.mOnTouchListener != null 13952 && (mViewFlags & ENABLED_MASK) == ENABLED 13953 && li.mOnTouchListener.onTouch(this, event)) { 13954 result = true; 13955 } 13956 13957 if (!result && onTouchEvent(event)) { 13958 result = true; 13959 } 13960 } 13961 13962 if (!result && mInputEventConsistencyVerifier != null) { 13963 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 13964 } 13965 13966 // Clean up after nested scrolls if this is the end of a gesture; 13967 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 13968 // of the gesture. 13969 if (actionMasked == MotionEvent.ACTION_UP || 13970 actionMasked == MotionEvent.ACTION_CANCEL || 13971 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 13972 stopNestedScroll(); 13973 } 13974 13975 return result; 13976 } 13977 isAccessibilityFocusedViewOrHost()13978 boolean isAccessibilityFocusedViewOrHost() { 13979 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 13980 .getAccessibilityFocusedHost() == this); 13981 } 13982 13983 /** 13984 * Returns whether this view can receive pointer events. 13985 * 13986 * @return {@code true} if this view can receive pointer events. 13987 * @hide 13988 */ canReceivePointerEvents()13989 protected boolean canReceivePointerEvents() { 13990 return (mViewFlags & VISIBILITY_MASK) == VISIBLE || getAnimation() != null; 13991 } 13992 13993 /** 13994 * Filter the touch event to apply security policies. 13995 * 13996 * @param event The motion event to be filtered. 13997 * @return True if the event should be dispatched, false if the event should be dropped. 13998 * 13999 * @see #getFilterTouchesWhenObscured 14000 */ onFilterTouchEventForSecurity(MotionEvent event)14001 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 14002 //noinspection RedundantIfStatement 14003 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 14004 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 14005 // Window is obscured, drop this touch. 14006 return false; 14007 } 14008 return true; 14009 } 14010 14011 /** 14012 * Pass a trackball motion event down to the focused view. 14013 * 14014 * @param event The motion event to be dispatched. 14015 * @return True if the event was handled by the view, false otherwise. 14016 */ dispatchTrackballEvent(MotionEvent event)14017 public boolean dispatchTrackballEvent(MotionEvent event) { 14018 if (mInputEventConsistencyVerifier != null) { 14019 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 14020 } 14021 14022 return onTrackballEvent(event); 14023 } 14024 14025 /** 14026 * Pass a captured pointer event down to the focused view. 14027 * 14028 * @param event The motion event to be dispatched. 14029 * @return True if the event was handled by the view, false otherwise. 14030 */ dispatchCapturedPointerEvent(MotionEvent event)14031 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 14032 if (!hasPointerCapture()) { 14033 return false; 14034 } 14035 //noinspection SimplifiableIfStatement 14036 ListenerInfo li = mListenerInfo; 14037 if (li != null && li.mOnCapturedPointerListener != null 14038 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 14039 return true; 14040 } 14041 return onCapturedPointerEvent(event); 14042 } 14043 14044 /** 14045 * Dispatch a generic motion event. 14046 * <p> 14047 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 14048 * are delivered to the view under the pointer. All other generic motion events are 14049 * delivered to the focused view. Hover events are handled specially and are delivered 14050 * to {@link #onHoverEvent(MotionEvent)}. 14051 * </p> 14052 * 14053 * @param event The motion event to be dispatched. 14054 * @return True if the event was handled by the view, false otherwise. 14055 */ dispatchGenericMotionEvent(MotionEvent event)14056 public boolean dispatchGenericMotionEvent(MotionEvent event) { 14057 if (mInputEventConsistencyVerifier != null) { 14058 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 14059 } 14060 14061 final int source = event.getSource(); 14062 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 14063 final int action = event.getAction(); 14064 if (action == MotionEvent.ACTION_HOVER_ENTER 14065 || action == MotionEvent.ACTION_HOVER_MOVE 14066 || action == MotionEvent.ACTION_HOVER_EXIT) { 14067 if (dispatchHoverEvent(event)) { 14068 return true; 14069 } 14070 } else if (dispatchGenericPointerEvent(event)) { 14071 return true; 14072 } 14073 } else if (dispatchGenericFocusedEvent(event)) { 14074 return true; 14075 } 14076 14077 if (dispatchGenericMotionEventInternal(event)) { 14078 return true; 14079 } 14080 14081 if (mInputEventConsistencyVerifier != null) { 14082 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 14083 } 14084 return false; 14085 } 14086 dispatchGenericMotionEventInternal(MotionEvent event)14087 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 14088 //noinspection SimplifiableIfStatement 14089 ListenerInfo li = mListenerInfo; 14090 if (li != null && li.mOnGenericMotionListener != null 14091 && (mViewFlags & ENABLED_MASK) == ENABLED 14092 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 14093 return true; 14094 } 14095 14096 if (onGenericMotionEvent(event)) { 14097 return true; 14098 } 14099 14100 final int actionButton = event.getActionButton(); 14101 switch (event.getActionMasked()) { 14102 case MotionEvent.ACTION_BUTTON_PRESS: 14103 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 14104 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 14105 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 14106 if (performContextClick(event.getX(), event.getY())) { 14107 mInContextButtonPress = true; 14108 setPressed(true, event.getX(), event.getY()); 14109 removeTapCallback(); 14110 removeLongPressCallback(); 14111 return true; 14112 } 14113 } 14114 break; 14115 14116 case MotionEvent.ACTION_BUTTON_RELEASE: 14117 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 14118 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 14119 mInContextButtonPress = false; 14120 mIgnoreNextUpEvent = true; 14121 } 14122 break; 14123 } 14124 14125 if (mInputEventConsistencyVerifier != null) { 14126 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 14127 } 14128 return false; 14129 } 14130 14131 /** 14132 * Dispatch a hover event. 14133 * <p> 14134 * Do not call this method directly. 14135 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 14136 * </p> 14137 * 14138 * @param event The motion event to be dispatched. 14139 * @return True if the event was handled by the view, false otherwise. 14140 */ dispatchHoverEvent(MotionEvent event)14141 protected boolean dispatchHoverEvent(MotionEvent event) { 14142 ListenerInfo li = mListenerInfo; 14143 //noinspection SimplifiableIfStatement 14144 if (li != null && li.mOnHoverListener != null 14145 && (mViewFlags & ENABLED_MASK) == ENABLED 14146 && li.mOnHoverListener.onHover(this, event)) { 14147 return true; 14148 } 14149 14150 return onHoverEvent(event); 14151 } 14152 14153 /** 14154 * Returns true if the view has a child to which it has recently sent 14155 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 14156 * it does not have a hovered child, then it must be the innermost hovered view. 14157 * @hide 14158 */ hasHoveredChild()14159 protected boolean hasHoveredChild() { 14160 return false; 14161 } 14162 14163 /** 14164 * Returns true if the given point, in local coordinates, is inside the hovered child. 14165 * 14166 * @hide 14167 */ pointInHoveredChild(MotionEvent event)14168 protected boolean pointInHoveredChild(MotionEvent event) { 14169 return false; 14170 } 14171 14172 /** 14173 * Dispatch a generic motion event to the view under the first pointer. 14174 * <p> 14175 * Do not call this method directly. 14176 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 14177 * </p> 14178 * 14179 * @param event The motion event to be dispatched. 14180 * @return True if the event was handled by the view, false otherwise. 14181 */ dispatchGenericPointerEvent(MotionEvent event)14182 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 14183 return false; 14184 } 14185 14186 /** 14187 * Dispatch a generic motion event to the currently focused view. 14188 * <p> 14189 * Do not call this method directly. 14190 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 14191 * </p> 14192 * 14193 * @param event The motion event to be dispatched. 14194 * @return True if the event was handled by the view, false otherwise. 14195 */ dispatchGenericFocusedEvent(MotionEvent event)14196 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 14197 return false; 14198 } 14199 14200 /** 14201 * Dispatch a pointer event. 14202 * <p> 14203 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 14204 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 14205 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 14206 * and should not be expected to handle other pointing device features. 14207 * </p> 14208 * 14209 * @param event The motion event to be dispatched. 14210 * @return True if the event was handled by the view, false otherwise. 14211 * @hide 14212 */ 14213 @UnsupportedAppUsage dispatchPointerEvent(MotionEvent event)14214 public final boolean dispatchPointerEvent(MotionEvent event) { 14215 if (event.isTouchEvent()) { 14216 return dispatchTouchEvent(event); 14217 } else { 14218 return dispatchGenericMotionEvent(event); 14219 } 14220 } 14221 14222 /** 14223 * Called when the window containing this view gains or loses window focus. 14224 * ViewGroups should override to route to their children. 14225 * 14226 * @param hasFocus True if the window containing this view now has focus, 14227 * false otherwise. 14228 */ dispatchWindowFocusChanged(boolean hasFocus)14229 public void dispatchWindowFocusChanged(boolean hasFocus) { 14230 onWindowFocusChanged(hasFocus); 14231 } 14232 14233 /** 14234 * Called when the window containing this view gains or loses focus. Note 14235 * that this is separate from view focus: to receive key events, both 14236 * your view and its window must have focus. If a window is displayed 14237 * on top of yours that takes input focus, then your own window will lose 14238 * focus but the view focus will remain unchanged. 14239 * 14240 * @param hasWindowFocus True if the window containing this view now has 14241 * focus, false otherwise. 14242 */ onWindowFocusChanged(boolean hasWindowFocus)14243 public void onWindowFocusChanged(boolean hasWindowFocus) { 14244 if (!hasWindowFocus) { 14245 if (isPressed()) { 14246 setPressed(false); 14247 } 14248 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 14249 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 14250 notifyFocusChangeToInputMethodManager(false /* hasFocus */); 14251 } 14252 removeLongPressCallback(); 14253 removeTapCallback(); 14254 onFocusLost(); 14255 } else if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 14256 notifyFocusChangeToInputMethodManager(true /* hasFocus */); 14257 } 14258 14259 refreshDrawableState(); 14260 } 14261 14262 /** 14263 * Returns true if this view is in a window that currently has window focus. 14264 * Note that this is not the same as the view itself having focus. 14265 * 14266 * @return True if this view is in a window that currently has window focus. 14267 */ hasWindowFocus()14268 public boolean hasWindowFocus() { 14269 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 14270 } 14271 14272 /** 14273 * Dispatch a view visibility change down the view hierarchy. 14274 * ViewGroups should override to route to their children. 14275 * @param changedView The view whose visibility changed. Could be 'this' or 14276 * an ancestor view. 14277 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 14278 * {@link #INVISIBLE} or {@link #GONE}. 14279 */ dispatchVisibilityChanged(@onNull View changedView, @Visibility int visibility)14280 protected void dispatchVisibilityChanged(@NonNull View changedView, 14281 @Visibility int visibility) { 14282 onVisibilityChanged(changedView, visibility); 14283 } 14284 14285 /** 14286 * Called when the visibility of the view or an ancestor of the view has 14287 * changed. 14288 * 14289 * @param changedView The view whose visibility changed. May be 14290 * {@code this} or an ancestor view. 14291 * @param visibility The new visibility, one of {@link #VISIBLE}, 14292 * {@link #INVISIBLE} or {@link #GONE}. 14293 */ onVisibilityChanged(@onNull View changedView, @Visibility int visibility)14294 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 14295 } 14296 14297 /** 14298 * Dispatch a hint about whether this view is displayed. For instance, when 14299 * a View moves out of the screen, it might receives a display hint indicating 14300 * the view is not displayed. Applications should not <em>rely</em> on this hint 14301 * as there is no guarantee that they will receive one. 14302 * 14303 * @param hint A hint about whether or not this view is displayed: 14304 * {@link #VISIBLE} or {@link #INVISIBLE}. 14305 */ dispatchDisplayHint(@isibility int hint)14306 public void dispatchDisplayHint(@Visibility int hint) { 14307 onDisplayHint(hint); 14308 } 14309 14310 /** 14311 * Gives this view a hint about whether is displayed or not. For instance, when 14312 * a View moves out of the screen, it might receives a display hint indicating 14313 * the view is not displayed. Applications should not <em>rely</em> on this hint 14314 * as there is no guarantee that they will receive one. 14315 * 14316 * @param hint A hint about whether or not this view is displayed: 14317 * {@link #VISIBLE} or {@link #INVISIBLE}. 14318 */ onDisplayHint(@isibility int hint)14319 protected void onDisplayHint(@Visibility int hint) { 14320 } 14321 14322 /** 14323 * Dispatch a window visibility change down the view hierarchy. 14324 * ViewGroups should override to route to their children. 14325 * 14326 * @param visibility The new visibility of the window. 14327 * 14328 * @see #onWindowVisibilityChanged(int) 14329 */ dispatchWindowVisibilityChanged(@isibility int visibility)14330 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 14331 onWindowVisibilityChanged(visibility); 14332 } 14333 14334 /** 14335 * Called when the window containing has change its visibility 14336 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 14337 * that this tells you whether or not your window is being made visible 14338 * to the window manager; this does <em>not</em> tell you whether or not 14339 * your window is obscured by other windows on the screen, even if it 14340 * is itself visible. 14341 * 14342 * @param visibility The new visibility of the window. 14343 */ onWindowVisibilityChanged(@isibility int visibility)14344 protected void onWindowVisibilityChanged(@Visibility int visibility) { 14345 if (visibility == VISIBLE) { 14346 initialAwakenScrollBars(); 14347 } 14348 } 14349 14350 /** 14351 * @return true if this view and all ancestors are visible as of the last 14352 * {@link #onVisibilityAggregated(boolean)} call. 14353 */ isAggregatedVisible()14354 boolean isAggregatedVisible() { 14355 return (mPrivateFlags3 & PFLAG3_AGGREGATED_VISIBLE) != 0; 14356 } 14357 14358 /** 14359 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 14360 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 14361 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 14362 * 14363 * @param isVisible true if this view's visibility to the user is uninterrupted by its 14364 * ancestors or by window visibility 14365 * @return true if this view is visible to the user, not counting clipping or overlapping 14366 */ dispatchVisibilityAggregated(boolean isVisible)14367 boolean dispatchVisibilityAggregated(boolean isVisible) { 14368 final boolean thisVisible = getVisibility() == VISIBLE; 14369 // If we're not visible but something is telling us we are, ignore it. 14370 if (thisVisible || !isVisible) { 14371 onVisibilityAggregated(isVisible); 14372 } 14373 return thisVisible && isVisible; 14374 } 14375 14376 /** 14377 * Called when the user-visibility of this View is potentially affected by a change 14378 * to this view itself, an ancestor view or the window this view is attached to. 14379 * 14380 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 14381 * and this view's window is also visible 14382 */ 14383 @CallSuper onVisibilityAggregated(boolean isVisible)14384 public void onVisibilityAggregated(boolean isVisible) { 14385 // Update our internal visibility tracking so we can detect changes 14386 boolean oldVisible = isAggregatedVisible(); 14387 mPrivateFlags3 = isVisible ? (mPrivateFlags3 | PFLAG3_AGGREGATED_VISIBLE) 14388 : (mPrivateFlags3 & ~PFLAG3_AGGREGATED_VISIBLE); 14389 if (isVisible && mAttachInfo != null) { 14390 initialAwakenScrollBars(); 14391 } 14392 14393 final Drawable dr = mBackground; 14394 if (dr != null && isVisible != dr.isVisible()) { 14395 dr.setVisible(isVisible, false); 14396 } 14397 final Drawable hl = mDefaultFocusHighlight; 14398 if (hl != null && isVisible != hl.isVisible()) { 14399 hl.setVisible(isVisible, false); 14400 } 14401 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 14402 if (fg != null && isVisible != fg.isVisible()) { 14403 fg.setVisible(isVisible, false); 14404 } 14405 14406 if (isAutofillable()) { 14407 AutofillManager afm = getAutofillManager(); 14408 14409 if (afm != null && getAutofillViewId() > LAST_APP_AUTOFILL_ID) { 14410 if (mVisibilityChangeForAutofillHandler != null) { 14411 mVisibilityChangeForAutofillHandler.removeMessages(0); 14412 } 14413 14414 // If the view is in the background but still part of the hierarchy this is called 14415 // with isVisible=false. Hence visibility==false requires further checks 14416 if (isVisible) { 14417 afm.notifyViewVisibilityChanged(this, true); 14418 } else { 14419 if (mVisibilityChangeForAutofillHandler == null) { 14420 mVisibilityChangeForAutofillHandler = 14421 new VisibilityChangeForAutofillHandler(afm, this); 14422 } 14423 // Let current operation (e.g. removal of the view from the hierarchy) 14424 // finish before checking state 14425 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); 14426 } 14427 } 14428 } 14429 if (isAccessibilityPane()) { 14430 if (isVisible != oldVisible) { 14431 notifyViewAccessibilityStateChangedIfNeeded(isVisible 14432 ? AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED 14433 : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); 14434 } 14435 } 14436 14437 notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); 14438 if (!getSystemGestureExclusionRects().isEmpty() && isVisible != oldVisible) { 14439 postUpdateSystemGestureExclusionRects(); 14440 } 14441 } 14442 14443 /** 14444 * Returns the current visibility of the window this view is attached to 14445 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 14446 * 14447 * @return Returns the current visibility of the view's window. 14448 */ 14449 @Visibility getWindowVisibility()14450 public int getWindowVisibility() { 14451 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 14452 } 14453 14454 /** 14455 * Retrieve the overall visible display size in which the window this view is 14456 * attached to has been positioned in. This takes into account screen 14457 * decorations above the window, for both cases where the window itself 14458 * is being position inside of them or the window is being placed under 14459 * then and covered insets are used for the window to position its content 14460 * inside. In effect, this tells you the available area where content can 14461 * be placed and remain visible to users. 14462 * 14463 * <p>This function requires an IPC back to the window manager to retrieve 14464 * the requested information, so should not be used in performance critical 14465 * code like drawing. 14466 * 14467 * @param outRect Filled in with the visible display frame. If the view 14468 * is not attached to a window, this is simply the raw display size. 14469 */ getWindowVisibleDisplayFrame(Rect outRect)14470 public void getWindowVisibleDisplayFrame(Rect outRect) { 14471 if (mAttachInfo != null) { 14472 try { 14473 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 14474 } catch (RemoteException e) { 14475 return; 14476 } 14477 // XXX This is really broken, and probably all needs to be done 14478 // in the window manager, and we need to know more about whether 14479 // we want the area behind or in front of the IME. 14480 final Rect insets = mAttachInfo.mVisibleInsets; 14481 outRect.left += insets.left; 14482 outRect.top += insets.top; 14483 outRect.right -= insets.right; 14484 outRect.bottom -= insets.bottom; 14485 return; 14486 } 14487 // The view is not attached to a display so we don't have a context. 14488 // Make a best guess about the display size. 14489 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 14490 d.getRectSize(outRect); 14491 } 14492 14493 /** 14494 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 14495 * is currently in without any insets. 14496 * 14497 * @hide 14498 */ 14499 @UnsupportedAppUsage getWindowDisplayFrame(Rect outRect)14500 public void getWindowDisplayFrame(Rect outRect) { 14501 if (mAttachInfo != null) { 14502 try { 14503 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 14504 } catch (RemoteException e) { 14505 return; 14506 } 14507 return; 14508 } 14509 // The view is not attached to a display so we don't have a context. 14510 // Make a best guess about the display size. 14511 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 14512 d.getRectSize(outRect); 14513 } 14514 14515 /** 14516 * Dispatch a notification about a resource configuration change down 14517 * the view hierarchy. 14518 * ViewGroups should override to route to their children. 14519 * 14520 * @param newConfig The new resource configuration. 14521 * 14522 * @see #onConfigurationChanged(android.content.res.Configuration) 14523 */ dispatchConfigurationChanged(Configuration newConfig)14524 public void dispatchConfigurationChanged(Configuration newConfig) { 14525 onConfigurationChanged(newConfig); 14526 } 14527 14528 /** 14529 * Called when the current configuration of the resources being used 14530 * by the application have changed. You can use this to decide when 14531 * to reload resources that can changed based on orientation and other 14532 * configuration characteristics. You only need to use this if you are 14533 * not relying on the normal {@link android.app.Activity} mechanism of 14534 * recreating the activity instance upon a configuration change. 14535 * 14536 * @param newConfig The new resource configuration. 14537 */ onConfigurationChanged(Configuration newConfig)14538 protected void onConfigurationChanged(Configuration newConfig) { 14539 } 14540 14541 /** 14542 * Private function to aggregate all per-view attributes in to the view 14543 * root. 14544 */ dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility)14545 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 14546 performCollectViewAttributes(attachInfo, visibility); 14547 } 14548 performCollectViewAttributes(AttachInfo attachInfo, int visibility)14549 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 14550 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 14551 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 14552 attachInfo.mKeepScreenOn = true; 14553 } 14554 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 14555 ListenerInfo li = mListenerInfo; 14556 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 14557 attachInfo.mHasSystemUiListeners = true; 14558 } 14559 } 14560 } 14561 needGlobalAttributesUpdate(boolean force)14562 void needGlobalAttributesUpdate(boolean force) { 14563 final AttachInfo ai = mAttachInfo; 14564 if (ai != null && !ai.mRecomputeGlobalAttributes) { 14565 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 14566 || ai.mHasSystemUiListeners) { 14567 ai.mRecomputeGlobalAttributes = true; 14568 } 14569 } 14570 } 14571 14572 /** 14573 * Returns whether the device is currently in touch mode. Touch mode is entered 14574 * once the user begins interacting with the device by touch, and affects various 14575 * things like whether focus is always visible to the user. 14576 * 14577 * @return Whether the device is in touch mode. 14578 */ 14579 @ViewDebug.ExportedProperty isInTouchMode()14580 public boolean isInTouchMode() { 14581 if (mAttachInfo != null) { 14582 return mAttachInfo.mInTouchMode; 14583 } else { 14584 return ViewRootImpl.isInTouchMode(); 14585 } 14586 } 14587 14588 /** 14589 * Returns the context the view is running in, through which it can 14590 * access the current theme, resources, etc. 14591 * 14592 * @return The view's Context. 14593 */ 14594 @ViewDebug.CapturedViewProperty getContext()14595 public final Context getContext() { 14596 return mContext; 14597 } 14598 14599 /** 14600 * Handle a key event before it is processed by any input method 14601 * associated with the view hierarchy. This can be used to intercept 14602 * key events in special situations before the IME consumes them; a 14603 * typical example would be handling the BACK key to update the application's 14604 * UI instead of allowing the IME to see it and close itself. 14605 * 14606 * @param keyCode The value in event.getKeyCode(). 14607 * @param event Description of the key event. 14608 * @return If you handled the event, return true. If you want to allow the 14609 * event to be handled by the next receiver, return false. 14610 */ onKeyPreIme(int keyCode, KeyEvent event)14611 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 14612 return false; 14613 } 14614 14615 /** 14616 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 14617 * KeyEvent.Callback.onKeyDown()}: perform press of the view 14618 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 14619 * is released, if the view is enabled and clickable. 14620 * <p> 14621 * Key presses in software keyboards will generally NOT trigger this 14622 * listener, although some may elect to do so in some situations. Do not 14623 * rely on this to catch software key presses. 14624 * 14625 * @param keyCode a key code that represents the button pressed, from 14626 * {@link android.view.KeyEvent} 14627 * @param event the KeyEvent object that defines the button action 14628 */ onKeyDown(int keyCode, KeyEvent event)14629 public boolean onKeyDown(int keyCode, KeyEvent event) { 14630 if (KeyEvent.isConfirmKey(keyCode)) { 14631 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 14632 return true; 14633 } 14634 14635 if (event.getRepeatCount() == 0) { 14636 // Long clickable items don't necessarily have to be clickable. 14637 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 14638 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 14639 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 14640 // For the purposes of menu anchoring and drawable hotspots, 14641 // key events are considered to be at the center of the view. 14642 final float x = getWidth() / 2f; 14643 final float y = getHeight() / 2f; 14644 if (clickable) { 14645 setPressed(true, x, y); 14646 } 14647 checkForLongClick( 14648 ViewConfiguration.getLongPressTimeout(), 14649 x, 14650 y, 14651 // This is not a touch gesture -- do not classify it as one. 14652 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION); 14653 return true; 14654 } 14655 } 14656 } 14657 14658 return false; 14659 } 14660 14661 /** 14662 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 14663 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 14664 * the event). 14665 * <p>Key presses in software keyboards will generally NOT trigger this listener, 14666 * although some may elect to do so in some situations. Do not rely on this to 14667 * catch software key presses. 14668 */ onKeyLongPress(int keyCode, KeyEvent event)14669 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 14670 return false; 14671 } 14672 14673 /** 14674 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 14675 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 14676 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 14677 * or {@link KeyEvent#KEYCODE_SPACE} is released. 14678 * <p>Key presses in software keyboards will generally NOT trigger this listener, 14679 * although some may elect to do so in some situations. Do not rely on this to 14680 * catch software key presses. 14681 * 14682 * @param keyCode A key code that represents the button pressed, from 14683 * {@link android.view.KeyEvent}. 14684 * @param event The KeyEvent object that defines the button action. 14685 */ onKeyUp(int keyCode, KeyEvent event)14686 public boolean onKeyUp(int keyCode, KeyEvent event) { 14687 if (KeyEvent.isConfirmKey(keyCode)) { 14688 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 14689 return true; 14690 } 14691 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 14692 setPressed(false); 14693 14694 if (!mHasPerformedLongPress) { 14695 // This is a tap, so remove the longpress check 14696 removeLongPressCallback(); 14697 if (!event.isCanceled()) { 14698 return performClickInternal(); 14699 } 14700 } 14701 } 14702 } 14703 return false; 14704 } 14705 14706 /** 14707 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 14708 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 14709 * the event). 14710 * <p>Key presses in software keyboards will generally NOT trigger this listener, 14711 * although some may elect to do so in some situations. Do not rely on this to 14712 * catch software key presses. 14713 * 14714 * @param keyCode A key code that represents the button pressed, from 14715 * {@link android.view.KeyEvent}. 14716 * @param repeatCount The number of times the action was made. 14717 * @param event The KeyEvent object that defines the button action. 14718 */ onKeyMultiple(int keyCode, int repeatCount, KeyEvent event)14719 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 14720 return false; 14721 } 14722 14723 /** 14724 * Called on the focused view when a key shortcut event is not handled. 14725 * Override this method to implement local key shortcuts for the View. 14726 * Key shortcuts can also be implemented by setting the 14727 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 14728 * 14729 * @param keyCode The value in event.getKeyCode(). 14730 * @param event Description of the key event. 14731 * @return If you handled the event, return true. If you want to allow the 14732 * event to be handled by the next receiver, return false. 14733 */ onKeyShortcut(int keyCode, KeyEvent event)14734 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 14735 return false; 14736 } 14737 14738 /** 14739 * Check whether the called view is a text editor, in which case it 14740 * would make sense to automatically display a soft input window for 14741 * it. Subclasses should override this if they implement 14742 * {@link #onCreateInputConnection(EditorInfo)} to return true if 14743 * a call on that method would return a non-null InputConnection, and 14744 * they are really a first-class editor that the user would normally 14745 * start typing on when the go into a window containing your view. 14746 * 14747 * <p>The default implementation always returns false. This does 14748 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 14749 * will not be called or the user can not otherwise perform edits on your 14750 * view; it is just a hint to the system that this is not the primary 14751 * purpose of this view. 14752 * 14753 * @return Returns true if this view is a text editor, else false. 14754 */ onCheckIsTextEditor()14755 public boolean onCheckIsTextEditor() { 14756 return false; 14757 } 14758 14759 /** 14760 * Create a new InputConnection for an InputMethod to interact 14761 * with the view. The default implementation returns null, since it doesn't 14762 * support input methods. You can override this to implement such support. 14763 * This is only needed for views that take focus and text input. 14764 * 14765 * <p>When implementing this, you probably also want to implement 14766 * {@link #onCheckIsTextEditor()} to indicate you will return a 14767 * non-null InputConnection.</p> 14768 * 14769 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 14770 * object correctly and in its entirety, so that the connected IME can rely 14771 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 14772 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 14773 * must be filled in with the correct cursor position for IMEs to work correctly 14774 * with your application.</p> 14775 * 14776 * @param outAttrs Fill in with attribute information about the connection. 14777 */ onCreateInputConnection(EditorInfo outAttrs)14778 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 14779 return null; 14780 } 14781 14782 /** 14783 * Called by the {@link android.view.inputmethod.InputMethodManager} 14784 * when a view who is not the current 14785 * input connection target is trying to make a call on the manager. The 14786 * default implementation returns false; you can override this to return 14787 * true for certain views if you are performing InputConnection proxying 14788 * to them. 14789 * @param view The View that is making the InputMethodManager call. 14790 * @return Return true to allow the call, false to reject. 14791 */ checkInputConnectionProxy(View view)14792 public boolean checkInputConnectionProxy(View view) { 14793 return false; 14794 } 14795 14796 /** 14797 * Show the context menu for this view. It is not safe to hold on to the 14798 * menu after returning from this method. 14799 * 14800 * You should normally not overload this method. Overload 14801 * {@link #onCreateContextMenu(ContextMenu)} or define an 14802 * {@link OnCreateContextMenuListener} to add items to the context menu. 14803 * 14804 * @param menu The context menu to populate 14805 */ createContextMenu(ContextMenu menu)14806 public void createContextMenu(ContextMenu menu) { 14807 ContextMenuInfo menuInfo = getContextMenuInfo(); 14808 14809 // Sets the current menu info so all items added to menu will have 14810 // my extra info set. 14811 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 14812 14813 onCreateContextMenu(menu); 14814 ListenerInfo li = mListenerInfo; 14815 if (li != null && li.mOnCreateContextMenuListener != null) { 14816 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 14817 } 14818 14819 // Clear the extra information so subsequent items that aren't mine don't 14820 // have my extra info. 14821 ((MenuBuilder)menu).setCurrentMenuInfo(null); 14822 14823 if (mParent != null) { 14824 mParent.createContextMenu(menu); 14825 } 14826 } 14827 14828 /** 14829 * Views should implement this if they have extra information to associate 14830 * with the context menu. The return result is supplied as a parameter to 14831 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 14832 * callback. 14833 * 14834 * @return Extra information about the item for which the context menu 14835 * should be shown. This information will vary across different 14836 * subclasses of View. 14837 */ getContextMenuInfo()14838 protected ContextMenuInfo getContextMenuInfo() { 14839 return null; 14840 } 14841 14842 /** 14843 * Views should implement this if the view itself is going to add items to 14844 * the context menu. 14845 * 14846 * @param menu the context menu to populate 14847 */ onCreateContextMenu(ContextMenu menu)14848 protected void onCreateContextMenu(ContextMenu menu) { 14849 } 14850 14851 /** 14852 * Implement this method to handle trackball motion events. The 14853 * <em>relative</em> movement of the trackball since the last event 14854 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 14855 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 14856 * that a movement of 1 corresponds to the user pressing one DPAD key (so 14857 * they will often be fractional values, representing the more fine-grained 14858 * movement information available from a trackball). 14859 * 14860 * @param event The motion event. 14861 * @return True if the event was handled, false otherwise. 14862 */ onTrackballEvent(MotionEvent event)14863 public boolean onTrackballEvent(MotionEvent event) { 14864 return false; 14865 } 14866 14867 /** 14868 * Implement this method to handle generic motion events. 14869 * <p> 14870 * Generic motion events describe joystick movements, mouse hovers, track pad 14871 * touches, scroll wheel movements and other input events. The 14872 * {@link MotionEvent#getSource() source} of the motion event specifies 14873 * the class of input that was received. Implementations of this method 14874 * must examine the bits in the source before processing the event. 14875 * The following code example shows how this is done. 14876 * </p><p> 14877 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 14878 * are delivered to the view under the pointer. All other generic motion events are 14879 * delivered to the focused view. 14880 * </p> 14881 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 14882 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 14883 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 14884 * // process the joystick movement... 14885 * return true; 14886 * } 14887 * } 14888 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 14889 * switch (event.getAction()) { 14890 * case MotionEvent.ACTION_HOVER_MOVE: 14891 * // process the mouse hover movement... 14892 * return true; 14893 * case MotionEvent.ACTION_SCROLL: 14894 * // process the scroll wheel movement... 14895 * return true; 14896 * } 14897 * } 14898 * return super.onGenericMotionEvent(event); 14899 * }</pre> 14900 * 14901 * @param event The generic motion event being processed. 14902 * @return True if the event was handled, false otherwise. 14903 */ onGenericMotionEvent(MotionEvent event)14904 public boolean onGenericMotionEvent(MotionEvent event) { 14905 return false; 14906 } 14907 14908 /** 14909 * Dispatching hover events to {@link TouchDelegate} to improve accessibility. 14910 * <p> 14911 * This method is dispatching hover events to the delegate target to support explore by touch. 14912 * Similar to {@link ViewGroup#dispatchTouchEvent}, this method send proper hover events to 14913 * the delegate target according to the pointer and the touch area of the delegate while touch 14914 * exploration enabled. 14915 * </p> 14916 * 14917 * @param event The motion event dispatch to the delegate target. 14918 * @return True if the event was handled, false otherwise. 14919 * 14920 * @see #onHoverEvent 14921 */ dispatchTouchExplorationHoverEvent(MotionEvent event)14922 private boolean dispatchTouchExplorationHoverEvent(MotionEvent event) { 14923 final AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 14924 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 14925 return false; 14926 } 14927 14928 final boolean oldHoveringTouchDelegate = mHoveringTouchDelegate; 14929 final int action = event.getActionMasked(); 14930 boolean pointInDelegateRegion = false; 14931 boolean handled = false; 14932 14933 final AccessibilityNodeInfo.TouchDelegateInfo info = mTouchDelegate.getTouchDelegateInfo(); 14934 for (int i = 0; i < info.getRegionCount(); i++) { 14935 Region r = info.getRegionAt(i); 14936 if (r.contains((int) event.getX(), (int) event.getY())) { 14937 pointInDelegateRegion = true; 14938 } 14939 } 14940 14941 // Explore by touch should dispatch events to children under the pointer first if any 14942 // before dispatching to TouchDelegate. For non-hoverable views that do not consume 14943 // hover events but receive accessibility focus, it should also not delegate to these 14944 // views when hovered. 14945 if (!oldHoveringTouchDelegate) { 14946 if ((action == MotionEvent.ACTION_HOVER_ENTER 14947 || action == MotionEvent.ACTION_HOVER_MOVE) 14948 && !pointInHoveredChild(event) 14949 && pointInDelegateRegion) { 14950 mHoveringTouchDelegate = true; 14951 } 14952 } else { 14953 if (action == MotionEvent.ACTION_HOVER_EXIT 14954 || (action == MotionEvent.ACTION_HOVER_MOVE 14955 && (pointInHoveredChild(event) || !pointInDelegateRegion))) { 14956 mHoveringTouchDelegate = false; 14957 } 14958 } 14959 switch (action) { 14960 case MotionEvent.ACTION_HOVER_MOVE: 14961 if (oldHoveringTouchDelegate && mHoveringTouchDelegate) { 14962 // Inside bounds, dispatch as is. 14963 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 14964 } else if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 14965 // Moving inbound, synthesize hover enter. 14966 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 14967 ? event : MotionEvent.obtainNoHistory(event); 14968 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER); 14969 handled = mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 14970 eventNoHistory.setAction(action); 14971 handled |= mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 14972 } else if (oldHoveringTouchDelegate && !mHoveringTouchDelegate) { 14973 // Moving outbound, synthesize hover exit. 14974 final boolean hoverExitPending = event.isHoverExitPending(); 14975 event.setHoverExitPending(true); 14976 mTouchDelegate.onTouchExplorationHoverEvent(event); 14977 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 14978 ? event : MotionEvent.obtainNoHistory(event); 14979 eventNoHistory.setHoverExitPending(hoverExitPending); 14980 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); 14981 mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 14982 } // else: outside bounds, do nothing. 14983 break; 14984 case MotionEvent.ACTION_HOVER_ENTER: 14985 if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 14986 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 14987 } 14988 break; 14989 case MotionEvent.ACTION_HOVER_EXIT: 14990 if (oldHoveringTouchDelegate) { 14991 mTouchDelegate.onTouchExplorationHoverEvent(event); 14992 } 14993 break; 14994 } 14995 return handled; 14996 } 14997 14998 /** 14999 * Implement this method to handle hover events. 15000 * <p> 15001 * This method is called whenever a pointer is hovering into, over, or out of the 15002 * bounds of a view and the view is not currently being touched. 15003 * Hover events are represented as pointer events with action 15004 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 15005 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 15006 * </p> 15007 * <ul> 15008 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 15009 * when the pointer enters the bounds of the view.</li> 15010 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 15011 * when the pointer has already entered the bounds of the view and has moved.</li> 15012 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 15013 * when the pointer has exited the bounds of the view or when the pointer is 15014 * about to go down due to a button click, tap, or similar user action that 15015 * causes the view to be touched.</li> 15016 * </ul> 15017 * <p> 15018 * The view should implement this method to return true to indicate that it is 15019 * handling the hover event, such as by changing its drawable state. 15020 * </p><p> 15021 * The default implementation calls {@link #setHovered} to update the hovered state 15022 * of the view when a hover enter or hover exit event is received, if the view 15023 * is enabled and is clickable. The default implementation also sends hover 15024 * accessibility events. 15025 * </p> 15026 * 15027 * @param event The motion event that describes the hover. 15028 * @return True if the view handled the hover event. 15029 * 15030 * @see #isHovered 15031 * @see #setHovered 15032 * @see #onHoverChanged 15033 */ onHoverEvent(MotionEvent event)15034 public boolean onHoverEvent(MotionEvent event) { 15035 if (mTouchDelegate != null && dispatchTouchExplorationHoverEvent(event)) { 15036 return true; 15037 } 15038 15039 // The root view may receive hover (or touch) events that are outside the bounds of 15040 // the window. This code ensures that we only send accessibility events for 15041 // hovers that are actually within the bounds of the root view. 15042 final int action = event.getActionMasked(); 15043 if (!mSendingHoverAccessibilityEvents) { 15044 if ((action == MotionEvent.ACTION_HOVER_ENTER 15045 || action == MotionEvent.ACTION_HOVER_MOVE) 15046 && !hasHoveredChild() 15047 && pointInView(event.getX(), event.getY())) { 15048 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 15049 mSendingHoverAccessibilityEvents = true; 15050 } 15051 } else { 15052 if (action == MotionEvent.ACTION_HOVER_EXIT 15053 || (action == MotionEvent.ACTION_HOVER_MOVE 15054 && !pointInView(event.getX(), event.getY()))) { 15055 mSendingHoverAccessibilityEvents = false; 15056 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 15057 } 15058 } 15059 15060 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 15061 && event.isFromSource(InputDevice.SOURCE_MOUSE) 15062 && isOnScrollbar(event.getX(), event.getY())) { 15063 awakenScrollBars(); 15064 } 15065 15066 // If we consider ourself hoverable, or if we we're already hovered, 15067 // handle changing state in response to ENTER and EXIT events. 15068 if (isHoverable() || isHovered()) { 15069 switch (action) { 15070 case MotionEvent.ACTION_HOVER_ENTER: 15071 setHovered(true); 15072 break; 15073 case MotionEvent.ACTION_HOVER_EXIT: 15074 setHovered(false); 15075 break; 15076 } 15077 15078 // Dispatch the event to onGenericMotionEvent before returning true. 15079 // This is to provide compatibility with existing applications that 15080 // handled HOVER_MOVE events in onGenericMotionEvent and that would 15081 // break because of the new default handling for hoverable views 15082 // in onHoverEvent. 15083 // Note that onGenericMotionEvent will be called by default when 15084 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 15085 dispatchGenericMotionEventInternal(event); 15086 // The event was already handled by calling setHovered(), so always 15087 // return true. 15088 return true; 15089 } 15090 15091 return false; 15092 } 15093 15094 /** 15095 * Returns true if the view should handle {@link #onHoverEvent} 15096 * by calling {@link #setHovered} to change its hovered state. 15097 * 15098 * @return True if the view is hoverable. 15099 */ isHoverable()15100 private boolean isHoverable() { 15101 final int viewFlags = mViewFlags; 15102 if ((viewFlags & ENABLED_MASK) == DISABLED) { 15103 return false; 15104 } 15105 15106 return (viewFlags & CLICKABLE) == CLICKABLE 15107 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 15108 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 15109 } 15110 15111 /** 15112 * Returns true if the view is currently hovered. 15113 * 15114 * @return True if the view is currently hovered. 15115 * 15116 * @see #setHovered 15117 * @see #onHoverChanged 15118 */ 15119 @ViewDebug.ExportedProperty isHovered()15120 public boolean isHovered() { 15121 return (mPrivateFlags & PFLAG_HOVERED) != 0; 15122 } 15123 15124 /** 15125 * Sets whether the view is currently hovered. 15126 * <p> 15127 * Calling this method also changes the drawable state of the view. This 15128 * enables the view to react to hover by using different drawable resources 15129 * to change its appearance. 15130 * </p><p> 15131 * The {@link #onHoverChanged} method is called when the hovered state changes. 15132 * </p> 15133 * 15134 * @param hovered True if the view is hovered. 15135 * 15136 * @see #isHovered 15137 * @see #onHoverChanged 15138 */ setHovered(boolean hovered)15139 public void setHovered(boolean hovered) { 15140 if (hovered) { 15141 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 15142 mPrivateFlags |= PFLAG_HOVERED; 15143 refreshDrawableState(); 15144 onHoverChanged(true); 15145 } 15146 } else { 15147 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 15148 mPrivateFlags &= ~PFLAG_HOVERED; 15149 refreshDrawableState(); 15150 onHoverChanged(false); 15151 } 15152 } 15153 } 15154 15155 /** 15156 * Implement this method to handle hover state changes. 15157 * <p> 15158 * This method is called whenever the hover state changes as a result of a 15159 * call to {@link #setHovered}. 15160 * </p> 15161 * 15162 * @param hovered The current hover state, as returned by {@link #isHovered}. 15163 * 15164 * @see #isHovered 15165 * @see #setHovered 15166 */ onHoverChanged(boolean hovered)15167 public void onHoverChanged(boolean hovered) { 15168 } 15169 15170 /** 15171 * Handles scroll bar dragging by mouse input. 15172 * 15173 * @hide 15174 * @param event The motion event. 15175 * 15176 * @return true if the event was handled as a scroll bar dragging, false otherwise. 15177 */ handleScrollBarDragging(MotionEvent event)15178 protected boolean handleScrollBarDragging(MotionEvent event) { 15179 if (mScrollCache == null) { 15180 return false; 15181 } 15182 final float x = event.getX(); 15183 final float y = event.getY(); 15184 final int action = event.getAction(); 15185 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 15186 && action != MotionEvent.ACTION_DOWN) 15187 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 15188 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 15189 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 15190 return false; 15191 } 15192 15193 switch (action) { 15194 case MotionEvent.ACTION_MOVE: 15195 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 15196 return false; 15197 } 15198 if (mScrollCache.mScrollBarDraggingState 15199 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 15200 final Rect bounds = mScrollCache.mScrollBarBounds; 15201 getVerticalScrollBarBounds(bounds, null); 15202 final int range = computeVerticalScrollRange(); 15203 final int offset = computeVerticalScrollOffset(); 15204 final int extent = computeVerticalScrollExtent(); 15205 15206 final int thumbLength = ScrollBarUtils.getThumbLength( 15207 bounds.height(), bounds.width(), extent, range); 15208 final int thumbOffset = ScrollBarUtils.getThumbOffset( 15209 bounds.height(), thumbLength, extent, range, offset); 15210 15211 final float diff = y - mScrollCache.mScrollBarDraggingPos; 15212 final float maxThumbOffset = bounds.height() - thumbLength; 15213 final float newThumbOffset = 15214 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 15215 final int height = getHeight(); 15216 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 15217 && height > 0 && extent > 0) { 15218 final int newY = Math.round((range - extent) 15219 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 15220 if (newY != getScrollY()) { 15221 mScrollCache.mScrollBarDraggingPos = y; 15222 setScrollY(newY); 15223 } 15224 } 15225 return true; 15226 } 15227 if (mScrollCache.mScrollBarDraggingState 15228 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 15229 final Rect bounds = mScrollCache.mScrollBarBounds; 15230 getHorizontalScrollBarBounds(bounds, null); 15231 final int range = computeHorizontalScrollRange(); 15232 final int offset = computeHorizontalScrollOffset(); 15233 final int extent = computeHorizontalScrollExtent(); 15234 15235 final int thumbLength = ScrollBarUtils.getThumbLength( 15236 bounds.width(), bounds.height(), extent, range); 15237 final int thumbOffset = ScrollBarUtils.getThumbOffset( 15238 bounds.width(), thumbLength, extent, range, offset); 15239 15240 final float diff = x - mScrollCache.mScrollBarDraggingPos; 15241 final float maxThumbOffset = bounds.width() - thumbLength; 15242 final float newThumbOffset = 15243 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 15244 final int width = getWidth(); 15245 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 15246 && width > 0 && extent > 0) { 15247 final int newX = Math.round((range - extent) 15248 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 15249 if (newX != getScrollX()) { 15250 mScrollCache.mScrollBarDraggingPos = x; 15251 setScrollX(newX); 15252 } 15253 } 15254 return true; 15255 } 15256 case MotionEvent.ACTION_DOWN: 15257 if (mScrollCache.state == ScrollabilityCache.OFF) { 15258 return false; 15259 } 15260 if (isOnVerticalScrollbarThumb(x, y)) { 15261 mScrollCache.mScrollBarDraggingState = 15262 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 15263 mScrollCache.mScrollBarDraggingPos = y; 15264 return true; 15265 } 15266 if (isOnHorizontalScrollbarThumb(x, y)) { 15267 mScrollCache.mScrollBarDraggingState = 15268 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 15269 mScrollCache.mScrollBarDraggingPos = x; 15270 return true; 15271 } 15272 } 15273 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 15274 return false; 15275 } 15276 15277 /** 15278 * Implement this method to handle touch screen motion events. 15279 * <p> 15280 * If this method is used to detect click actions, it is recommended that 15281 * the actions be performed by implementing and calling 15282 * {@link #performClick()}. This will ensure consistent system behavior, 15283 * including: 15284 * <ul> 15285 * <li>obeying click sound preferences 15286 * <li>dispatching OnClickListener calls 15287 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 15288 * accessibility features are enabled 15289 * </ul> 15290 * 15291 * @param event The motion event. 15292 * @return True if the event was handled, false otherwise. 15293 */ onTouchEvent(MotionEvent event)15294 public boolean onTouchEvent(MotionEvent event) { 15295 final float x = event.getX(); 15296 final float y = event.getY(); 15297 final int viewFlags = mViewFlags; 15298 final int action = event.getAction(); 15299 15300 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 15301 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 15302 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 15303 15304 if ((viewFlags & ENABLED_MASK) == DISABLED) { 15305 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 15306 setPressed(false); 15307 } 15308 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 15309 // A disabled view that is clickable still consumes the touch 15310 // events, it just doesn't respond to them. 15311 return clickable; 15312 } 15313 if (mTouchDelegate != null) { 15314 if (mTouchDelegate.onTouchEvent(event)) { 15315 return true; 15316 } 15317 } 15318 15319 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 15320 switch (action) { 15321 case MotionEvent.ACTION_UP: 15322 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 15323 if ((viewFlags & TOOLTIP) == TOOLTIP) { 15324 handleTooltipUp(); 15325 } 15326 if (!clickable) { 15327 removeTapCallback(); 15328 removeLongPressCallback(); 15329 mInContextButtonPress = false; 15330 mHasPerformedLongPress = false; 15331 mIgnoreNextUpEvent = false; 15332 break; 15333 } 15334 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 15335 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 15336 // take focus if we don't have it already and we should in 15337 // touch mode. 15338 boolean focusTaken = false; 15339 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 15340 focusTaken = requestFocus(); 15341 } 15342 15343 if (prepressed) { 15344 // The button is being released before we actually 15345 // showed it as pressed. Make it show the pressed 15346 // state now (before scheduling the click) to ensure 15347 // the user sees it. 15348 setPressed(true, x, y); 15349 } 15350 15351 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 15352 // This is a tap, so remove the longpress check 15353 removeLongPressCallback(); 15354 15355 // Only perform take click actions if we were in the pressed state 15356 if (!focusTaken) { 15357 // Use a Runnable and post this rather than calling 15358 // performClick directly. This lets other visual state 15359 // of the view update before click actions start. 15360 if (mPerformClick == null) { 15361 mPerformClick = new PerformClick(); 15362 } 15363 if (!post(mPerformClick)) { 15364 performClickInternal(); 15365 } 15366 } 15367 } 15368 15369 if (mUnsetPressedState == null) { 15370 mUnsetPressedState = new UnsetPressedState(); 15371 } 15372 15373 if (prepressed) { 15374 postDelayed(mUnsetPressedState, 15375 ViewConfiguration.getPressedStateDuration()); 15376 } else if (!post(mUnsetPressedState)) { 15377 // If the post failed, unpress right now 15378 mUnsetPressedState.run(); 15379 } 15380 15381 removeTapCallback(); 15382 } 15383 mIgnoreNextUpEvent = false; 15384 break; 15385 15386 case MotionEvent.ACTION_DOWN: 15387 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 15388 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 15389 } 15390 mHasPerformedLongPress = false; 15391 15392 if (!clickable) { 15393 checkForLongClick( 15394 ViewConfiguration.getLongPressTimeout(), 15395 x, 15396 y, 15397 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 15398 break; 15399 } 15400 15401 if (performButtonActionOnTouchDown(event)) { 15402 break; 15403 } 15404 15405 // Walk up the hierarchy to determine if we're inside a scrolling container. 15406 boolean isInScrollingContainer = isInScrollingContainer(); 15407 15408 // For views inside a scrolling container, delay the pressed feedback for 15409 // a short period in case this is a scroll. 15410 if (isInScrollingContainer) { 15411 mPrivateFlags |= PFLAG_PREPRESSED; 15412 if (mPendingCheckForTap == null) { 15413 mPendingCheckForTap = new CheckForTap(); 15414 } 15415 mPendingCheckForTap.x = event.getX(); 15416 mPendingCheckForTap.y = event.getY(); 15417 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 15418 } else { 15419 // Not inside a scrolling container, so show the feedback right away 15420 setPressed(true, x, y); 15421 checkForLongClick( 15422 ViewConfiguration.getLongPressTimeout(), 15423 x, 15424 y, 15425 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 15426 } 15427 break; 15428 15429 case MotionEvent.ACTION_CANCEL: 15430 if (clickable) { 15431 setPressed(false); 15432 } 15433 removeTapCallback(); 15434 removeLongPressCallback(); 15435 mInContextButtonPress = false; 15436 mHasPerformedLongPress = false; 15437 mIgnoreNextUpEvent = false; 15438 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 15439 break; 15440 15441 case MotionEvent.ACTION_MOVE: 15442 if (clickable) { 15443 drawableHotspotChanged(x, y); 15444 } 15445 15446 final int motionClassification = event.getClassification(); 15447 final boolean ambiguousGesture = 15448 motionClassification == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE; 15449 int touchSlop = mTouchSlop; 15450 if (ambiguousGesture && hasPendingLongPressCallback()) { 15451 final float ambiguousMultiplier = 15452 ViewConfiguration.getAmbiguousGestureMultiplier(); 15453 if (!pointInView(x, y, touchSlop)) { 15454 // The default action here is to cancel long press. But instead, we 15455 // just extend the timeout here, in case the classification 15456 // stays ambiguous. 15457 removeLongPressCallback(); 15458 long delay = (long) (ViewConfiguration.getLongPressTimeout() 15459 * ambiguousMultiplier); 15460 // Subtract the time already spent 15461 delay -= event.getEventTime() - event.getDownTime(); 15462 checkForLongClick( 15463 delay, 15464 x, 15465 y, 15466 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 15467 } 15468 touchSlop *= ambiguousMultiplier; 15469 } 15470 15471 // Be lenient about moving outside of buttons 15472 if (!pointInView(x, y, touchSlop)) { 15473 // Outside button 15474 // Remove any future long press/tap checks 15475 removeTapCallback(); 15476 removeLongPressCallback(); 15477 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 15478 setPressed(false); 15479 } 15480 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 15481 } 15482 15483 final boolean deepPress = 15484 motionClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS; 15485 if (deepPress && hasPendingLongPressCallback()) { 15486 // process the long click action immediately 15487 removeLongPressCallback(); 15488 checkForLongClick( 15489 0 /* send immediately */, 15490 x, 15491 y, 15492 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS); 15493 } 15494 15495 break; 15496 } 15497 15498 return true; 15499 } 15500 15501 return false; 15502 } 15503 15504 /** 15505 * @hide 15506 */ 15507 @UnsupportedAppUsage isInScrollingContainer()15508 public boolean isInScrollingContainer() { 15509 ViewParent p = getParent(); 15510 while (p != null && p instanceof ViewGroup) { 15511 if (((ViewGroup) p).shouldDelayChildPressedState()) { 15512 return true; 15513 } 15514 p = p.getParent(); 15515 } 15516 return false; 15517 } 15518 15519 /** 15520 * Remove the longpress detection timer. 15521 */ removeLongPressCallback()15522 private void removeLongPressCallback() { 15523 if (mPendingCheckForLongPress != null) { 15524 removeCallbacks(mPendingCheckForLongPress); 15525 } 15526 } 15527 15528 /** 15529 * Return true if the long press callback is scheduled to run sometime in the future. 15530 * Return false if there is no scheduled long press callback at the moment. 15531 */ hasPendingLongPressCallback()15532 private boolean hasPendingLongPressCallback() { 15533 if (mPendingCheckForLongPress == null) { 15534 return false; 15535 } 15536 final AttachInfo attachInfo = mAttachInfo; 15537 if (attachInfo == null) { 15538 return false; 15539 } 15540 return attachInfo.mHandler.hasCallbacks(mPendingCheckForLongPress); 15541 } 15542 15543 /** 15544 * Remove the pending click action 15545 */ 15546 @UnsupportedAppUsage removePerformClickCallback()15547 private void removePerformClickCallback() { 15548 if (mPerformClick != null) { 15549 removeCallbacks(mPerformClick); 15550 } 15551 } 15552 15553 /** 15554 * Remove the prepress detection timer. 15555 */ removeUnsetPressCallback()15556 private void removeUnsetPressCallback() { 15557 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 15558 setPressed(false); 15559 removeCallbacks(mUnsetPressedState); 15560 } 15561 } 15562 15563 /** 15564 * Remove the tap detection timer. 15565 */ removeTapCallback()15566 private void removeTapCallback() { 15567 if (mPendingCheckForTap != null) { 15568 mPrivateFlags &= ~PFLAG_PREPRESSED; 15569 removeCallbacks(mPendingCheckForTap); 15570 } 15571 } 15572 15573 /** 15574 * Cancels a pending long press. Your subclass can use this if you 15575 * want the context menu to come up if the user presses and holds 15576 * at the same place, but you don't want it to come up if they press 15577 * and then move around enough to cause scrolling. 15578 */ cancelLongPress()15579 public void cancelLongPress() { 15580 removeLongPressCallback(); 15581 15582 /* 15583 * The prepressed state handled by the tap callback is a display 15584 * construct, but the tap callback will post a long press callback 15585 * less its own timeout. Remove it here. 15586 */ 15587 removeTapCallback(); 15588 } 15589 15590 /** 15591 * Sets the TouchDelegate for this View. 15592 */ setTouchDelegate(TouchDelegate delegate)15593 public void setTouchDelegate(TouchDelegate delegate) { 15594 mTouchDelegate = delegate; 15595 } 15596 15597 /** 15598 * Gets the TouchDelegate for this View. 15599 */ getTouchDelegate()15600 public TouchDelegate getTouchDelegate() { 15601 return mTouchDelegate; 15602 } 15603 15604 /** 15605 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 15606 * 15607 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 15608 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 15609 * available. This method should only be called for touch events. 15610 * 15611 * <p class="note">This api is not intended for most applications. Buffered dispatch 15612 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 15613 * streams will not improve your input latency. Side effects include: increased latency, 15614 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 15615 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 15616 * you.</p> 15617 */ requestUnbufferedDispatch(MotionEvent event)15618 public final void requestUnbufferedDispatch(MotionEvent event) { 15619 final int action = event.getAction(); 15620 if (mAttachInfo == null 15621 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 15622 || !event.isTouchEvent()) { 15623 return; 15624 } 15625 mAttachInfo.mUnbufferedDispatchRequested = true; 15626 } 15627 hasSize()15628 private boolean hasSize() { 15629 return (mBottom > mTop) && (mRight > mLeft); 15630 } 15631 canTakeFocus()15632 private boolean canTakeFocus() { 15633 return ((mViewFlags & VISIBILITY_MASK) == VISIBLE) 15634 && ((mViewFlags & FOCUSABLE) == FOCUSABLE) 15635 && ((mViewFlags & ENABLED_MASK) == ENABLED) 15636 && (sCanFocusZeroSized || !isLayoutValid() || hasSize()); 15637 } 15638 15639 /** 15640 * Set flags controlling behavior of this view. 15641 * 15642 * @param flags Constant indicating the value which should be set 15643 * @param mask Constant indicating the bit range that should be changed 15644 */ 15645 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) setFlags(int flags, int mask)15646 void setFlags(int flags, int mask) { 15647 final boolean accessibilityEnabled = 15648 AccessibilityManager.getInstance(mContext).isEnabled(); 15649 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 15650 15651 int old = mViewFlags; 15652 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 15653 15654 int changed = mViewFlags ^ old; 15655 if (changed == 0) { 15656 return; 15657 } 15658 int privateFlags = mPrivateFlags; 15659 boolean shouldNotifyFocusableAvailable = false; 15660 15661 // If focusable is auto, update the FOCUSABLE bit. 15662 int focusableChangedByAuto = 0; 15663 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 15664 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 15665 // Heuristic only takes into account whether view is clickable. 15666 final int newFocus; 15667 if ((mViewFlags & CLICKABLE) != 0) { 15668 newFocus = FOCUSABLE; 15669 } else { 15670 newFocus = NOT_FOCUSABLE; 15671 } 15672 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 15673 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 15674 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 15675 } 15676 15677 /* Check if the FOCUSABLE bit has changed */ 15678 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 15679 if (((old & FOCUSABLE) == FOCUSABLE) 15680 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 15681 /* Give up focus if we are no longer focusable */ 15682 clearFocus(); 15683 if (mParent instanceof ViewGroup) { 15684 ((ViewGroup) mParent).clearFocusedInCluster(); 15685 } 15686 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 15687 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 15688 /* 15689 * Tell the view system that we are now available to take focus 15690 * if no one else already has it. 15691 */ 15692 if (mParent != null) { 15693 ViewRootImpl viewRootImpl = getViewRootImpl(); 15694 if (!sAutoFocusableOffUIThreadWontNotifyParents 15695 || focusableChangedByAuto == 0 15696 || viewRootImpl == null 15697 || viewRootImpl.mThread == Thread.currentThread()) { 15698 shouldNotifyFocusableAvailable = canTakeFocus(); 15699 } 15700 } 15701 } 15702 } 15703 15704 final int newVisibility = flags & VISIBILITY_MASK; 15705 if (newVisibility == VISIBLE) { 15706 if ((changed & VISIBILITY_MASK) != 0) { 15707 /* 15708 * If this view is becoming visible, invalidate it in case it changed while 15709 * it was not visible. Marking it drawn ensures that the invalidation will 15710 * go through. 15711 */ 15712 mPrivateFlags |= PFLAG_DRAWN; 15713 invalidate(true); 15714 15715 needGlobalAttributesUpdate(true); 15716 15717 // a view becoming visible is worth notifying the parent about in case nothing has 15718 // focus. Even if this specific view isn't focusable, it may contain something that 15719 // is, so let the root view try to give this focus if nothing else does. 15720 shouldNotifyFocusableAvailable = hasSize(); 15721 } 15722 } 15723 15724 if ((changed & ENABLED_MASK) != 0) { 15725 if ((mViewFlags & ENABLED_MASK) == ENABLED) { 15726 // a view becoming enabled should notify the parent as long as the view is also 15727 // visible and the parent wasn't already notified by becoming visible during this 15728 // setFlags invocation. 15729 shouldNotifyFocusableAvailable = canTakeFocus(); 15730 } else { 15731 if (isFocused()) clearFocus(); 15732 } 15733 } 15734 15735 if (shouldNotifyFocusableAvailable && mParent != null) { 15736 mParent.focusableViewAvailable(this); 15737 } 15738 15739 /* Check if the GONE bit has changed */ 15740 if ((changed & GONE) != 0) { 15741 needGlobalAttributesUpdate(false); 15742 requestLayout(); 15743 15744 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 15745 if (hasFocus()) { 15746 clearFocus(); 15747 if (mParent instanceof ViewGroup) { 15748 ((ViewGroup) mParent).clearFocusedInCluster(); 15749 } 15750 } 15751 clearAccessibilityFocus(); 15752 destroyDrawingCache(); 15753 if (mParent instanceof View) { 15754 // GONE views noop invalidation, so invalidate the parent 15755 ((View) mParent).invalidate(true); 15756 } 15757 // Mark the view drawn to ensure that it gets invalidated properly the next 15758 // time it is visible and gets invalidated 15759 mPrivateFlags |= PFLAG_DRAWN; 15760 } 15761 if (mAttachInfo != null) { 15762 mAttachInfo.mViewVisibilityChanged = true; 15763 } 15764 } 15765 15766 /* Check if the VISIBLE bit has changed */ 15767 if ((changed & INVISIBLE) != 0) { 15768 needGlobalAttributesUpdate(false); 15769 /* 15770 * If this view is becoming invisible, set the DRAWN flag so that 15771 * the next invalidate() will not be skipped. 15772 */ 15773 mPrivateFlags |= PFLAG_DRAWN; 15774 15775 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 15776 // root view becoming invisible shouldn't clear focus and accessibility focus 15777 if (getRootView() != this) { 15778 if (hasFocus()) { 15779 clearFocus(); 15780 if (mParent instanceof ViewGroup) { 15781 ((ViewGroup) mParent).clearFocusedInCluster(); 15782 } 15783 } 15784 clearAccessibilityFocus(); 15785 } 15786 } 15787 if (mAttachInfo != null) { 15788 mAttachInfo.mViewVisibilityChanged = true; 15789 } 15790 } 15791 15792 if ((changed & VISIBILITY_MASK) != 0) { 15793 // If the view is invisible, cleanup its display list to free up resources 15794 if (newVisibility != VISIBLE && mAttachInfo != null) { 15795 cleanupDraw(); 15796 } 15797 15798 if (mParent instanceof ViewGroup) { 15799 ViewGroup parent = (ViewGroup) mParent; 15800 parent.onChildVisibilityChanged(this, (changed & VISIBILITY_MASK), 15801 newVisibility); 15802 parent.invalidate(true); 15803 } else if (mParent != null) { 15804 mParent.invalidateChild(this, null); 15805 } 15806 15807 if (mAttachInfo != null) { 15808 dispatchVisibilityChanged(this, newVisibility); 15809 15810 // Aggregated visibility changes are dispatched to attached views 15811 // in visible windows where the parent is currently shown/drawn 15812 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 15813 // discounting clipping or overlapping. This makes it a good place 15814 // to change animation states. 15815 if (mParent != null && getWindowVisibility() == VISIBLE && 15816 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 15817 dispatchVisibilityAggregated(newVisibility == VISIBLE); 15818 } 15819 notifySubtreeAccessibilityStateChangedIfNeeded(); 15820 } 15821 } 15822 15823 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 15824 destroyDrawingCache(); 15825 } 15826 15827 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 15828 destroyDrawingCache(); 15829 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 15830 invalidateParentCaches(); 15831 } 15832 15833 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 15834 destroyDrawingCache(); 15835 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 15836 } 15837 15838 if ((changed & DRAW_MASK) != 0) { 15839 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 15840 if (mBackground != null 15841 || mDefaultFocusHighlight != null 15842 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 15843 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 15844 } else { 15845 mPrivateFlags |= PFLAG_SKIP_DRAW; 15846 } 15847 } else { 15848 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 15849 } 15850 requestLayout(); 15851 invalidate(true); 15852 } 15853 15854 if ((changed & KEEP_SCREEN_ON) != 0) { 15855 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 15856 mParent.recomputeViewAttributes(this); 15857 } 15858 } 15859 15860 if (accessibilityEnabled) { 15861 // If we're an accessibility pane and the visibility changed, we already have sent 15862 // a state change, so we really don't need to report other changes. 15863 if (isAccessibilityPane()) { 15864 changed &= ~VISIBILITY_MASK; 15865 } 15866 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 15867 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 15868 || (changed & CONTEXT_CLICKABLE) != 0) { 15869 if (oldIncludeForAccessibility != includeForAccessibility()) { 15870 notifySubtreeAccessibilityStateChangedIfNeeded(); 15871 } else { 15872 notifyViewAccessibilityStateChangedIfNeeded( 15873 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 15874 } 15875 } else if ((changed & ENABLED_MASK) != 0) { 15876 notifyViewAccessibilityStateChangedIfNeeded( 15877 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 15878 } 15879 } 15880 } 15881 15882 /** 15883 * Change the view's z order in the tree, so it's on top of other sibling 15884 * views. This ordering change may affect layout, if the parent container 15885 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 15886 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 15887 * method should be followed by calls to {@link #requestLayout()} and 15888 * {@link View#invalidate()} on the view's parent to force the parent to redraw 15889 * with the new child ordering. 15890 * 15891 * @see ViewGroup#bringChildToFront(View) 15892 */ bringToFront()15893 public void bringToFront() { 15894 if (mParent != null) { 15895 mParent.bringChildToFront(this); 15896 } 15897 } 15898 15899 /** 15900 * This is called in response to an internal scroll in this view (i.e., the 15901 * view scrolled its own contents). This is typically as a result of 15902 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 15903 * called. 15904 * 15905 * @param l Current horizontal scroll origin. 15906 * @param t Current vertical scroll origin. 15907 * @param oldl Previous horizontal scroll origin. 15908 * @param oldt Previous vertical scroll origin. 15909 */ onScrollChanged(int l, int t, int oldl, int oldt)15910 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 15911 notifySubtreeAccessibilityStateChangedIfNeeded(); 15912 15913 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 15914 postSendViewScrolledAccessibilityEventCallback(l - oldl, t - oldt); 15915 } 15916 15917 mBackgroundSizeChanged = true; 15918 mDefaultFocusHighlightSizeChanged = true; 15919 if (mForegroundInfo != null) { 15920 mForegroundInfo.mBoundsChanged = true; 15921 } 15922 15923 final AttachInfo ai = mAttachInfo; 15924 if (ai != null) { 15925 ai.mViewScrollChanged = true; 15926 } 15927 15928 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 15929 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 15930 } 15931 } 15932 15933 /** 15934 * Interface definition for a callback to be invoked when the scroll 15935 * X or Y positions of a view change. 15936 * <p> 15937 * <b>Note:</b> Some views handle scrolling independently from View and may 15938 * have their own separate listeners for scroll-type events. For example, 15939 * {@link android.widget.ListView ListView} allows clients to register an 15940 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 15941 * to listen for changes in list scroll position. 15942 * 15943 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 15944 */ 15945 public interface OnScrollChangeListener { 15946 /** 15947 * Called when the scroll position of a view changes. 15948 * 15949 * @param v The view whose scroll position has changed. 15950 * @param scrollX Current horizontal scroll origin. 15951 * @param scrollY Current vertical scroll origin. 15952 * @param oldScrollX Previous horizontal scroll origin. 15953 * @param oldScrollY Previous vertical scroll origin. 15954 */ onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY)15955 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 15956 } 15957 15958 /** 15959 * Interface definition for a callback to be invoked when the layout bounds of a view 15960 * changes due to layout processing. 15961 */ 15962 public interface OnLayoutChangeListener { 15963 /** 15964 * Called when the layout bounds of a view changes due to layout processing. 15965 * 15966 * @param v The view whose bounds have changed. 15967 * @param left The new value of the view's left property. 15968 * @param top The new value of the view's top property. 15969 * @param right The new value of the view's right property. 15970 * @param bottom The new value of the view's bottom property. 15971 * @param oldLeft The previous value of the view's left property. 15972 * @param oldTop The previous value of the view's top property. 15973 * @param oldRight The previous value of the view's right property. 15974 * @param oldBottom The previous value of the view's bottom property. 15975 */ onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)15976 void onLayoutChange(View v, int left, int top, int right, int bottom, 15977 int oldLeft, int oldTop, int oldRight, int oldBottom); 15978 } 15979 15980 /** 15981 * This is called during layout when the size of this view has changed. If 15982 * you were just added to the view hierarchy, you're called with the old 15983 * values of 0. 15984 * 15985 * @param w Current width of this view. 15986 * @param h Current height of this view. 15987 * @param oldw Old width of this view. 15988 * @param oldh Old height of this view. 15989 */ onSizeChanged(int w, int h, int oldw, int oldh)15990 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 15991 } 15992 15993 /** 15994 * Called by draw to draw the child views. This may be overridden 15995 * by derived classes to gain control just before its children are drawn 15996 * (but after its own view has been drawn). 15997 * @param canvas the canvas on which to draw the view 15998 */ dispatchDraw(Canvas canvas)15999 protected void dispatchDraw(Canvas canvas) { 16000 16001 } 16002 16003 /** 16004 * Gets the parent of this view. Note that the parent is a 16005 * ViewParent and not necessarily a View. 16006 * 16007 * @return Parent of this view. 16008 */ getParent()16009 public final ViewParent getParent() { 16010 return mParent; 16011 } 16012 16013 /** 16014 * Set the horizontal scrolled position of your view. This will cause a call to 16015 * {@link #onScrollChanged(int, int, int, int)} and the view will be 16016 * invalidated. 16017 * @param value the x position to scroll to 16018 */ setScrollX(int value)16019 public void setScrollX(int value) { 16020 scrollTo(value, mScrollY); 16021 } 16022 16023 /** 16024 * Set the vertical scrolled position of your view. This will cause a call to 16025 * {@link #onScrollChanged(int, int, int, int)} and the view will be 16026 * invalidated. 16027 * @param value the y position to scroll to 16028 */ setScrollY(int value)16029 public void setScrollY(int value) { 16030 scrollTo(mScrollX, value); 16031 } 16032 16033 /** 16034 * Return the scrolled left position of this view. This is the left edge of 16035 * the displayed part of your view. You do not need to draw any pixels 16036 * farther left, since those are outside of the frame of your view on 16037 * screen. 16038 * 16039 * @return The left edge of the displayed part of your view, in pixels. 16040 */ 16041 @InspectableProperty getScrollX()16042 public final int getScrollX() { 16043 return mScrollX; 16044 } 16045 16046 /** 16047 * Return the scrolled top position of this view. This is the top edge of 16048 * the displayed part of your view. You do not need to draw any pixels above 16049 * it, since those are outside of the frame of your view on screen. 16050 * 16051 * @return The top edge of the displayed part of your view, in pixels. 16052 */ 16053 @InspectableProperty getScrollY()16054 public final int getScrollY() { 16055 return mScrollY; 16056 } 16057 16058 /** 16059 * Return the width of your view. 16060 * 16061 * @return The width of your view, in pixels. 16062 */ 16063 @ViewDebug.ExportedProperty(category = "layout") getWidth()16064 public final int getWidth() { 16065 return mRight - mLeft; 16066 } 16067 16068 /** 16069 * Return the height of your view. 16070 * 16071 * @return The height of your view, in pixels. 16072 */ 16073 @ViewDebug.ExportedProperty(category = "layout") getHeight()16074 public final int getHeight() { 16075 return mBottom - mTop; 16076 } 16077 16078 /** 16079 * Return the visible drawing bounds of your view. Fills in the output 16080 * rectangle with the values from getScrollX(), getScrollY(), 16081 * getWidth(), and getHeight(). These bounds do not account for any 16082 * transformation properties currently set on the view, such as 16083 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 16084 * 16085 * @param outRect The (scrolled) drawing bounds of the view. 16086 */ getDrawingRect(Rect outRect)16087 public void getDrawingRect(Rect outRect) { 16088 outRect.left = mScrollX; 16089 outRect.top = mScrollY; 16090 outRect.right = mScrollX + (mRight - mLeft); 16091 outRect.bottom = mScrollY + (mBottom - mTop); 16092 } 16093 16094 /** 16095 * Like {@link #getMeasuredWidthAndState()}, but only returns the 16096 * raw width component (that is the result is masked by 16097 * {@link #MEASURED_SIZE_MASK}). 16098 * 16099 * @return The raw measured width of this view. 16100 */ getMeasuredWidth()16101 public final int getMeasuredWidth() { 16102 return mMeasuredWidth & MEASURED_SIZE_MASK; 16103 } 16104 16105 /** 16106 * Return the full width measurement information for this view as computed 16107 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 16108 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 16109 * This should be used during measurement and layout calculations only. Use 16110 * {@link #getWidth()} to see how wide a view is after layout. 16111 * 16112 * @return The measured width of this view as a bit mask. 16113 */ 16114 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 16115 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 16116 name = "MEASURED_STATE_TOO_SMALL"), 16117 }) getMeasuredWidthAndState()16118 public final int getMeasuredWidthAndState() { 16119 return mMeasuredWidth; 16120 } 16121 16122 /** 16123 * Like {@link #getMeasuredHeightAndState()}, but only returns the 16124 * raw height component (that is the result is masked by 16125 * {@link #MEASURED_SIZE_MASK}). 16126 * 16127 * @return The raw measured height of this view. 16128 */ getMeasuredHeight()16129 public final int getMeasuredHeight() { 16130 return mMeasuredHeight & MEASURED_SIZE_MASK; 16131 } 16132 16133 /** 16134 * Return the full height measurement information for this view as computed 16135 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 16136 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 16137 * This should be used during measurement and layout calculations only. Use 16138 * {@link #getHeight()} to see how high a view is after layout. 16139 * 16140 * @return The measured height of this view as a bit mask. 16141 */ 16142 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 16143 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 16144 name = "MEASURED_STATE_TOO_SMALL"), 16145 }) getMeasuredHeightAndState()16146 public final int getMeasuredHeightAndState() { 16147 return mMeasuredHeight; 16148 } 16149 16150 /** 16151 * Return only the state bits of {@link #getMeasuredWidthAndState()} 16152 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 16153 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 16154 * and the height component is at the shifted bits 16155 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 16156 */ getMeasuredState()16157 public final int getMeasuredState() { 16158 return (mMeasuredWidth&MEASURED_STATE_MASK) 16159 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 16160 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 16161 } 16162 16163 /** 16164 * The transform matrix of this view, which is calculated based on the current 16165 * rotation, scale, and pivot properties. 16166 * 16167 * @see #getRotation() 16168 * @see #getScaleX() 16169 * @see #getScaleY() 16170 * @see #getPivotX() 16171 * @see #getPivotY() 16172 * @return The current transform matrix for the view 16173 */ getMatrix()16174 public Matrix getMatrix() { 16175 ensureTransformationInfo(); 16176 final Matrix matrix = mTransformationInfo.mMatrix; 16177 mRenderNode.getMatrix(matrix); 16178 return matrix; 16179 } 16180 16181 /** 16182 * Returns true if the transform matrix is the identity matrix. 16183 * Recomputes the matrix if necessary. 16184 * 16185 * @return True if the transform matrix is the identity matrix, false otherwise. 16186 * @hide 16187 */ 16188 @UnsupportedAppUsage hasIdentityMatrix()16189 public final boolean hasIdentityMatrix() { 16190 return mRenderNode.hasIdentityMatrix(); 16191 } 16192 16193 @UnsupportedAppUsage ensureTransformationInfo()16194 void ensureTransformationInfo() { 16195 if (mTransformationInfo == null) { 16196 mTransformationInfo = new TransformationInfo(); 16197 } 16198 } 16199 16200 /** 16201 * Utility method to retrieve the inverse of the current mMatrix property. 16202 * We cache the matrix to avoid recalculating it when transform properties 16203 * have not changed. 16204 * 16205 * @return The inverse of the current matrix of this view. 16206 * @hide 16207 */ 16208 @UnsupportedAppUsage getInverseMatrix()16209 public final Matrix getInverseMatrix() { 16210 ensureTransformationInfo(); 16211 if (mTransformationInfo.mInverseMatrix == null) { 16212 mTransformationInfo.mInverseMatrix = new Matrix(); 16213 } 16214 final Matrix matrix = mTransformationInfo.mInverseMatrix; 16215 mRenderNode.getInverseMatrix(matrix); 16216 return matrix; 16217 } 16218 16219 /** 16220 * Gets the distance along the Z axis from the camera to this view. 16221 * 16222 * @see #setCameraDistance(float) 16223 * 16224 * @return The distance along the Z axis. 16225 */ getCameraDistance()16226 public float getCameraDistance() { 16227 final float dpi = mResources.getDisplayMetrics().densityDpi; 16228 return mRenderNode.getCameraDistance() * dpi; 16229 } 16230 16231 /** 16232 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 16233 * views are drawn) from the camera to this view. The camera's distance 16234 * affects 3D transformations, for instance rotations around the X and Y 16235 * axis. If the rotationX or rotationY properties are changed and this view is 16236 * large (more than half the size of the screen), it is recommended to always 16237 * use a camera distance that's greater than the height (X axis rotation) or 16238 * the width (Y axis rotation) of this view.</p> 16239 * 16240 * <p>The distance of the camera from the view plane can have an affect on the 16241 * perspective distortion of the view when it is rotated around the x or y axis. 16242 * For example, a large distance will result in a large viewing angle, and there 16243 * will not be much perspective distortion of the view as it rotates. A short 16244 * distance may cause much more perspective distortion upon rotation, and can 16245 * also result in some drawing artifacts if the rotated view ends up partially 16246 * behind the camera (which is why the recommendation is to use a distance at 16247 * least as far as the size of the view, if the view is to be rotated.)</p> 16248 * 16249 * <p>The distance is expressed in "depth pixels." The default distance depends 16250 * on the screen density. For instance, on a medium density display, the 16251 * default distance is 1280. On a high density display, the default distance 16252 * is 1920.</p> 16253 * 16254 * <p>If you want to specify a distance that leads to visually consistent 16255 * results across various densities, use the following formula:</p> 16256 * <pre> 16257 * float scale = context.getResources().getDisplayMetrics().density; 16258 * view.setCameraDistance(distance * scale); 16259 * </pre> 16260 * 16261 * <p>The density scale factor of a high density display is 1.5, 16262 * and 1920 = 1280 * 1.5.</p> 16263 * 16264 * @param distance The distance in "depth pixels", if negative the opposite 16265 * value is used 16266 * 16267 * @see #setRotationX(float) 16268 * @see #setRotationY(float) 16269 */ setCameraDistance(float distance)16270 public void setCameraDistance(float distance) { 16271 final float dpi = mResources.getDisplayMetrics().densityDpi; 16272 16273 invalidateViewProperty(true, false); 16274 mRenderNode.setCameraDistance(Math.abs(distance) / dpi); 16275 invalidateViewProperty(false, false); 16276 16277 invalidateParentIfNeededAndWasQuickRejected(); 16278 } 16279 16280 /** 16281 * The degrees that the view is rotated around the pivot point. 16282 * 16283 * @see #setRotation(float) 16284 * @see #getPivotX() 16285 * @see #getPivotY() 16286 * 16287 * @return The degrees of rotation. 16288 */ 16289 @ViewDebug.ExportedProperty(category = "drawing") 16290 @InspectableProperty getRotation()16291 public float getRotation() { 16292 return mRenderNode.getRotationZ(); 16293 } 16294 16295 /** 16296 * Sets the degrees that the view is rotated around the pivot point. Increasing values 16297 * result in clockwise rotation. 16298 * 16299 * @param rotation The degrees of rotation. 16300 * 16301 * @see #getRotation() 16302 * @see #getPivotX() 16303 * @see #getPivotY() 16304 * @see #setRotationX(float) 16305 * @see #setRotationY(float) 16306 * 16307 * @attr ref android.R.styleable#View_rotation 16308 */ setRotation(float rotation)16309 public void setRotation(float rotation) { 16310 if (rotation != getRotation()) { 16311 // Double-invalidation is necessary to capture view's old and new areas 16312 invalidateViewProperty(true, false); 16313 mRenderNode.setRotationZ(rotation); 16314 invalidateViewProperty(false, true); 16315 16316 invalidateParentIfNeededAndWasQuickRejected(); 16317 notifySubtreeAccessibilityStateChangedIfNeeded(); 16318 } 16319 } 16320 16321 /** 16322 * The degrees that the view is rotated around the vertical axis through the pivot point. 16323 * 16324 * @see #getPivotX() 16325 * @see #getPivotY() 16326 * @see #setRotationY(float) 16327 * 16328 * @return The degrees of Y rotation. 16329 */ 16330 @ViewDebug.ExportedProperty(category = "drawing") 16331 @InspectableProperty getRotationY()16332 public float getRotationY() { 16333 return mRenderNode.getRotationY(); 16334 } 16335 16336 /** 16337 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 16338 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 16339 * down the y axis. 16340 * 16341 * When rotating large views, it is recommended to adjust the camera distance 16342 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 16343 * 16344 * @param rotationY The degrees of Y rotation. 16345 * 16346 * @see #getRotationY() 16347 * @see #getPivotX() 16348 * @see #getPivotY() 16349 * @see #setRotation(float) 16350 * @see #setRotationX(float) 16351 * @see #setCameraDistance(float) 16352 * 16353 * @attr ref android.R.styleable#View_rotationY 16354 */ setRotationY(float rotationY)16355 public void setRotationY(float rotationY) { 16356 if (rotationY != getRotationY()) { 16357 invalidateViewProperty(true, false); 16358 mRenderNode.setRotationY(rotationY); 16359 invalidateViewProperty(false, true); 16360 16361 invalidateParentIfNeededAndWasQuickRejected(); 16362 notifySubtreeAccessibilityStateChangedIfNeeded(); 16363 } 16364 } 16365 16366 /** 16367 * The degrees that the view is rotated around the horizontal axis through the pivot point. 16368 * 16369 * @see #getPivotX() 16370 * @see #getPivotY() 16371 * @see #setRotationX(float) 16372 * 16373 * @return The degrees of X rotation. 16374 */ 16375 @ViewDebug.ExportedProperty(category = "drawing") 16376 @InspectableProperty getRotationX()16377 public float getRotationX() { 16378 return mRenderNode.getRotationX(); 16379 } 16380 16381 /** 16382 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 16383 * Increasing values result in clockwise rotation from the viewpoint of looking down the 16384 * x axis. 16385 * 16386 * When rotating large views, it is recommended to adjust the camera distance 16387 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 16388 * 16389 * @param rotationX The degrees of X rotation. 16390 * 16391 * @see #getRotationX() 16392 * @see #getPivotX() 16393 * @see #getPivotY() 16394 * @see #setRotation(float) 16395 * @see #setRotationY(float) 16396 * @see #setCameraDistance(float) 16397 * 16398 * @attr ref android.R.styleable#View_rotationX 16399 */ setRotationX(float rotationX)16400 public void setRotationX(float rotationX) { 16401 if (rotationX != getRotationX()) { 16402 invalidateViewProperty(true, false); 16403 mRenderNode.setRotationX(rotationX); 16404 invalidateViewProperty(false, true); 16405 16406 invalidateParentIfNeededAndWasQuickRejected(); 16407 notifySubtreeAccessibilityStateChangedIfNeeded(); 16408 } 16409 } 16410 16411 /** 16412 * The amount that the view is scaled in x around the pivot point, as a proportion of 16413 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 16414 * 16415 * <p>By default, this is 1.0f. 16416 * 16417 * @see #getPivotX() 16418 * @see #getPivotY() 16419 * @return The scaling factor. 16420 */ 16421 @ViewDebug.ExportedProperty(category = "drawing") 16422 @InspectableProperty getScaleX()16423 public float getScaleX() { 16424 return mRenderNode.getScaleX(); 16425 } 16426 16427 /** 16428 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 16429 * the view's unscaled width. A value of 1 means that no scaling is applied. 16430 * 16431 * @param scaleX The scaling factor. 16432 * @see #getPivotX() 16433 * @see #getPivotY() 16434 * 16435 * @attr ref android.R.styleable#View_scaleX 16436 */ setScaleX(float scaleX)16437 public void setScaleX(float scaleX) { 16438 if (scaleX != getScaleX()) { 16439 scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX"); 16440 invalidateViewProperty(true, false); 16441 mRenderNode.setScaleX(scaleX); 16442 invalidateViewProperty(false, true); 16443 16444 invalidateParentIfNeededAndWasQuickRejected(); 16445 notifySubtreeAccessibilityStateChangedIfNeeded(); 16446 } 16447 } 16448 16449 /** 16450 * The amount that the view is scaled in y around the pivot point, as a proportion of 16451 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 16452 * 16453 * <p>By default, this is 1.0f. 16454 * 16455 * @see #getPivotX() 16456 * @see #getPivotY() 16457 * @return The scaling factor. 16458 */ 16459 @ViewDebug.ExportedProperty(category = "drawing") 16460 @InspectableProperty getScaleY()16461 public float getScaleY() { 16462 return mRenderNode.getScaleY(); 16463 } 16464 16465 /** 16466 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 16467 * the view's unscaled width. A value of 1 means that no scaling is applied. 16468 * 16469 * @param scaleY The scaling factor. 16470 * @see #getPivotX() 16471 * @see #getPivotY() 16472 * 16473 * @attr ref android.R.styleable#View_scaleY 16474 */ setScaleY(float scaleY)16475 public void setScaleY(float scaleY) { 16476 if (scaleY != getScaleY()) { 16477 scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY"); 16478 invalidateViewProperty(true, false); 16479 mRenderNode.setScaleY(scaleY); 16480 invalidateViewProperty(false, true); 16481 16482 invalidateParentIfNeededAndWasQuickRejected(); 16483 notifySubtreeAccessibilityStateChangedIfNeeded(); 16484 } 16485 } 16486 16487 /** 16488 * The x location of the point around which the view is {@link #setRotation(float) rotated} 16489 * and {@link #setScaleX(float) scaled}. 16490 * 16491 * @see #getRotation() 16492 * @see #getScaleX() 16493 * @see #getScaleY() 16494 * @see #getPivotY() 16495 * @return The x location of the pivot point. 16496 * 16497 * @attr ref android.R.styleable#View_transformPivotX 16498 */ 16499 @ViewDebug.ExportedProperty(category = "drawing") 16500 @InspectableProperty(name = "transformPivotX") getPivotX()16501 public float getPivotX() { 16502 return mRenderNode.getPivotX(); 16503 } 16504 16505 /** 16506 * Sets the x location of the point around which the view is 16507 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 16508 * By default, the pivot point is centered on the object. 16509 * Setting this property disables this behavior and causes the view to use only the 16510 * explicitly set pivotX and pivotY values. 16511 * 16512 * @param pivotX The x location of the pivot point. 16513 * @see #getRotation() 16514 * @see #getScaleX() 16515 * @see #getScaleY() 16516 * @see #getPivotY() 16517 * 16518 * @attr ref android.R.styleable#View_transformPivotX 16519 */ setPivotX(float pivotX)16520 public void setPivotX(float pivotX) { 16521 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 16522 invalidateViewProperty(true, false); 16523 mRenderNode.setPivotX(pivotX); 16524 invalidateViewProperty(false, true); 16525 16526 invalidateParentIfNeededAndWasQuickRejected(); 16527 } 16528 } 16529 16530 /** 16531 * The y location of the point around which the view is {@link #setRotation(float) rotated} 16532 * and {@link #setScaleY(float) scaled}. 16533 * 16534 * @see #getRotation() 16535 * @see #getScaleX() 16536 * @see #getScaleY() 16537 * @see #getPivotY() 16538 * @return The y location of the pivot point. 16539 * 16540 * @attr ref android.R.styleable#View_transformPivotY 16541 */ 16542 @ViewDebug.ExportedProperty(category = "drawing") 16543 @InspectableProperty(name = "transformPivotY") getPivotY()16544 public float getPivotY() { 16545 return mRenderNode.getPivotY(); 16546 } 16547 16548 /** 16549 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 16550 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 16551 * Setting this property disables this behavior and causes the view to use only the 16552 * explicitly set pivotX and pivotY values. 16553 * 16554 * @param pivotY The y location of the pivot point. 16555 * @see #getRotation() 16556 * @see #getScaleX() 16557 * @see #getScaleY() 16558 * @see #getPivotY() 16559 * 16560 * @attr ref android.R.styleable#View_transformPivotY 16561 */ setPivotY(float pivotY)16562 public void setPivotY(float pivotY) { 16563 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 16564 invalidateViewProperty(true, false); 16565 mRenderNode.setPivotY(pivotY); 16566 invalidateViewProperty(false, true); 16567 16568 invalidateParentIfNeededAndWasQuickRejected(); 16569 } 16570 } 16571 16572 /** 16573 * Returns whether or not a pivot has been set by a call to {@link #setPivotX(float)} or 16574 * {@link #setPivotY(float)}. If no pivot has been set then the pivot will be the center 16575 * of the view. 16576 * 16577 * @return True if a pivot has been set, false if the default pivot is being used 16578 */ isPivotSet()16579 public boolean isPivotSet() { 16580 return mRenderNode.isPivotExplicitlySet(); 16581 } 16582 16583 /** 16584 * Clears any pivot previously set by a call to {@link #setPivotX(float)} or 16585 * {@link #setPivotY(float)}. After calling this {@link #isPivotSet()} will be false 16586 * and the pivot used for rotation will return to default of being centered on the view. 16587 */ resetPivot()16588 public void resetPivot() { 16589 if (mRenderNode.resetPivot()) { 16590 invalidateViewProperty(false, false); 16591 } 16592 } 16593 16594 /** 16595 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 16596 * completely transparent and 1 means the view is completely opaque. 16597 * 16598 * <p>By default this is 1.0f. 16599 * @return The opacity of the view. 16600 */ 16601 @ViewDebug.ExportedProperty(category = "drawing") 16602 @InspectableProperty getAlpha()16603 public float getAlpha() { 16604 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 16605 } 16606 16607 /** 16608 * Sets the behavior for overlapping rendering for this view (see {@link 16609 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 16610 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 16611 * providing the value which is then used internally. That is, when {@link 16612 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 16613 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 16614 * instead. 16615 * 16616 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 16617 * instead of that returned by {@link #hasOverlappingRendering()}. 16618 * 16619 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 16620 */ forceHasOverlappingRendering(boolean hasOverlappingRendering)16621 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 16622 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 16623 if (hasOverlappingRendering) { 16624 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 16625 } else { 16626 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 16627 } 16628 } 16629 16630 /** 16631 * Returns the value for overlapping rendering that is used internally. This is either 16632 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 16633 * the return value of {@link #hasOverlappingRendering()}, otherwise. 16634 * 16635 * @return The value for overlapping rendering being used internally. 16636 */ getHasOverlappingRendering()16637 public final boolean getHasOverlappingRendering() { 16638 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 16639 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 16640 hasOverlappingRendering(); 16641 } 16642 16643 /** 16644 * Returns whether this View has content which overlaps. 16645 * 16646 * <p>This function, intended to be overridden by specific View types, is an optimization when 16647 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 16648 * an offscreen buffer and then composited into place, which can be expensive. If the view has 16649 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 16650 * directly. An example of overlapping rendering is a TextView with a background image, such as 16651 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 16652 * ImageView with only the foreground image. The default implementation returns true; subclasses 16653 * should override if they have cases which can be optimized.</p> 16654 * 16655 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 16656 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 16657 * 16658 * @return true if the content in this view might overlap, false otherwise. 16659 */ 16660 @ViewDebug.ExportedProperty(category = "drawing") hasOverlappingRendering()16661 public boolean hasOverlappingRendering() { 16662 return true; 16663 } 16664 16665 /** 16666 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 16667 * completely transparent and 1 means the view is completely opaque. 16668 * 16669 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 16670 * can have significant performance implications, especially for large views. It is best to use 16671 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 16672 * 16673 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 16674 * strongly recommended for performance reasons to either override 16675 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 16676 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 16677 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 16678 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 16679 * of rendering cost, even for simple or small views. Starting with 16680 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 16681 * applied to the view at the rendering level.</p> 16682 * 16683 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 16684 * responsible for applying the opacity itself.</p> 16685 * 16686 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 16687 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 16688 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 16689 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 16690 * 16691 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 16692 * value will clip a View to its bounds, unless the View returns <code>false</code> from 16693 * {@link #hasOverlappingRendering}.</p> 16694 * 16695 * @param alpha The opacity of the view. 16696 * 16697 * @see #hasOverlappingRendering() 16698 * @see #setLayerType(int, android.graphics.Paint) 16699 * 16700 * @attr ref android.R.styleable#View_alpha 16701 */ setAlpha(@loatRangefrom=0.0, to=1.0) float alpha)16702 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 16703 ensureTransformationInfo(); 16704 if (mTransformationInfo.mAlpha != alpha) { 16705 setAlphaInternal(alpha); 16706 if (onSetAlpha((int) (alpha * 255))) { 16707 mPrivateFlags |= PFLAG_ALPHA_SET; 16708 // subclass is handling alpha - don't optimize rendering cache invalidation 16709 invalidateParentCaches(); 16710 invalidate(true); 16711 } else { 16712 mPrivateFlags &= ~PFLAG_ALPHA_SET; 16713 invalidateViewProperty(true, false); 16714 mRenderNode.setAlpha(getFinalAlpha()); 16715 } 16716 } 16717 } 16718 16719 /** 16720 * Faster version of setAlpha() which performs the same steps except there are 16721 * no calls to invalidate(). The caller of this function should perform proper invalidation 16722 * on the parent and this object. The return value indicates whether the subclass handles 16723 * alpha (the return value for onSetAlpha()). 16724 * 16725 * @param alpha The new value for the alpha property 16726 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 16727 * the new value for the alpha property is different from the old value 16728 */ 16729 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768435) setAlphaNoInvalidation(float alpha)16730 boolean setAlphaNoInvalidation(float alpha) { 16731 ensureTransformationInfo(); 16732 if (mTransformationInfo.mAlpha != alpha) { 16733 setAlphaInternal(alpha); 16734 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 16735 if (subclassHandlesAlpha) { 16736 mPrivateFlags |= PFLAG_ALPHA_SET; 16737 return true; 16738 } else { 16739 mPrivateFlags &= ~PFLAG_ALPHA_SET; 16740 mRenderNode.setAlpha(getFinalAlpha()); 16741 } 16742 } 16743 return false; 16744 } 16745 setAlphaInternal(float alpha)16746 void setAlphaInternal(float alpha) { 16747 float oldAlpha = mTransformationInfo.mAlpha; 16748 mTransformationInfo.mAlpha = alpha; 16749 // Report visibility changes, which can affect children, to accessibility 16750 if ((alpha == 0) ^ (oldAlpha == 0)) { 16751 notifySubtreeAccessibilityStateChangedIfNeeded(); 16752 } 16753 } 16754 16755 /** 16756 * This property is intended only for use by the Fade transition, which animates it 16757 * to produce a visual translucency that does not side-effect (or get affected by) 16758 * the real alpha property. This value is composited with the other alpha value 16759 * (and the AlphaAnimation value, when that is present) to produce a final visual 16760 * translucency result, which is what is passed into the DisplayList. 16761 */ setTransitionAlpha(float alpha)16762 public void setTransitionAlpha(float alpha) { 16763 ensureTransformationInfo(); 16764 if (mTransformationInfo.mTransitionAlpha != alpha) { 16765 mTransformationInfo.mTransitionAlpha = alpha; 16766 mPrivateFlags &= ~PFLAG_ALPHA_SET; 16767 invalidateViewProperty(true, false); 16768 mRenderNode.setAlpha(getFinalAlpha()); 16769 } 16770 } 16771 16772 /** 16773 * Calculates the visual alpha of this view, which is a combination of the actual 16774 * alpha value and the transitionAlpha value (if set). 16775 */ getFinalAlpha()16776 private float getFinalAlpha() { 16777 if (mTransformationInfo != null) { 16778 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 16779 } 16780 return 1; 16781 } 16782 16783 /** 16784 * This property is intended only for use by the Fade transition, which animates 16785 * it to produce a visual translucency that does not side-effect (or get affected 16786 * by) the real alpha property. This value is composited with the other alpha 16787 * value (and the AlphaAnimation value, when that is present) to produce a final 16788 * visual translucency result, which is what is passed into the DisplayList. 16789 */ 16790 @ViewDebug.ExportedProperty(category = "drawing") getTransitionAlpha()16791 public float getTransitionAlpha() { 16792 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 16793 } 16794 16795 /** 16796 * Sets whether or not to allow force dark to apply to this view. 16797 * 16798 * Setting this to false will disable the auto-dark feature on everything this view 16799 * draws, including any descendants. 16800 * 16801 * Setting this to true will allow this view to be automatically made dark, however 16802 * a value of 'true' will not override any 'false' value in its parent chain nor will 16803 * it prevent any 'false' in any of its children. 16804 * 16805 * The default behavior of force dark is also influenced by the Theme's 16806 * {@link android.R.styleable#Theme_isLightTheme isLightTheme} attribute. 16807 * If a theme is isLightTheme="false", then force dark is globally disabled for that theme. 16808 * 16809 * @param allow Whether or not to allow force dark. 16810 */ setForceDarkAllowed(boolean allow)16811 public void setForceDarkAllowed(boolean allow) { 16812 if (mRenderNode.setForceDarkAllowed(allow)) { 16813 // Currently toggling force-dark requires a new display list push to apply 16814 // TODO: Make it not clobber the display list so this is just a damageSelf() instead 16815 invalidate(); 16816 } 16817 } 16818 16819 /** 16820 * See {@link #setForceDarkAllowed(boolean)} 16821 * 16822 * @return true if force dark is allowed (default), false if it is disabled 16823 */ 16824 @ViewDebug.ExportedProperty(category = "drawing") 16825 @InspectableProperty isForceDarkAllowed()16826 public boolean isForceDarkAllowed() { 16827 return mRenderNode.isForceDarkAllowed(); 16828 } 16829 16830 /** 16831 * Top position of this view relative to its parent. 16832 * 16833 * @return The top of this view, in pixels. 16834 */ 16835 @ViewDebug.CapturedViewProperty getTop()16836 public final int getTop() { 16837 return mTop; 16838 } 16839 16840 /** 16841 * Sets the top position of this view relative to its parent. This method is meant to be called 16842 * by the layout system and should not generally be called otherwise, because the property 16843 * may be changed at any time by the layout. 16844 * 16845 * @param top The top of this view, in pixels. 16846 */ setTop(int top)16847 public final void setTop(int top) { 16848 if (top != mTop) { 16849 final boolean matrixIsIdentity = hasIdentityMatrix(); 16850 if (matrixIsIdentity) { 16851 if (mAttachInfo != null) { 16852 int minTop; 16853 int yLoc; 16854 if (top < mTop) { 16855 minTop = top; 16856 yLoc = top - mTop; 16857 } else { 16858 minTop = mTop; 16859 yLoc = 0; 16860 } 16861 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 16862 } 16863 } else { 16864 // Double-invalidation is necessary to capture view's old and new areas 16865 invalidate(true); 16866 } 16867 16868 int width = mRight - mLeft; 16869 int oldHeight = mBottom - mTop; 16870 16871 mTop = top; 16872 mRenderNode.setTop(mTop); 16873 16874 sizeChange(width, mBottom - mTop, width, oldHeight); 16875 16876 if (!matrixIsIdentity) { 16877 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 16878 invalidate(true); 16879 } 16880 mBackgroundSizeChanged = true; 16881 mDefaultFocusHighlightSizeChanged = true; 16882 if (mForegroundInfo != null) { 16883 mForegroundInfo.mBoundsChanged = true; 16884 } 16885 invalidateParentIfNeeded(); 16886 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 16887 // View was rejected last time it was drawn by its parent; this may have changed 16888 invalidateParentIfNeeded(); 16889 } 16890 } 16891 } 16892 16893 /** 16894 * Bottom position of this view relative to its parent. 16895 * 16896 * @return The bottom of this view, in pixels. 16897 */ 16898 @ViewDebug.CapturedViewProperty getBottom()16899 public final int getBottom() { 16900 return mBottom; 16901 } 16902 16903 /** 16904 * True if this view has changed since the last time being drawn. 16905 * 16906 * @return The dirty state of this view. 16907 */ isDirty()16908 public boolean isDirty() { 16909 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 16910 } 16911 16912 /** 16913 * Sets the bottom position of this view relative to its parent. This method is meant to be 16914 * called by the layout system and should not generally be called otherwise, because the 16915 * property may be changed at any time by the layout. 16916 * 16917 * @param bottom The bottom of this view, in pixels. 16918 */ setBottom(int bottom)16919 public final void setBottom(int bottom) { 16920 if (bottom != mBottom) { 16921 final boolean matrixIsIdentity = hasIdentityMatrix(); 16922 if (matrixIsIdentity) { 16923 if (mAttachInfo != null) { 16924 int maxBottom; 16925 if (bottom < mBottom) { 16926 maxBottom = mBottom; 16927 } else { 16928 maxBottom = bottom; 16929 } 16930 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 16931 } 16932 } else { 16933 // Double-invalidation is necessary to capture view's old and new areas 16934 invalidate(true); 16935 } 16936 16937 int width = mRight - mLeft; 16938 int oldHeight = mBottom - mTop; 16939 16940 mBottom = bottom; 16941 mRenderNode.setBottom(mBottom); 16942 16943 sizeChange(width, mBottom - mTop, width, oldHeight); 16944 16945 if (!matrixIsIdentity) { 16946 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 16947 invalidate(true); 16948 } 16949 mBackgroundSizeChanged = true; 16950 mDefaultFocusHighlightSizeChanged = true; 16951 if (mForegroundInfo != null) { 16952 mForegroundInfo.mBoundsChanged = true; 16953 } 16954 invalidateParentIfNeeded(); 16955 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 16956 // View was rejected last time it was drawn by its parent; this may have changed 16957 invalidateParentIfNeeded(); 16958 } 16959 } 16960 } 16961 16962 /** 16963 * Left position of this view relative to its parent. 16964 * 16965 * @return The left edge of this view, in pixels. 16966 */ 16967 @ViewDebug.CapturedViewProperty getLeft()16968 public final int getLeft() { 16969 return mLeft; 16970 } 16971 16972 /** 16973 * Sets the left position of this view relative to its parent. This method is meant to be called 16974 * by the layout system and should not generally be called otherwise, because the property 16975 * may be changed at any time by the layout. 16976 * 16977 * @param left The left of this view, in pixels. 16978 */ setLeft(int left)16979 public final void setLeft(int left) { 16980 if (left != mLeft) { 16981 final boolean matrixIsIdentity = hasIdentityMatrix(); 16982 if (matrixIsIdentity) { 16983 if (mAttachInfo != null) { 16984 int minLeft; 16985 int xLoc; 16986 if (left < mLeft) { 16987 minLeft = left; 16988 xLoc = left - mLeft; 16989 } else { 16990 minLeft = mLeft; 16991 xLoc = 0; 16992 } 16993 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 16994 } 16995 } else { 16996 // Double-invalidation is necessary to capture view's old and new areas 16997 invalidate(true); 16998 } 16999 17000 int oldWidth = mRight - mLeft; 17001 int height = mBottom - mTop; 17002 17003 mLeft = left; 17004 mRenderNode.setLeft(left); 17005 17006 sizeChange(mRight - mLeft, height, oldWidth, height); 17007 17008 if (!matrixIsIdentity) { 17009 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 17010 invalidate(true); 17011 } 17012 mBackgroundSizeChanged = true; 17013 mDefaultFocusHighlightSizeChanged = true; 17014 if (mForegroundInfo != null) { 17015 mForegroundInfo.mBoundsChanged = true; 17016 } 17017 invalidateParentIfNeeded(); 17018 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 17019 // View was rejected last time it was drawn by its parent; this may have changed 17020 invalidateParentIfNeeded(); 17021 } 17022 } 17023 } 17024 17025 /** 17026 * Right position of this view relative to its parent. 17027 * 17028 * @return The right edge of this view, in pixels. 17029 */ 17030 @ViewDebug.CapturedViewProperty getRight()17031 public final int getRight() { 17032 return mRight; 17033 } 17034 17035 /** 17036 * Sets the right position of this view relative to its parent. This method is meant to be called 17037 * by the layout system and should not generally be called otherwise, because the property 17038 * may be changed at any time by the layout. 17039 * 17040 * @param right The right of this view, in pixels. 17041 */ setRight(int right)17042 public final void setRight(int right) { 17043 if (right != mRight) { 17044 final boolean matrixIsIdentity = hasIdentityMatrix(); 17045 if (matrixIsIdentity) { 17046 if (mAttachInfo != null) { 17047 int maxRight; 17048 if (right < mRight) { 17049 maxRight = mRight; 17050 } else { 17051 maxRight = right; 17052 } 17053 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 17054 } 17055 } else { 17056 // Double-invalidation is necessary to capture view's old and new areas 17057 invalidate(true); 17058 } 17059 17060 int oldWidth = mRight - mLeft; 17061 int height = mBottom - mTop; 17062 17063 mRight = right; 17064 mRenderNode.setRight(mRight); 17065 17066 sizeChange(mRight - mLeft, height, oldWidth, height); 17067 17068 if (!matrixIsIdentity) { 17069 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 17070 invalidate(true); 17071 } 17072 mBackgroundSizeChanged = true; 17073 mDefaultFocusHighlightSizeChanged = true; 17074 if (mForegroundInfo != null) { 17075 mForegroundInfo.mBoundsChanged = true; 17076 } 17077 invalidateParentIfNeeded(); 17078 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { 17079 // View was rejected last time it was drawn by its parent; this may have changed 17080 invalidateParentIfNeeded(); 17081 } 17082 } 17083 } 17084 sanitizeFloatPropertyValue(float value, String propertyName)17085 private static float sanitizeFloatPropertyValue(float value, String propertyName) { 17086 return sanitizeFloatPropertyValue(value, propertyName, -Float.MAX_VALUE, Float.MAX_VALUE); 17087 } 17088 sanitizeFloatPropertyValue(float value, String propertyName, float min, float max)17089 private static float sanitizeFloatPropertyValue(float value, String propertyName, 17090 float min, float max) { 17091 // The expected "nothing bad happened" path 17092 if (value >= min && value <= max) return value; 17093 17094 if (value < min || value == Float.NEGATIVE_INFINITY) { 17095 if (sThrowOnInvalidFloatProperties) { 17096 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 17097 + value + ", the value must be >= " + min); 17098 } 17099 return min; 17100 } 17101 17102 if (value > max || value == Float.POSITIVE_INFINITY) { 17103 if (sThrowOnInvalidFloatProperties) { 17104 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 17105 + value + ", the value must be <= " + max); 17106 } 17107 return max; 17108 } 17109 17110 if (Float.isNaN(value)) { 17111 if (sThrowOnInvalidFloatProperties) { 17112 throw new IllegalArgumentException( 17113 "Cannot set '" + propertyName + "' to Float.NaN"); 17114 } 17115 return 0; // Unclear which direction this NaN went so... 0? 17116 } 17117 17118 // Shouldn't be possible to reach this. 17119 throw new IllegalStateException("How do you get here?? " + value); 17120 } 17121 17122 /** 17123 * The visual x position of this view, in pixels. This is equivalent to the 17124 * {@link #setTranslationX(float) translationX} property plus the current 17125 * {@link #getLeft() left} property. 17126 * 17127 * @return The visual x position of this view, in pixels. 17128 */ 17129 @ViewDebug.ExportedProperty(category = "drawing") getX()17130 public float getX() { 17131 return mLeft + getTranslationX(); 17132 } 17133 17134 /** 17135 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 17136 * {@link #setTranslationX(float) translationX} property to be the difference between 17137 * the x value passed in and the current {@link #getLeft() left} property. 17138 * 17139 * @param x The visual x position of this view, in pixels. 17140 */ setX(float x)17141 public void setX(float x) { 17142 setTranslationX(x - mLeft); 17143 } 17144 17145 /** 17146 * The visual y position of this view, in pixels. This is equivalent to the 17147 * {@link #setTranslationY(float) translationY} property plus the current 17148 * {@link #getTop() top} property. 17149 * 17150 * @return The visual y position of this view, in pixels. 17151 */ 17152 @ViewDebug.ExportedProperty(category = "drawing") getY()17153 public float getY() { 17154 return mTop + getTranslationY(); 17155 } 17156 17157 /** 17158 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 17159 * {@link #setTranslationY(float) translationY} property to be the difference between 17160 * the y value passed in and the current {@link #getTop() top} property. 17161 * 17162 * @param y The visual y position of this view, in pixels. 17163 */ setY(float y)17164 public void setY(float y) { 17165 setTranslationY(y - mTop); 17166 } 17167 17168 /** 17169 * The visual z position of this view, in pixels. This is equivalent to the 17170 * {@link #setTranslationZ(float) translationZ} property plus the current 17171 * {@link #getElevation() elevation} property. 17172 * 17173 * @return The visual z position of this view, in pixels. 17174 */ 17175 @ViewDebug.ExportedProperty(category = "drawing") getZ()17176 public float getZ() { 17177 return getElevation() + getTranslationZ(); 17178 } 17179 17180 /** 17181 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 17182 * {@link #setTranslationZ(float) translationZ} property to be the difference between 17183 * the z value passed in and the current {@link #getElevation() elevation} property. 17184 * 17185 * @param z The visual z position of this view, in pixels. 17186 */ setZ(float z)17187 public void setZ(float z) { 17188 setTranslationZ(z - getElevation()); 17189 } 17190 17191 /** 17192 * The base elevation of this view relative to its parent, in pixels. 17193 * 17194 * @return The base depth position of the view, in pixels. 17195 */ 17196 @ViewDebug.ExportedProperty(category = "drawing") 17197 @InspectableProperty getElevation()17198 public float getElevation() { 17199 return mRenderNode.getElevation(); 17200 } 17201 17202 /** 17203 * Sets the base elevation of this view, in pixels. 17204 * 17205 * @attr ref android.R.styleable#View_elevation 17206 */ setElevation(float elevation)17207 public void setElevation(float elevation) { 17208 if (elevation != getElevation()) { 17209 elevation = sanitizeFloatPropertyValue(elevation, "elevation"); 17210 invalidateViewProperty(true, false); 17211 mRenderNode.setElevation(elevation); 17212 invalidateViewProperty(false, true); 17213 17214 invalidateParentIfNeededAndWasQuickRejected(); 17215 } 17216 } 17217 17218 /** 17219 * The horizontal location of this view relative to its {@link #getLeft() left} position. 17220 * This position is post-layout, in addition to wherever the object's 17221 * layout placed it. 17222 * 17223 * @return The horizontal position of this view relative to its left position, in pixels. 17224 */ 17225 @ViewDebug.ExportedProperty(category = "drawing") 17226 @InspectableProperty getTranslationX()17227 public float getTranslationX() { 17228 return mRenderNode.getTranslationX(); 17229 } 17230 17231 /** 17232 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 17233 * This effectively positions the object post-layout, in addition to wherever the object's 17234 * layout placed it. 17235 * 17236 * @param translationX The horizontal position of this view relative to its left position, 17237 * in pixels. 17238 * 17239 * @attr ref android.R.styleable#View_translationX 17240 */ setTranslationX(float translationX)17241 public void setTranslationX(float translationX) { 17242 if (translationX != getTranslationX()) { 17243 invalidateViewProperty(true, false); 17244 mRenderNode.setTranslationX(translationX); 17245 invalidateViewProperty(false, true); 17246 17247 invalidateParentIfNeededAndWasQuickRejected(); 17248 notifySubtreeAccessibilityStateChangedIfNeeded(); 17249 } 17250 } 17251 17252 /** 17253 * The vertical location of this view relative to its {@link #getTop() top} position. 17254 * This position is post-layout, in addition to wherever the object's 17255 * layout placed it. 17256 * 17257 * @return The vertical position of this view relative to its top position, 17258 * in pixels. 17259 */ 17260 @ViewDebug.ExportedProperty(category = "drawing") 17261 @InspectableProperty getTranslationY()17262 public float getTranslationY() { 17263 return mRenderNode.getTranslationY(); 17264 } 17265 17266 /** 17267 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 17268 * This effectively positions the object post-layout, in addition to wherever the object's 17269 * layout placed it. 17270 * 17271 * @param translationY The vertical position of this view relative to its top position, 17272 * in pixels. 17273 * 17274 * @attr ref android.R.styleable#View_translationY 17275 */ setTranslationY(float translationY)17276 public void setTranslationY(float translationY) { 17277 if (translationY != getTranslationY()) { 17278 invalidateViewProperty(true, false); 17279 mRenderNode.setTranslationY(translationY); 17280 invalidateViewProperty(false, true); 17281 17282 invalidateParentIfNeededAndWasQuickRejected(); 17283 notifySubtreeAccessibilityStateChangedIfNeeded(); 17284 } 17285 } 17286 17287 /** 17288 * The depth location of this view relative to its {@link #getElevation() elevation}. 17289 * 17290 * @return The depth of this view relative to its elevation. 17291 */ 17292 @ViewDebug.ExportedProperty(category = "drawing") 17293 @InspectableProperty getTranslationZ()17294 public float getTranslationZ() { 17295 return mRenderNode.getTranslationZ(); 17296 } 17297 17298 /** 17299 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 17300 * 17301 * @attr ref android.R.styleable#View_translationZ 17302 */ setTranslationZ(float translationZ)17303 public void setTranslationZ(float translationZ) { 17304 if (translationZ != getTranslationZ()) { 17305 translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ"); 17306 invalidateViewProperty(true, false); 17307 mRenderNode.setTranslationZ(translationZ); 17308 invalidateViewProperty(false, true); 17309 17310 invalidateParentIfNeededAndWasQuickRejected(); 17311 } 17312 } 17313 17314 /** 17315 * Changes the transformation matrix on the view. This is used in animation frameworks, 17316 * such as {@link android.transition.Transition}. When the animation finishes, the matrix 17317 * should be cleared by calling this method with <code>null</code> as the matrix parameter. 17318 * Application developers should use transformation methods like {@link #setRotation(float)}, 17319 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 17320 * and {@link #setTranslationY(float)} (float)}} instead. 17321 * 17322 * @param matrix The matrix, null indicates that the matrix should be cleared. 17323 * @see #getAnimationMatrix() 17324 */ setAnimationMatrix(@ullable Matrix matrix)17325 public void setAnimationMatrix(@Nullable Matrix matrix) { 17326 invalidateViewProperty(true, false); 17327 mRenderNode.setAnimationMatrix(matrix); 17328 invalidateViewProperty(false, true); 17329 17330 invalidateParentIfNeededAndWasQuickRejected(); 17331 } 17332 17333 /** 17334 * Return the current transformation matrix of the view. This is used in animation frameworks, 17335 * such as {@link android.transition.Transition}. Returns <code>null</code> when there is no 17336 * transformation provided by {@link #setAnimationMatrix(Matrix)}. 17337 * Application developers should use transformation methods like {@link #setRotation(float)}, 17338 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 17339 * and {@link #setTranslationY(float)} (float)}} instead. 17340 * 17341 * @return the Matrix, null indicates there is no transformation 17342 * @see #setAnimationMatrix(Matrix) 17343 */ 17344 @Nullable getAnimationMatrix()17345 public Matrix getAnimationMatrix() { 17346 return mRenderNode.getAnimationMatrix(); 17347 } 17348 17349 /** 17350 * Returns the current StateListAnimator if exists. 17351 * 17352 * @return StateListAnimator or null if it does not exists 17353 * @see #setStateListAnimator(android.animation.StateListAnimator) 17354 */ 17355 @InspectableProperty getStateListAnimator()17356 public StateListAnimator getStateListAnimator() { 17357 return mStateListAnimator; 17358 } 17359 17360 /** 17361 * Attaches the provided StateListAnimator to this View. 17362 * <p> 17363 * Any previously attached StateListAnimator will be detached. 17364 * 17365 * @param stateListAnimator The StateListAnimator to update the view 17366 * @see android.animation.StateListAnimator 17367 */ setStateListAnimator(StateListAnimator stateListAnimator)17368 public void setStateListAnimator(StateListAnimator stateListAnimator) { 17369 if (mStateListAnimator == stateListAnimator) { 17370 return; 17371 } 17372 if (mStateListAnimator != null) { 17373 mStateListAnimator.setTarget(null); 17374 } 17375 mStateListAnimator = stateListAnimator; 17376 if (stateListAnimator != null) { 17377 stateListAnimator.setTarget(this); 17378 if (isAttachedToWindow()) { 17379 stateListAnimator.setState(getDrawableState()); 17380 } 17381 } 17382 } 17383 17384 /** 17385 * Returns whether the Outline should be used to clip the contents of the View. 17386 * <p> 17387 * Note that this flag will only be respected if the View's Outline returns true from 17388 * {@link Outline#canClip()}. 17389 * 17390 * @see #setOutlineProvider(ViewOutlineProvider) 17391 * @see #setClipToOutline(boolean) 17392 */ getClipToOutline()17393 public final boolean getClipToOutline() { 17394 return mRenderNode.getClipToOutline(); 17395 } 17396 17397 /** 17398 * Sets whether the View's Outline should be used to clip the contents of the View. 17399 * <p> 17400 * Only a single non-rectangular clip can be applied on a View at any time. 17401 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 17402 * circular reveal} animation take priority over Outline clipping, and 17403 * child Outline clipping takes priority over Outline clipping done by a 17404 * parent. 17405 * <p> 17406 * Note that this flag will only be respected if the View's Outline returns true from 17407 * {@link Outline#canClip()}. 17408 * 17409 * @see #setOutlineProvider(ViewOutlineProvider) 17410 * @see #getClipToOutline() 17411 */ setClipToOutline(boolean clipToOutline)17412 public void setClipToOutline(boolean clipToOutline) { 17413 damageInParent(); 17414 if (getClipToOutline() != clipToOutline) { 17415 mRenderNode.setClipToOutline(clipToOutline); 17416 } 17417 } 17418 17419 // correspond to the enum values of View_outlineProvider 17420 private static final int PROVIDER_BACKGROUND = 0; 17421 private static final int PROVIDER_NONE = 1; 17422 private static final int PROVIDER_BOUNDS = 2; 17423 private static final int PROVIDER_PADDED_BOUNDS = 3; setOutlineProviderFromAttribute(int providerInt)17424 private void setOutlineProviderFromAttribute(int providerInt) { 17425 switch (providerInt) { 17426 case PROVIDER_BACKGROUND: 17427 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 17428 break; 17429 case PROVIDER_NONE: 17430 setOutlineProvider(null); 17431 break; 17432 case PROVIDER_BOUNDS: 17433 setOutlineProvider(ViewOutlineProvider.BOUNDS); 17434 break; 17435 case PROVIDER_PADDED_BOUNDS: 17436 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 17437 break; 17438 } 17439 } 17440 17441 /** 17442 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 17443 * the shape of the shadow it casts, and enables outline clipping. 17444 * <p> 17445 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 17446 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 17447 * outline provider with this method allows this behavior to be overridden. 17448 * <p> 17449 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 17450 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 17451 * <p> 17452 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 17453 * 17454 * @see #setClipToOutline(boolean) 17455 * @see #getClipToOutline() 17456 * @see #getOutlineProvider() 17457 */ setOutlineProvider(ViewOutlineProvider provider)17458 public void setOutlineProvider(ViewOutlineProvider provider) { 17459 mOutlineProvider = provider; 17460 invalidateOutline(); 17461 } 17462 17463 /** 17464 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 17465 * that defines the shape of the shadow it casts, and enables outline clipping. 17466 * 17467 * @see #setOutlineProvider(ViewOutlineProvider) 17468 */ 17469 @InspectableProperty getOutlineProvider()17470 public ViewOutlineProvider getOutlineProvider() { 17471 return mOutlineProvider; 17472 } 17473 17474 /** 17475 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 17476 * 17477 * @see #setOutlineProvider(ViewOutlineProvider) 17478 */ invalidateOutline()17479 public void invalidateOutline() { 17480 rebuildOutline(); 17481 17482 notifySubtreeAccessibilityStateChangedIfNeeded(); 17483 invalidateViewProperty(false, false); 17484 } 17485 17486 /** 17487 * Internal version of {@link #invalidateOutline()} which invalidates the 17488 * outline without invalidating the view itself. This is intended to be called from 17489 * within methods in the View class itself which are the result of the view being 17490 * invalidated already. For example, when we are drawing the background of a View, 17491 * we invalidate the outline in case it changed in the meantime, but we do not 17492 * need to invalidate the view because we're already drawing the background as part 17493 * of drawing the view in response to an earlier invalidation of the view. 17494 */ rebuildOutline()17495 private void rebuildOutline() { 17496 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 17497 if (mAttachInfo == null) return; 17498 17499 if (mOutlineProvider == null) { 17500 // no provider, remove outline 17501 mRenderNode.setOutline(null); 17502 } else { 17503 final Outline outline = mAttachInfo.mTmpOutline; 17504 outline.setEmpty(); 17505 outline.setAlpha(1.0f); 17506 17507 mOutlineProvider.getOutline(this, outline); 17508 mRenderNode.setOutline(outline); 17509 } 17510 } 17511 17512 /** 17513 * HierarchyViewer only 17514 * 17515 * @hide 17516 */ 17517 @ViewDebug.ExportedProperty(category = "drawing") hasShadow()17518 public boolean hasShadow() { 17519 return mRenderNode.hasShadow(); 17520 } 17521 17522 /** 17523 * Sets the color of the spot shadow that is drawn when the view has a positive Z or 17524 * elevation value. 17525 * <p> 17526 * By default the shadow color is black. Generally, this color will be opaque so the intensity 17527 * of the shadow is consistent between different views with different colors. 17528 * <p> 17529 * The opacity of the final spot shadow is a function of the shadow caster height, the 17530 * alpha channel of the outlineSpotShadowColor (typically opaque), and the 17531 * {@link android.R.attr#spotShadowAlpha} theme attribute. 17532 * 17533 * @attr ref android.R.styleable#View_outlineSpotShadowColor 17534 * @param color The color this View will cast for its elevation spot shadow. 17535 */ setOutlineSpotShadowColor(@olorInt int color)17536 public void setOutlineSpotShadowColor(@ColorInt int color) { 17537 if (mRenderNode.setSpotShadowColor(color)) { 17538 invalidateViewProperty(true, true); 17539 } 17540 } 17541 17542 /** 17543 * @return The shadow color set by {@link #setOutlineSpotShadowColor(int)}, or black if nothing 17544 * was set 17545 */ 17546 @InspectableProperty getOutlineSpotShadowColor()17547 public @ColorInt int getOutlineSpotShadowColor() { 17548 return mRenderNode.getSpotShadowColor(); 17549 } 17550 17551 /** 17552 * Sets the color of the ambient shadow that is drawn when the view has a positive Z or 17553 * elevation value. 17554 * <p> 17555 * By default the shadow color is black. Generally, this color will be opaque so the intensity 17556 * of the shadow is consistent between different views with different colors. 17557 * <p> 17558 * The opacity of the final ambient shadow is a function of the shadow caster height, the 17559 * alpha channel of the outlineAmbientShadowColor (typically opaque), and the 17560 * {@link android.R.attr#ambientShadowAlpha} theme attribute. 17561 * 17562 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 17563 * @param color The color this View will cast for its elevation shadow. 17564 */ setOutlineAmbientShadowColor(@olorInt int color)17565 public void setOutlineAmbientShadowColor(@ColorInt int color) { 17566 if (mRenderNode.setAmbientShadowColor(color)) { 17567 invalidateViewProperty(true, true); 17568 } 17569 } 17570 17571 /** 17572 * @return The shadow color set by {@link #setOutlineAmbientShadowColor(int)}, or black if 17573 * nothing was set 17574 */ 17575 @InspectableProperty getOutlineAmbientShadowColor()17576 public @ColorInt int getOutlineAmbientShadowColor() { 17577 return mRenderNode.getAmbientShadowColor(); 17578 } 17579 17580 17581 /** @hide */ setRevealClip(boolean shouldClip, float x, float y, float radius)17582 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 17583 mRenderNode.setRevealClip(shouldClip, x, y, radius); 17584 invalidateViewProperty(false, false); 17585 } 17586 17587 /** 17588 * Hit rectangle in parent's coordinates 17589 * 17590 * @param outRect The hit rectangle of the view. 17591 */ getHitRect(Rect outRect)17592 public void getHitRect(Rect outRect) { 17593 if (hasIdentityMatrix() || mAttachInfo == null) { 17594 outRect.set(mLeft, mTop, mRight, mBottom); 17595 } else { 17596 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 17597 tmpRect.set(0, 0, getWidth(), getHeight()); 17598 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 17599 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 17600 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 17601 } 17602 } 17603 17604 /** 17605 * Determines whether the given point, in local coordinates is inside the view. 17606 */ pointInView(float localX, float localY)17607 /*package*/ final boolean pointInView(float localX, float localY) { 17608 return pointInView(localX, localY, 0); 17609 } 17610 17611 /** 17612 * Utility method to determine whether the given point, in local coordinates, 17613 * is inside the view, where the area of the view is expanded by the slop factor. 17614 * This method is called while processing touch-move events to determine if the event 17615 * is still within the view. 17616 * 17617 * @hide 17618 */ 17619 @UnsupportedAppUsage pointInView(float localX, float localY, float slop)17620 public boolean pointInView(float localX, float localY, float slop) { 17621 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 17622 localY < ((mBottom - mTop) + slop); 17623 } 17624 17625 /** 17626 * When a view has focus and the user navigates away from it, the next view is searched for 17627 * starting from the rectangle filled in by this method. 17628 * 17629 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 17630 * of the view. However, if your view maintains some idea of internal selection, 17631 * such as a cursor, or a selected row or column, you should override this method and 17632 * fill in a more specific rectangle. 17633 * 17634 * @param r The rectangle to fill in, in this view's coordinates. 17635 */ getFocusedRect(Rect r)17636 public void getFocusedRect(Rect r) { 17637 getDrawingRect(r); 17638 } 17639 17640 /** 17641 * If some part of this view is not clipped by any of its parents, then 17642 * return that area in r in global (root) coordinates. To convert r to local 17643 * coordinates (without taking possible View rotations into account), offset 17644 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 17645 * If the view is completely clipped or translated out, return false. 17646 * 17647 * @param r If true is returned, r holds the global coordinates of the 17648 * visible portion of this view. 17649 * @param globalOffset If true is returned, globalOffset holds the dx,dy 17650 * between this view and its root. globalOffet may be null. 17651 * @return true if r is non-empty (i.e. part of the view is visible at the 17652 * root level. 17653 */ getGlobalVisibleRect(Rect r, Point globalOffset)17654 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 17655 int width = mRight - mLeft; 17656 int height = mBottom - mTop; 17657 if (width > 0 && height > 0) { 17658 r.set(0, 0, width, height); 17659 if (globalOffset != null) { 17660 globalOffset.set(-mScrollX, -mScrollY); 17661 } 17662 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 17663 } 17664 return false; 17665 } 17666 getGlobalVisibleRect(Rect r)17667 public final boolean getGlobalVisibleRect(Rect r) { 17668 return getGlobalVisibleRect(r, null); 17669 } 17670 getLocalVisibleRect(Rect r)17671 public final boolean getLocalVisibleRect(Rect r) { 17672 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 17673 if (getGlobalVisibleRect(r, offset)) { 17674 r.offset(-offset.x, -offset.y); // make r local 17675 return true; 17676 } 17677 return false; 17678 } 17679 17680 /** 17681 * Offset this view's vertical location by the specified number of pixels. 17682 * 17683 * @param offset the number of pixels to offset the view by 17684 */ offsetTopAndBottom(int offset)17685 public void offsetTopAndBottom(int offset) { 17686 if (offset != 0) { 17687 final boolean matrixIsIdentity = hasIdentityMatrix(); 17688 if (matrixIsIdentity) { 17689 if (isHardwareAccelerated()) { 17690 invalidateViewProperty(false, false); 17691 } else { 17692 final ViewParent p = mParent; 17693 if (p != null && mAttachInfo != null) { 17694 final Rect r = mAttachInfo.mTmpInvalRect; 17695 int minTop; 17696 int maxBottom; 17697 int yLoc; 17698 if (offset < 0) { 17699 minTop = mTop + offset; 17700 maxBottom = mBottom; 17701 yLoc = offset; 17702 } else { 17703 minTop = mTop; 17704 maxBottom = mBottom + offset; 17705 yLoc = 0; 17706 } 17707 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 17708 p.invalidateChild(this, r); 17709 } 17710 } 17711 } else { 17712 invalidateViewProperty(false, false); 17713 } 17714 17715 mTop += offset; 17716 mBottom += offset; 17717 mRenderNode.offsetTopAndBottom(offset); 17718 if (isHardwareAccelerated()) { 17719 invalidateViewProperty(false, false); 17720 invalidateParentIfNeededAndWasQuickRejected(); 17721 } else { 17722 if (!matrixIsIdentity) { 17723 invalidateViewProperty(false, true); 17724 } 17725 invalidateParentIfNeeded(); 17726 } 17727 notifySubtreeAccessibilityStateChangedIfNeeded(); 17728 } 17729 } 17730 17731 /** 17732 * Offset this view's horizontal location by the specified amount of pixels. 17733 * 17734 * @param offset the number of pixels to offset the view by 17735 */ offsetLeftAndRight(int offset)17736 public void offsetLeftAndRight(int offset) { 17737 if (offset != 0) { 17738 final boolean matrixIsIdentity = hasIdentityMatrix(); 17739 if (matrixIsIdentity) { 17740 if (isHardwareAccelerated()) { 17741 invalidateViewProperty(false, false); 17742 } else { 17743 final ViewParent p = mParent; 17744 if (p != null && mAttachInfo != null) { 17745 final Rect r = mAttachInfo.mTmpInvalRect; 17746 int minLeft; 17747 int maxRight; 17748 if (offset < 0) { 17749 minLeft = mLeft + offset; 17750 maxRight = mRight; 17751 } else { 17752 minLeft = mLeft; 17753 maxRight = mRight + offset; 17754 } 17755 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 17756 p.invalidateChild(this, r); 17757 } 17758 } 17759 } else { 17760 invalidateViewProperty(false, false); 17761 } 17762 17763 mLeft += offset; 17764 mRight += offset; 17765 mRenderNode.offsetLeftAndRight(offset); 17766 if (isHardwareAccelerated()) { 17767 invalidateViewProperty(false, false); 17768 invalidateParentIfNeededAndWasQuickRejected(); 17769 } else { 17770 if (!matrixIsIdentity) { 17771 invalidateViewProperty(false, true); 17772 } 17773 invalidateParentIfNeeded(); 17774 } 17775 notifySubtreeAccessibilityStateChangedIfNeeded(); 17776 } 17777 } 17778 17779 /** 17780 * Get the LayoutParams associated with this view. All views should have 17781 * layout parameters. These supply parameters to the <i>parent</i> of this 17782 * view specifying how it should be arranged. There are many subclasses of 17783 * ViewGroup.LayoutParams, and these correspond to the different subclasses 17784 * of ViewGroup that are responsible for arranging their children. 17785 * 17786 * This method may return null if this View is not attached to a parent 17787 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 17788 * was not invoked successfully. When a View is attached to a parent 17789 * ViewGroup, this method must not return null. 17790 * 17791 * @return The LayoutParams associated with this view, or null if no 17792 * parameters have been set yet 17793 */ 17794 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") getLayoutParams()17795 public ViewGroup.LayoutParams getLayoutParams() { 17796 return mLayoutParams; 17797 } 17798 17799 /** 17800 * Set the layout parameters associated with this view. These supply 17801 * parameters to the <i>parent</i> of this view specifying how it should be 17802 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 17803 * correspond to the different subclasses of ViewGroup that are responsible 17804 * for arranging their children. 17805 * 17806 * @param params The layout parameters for this view, cannot be null 17807 */ setLayoutParams(ViewGroup.LayoutParams params)17808 public void setLayoutParams(ViewGroup.LayoutParams params) { 17809 if (params == null) { 17810 throw new NullPointerException("Layout parameters cannot be null"); 17811 } 17812 mLayoutParams = params; 17813 resolveLayoutParams(); 17814 if (mParent instanceof ViewGroup) { 17815 ((ViewGroup) mParent).onSetLayoutParams(this, params); 17816 } 17817 requestLayout(); 17818 } 17819 17820 /** 17821 * Resolve the layout parameters depending on the resolved layout direction 17822 * 17823 * @hide 17824 */ resolveLayoutParams()17825 public void resolveLayoutParams() { 17826 if (mLayoutParams != null) { 17827 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 17828 } 17829 } 17830 17831 /** 17832 * Set the scrolled position of your view. This will cause a call to 17833 * {@link #onScrollChanged(int, int, int, int)} and the view will be 17834 * invalidated. 17835 * @param x the x position to scroll to 17836 * @param y the y position to scroll to 17837 */ scrollTo(int x, int y)17838 public void scrollTo(int x, int y) { 17839 if (mScrollX != x || mScrollY != y) { 17840 int oldX = mScrollX; 17841 int oldY = mScrollY; 17842 mScrollX = x; 17843 mScrollY = y; 17844 invalidateParentCaches(); 17845 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 17846 if (!awakenScrollBars()) { 17847 postInvalidateOnAnimation(); 17848 } 17849 } 17850 } 17851 17852 /** 17853 * Move the scrolled position of your view. This will cause a call to 17854 * {@link #onScrollChanged(int, int, int, int)} and the view will be 17855 * invalidated. 17856 * @param x the amount of pixels to scroll by horizontally 17857 * @param y the amount of pixels to scroll by vertically 17858 */ scrollBy(int x, int y)17859 public void scrollBy(int x, int y) { 17860 scrollTo(mScrollX + x, mScrollY + y); 17861 } 17862 17863 /** 17864 * <p>Trigger the scrollbars to draw. When invoked this method starts an 17865 * animation to fade the scrollbars out after a default delay. If a subclass 17866 * provides animated scrolling, the start delay should equal the duration 17867 * of the scrolling animation.</p> 17868 * 17869 * <p>The animation starts only if at least one of the scrollbars is 17870 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 17871 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 17872 * this method returns true, and false otherwise. If the animation is 17873 * started, this method calls {@link #invalidate()}; in that case the 17874 * caller should not call {@link #invalidate()}.</p> 17875 * 17876 * <p>This method should be invoked every time a subclass directly updates 17877 * the scroll parameters.</p> 17878 * 17879 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 17880 * and {@link #scrollTo(int, int)}.</p> 17881 * 17882 * @return true if the animation is played, false otherwise 17883 * 17884 * @see #awakenScrollBars(int) 17885 * @see #scrollBy(int, int) 17886 * @see #scrollTo(int, int) 17887 * @see #isHorizontalScrollBarEnabled() 17888 * @see #isVerticalScrollBarEnabled() 17889 * @see #setHorizontalScrollBarEnabled(boolean) 17890 * @see #setVerticalScrollBarEnabled(boolean) 17891 */ awakenScrollBars()17892 protected boolean awakenScrollBars() { 17893 return mScrollCache != null && 17894 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 17895 } 17896 17897 /** 17898 * Trigger the scrollbars to draw. 17899 * This method differs from awakenScrollBars() only in its default duration. 17900 * initialAwakenScrollBars() will show the scroll bars for longer than 17901 * usual to give the user more of a chance to notice them. 17902 * 17903 * @return true if the animation is played, false otherwise. 17904 */ initialAwakenScrollBars()17905 private boolean initialAwakenScrollBars() { 17906 return mScrollCache != null && 17907 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 17908 } 17909 17910 /** 17911 * <p> 17912 * Trigger the scrollbars to draw. When invoked this method starts an 17913 * animation to fade the scrollbars out after a fixed delay. If a subclass 17914 * provides animated scrolling, the start delay should equal the duration of 17915 * the scrolling animation. 17916 * </p> 17917 * 17918 * <p> 17919 * The animation starts only if at least one of the scrollbars is enabled, 17920 * as specified by {@link #isHorizontalScrollBarEnabled()} and 17921 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 17922 * this method returns true, and false otherwise. If the animation is 17923 * started, this method calls {@link #invalidate()}; in that case the caller 17924 * should not call {@link #invalidate()}. 17925 * </p> 17926 * 17927 * <p> 17928 * This method should be invoked every time a subclass directly updates the 17929 * scroll parameters. 17930 * </p> 17931 * 17932 * @param startDelay the delay, in milliseconds, after which the animation 17933 * should start; when the delay is 0, the animation starts 17934 * immediately 17935 * @return true if the animation is played, false otherwise 17936 * 17937 * @see #scrollBy(int, int) 17938 * @see #scrollTo(int, int) 17939 * @see #isHorizontalScrollBarEnabled() 17940 * @see #isVerticalScrollBarEnabled() 17941 * @see #setHorizontalScrollBarEnabled(boolean) 17942 * @see #setVerticalScrollBarEnabled(boolean) 17943 */ awakenScrollBars(int startDelay)17944 protected boolean awakenScrollBars(int startDelay) { 17945 return awakenScrollBars(startDelay, true); 17946 } 17947 17948 /** 17949 * <p> 17950 * Trigger the scrollbars to draw. When invoked this method starts an 17951 * animation to fade the scrollbars out after a fixed delay. If a subclass 17952 * provides animated scrolling, the start delay should equal the duration of 17953 * the scrolling animation. 17954 * </p> 17955 * 17956 * <p> 17957 * The animation starts only if at least one of the scrollbars is enabled, 17958 * as specified by {@link #isHorizontalScrollBarEnabled()} and 17959 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 17960 * this method returns true, and false otherwise. If the animation is 17961 * started, this method calls {@link #invalidate()} if the invalidate parameter 17962 * is set to true; in that case the caller 17963 * should not call {@link #invalidate()}. 17964 * </p> 17965 * 17966 * <p> 17967 * This method should be invoked every time a subclass directly updates the 17968 * scroll parameters. 17969 * </p> 17970 * 17971 * @param startDelay the delay, in milliseconds, after which the animation 17972 * should start; when the delay is 0, the animation starts 17973 * immediately 17974 * 17975 * @param invalidate Whether this method should call invalidate 17976 * 17977 * @return true if the animation is played, false otherwise 17978 * 17979 * @see #scrollBy(int, int) 17980 * @see #scrollTo(int, int) 17981 * @see #isHorizontalScrollBarEnabled() 17982 * @see #isVerticalScrollBarEnabled() 17983 * @see #setHorizontalScrollBarEnabled(boolean) 17984 * @see #setVerticalScrollBarEnabled(boolean) 17985 */ awakenScrollBars(int startDelay, boolean invalidate)17986 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 17987 final ScrollabilityCache scrollCache = mScrollCache; 17988 17989 if (scrollCache == null || !scrollCache.fadeScrollBars) { 17990 return false; 17991 } 17992 17993 if (scrollCache.scrollBar == null) { 17994 scrollCache.scrollBar = new ScrollBarDrawable(); 17995 scrollCache.scrollBar.setState(getDrawableState()); 17996 scrollCache.scrollBar.setCallback(this); 17997 } 17998 17999 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 18000 18001 if (invalidate) { 18002 // Invalidate to show the scrollbars 18003 postInvalidateOnAnimation(); 18004 } 18005 18006 if (scrollCache.state == ScrollabilityCache.OFF) { 18007 // FIXME: this is copied from WindowManagerService. 18008 // We should get this value from the system when it 18009 // is possible to do so. 18010 final int KEY_REPEAT_FIRST_DELAY = 750; 18011 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 18012 } 18013 18014 // Tell mScrollCache when we should start fading. This may 18015 // extend the fade start time if one was already scheduled 18016 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 18017 scrollCache.fadeStartTime = fadeStartTime; 18018 scrollCache.state = ScrollabilityCache.ON; 18019 18020 // Schedule our fader to run, unscheduling any old ones first 18021 if (mAttachInfo != null) { 18022 mAttachInfo.mHandler.removeCallbacks(scrollCache); 18023 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 18024 } 18025 18026 return true; 18027 } 18028 18029 return false; 18030 } 18031 18032 /** 18033 * Do not invalidate views which are not visible and which are not running an animation. They 18034 * will not get drawn and they should not set dirty flags as if they will be drawn 18035 */ skipInvalidate()18036 private boolean skipInvalidate() { 18037 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 18038 (!(mParent instanceof ViewGroup) || 18039 !((ViewGroup) mParent).isViewTransitioning(this)); 18040 } 18041 18042 /** 18043 * Mark the area defined by dirty as needing to be drawn. If the view is 18044 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 18045 * point in the future. 18046 * <p> 18047 * This must be called from a UI thread. To call from a non-UI thread, call 18048 * {@link #postInvalidate()}. 18049 * <p> 18050 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 18051 * {@code dirty}. 18052 * 18053 * @param dirty the rectangle representing the bounds of the dirty region 18054 * 18055 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 18056 * the importance of the dirty rectangle. In API 21 the given rectangle is 18057 * ignored entirely in favor of an internally-calculated area instead. 18058 * Because of this, clients are encouraged to just call {@link #invalidate()}. 18059 */ 18060 @Deprecated invalidate(Rect dirty)18061 public void invalidate(Rect dirty) { 18062 final int scrollX = mScrollX; 18063 final int scrollY = mScrollY; 18064 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 18065 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 18066 } 18067 18068 /** 18069 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 18070 * coordinates of the dirty rect are relative to the view. If the view is 18071 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 18072 * point in the future. 18073 * <p> 18074 * This must be called from a UI thread. To call from a non-UI thread, call 18075 * {@link #postInvalidate()}. 18076 * 18077 * @param l the left position of the dirty region 18078 * @param t the top position of the dirty region 18079 * @param r the right position of the dirty region 18080 * @param b the bottom position of the dirty region 18081 * 18082 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 18083 * the importance of the dirty rectangle. In API 21 the given rectangle is 18084 * ignored entirely in favor of an internally-calculated area instead. 18085 * Because of this, clients are encouraged to just call {@link #invalidate()}. 18086 */ 18087 @Deprecated invalidate(int l, int t, int r, int b)18088 public void invalidate(int l, int t, int r, int b) { 18089 final int scrollX = mScrollX; 18090 final int scrollY = mScrollY; 18091 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 18092 } 18093 18094 /** 18095 * Invalidate the whole view. If the view is visible, 18096 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 18097 * the future. 18098 * <p> 18099 * This must be called from a UI thread. To call from a non-UI thread, call 18100 * {@link #postInvalidate()}. 18101 */ invalidate()18102 public void invalidate() { 18103 invalidate(true); 18104 } 18105 18106 /** 18107 * This is where the invalidate() work actually happens. A full invalidate() 18108 * causes the drawing cache to be invalidated, but this function can be 18109 * called with invalidateCache set to false to skip that invalidation step 18110 * for cases that do not need it (for example, a component that remains at 18111 * the same dimensions with the same content). 18112 * 18113 * @param invalidateCache Whether the drawing cache for this view should be 18114 * invalidated as well. This is usually true for a full 18115 * invalidate, but may be set to false if the View's contents or 18116 * dimensions have not changed. 18117 * @hide 18118 */ 18119 @UnsupportedAppUsage invalidate(boolean invalidateCache)18120 public void invalidate(boolean invalidateCache) { 18121 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 18122 } 18123 invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate)18124 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 18125 boolean fullInvalidate) { 18126 if (mGhostView != null) { 18127 mGhostView.invalidate(true); 18128 return; 18129 } 18130 18131 if (skipInvalidate()) { 18132 return; 18133 } 18134 18135 // Reset content capture caches 18136 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; 18137 mCachedContentCaptureSession = null; 18138 18139 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 18140 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 18141 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 18142 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 18143 if (fullInvalidate) { 18144 mLastIsOpaque = isOpaque(); 18145 mPrivateFlags &= ~PFLAG_DRAWN; 18146 } 18147 18148 mPrivateFlags |= PFLAG_DIRTY; 18149 18150 if (invalidateCache) { 18151 mPrivateFlags |= PFLAG_INVALIDATED; 18152 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 18153 } 18154 18155 // Propagate the damage rectangle to the parent view. 18156 final AttachInfo ai = mAttachInfo; 18157 final ViewParent p = mParent; 18158 if (p != null && ai != null && l < r && t < b) { 18159 final Rect damage = ai.mTmpInvalRect; 18160 damage.set(l, t, r, b); 18161 p.invalidateChild(this, damage); 18162 } 18163 18164 // Damage the entire projection receiver, if necessary. 18165 if (mBackground != null && mBackground.isProjected()) { 18166 final View receiver = getProjectionReceiver(); 18167 if (receiver != null) { 18168 receiver.damageInParent(); 18169 } 18170 } 18171 } 18172 } 18173 18174 /** 18175 * @return this view's projection receiver, or {@code null} if none exists 18176 */ getProjectionReceiver()18177 private View getProjectionReceiver() { 18178 ViewParent p = getParent(); 18179 while (p != null && p instanceof View) { 18180 final View v = (View) p; 18181 if (v.isProjectionReceiver()) { 18182 return v; 18183 } 18184 p = p.getParent(); 18185 } 18186 18187 return null; 18188 } 18189 18190 /** 18191 * @return whether the view is a projection receiver 18192 */ isProjectionReceiver()18193 private boolean isProjectionReceiver() { 18194 return mBackground != null; 18195 } 18196 18197 /** 18198 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 18199 * set any flags or handle all of the cases handled by the default invalidation methods. 18200 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 18201 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 18202 * walk up the hierarchy, transforming the dirty rect as necessary. 18203 * 18204 * The method also handles normal invalidation logic if display list properties are not 18205 * being used in this view. The invalidateParent and forceRedraw flags are used by that 18206 * backup approach, to handle these cases used in the various property-setting methods. 18207 * 18208 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 18209 * are not being used in this view 18210 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 18211 * list properties are not being used in this view 18212 */ 18213 @UnsupportedAppUsage invalidateViewProperty(boolean invalidateParent, boolean forceRedraw)18214 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 18215 if (!isHardwareAccelerated() 18216 || !mRenderNode.hasDisplayList() 18217 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 18218 if (invalidateParent) { 18219 invalidateParentCaches(); 18220 } 18221 if (forceRedraw) { 18222 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 18223 } 18224 invalidate(false); 18225 } else { 18226 damageInParent(); 18227 } 18228 } 18229 18230 /** 18231 * Tells the parent view to damage this view's bounds. 18232 * 18233 * @hide 18234 */ damageInParent()18235 protected void damageInParent() { 18236 if (mParent != null && mAttachInfo != null) { 18237 mParent.onDescendantInvalidated(this, this); 18238 } 18239 } 18240 18241 /** 18242 * Used to indicate that the parent of this view should clear its caches. This functionality 18243 * is used to force the parent to rebuild its display list (when hardware-accelerated), 18244 * which is necessary when various parent-managed properties of the view change, such as 18245 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 18246 * clears the parent caches and does not causes an invalidate event. 18247 * 18248 * @hide 18249 */ 18250 @UnsupportedAppUsage invalidateParentCaches()18251 protected void invalidateParentCaches() { 18252 if (mParent instanceof View) { 18253 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 18254 } 18255 } 18256 18257 /** 18258 * Used to indicate that the parent of this view should be invalidated. This functionality 18259 * is used to force the parent to rebuild its display list (when hardware-accelerated), 18260 * which is necessary when various parent-managed properties of the view change, such as 18261 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 18262 * an invalidation event to the parent. 18263 * 18264 * @hide 18265 */ 18266 @UnsupportedAppUsage invalidateParentIfNeeded()18267 protected void invalidateParentIfNeeded() { 18268 if (isHardwareAccelerated() && mParent instanceof View) { 18269 ((View) mParent).invalidate(true); 18270 } 18271 } 18272 18273 /** 18274 * @hide 18275 */ invalidateParentIfNeededAndWasQuickRejected()18276 protected void invalidateParentIfNeededAndWasQuickRejected() { 18277 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 18278 // View was rejected last time it was drawn by its parent; this may have changed 18279 invalidateParentIfNeeded(); 18280 } 18281 } 18282 18283 /** 18284 * Indicates whether this View is opaque. An opaque View guarantees that it will 18285 * draw all the pixels overlapping its bounds using a fully opaque color. 18286 * 18287 * Subclasses of View should override this method whenever possible to indicate 18288 * whether an instance is opaque. Opaque Views are treated in a special way by 18289 * the View hierarchy, possibly allowing it to perform optimizations during 18290 * invalidate/draw passes. 18291 * 18292 * @return True if this View is guaranteed to be fully opaque, false otherwise. 18293 */ 18294 @ViewDebug.ExportedProperty(category = "drawing") isOpaque()18295 public boolean isOpaque() { 18296 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 18297 getFinalAlpha() >= 1.0f; 18298 } 18299 18300 /** 18301 * @hide 18302 */ 18303 @UnsupportedAppUsage computeOpaqueFlags()18304 protected void computeOpaqueFlags() { 18305 // Opaque if: 18306 // - Has a background 18307 // - Background is opaque 18308 // - Doesn't have scrollbars or scrollbars overlay 18309 18310 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 18311 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 18312 } else { 18313 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 18314 } 18315 18316 final int flags = mViewFlags; 18317 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 18318 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 18319 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 18320 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 18321 } else { 18322 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 18323 } 18324 } 18325 18326 /** 18327 * @hide 18328 */ hasOpaqueScrollbars()18329 protected boolean hasOpaqueScrollbars() { 18330 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 18331 } 18332 18333 /** 18334 * @return A handler associated with the thread running the View. This 18335 * handler can be used to pump events in the UI events queue. 18336 */ getHandler()18337 public Handler getHandler() { 18338 final AttachInfo attachInfo = mAttachInfo; 18339 if (attachInfo != null) { 18340 return attachInfo.mHandler; 18341 } 18342 return null; 18343 } 18344 18345 /** 18346 * Returns the queue of runnable for this view. 18347 * 18348 * @return the queue of runnables for this view 18349 */ getRunQueue()18350 private HandlerActionQueue getRunQueue() { 18351 if (mRunQueue == null) { 18352 mRunQueue = new HandlerActionQueue(); 18353 } 18354 return mRunQueue; 18355 } 18356 18357 /** 18358 * Gets the view root associated with the View. 18359 * @return The view root, or null if none. 18360 * @hide 18361 */ 18362 @UnsupportedAppUsage getViewRootImpl()18363 public ViewRootImpl getViewRootImpl() { 18364 if (mAttachInfo != null) { 18365 return mAttachInfo.mViewRootImpl; 18366 } 18367 return null; 18368 } 18369 18370 /** 18371 * @hide 18372 */ 18373 @UnsupportedAppUsage getThreadedRenderer()18374 public ThreadedRenderer getThreadedRenderer() { 18375 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 18376 } 18377 18378 /** 18379 * <p>Causes the Runnable to be added to the message queue. 18380 * The runnable will be run on the user interface thread.</p> 18381 * 18382 * @param action The Runnable that will be executed. 18383 * 18384 * @return Returns true if the Runnable was successfully placed in to the 18385 * message queue. Returns false on failure, usually because the 18386 * looper processing the message queue is exiting. 18387 * 18388 * @see #postDelayed 18389 * @see #removeCallbacks 18390 */ post(Runnable action)18391 public boolean post(Runnable action) { 18392 final AttachInfo attachInfo = mAttachInfo; 18393 if (attachInfo != null) { 18394 return attachInfo.mHandler.post(action); 18395 } 18396 18397 // Postpone the runnable until we know on which thread it needs to run. 18398 // Assume that the runnable will be successfully placed after attach. 18399 getRunQueue().post(action); 18400 return true; 18401 } 18402 18403 /** 18404 * <p>Causes the Runnable to be added to the message queue, to be run 18405 * after the specified amount of time elapses. 18406 * The runnable will be run on the user interface thread.</p> 18407 * 18408 * @param action The Runnable that will be executed. 18409 * @param delayMillis The delay (in milliseconds) until the Runnable 18410 * will be executed. 18411 * 18412 * @return true if the Runnable was successfully placed in to the 18413 * message queue. Returns false on failure, usually because the 18414 * looper processing the message queue is exiting. Note that a 18415 * result of true does not mean the Runnable will be processed -- 18416 * if the looper is quit before the delivery time of the message 18417 * occurs then the message will be dropped. 18418 * 18419 * @see #post 18420 * @see #removeCallbacks 18421 */ postDelayed(Runnable action, long delayMillis)18422 public boolean postDelayed(Runnable action, long delayMillis) { 18423 final AttachInfo attachInfo = mAttachInfo; 18424 if (attachInfo != null) { 18425 return attachInfo.mHandler.postDelayed(action, delayMillis); 18426 } 18427 18428 // Postpone the runnable until we know on which thread it needs to run. 18429 // Assume that the runnable will be successfully placed after attach. 18430 getRunQueue().postDelayed(action, delayMillis); 18431 return true; 18432 } 18433 18434 /** 18435 * <p>Causes the Runnable to execute on the next animation time step. 18436 * The runnable will be run on the user interface thread.</p> 18437 * 18438 * @param action The Runnable that will be executed. 18439 * 18440 * @see #postOnAnimationDelayed 18441 * @see #removeCallbacks 18442 */ postOnAnimation(Runnable action)18443 public void postOnAnimation(Runnable action) { 18444 final AttachInfo attachInfo = mAttachInfo; 18445 if (attachInfo != null) { 18446 attachInfo.mViewRootImpl.mChoreographer.postCallback( 18447 Choreographer.CALLBACK_ANIMATION, action, null); 18448 } else { 18449 // Postpone the runnable until we know 18450 // on which thread it needs to run. 18451 getRunQueue().post(action); 18452 } 18453 } 18454 18455 /** 18456 * <p>Causes the Runnable to execute on the next animation time step, 18457 * after the specified amount of time elapses. 18458 * The runnable will be run on the user interface thread.</p> 18459 * 18460 * @param action The Runnable that will be executed. 18461 * @param delayMillis The delay (in milliseconds) until the Runnable 18462 * will be executed. 18463 * 18464 * @see #postOnAnimation 18465 * @see #removeCallbacks 18466 */ postOnAnimationDelayed(Runnable action, long delayMillis)18467 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 18468 final AttachInfo attachInfo = mAttachInfo; 18469 if (attachInfo != null) { 18470 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 18471 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 18472 } else { 18473 // Postpone the runnable until we know 18474 // on which thread it needs to run. 18475 getRunQueue().postDelayed(action, delayMillis); 18476 } 18477 } 18478 18479 /** 18480 * <p>Removes the specified Runnable from the message queue.</p> 18481 * 18482 * @param action The Runnable to remove from the message handling queue 18483 * 18484 * @return true if this view could ask the Handler to remove the Runnable, 18485 * false otherwise. When the returned value is true, the Runnable 18486 * may or may not have been actually removed from the message queue 18487 * (for instance, if the Runnable was not in the queue already.) 18488 * 18489 * @see #post 18490 * @see #postDelayed 18491 * @see #postOnAnimation 18492 * @see #postOnAnimationDelayed 18493 */ removeCallbacks(Runnable action)18494 public boolean removeCallbacks(Runnable action) { 18495 if (action != null) { 18496 final AttachInfo attachInfo = mAttachInfo; 18497 if (attachInfo != null) { 18498 attachInfo.mHandler.removeCallbacks(action); 18499 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 18500 Choreographer.CALLBACK_ANIMATION, action, null); 18501 } 18502 getRunQueue().removeCallbacks(action); 18503 } 18504 return true; 18505 } 18506 18507 /** 18508 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 18509 * Use this to invalidate the View from a non-UI thread.</p> 18510 * 18511 * <p>This method can be invoked from outside of the UI thread 18512 * only when this View is attached to a window.</p> 18513 * 18514 * @see #invalidate() 18515 * @see #postInvalidateDelayed(long) 18516 */ postInvalidate()18517 public void postInvalidate() { 18518 postInvalidateDelayed(0); 18519 } 18520 18521 /** 18522 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 18523 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 18524 * 18525 * <p>This method can be invoked from outside of the UI thread 18526 * only when this View is attached to a window.</p> 18527 * 18528 * @param left The left coordinate of the rectangle to invalidate. 18529 * @param top The top coordinate of the rectangle to invalidate. 18530 * @param right The right coordinate of the rectangle to invalidate. 18531 * @param bottom The bottom coordinate of the rectangle to invalidate. 18532 * 18533 * @see #invalidate(int, int, int, int) 18534 * @see #invalidate(Rect) 18535 * @see #postInvalidateDelayed(long, int, int, int, int) 18536 */ postInvalidate(int left, int top, int right, int bottom)18537 public void postInvalidate(int left, int top, int right, int bottom) { 18538 postInvalidateDelayed(0, left, top, right, bottom); 18539 } 18540 18541 /** 18542 * <p>Cause an invalidate to happen on a subsequent cycle through the event 18543 * loop. Waits for the specified amount of time.</p> 18544 * 18545 * <p>This method can be invoked from outside of the UI thread 18546 * only when this View is attached to a window.</p> 18547 * 18548 * @param delayMilliseconds the duration in milliseconds to delay the 18549 * invalidation by 18550 * 18551 * @see #invalidate() 18552 * @see #postInvalidate() 18553 */ postInvalidateDelayed(long delayMilliseconds)18554 public void postInvalidateDelayed(long delayMilliseconds) { 18555 // We try only with the AttachInfo because there's no point in invalidating 18556 // if we are not attached to our window 18557 final AttachInfo attachInfo = mAttachInfo; 18558 if (attachInfo != null) { 18559 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 18560 } 18561 } 18562 18563 /** 18564 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 18565 * through the event loop. Waits for the specified amount of time.</p> 18566 * 18567 * <p>This method can be invoked from outside of the UI thread 18568 * only when this View is attached to a window.</p> 18569 * 18570 * @param delayMilliseconds the duration in milliseconds to delay the 18571 * invalidation by 18572 * @param left The left coordinate of the rectangle to invalidate. 18573 * @param top The top coordinate of the rectangle to invalidate. 18574 * @param right The right coordinate of the rectangle to invalidate. 18575 * @param bottom The bottom coordinate of the rectangle to invalidate. 18576 * 18577 * @see #invalidate(int, int, int, int) 18578 * @see #invalidate(Rect) 18579 * @see #postInvalidate(int, int, int, int) 18580 */ postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom)18581 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 18582 int right, int bottom) { 18583 18584 // We try only with the AttachInfo because there's no point in invalidating 18585 // if we are not attached to our window 18586 final AttachInfo attachInfo = mAttachInfo; 18587 if (attachInfo != null) { 18588 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 18589 info.target = this; 18590 info.left = left; 18591 info.top = top; 18592 info.right = right; 18593 info.bottom = bottom; 18594 18595 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 18596 } 18597 } 18598 18599 /** 18600 * <p>Cause an invalidate to happen on the next animation time step, typically the 18601 * next display frame.</p> 18602 * 18603 * <p>This method can be invoked from outside of the UI thread 18604 * only when this View is attached to a window.</p> 18605 * 18606 * @see #invalidate() 18607 */ postInvalidateOnAnimation()18608 public void postInvalidateOnAnimation() { 18609 // We try only with the AttachInfo because there's no point in invalidating 18610 // if we are not attached to our window 18611 final AttachInfo attachInfo = mAttachInfo; 18612 if (attachInfo != null) { 18613 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 18614 } 18615 } 18616 18617 /** 18618 * <p>Cause an invalidate of the specified area to happen on the next animation 18619 * time step, typically the next display frame.</p> 18620 * 18621 * <p>This method can be invoked from outside of the UI thread 18622 * only when this View is attached to a window.</p> 18623 * 18624 * @param left The left coordinate of the rectangle to invalidate. 18625 * @param top The top coordinate of the rectangle to invalidate. 18626 * @param right The right coordinate of the rectangle to invalidate. 18627 * @param bottom The bottom coordinate of the rectangle to invalidate. 18628 * 18629 * @see #invalidate(int, int, int, int) 18630 * @see #invalidate(Rect) 18631 */ postInvalidateOnAnimation(int left, int top, int right, int bottom)18632 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 18633 // We try only with the AttachInfo because there's no point in invalidating 18634 // if we are not attached to our window 18635 final AttachInfo attachInfo = mAttachInfo; 18636 if (attachInfo != null) { 18637 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 18638 info.target = this; 18639 info.left = left; 18640 info.top = top; 18641 info.right = right; 18642 info.bottom = bottom; 18643 18644 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 18645 } 18646 } 18647 18648 /** 18649 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 18650 * This event is sent at most once every 18651 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 18652 */ postSendViewScrolledAccessibilityEventCallback(int dx, int dy)18653 private void postSendViewScrolledAccessibilityEventCallback(int dx, int dy) { 18654 if (mSendViewScrolledAccessibilityEvent == null) { 18655 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 18656 } 18657 mSendViewScrolledAccessibilityEvent.post(dx, dy); 18658 } 18659 18660 /** 18661 * Called by a parent to request that a child update its values for mScrollX 18662 * and mScrollY if necessary. This will typically be done if the child is 18663 * animating a scroll using a {@link android.widget.Scroller Scroller} 18664 * object. 18665 */ computeScroll()18666 public void computeScroll() { 18667 } 18668 18669 /** 18670 * <p>Indicate whether the horizontal edges are faded when the view is 18671 * scrolled horizontally.</p> 18672 * 18673 * @return true if the horizontal edges should are faded on scroll, false 18674 * otherwise 18675 * 18676 * @see #setHorizontalFadingEdgeEnabled(boolean) 18677 * 18678 * @attr ref android.R.styleable#View_requiresFadingEdge 18679 */ isHorizontalFadingEdgeEnabled()18680 public boolean isHorizontalFadingEdgeEnabled() { 18681 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 18682 } 18683 18684 /** 18685 * <p>Define whether the horizontal edges should be faded when this view 18686 * is scrolled horizontally.</p> 18687 * 18688 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 18689 * be faded when the view is scrolled 18690 * horizontally 18691 * 18692 * @see #isHorizontalFadingEdgeEnabled() 18693 * 18694 * @attr ref android.R.styleable#View_requiresFadingEdge 18695 */ setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled)18696 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 18697 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 18698 if (horizontalFadingEdgeEnabled) { 18699 initScrollCache(); 18700 } 18701 18702 mViewFlags ^= FADING_EDGE_HORIZONTAL; 18703 } 18704 } 18705 18706 /** 18707 * <p>Indicate whether the vertical edges are faded when the view is 18708 * scrolled horizontally.</p> 18709 * 18710 * @return true if the vertical edges should are faded on scroll, false 18711 * otherwise 18712 * 18713 * @see #setVerticalFadingEdgeEnabled(boolean) 18714 * 18715 * @attr ref android.R.styleable#View_requiresFadingEdge 18716 */ isVerticalFadingEdgeEnabled()18717 public boolean isVerticalFadingEdgeEnabled() { 18718 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 18719 } 18720 18721 /** 18722 * <p>Define whether the vertical edges should be faded when this view 18723 * is scrolled vertically.</p> 18724 * 18725 * @param verticalFadingEdgeEnabled true if the vertical edges should 18726 * be faded when the view is scrolled 18727 * vertically 18728 * 18729 * @see #isVerticalFadingEdgeEnabled() 18730 * 18731 * @attr ref android.R.styleable#View_requiresFadingEdge 18732 */ setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled)18733 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 18734 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 18735 if (verticalFadingEdgeEnabled) { 18736 initScrollCache(); 18737 } 18738 18739 mViewFlags ^= FADING_EDGE_VERTICAL; 18740 } 18741 } 18742 18743 /** 18744 * Get the fading edge flags, used for inspection. 18745 * 18746 * @return One of {@link #FADING_EDGE_NONE}, {@link #FADING_EDGE_VERTICAL}, 18747 * or {@link #FADING_EDGE_HORIZONTAL} 18748 * @hide 18749 */ 18750 @InspectableProperty(name = "requiresFadingEdge", flagMapping = { 18751 @FlagEntry(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"), 18752 @FlagEntry(target = FADING_EDGE_VERTICAL, name = "vertical"), 18753 @FlagEntry(target = FADING_EDGE_HORIZONTAL, name = "horizontal") 18754 }) getFadingEdge()18755 public int getFadingEdge() { 18756 return mViewFlags & FADING_EDGE_MASK; 18757 } 18758 18759 /** 18760 * Get the fading edge length, used for inspection 18761 * 18762 * @return The fading edge length or 0 18763 * @hide 18764 */ 18765 @InspectableProperty getFadingEdgeLength()18766 public int getFadingEdgeLength() { 18767 if (mScrollCache != null && (mViewFlags & FADING_EDGE_MASK) != FADING_EDGE_NONE) { 18768 return mScrollCache.fadingEdgeLength; 18769 } 18770 return 0; 18771 } 18772 18773 /** 18774 * Returns the strength, or intensity, of the top faded edge. The strength is 18775 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 18776 * returns 0.0 or 1.0 but no value in between. 18777 * 18778 * Subclasses should override this method to provide a smoother fade transition 18779 * when scrolling occurs. 18780 * 18781 * @return the intensity of the top fade as a float between 0.0f and 1.0f 18782 */ getTopFadingEdgeStrength()18783 protected float getTopFadingEdgeStrength() { 18784 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 18785 } 18786 18787 /** 18788 * Returns the strength, or intensity, of the bottom faded edge. The strength is 18789 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 18790 * returns 0.0 or 1.0 but no value in between. 18791 * 18792 * Subclasses should override this method to provide a smoother fade transition 18793 * when scrolling occurs. 18794 * 18795 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 18796 */ getBottomFadingEdgeStrength()18797 protected float getBottomFadingEdgeStrength() { 18798 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 18799 computeVerticalScrollRange() ? 1.0f : 0.0f; 18800 } 18801 18802 /** 18803 * Returns the strength, or intensity, of the left faded edge. The strength is 18804 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 18805 * returns 0.0 or 1.0 but no value in between. 18806 * 18807 * Subclasses should override this method to provide a smoother fade transition 18808 * when scrolling occurs. 18809 * 18810 * @return the intensity of the left fade as a float between 0.0f and 1.0f 18811 */ getLeftFadingEdgeStrength()18812 protected float getLeftFadingEdgeStrength() { 18813 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 18814 } 18815 18816 /** 18817 * Returns the strength, or intensity, of the right faded edge. The strength is 18818 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 18819 * returns 0.0 or 1.0 but no value in between. 18820 * 18821 * Subclasses should override this method to provide a smoother fade transition 18822 * when scrolling occurs. 18823 * 18824 * @return the intensity of the right fade as a float between 0.0f and 1.0f 18825 */ getRightFadingEdgeStrength()18826 protected float getRightFadingEdgeStrength() { 18827 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 18828 computeHorizontalScrollRange() ? 1.0f : 0.0f; 18829 } 18830 18831 /** 18832 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 18833 * scrollbar is not drawn by default.</p> 18834 * 18835 * @return true if the horizontal scrollbar should be painted, false 18836 * otherwise 18837 * 18838 * @see #setHorizontalScrollBarEnabled(boolean) 18839 */ isHorizontalScrollBarEnabled()18840 public boolean isHorizontalScrollBarEnabled() { 18841 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 18842 } 18843 18844 /** 18845 * <p>Define whether the horizontal scrollbar should be drawn or not. The 18846 * scrollbar is not drawn by default.</p> 18847 * 18848 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 18849 * be painted 18850 * 18851 * @see #isHorizontalScrollBarEnabled() 18852 */ setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled)18853 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 18854 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 18855 mViewFlags ^= SCROLLBARS_HORIZONTAL; 18856 computeOpaqueFlags(); 18857 resolvePadding(); 18858 } 18859 } 18860 18861 /** 18862 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 18863 * scrollbar is not drawn by default.</p> 18864 * 18865 * @return true if the vertical scrollbar should be painted, false 18866 * otherwise 18867 * 18868 * @see #setVerticalScrollBarEnabled(boolean) 18869 */ isVerticalScrollBarEnabled()18870 public boolean isVerticalScrollBarEnabled() { 18871 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 18872 } 18873 18874 /** 18875 * <p>Define whether the vertical scrollbar should be drawn or not. The 18876 * scrollbar is not drawn by default.</p> 18877 * 18878 * @param verticalScrollBarEnabled true if the vertical scrollbar should 18879 * be painted 18880 * 18881 * @see #isVerticalScrollBarEnabled() 18882 */ setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled)18883 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 18884 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 18885 mViewFlags ^= SCROLLBARS_VERTICAL; 18886 computeOpaqueFlags(); 18887 resolvePadding(); 18888 } 18889 } 18890 18891 /** 18892 * @hide 18893 */ 18894 @UnsupportedAppUsage recomputePadding()18895 protected void recomputePadding() { 18896 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 18897 } 18898 18899 /** 18900 * Define whether scrollbars will fade when the view is not scrolling. 18901 * 18902 * @param fadeScrollbars whether to enable fading 18903 * 18904 * @attr ref android.R.styleable#View_fadeScrollbars 18905 */ setScrollbarFadingEnabled(boolean fadeScrollbars)18906 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 18907 initScrollCache(); 18908 final ScrollabilityCache scrollabilityCache = mScrollCache; 18909 scrollabilityCache.fadeScrollBars = fadeScrollbars; 18910 if (fadeScrollbars) { 18911 scrollabilityCache.state = ScrollabilityCache.OFF; 18912 } else { 18913 scrollabilityCache.state = ScrollabilityCache.ON; 18914 } 18915 } 18916 18917 /** 18918 * 18919 * Returns true if scrollbars will fade when this view is not scrolling 18920 * 18921 * @return true if scrollbar fading is enabled 18922 * 18923 * @attr ref android.R.styleable#View_fadeScrollbars 18924 */ isScrollbarFadingEnabled()18925 public boolean isScrollbarFadingEnabled() { 18926 return mScrollCache != null && mScrollCache.fadeScrollBars; 18927 } 18928 18929 /** 18930 * 18931 * Returns the delay before scrollbars fade. 18932 * 18933 * @return the delay before scrollbars fade 18934 * 18935 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 18936 */ 18937 @InspectableProperty(name = "scrollbarDefaultDelayBeforeFade") getScrollBarDefaultDelayBeforeFade()18938 public int getScrollBarDefaultDelayBeforeFade() { 18939 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 18940 mScrollCache.scrollBarDefaultDelayBeforeFade; 18941 } 18942 18943 /** 18944 * Define the delay before scrollbars fade. 18945 * 18946 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 18947 * 18948 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 18949 */ setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade)18950 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 18951 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 18952 } 18953 18954 /** 18955 * 18956 * Returns the scrollbar fade duration. 18957 * 18958 * @return the scrollbar fade duration, in milliseconds 18959 * 18960 * @attr ref android.R.styleable#View_scrollbarFadeDuration 18961 */ 18962 @InspectableProperty(name = "scrollbarFadeDuration") getScrollBarFadeDuration()18963 public int getScrollBarFadeDuration() { 18964 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 18965 mScrollCache.scrollBarFadeDuration; 18966 } 18967 18968 /** 18969 * Define the scrollbar fade duration. 18970 * 18971 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 18972 * 18973 * @attr ref android.R.styleable#View_scrollbarFadeDuration 18974 */ setScrollBarFadeDuration(int scrollBarFadeDuration)18975 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 18976 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 18977 } 18978 18979 /** 18980 * 18981 * Returns the scrollbar size. 18982 * 18983 * @return the scrollbar size 18984 * 18985 * @attr ref android.R.styleable#View_scrollbarSize 18986 */ 18987 @InspectableProperty(name = "scrollbarSize") getScrollBarSize()18988 public int getScrollBarSize() { 18989 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 18990 mScrollCache.scrollBarSize; 18991 } 18992 18993 /** 18994 * Define the scrollbar size. 18995 * 18996 * @param scrollBarSize - the scrollbar size 18997 * 18998 * @attr ref android.R.styleable#View_scrollbarSize 18999 */ setScrollBarSize(int scrollBarSize)19000 public void setScrollBarSize(int scrollBarSize) { 19001 getScrollCache().scrollBarSize = scrollBarSize; 19002 } 19003 19004 /** 19005 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 19006 * inset. When inset, they add to the padding of the view. And the scrollbars 19007 * can be drawn inside the padding area or on the edge of the view. For example, 19008 * if a view has a background drawable and you want to draw the scrollbars 19009 * inside the padding specified by the drawable, you can use 19010 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 19011 * appear at the edge of the view, ignoring the padding, then you can use 19012 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 19013 * @param style the style of the scrollbars. Should be one of 19014 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 19015 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 19016 * @see #SCROLLBARS_INSIDE_OVERLAY 19017 * @see #SCROLLBARS_INSIDE_INSET 19018 * @see #SCROLLBARS_OUTSIDE_OVERLAY 19019 * @see #SCROLLBARS_OUTSIDE_INSET 19020 * 19021 * @attr ref android.R.styleable#View_scrollbarStyle 19022 */ setScrollBarStyle(@crollBarStyle int style)19023 public void setScrollBarStyle(@ScrollBarStyle int style) { 19024 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 19025 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 19026 computeOpaqueFlags(); 19027 resolvePadding(); 19028 } 19029 } 19030 19031 /** 19032 * <p>Returns the current scrollbar style.</p> 19033 * @return the current scrollbar style 19034 * @see #SCROLLBARS_INSIDE_OVERLAY 19035 * @see #SCROLLBARS_INSIDE_INSET 19036 * @see #SCROLLBARS_OUTSIDE_OVERLAY 19037 * @see #SCROLLBARS_OUTSIDE_INSET 19038 * 19039 * @attr ref android.R.styleable#View_scrollbarStyle 19040 */ 19041 @ViewDebug.ExportedProperty(mapping = { 19042 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 19043 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 19044 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 19045 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 19046 }) 19047 @InspectableProperty(name = "scrollbarStyle", enumMapping = { 19048 @EnumEntry(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"), 19049 @EnumEntry(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"), 19050 @EnumEntry(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"), 19051 @EnumEntry(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset") 19052 }) 19053 @ScrollBarStyle getScrollBarStyle()19054 public int getScrollBarStyle() { 19055 return mViewFlags & SCROLLBARS_STYLE_MASK; 19056 } 19057 19058 /** 19059 * <p>Compute the horizontal range that the horizontal scrollbar 19060 * represents.</p> 19061 * 19062 * <p>The range is expressed in arbitrary units that must be the same as the 19063 * units used by {@link #computeHorizontalScrollExtent()} and 19064 * {@link #computeHorizontalScrollOffset()}.</p> 19065 * 19066 * <p>The default range is the drawing width of this view.</p> 19067 * 19068 * @return the total horizontal range represented by the horizontal 19069 * scrollbar 19070 * 19071 * @see #computeHorizontalScrollExtent() 19072 * @see #computeHorizontalScrollOffset() 19073 */ computeHorizontalScrollRange()19074 protected int computeHorizontalScrollRange() { 19075 return getWidth(); 19076 } 19077 19078 /** 19079 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 19080 * within the horizontal range. This value is used to compute the position 19081 * of the thumb within the scrollbar's track.</p> 19082 * 19083 * <p>The range is expressed in arbitrary units that must be the same as the 19084 * units used by {@link #computeHorizontalScrollRange()} and 19085 * {@link #computeHorizontalScrollExtent()}.</p> 19086 * 19087 * <p>The default offset is the scroll offset of this view.</p> 19088 * 19089 * @return the horizontal offset of the scrollbar's thumb 19090 * 19091 * @see #computeHorizontalScrollRange() 19092 * @see #computeHorizontalScrollExtent() 19093 */ computeHorizontalScrollOffset()19094 protected int computeHorizontalScrollOffset() { 19095 return mScrollX; 19096 } 19097 19098 /** 19099 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 19100 * within the horizontal range. This value is used to compute the length 19101 * of the thumb within the scrollbar's track.</p> 19102 * 19103 * <p>The range is expressed in arbitrary units that must be the same as the 19104 * units used by {@link #computeHorizontalScrollRange()} and 19105 * {@link #computeHorizontalScrollOffset()}.</p> 19106 * 19107 * <p>The default extent is the drawing width of this view.</p> 19108 * 19109 * @return the horizontal extent of the scrollbar's thumb 19110 * 19111 * @see #computeHorizontalScrollRange() 19112 * @see #computeHorizontalScrollOffset() 19113 */ computeHorizontalScrollExtent()19114 protected int computeHorizontalScrollExtent() { 19115 return getWidth(); 19116 } 19117 19118 /** 19119 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 19120 * 19121 * <p>The range is expressed in arbitrary units that must be the same as the 19122 * units used by {@link #computeVerticalScrollExtent()} and 19123 * {@link #computeVerticalScrollOffset()}.</p> 19124 * 19125 * @return the total vertical range represented by the vertical scrollbar 19126 * 19127 * <p>The default range is the drawing height of this view.</p> 19128 * 19129 * @see #computeVerticalScrollExtent() 19130 * @see #computeVerticalScrollOffset() 19131 */ computeVerticalScrollRange()19132 protected int computeVerticalScrollRange() { 19133 return getHeight(); 19134 } 19135 19136 /** 19137 * <p>Compute the vertical offset of the vertical scrollbar's thumb 19138 * within the horizontal range. This value is used to compute the position 19139 * of the thumb within the scrollbar's track.</p> 19140 * 19141 * <p>The range is expressed in arbitrary units that must be the same as the 19142 * units used by {@link #computeVerticalScrollRange()} and 19143 * {@link #computeVerticalScrollExtent()}.</p> 19144 * 19145 * <p>The default offset is the scroll offset of this view.</p> 19146 * 19147 * @return the vertical offset of the scrollbar's thumb 19148 * 19149 * @see #computeVerticalScrollRange() 19150 * @see #computeVerticalScrollExtent() 19151 */ computeVerticalScrollOffset()19152 protected int computeVerticalScrollOffset() { 19153 return mScrollY; 19154 } 19155 19156 /** 19157 * <p>Compute the vertical extent of the vertical scrollbar's thumb 19158 * within the vertical range. This value is used to compute the length 19159 * of the thumb within the scrollbar's track.</p> 19160 * 19161 * <p>The range is expressed in arbitrary units that must be the same as the 19162 * units used by {@link #computeVerticalScrollRange()} and 19163 * {@link #computeVerticalScrollOffset()}.</p> 19164 * 19165 * <p>The default extent is the drawing height of this view.</p> 19166 * 19167 * @return the vertical extent of the scrollbar's thumb 19168 * 19169 * @see #computeVerticalScrollRange() 19170 * @see #computeVerticalScrollOffset() 19171 */ computeVerticalScrollExtent()19172 protected int computeVerticalScrollExtent() { 19173 return getHeight(); 19174 } 19175 19176 /** 19177 * Check if this view can be scrolled horizontally in a certain direction. 19178 * 19179 * @param direction Negative to check scrolling left, positive to check scrolling right. 19180 * @return true if this view can be scrolled in the specified direction, false otherwise. 19181 */ canScrollHorizontally(int direction)19182 public boolean canScrollHorizontally(int direction) { 19183 final int offset = computeHorizontalScrollOffset(); 19184 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 19185 if (range == 0) return false; 19186 if (direction < 0) { 19187 return offset > 0; 19188 } else { 19189 return offset < range - 1; 19190 } 19191 } 19192 19193 /** 19194 * Check if this view can be scrolled vertically in a certain direction. 19195 * 19196 * @param direction Negative to check scrolling up, positive to check scrolling down. 19197 * @return true if this view can be scrolled in the specified direction, false otherwise. 19198 */ canScrollVertically(int direction)19199 public boolean canScrollVertically(int direction) { 19200 final int offset = computeVerticalScrollOffset(); 19201 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 19202 if (range == 0) return false; 19203 if (direction < 0) { 19204 return offset > 0; 19205 } else { 19206 return offset < range - 1; 19207 } 19208 } 19209 getScrollIndicatorBounds(@onNull Rect out)19210 void getScrollIndicatorBounds(@NonNull Rect out) { 19211 out.left = mScrollX; 19212 out.right = mScrollX + mRight - mLeft; 19213 out.top = mScrollY; 19214 out.bottom = mScrollY + mBottom - mTop; 19215 } 19216 onDrawScrollIndicators(Canvas c)19217 private void onDrawScrollIndicators(Canvas c) { 19218 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 19219 // No scroll indicators enabled. 19220 return; 19221 } 19222 19223 final Drawable dr = mScrollIndicatorDrawable; 19224 if (dr == null) { 19225 // Scroll indicators aren't supported here. 19226 return; 19227 } 19228 19229 final int h = dr.getIntrinsicHeight(); 19230 final int w = dr.getIntrinsicWidth(); 19231 final Rect rect = mAttachInfo.mTmpInvalRect; 19232 getScrollIndicatorBounds(rect); 19233 19234 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 19235 final boolean canScrollUp = canScrollVertically(-1); 19236 if (canScrollUp) { 19237 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 19238 dr.draw(c); 19239 } 19240 } 19241 19242 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 19243 final boolean canScrollDown = canScrollVertically(1); 19244 if (canScrollDown) { 19245 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 19246 dr.draw(c); 19247 } 19248 } 19249 19250 final int leftRtl; 19251 final int rightRtl; 19252 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 19253 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 19254 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 19255 } else { 19256 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 19257 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 19258 } 19259 19260 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 19261 if ((mPrivateFlags3 & leftMask) != 0) { 19262 final boolean canScrollLeft = canScrollHorizontally(-1); 19263 if (canScrollLeft) { 19264 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 19265 dr.draw(c); 19266 } 19267 } 19268 19269 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 19270 if ((mPrivateFlags3 & rightMask) != 0) { 19271 final boolean canScrollRight = canScrollHorizontally(1); 19272 if (canScrollRight) { 19273 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 19274 dr.draw(c); 19275 } 19276 } 19277 } 19278 getHorizontalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)19279 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 19280 @Nullable Rect touchBounds) { 19281 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 19282 if (bounds == null) { 19283 return; 19284 } 19285 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 19286 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 19287 && !isVerticalScrollBarHidden(); 19288 final int size = getHorizontalScrollbarHeight(); 19289 final int verticalScrollBarGap = drawVerticalScrollBar ? 19290 getVerticalScrollbarWidth() : 0; 19291 final int width = mRight - mLeft; 19292 final int height = mBottom - mTop; 19293 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 19294 bounds.left = mScrollX + (mPaddingLeft & inside); 19295 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 19296 bounds.bottom = bounds.top + size; 19297 19298 if (touchBounds == null) { 19299 return; 19300 } 19301 if (touchBounds != bounds) { 19302 touchBounds.set(bounds); 19303 } 19304 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 19305 if (touchBounds.height() < minTouchTarget) { 19306 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 19307 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 19308 touchBounds.top = touchBounds.bottom - minTouchTarget; 19309 } 19310 if (touchBounds.width() < minTouchTarget) { 19311 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 19312 touchBounds.left -= adjust; 19313 touchBounds.right = touchBounds.left + minTouchTarget; 19314 } 19315 } 19316 getVerticalScrollBarBounds(@ullable Rect bounds, @Nullable Rect touchBounds)19317 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 19318 if (mRoundScrollbarRenderer == null) { 19319 getStraightVerticalScrollBarBounds(bounds, touchBounds); 19320 } else { 19321 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds); 19322 } 19323 } 19324 getRoundVerticalScrollBarBounds(Rect bounds)19325 private void getRoundVerticalScrollBarBounds(Rect bounds) { 19326 final int width = mRight - mLeft; 19327 final int height = mBottom - mTop; 19328 // Do not take padding into account as we always want the scrollbars 19329 // to hug the screen for round wearable devices. 19330 bounds.left = mScrollX; 19331 bounds.top = mScrollY; 19332 bounds.right = bounds.left + width; 19333 bounds.bottom = mScrollY + height; 19334 } 19335 getStraightVerticalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)19336 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 19337 @Nullable Rect touchBounds) { 19338 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 19339 if (bounds == null) { 19340 return; 19341 } 19342 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 19343 final int size = getVerticalScrollbarWidth(); 19344 int verticalScrollbarPosition = mVerticalScrollbarPosition; 19345 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 19346 verticalScrollbarPosition = isLayoutRtl() ? 19347 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 19348 } 19349 final int width = mRight - mLeft; 19350 final int height = mBottom - mTop; 19351 switch (verticalScrollbarPosition) { 19352 default: 19353 case SCROLLBAR_POSITION_RIGHT: 19354 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 19355 break; 19356 case SCROLLBAR_POSITION_LEFT: 19357 bounds.left = mScrollX + (mUserPaddingLeft & inside); 19358 break; 19359 } 19360 bounds.top = mScrollY + (mPaddingTop & inside); 19361 bounds.right = bounds.left + size; 19362 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 19363 19364 if (touchBounds == null) { 19365 return; 19366 } 19367 if (touchBounds != bounds) { 19368 touchBounds.set(bounds); 19369 } 19370 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 19371 if (touchBounds.width() < minTouchTarget) { 19372 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 19373 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 19374 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 19375 touchBounds.left = touchBounds.right - minTouchTarget; 19376 } else { 19377 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 19378 touchBounds.right = touchBounds.left + minTouchTarget; 19379 } 19380 } 19381 if (touchBounds.height() < minTouchTarget) { 19382 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 19383 touchBounds.top -= adjust; 19384 touchBounds.bottom = touchBounds.top + minTouchTarget; 19385 } 19386 } 19387 19388 /** 19389 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 19390 * scrollbars are painted only if they have been awakened first.</p> 19391 * 19392 * @param canvas the canvas on which to draw the scrollbars 19393 * 19394 * @see #awakenScrollBars(int) 19395 */ onDrawScrollBars(Canvas canvas)19396 protected final void onDrawScrollBars(Canvas canvas) { 19397 // scrollbars are drawn only when the animation is running 19398 final ScrollabilityCache cache = mScrollCache; 19399 19400 if (cache != null) { 19401 19402 int state = cache.state; 19403 19404 if (state == ScrollabilityCache.OFF) { 19405 return; 19406 } 19407 19408 boolean invalidate = false; 19409 19410 if (state == ScrollabilityCache.FADING) { 19411 // We're fading -- get our fade interpolation 19412 if (cache.interpolatorValues == null) { 19413 cache.interpolatorValues = new float[1]; 19414 } 19415 19416 float[] values = cache.interpolatorValues; 19417 19418 // Stops the animation if we're done 19419 if (cache.scrollBarInterpolator.timeToValues(values) == 19420 Interpolator.Result.FREEZE_END) { 19421 cache.state = ScrollabilityCache.OFF; 19422 } else { 19423 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 19424 } 19425 19426 // This will make the scroll bars inval themselves after 19427 // drawing. We only want this when we're fading so that 19428 // we prevent excessive redraws 19429 invalidate = true; 19430 } else { 19431 // We're just on -- but we may have been fading before so 19432 // reset alpha 19433 cache.scrollBar.mutate().setAlpha(255); 19434 } 19435 19436 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 19437 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 19438 && !isVerticalScrollBarHidden(); 19439 19440 // Fork out the scroll bar drawing for round wearable devices. 19441 if (mRoundScrollbarRenderer != null) { 19442 if (drawVerticalScrollBar) { 19443 final Rect bounds = cache.mScrollBarBounds; 19444 getVerticalScrollBarBounds(bounds, null); 19445 mRoundScrollbarRenderer.drawRoundScrollbars( 19446 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 19447 if (invalidate) { 19448 invalidate(); 19449 } 19450 } 19451 // Do not draw horizontal scroll bars for round wearable devices. 19452 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 19453 final ScrollBarDrawable scrollBar = cache.scrollBar; 19454 19455 if (drawHorizontalScrollBar) { 19456 scrollBar.setParameters(computeHorizontalScrollRange(), 19457 computeHorizontalScrollOffset(), 19458 computeHorizontalScrollExtent(), false); 19459 final Rect bounds = cache.mScrollBarBounds; 19460 getHorizontalScrollBarBounds(bounds, null); 19461 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 19462 bounds.right, bounds.bottom); 19463 if (invalidate) { 19464 invalidate(bounds); 19465 } 19466 } 19467 19468 if (drawVerticalScrollBar) { 19469 scrollBar.setParameters(computeVerticalScrollRange(), 19470 computeVerticalScrollOffset(), 19471 computeVerticalScrollExtent(), true); 19472 final Rect bounds = cache.mScrollBarBounds; 19473 getVerticalScrollBarBounds(bounds, null); 19474 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 19475 bounds.right, bounds.bottom); 19476 if (invalidate) { 19477 invalidate(bounds); 19478 } 19479 } 19480 } 19481 } 19482 } 19483 19484 /** 19485 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 19486 * FastScroller is visible. 19487 * @return whether to temporarily hide the vertical scrollbar 19488 * @hide 19489 */ isVerticalScrollBarHidden()19490 protected boolean isVerticalScrollBarHidden() { 19491 return false; 19492 } 19493 19494 /** 19495 * <p>Draw the horizontal scrollbar if 19496 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 19497 * 19498 * @param canvas the canvas on which to draw the scrollbar 19499 * @param scrollBar the scrollbar's drawable 19500 * 19501 * @see #isHorizontalScrollBarEnabled() 19502 * @see #computeHorizontalScrollRange() 19503 * @see #computeHorizontalScrollExtent() 19504 * @see #computeHorizontalScrollOffset() 19505 * @hide 19506 */ 19507 @UnsupportedAppUsage onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)19508 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 19509 int l, int t, int r, int b) { 19510 scrollBar.setBounds(l, t, r, b); 19511 scrollBar.draw(canvas); 19512 } 19513 19514 /** 19515 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 19516 * returns true.</p> 19517 * 19518 * @param canvas the canvas on which to draw the scrollbar 19519 * @param scrollBar the scrollbar's drawable 19520 * 19521 * @see #isVerticalScrollBarEnabled() 19522 * @see #computeVerticalScrollRange() 19523 * @see #computeVerticalScrollExtent() 19524 * @see #computeVerticalScrollOffset() 19525 * @hide 19526 */ 19527 @UnsupportedAppUsage onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)19528 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 19529 int l, int t, int r, int b) { 19530 scrollBar.setBounds(l, t, r, b); 19531 scrollBar.draw(canvas); 19532 } 19533 19534 /** 19535 * Implement this to do your drawing. 19536 * 19537 * @param canvas the canvas on which the background will be drawn 19538 */ onDraw(Canvas canvas)19539 protected void onDraw(Canvas canvas) { 19540 } 19541 19542 /* 19543 * Caller is responsible for calling requestLayout if necessary. 19544 * (This allows addViewInLayout to not request a new layout.) 19545 */ 19546 @UnsupportedAppUsage assignParent(ViewParent parent)19547 void assignParent(ViewParent parent) { 19548 if (mParent == null) { 19549 mParent = parent; 19550 } else if (parent == null) { 19551 mParent = null; 19552 } else { 19553 throw new RuntimeException("view " + this + " being added, but" 19554 + " it already has a parent"); 19555 } 19556 } 19557 19558 /** 19559 * This is called when the view is attached to a window. At this point it 19560 * has a Surface and will start drawing. Note that this function is 19561 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 19562 * however it may be called any time before the first onDraw -- including 19563 * before or after {@link #onMeasure(int, int)}. 19564 * 19565 * @see #onDetachedFromWindow() 19566 */ 19567 @CallSuper onAttachedToWindow()19568 protected void onAttachedToWindow() { 19569 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 19570 mParent.requestTransparentRegion(this); 19571 } 19572 19573 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 19574 19575 jumpDrawablesToCurrentState(); 19576 19577 AccessibilityNodeIdManager.getInstance().registerViewWithId(this, getAccessibilityViewId()); 19578 resetSubtreeAccessibilityStateChanged(); 19579 19580 // rebuild, since Outline not maintained while View is detached 19581 rebuildOutline(); 19582 19583 if (isFocused()) { 19584 notifyFocusChangeToInputMethodManager(true /* hasFocus */); 19585 } 19586 } 19587 19588 /** 19589 * Resolve all RTL related properties. 19590 * 19591 * @return true if resolution of RTL properties has been done 19592 * 19593 * @hide 19594 */ resolveRtlPropertiesIfNeeded()19595 public boolean resolveRtlPropertiesIfNeeded() { 19596 if (!needRtlPropertiesResolution()) return false; 19597 19598 // Order is important here: LayoutDirection MUST be resolved first 19599 if (!isLayoutDirectionResolved()) { 19600 resolveLayoutDirection(); 19601 resolveLayoutParams(); 19602 } 19603 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 19604 if (!isTextDirectionResolved()) { 19605 resolveTextDirection(); 19606 } 19607 if (!isTextAlignmentResolved()) { 19608 resolveTextAlignment(); 19609 } 19610 // Should resolve Drawables before Padding because we need the layout direction of the 19611 // Drawable to correctly resolve Padding. 19612 if (!areDrawablesResolved()) { 19613 resolveDrawables(); 19614 } 19615 if (!isPaddingResolved()) { 19616 resolvePadding(); 19617 } 19618 onRtlPropertiesChanged(getLayoutDirection()); 19619 return true; 19620 } 19621 19622 /** 19623 * Reset resolution of all RTL related properties. 19624 * 19625 * @hide 19626 */ 19627 @TestApi resetRtlProperties()19628 public void resetRtlProperties() { 19629 resetResolvedLayoutDirection(); 19630 resetResolvedTextDirection(); 19631 resetResolvedTextAlignment(); 19632 resetResolvedPadding(); 19633 resetResolvedDrawables(); 19634 } 19635 19636 /** 19637 * @see #onScreenStateChanged(int) 19638 */ dispatchScreenStateChanged(int screenState)19639 void dispatchScreenStateChanged(int screenState) { 19640 onScreenStateChanged(screenState); 19641 } 19642 19643 /** 19644 * This method is called whenever the state of the screen this view is 19645 * attached to changes. A state change will usually occurs when the screen 19646 * turns on or off (whether it happens automatically or the user does it 19647 * manually.) 19648 * 19649 * @param screenState The new state of the screen. Can be either 19650 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 19651 */ onScreenStateChanged(int screenState)19652 public void onScreenStateChanged(int screenState) { 19653 } 19654 19655 /** 19656 * @see #onMovedToDisplay(int, Configuration) 19657 */ dispatchMovedToDisplay(Display display, Configuration config)19658 void dispatchMovedToDisplay(Display display, Configuration config) { 19659 mAttachInfo.mDisplay = display; 19660 mAttachInfo.mDisplayState = display.getState(); 19661 onMovedToDisplay(display.getDisplayId(), config); 19662 } 19663 19664 /** 19665 * Called by the system when the hosting activity is moved from one display to another without 19666 * recreation. This means that the activity is declared to handle all changes to configuration 19667 * that happened when it was switched to another display, so it wasn't destroyed and created 19668 * again. 19669 * 19670 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 19671 * applied configuration actually changed. It is up to app developer to choose whether to handle 19672 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)} 19673 * call. 19674 * 19675 * <p>Use this callback to track changes to the displays if some functionality relies on an 19676 * association with some display properties. 19677 * 19678 * @param displayId The id of the display to which the view was moved. 19679 * @param config Configuration of the resources on new display after move. 19680 * 19681 * @see #onConfigurationChanged(Configuration) 19682 * @hide 19683 */ onMovedToDisplay(int displayId, Configuration config)19684 public void onMovedToDisplay(int displayId, Configuration config) { 19685 } 19686 19687 /** 19688 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 19689 */ 19690 @UnsupportedAppUsage hasRtlSupport()19691 private boolean hasRtlSupport() { 19692 return mContext.getApplicationInfo().hasRtlSupport(); 19693 } 19694 19695 /** 19696 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 19697 * RTL not supported) 19698 */ isRtlCompatibilityMode()19699 private boolean isRtlCompatibilityMode() { 19700 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 19701 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport(); 19702 } 19703 19704 /** 19705 * @return true if RTL properties need resolution. 19706 * 19707 */ needRtlPropertiesResolution()19708 private boolean needRtlPropertiesResolution() { 19709 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 19710 } 19711 19712 /** 19713 * Called when any RTL property (layout direction or text direction or text alignment) has 19714 * been changed. 19715 * 19716 * Subclasses need to override this method to take care of cached information that depends on the 19717 * resolved layout direction, or to inform child views that inherit their layout direction. 19718 * 19719 * The default implementation does nothing. 19720 * 19721 * @param layoutDirection the direction of the layout 19722 * 19723 * @see #LAYOUT_DIRECTION_LTR 19724 * @see #LAYOUT_DIRECTION_RTL 19725 */ onRtlPropertiesChanged(@esolvedLayoutDir int layoutDirection)19726 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 19727 } 19728 19729 /** 19730 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 19731 * that the parent directionality can and will be resolved before its children. 19732 * 19733 * @return true if resolution has been done, false otherwise. 19734 * 19735 * @hide 19736 */ resolveLayoutDirection()19737 public boolean resolveLayoutDirection() { 19738 // Clear any previous layout direction resolution 19739 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 19740 19741 if (hasRtlSupport()) { 19742 // Set resolved depending on layout direction 19743 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 19744 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 19745 case LAYOUT_DIRECTION_INHERIT: 19746 // We cannot resolve yet. LTR is by default and let the resolution happen again 19747 // later to get the correct resolved value 19748 if (!canResolveLayoutDirection()) return false; 19749 19750 // Parent has not yet resolved, LTR is still the default 19751 try { 19752 if (!mParent.isLayoutDirectionResolved()) return false; 19753 19754 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 19755 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 19756 } 19757 } catch (AbstractMethodError e) { 19758 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 19759 " does not fully implement ViewParent", e); 19760 } 19761 break; 19762 case LAYOUT_DIRECTION_RTL: 19763 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 19764 break; 19765 case LAYOUT_DIRECTION_LOCALE: 19766 if((LAYOUT_DIRECTION_RTL == 19767 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 19768 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 19769 } 19770 break; 19771 default: 19772 // Nothing to do, LTR by default 19773 } 19774 } 19775 19776 // Set to resolved 19777 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 19778 return true; 19779 } 19780 19781 /** 19782 * Check if layout direction resolution can be done. 19783 * 19784 * @return true if layout direction resolution can be done otherwise return false. 19785 */ canResolveLayoutDirection()19786 public boolean canResolveLayoutDirection() { 19787 switch (getRawLayoutDirection()) { 19788 case LAYOUT_DIRECTION_INHERIT: 19789 if (mParent != null) { 19790 try { 19791 return mParent.canResolveLayoutDirection(); 19792 } catch (AbstractMethodError e) { 19793 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 19794 " does not fully implement ViewParent", e); 19795 } 19796 } 19797 return false; 19798 19799 default: 19800 return true; 19801 } 19802 } 19803 19804 /** 19805 * Reset the resolved layout direction. Layout direction will be resolved during a call to 19806 * {@link #onMeasure(int, int)}. 19807 * 19808 * @hide 19809 */ 19810 @TestApi resetResolvedLayoutDirection()19811 public void resetResolvedLayoutDirection() { 19812 // Reset the current resolved bits 19813 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 19814 } 19815 19816 /** 19817 * @return true if the layout direction is inherited. 19818 * 19819 * @hide 19820 */ isLayoutDirectionInherited()19821 public boolean isLayoutDirectionInherited() { 19822 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 19823 } 19824 19825 /** 19826 * @return true if layout direction has been resolved. 19827 */ isLayoutDirectionResolved()19828 public boolean isLayoutDirectionResolved() { 19829 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 19830 } 19831 19832 /** 19833 * Return if padding has been resolved 19834 * 19835 * @hide 19836 */ 19837 @UnsupportedAppUsage isPaddingResolved()19838 boolean isPaddingResolved() { 19839 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 19840 } 19841 19842 /** 19843 * Resolves padding depending on layout direction, if applicable, and 19844 * recomputes internal padding values to adjust for scroll bars. 19845 * 19846 * @hide 19847 */ 19848 @UnsupportedAppUsage resolvePadding()19849 public void resolvePadding() { 19850 final int resolvedLayoutDirection = getLayoutDirection(); 19851 19852 if (!isRtlCompatibilityMode()) { 19853 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 19854 // If start / end padding are defined, they will be resolved (hence overriding) to 19855 // left / right or right / left depending on the resolved layout direction. 19856 // If start / end padding are not defined, use the left / right ones. 19857 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 19858 Rect padding = sThreadLocal.get(); 19859 if (padding == null) { 19860 padding = new Rect(); 19861 sThreadLocal.set(padding); 19862 } 19863 mBackground.getPadding(padding); 19864 if (!mLeftPaddingDefined) { 19865 mUserPaddingLeftInitial = padding.left; 19866 } 19867 if (!mRightPaddingDefined) { 19868 mUserPaddingRightInitial = padding.right; 19869 } 19870 } 19871 switch (resolvedLayoutDirection) { 19872 case LAYOUT_DIRECTION_RTL: 19873 if (mUserPaddingStart != UNDEFINED_PADDING) { 19874 mUserPaddingRight = mUserPaddingStart; 19875 } else { 19876 mUserPaddingRight = mUserPaddingRightInitial; 19877 } 19878 if (mUserPaddingEnd != UNDEFINED_PADDING) { 19879 mUserPaddingLeft = mUserPaddingEnd; 19880 } else { 19881 mUserPaddingLeft = mUserPaddingLeftInitial; 19882 } 19883 break; 19884 case LAYOUT_DIRECTION_LTR: 19885 default: 19886 if (mUserPaddingStart != UNDEFINED_PADDING) { 19887 mUserPaddingLeft = mUserPaddingStart; 19888 } else { 19889 mUserPaddingLeft = mUserPaddingLeftInitial; 19890 } 19891 if (mUserPaddingEnd != UNDEFINED_PADDING) { 19892 mUserPaddingRight = mUserPaddingEnd; 19893 } else { 19894 mUserPaddingRight = mUserPaddingRightInitial; 19895 } 19896 } 19897 19898 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 19899 } 19900 19901 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 19902 onRtlPropertiesChanged(resolvedLayoutDirection); 19903 19904 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 19905 } 19906 19907 /** 19908 * Reset the resolved layout direction. 19909 * 19910 * @hide 19911 */ 19912 @TestApi resetResolvedPadding()19913 public void resetResolvedPadding() { 19914 resetResolvedPaddingInternal(); 19915 } 19916 19917 /** 19918 * Used when we only want to reset *this* view's padding and not trigger overrides 19919 * in ViewGroup that reset children too. 19920 */ resetResolvedPaddingInternal()19921 void resetResolvedPaddingInternal() { 19922 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 19923 } 19924 19925 /** 19926 * This is called when the view is detached from a window. At this point it 19927 * no longer has a surface for drawing. 19928 * 19929 * @see #onAttachedToWindow() 19930 */ 19931 @CallSuper onDetachedFromWindow()19932 protected void onDetachedFromWindow() { 19933 } 19934 19935 /** 19936 * This is a framework-internal mirror of onDetachedFromWindow() that's called 19937 * after onDetachedFromWindow(). 19938 * 19939 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 19940 * The super method should be called at the end of the overridden method to ensure 19941 * subclasses are destroyed first 19942 * 19943 * @hide 19944 */ 19945 @CallSuper 19946 @UnsupportedAppUsage onDetachedFromWindowInternal()19947 protected void onDetachedFromWindowInternal() { 19948 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 19949 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 19950 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 19951 19952 removeUnsetPressCallback(); 19953 removeLongPressCallback(); 19954 removePerformClickCallback(); 19955 cancel(mSendViewScrolledAccessibilityEvent); 19956 stopNestedScroll(); 19957 19958 // Anything that started animating right before detach should already 19959 // be in its final state when re-attached. 19960 jumpDrawablesToCurrentState(); 19961 19962 destroyDrawingCache(); 19963 19964 cleanupDraw(); 19965 mCurrentAnimation = null; 19966 19967 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 19968 hideTooltip(); 19969 } 19970 19971 AccessibilityNodeIdManager.getInstance().unregisterViewWithId(getAccessibilityViewId()); 19972 } 19973 cleanupDraw()19974 private void cleanupDraw() { 19975 resetDisplayList(); 19976 if (mAttachInfo != null) { 19977 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 19978 } 19979 } 19980 invalidateInheritedLayoutMode(int layoutModeOfRoot)19981 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 19982 } 19983 19984 /** 19985 * @return The number of times this view has been attached to a window 19986 */ getWindowAttachCount()19987 protected int getWindowAttachCount() { 19988 return mWindowAttachCount; 19989 } 19990 19991 /** 19992 * Retrieve a unique token identifying the window this view is attached to. 19993 * @return Return the window's token for use in 19994 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 19995 */ getWindowToken()19996 public IBinder getWindowToken() { 19997 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 19998 } 19999 20000 /** 20001 * Retrieve the {@link WindowId} for the window this view is 20002 * currently attached to. 20003 */ getWindowId()20004 public WindowId getWindowId() { 20005 AttachInfo ai = mAttachInfo; 20006 if (ai == null) { 20007 return null; 20008 } 20009 if (ai.mWindowId == null) { 20010 try { 20011 ai.mIWindowId = ai.mSession.getWindowId(ai.mWindowToken); 20012 if (ai.mIWindowId != null) { 20013 ai.mWindowId = new WindowId(ai.mIWindowId); 20014 } 20015 } catch (RemoteException e) { 20016 } 20017 } 20018 return ai.mWindowId; 20019 } 20020 20021 /** 20022 * Retrieve a unique token identifying the top-level "real" window of 20023 * the window that this view is attached to. That is, this is like 20024 * {@link #getWindowToken}, except if the window this view in is a panel 20025 * window (attached to another containing window), then the token of 20026 * the containing window is returned instead. 20027 * 20028 * @return Returns the associated window token, either 20029 * {@link #getWindowToken()} or the containing window's token. 20030 */ getApplicationWindowToken()20031 public IBinder getApplicationWindowToken() { 20032 AttachInfo ai = mAttachInfo; 20033 if (ai != null) { 20034 IBinder appWindowToken = ai.mPanelParentWindowToken; 20035 if (appWindowToken == null) { 20036 appWindowToken = ai.mWindowToken; 20037 } 20038 return appWindowToken; 20039 } 20040 return null; 20041 } 20042 20043 /** 20044 * Gets the logical display to which the view's window has been attached. 20045 * 20046 * @return The logical display, or null if the view is not currently attached to a window. 20047 */ getDisplay()20048 public Display getDisplay() { 20049 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 20050 } 20051 20052 /** 20053 * Retrieve private session object this view hierarchy is using to 20054 * communicate with the window manager. 20055 * @return the session object to communicate with the window manager 20056 */ 20057 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) getWindowSession()20058 /*package*/ IWindowSession getWindowSession() { 20059 return mAttachInfo != null ? mAttachInfo.mSession : null; 20060 } 20061 20062 /** 20063 * Return the window this view is currently attached to. Used in 20064 * {@link android.app.ActivityView} to communicate with WM. 20065 * @hide 20066 */ getWindow()20067 protected IWindow getWindow() { 20068 return mAttachInfo != null ? mAttachInfo.mWindow : null; 20069 } 20070 20071 /** 20072 * Return the visibility value of the least visible component passed. 20073 */ combineVisibility(int vis1, int vis2)20074 int combineVisibility(int vis1, int vis2) { 20075 // This works because VISIBLE < INVISIBLE < GONE. 20076 return Math.max(vis1, vis2); 20077 } 20078 20079 /** 20080 * @param info the {@link android.view.View.AttachInfo} to associated with 20081 * this view 20082 */ 20083 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchAttachedToWindow(AttachInfo info, int visibility)20084 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 20085 mAttachInfo = info; 20086 if (mOverlay != null) { 20087 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 20088 } 20089 mWindowAttachCount++; 20090 // We will need to evaluate the drawable state at least once. 20091 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 20092 if (mFloatingTreeObserver != null) { 20093 info.mTreeObserver.merge(mFloatingTreeObserver); 20094 mFloatingTreeObserver = null; 20095 } 20096 20097 registerPendingFrameMetricsObservers(); 20098 20099 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 20100 mAttachInfo.mScrollContainers.add(this); 20101 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 20102 } 20103 // Transfer all pending runnables. 20104 if (mRunQueue != null) { 20105 mRunQueue.executeActions(info.mHandler); 20106 mRunQueue = null; 20107 } 20108 performCollectViewAttributes(mAttachInfo, visibility); 20109 onAttachedToWindow(); 20110 20111 ListenerInfo li = mListenerInfo; 20112 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 20113 li != null ? li.mOnAttachStateChangeListeners : null; 20114 if (listeners != null && listeners.size() > 0) { 20115 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 20116 // perform the dispatching. The iterator is a safe guard against listeners that 20117 // could mutate the list by calling the various add/remove methods. This prevents 20118 // the array from being modified while we iterate it. 20119 for (OnAttachStateChangeListener listener : listeners) { 20120 listener.onViewAttachedToWindow(this); 20121 } 20122 } 20123 20124 int vis = info.mWindowVisibility; 20125 if (vis != GONE) { 20126 onWindowVisibilityChanged(vis); 20127 if (isShown()) { 20128 // Calling onVisibilityAggregated directly here since the subtree will also 20129 // receive dispatchAttachedToWindow and this same call 20130 onVisibilityAggregated(vis == VISIBLE); 20131 } 20132 } 20133 20134 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 20135 // As all views in the subtree will already receive dispatchAttachedToWindow 20136 // traversing the subtree again here is not desired. 20137 onVisibilityChanged(this, visibility); 20138 20139 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 20140 // If nobody has evaluated the drawable state yet, then do it now. 20141 refreshDrawableState(); 20142 } 20143 needGlobalAttributesUpdate(false); 20144 20145 notifyEnterOrExitForAutoFillIfNeeded(true); 20146 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 20147 } 20148 20149 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchDetachedFromWindow()20150 void dispatchDetachedFromWindow() { 20151 AttachInfo info = mAttachInfo; 20152 if (info != null) { 20153 int vis = info.mWindowVisibility; 20154 if (vis != GONE) { 20155 onWindowVisibilityChanged(GONE); 20156 if (isShown()) { 20157 // Invoking onVisibilityAggregated directly here since the subtree 20158 // will also receive detached from window 20159 onVisibilityAggregated(false); 20160 } 20161 } 20162 } 20163 20164 onDetachedFromWindow(); 20165 onDetachedFromWindowInternal(); 20166 20167 InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); 20168 if (imm != null) { 20169 imm.onViewDetachedFromWindow(this); 20170 } 20171 20172 ListenerInfo li = mListenerInfo; 20173 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 20174 li != null ? li.mOnAttachStateChangeListeners : null; 20175 if (listeners != null && listeners.size() > 0) { 20176 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 20177 // perform the dispatching. The iterator is a safe guard against listeners that 20178 // could mutate the list by calling the various add/remove methods. This prevents 20179 // the array from being modified while we iterate it. 20180 for (OnAttachStateChangeListener listener : listeners) { 20181 listener.onViewDetachedFromWindow(this); 20182 } 20183 } 20184 20185 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 20186 mAttachInfo.mScrollContainers.remove(this); 20187 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 20188 } 20189 20190 mAttachInfo = null; 20191 if (mOverlay != null) { 20192 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 20193 } 20194 20195 notifyEnterOrExitForAutoFillIfNeeded(false); 20196 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 20197 } 20198 20199 /** 20200 * Cancel any deferred high-level input events that were previously posted to the event queue. 20201 * 20202 * <p>Many views post high-level events such as click handlers to the event queue 20203 * to run deferred in order to preserve a desired user experience - clearing visible 20204 * pressed states before executing, etc. This method will abort any events of this nature 20205 * that are currently in flight.</p> 20206 * 20207 * <p>Custom views that generate their own high-level deferred input events should override 20208 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 20209 * 20210 * <p>This will also cancel pending input events for any child views.</p> 20211 * 20212 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 20213 * This will not impact newer events posted after this call that may occur as a result of 20214 * lower-level input events still waiting in the queue. If you are trying to prevent 20215 * double-submitted events for the duration of some sort of asynchronous transaction 20216 * you should also take other steps to protect against unexpected double inputs e.g. calling 20217 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 20218 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 20219 */ cancelPendingInputEvents()20220 public final void cancelPendingInputEvents() { 20221 dispatchCancelPendingInputEvents(); 20222 } 20223 20224 /** 20225 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 20226 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 20227 */ dispatchCancelPendingInputEvents()20228 void dispatchCancelPendingInputEvents() { 20229 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 20230 onCancelPendingInputEvents(); 20231 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 20232 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 20233 " did not call through to super.onCancelPendingInputEvents()"); 20234 } 20235 } 20236 20237 /** 20238 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 20239 * a parent view. 20240 * 20241 * <p>This method is responsible for removing any pending high-level input events that were 20242 * posted to the event queue to run later. Custom view classes that post their own deferred 20243 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 20244 * {@link android.os.Handler} should override this method, call 20245 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 20246 * </p> 20247 */ onCancelPendingInputEvents()20248 public void onCancelPendingInputEvents() { 20249 removePerformClickCallback(); 20250 cancelLongPress(); 20251 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 20252 } 20253 20254 /** 20255 * Store this view hierarchy's frozen state into the given container. 20256 * 20257 * @param container The SparseArray in which to save the view's state. 20258 * 20259 * @see #restoreHierarchyState(android.util.SparseArray) 20260 * @see #dispatchSaveInstanceState(android.util.SparseArray) 20261 * @see #onSaveInstanceState() 20262 */ saveHierarchyState(SparseArray<Parcelable> container)20263 public void saveHierarchyState(SparseArray<Parcelable> container) { 20264 dispatchSaveInstanceState(container); 20265 } 20266 20267 /** 20268 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 20269 * this view and its children. May be overridden to modify how freezing happens to a 20270 * view's children; for example, some views may want to not store state for their children. 20271 * 20272 * @param container The SparseArray in which to save the view's state. 20273 * 20274 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 20275 * @see #saveHierarchyState(android.util.SparseArray) 20276 * @see #onSaveInstanceState() 20277 */ dispatchSaveInstanceState(SparseArray<Parcelable> container)20278 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 20279 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 20280 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 20281 Parcelable state = onSaveInstanceState(); 20282 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 20283 throw new IllegalStateException( 20284 "Derived class did not call super.onSaveInstanceState()"); 20285 } 20286 if (state != null) { 20287 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 20288 // + ": " + state); 20289 container.put(mID, state); 20290 } 20291 } 20292 } 20293 20294 /** 20295 * Hook allowing a view to generate a representation of its internal state 20296 * that can later be used to create a new instance with that same state. 20297 * This state should only contain information that is not persistent or can 20298 * not be reconstructed later. For example, you will never store your 20299 * current position on screen because that will be computed again when a 20300 * new instance of the view is placed in its view hierarchy. 20301 * <p> 20302 * Some examples of things you may store here: the current cursor position 20303 * in a text view (but usually not the text itself since that is stored in a 20304 * content provider or other persistent storage), the currently selected 20305 * item in a list view. 20306 * 20307 * @return Returns a Parcelable object containing the view's current dynamic 20308 * state, or null if there is nothing interesting to save. 20309 * @see #onRestoreInstanceState(Parcelable) 20310 * @see #saveHierarchyState(SparseArray) 20311 * @see #dispatchSaveInstanceState(SparseArray) 20312 * @see #setSaveEnabled(boolean) 20313 */ 20314 @CallSuper onSaveInstanceState()20315 @Nullable protected Parcelable onSaveInstanceState() { 20316 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 20317 if (mStartActivityRequestWho != null || isAutofilled() 20318 || mAutofillViewId > LAST_APP_AUTOFILL_ID) { 20319 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 20320 20321 if (mStartActivityRequestWho != null) { 20322 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; 20323 } 20324 20325 if (isAutofilled()) { 20326 state.mSavedData |= BaseSavedState.IS_AUTOFILLED; 20327 } 20328 20329 if (mAutofillViewId > LAST_APP_AUTOFILL_ID) { 20330 state.mSavedData |= BaseSavedState.AUTOFILL_ID; 20331 } 20332 20333 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 20334 state.mIsAutofilled = isAutofilled(); 20335 state.mAutofillViewId = mAutofillViewId; 20336 return state; 20337 } 20338 return BaseSavedState.EMPTY_STATE; 20339 } 20340 20341 /** 20342 * Restore this view hierarchy's frozen state from the given container. 20343 * 20344 * @param container The SparseArray which holds previously frozen states. 20345 * 20346 * @see #saveHierarchyState(android.util.SparseArray) 20347 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 20348 * @see #onRestoreInstanceState(android.os.Parcelable) 20349 */ restoreHierarchyState(SparseArray<Parcelable> container)20350 public void restoreHierarchyState(SparseArray<Parcelable> container) { 20351 dispatchRestoreInstanceState(container); 20352 } 20353 20354 /** 20355 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 20356 * state for this view and its children. May be overridden to modify how restoring 20357 * happens to a view's children; for example, some views may want to not store state 20358 * for their children. 20359 * 20360 * @param container The SparseArray which holds previously saved state. 20361 * 20362 * @see #dispatchSaveInstanceState(android.util.SparseArray) 20363 * @see #restoreHierarchyState(android.util.SparseArray) 20364 * @see #onRestoreInstanceState(android.os.Parcelable) 20365 */ dispatchRestoreInstanceState(SparseArray<Parcelable> container)20366 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 20367 if (mID != NO_ID) { 20368 Parcelable state = container.get(mID); 20369 if (state != null) { 20370 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 20371 // + ": " + state); 20372 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 20373 onRestoreInstanceState(state); 20374 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 20375 throw new IllegalStateException( 20376 "Derived class did not call super.onRestoreInstanceState()"); 20377 } 20378 } 20379 } 20380 } 20381 20382 /** 20383 * Hook allowing a view to re-apply a representation of its internal state that had previously 20384 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 20385 * null state. 20386 * 20387 * @param state The frozen state that had previously been returned by 20388 * {@link #onSaveInstanceState}. 20389 * 20390 * @see #onSaveInstanceState() 20391 * @see #restoreHierarchyState(android.util.SparseArray) 20392 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 20393 */ 20394 @CallSuper onRestoreInstanceState(Parcelable state)20395 protected void onRestoreInstanceState(Parcelable state) { 20396 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 20397 if (state != null && !(state instanceof AbsSavedState)) { 20398 throw new IllegalArgumentException("Wrong state class, expecting View State but " 20399 + "received " + state.getClass().toString() + " instead. This usually happens " 20400 + "when two views of different type have the same id in the same hierarchy. " 20401 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 20402 + "other views do not use the same id."); 20403 } 20404 if (state != null && state instanceof BaseSavedState) { 20405 BaseSavedState baseState = (BaseSavedState) state; 20406 20407 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { 20408 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; 20409 } 20410 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { 20411 setAutofilled(baseState.mIsAutofilled); 20412 } 20413 if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) { 20414 // It can happen that views have the same view id and the restoration path will not 20415 // be able to distinguish between them. The autofill id needs to be unique though. 20416 // Hence prevent the same autofill view id from being restored multiple times. 20417 ((BaseSavedState) state).mSavedData &= ~BaseSavedState.AUTOFILL_ID; 20418 20419 if ((mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) != 0) { 20420 // Ignore when view already set it through setAutofillId(); 20421 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.DEBUG)) { 20422 Log.d(AUTOFILL_LOG_TAG, "onRestoreInstanceState(): not setting autofillId " 20423 + "to " + baseState.mAutofillViewId + " because view explicitly set" 20424 + " it to " + mAutofillId); 20425 } 20426 } else { 20427 mAutofillViewId = baseState.mAutofillViewId; 20428 mAutofillId = null; // will be set on demand by getAutofillId() 20429 } 20430 } 20431 } 20432 } 20433 20434 /** 20435 * <p>Return the time at which the drawing of the view hierarchy started.</p> 20436 * 20437 * @return the drawing start time in milliseconds 20438 */ getDrawingTime()20439 public long getDrawingTime() { 20440 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 20441 } 20442 20443 /** 20444 * <p>Enables or disables the duplication of the parent's state into this view. When 20445 * duplication is enabled, this view gets its drawable state from its parent rather 20446 * than from its own internal properties.</p> 20447 * 20448 * <p>Note: in the current implementation, setting this property to true after the 20449 * view was added to a ViewGroup might have no effect at all. This property should 20450 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 20451 * 20452 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 20453 * property is enabled, an exception will be thrown.</p> 20454 * 20455 * <p>Note: if the child view uses and updates additional states which are unknown to the 20456 * parent, these states should not be affected by this method.</p> 20457 * 20458 * @param enabled True to enable duplication of the parent's drawable state, false 20459 * to disable it. 20460 * 20461 * @see #getDrawableState() 20462 * @see #isDuplicateParentStateEnabled() 20463 */ setDuplicateParentStateEnabled(boolean enabled)20464 public void setDuplicateParentStateEnabled(boolean enabled) { 20465 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 20466 } 20467 20468 /** 20469 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 20470 * 20471 * @return True if this view's drawable state is duplicated from the parent, 20472 * false otherwise 20473 * 20474 * @see #getDrawableState() 20475 * @see #setDuplicateParentStateEnabled(boolean) 20476 */ 20477 @InspectableProperty(name = "duplicateParentState") isDuplicateParentStateEnabled()20478 public boolean isDuplicateParentStateEnabled() { 20479 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 20480 } 20481 20482 /** 20483 * <p>Specifies the type of layer backing this view. The layer can be 20484 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 20485 * {@link #LAYER_TYPE_HARDWARE}.</p> 20486 * 20487 * <p>A layer is associated with an optional {@link android.graphics.Paint} 20488 * instance that controls how the layer is composed on screen. The following 20489 * properties of the paint are taken into account when composing the layer:</p> 20490 * <ul> 20491 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 20492 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 20493 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 20494 * </ul> 20495 * 20496 * <p>If this view has an alpha value set to < 1.0 by calling 20497 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 20498 * by this view's alpha value.</p> 20499 * 20500 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 20501 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 20502 * for more information on when and how to use layers.</p> 20503 * 20504 * @param layerType The type of layer to use with this view, must be one of 20505 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 20506 * {@link #LAYER_TYPE_HARDWARE} 20507 * @param paint The paint used to compose the layer. This argument is optional 20508 * and can be null. It is ignored when the layer type is 20509 * {@link #LAYER_TYPE_NONE} 20510 * 20511 * @see #getLayerType() 20512 * @see #LAYER_TYPE_NONE 20513 * @see #LAYER_TYPE_SOFTWARE 20514 * @see #LAYER_TYPE_HARDWARE 20515 * @see #setAlpha(float) 20516 * 20517 * @attr ref android.R.styleable#View_layerType 20518 */ setLayerType(@ayerType int layerType, @Nullable Paint paint)20519 public void setLayerType(@LayerType int layerType, @Nullable Paint paint) { 20520 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 20521 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 20522 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 20523 } 20524 20525 boolean typeChanged = mRenderNode.setLayerType(layerType); 20526 20527 if (!typeChanged) { 20528 setLayerPaint(paint); 20529 return; 20530 } 20531 20532 if (layerType != LAYER_TYPE_SOFTWARE) { 20533 // Destroy any previous software drawing cache if present 20534 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 20535 // drawing cache created in View#draw when drawing to a SW canvas. 20536 destroyDrawingCache(); 20537 } 20538 20539 mLayerType = layerType; 20540 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 20541 mRenderNode.setLayerPaint(mLayerPaint); 20542 20543 // draw() behaves differently if we are on a layer, so we need to 20544 // invalidate() here 20545 invalidateParentCaches(); 20546 invalidate(true); 20547 } 20548 20549 /** 20550 * Updates the {@link Paint} object used with the current layer (used only if the current 20551 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 20552 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 20553 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 20554 * ensure that the view gets redrawn immediately. 20555 * 20556 * <p>A layer is associated with an optional {@link android.graphics.Paint} 20557 * instance that controls how the layer is composed on screen. The following 20558 * properties of the paint are taken into account when composing the layer:</p> 20559 * <ul> 20560 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 20561 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 20562 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 20563 * </ul> 20564 * 20565 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 20566 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 20567 * 20568 * @param paint The paint used to compose the layer. This argument is optional 20569 * and can be null. It is ignored when the layer type is 20570 * {@link #LAYER_TYPE_NONE} 20571 * 20572 * @see #setLayerType(int, android.graphics.Paint) 20573 */ setLayerPaint(@ullable Paint paint)20574 public void setLayerPaint(@Nullable Paint paint) { 20575 int layerType = getLayerType(); 20576 if (layerType != LAYER_TYPE_NONE) { 20577 mLayerPaint = paint; 20578 if (layerType == LAYER_TYPE_HARDWARE) { 20579 if (mRenderNode.setLayerPaint(paint)) { 20580 invalidateViewProperty(false, false); 20581 } 20582 } else { 20583 invalidate(); 20584 } 20585 } 20586 } 20587 20588 /** 20589 * Indicates what type of layer is currently associated with this view. By default 20590 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 20591 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 20592 * for more information on the different types of layers. 20593 * 20594 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 20595 * {@link #LAYER_TYPE_HARDWARE} 20596 * 20597 * @see #setLayerType(int, android.graphics.Paint) 20598 * @see #buildLayer() 20599 * @see #LAYER_TYPE_NONE 20600 * @see #LAYER_TYPE_SOFTWARE 20601 * @see #LAYER_TYPE_HARDWARE 20602 */ 20603 @InspectableProperty(enumMapping = { 20604 @EnumEntry(value = LAYER_TYPE_NONE, name = "none"), 20605 @EnumEntry(value = LAYER_TYPE_SOFTWARE, name = "software"), 20606 @EnumEntry(value = LAYER_TYPE_HARDWARE, name = "hardware") 20607 }) 20608 @LayerType getLayerType()20609 public int getLayerType() { 20610 return mLayerType; 20611 } 20612 20613 /** 20614 * Forces this view's layer to be created and this view to be rendered 20615 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 20616 * invoking this method will have no effect. 20617 * 20618 * This method can for instance be used to render a view into its layer before 20619 * starting an animation. If this view is complex, rendering into the layer 20620 * before starting the animation will avoid skipping frames. 20621 * 20622 * @throws IllegalStateException If this view is not attached to a window 20623 * 20624 * @see #setLayerType(int, android.graphics.Paint) 20625 */ buildLayer()20626 public void buildLayer() { 20627 if (mLayerType == LAYER_TYPE_NONE) return; 20628 20629 final AttachInfo attachInfo = mAttachInfo; 20630 if (attachInfo == null) { 20631 throw new IllegalStateException("This view must be attached to a window first"); 20632 } 20633 20634 if (getWidth() == 0 || getHeight() == 0) { 20635 return; 20636 } 20637 20638 switch (mLayerType) { 20639 case LAYER_TYPE_HARDWARE: 20640 updateDisplayListIfDirty(); 20641 if (attachInfo.mThreadedRenderer != null && mRenderNode.hasDisplayList()) { 20642 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 20643 } 20644 break; 20645 case LAYER_TYPE_SOFTWARE: 20646 buildDrawingCache(true); 20647 break; 20648 } 20649 } 20650 20651 /** 20652 * Destroys all hardware rendering resources. This method is invoked 20653 * when the system needs to reclaim resources. Upon execution of this 20654 * method, you should free any OpenGL resources created by the view. 20655 * 20656 * Note: you <strong>must</strong> call 20657 * <code>super.destroyHardwareResources()</code> when overriding 20658 * this method. 20659 * 20660 * @hide 20661 */ 20662 @CallSuper 20663 @UnsupportedAppUsage destroyHardwareResources()20664 protected void destroyHardwareResources() { 20665 if (mOverlay != null) { 20666 mOverlay.getOverlayView().destroyHardwareResources(); 20667 } 20668 if (mGhostView != null) { 20669 mGhostView.destroyHardwareResources(); 20670 } 20671 } 20672 20673 /** 20674 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 20675 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 20676 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 20677 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 20678 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 20679 * null.</p> 20680 * 20681 * <p>Enabling the drawing cache is similar to 20682 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 20683 * acceleration is turned off. When hardware acceleration is turned on, enabling the 20684 * drawing cache has no effect on rendering because the system uses a different mechanism 20685 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 20686 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 20687 * for information on how to enable software and hardware layers.</p> 20688 * 20689 * <p>This API can be used to manually generate 20690 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 20691 * {@link #getDrawingCache()}.</p> 20692 * 20693 * @param enabled true to enable the drawing cache, false otherwise 20694 * 20695 * @see #isDrawingCacheEnabled() 20696 * @see #getDrawingCache() 20697 * @see #buildDrawingCache() 20698 * @see #setLayerType(int, android.graphics.Paint) 20699 * 20700 * @deprecated The view drawing cache was largely made obsolete with the introduction of 20701 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 20702 * layers are largely unnecessary and can easily result in a net loss in performance due to the 20703 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 20704 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 20705 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 20706 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 20707 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 20708 * software-rendered usages are discouraged and have compatibility issues with hardware-only 20709 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 20710 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 20711 * reports or unit testing the {@link PixelCopy} API is recommended. 20712 */ 20713 @Deprecated setDrawingCacheEnabled(boolean enabled)20714 public void setDrawingCacheEnabled(boolean enabled) { 20715 mCachingFailed = false; 20716 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 20717 } 20718 20719 /** 20720 * <p>Indicates whether the drawing cache is enabled for this view.</p> 20721 * 20722 * @return true if the drawing cache is enabled 20723 * 20724 * @see #setDrawingCacheEnabled(boolean) 20725 * @see #getDrawingCache() 20726 * 20727 * @deprecated The view drawing cache was largely made obsolete with the introduction of 20728 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 20729 * layers are largely unnecessary and can easily result in a net loss in performance due to the 20730 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 20731 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 20732 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 20733 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 20734 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 20735 * software-rendered usages are discouraged and have compatibility issues with hardware-only 20736 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 20737 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 20738 * reports or unit testing the {@link PixelCopy} API is recommended. 20739 */ 20740 @Deprecated 20741 @ViewDebug.ExportedProperty(category = "drawing") isDrawingCacheEnabled()20742 public boolean isDrawingCacheEnabled() { 20743 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 20744 } 20745 20746 /** 20747 * Debugging utility which recursively outputs the dirty state of a view and its 20748 * descendants. 20749 * 20750 * @hide 20751 */ 20752 @SuppressWarnings({"UnusedDeclaration"}) outputDirtyFlags(String indent, boolean clear, int clearMask)20753 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 20754 Log.d(VIEW_LOG_TAG, indent + this + " DIRTY(" 20755 + (mPrivateFlags & View.PFLAG_DIRTY_MASK) 20756 + ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" 20757 + (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) 20758 + ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 20759 if (clear) { 20760 mPrivateFlags &= clearMask; 20761 } 20762 if (this instanceof ViewGroup) { 20763 ViewGroup parent = (ViewGroup) this; 20764 final int count = parent.getChildCount(); 20765 for (int i = 0; i < count; i++) { 20766 final View child = parent.getChildAt(i); 20767 child.outputDirtyFlags(indent + " ", clear, clearMask); 20768 } 20769 } 20770 } 20771 20772 /** 20773 * This method is used by ViewGroup to cause its children to restore or recreate their 20774 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 20775 * to recreate its own display list, which would happen if it went through the normal 20776 * draw/dispatchDraw mechanisms. 20777 * 20778 * @hide 20779 */ dispatchGetDisplayList()20780 protected void dispatchGetDisplayList() {} 20781 20782 /** 20783 * A view that is not attached or hardware accelerated cannot create a display list. 20784 * This method checks these conditions and returns the appropriate result. 20785 * 20786 * @return true if view has the ability to create a display list, false otherwise. 20787 * 20788 * @hide 20789 */ canHaveDisplayList()20790 public boolean canHaveDisplayList() { 20791 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 20792 } 20793 20794 /** 20795 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 20796 * @hide 20797 */ 20798 @NonNull 20799 @UnsupportedAppUsage updateDisplayListIfDirty()20800 public RenderNode updateDisplayListIfDirty() { 20801 final RenderNode renderNode = mRenderNode; 20802 if (!canHaveDisplayList()) { 20803 // can't populate RenderNode, don't try 20804 return renderNode; 20805 } 20806 20807 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 20808 || !renderNode.hasDisplayList() 20809 || (mRecreateDisplayList)) { 20810 // Don't need to recreate the display list, just need to tell our 20811 // children to restore/recreate theirs 20812 if (renderNode.hasDisplayList() 20813 && !mRecreateDisplayList) { 20814 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 20815 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 20816 dispatchGetDisplayList(); 20817 20818 return renderNode; // no work needed 20819 } 20820 20821 // If we got here, we're recreating it. Mark it as such to ensure that 20822 // we copy in child display lists into ours in drawChild() 20823 mRecreateDisplayList = true; 20824 20825 int width = mRight - mLeft; 20826 int height = mBottom - mTop; 20827 int layerType = getLayerType(); 20828 20829 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 20830 20831 try { 20832 if (layerType == LAYER_TYPE_SOFTWARE) { 20833 buildDrawingCache(true); 20834 Bitmap cache = getDrawingCache(true); 20835 if (cache != null) { 20836 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 20837 } 20838 } else { 20839 computeScroll(); 20840 20841 canvas.translate(-mScrollX, -mScrollY); 20842 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 20843 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 20844 20845 // Fast path for layouts with no backgrounds 20846 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 20847 dispatchDraw(canvas); 20848 drawAutofilledHighlight(canvas); 20849 if (mOverlay != null && !mOverlay.isEmpty()) { 20850 mOverlay.getOverlayView().draw(canvas); 20851 } 20852 if (debugDraw()) { 20853 debugDrawFocus(canvas); 20854 } 20855 } else { 20856 draw(canvas); 20857 } 20858 } 20859 } finally { 20860 renderNode.endRecording(); 20861 setDisplayListProperties(renderNode); 20862 } 20863 } else { 20864 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 20865 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 20866 } 20867 return renderNode; 20868 } 20869 20870 @UnsupportedAppUsage resetDisplayList()20871 private void resetDisplayList() { 20872 mRenderNode.discardDisplayList(); 20873 if (mBackgroundRenderNode != null) { 20874 mBackgroundRenderNode.discardDisplayList(); 20875 } 20876 } 20877 20878 /** 20879 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 20880 * 20881 * @return A non-scaled bitmap representing this view or null if cache is disabled. 20882 * 20883 * @see #getDrawingCache(boolean) 20884 * 20885 * @deprecated The view drawing cache was largely made obsolete with the introduction of 20886 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 20887 * layers are largely unnecessary and can easily result in a net loss in performance due to the 20888 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 20889 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 20890 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 20891 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 20892 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 20893 * software-rendered usages are discouraged and have compatibility issues with hardware-only 20894 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 20895 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 20896 * reports or unit testing the {@link PixelCopy} API is recommended. 20897 */ 20898 @Deprecated getDrawingCache()20899 public Bitmap getDrawingCache() { 20900 return getDrawingCache(false); 20901 } 20902 20903 /** 20904 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 20905 * is null when caching is disabled. If caching is enabled and the cache is not ready, 20906 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 20907 * draw from the cache when the cache is enabled. To benefit from the cache, you must 20908 * request the drawing cache by calling this method and draw it on screen if the 20909 * returned bitmap is not null.</p> 20910 * 20911 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 20912 * this method will create a bitmap of the same size as this view. Because this bitmap 20913 * will be drawn scaled by the parent ViewGroup, the result on screen might show 20914 * scaling artifacts. To avoid such artifacts, you should call this method by setting 20915 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 20916 * size than the view. This implies that your application must be able to handle this 20917 * size.</p> 20918 * 20919 * @param autoScale Indicates whether the generated bitmap should be scaled based on 20920 * the current density of the screen when the application is in compatibility 20921 * mode. 20922 * 20923 * @return A bitmap representing this view or null if cache is disabled. 20924 * 20925 * @see #setDrawingCacheEnabled(boolean) 20926 * @see #isDrawingCacheEnabled() 20927 * @see #buildDrawingCache(boolean) 20928 * @see #destroyDrawingCache() 20929 * 20930 * @deprecated The view drawing cache was largely made obsolete with the introduction of 20931 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 20932 * layers are largely unnecessary and can easily result in a net loss in performance due to the 20933 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 20934 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 20935 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 20936 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 20937 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 20938 * software-rendered usages are discouraged and have compatibility issues with hardware-only 20939 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 20940 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 20941 * reports or unit testing the {@link PixelCopy} API is recommended. 20942 */ 20943 @Deprecated getDrawingCache(boolean autoScale)20944 public Bitmap getDrawingCache(boolean autoScale) { 20945 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 20946 return null; 20947 } 20948 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 20949 buildDrawingCache(autoScale); 20950 } 20951 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 20952 } 20953 20954 /** 20955 * <p>Frees the resources used by the drawing cache. If you call 20956 * {@link #buildDrawingCache()} manually without calling 20957 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 20958 * should cleanup the cache with this method afterwards.</p> 20959 * 20960 * @see #setDrawingCacheEnabled(boolean) 20961 * @see #buildDrawingCache() 20962 * @see #getDrawingCache() 20963 * 20964 * @deprecated The view drawing cache was largely made obsolete with the introduction of 20965 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 20966 * layers are largely unnecessary and can easily result in a net loss in performance due to the 20967 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 20968 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 20969 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 20970 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 20971 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 20972 * software-rendered usages are discouraged and have compatibility issues with hardware-only 20973 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 20974 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 20975 * reports or unit testing the {@link PixelCopy} API is recommended. 20976 */ 20977 @Deprecated destroyDrawingCache()20978 public void destroyDrawingCache() { 20979 if (mDrawingCache != null) { 20980 mDrawingCache.recycle(); 20981 mDrawingCache = null; 20982 } 20983 if (mUnscaledDrawingCache != null) { 20984 mUnscaledDrawingCache.recycle(); 20985 mUnscaledDrawingCache = null; 20986 } 20987 } 20988 20989 /** 20990 * Setting a solid background color for the drawing cache's bitmaps will improve 20991 * performance and memory usage. Note, though that this should only be used if this 20992 * view will always be drawn on top of a solid color. 20993 * 20994 * @param color The background color to use for the drawing cache's bitmap 20995 * 20996 * @see #setDrawingCacheEnabled(boolean) 20997 * @see #buildDrawingCache() 20998 * @see #getDrawingCache() 20999 * 21000 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21001 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21002 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21003 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21004 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21005 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21006 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21007 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21008 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21009 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21010 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21011 * reports or unit testing the {@link PixelCopy} API is recommended. 21012 */ 21013 @Deprecated setDrawingCacheBackgroundColor(@olorInt int color)21014 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 21015 if (color != mDrawingCacheBackgroundColor) { 21016 mDrawingCacheBackgroundColor = color; 21017 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 21018 } 21019 } 21020 21021 /** 21022 * @see #setDrawingCacheBackgroundColor(int) 21023 * 21024 * @return The background color to used for the drawing cache's bitmap 21025 * 21026 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21027 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21028 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21029 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21030 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21031 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21032 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21033 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21034 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21035 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21036 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21037 * reports or unit testing the {@link PixelCopy} API is recommended. 21038 */ 21039 @Deprecated 21040 @ColorInt getDrawingCacheBackgroundColor()21041 public int getDrawingCacheBackgroundColor() { 21042 return mDrawingCacheBackgroundColor; 21043 } 21044 21045 /** 21046 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 21047 * 21048 * @see #buildDrawingCache(boolean) 21049 * 21050 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21051 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21052 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21053 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21054 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21055 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21056 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21057 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21058 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21059 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21060 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21061 * reports or unit testing the {@link PixelCopy} API is recommended. 21062 */ 21063 @Deprecated buildDrawingCache()21064 public void buildDrawingCache() { 21065 buildDrawingCache(false); 21066 } 21067 21068 /** 21069 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 21070 * 21071 * <p>If you call {@link #buildDrawingCache()} manually without calling 21072 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 21073 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 21074 * 21075 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 21076 * this method will create a bitmap of the same size as this view. Because this bitmap 21077 * will be drawn scaled by the parent ViewGroup, the result on screen might show 21078 * scaling artifacts. To avoid such artifacts, you should call this method by setting 21079 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 21080 * size than the view. This implies that your application must be able to handle this 21081 * size.</p> 21082 * 21083 * <p>You should avoid calling this method when hardware acceleration is enabled. If 21084 * you do not need the drawing cache bitmap, calling this method will increase memory 21085 * usage and cause the view to be rendered in software once, thus negatively impacting 21086 * performance.</p> 21087 * 21088 * @see #getDrawingCache() 21089 * @see #destroyDrawingCache() 21090 * 21091 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21092 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21093 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21094 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21095 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21096 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21097 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21098 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21099 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21100 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21101 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21102 * reports or unit testing the {@link PixelCopy} API is recommended. 21103 */ 21104 @Deprecated buildDrawingCache(boolean autoScale)21105 public void buildDrawingCache(boolean autoScale) { 21106 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 21107 mDrawingCache == null : mUnscaledDrawingCache == null)) { 21108 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 21109 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 21110 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 21111 } 21112 try { 21113 buildDrawingCacheImpl(autoScale); 21114 } finally { 21115 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 21116 } 21117 } 21118 } 21119 21120 /** 21121 * private, internal implementation of buildDrawingCache, used to enable tracing 21122 */ buildDrawingCacheImpl(boolean autoScale)21123 private void buildDrawingCacheImpl(boolean autoScale) { 21124 mCachingFailed = false; 21125 21126 int width = mRight - mLeft; 21127 int height = mBottom - mTop; 21128 21129 final AttachInfo attachInfo = mAttachInfo; 21130 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 21131 21132 if (autoScale && scalingRequired) { 21133 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 21134 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 21135 } 21136 21137 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 21138 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 21139 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 21140 21141 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 21142 final long drawingCacheSize = 21143 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 21144 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 21145 if (width > 0 && height > 0) { 21146 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 21147 + " too large to fit into a software layer (or drawing cache), needs " 21148 + projectedBitmapSize + " bytes, only " 21149 + drawingCacheSize + " available"); 21150 } 21151 destroyDrawingCache(); 21152 mCachingFailed = true; 21153 return; 21154 } 21155 21156 boolean clear = true; 21157 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 21158 21159 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 21160 Bitmap.Config quality; 21161 if (!opaque) { 21162 // Never pick ARGB_4444 because it looks awful 21163 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 21164 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 21165 case DRAWING_CACHE_QUALITY_AUTO: 21166 case DRAWING_CACHE_QUALITY_LOW: 21167 case DRAWING_CACHE_QUALITY_HIGH: 21168 default: 21169 quality = Bitmap.Config.ARGB_8888; 21170 break; 21171 } 21172 } else { 21173 // Optimization for translucent windows 21174 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 21175 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 21176 } 21177 21178 // Try to cleanup memory 21179 if (bitmap != null) bitmap.recycle(); 21180 21181 try { 21182 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 21183 width, height, quality); 21184 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 21185 if (autoScale) { 21186 mDrawingCache = bitmap; 21187 } else { 21188 mUnscaledDrawingCache = bitmap; 21189 } 21190 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 21191 } catch (OutOfMemoryError e) { 21192 // If there is not enough memory to create the bitmap cache, just 21193 // ignore the issue as bitmap caches are not required to draw the 21194 // view hierarchy 21195 if (autoScale) { 21196 mDrawingCache = null; 21197 } else { 21198 mUnscaledDrawingCache = null; 21199 } 21200 mCachingFailed = true; 21201 return; 21202 } 21203 21204 clear = drawingCacheBackgroundColor != 0; 21205 } 21206 21207 Canvas canvas; 21208 if (attachInfo != null) { 21209 canvas = attachInfo.mCanvas; 21210 if (canvas == null) { 21211 canvas = new Canvas(); 21212 } 21213 canvas.setBitmap(bitmap); 21214 // Temporarily clobber the cached Canvas in case one of our children 21215 // is also using a drawing cache. Without this, the children would 21216 // steal the canvas by attaching their own bitmap to it and bad, bad 21217 // thing would happen (invisible views, corrupted drawings, etc.) 21218 attachInfo.mCanvas = null; 21219 } else { 21220 // This case should hopefully never or seldom happen 21221 canvas = new Canvas(bitmap); 21222 } 21223 21224 if (clear) { 21225 bitmap.eraseColor(drawingCacheBackgroundColor); 21226 } 21227 21228 computeScroll(); 21229 final int restoreCount = canvas.save(); 21230 21231 if (autoScale && scalingRequired) { 21232 final float scale = attachInfo.mApplicationScale; 21233 canvas.scale(scale, scale); 21234 } 21235 21236 canvas.translate(-mScrollX, -mScrollY); 21237 21238 mPrivateFlags |= PFLAG_DRAWN; 21239 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 21240 mLayerType != LAYER_TYPE_NONE) { 21241 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 21242 } 21243 21244 // Fast path for layouts with no backgrounds 21245 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 21246 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21247 dispatchDraw(canvas); 21248 drawAutofilledHighlight(canvas); 21249 if (mOverlay != null && !mOverlay.isEmpty()) { 21250 mOverlay.getOverlayView().draw(canvas); 21251 } 21252 } else { 21253 draw(canvas); 21254 } 21255 21256 canvas.restoreToCount(restoreCount); 21257 canvas.setBitmap(null); 21258 21259 if (attachInfo != null) { 21260 // Restore the cached Canvas for our siblings 21261 attachInfo.mCanvas = canvas; 21262 } 21263 } 21264 21265 /** 21266 * Create a snapshot of the view into a bitmap. We should probably make 21267 * some form of this public, but should think about the API. 21268 * 21269 * @hide 21270 */ 21271 @UnsupportedAppUsage createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren)21272 public Bitmap createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren) { 21273 int width = mRight - mLeft; 21274 int height = mBottom - mTop; 21275 21276 final AttachInfo attachInfo = mAttachInfo; 21277 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 21278 width = (int) ((width * scale) + 0.5f); 21279 height = (int) ((height * scale) + 0.5f); 21280 21281 Canvas oldCanvas = null; 21282 try { 21283 Canvas canvas = canvasProvider.getCanvas(this, 21284 width > 0 ? width : 1, height > 0 ? height : 1); 21285 21286 if (attachInfo != null) { 21287 oldCanvas = attachInfo.mCanvas; 21288 // Temporarily clobber the cached Canvas in case one of our children 21289 // is also using a drawing cache. Without this, the children would 21290 // steal the canvas by attaching their own bitmap to it and bad, bad 21291 // things would happen (invisible views, corrupted drawings, etc.) 21292 attachInfo.mCanvas = null; 21293 } 21294 21295 computeScroll(); 21296 final int restoreCount = canvas.save(); 21297 canvas.scale(scale, scale); 21298 canvas.translate(-mScrollX, -mScrollY); 21299 21300 // Temporarily remove the dirty mask 21301 int flags = mPrivateFlags; 21302 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21303 21304 // Fast path for layouts with no backgrounds 21305 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 21306 dispatchDraw(canvas); 21307 drawAutofilledHighlight(canvas); 21308 if (mOverlay != null && !mOverlay.isEmpty()) { 21309 mOverlay.getOverlayView().draw(canvas); 21310 } 21311 } else { 21312 draw(canvas); 21313 } 21314 21315 mPrivateFlags = flags; 21316 canvas.restoreToCount(restoreCount); 21317 return canvasProvider.createBitmap(); 21318 } finally { 21319 if (oldCanvas != null) { 21320 attachInfo.mCanvas = oldCanvas; 21321 } 21322 } 21323 } 21324 21325 /** 21326 * Indicates whether this View is currently in edit mode. A View is usually 21327 * in edit mode when displayed within a developer tool. For instance, if 21328 * this View is being drawn by a visual user interface builder, this method 21329 * should return true. 21330 * 21331 * Subclasses should check the return value of this method to provide 21332 * different behaviors if their normal behavior might interfere with the 21333 * host environment. For instance: the class spawns a thread in its 21334 * constructor, the drawing code relies on device-specific features, etc. 21335 * 21336 * This method is usually checked in the drawing code of custom widgets. 21337 * 21338 * @return True if this View is in edit mode, false otherwise. 21339 */ isInEditMode()21340 public boolean isInEditMode() { 21341 return false; 21342 } 21343 21344 /** 21345 * If the View draws content inside its padding and enables fading edges, 21346 * it needs to support padding offsets. Padding offsets are added to the 21347 * fading edges to extend the length of the fade so that it covers pixels 21348 * drawn inside the padding. 21349 * 21350 * Subclasses of this class should override this method if they need 21351 * to draw content inside the padding. 21352 * 21353 * @return True if padding offset must be applied, false otherwise. 21354 * 21355 * @see #getLeftPaddingOffset() 21356 * @see #getRightPaddingOffset() 21357 * @see #getTopPaddingOffset() 21358 * @see #getBottomPaddingOffset() 21359 * 21360 * @since CURRENT 21361 */ isPaddingOffsetRequired()21362 protected boolean isPaddingOffsetRequired() { 21363 return false; 21364 } 21365 21366 /** 21367 * Amount by which to extend the left fading region. Called only when 21368 * {@link #isPaddingOffsetRequired()} returns true. 21369 * 21370 * @return The left padding offset in pixels. 21371 * 21372 * @see #isPaddingOffsetRequired() 21373 * 21374 * @since CURRENT 21375 */ getLeftPaddingOffset()21376 protected int getLeftPaddingOffset() { 21377 return 0; 21378 } 21379 21380 /** 21381 * Amount by which to extend the right fading region. Called only when 21382 * {@link #isPaddingOffsetRequired()} returns true. 21383 * 21384 * @return The right padding offset in pixels. 21385 * 21386 * @see #isPaddingOffsetRequired() 21387 * 21388 * @since CURRENT 21389 */ getRightPaddingOffset()21390 protected int getRightPaddingOffset() { 21391 return 0; 21392 } 21393 21394 /** 21395 * Amount by which to extend the top fading region. Called only when 21396 * {@link #isPaddingOffsetRequired()} returns true. 21397 * 21398 * @return The top padding offset in pixels. 21399 * 21400 * @see #isPaddingOffsetRequired() 21401 * 21402 * @since CURRENT 21403 */ getTopPaddingOffset()21404 protected int getTopPaddingOffset() { 21405 return 0; 21406 } 21407 21408 /** 21409 * Amount by which to extend the bottom fading region. Called only when 21410 * {@link #isPaddingOffsetRequired()} returns true. 21411 * 21412 * @return The bottom padding offset in pixels. 21413 * 21414 * @see #isPaddingOffsetRequired() 21415 * 21416 * @since CURRENT 21417 */ getBottomPaddingOffset()21418 protected int getBottomPaddingOffset() { 21419 return 0; 21420 } 21421 21422 /** 21423 * @hide 21424 * @param offsetRequired 21425 */ getFadeTop(boolean offsetRequired)21426 protected int getFadeTop(boolean offsetRequired) { 21427 int top = mPaddingTop; 21428 if (offsetRequired) top += getTopPaddingOffset(); 21429 return top; 21430 } 21431 21432 /** 21433 * @hide 21434 * @param offsetRequired 21435 */ getFadeHeight(boolean offsetRequired)21436 protected int getFadeHeight(boolean offsetRequired) { 21437 int padding = mPaddingTop; 21438 if (offsetRequired) padding += getTopPaddingOffset(); 21439 return mBottom - mTop - mPaddingBottom - padding; 21440 } 21441 21442 /** 21443 * <p>Indicates whether this view is attached to a hardware accelerated 21444 * window or not.</p> 21445 * 21446 * <p>Even if this method returns true, it does not mean that every call 21447 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 21448 * accelerated {@link android.graphics.Canvas}. For instance, if this view 21449 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 21450 * window is hardware accelerated, 21451 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 21452 * return false, and this method will return true.</p> 21453 * 21454 * @return True if the view is attached to a window and the window is 21455 * hardware accelerated; false in any other case. 21456 */ 21457 @ViewDebug.ExportedProperty(category = "drawing") isHardwareAccelerated()21458 public boolean isHardwareAccelerated() { 21459 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 21460 } 21461 21462 /** 21463 * Sets a rectangular area on this view to which the view will be clipped 21464 * when it is drawn. Setting the value to null will remove the clip bounds 21465 * and the view will draw normally, using its full bounds. 21466 * 21467 * @param clipBounds The rectangular area, in the local coordinates of 21468 * this view, to which future drawing operations will be clipped. 21469 */ setClipBounds(Rect clipBounds)21470 public void setClipBounds(Rect clipBounds) { 21471 if (clipBounds == mClipBounds 21472 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 21473 return; 21474 } 21475 if (clipBounds != null) { 21476 if (mClipBounds == null) { 21477 mClipBounds = new Rect(clipBounds); 21478 } else { 21479 mClipBounds.set(clipBounds); 21480 } 21481 } else { 21482 mClipBounds = null; 21483 } 21484 mRenderNode.setClipRect(mClipBounds); 21485 invalidateViewProperty(false, false); 21486 } 21487 21488 /** 21489 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 21490 * 21491 * @return A copy of the current clip bounds if clip bounds are set, 21492 * otherwise null. 21493 */ getClipBounds()21494 public Rect getClipBounds() { 21495 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 21496 } 21497 21498 21499 /** 21500 * Populates an output rectangle with the clip bounds of the view, 21501 * returning {@code true} if successful or {@code false} if the view's 21502 * clip bounds are {@code null}. 21503 * 21504 * @param outRect rectangle in which to place the clip bounds of the view 21505 * @return {@code true} if successful or {@code false} if the view's 21506 * clip bounds are {@code null} 21507 */ getClipBounds(Rect outRect)21508 public boolean getClipBounds(Rect outRect) { 21509 if (mClipBounds != null) { 21510 outRect.set(mClipBounds); 21511 return true; 21512 } 21513 return false; 21514 } 21515 21516 /** 21517 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 21518 * case of an active Animation being run on the view. 21519 */ applyLegacyAnimation(ViewGroup parent, long drawingTime, Animation a, boolean scalingRequired)21520 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 21521 Animation a, boolean scalingRequired) { 21522 Transformation invalidationTransform; 21523 final int flags = parent.mGroupFlags; 21524 final boolean initialized = a.isInitialized(); 21525 if (!initialized) { 21526 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 21527 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 21528 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 21529 onAnimationStart(); 21530 } 21531 21532 final Transformation t = parent.getChildTransformation(); 21533 boolean more = a.getTransformation(drawingTime, t, 1f); 21534 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 21535 if (parent.mInvalidationTransformation == null) { 21536 parent.mInvalidationTransformation = new Transformation(); 21537 } 21538 invalidationTransform = parent.mInvalidationTransformation; 21539 a.getTransformation(drawingTime, invalidationTransform, 1f); 21540 } else { 21541 invalidationTransform = t; 21542 } 21543 21544 if (more) { 21545 if (!a.willChangeBounds()) { 21546 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 21547 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 21548 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 21549 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 21550 // The child need to draw an animation, potentially offscreen, so 21551 // make sure we do not cancel invalidate requests 21552 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 21553 parent.invalidate(mLeft, mTop, mRight, mBottom); 21554 } 21555 } else { 21556 if (parent.mInvalidateRegion == null) { 21557 parent.mInvalidateRegion = new RectF(); 21558 } 21559 final RectF region = parent.mInvalidateRegion; 21560 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 21561 invalidationTransform); 21562 21563 // The child need to draw an animation, potentially offscreen, so 21564 // make sure we do not cancel invalidate requests 21565 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 21566 21567 final int left = mLeft + (int) region.left; 21568 final int top = mTop + (int) region.top; 21569 parent.invalidate(left, top, left + (int) (region.width() + .5f), 21570 top + (int) (region.height() + .5f)); 21571 } 21572 } 21573 return more; 21574 } 21575 21576 /** 21577 * This method is called by getDisplayList() when a display list is recorded for a View. 21578 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 21579 */ setDisplayListProperties(RenderNode renderNode)21580 void setDisplayListProperties(RenderNode renderNode) { 21581 if (renderNode != null) { 21582 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 21583 renderNode.setClipToBounds(mParent instanceof ViewGroup 21584 && ((ViewGroup) mParent).getClipChildren()); 21585 21586 float alpha = 1; 21587 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 21588 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 21589 ViewGroup parentVG = (ViewGroup) mParent; 21590 final Transformation t = parentVG.getChildTransformation(); 21591 if (parentVG.getChildStaticTransformation(this, t)) { 21592 final int transformType = t.getTransformationType(); 21593 if (transformType != Transformation.TYPE_IDENTITY) { 21594 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 21595 alpha = t.getAlpha(); 21596 } 21597 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 21598 renderNode.setStaticMatrix(t.getMatrix()); 21599 } 21600 } 21601 } 21602 } 21603 if (mTransformationInfo != null) { 21604 alpha *= getFinalAlpha(); 21605 if (alpha < 1) { 21606 final int multipliedAlpha = (int) (255 * alpha); 21607 if (onSetAlpha(multipliedAlpha)) { 21608 alpha = 1; 21609 } 21610 } 21611 renderNode.setAlpha(alpha); 21612 } else if (alpha < 1) { 21613 renderNode.setAlpha(alpha); 21614 } 21615 } 21616 } 21617 21618 /** 21619 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 21620 * 21621 * This is where the View specializes rendering behavior based on layer type, 21622 * and hardware acceleration. 21623 */ draw(Canvas canvas, ViewGroup parent, long drawingTime)21624 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 21625 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 21626 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 21627 * 21628 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 21629 * HW accelerated, it can't handle drawing RenderNodes. 21630 */ 21631 boolean drawingWithRenderNode = mAttachInfo != null 21632 && mAttachInfo.mHardwareAccelerated 21633 && hardwareAcceleratedCanvas; 21634 21635 boolean more = false; 21636 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 21637 final int parentFlags = parent.mGroupFlags; 21638 21639 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 21640 parent.getChildTransformation().clear(); 21641 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 21642 } 21643 21644 Transformation transformToApply = null; 21645 boolean concatMatrix = false; 21646 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 21647 final Animation a = getAnimation(); 21648 if (a != null) { 21649 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 21650 concatMatrix = a.willChangeTransformationMatrix(); 21651 if (concatMatrix) { 21652 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 21653 } 21654 transformToApply = parent.getChildTransformation(); 21655 } else { 21656 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 21657 // No longer animating: clear out old animation matrix 21658 mRenderNode.setAnimationMatrix(null); 21659 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 21660 } 21661 if (!drawingWithRenderNode 21662 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 21663 final Transformation t = parent.getChildTransformation(); 21664 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 21665 if (hasTransform) { 21666 final int transformType = t.getTransformationType(); 21667 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 21668 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 21669 } 21670 } 21671 } 21672 21673 concatMatrix |= !childHasIdentityMatrix; 21674 21675 // Sets the flag as early as possible to allow draw() implementations 21676 // to call invalidate() successfully when doing animations 21677 mPrivateFlags |= PFLAG_DRAWN; 21678 21679 if (!concatMatrix && 21680 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 21681 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 21682 canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) && 21683 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 21684 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 21685 return more; 21686 } 21687 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 21688 21689 if (hardwareAcceleratedCanvas) { 21690 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 21691 // retain the flag's value temporarily in the mRecreateDisplayList flag 21692 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 21693 mPrivateFlags &= ~PFLAG_INVALIDATED; 21694 } 21695 21696 RenderNode renderNode = null; 21697 Bitmap cache = null; 21698 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 21699 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 21700 if (layerType != LAYER_TYPE_NONE) { 21701 // If not drawing with RenderNode, treat HW layers as SW 21702 layerType = LAYER_TYPE_SOFTWARE; 21703 buildDrawingCache(true); 21704 } 21705 cache = getDrawingCache(true); 21706 } 21707 21708 if (drawingWithRenderNode) { 21709 // Delay getting the display list until animation-driven alpha values are 21710 // set up and possibly passed on to the view 21711 renderNode = updateDisplayListIfDirty(); 21712 if (!renderNode.hasDisplayList()) { 21713 // Uncommon, but possible. If a view is removed from the hierarchy during the call 21714 // to getDisplayList(), the display list will be marked invalid and we should not 21715 // try to use it again. 21716 renderNode = null; 21717 drawingWithRenderNode = false; 21718 } 21719 } 21720 21721 int sx = 0; 21722 int sy = 0; 21723 if (!drawingWithRenderNode) { 21724 computeScroll(); 21725 sx = mScrollX; 21726 sy = mScrollY; 21727 } 21728 21729 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 21730 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 21731 21732 int restoreTo = -1; 21733 if (!drawingWithRenderNode || transformToApply != null) { 21734 restoreTo = canvas.save(); 21735 } 21736 if (offsetForScroll) { 21737 canvas.translate(mLeft - sx, mTop - sy); 21738 } else { 21739 if (!drawingWithRenderNode) { 21740 canvas.translate(mLeft, mTop); 21741 } 21742 if (scalingRequired) { 21743 if (drawingWithRenderNode) { 21744 // TODO: Might not need this if we put everything inside the DL 21745 restoreTo = canvas.save(); 21746 } 21747 // mAttachInfo cannot be null, otherwise scalingRequired == false 21748 final float scale = 1.0f / mAttachInfo.mApplicationScale; 21749 canvas.scale(scale, scale); 21750 } 21751 } 21752 21753 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 21754 if (transformToApply != null 21755 || alpha < 1 21756 || !hasIdentityMatrix() 21757 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 21758 if (transformToApply != null || !childHasIdentityMatrix) { 21759 int transX = 0; 21760 int transY = 0; 21761 21762 if (offsetForScroll) { 21763 transX = -sx; 21764 transY = -sy; 21765 } 21766 21767 if (transformToApply != null) { 21768 if (concatMatrix) { 21769 if (drawingWithRenderNode) { 21770 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 21771 } else { 21772 // Undo the scroll translation, apply the transformation matrix, 21773 // then redo the scroll translate to get the correct result. 21774 canvas.translate(-transX, -transY); 21775 canvas.concat(transformToApply.getMatrix()); 21776 canvas.translate(transX, transY); 21777 } 21778 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 21779 } 21780 21781 float transformAlpha = transformToApply.getAlpha(); 21782 if (transformAlpha < 1) { 21783 alpha *= transformAlpha; 21784 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 21785 } 21786 } 21787 21788 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 21789 canvas.translate(-transX, -transY); 21790 canvas.concat(getMatrix()); 21791 canvas.translate(transX, transY); 21792 } 21793 } 21794 21795 // Deal with alpha if it is or used to be <1 21796 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 21797 if (alpha < 1) { 21798 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 21799 } else { 21800 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 21801 } 21802 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 21803 if (!drawingWithDrawingCache) { 21804 final int multipliedAlpha = (int) (255 * alpha); 21805 if (!onSetAlpha(multipliedAlpha)) { 21806 if (drawingWithRenderNode) { 21807 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 21808 } else if (layerType == LAYER_TYPE_NONE) { 21809 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 21810 multipliedAlpha); 21811 } 21812 } else { 21813 // Alpha is handled by the child directly, clobber the layer's alpha 21814 mPrivateFlags |= PFLAG_ALPHA_SET; 21815 } 21816 } 21817 } 21818 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 21819 onSetAlpha(255); 21820 mPrivateFlags &= ~PFLAG_ALPHA_SET; 21821 } 21822 21823 if (!drawingWithRenderNode) { 21824 // apply clips directly, since RenderNode won't do it for this draw 21825 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 21826 if (offsetForScroll) { 21827 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 21828 } else { 21829 if (!scalingRequired || cache == null) { 21830 canvas.clipRect(0, 0, getWidth(), getHeight()); 21831 } else { 21832 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 21833 } 21834 } 21835 } 21836 21837 if (mClipBounds != null) { 21838 // clip bounds ignore scroll 21839 canvas.clipRect(mClipBounds); 21840 } 21841 } 21842 21843 if (!drawingWithDrawingCache) { 21844 if (drawingWithRenderNode) { 21845 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21846 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 21847 } else { 21848 // Fast path for layouts with no backgrounds 21849 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 21850 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21851 dispatchDraw(canvas); 21852 } else { 21853 draw(canvas); 21854 } 21855 } 21856 } else if (cache != null) { 21857 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21858 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 21859 // no layer paint, use temporary paint to draw bitmap 21860 Paint cachePaint = parent.mCachePaint; 21861 if (cachePaint == null) { 21862 cachePaint = new Paint(); 21863 cachePaint.setDither(false); 21864 parent.mCachePaint = cachePaint; 21865 } 21866 cachePaint.setAlpha((int) (alpha * 255)); 21867 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 21868 } else { 21869 // use layer paint to draw the bitmap, merging the two alphas, but also restore 21870 int layerPaintAlpha = mLayerPaint.getAlpha(); 21871 if (alpha < 1) { 21872 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 21873 } 21874 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 21875 if (alpha < 1) { 21876 mLayerPaint.setAlpha(layerPaintAlpha); 21877 } 21878 } 21879 } 21880 21881 if (restoreTo >= 0) { 21882 canvas.restoreToCount(restoreTo); 21883 } 21884 21885 if (a != null && !more) { 21886 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 21887 onSetAlpha(255); 21888 } 21889 parent.finishAnimatingView(this, a); 21890 } 21891 21892 if (more && hardwareAcceleratedCanvas) { 21893 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 21894 // alpha animations should cause the child to recreate its display list 21895 invalidate(true); 21896 } 21897 } 21898 21899 mRecreateDisplayList = false; 21900 21901 return more; 21902 } 21903 getDebugPaint()21904 static Paint getDebugPaint() { 21905 if (sDebugPaint == null) { 21906 sDebugPaint = new Paint(); 21907 sDebugPaint.setAntiAlias(false); 21908 } 21909 return sDebugPaint; 21910 } 21911 dipsToPixels(int dips)21912 final int dipsToPixels(int dips) { 21913 float scale = getContext().getResources().getDisplayMetrics().density; 21914 return (int) (dips * scale + 0.5f); 21915 } 21916 debugDrawFocus(Canvas canvas)21917 final private void debugDrawFocus(Canvas canvas) { 21918 if (isFocused()) { 21919 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 21920 final int l = mScrollX; 21921 final int r = l + mRight - mLeft; 21922 final int t = mScrollY; 21923 final int b = t + mBottom - mTop; 21924 21925 final Paint paint = getDebugPaint(); 21926 paint.setColor(DEBUG_CORNERS_COLOR); 21927 21928 // Draw squares in corners. 21929 paint.setStyle(Paint.Style.FILL); 21930 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 21931 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 21932 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 21933 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 21934 21935 // Draw big X across the view. 21936 paint.setStyle(Paint.Style.STROKE); 21937 canvas.drawLine(l, t, r, b, paint); 21938 canvas.drawLine(l, b, r, t, paint); 21939 } 21940 } 21941 21942 /** 21943 * Manually render this view (and all of its children) to the given Canvas. 21944 * The view must have already done a full layout before this function is 21945 * called. When implementing a view, implement 21946 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 21947 * If you do need to override this method, call the superclass version. 21948 * 21949 * @param canvas The Canvas to which the View is rendered. 21950 */ 21951 @CallSuper draw(Canvas canvas)21952 public void draw(Canvas canvas) { 21953 final int privateFlags = mPrivateFlags; 21954 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 21955 21956 /* 21957 * Draw traversal performs several drawing steps which must be executed 21958 * in the appropriate order: 21959 * 21960 * 1. Draw the background 21961 * 2. If necessary, save the canvas' layers to prepare for fading 21962 * 3. Draw view's content 21963 * 4. Draw children 21964 * 5. If necessary, draw the fading edges and restore layers 21965 * 6. Draw decorations (scrollbars for instance) 21966 */ 21967 21968 // Step 1, draw the background, if needed 21969 int saveCount; 21970 21971 drawBackground(canvas); 21972 21973 // skip step 2 & 5 if possible (common case) 21974 final int viewFlags = mViewFlags; 21975 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 21976 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 21977 if (!verticalEdges && !horizontalEdges) { 21978 // Step 3, draw the content 21979 onDraw(canvas); 21980 21981 // Step 4, draw the children 21982 dispatchDraw(canvas); 21983 21984 drawAutofilledHighlight(canvas); 21985 21986 // Overlay is part of the content and draws beneath Foreground 21987 if (mOverlay != null && !mOverlay.isEmpty()) { 21988 mOverlay.getOverlayView().dispatchDraw(canvas); 21989 } 21990 21991 // Step 6, draw decorations (foreground, scrollbars) 21992 onDrawForeground(canvas); 21993 21994 // Step 7, draw the default focus highlight 21995 drawDefaultFocusHighlight(canvas); 21996 21997 if (debugDraw()) { 21998 debugDrawFocus(canvas); 21999 } 22000 22001 // we're done... 22002 return; 22003 } 22004 22005 /* 22006 * Here we do the full fledged routine... 22007 * (this is an uncommon case where speed matters less, 22008 * this is why we repeat some of the tests that have been 22009 * done above) 22010 */ 22011 22012 boolean drawTop = false; 22013 boolean drawBottom = false; 22014 boolean drawLeft = false; 22015 boolean drawRight = false; 22016 22017 float topFadeStrength = 0.0f; 22018 float bottomFadeStrength = 0.0f; 22019 float leftFadeStrength = 0.0f; 22020 float rightFadeStrength = 0.0f; 22021 22022 // Step 2, save the canvas' layers 22023 int paddingLeft = mPaddingLeft; 22024 22025 final boolean offsetRequired = isPaddingOffsetRequired(); 22026 if (offsetRequired) { 22027 paddingLeft += getLeftPaddingOffset(); 22028 } 22029 22030 int left = mScrollX + paddingLeft; 22031 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 22032 int top = mScrollY + getFadeTop(offsetRequired); 22033 int bottom = top + getFadeHeight(offsetRequired); 22034 22035 if (offsetRequired) { 22036 right += getRightPaddingOffset(); 22037 bottom += getBottomPaddingOffset(); 22038 } 22039 22040 final ScrollabilityCache scrollabilityCache = mScrollCache; 22041 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 22042 int length = (int) fadeHeight; 22043 22044 // clip the fade length if top and bottom fades overlap 22045 // overlapping fades produce odd-looking artifacts 22046 if (verticalEdges && (top + length > bottom - length)) { 22047 length = (bottom - top) / 2; 22048 } 22049 22050 // also clip horizontal fades if necessary 22051 if (horizontalEdges && (left + length > right - length)) { 22052 length = (right - left) / 2; 22053 } 22054 22055 if (verticalEdges) { 22056 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 22057 drawTop = topFadeStrength * fadeHeight > 1.0f; 22058 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 22059 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 22060 } 22061 22062 if (horizontalEdges) { 22063 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 22064 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 22065 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 22066 drawRight = rightFadeStrength * fadeHeight > 1.0f; 22067 } 22068 22069 saveCount = canvas.getSaveCount(); 22070 int topSaveCount = -1; 22071 int bottomSaveCount = -1; 22072 int leftSaveCount = -1; 22073 int rightSaveCount = -1; 22074 22075 int solidColor = getSolidColor(); 22076 if (solidColor == 0) { 22077 if (drawTop) { 22078 topSaveCount = canvas.saveUnclippedLayer(left, top, right, top + length); 22079 } 22080 22081 if (drawBottom) { 22082 bottomSaveCount = canvas.saveUnclippedLayer(left, bottom - length, right, bottom); 22083 } 22084 22085 if (drawLeft) { 22086 leftSaveCount = canvas.saveUnclippedLayer(left, top, left + length, bottom); 22087 } 22088 22089 if (drawRight) { 22090 rightSaveCount = canvas.saveUnclippedLayer(right - length, top, right, bottom); 22091 } 22092 } else { 22093 scrollabilityCache.setFadeColor(solidColor); 22094 } 22095 22096 // Step 3, draw the content 22097 onDraw(canvas); 22098 22099 // Step 4, draw the children 22100 dispatchDraw(canvas); 22101 22102 // Step 5, draw the fade effect and restore layers 22103 final Paint p = scrollabilityCache.paint; 22104 final Matrix matrix = scrollabilityCache.matrix; 22105 final Shader fade = scrollabilityCache.shader; 22106 22107 // must be restored in the reverse order that they were saved 22108 if (drawRight) { 22109 matrix.setScale(1, fadeHeight * rightFadeStrength); 22110 matrix.postRotate(90); 22111 matrix.postTranslate(right, top); 22112 fade.setLocalMatrix(matrix); 22113 p.setShader(fade); 22114 if (solidColor == 0) { 22115 canvas.restoreUnclippedLayer(rightSaveCount, p); 22116 22117 } else { 22118 canvas.drawRect(right - length, top, right, bottom, p); 22119 } 22120 } 22121 22122 if (drawLeft) { 22123 matrix.setScale(1, fadeHeight * leftFadeStrength); 22124 matrix.postRotate(-90); 22125 matrix.postTranslate(left, top); 22126 fade.setLocalMatrix(matrix); 22127 p.setShader(fade); 22128 if (solidColor == 0) { 22129 canvas.restoreUnclippedLayer(leftSaveCount, p); 22130 } else { 22131 canvas.drawRect(left, top, left + length, bottom, p); 22132 } 22133 } 22134 22135 if (drawBottom) { 22136 matrix.setScale(1, fadeHeight * bottomFadeStrength); 22137 matrix.postRotate(180); 22138 matrix.postTranslate(left, bottom); 22139 fade.setLocalMatrix(matrix); 22140 p.setShader(fade); 22141 if (solidColor == 0) { 22142 canvas.restoreUnclippedLayer(bottomSaveCount, p); 22143 } else { 22144 canvas.drawRect(left, bottom - length, right, bottom, p); 22145 } 22146 } 22147 22148 if (drawTop) { 22149 matrix.setScale(1, fadeHeight * topFadeStrength); 22150 matrix.postTranslate(left, top); 22151 fade.setLocalMatrix(matrix); 22152 p.setShader(fade); 22153 if (solidColor == 0) { 22154 canvas.restoreUnclippedLayer(topSaveCount, p); 22155 } else { 22156 canvas.drawRect(left, top, right, top + length, p); 22157 } 22158 } 22159 22160 canvas.restoreToCount(saveCount); 22161 22162 drawAutofilledHighlight(canvas); 22163 22164 // Overlay is part of the content and draws beneath Foreground 22165 if (mOverlay != null && !mOverlay.isEmpty()) { 22166 mOverlay.getOverlayView().dispatchDraw(canvas); 22167 } 22168 22169 // Step 6, draw decorations (foreground, scrollbars) 22170 onDrawForeground(canvas); 22171 22172 if (debugDraw()) { 22173 debugDrawFocus(canvas); 22174 } 22175 } 22176 22177 /** 22178 * Draws the background onto the specified canvas. 22179 * 22180 * @param canvas Canvas on which to draw the background 22181 */ 22182 @UnsupportedAppUsage drawBackground(Canvas canvas)22183 private void drawBackground(Canvas canvas) { 22184 final Drawable background = mBackground; 22185 if (background == null) { 22186 return; 22187 } 22188 22189 setBackgroundBounds(); 22190 22191 // Attempt to use a display list if requested. 22192 if (canvas.isHardwareAccelerated() && mAttachInfo != null 22193 && mAttachInfo.mThreadedRenderer != null) { 22194 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 22195 22196 final RenderNode renderNode = mBackgroundRenderNode; 22197 if (renderNode != null && renderNode.hasDisplayList()) { 22198 setBackgroundRenderNodeProperties(renderNode); 22199 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 22200 return; 22201 } 22202 } 22203 22204 final int scrollX = mScrollX; 22205 final int scrollY = mScrollY; 22206 if ((scrollX | scrollY) == 0) { 22207 background.draw(canvas); 22208 } else { 22209 canvas.translate(scrollX, scrollY); 22210 background.draw(canvas); 22211 canvas.translate(-scrollX, -scrollY); 22212 } 22213 } 22214 22215 /** 22216 * Sets the correct background bounds and rebuilds the outline, if needed. 22217 * <p/> 22218 * This is called by LayoutLib. 22219 */ setBackgroundBounds()22220 void setBackgroundBounds() { 22221 if (mBackgroundSizeChanged && mBackground != null) { 22222 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 22223 mBackgroundSizeChanged = false; 22224 rebuildOutline(); 22225 } 22226 } 22227 setBackgroundRenderNodeProperties(RenderNode renderNode)22228 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 22229 renderNode.setTranslationX(mScrollX); 22230 renderNode.setTranslationY(mScrollY); 22231 } 22232 22233 /** 22234 * Creates a new display list or updates the existing display list for the 22235 * specified Drawable. 22236 * 22237 * @param drawable Drawable for which to create a display list 22238 * @param renderNode Existing RenderNode, or {@code null} 22239 * @return A valid display list for the specified drawable 22240 */ getDrawableRenderNode(Drawable drawable, RenderNode renderNode)22241 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 22242 if (renderNode == null) { 22243 renderNode = RenderNode.create(drawable.getClass().getName(), 22244 new ViewAnimationHostBridge(this)); 22245 renderNode.setUsageHint(RenderNode.USAGE_BACKGROUND); 22246 } 22247 22248 final Rect bounds = drawable.getBounds(); 22249 final int width = bounds.width(); 22250 final int height = bounds.height(); 22251 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 22252 22253 // Reverse left/top translation done by drawable canvas, which will 22254 // instead be applied by rendernode's LTRB bounds below. This way, the 22255 // drawable's bounds match with its rendernode bounds and its content 22256 // will lie within those bounds in the rendernode tree. 22257 canvas.translate(-bounds.left, -bounds.top); 22258 22259 try { 22260 drawable.draw(canvas); 22261 } finally { 22262 renderNode.endRecording(); 22263 } 22264 22265 // Set up drawable properties that are view-independent. 22266 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 22267 renderNode.setProjectBackwards(drawable.isProjected()); 22268 renderNode.setProjectionReceiver(true); 22269 renderNode.setClipToBounds(false); 22270 return renderNode; 22271 } 22272 22273 /** 22274 * Returns the overlay for this view, creating it if it does not yet exist. 22275 * Adding drawables to the overlay will cause them to be displayed whenever 22276 * the view itself is redrawn. Objects in the overlay should be actively 22277 * managed: remove them when they should not be displayed anymore. The 22278 * overlay will always have the same size as its host view. 22279 * 22280 * <p>Note: Overlays do not currently work correctly with {@link 22281 * SurfaceView} or {@link TextureView}; contents in overlays for these 22282 * types of views may not display correctly.</p> 22283 * 22284 * @return The ViewOverlay object for this view. 22285 * @see ViewOverlay 22286 */ getOverlay()22287 public ViewOverlay getOverlay() { 22288 if (mOverlay == null) { 22289 mOverlay = new ViewOverlay(mContext, this); 22290 } 22291 return mOverlay; 22292 } 22293 22294 /** 22295 * Override this if your view is known to always be drawn on top of a solid color background, 22296 * and needs to draw fading edges. Returning a non-zero color enables the view system to 22297 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 22298 * should be set to 0xFF. 22299 * 22300 * @see #setVerticalFadingEdgeEnabled(boolean) 22301 * @see #setHorizontalFadingEdgeEnabled(boolean) 22302 * 22303 * @return The known solid color background for this view, or 0 if the color may vary 22304 */ 22305 @ViewDebug.ExportedProperty(category = "drawing") 22306 @InspectableProperty 22307 @ColorInt getSolidColor()22308 public int getSolidColor() { 22309 return 0; 22310 } 22311 22312 /** 22313 * Build a human readable string representation of the specified view flags. 22314 * 22315 * @param flags the view flags to convert to a string 22316 * @return a String representing the supplied flags 22317 */ printFlags(int flags)22318 private static String printFlags(int flags) { 22319 String output = ""; 22320 int numFlags = 0; 22321 if ((flags & FOCUSABLE) == FOCUSABLE) { 22322 output += "TAKES_FOCUS"; 22323 numFlags++; 22324 } 22325 22326 switch (flags & VISIBILITY_MASK) { 22327 case INVISIBLE: 22328 if (numFlags > 0) { 22329 output += " "; 22330 } 22331 output += "INVISIBLE"; 22332 // USELESS HERE numFlags++; 22333 break; 22334 case GONE: 22335 if (numFlags > 0) { 22336 output += " "; 22337 } 22338 output += "GONE"; 22339 // USELESS HERE numFlags++; 22340 break; 22341 default: 22342 break; 22343 } 22344 return output; 22345 } 22346 22347 /** 22348 * Build a human readable string representation of the specified private 22349 * view flags. 22350 * 22351 * @param privateFlags the private view flags to convert to a string 22352 * @return a String representing the supplied flags 22353 */ printPrivateFlags(int privateFlags)22354 private static String printPrivateFlags(int privateFlags) { 22355 String output = ""; 22356 int numFlags = 0; 22357 22358 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 22359 output += "WANTS_FOCUS"; 22360 numFlags++; 22361 } 22362 22363 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 22364 if (numFlags > 0) { 22365 output += " "; 22366 } 22367 output += "FOCUSED"; 22368 numFlags++; 22369 } 22370 22371 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 22372 if (numFlags > 0) { 22373 output += " "; 22374 } 22375 output += "SELECTED"; 22376 numFlags++; 22377 } 22378 22379 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 22380 if (numFlags > 0) { 22381 output += " "; 22382 } 22383 output += "IS_ROOT_NAMESPACE"; 22384 numFlags++; 22385 } 22386 22387 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 22388 if (numFlags > 0) { 22389 output += " "; 22390 } 22391 output += "HAS_BOUNDS"; 22392 numFlags++; 22393 } 22394 22395 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 22396 if (numFlags > 0) { 22397 output += " "; 22398 } 22399 output += "DRAWN"; 22400 // USELESS HERE numFlags++; 22401 } 22402 return output; 22403 } 22404 22405 /** 22406 * <p>Indicates whether or not this view's layout will be requested during 22407 * the next hierarchy layout pass.</p> 22408 * 22409 * @return true if the layout will be forced during next layout pass 22410 */ isLayoutRequested()22411 public boolean isLayoutRequested() { 22412 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 22413 } 22414 22415 /** 22416 * Return true if o is a ViewGroup that is laying out using optical bounds. 22417 * @hide 22418 */ isLayoutModeOptical(Object o)22419 public static boolean isLayoutModeOptical(Object o) { 22420 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 22421 } 22422 setOpticalFrame(int left, int top, int right, int bottom)22423 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 22424 Insets parentInsets = mParent instanceof View ? 22425 ((View) mParent).getOpticalInsets() : Insets.NONE; 22426 Insets childInsets = getOpticalInsets(); 22427 return setFrame( 22428 left + parentInsets.left - childInsets.left, 22429 top + parentInsets.top - childInsets.top, 22430 right + parentInsets.left + childInsets.right, 22431 bottom + parentInsets.top + childInsets.bottom); 22432 } 22433 22434 /** 22435 * Assign a size and position to a view and all of its 22436 * descendants 22437 * 22438 * <p>This is the second phase of the layout mechanism. 22439 * (The first is measuring). In this phase, each parent calls 22440 * layout on all of its children to position them. 22441 * This is typically done using the child measurements 22442 * that were stored in the measure pass().</p> 22443 * 22444 * <p>Derived classes should not override this method. 22445 * Derived classes with children should override 22446 * onLayout. In that method, they should 22447 * call layout on each of their children.</p> 22448 * 22449 * @param l Left position, relative to parent 22450 * @param t Top position, relative to parent 22451 * @param r Right position, relative to parent 22452 * @param b Bottom position, relative to parent 22453 */ 22454 @SuppressWarnings({"unchecked"}) layout(int l, int t, int r, int b)22455 public void layout(int l, int t, int r, int b) { 22456 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 22457 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 22458 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 22459 } 22460 22461 int oldL = mLeft; 22462 int oldT = mTop; 22463 int oldB = mBottom; 22464 int oldR = mRight; 22465 22466 boolean changed = isLayoutModeOptical(mParent) ? 22467 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 22468 22469 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 22470 onLayout(changed, l, t, r, b); 22471 22472 if (shouldDrawRoundScrollbar()) { 22473 if(mRoundScrollbarRenderer == null) { 22474 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 22475 } 22476 } else { 22477 mRoundScrollbarRenderer = null; 22478 } 22479 22480 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 22481 22482 ListenerInfo li = mListenerInfo; 22483 if (li != null && li.mOnLayoutChangeListeners != null) { 22484 ArrayList<OnLayoutChangeListener> listenersCopy = 22485 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 22486 int numListeners = listenersCopy.size(); 22487 for (int i = 0; i < numListeners; ++i) { 22488 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 22489 } 22490 } 22491 } 22492 22493 final boolean wasLayoutValid = isLayoutValid(); 22494 22495 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 22496 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 22497 22498 if (!wasLayoutValid && isFocused()) { 22499 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 22500 if (canTakeFocus()) { 22501 // We have a robust focus, so parents should no longer be wanting focus. 22502 clearParentsWantFocus(); 22503 } else if (getViewRootImpl() == null || !getViewRootImpl().isInLayout()) { 22504 // This is a weird case. Most-likely the user, rather than ViewRootImpl, called 22505 // layout. In this case, there's no guarantee that parent layouts will be evaluated 22506 // and thus the safest action is to clear focus here. 22507 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 22508 clearParentsWantFocus(); 22509 } else if (!hasParentWantsFocus()) { 22510 // original requestFocus was likely on this view directly, so just clear focus 22511 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 22512 } 22513 // otherwise, we let parents handle re-assigning focus during their layout passes. 22514 } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 22515 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 22516 View focused = findFocus(); 22517 if (focused != null) { 22518 // Try to restore focus as close as possible to our starting focus. 22519 if (!restoreDefaultFocus() && !hasParentWantsFocus()) { 22520 // Give up and clear focus once we've reached the top-most parent which wants 22521 // focus. 22522 focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 22523 } 22524 } 22525 } 22526 22527 if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { 22528 mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 22529 notifyEnterOrExitForAutoFillIfNeeded(true); 22530 } 22531 22532 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 22533 } 22534 hasParentWantsFocus()22535 private boolean hasParentWantsFocus() { 22536 ViewParent parent = mParent; 22537 while (parent instanceof ViewGroup) { 22538 ViewGroup pv = (ViewGroup) parent; 22539 if ((pv.mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 22540 return true; 22541 } 22542 parent = pv.mParent; 22543 } 22544 return false; 22545 } 22546 22547 /** 22548 * Called from layout when this view should 22549 * assign a size and position to each of its children. 22550 * 22551 * Derived classes with children should override 22552 * this method and call layout on each of 22553 * their children. 22554 * @param changed This is a new size or position for this view 22555 * @param left Left position, relative to parent 22556 * @param top Top position, relative to parent 22557 * @param right Right position, relative to parent 22558 * @param bottom Bottom position, relative to parent 22559 */ onLayout(boolean changed, int left, int top, int right, int bottom)22560 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 22561 } 22562 22563 /** 22564 * Assign a size and position to this view. 22565 * 22566 * This is called from layout. 22567 * 22568 * @param left Left position, relative to parent 22569 * @param top Top position, relative to parent 22570 * @param right Right position, relative to parent 22571 * @param bottom Bottom position, relative to parent 22572 * @return true if the new size and position are different than the 22573 * previous ones 22574 * {@hide} 22575 */ 22576 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) setFrame(int left, int top, int right, int bottom)22577 protected boolean setFrame(int left, int top, int right, int bottom) { 22578 boolean changed = false; 22579 22580 if (DBG) { 22581 Log.d(VIEW_LOG_TAG, this + " View.setFrame(" + left + "," + top + "," 22582 + right + "," + bottom + ")"); 22583 } 22584 22585 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 22586 changed = true; 22587 22588 // Remember our drawn bit 22589 int drawn = mPrivateFlags & PFLAG_DRAWN; 22590 22591 int oldWidth = mRight - mLeft; 22592 int oldHeight = mBottom - mTop; 22593 int newWidth = right - left; 22594 int newHeight = bottom - top; 22595 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 22596 22597 // Invalidate our old position 22598 invalidate(sizeChanged); 22599 22600 mLeft = left; 22601 mTop = top; 22602 mRight = right; 22603 mBottom = bottom; 22604 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 22605 22606 mPrivateFlags |= PFLAG_HAS_BOUNDS; 22607 22608 22609 if (sizeChanged) { 22610 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 22611 } 22612 22613 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 22614 // If we are visible, force the DRAWN bit to on so that 22615 // this invalidate will go through (at least to our parent). 22616 // This is because someone may have invalidated this view 22617 // before this call to setFrame came in, thereby clearing 22618 // the DRAWN bit. 22619 mPrivateFlags |= PFLAG_DRAWN; 22620 invalidate(sizeChanged); 22621 // parent display list may need to be recreated based on a change in the bounds 22622 // of any child 22623 invalidateParentCaches(); 22624 } 22625 22626 // Reset drawn bit to original value (invalidate turns it off) 22627 mPrivateFlags |= drawn; 22628 22629 mBackgroundSizeChanged = true; 22630 mDefaultFocusHighlightSizeChanged = true; 22631 if (mForegroundInfo != null) { 22632 mForegroundInfo.mBoundsChanged = true; 22633 } 22634 22635 notifySubtreeAccessibilityStateChangedIfNeeded(); 22636 } 22637 return changed; 22638 } 22639 22640 /** 22641 * Assign a size and position to this view. 22642 * 22643 * This method is meant to be used in animations only as it applies this position and size 22644 * for the view only temporary and it can be changed back at any time by the layout. 22645 * 22646 * @param left Left position, relative to parent 22647 * @param top Top position, relative to parent 22648 * @param right Right position, relative to parent 22649 * @param bottom Bottom position, relative to parent 22650 * 22651 * @see #setLeft(int), #setRight(int), #setTop(int), #setBottom(int) 22652 */ setLeftTopRightBottom(int left, int top, int right, int bottom)22653 public final void setLeftTopRightBottom(int left, int top, int right, int bottom) { 22654 setFrame(left, top, right, bottom); 22655 } 22656 sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight)22657 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 22658 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 22659 if (mOverlay != null) { 22660 mOverlay.getOverlayView().setRight(newWidth); 22661 mOverlay.getOverlayView().setBottom(newHeight); 22662 } 22663 // If this isn't laid out yet, focus assignment will be handled during the "deferment/ 22664 // backtracking" of requestFocus during layout, so don't touch focus here. 22665 if (!sCanFocusZeroSized && isLayoutValid() 22666 // Don't touch focus if animating 22667 && !(mParent instanceof ViewGroup && ((ViewGroup) mParent).isLayoutSuppressed())) { 22668 if (newWidth <= 0 || newHeight <= 0) { 22669 if (hasFocus()) { 22670 clearFocus(); 22671 if (mParent instanceof ViewGroup) { 22672 ((ViewGroup) mParent).clearFocusedInCluster(); 22673 } 22674 } 22675 clearAccessibilityFocus(); 22676 } else if (oldWidth <= 0 || oldHeight <= 0) { 22677 if (mParent != null && canTakeFocus()) { 22678 mParent.focusableViewAvailable(this); 22679 } 22680 } 22681 } 22682 rebuildOutline(); 22683 } 22684 22685 /** 22686 * Finalize inflating a view from XML. This is called as the last phase 22687 * of inflation, after all child views have been added. 22688 * 22689 * <p>Even if the subclass overrides onFinishInflate, they should always be 22690 * sure to call the super method, so that we get called. 22691 */ 22692 @CallSuper onFinishInflate()22693 protected void onFinishInflate() { 22694 } 22695 22696 /** 22697 * Returns the resources associated with this view. 22698 * 22699 * @return Resources object. 22700 */ getResources()22701 public Resources getResources() { 22702 return mResources; 22703 } 22704 22705 /** 22706 * Invalidates the specified Drawable. 22707 * 22708 * @param drawable the drawable to invalidate 22709 */ 22710 @Override invalidateDrawable(@onNull Drawable drawable)22711 public void invalidateDrawable(@NonNull Drawable drawable) { 22712 if (verifyDrawable(drawable)) { 22713 final Rect dirty = drawable.getDirtyBounds(); 22714 final int scrollX = mScrollX; 22715 final int scrollY = mScrollY; 22716 22717 invalidate(dirty.left + scrollX, dirty.top + scrollY, 22718 dirty.right + scrollX, dirty.bottom + scrollY); 22719 rebuildOutline(); 22720 } 22721 } 22722 22723 /** 22724 * Schedules an action on a drawable to occur at a specified time. 22725 * 22726 * @param who the recipient of the action 22727 * @param what the action to run on the drawable 22728 * @param when the time at which the action must occur. Uses the 22729 * {@link SystemClock#uptimeMillis} timebase. 22730 */ 22731 @Override scheduleDrawable(@onNull Drawable who, @NonNull Runnable what, long when)22732 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 22733 if (verifyDrawable(who) && what != null) { 22734 final long delay = when - SystemClock.uptimeMillis(); 22735 if (mAttachInfo != null) { 22736 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 22737 Choreographer.CALLBACK_ANIMATION, what, who, 22738 Choreographer.subtractFrameDelay(delay)); 22739 } else { 22740 // Postpone the runnable until we know 22741 // on which thread it needs to run. 22742 getRunQueue().postDelayed(what, delay); 22743 } 22744 } 22745 } 22746 22747 /** 22748 * Cancels a scheduled action on a drawable. 22749 * 22750 * @param who the recipient of the action 22751 * @param what the action to cancel 22752 */ 22753 @Override unscheduleDrawable(@onNull Drawable who, @NonNull Runnable what)22754 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 22755 if (verifyDrawable(who) && what != null) { 22756 if (mAttachInfo != null) { 22757 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 22758 Choreographer.CALLBACK_ANIMATION, what, who); 22759 } 22760 getRunQueue().removeCallbacks(what); 22761 } 22762 } 22763 22764 /** 22765 * Unschedule any events associated with the given Drawable. This can be 22766 * used when selecting a new Drawable into a view, so that the previous 22767 * one is completely unscheduled. 22768 * 22769 * @param who The Drawable to unschedule. 22770 * 22771 * @see #drawableStateChanged 22772 */ unscheduleDrawable(Drawable who)22773 public void unscheduleDrawable(Drawable who) { 22774 if (mAttachInfo != null && who != null) { 22775 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 22776 Choreographer.CALLBACK_ANIMATION, null, who); 22777 } 22778 } 22779 22780 /** 22781 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 22782 * that the View directionality can and will be resolved before its Drawables. 22783 * 22784 * Will call {@link View#onResolveDrawables} when resolution is done. 22785 * 22786 * @hide 22787 */ resolveDrawables()22788 protected void resolveDrawables() { 22789 // Drawables resolution may need to happen before resolving the layout direction (which is 22790 // done only during the measure() call). 22791 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 22792 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 22793 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 22794 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 22795 // direction to be resolved as its resolved value will be the same as its raw value. 22796 if (!isLayoutDirectionResolved() && 22797 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 22798 return; 22799 } 22800 22801 final int layoutDirection = isLayoutDirectionResolved() ? 22802 getLayoutDirection() : getRawLayoutDirection(); 22803 22804 if (mBackground != null) { 22805 mBackground.setLayoutDirection(layoutDirection); 22806 } 22807 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 22808 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 22809 } 22810 if (mDefaultFocusHighlight != null) { 22811 mDefaultFocusHighlight.setLayoutDirection(layoutDirection); 22812 } 22813 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 22814 onResolveDrawables(layoutDirection); 22815 } 22816 areDrawablesResolved()22817 boolean areDrawablesResolved() { 22818 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 22819 } 22820 22821 /** 22822 * Called when layout direction has been resolved. 22823 * 22824 * The default implementation does nothing. 22825 * 22826 * @param layoutDirection The resolved layout direction. 22827 * 22828 * @see #LAYOUT_DIRECTION_LTR 22829 * @see #LAYOUT_DIRECTION_RTL 22830 * 22831 * @hide 22832 */ onResolveDrawables(@esolvedLayoutDir int layoutDirection)22833 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 22834 } 22835 22836 /** 22837 * @hide 22838 */ 22839 @TestApi resetResolvedDrawables()22840 protected void resetResolvedDrawables() { 22841 resetResolvedDrawablesInternal(); 22842 } 22843 resetResolvedDrawablesInternal()22844 void resetResolvedDrawablesInternal() { 22845 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 22846 } 22847 22848 /** 22849 * If your view subclass is displaying its own Drawable objects, it should 22850 * override this function and return true for any Drawable it is 22851 * displaying. This allows animations for those drawables to be 22852 * scheduled. 22853 * 22854 * <p>Be sure to call through to the super class when overriding this 22855 * function. 22856 * 22857 * @param who The Drawable to verify. Return true if it is one you are 22858 * displaying, else return the result of calling through to the 22859 * super class. 22860 * 22861 * @return boolean If true than the Drawable is being displayed in the 22862 * view; else false and it is not allowed to animate. 22863 * 22864 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 22865 * @see #drawableStateChanged() 22866 */ 22867 @CallSuper verifyDrawable(@onNull Drawable who)22868 protected boolean verifyDrawable(@NonNull Drawable who) { 22869 // Avoid verifying the scroll bar drawable so that we don't end up in 22870 // an invalidation loop. This effectively prevents the scroll bar 22871 // drawable from triggering invalidations and scheduling runnables. 22872 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) 22873 || (mDefaultFocusHighlight == who); 22874 } 22875 22876 /** 22877 * This function is called whenever the state of the view changes in such 22878 * a way that it impacts the state of drawables being shown. 22879 * <p> 22880 * If the View has a StateListAnimator, it will also be called to run necessary state 22881 * change animations. 22882 * <p> 22883 * Be sure to call through to the superclass when overriding this function. 22884 * 22885 * @see Drawable#setState(int[]) 22886 */ 22887 @CallSuper drawableStateChanged()22888 protected void drawableStateChanged() { 22889 final int[] state = getDrawableState(); 22890 boolean changed = false; 22891 22892 final Drawable bg = mBackground; 22893 if (bg != null && bg.isStateful()) { 22894 changed |= bg.setState(state); 22895 } 22896 22897 final Drawable hl = mDefaultFocusHighlight; 22898 if (hl != null && hl.isStateful()) { 22899 changed |= hl.setState(state); 22900 } 22901 22902 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 22903 if (fg != null && fg.isStateful()) { 22904 changed |= fg.setState(state); 22905 } 22906 22907 if (mScrollCache != null) { 22908 final Drawable scrollBar = mScrollCache.scrollBar; 22909 if (scrollBar != null && scrollBar.isStateful()) { 22910 changed |= scrollBar.setState(state) 22911 && mScrollCache.state != ScrollabilityCache.OFF; 22912 } 22913 } 22914 22915 if (mStateListAnimator != null) { 22916 mStateListAnimator.setState(state); 22917 } 22918 22919 if (changed) { 22920 invalidate(); 22921 } 22922 } 22923 22924 /** 22925 * This function is called whenever the view hotspot changes and needs to 22926 * be propagated to drawables or child views managed by the view. 22927 * <p> 22928 * Dispatching to child views is handled by 22929 * {@link #dispatchDrawableHotspotChanged(float, float)}. 22930 * <p> 22931 * Be sure to call through to the superclass when overriding this function. 22932 * 22933 * @param x hotspot x coordinate 22934 * @param y hotspot y coordinate 22935 */ 22936 @CallSuper drawableHotspotChanged(float x, float y)22937 public void drawableHotspotChanged(float x, float y) { 22938 if (mBackground != null) { 22939 mBackground.setHotspot(x, y); 22940 } 22941 if (mDefaultFocusHighlight != null) { 22942 mDefaultFocusHighlight.setHotspot(x, y); 22943 } 22944 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 22945 mForegroundInfo.mDrawable.setHotspot(x, y); 22946 } 22947 22948 dispatchDrawableHotspotChanged(x, y); 22949 } 22950 22951 /** 22952 * Dispatches drawableHotspotChanged to all of this View's children. 22953 * 22954 * @param x hotspot x coordinate 22955 * @param y hotspot y coordinate 22956 * @see #drawableHotspotChanged(float, float) 22957 */ dispatchDrawableHotspotChanged(float x, float y)22958 public void dispatchDrawableHotspotChanged(float x, float y) { 22959 } 22960 22961 /** 22962 * Call this to force a view to update its drawable state. This will cause 22963 * drawableStateChanged to be called on this view. Views that are interested 22964 * in the new state should call getDrawableState. 22965 * 22966 * @see #drawableStateChanged 22967 * @see #getDrawableState 22968 */ refreshDrawableState()22969 public void refreshDrawableState() { 22970 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 22971 drawableStateChanged(); 22972 22973 ViewParent parent = mParent; 22974 if (parent != null) { 22975 parent.childDrawableStateChanged(this); 22976 } 22977 } 22978 22979 /** 22980 * Create a default focus highlight if it doesn't exist. 22981 * @return a default focus highlight. 22982 */ getDefaultFocusHighlightDrawable()22983 private Drawable getDefaultFocusHighlightDrawable() { 22984 if (mDefaultFocusHighlightCache == null) { 22985 if (mContext != null) { 22986 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; 22987 final TypedArray ta = mContext.obtainStyledAttributes(attrs); 22988 mDefaultFocusHighlightCache = ta.getDrawable(0); 22989 ta.recycle(); 22990 } 22991 } 22992 return mDefaultFocusHighlightCache; 22993 } 22994 22995 /** 22996 * Set the current default focus highlight. 22997 * @param highlight the highlight drawable, or {@code null} if it's no longer needed. 22998 */ setDefaultFocusHighlight(Drawable highlight)22999 private void setDefaultFocusHighlight(Drawable highlight) { 23000 mDefaultFocusHighlight = highlight; 23001 mDefaultFocusHighlightSizeChanged = true; 23002 if (highlight != null) { 23003 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 23004 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 23005 } 23006 highlight.setLayoutDirection(getLayoutDirection()); 23007 if (highlight.isStateful()) { 23008 highlight.setState(getDrawableState()); 23009 } 23010 if (isAttachedToWindow()) { 23011 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 23012 } 23013 // Set callback last, since the view may still be initializing. 23014 highlight.setCallback(this); 23015 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 23016 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 23017 mPrivateFlags |= PFLAG_SKIP_DRAW; 23018 } 23019 invalidate(); 23020 } 23021 23022 /** 23023 * Check whether we need to draw a default focus highlight when this view gets focused, 23024 * which requires: 23025 * <ul> 23026 * <li>In both background and foreground, {@link android.R.attr#state_focused} 23027 * is not defined.</li> 23028 * <li>This view is not in touch mode.</li> 23029 * <li>This view doesn't opt out for a default focus highlight, via 23030 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li> 23031 * <li>This view is attached to window.</li> 23032 * </ul> 23033 * @return {@code true} if a default focus highlight is needed. 23034 * @hide 23035 */ 23036 @TestApi isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground)23037 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { 23038 final boolean lackFocusState = (background == null || !background.isStateful() 23039 || !background.hasFocusStateSpecified()) 23040 && (foreground == null || !foreground.isStateful() 23041 || !foreground.hasFocusStateSpecified()); 23042 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState 23043 && isAttachedToWindow() && sUseDefaultFocusHighlight; 23044 } 23045 23046 /** 23047 * When this view is focused, switches on/off the default focused highlight. 23048 * <p> 23049 * This always happens when this view is focused, and only at this moment the default focus 23050 * highlight can be visible. 23051 */ switchDefaultFocusHighlight()23052 private void switchDefaultFocusHighlight() { 23053 if (isFocused()) { 23054 final boolean needed = isDefaultFocusHighlightNeeded(mBackground, 23055 mForegroundInfo == null ? null : mForegroundInfo.mDrawable); 23056 final boolean active = mDefaultFocusHighlight != null; 23057 if (needed && !active) { 23058 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); 23059 } else if (!needed && active) { 23060 // The highlight is no longer needed, so tear it down. 23061 setDefaultFocusHighlight(null); 23062 } 23063 } 23064 } 23065 23066 /** 23067 * Draw the default focus highlight onto the canvas. 23068 * @param canvas the canvas where we're drawing the highlight. 23069 */ drawDefaultFocusHighlight(Canvas canvas)23070 private void drawDefaultFocusHighlight(Canvas canvas) { 23071 if (mDefaultFocusHighlight != null) { 23072 if (mDefaultFocusHighlightSizeChanged) { 23073 mDefaultFocusHighlightSizeChanged = false; 23074 final int l = mScrollX; 23075 final int r = l + mRight - mLeft; 23076 final int t = mScrollY; 23077 final int b = t + mBottom - mTop; 23078 mDefaultFocusHighlight.setBounds(l, t, r, b); 23079 } 23080 mDefaultFocusHighlight.draw(canvas); 23081 } 23082 } 23083 23084 /** 23085 * Return an array of resource IDs of the drawable states representing the 23086 * current state of the view. 23087 * 23088 * @return The current drawable state 23089 * 23090 * @see Drawable#setState(int[]) 23091 * @see #drawableStateChanged() 23092 * @see #onCreateDrawableState(int) 23093 */ getDrawableState()23094 public final int[] getDrawableState() { 23095 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 23096 return mDrawableState; 23097 } else { 23098 mDrawableState = onCreateDrawableState(0); 23099 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 23100 return mDrawableState; 23101 } 23102 } 23103 23104 /** 23105 * Generate the new {@link android.graphics.drawable.Drawable} state for 23106 * this view. This is called by the view 23107 * system when the cached Drawable state is determined to be invalid. To 23108 * retrieve the current state, you should use {@link #getDrawableState}. 23109 * 23110 * @param extraSpace if non-zero, this is the number of extra entries you 23111 * would like in the returned array in which you can place your own 23112 * states. 23113 * 23114 * @return Returns an array holding the current {@link Drawable} state of 23115 * the view. 23116 * 23117 * @see #mergeDrawableStates(int[], int[]) 23118 */ onCreateDrawableState(int extraSpace)23119 protected int[] onCreateDrawableState(int extraSpace) { 23120 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 23121 mParent instanceof View) { 23122 return ((View) mParent).onCreateDrawableState(extraSpace); 23123 } 23124 23125 int[] drawableState; 23126 23127 int privateFlags = mPrivateFlags; 23128 23129 int viewStateIndex = 0; 23130 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 23131 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 23132 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 23133 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 23134 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 23135 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 23136 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 23137 ThreadedRenderer.isAvailable()) { 23138 // This is set if HW acceleration is requested, even if the current 23139 // process doesn't allow it. This is just to allow app preview 23140 // windows to better match their app. 23141 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 23142 } 23143 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 23144 23145 final int privateFlags2 = mPrivateFlags2; 23146 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 23147 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 23148 } 23149 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 23150 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 23151 } 23152 23153 drawableState = StateSet.get(viewStateIndex); 23154 23155 //noinspection ConstantIfStatement 23156 if (false) { 23157 Log.i("View", "drawableStateIndex=" + viewStateIndex); 23158 Log.i("View", toString() 23159 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 23160 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 23161 + " fo=" + hasFocus() 23162 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 23163 + " wf=" + hasWindowFocus() 23164 + ": " + Arrays.toString(drawableState)); 23165 } 23166 23167 if (extraSpace == 0) { 23168 return drawableState; 23169 } 23170 23171 final int[] fullState; 23172 if (drawableState != null) { 23173 fullState = new int[drawableState.length + extraSpace]; 23174 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 23175 } else { 23176 fullState = new int[extraSpace]; 23177 } 23178 23179 return fullState; 23180 } 23181 23182 /** 23183 * Merge your own state values in <var>additionalState</var> into the base 23184 * state values <var>baseState</var> that were returned by 23185 * {@link #onCreateDrawableState(int)}. 23186 * 23187 * @param baseState The base state values returned by 23188 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 23189 * own additional state values. 23190 * 23191 * @param additionalState The additional state values you would like 23192 * added to <var>baseState</var>; this array is not modified. 23193 * 23194 * @return As a convenience, the <var>baseState</var> array you originally 23195 * passed into the function is returned. 23196 * 23197 * @see #onCreateDrawableState(int) 23198 */ mergeDrawableStates(int[] baseState, int[] additionalState)23199 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 23200 final int N = baseState.length; 23201 int i = N - 1; 23202 while (i >= 0 && baseState[i] == 0) { 23203 i--; 23204 } 23205 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 23206 return baseState; 23207 } 23208 23209 /** 23210 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 23211 * on all Drawable objects associated with this view. 23212 * <p> 23213 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 23214 * attached to this view. 23215 */ 23216 @CallSuper jumpDrawablesToCurrentState()23217 public void jumpDrawablesToCurrentState() { 23218 if (mBackground != null) { 23219 mBackground.jumpToCurrentState(); 23220 } 23221 if (mStateListAnimator != null) { 23222 mStateListAnimator.jumpToCurrentState(); 23223 } 23224 if (mDefaultFocusHighlight != null) { 23225 mDefaultFocusHighlight.jumpToCurrentState(); 23226 } 23227 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 23228 mForegroundInfo.mDrawable.jumpToCurrentState(); 23229 } 23230 } 23231 23232 /** 23233 * Sets the background color for this view. 23234 * @param color the color of the background 23235 */ 23236 @RemotableViewMethod setBackgroundColor(@olorInt int color)23237 public void setBackgroundColor(@ColorInt int color) { 23238 if (mBackground instanceof ColorDrawable) { 23239 ((ColorDrawable) mBackground.mutate()).setColor(color); 23240 computeOpaqueFlags(); 23241 mBackgroundResource = 0; 23242 } else { 23243 setBackground(new ColorDrawable(color)); 23244 } 23245 } 23246 23247 /** 23248 * Set the background to a given resource. The resource should refer to 23249 * a Drawable object or 0 to remove the background. 23250 * @param resid The identifier of the resource. 23251 * 23252 * @attr ref android.R.styleable#View_background 23253 */ 23254 @RemotableViewMethod setBackgroundResource(@rawableRes int resid)23255 public void setBackgroundResource(@DrawableRes int resid) { 23256 if (resid != 0 && resid == mBackgroundResource) { 23257 return; 23258 } 23259 23260 Drawable d = null; 23261 if (resid != 0) { 23262 d = mContext.getDrawable(resid); 23263 } 23264 setBackground(d); 23265 23266 mBackgroundResource = resid; 23267 } 23268 23269 /** 23270 * Set the background to a given Drawable, or remove the background. If the 23271 * background has padding, this View's padding is set to the background's 23272 * padding. However, when a background is removed, this View's padding isn't 23273 * touched. If setting the padding is desired, please use 23274 * {@link #setPadding(int, int, int, int)}. 23275 * 23276 * @param background The Drawable to use as the background, or null to remove the 23277 * background 23278 */ setBackground(Drawable background)23279 public void setBackground(Drawable background) { 23280 //noinspection deprecation 23281 setBackgroundDrawable(background); 23282 } 23283 23284 /** 23285 * @deprecated use {@link #setBackground(Drawable)} instead 23286 */ 23287 @Deprecated setBackgroundDrawable(Drawable background)23288 public void setBackgroundDrawable(Drawable background) { 23289 computeOpaqueFlags(); 23290 23291 if (background == mBackground) { 23292 return; 23293 } 23294 23295 boolean requestLayout = false; 23296 23297 mBackgroundResource = 0; 23298 23299 /* 23300 * Regardless of whether we're setting a new background or not, we want 23301 * to clear the previous drawable. setVisible first while we still have the callback set. 23302 */ 23303 if (mBackground != null) { 23304 if (isAttachedToWindow()) { 23305 mBackground.setVisible(false, false); 23306 } 23307 mBackground.setCallback(null); 23308 unscheduleDrawable(mBackground); 23309 } 23310 23311 if (background != null) { 23312 Rect padding = sThreadLocal.get(); 23313 if (padding == null) { 23314 padding = new Rect(); 23315 sThreadLocal.set(padding); 23316 } 23317 resetResolvedDrawablesInternal(); 23318 background.setLayoutDirection(getLayoutDirection()); 23319 if (background.getPadding(padding)) { 23320 resetResolvedPaddingInternal(); 23321 switch (background.getLayoutDirection()) { 23322 case LAYOUT_DIRECTION_RTL: 23323 mUserPaddingLeftInitial = padding.right; 23324 mUserPaddingRightInitial = padding.left; 23325 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 23326 break; 23327 case LAYOUT_DIRECTION_LTR: 23328 default: 23329 mUserPaddingLeftInitial = padding.left; 23330 mUserPaddingRightInitial = padding.right; 23331 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 23332 } 23333 mLeftPaddingDefined = false; 23334 mRightPaddingDefined = false; 23335 } 23336 23337 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 23338 // if it has a different minimum size, we should layout again 23339 if (mBackground == null 23340 || mBackground.getMinimumHeight() != background.getMinimumHeight() 23341 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 23342 requestLayout = true; 23343 } 23344 23345 // Set mBackground before we set this as the callback and start making other 23346 // background drawable state change calls. In particular, the setVisible call below 23347 // can result in drawables attempting to start animations or otherwise invalidate, 23348 // which requires the view set as the callback (us) to recognize the drawable as 23349 // belonging to it as per verifyDrawable. 23350 mBackground = background; 23351 if (background.isStateful()) { 23352 background.setState(getDrawableState()); 23353 } 23354 if (isAttachedToWindow()) { 23355 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 23356 } 23357 23358 applyBackgroundTint(); 23359 23360 // Set callback last, since the view may still be initializing. 23361 background.setCallback(this); 23362 23363 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 23364 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 23365 requestLayout = true; 23366 } 23367 } else { 23368 /* Remove the background */ 23369 mBackground = null; 23370 if ((mViewFlags & WILL_NOT_DRAW) != 0 23371 && (mDefaultFocusHighlight == null) 23372 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 23373 mPrivateFlags |= PFLAG_SKIP_DRAW; 23374 } 23375 23376 /* 23377 * When the background is set, we try to apply its padding to this 23378 * View. When the background is removed, we don't touch this View's 23379 * padding. This is noted in the Javadocs. Hence, we don't need to 23380 * requestLayout(), the invalidate() below is sufficient. 23381 */ 23382 23383 // The old background's minimum size could have affected this 23384 // View's layout, so let's requestLayout 23385 requestLayout = true; 23386 } 23387 23388 computeOpaqueFlags(); 23389 23390 if (requestLayout) { 23391 requestLayout(); 23392 } 23393 23394 mBackgroundSizeChanged = true; 23395 invalidate(true); 23396 invalidateOutline(); 23397 } 23398 23399 /** 23400 * Gets the background drawable 23401 * 23402 * @return The drawable used as the background for this view, if any. 23403 * 23404 * @see #setBackground(Drawable) 23405 * 23406 * @attr ref android.R.styleable#View_background 23407 */ 23408 @InspectableProperty getBackground()23409 public Drawable getBackground() { 23410 return mBackground; 23411 } 23412 23413 /** 23414 * Applies a tint to the background drawable. Does not modify the current tint 23415 * mode, which is {@link BlendMode#SRC_IN} by default. 23416 * <p> 23417 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 23418 * mutate the drawable and apply the specified tint and tint mode using 23419 * {@link Drawable#setTintList(ColorStateList)}. 23420 * 23421 * @param tint the tint to apply, may be {@code null} to clear tint 23422 * 23423 * @attr ref android.R.styleable#View_backgroundTint 23424 * @see #getBackgroundTintList() 23425 * @see Drawable#setTintList(ColorStateList) 23426 */ setBackgroundTintList(@ullable ColorStateList tint)23427 public void setBackgroundTintList(@Nullable ColorStateList tint) { 23428 if (mBackgroundTint == null) { 23429 mBackgroundTint = new TintInfo(); 23430 } 23431 mBackgroundTint.mTintList = tint; 23432 mBackgroundTint.mHasTintList = true; 23433 23434 applyBackgroundTint(); 23435 } 23436 23437 /** 23438 * Return the tint applied to the background drawable, if specified. 23439 * 23440 * @return the tint applied to the background drawable 23441 * @attr ref android.R.styleable#View_backgroundTint 23442 * @see #setBackgroundTintList(ColorStateList) 23443 */ 23444 @InspectableProperty(name = "backgroundTint") 23445 @Nullable getBackgroundTintList()23446 public ColorStateList getBackgroundTintList() { 23447 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 23448 } 23449 23450 /** 23451 * Specifies the blending mode used to apply the tint specified by 23452 * {@link #setBackgroundTintList(ColorStateList)}} to the background 23453 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 23454 * 23455 * @param tintMode the blending mode used to apply the tint, may be 23456 * {@code null} to clear tint 23457 * @attr ref android.R.styleable#View_backgroundTintMode 23458 * @see #getBackgroundTintMode() 23459 * @see Drawable#setTintMode(PorterDuff.Mode) 23460 */ setBackgroundTintMode(@ullable PorterDuff.Mode tintMode)23461 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 23462 BlendMode mode = null; 23463 if (tintMode != null) { 23464 mode = BlendMode.fromValue(tintMode.nativeInt); 23465 } 23466 23467 setBackgroundTintBlendMode(mode); 23468 } 23469 23470 /** 23471 * Specifies the blending mode used to apply the tint specified by 23472 * {@link #setBackgroundTintList(ColorStateList)}} to the background 23473 * drawable. The default mode is {@link BlendMode#SRC_IN}. 23474 * 23475 * @param blendMode the blending mode used to apply the tint, may be 23476 * {@code null} to clear tint 23477 * @attr ref android.R.styleable#View_backgroundTintMode 23478 * @see #getBackgroundTintMode() 23479 * @see Drawable#setTintBlendMode(BlendMode) 23480 */ setBackgroundTintBlendMode(@ullable BlendMode blendMode)23481 public void setBackgroundTintBlendMode(@Nullable BlendMode blendMode) { 23482 if (mBackgroundTint == null) { 23483 mBackgroundTint = new TintInfo(); 23484 } 23485 23486 mBackgroundTint.mBlendMode = blendMode; 23487 mBackgroundTint.mHasTintMode = true; 23488 23489 applyBackgroundTint(); 23490 } 23491 23492 /** 23493 * Return the blending mode used to apply the tint to the background 23494 * drawable, if specified. 23495 * 23496 * @return the blending mode used to apply the tint to the background 23497 * drawable 23498 * @attr ref android.R.styleable#View_backgroundTintMode 23499 * @see #setBackgroundTintBlendMode(BlendMode) 23500 * 23501 */ 23502 @Nullable 23503 @InspectableProperty getBackgroundTintMode()23504 public PorterDuff.Mode getBackgroundTintMode() { 23505 PorterDuff.Mode porterDuffMode; 23506 if (mBackgroundTint != null && mBackgroundTint.mBlendMode != null) { 23507 porterDuffMode = BlendMode.blendModeToPorterDuffMode(mBackgroundTint.mBlendMode); 23508 } else { 23509 porterDuffMode = null; 23510 } 23511 return porterDuffMode; 23512 } 23513 23514 /** 23515 * Return the blending mode used to apply the tint to the background 23516 * drawable, if specified. 23517 * 23518 * @return the blending mode used to apply the tint to the background 23519 * drawable, null if no blend has previously been configured 23520 * @attr ref android.R.styleable#View_backgroundTintMode 23521 * @see #setBackgroundTintBlendMode(BlendMode) 23522 */ getBackgroundTintBlendMode()23523 public @Nullable BlendMode getBackgroundTintBlendMode() { 23524 return mBackgroundTint != null ? mBackgroundTint.mBlendMode : null; 23525 } 23526 applyBackgroundTint()23527 private void applyBackgroundTint() { 23528 if (mBackground != null && mBackgroundTint != null) { 23529 final TintInfo tintInfo = mBackgroundTint; 23530 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 23531 mBackground = mBackground.mutate(); 23532 23533 if (tintInfo.mHasTintList) { 23534 mBackground.setTintList(tintInfo.mTintList); 23535 } 23536 23537 if (tintInfo.mHasTintMode) { 23538 mBackground.setTintBlendMode(tintInfo.mBlendMode); 23539 } 23540 23541 // The drawable (or one of its children) may not have been 23542 // stateful before applying the tint, so let's try again. 23543 if (mBackground.isStateful()) { 23544 mBackground.setState(getDrawableState()); 23545 } 23546 } 23547 } 23548 } 23549 23550 /** 23551 * Returns the drawable used as the foreground of this View. The 23552 * foreground drawable, if non-null, is always drawn on top of the view's content. 23553 * 23554 * @return a Drawable or null if no foreground was set 23555 * 23556 * @see #onDrawForeground(Canvas) 23557 */ 23558 @InspectableProperty getForeground()23559 public Drawable getForeground() { 23560 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 23561 } 23562 23563 /** 23564 * Supply a Drawable that is to be rendered on top of all of the content in the view. 23565 * 23566 * @param foreground the Drawable to be drawn on top of the children 23567 * 23568 * @attr ref android.R.styleable#View_foreground 23569 */ setForeground(Drawable foreground)23570 public void setForeground(Drawable foreground) { 23571 if (mForegroundInfo == null) { 23572 if (foreground == null) { 23573 // Nothing to do. 23574 return; 23575 } 23576 mForegroundInfo = new ForegroundInfo(); 23577 } 23578 23579 if (foreground == mForegroundInfo.mDrawable) { 23580 // Nothing to do 23581 return; 23582 } 23583 23584 if (mForegroundInfo.mDrawable != null) { 23585 if (isAttachedToWindow()) { 23586 mForegroundInfo.mDrawable.setVisible(false, false); 23587 } 23588 mForegroundInfo.mDrawable.setCallback(null); 23589 unscheduleDrawable(mForegroundInfo.mDrawable); 23590 } 23591 23592 mForegroundInfo.mDrawable = foreground; 23593 mForegroundInfo.mBoundsChanged = true; 23594 if (foreground != null) { 23595 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 23596 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 23597 } 23598 foreground.setLayoutDirection(getLayoutDirection()); 23599 if (foreground.isStateful()) { 23600 foreground.setState(getDrawableState()); 23601 } 23602 applyForegroundTint(); 23603 if (isAttachedToWindow()) { 23604 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 23605 } 23606 // Set callback last, since the view may still be initializing. 23607 foreground.setCallback(this); 23608 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 23609 && (mDefaultFocusHighlight == null)) { 23610 mPrivateFlags |= PFLAG_SKIP_DRAW; 23611 } 23612 requestLayout(); 23613 invalidate(); 23614 } 23615 23616 /** 23617 * Magic bit used to support features of framework-internal window decor implementation details. 23618 * This used to live exclusively in FrameLayout. 23619 * 23620 * @return true if the foreground should draw inside the padding region or false 23621 * if it should draw inset by the view's padding 23622 * @hide internal use only; only used by FrameLayout and internal screen layouts. 23623 */ isForegroundInsidePadding()23624 public boolean isForegroundInsidePadding() { 23625 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 23626 } 23627 23628 /** 23629 * Describes how the foreground is positioned. 23630 * 23631 * @return foreground gravity. 23632 * 23633 * @see #setForegroundGravity(int) 23634 * 23635 * @attr ref android.R.styleable#View_foregroundGravity 23636 */ 23637 @InspectableProperty(valueType = InspectableProperty.ValueType.GRAVITY) getForegroundGravity()23638 public int getForegroundGravity() { 23639 return mForegroundInfo != null ? mForegroundInfo.mGravity 23640 : Gravity.START | Gravity.TOP; 23641 } 23642 23643 /** 23644 * Describes how the foreground is positioned. Defaults to START and TOP. 23645 * 23646 * @param gravity see {@link android.view.Gravity} 23647 * 23648 * @see #getForegroundGravity() 23649 * 23650 * @attr ref android.R.styleable#View_foregroundGravity 23651 */ setForegroundGravity(int gravity)23652 public void setForegroundGravity(int gravity) { 23653 if (mForegroundInfo == null) { 23654 mForegroundInfo = new ForegroundInfo(); 23655 } 23656 23657 if (mForegroundInfo.mGravity != gravity) { 23658 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 23659 gravity |= Gravity.START; 23660 } 23661 23662 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 23663 gravity |= Gravity.TOP; 23664 } 23665 23666 mForegroundInfo.mGravity = gravity; 23667 requestLayout(); 23668 } 23669 } 23670 23671 /** 23672 * Applies a tint to the foreground drawable. Does not modify the current tint 23673 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 23674 * <p> 23675 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 23676 * mutate the drawable and apply the specified tint and tint mode using 23677 * {@link Drawable#setTintList(ColorStateList)}. 23678 * 23679 * @param tint the tint to apply, may be {@code null} to clear tint 23680 * 23681 * @attr ref android.R.styleable#View_foregroundTint 23682 * @see #getForegroundTintList() 23683 * @see Drawable#setTintList(ColorStateList) 23684 */ setForegroundTintList(@ullable ColorStateList tint)23685 public void setForegroundTintList(@Nullable ColorStateList tint) { 23686 if (mForegroundInfo == null) { 23687 mForegroundInfo = new ForegroundInfo(); 23688 } 23689 if (mForegroundInfo.mTintInfo == null) { 23690 mForegroundInfo.mTintInfo = new TintInfo(); 23691 } 23692 mForegroundInfo.mTintInfo.mTintList = tint; 23693 mForegroundInfo.mTintInfo.mHasTintList = true; 23694 23695 applyForegroundTint(); 23696 } 23697 23698 /** 23699 * Return the tint applied to the foreground drawable, if specified. 23700 * 23701 * @return the tint applied to the foreground drawable 23702 * @attr ref android.R.styleable#View_foregroundTint 23703 * @see #setForegroundTintList(ColorStateList) 23704 */ 23705 @InspectableProperty(name = "foregroundTint") 23706 @Nullable getForegroundTintList()23707 public ColorStateList getForegroundTintList() { 23708 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 23709 ? mForegroundInfo.mTintInfo.mTintList : null; 23710 } 23711 23712 /** 23713 * Specifies the blending mode used to apply the tint specified by 23714 * {@link #setForegroundTintList(ColorStateList)}} to the background 23715 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 23716 * 23717 * @param tintMode the blending mode used to apply the tint, may be 23718 * {@code null} to clear tint 23719 * @attr ref android.R.styleable#View_foregroundTintMode 23720 * @see #getForegroundTintMode() 23721 * @see Drawable#setTintMode(PorterDuff.Mode) 23722 * 23723 */ setForegroundTintMode(@ullable PorterDuff.Mode tintMode)23724 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 23725 BlendMode mode = null; 23726 if (tintMode != null) { 23727 mode = BlendMode.fromValue(tintMode.nativeInt); 23728 } 23729 setForegroundTintBlendMode(mode); 23730 } 23731 23732 /** 23733 * Specifies the blending mode used to apply the tint specified by 23734 * {@link #setForegroundTintList(ColorStateList)}} to the background 23735 * drawable. The default mode is {@link BlendMode#SRC_IN}. 23736 * 23737 * @param blendMode the blending mode used to apply the tint, may be 23738 * {@code null} to clear tint 23739 * @attr ref android.R.styleable#View_foregroundTintMode 23740 * @see #getForegroundTintMode() 23741 * @see Drawable#setTintBlendMode(BlendMode) 23742 */ setForegroundTintBlendMode(@ullable BlendMode blendMode)23743 public void setForegroundTintBlendMode(@Nullable BlendMode blendMode) { 23744 if (mForegroundInfo == null) { 23745 mForegroundInfo = new ForegroundInfo(); 23746 } 23747 if (mForegroundInfo.mTintInfo == null) { 23748 mForegroundInfo.mTintInfo = new TintInfo(); 23749 } 23750 mForegroundInfo.mTintInfo.mBlendMode = blendMode; 23751 mForegroundInfo.mTintInfo.mHasTintMode = true; 23752 23753 applyForegroundTint(); 23754 } 23755 23756 /** 23757 * Return the blending mode used to apply the tint to the foreground 23758 * drawable, if specified. 23759 * 23760 * @return the blending mode used to apply the tint to the foreground 23761 * drawable 23762 * @attr ref android.R.styleable#View_foregroundTintMode 23763 * @see #setForegroundTintMode(PorterDuff.Mode) 23764 */ 23765 @InspectableProperty 23766 @Nullable getForegroundTintMode()23767 public PorterDuff.Mode getForegroundTintMode() { 23768 BlendMode blendMode = mForegroundInfo != null && mForegroundInfo.mTintInfo != null 23769 ? mForegroundInfo.mTintInfo.mBlendMode : null; 23770 if (blendMode != null) { 23771 return BlendMode.blendModeToPorterDuffMode(blendMode); 23772 } else { 23773 return null; 23774 } 23775 } 23776 23777 /** 23778 * Return the blending mode used to apply the tint to the foreground 23779 * drawable, if specified. 23780 * 23781 * @return the blending mode used to apply the tint to the foreground 23782 * drawable 23783 * @attr ref android.R.styleable#View_foregroundTintMode 23784 * @see #setForegroundTintBlendMode(BlendMode) 23785 * 23786 */ getForegroundTintBlendMode()23787 public @Nullable BlendMode getForegroundTintBlendMode() { 23788 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 23789 ? mForegroundInfo.mTintInfo.mBlendMode : null; 23790 } 23791 applyForegroundTint()23792 private void applyForegroundTint() { 23793 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 23794 && mForegroundInfo.mTintInfo != null) { 23795 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 23796 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 23797 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 23798 23799 if (tintInfo.mHasTintList) { 23800 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 23801 } 23802 23803 if (tintInfo.mHasTintMode) { 23804 mForegroundInfo.mDrawable.setTintBlendMode(tintInfo.mBlendMode); 23805 } 23806 23807 // The drawable (or one of its children) may not have been 23808 // stateful before applying the tint, so let's try again. 23809 if (mForegroundInfo.mDrawable.isStateful()) { 23810 mForegroundInfo.mDrawable.setState(getDrawableState()); 23811 } 23812 } 23813 } 23814 } 23815 23816 /** 23817 * Get the drawable to be overlayed when a view is autofilled 23818 * 23819 * @return The drawable 23820 * 23821 * @throws IllegalStateException if the drawable could not be found. 23822 */ getAutofilledDrawable()23823 @Nullable private Drawable getAutofilledDrawable() { 23824 if (mAttachInfo == null) { 23825 return null; 23826 } 23827 // Lazily load the isAutofilled drawable. 23828 if (mAttachInfo.mAutofilledDrawable == null) { 23829 Context rootContext = getRootView().getContext(); 23830 TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR); 23831 int attributeResourceId = a.getResourceId(0, 0); 23832 mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId); 23833 a.recycle(); 23834 } 23835 23836 return mAttachInfo.mAutofilledDrawable; 23837 } 23838 23839 /** 23840 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled. 23841 * 23842 * @param canvas The canvas to draw on 23843 */ drawAutofilledHighlight(@onNull Canvas canvas)23844 private void drawAutofilledHighlight(@NonNull Canvas canvas) { 23845 if (isAutofilled()) { 23846 Drawable autofilledHighlight = getAutofilledDrawable(); 23847 23848 if (autofilledHighlight != null) { 23849 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); 23850 autofilledHighlight.draw(canvas); 23851 } 23852 } 23853 } 23854 23855 /** 23856 * Draw any foreground content for this view. 23857 * 23858 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 23859 * drawable or other view-specific decorations. The foreground is drawn on top of the 23860 * primary view content.</p> 23861 * 23862 * @param canvas canvas to draw into 23863 */ onDrawForeground(Canvas canvas)23864 public void onDrawForeground(Canvas canvas) { 23865 onDrawScrollIndicators(canvas); 23866 onDrawScrollBars(canvas); 23867 23868 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 23869 if (foreground != null) { 23870 if (mForegroundInfo.mBoundsChanged) { 23871 mForegroundInfo.mBoundsChanged = false; 23872 final Rect selfBounds = mForegroundInfo.mSelfBounds; 23873 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 23874 23875 if (mForegroundInfo.mInsidePadding) { 23876 selfBounds.set(0, 0, getWidth(), getHeight()); 23877 } else { 23878 selfBounds.set(getPaddingLeft(), getPaddingTop(), 23879 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 23880 } 23881 23882 final int ld = getLayoutDirection(); 23883 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 23884 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 23885 foreground.setBounds(overlayBounds); 23886 } 23887 23888 foreground.draw(canvas); 23889 } 23890 } 23891 23892 /** 23893 * Sets the padding. The view may add on the space required to display 23894 * the scrollbars, depending on the style and visibility of the scrollbars. 23895 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 23896 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 23897 * from the values set in this call. 23898 * 23899 * @attr ref android.R.styleable#View_padding 23900 * @attr ref android.R.styleable#View_paddingBottom 23901 * @attr ref android.R.styleable#View_paddingLeft 23902 * @attr ref android.R.styleable#View_paddingRight 23903 * @attr ref android.R.styleable#View_paddingTop 23904 * @param left the left padding in pixels 23905 * @param top the top padding in pixels 23906 * @param right the right padding in pixels 23907 * @param bottom the bottom padding in pixels 23908 */ setPadding(int left, int top, int right, int bottom)23909 public void setPadding(int left, int top, int right, int bottom) { 23910 resetResolvedPaddingInternal(); 23911 23912 mUserPaddingStart = UNDEFINED_PADDING; 23913 mUserPaddingEnd = UNDEFINED_PADDING; 23914 23915 mUserPaddingLeftInitial = left; 23916 mUserPaddingRightInitial = right; 23917 23918 mLeftPaddingDefined = true; 23919 mRightPaddingDefined = true; 23920 23921 internalSetPadding(left, top, right, bottom); 23922 } 23923 23924 /** 23925 * @hide 23926 */ 23927 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768420) internalSetPadding(int left, int top, int right, int bottom)23928 protected void internalSetPadding(int left, int top, int right, int bottom) { 23929 mUserPaddingLeft = left; 23930 mUserPaddingRight = right; 23931 mUserPaddingBottom = bottom; 23932 23933 final int viewFlags = mViewFlags; 23934 boolean changed = false; 23935 23936 // Common case is there are no scroll bars. 23937 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 23938 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 23939 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 23940 ? 0 : getVerticalScrollbarWidth(); 23941 switch (mVerticalScrollbarPosition) { 23942 case SCROLLBAR_POSITION_DEFAULT: 23943 if (isLayoutRtl()) { 23944 left += offset; 23945 } else { 23946 right += offset; 23947 } 23948 break; 23949 case SCROLLBAR_POSITION_RIGHT: 23950 right += offset; 23951 break; 23952 case SCROLLBAR_POSITION_LEFT: 23953 left += offset; 23954 break; 23955 } 23956 } 23957 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 23958 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 23959 ? 0 : getHorizontalScrollbarHeight(); 23960 } 23961 } 23962 23963 if (mPaddingLeft != left) { 23964 changed = true; 23965 mPaddingLeft = left; 23966 } 23967 if (mPaddingTop != top) { 23968 changed = true; 23969 mPaddingTop = top; 23970 } 23971 if (mPaddingRight != right) { 23972 changed = true; 23973 mPaddingRight = right; 23974 } 23975 if (mPaddingBottom != bottom) { 23976 changed = true; 23977 mPaddingBottom = bottom; 23978 } 23979 23980 if (changed) { 23981 requestLayout(); 23982 invalidateOutline(); 23983 } 23984 } 23985 23986 /** 23987 * Sets the relative padding. The view may add on the space required to display 23988 * the scrollbars, depending on the style and visibility of the scrollbars. 23989 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 23990 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 23991 * from the values set in this call. 23992 * 23993 * @attr ref android.R.styleable#View_padding 23994 * @attr ref android.R.styleable#View_paddingBottom 23995 * @attr ref android.R.styleable#View_paddingStart 23996 * @attr ref android.R.styleable#View_paddingEnd 23997 * @attr ref android.R.styleable#View_paddingTop 23998 * @param start the start padding in pixels 23999 * @param top the top padding in pixels 24000 * @param end the end padding in pixels 24001 * @param bottom the bottom padding in pixels 24002 */ setPaddingRelative(int start, int top, int end, int bottom)24003 public void setPaddingRelative(int start, int top, int end, int bottom) { 24004 resetResolvedPaddingInternal(); 24005 24006 mUserPaddingStart = start; 24007 mUserPaddingEnd = end; 24008 mLeftPaddingDefined = true; 24009 mRightPaddingDefined = true; 24010 24011 switch(getLayoutDirection()) { 24012 case LAYOUT_DIRECTION_RTL: 24013 mUserPaddingLeftInitial = end; 24014 mUserPaddingRightInitial = start; 24015 internalSetPadding(end, top, start, bottom); 24016 break; 24017 case LAYOUT_DIRECTION_LTR: 24018 default: 24019 mUserPaddingLeftInitial = start; 24020 mUserPaddingRightInitial = end; 24021 internalSetPadding(start, top, end, bottom); 24022 } 24023 } 24024 24025 /** 24026 * A {@link View} can be inflated from an XML layout. For such Views this method returns the 24027 * resource ID of the source layout. 24028 * 24029 * @return The layout resource id if this view was inflated from XML, otherwise 24030 * {@link Resources#ID_NULL}. 24031 */ 24032 @LayoutRes getSourceLayoutResId()24033 public int getSourceLayoutResId() { 24034 return mSourceLayoutId; 24035 } 24036 24037 /** 24038 * Returns the top padding of this view. 24039 * 24040 * @return the top padding in pixels 24041 */ 24042 @InspectableProperty getPaddingTop()24043 public int getPaddingTop() { 24044 return mPaddingTop; 24045 } 24046 24047 /** 24048 * Returns the bottom padding of this view. If there are inset and enabled 24049 * scrollbars, this value may include the space required to display the 24050 * scrollbars as well. 24051 * 24052 * @return the bottom padding in pixels 24053 */ 24054 @InspectableProperty getPaddingBottom()24055 public int getPaddingBottom() { 24056 return mPaddingBottom; 24057 } 24058 24059 /** 24060 * Returns the left padding of this view. If there are inset and enabled 24061 * scrollbars, this value may include the space required to display the 24062 * scrollbars as well. 24063 * 24064 * @return the left padding in pixels 24065 */ 24066 @InspectableProperty getPaddingLeft()24067 public int getPaddingLeft() { 24068 if (!isPaddingResolved()) { 24069 resolvePadding(); 24070 } 24071 return mPaddingLeft; 24072 } 24073 24074 /** 24075 * Returns the start padding of this view depending on its resolved layout direction. 24076 * If there are inset and enabled scrollbars, this value may include the space 24077 * required to display the scrollbars as well. 24078 * 24079 * @return the start padding in pixels 24080 */ getPaddingStart()24081 public int getPaddingStart() { 24082 if (!isPaddingResolved()) { 24083 resolvePadding(); 24084 } 24085 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 24086 mPaddingRight : mPaddingLeft; 24087 } 24088 24089 /** 24090 * Returns the right padding of this view. If there are inset and enabled 24091 * scrollbars, this value may include the space required to display the 24092 * scrollbars as well. 24093 * 24094 * @return the right padding in pixels 24095 */ 24096 @InspectableProperty getPaddingRight()24097 public int getPaddingRight() { 24098 if (!isPaddingResolved()) { 24099 resolvePadding(); 24100 } 24101 return mPaddingRight; 24102 } 24103 24104 /** 24105 * Returns the end padding of this view depending on its resolved layout direction. 24106 * If there are inset and enabled scrollbars, this value may include the space 24107 * required to display the scrollbars as well. 24108 * 24109 * @return the end padding in pixels 24110 */ getPaddingEnd()24111 public int getPaddingEnd() { 24112 if (!isPaddingResolved()) { 24113 resolvePadding(); 24114 } 24115 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 24116 mPaddingLeft : mPaddingRight; 24117 } 24118 24119 /** 24120 * Return if the padding has been set through relative values 24121 * {@link #setPaddingRelative(int, int, int, int)} or through 24122 * @attr ref android.R.styleable#View_paddingStart or 24123 * @attr ref android.R.styleable#View_paddingEnd 24124 * 24125 * @return true if the padding is relative or false if it is not. 24126 */ isPaddingRelative()24127 public boolean isPaddingRelative() { 24128 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 24129 } 24130 computeOpticalInsets()24131 Insets computeOpticalInsets() { 24132 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 24133 } 24134 24135 /** 24136 * @hide 24137 */ 24138 @UnsupportedAppUsage resetPaddingToInitialValues()24139 public void resetPaddingToInitialValues() { 24140 if (isRtlCompatibilityMode()) { 24141 mPaddingLeft = mUserPaddingLeftInitial; 24142 mPaddingRight = mUserPaddingRightInitial; 24143 return; 24144 } 24145 if (isLayoutRtl()) { 24146 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 24147 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 24148 } else { 24149 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 24150 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 24151 } 24152 } 24153 24154 /** 24155 * @hide 24156 */ getOpticalInsets()24157 public Insets getOpticalInsets() { 24158 if (mLayoutInsets == null) { 24159 mLayoutInsets = computeOpticalInsets(); 24160 } 24161 return mLayoutInsets; 24162 } 24163 24164 /** 24165 * Set this view's optical insets. 24166 * 24167 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 24168 * property. Views that compute their own optical insets should call it as part of measurement. 24169 * This method does not request layout. If you are setting optical insets outside of 24170 * measure/layout itself you will want to call requestLayout() yourself. 24171 * </p> 24172 * @hide 24173 */ setOpticalInsets(Insets insets)24174 public void setOpticalInsets(Insets insets) { 24175 mLayoutInsets = insets; 24176 } 24177 24178 /** 24179 * Changes the selection state of this view. A view can be selected or not. 24180 * Note that selection is not the same as focus. Views are typically 24181 * selected in the context of an AdapterView like ListView or GridView; 24182 * the selected view is the view that is highlighted. 24183 * 24184 * @param selected true if the view must be selected, false otherwise 24185 */ setSelected(boolean selected)24186 public void setSelected(boolean selected) { 24187 //noinspection DoubleNegation 24188 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 24189 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 24190 if (!selected) resetPressedState(); 24191 invalidate(true); 24192 refreshDrawableState(); 24193 dispatchSetSelected(selected); 24194 if (selected) { 24195 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 24196 } else { 24197 notifyViewAccessibilityStateChangedIfNeeded( 24198 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 24199 } 24200 } 24201 } 24202 24203 /** 24204 * Dispatch setSelected to all of this View's children. 24205 * 24206 * @see #setSelected(boolean) 24207 * 24208 * @param selected The new selected state 24209 */ dispatchSetSelected(boolean selected)24210 protected void dispatchSetSelected(boolean selected) { 24211 } 24212 24213 /** 24214 * Indicates the selection state of this view. 24215 * 24216 * @return true if the view is selected, false otherwise 24217 */ 24218 @ViewDebug.ExportedProperty 24219 @InspectableProperty(hasAttributeId = false) isSelected()24220 public boolean isSelected() { 24221 return (mPrivateFlags & PFLAG_SELECTED) != 0; 24222 } 24223 24224 /** 24225 * Changes the activated state of this view. A view can be activated or not. 24226 * Note that activation is not the same as selection. Selection is 24227 * a transient property, representing the view (hierarchy) the user is 24228 * currently interacting with. Activation is a longer-term state that the 24229 * user can move views in and out of. For example, in a list view with 24230 * single or multiple selection enabled, the views in the current selection 24231 * set are activated. (Um, yeah, we are deeply sorry about the terminology 24232 * here.) The activated state is propagated down to children of the view it 24233 * is set on. 24234 * 24235 * @param activated true if the view must be activated, false otherwise 24236 */ setActivated(boolean activated)24237 public void setActivated(boolean activated) { 24238 //noinspection DoubleNegation 24239 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 24240 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 24241 invalidate(true); 24242 refreshDrawableState(); 24243 dispatchSetActivated(activated); 24244 } 24245 } 24246 24247 /** 24248 * Dispatch setActivated to all of this View's children. 24249 * 24250 * @see #setActivated(boolean) 24251 * 24252 * @param activated The new activated state 24253 */ dispatchSetActivated(boolean activated)24254 protected void dispatchSetActivated(boolean activated) { 24255 } 24256 24257 /** 24258 * Indicates the activation state of this view. 24259 * 24260 * @return true if the view is activated, false otherwise 24261 */ 24262 @ViewDebug.ExportedProperty 24263 @InspectableProperty(hasAttributeId = false) isActivated()24264 public boolean isActivated() { 24265 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 24266 } 24267 24268 /** 24269 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 24270 * observer can be used to get notifications when global events, like 24271 * layout, happen. 24272 * 24273 * The returned ViewTreeObserver observer is not guaranteed to remain 24274 * valid for the lifetime of this View. If the caller of this method keeps 24275 * a long-lived reference to ViewTreeObserver, it should always check for 24276 * the return value of {@link ViewTreeObserver#isAlive()}. 24277 * 24278 * @return The ViewTreeObserver for this view's hierarchy. 24279 */ getViewTreeObserver()24280 public ViewTreeObserver getViewTreeObserver() { 24281 if (mAttachInfo != null) { 24282 return mAttachInfo.mTreeObserver; 24283 } 24284 if (mFloatingTreeObserver == null) { 24285 mFloatingTreeObserver = new ViewTreeObserver(mContext); 24286 } 24287 return mFloatingTreeObserver; 24288 } 24289 24290 /** 24291 * <p>Finds the topmost view in the current view hierarchy.</p> 24292 * 24293 * @return the topmost view containing this view 24294 */ getRootView()24295 public View getRootView() { 24296 if (mAttachInfo != null) { 24297 final View v = mAttachInfo.mRootView; 24298 if (v != null) { 24299 return v; 24300 } 24301 } 24302 24303 View parent = this; 24304 24305 while (parent.mParent != null && parent.mParent instanceof View) { 24306 parent = (View) parent.mParent; 24307 } 24308 24309 return parent; 24310 } 24311 24312 /** 24313 * Transforms a motion event from view-local coordinates to on-screen 24314 * coordinates. 24315 * 24316 * @param ev the view-local motion event 24317 * @return false if the transformation could not be applied 24318 * @hide 24319 */ 24320 @UnsupportedAppUsage toGlobalMotionEvent(MotionEvent ev)24321 public boolean toGlobalMotionEvent(MotionEvent ev) { 24322 final AttachInfo info = mAttachInfo; 24323 if (info == null) { 24324 return false; 24325 } 24326 24327 final Matrix m = info.mTmpMatrix; 24328 m.set(Matrix.IDENTITY_MATRIX); 24329 transformMatrixToGlobal(m); 24330 ev.transform(m); 24331 return true; 24332 } 24333 24334 /** 24335 * Transforms a motion event from on-screen coordinates to view-local 24336 * coordinates. 24337 * 24338 * @param ev the on-screen motion event 24339 * @return false if the transformation could not be applied 24340 * @hide 24341 */ 24342 @UnsupportedAppUsage toLocalMotionEvent(MotionEvent ev)24343 public boolean toLocalMotionEvent(MotionEvent ev) { 24344 final AttachInfo info = mAttachInfo; 24345 if (info == null) { 24346 return false; 24347 } 24348 24349 final Matrix m = info.mTmpMatrix; 24350 m.set(Matrix.IDENTITY_MATRIX); 24351 transformMatrixToLocal(m); 24352 ev.transform(m); 24353 return true; 24354 } 24355 24356 /** 24357 * Modifies the input matrix such that it maps view-local coordinates to 24358 * on-screen coordinates. 24359 * 24360 * @param matrix input matrix to modify 24361 */ transformMatrixToGlobal(@onNull Matrix matrix)24362 public void transformMatrixToGlobal(@NonNull Matrix matrix) { 24363 final ViewParent parent = mParent; 24364 if (parent instanceof View) { 24365 final View vp = (View) parent; 24366 vp.transformMatrixToGlobal(matrix); 24367 matrix.preTranslate(-vp.mScrollX, -vp.mScrollY); 24368 } else if (parent instanceof ViewRootImpl) { 24369 final ViewRootImpl vr = (ViewRootImpl) parent; 24370 vr.transformMatrixToGlobal(matrix); 24371 matrix.preTranslate(0, -vr.mCurScrollY); 24372 } 24373 24374 matrix.preTranslate(mLeft, mTop); 24375 24376 if (!hasIdentityMatrix()) { 24377 matrix.preConcat(getMatrix()); 24378 } 24379 } 24380 24381 /** 24382 * Modifies the input matrix such that it maps on-screen coordinates to 24383 * view-local coordinates. 24384 * 24385 * @param matrix input matrix to modify 24386 */ transformMatrixToLocal(@onNull Matrix matrix)24387 public void transformMatrixToLocal(@NonNull Matrix matrix) { 24388 final ViewParent parent = mParent; 24389 if (parent instanceof View) { 24390 final View vp = (View) parent; 24391 vp.transformMatrixToLocal(matrix); 24392 matrix.postTranslate(vp.mScrollX, vp.mScrollY); 24393 } else if (parent instanceof ViewRootImpl) { 24394 final ViewRootImpl vr = (ViewRootImpl) parent; 24395 vr.transformMatrixToLocal(matrix); 24396 matrix.postTranslate(0, vr.mCurScrollY); 24397 } 24398 24399 matrix.postTranslate(-mLeft, -mTop); 24400 24401 if (!hasIdentityMatrix()) { 24402 matrix.postConcat(getInverseMatrix()); 24403 } 24404 } 24405 24406 /** 24407 * @hide 24408 */ 24409 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 24410 @ViewDebug.IntToString(from = 0, to = "x"), 24411 @ViewDebug.IntToString(from = 1, to = "y") 24412 }) 24413 @UnsupportedAppUsage getLocationOnScreen()24414 public int[] getLocationOnScreen() { 24415 int[] location = new int[2]; 24416 getLocationOnScreen(location); 24417 return location; 24418 } 24419 24420 /** 24421 * <p>Computes the coordinates of this view on the screen. The argument 24422 * must be an array of two integers. After the method returns, the array 24423 * contains the x and y location in that order.</p> 24424 * 24425 * @param outLocation an array of two integers in which to hold the coordinates 24426 */ getLocationOnScreen(@ize2) int[] outLocation)24427 public void getLocationOnScreen(@Size(2) int[] outLocation) { 24428 getLocationInWindow(outLocation); 24429 24430 final AttachInfo info = mAttachInfo; 24431 if (info != null) { 24432 outLocation[0] += info.mWindowLeft; 24433 outLocation[1] += info.mWindowTop; 24434 } 24435 } 24436 24437 /** 24438 * <p>Computes the coordinates of this view in its window. The argument 24439 * must be an array of two integers. After the method returns, the array 24440 * contains the x and y location in that order.</p> 24441 * 24442 * @param outLocation an array of two integers in which to hold the coordinates 24443 */ getLocationInWindow(@ize2) int[] outLocation)24444 public void getLocationInWindow(@Size(2) int[] outLocation) { 24445 if (outLocation == null || outLocation.length < 2) { 24446 throw new IllegalArgumentException("outLocation must be an array of two integers"); 24447 } 24448 24449 outLocation[0] = 0; 24450 outLocation[1] = 0; 24451 24452 transformFromViewToWindowSpace(outLocation); 24453 } 24454 24455 /** @hide */ transformFromViewToWindowSpace(@ize2) int[] inOutLocation)24456 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 24457 if (inOutLocation == null || inOutLocation.length < 2) { 24458 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 24459 } 24460 24461 if (mAttachInfo == null) { 24462 // When the view is not attached to a window, this method does not make sense 24463 inOutLocation[0] = inOutLocation[1] = 0; 24464 return; 24465 } 24466 24467 float position[] = mAttachInfo.mTmpTransformLocation; 24468 position[0] = inOutLocation[0]; 24469 position[1] = inOutLocation[1]; 24470 24471 if (!hasIdentityMatrix()) { 24472 getMatrix().mapPoints(position); 24473 } 24474 24475 position[0] += mLeft; 24476 position[1] += mTop; 24477 24478 ViewParent viewParent = mParent; 24479 while (viewParent instanceof View) { 24480 final View view = (View) viewParent; 24481 24482 position[0] -= view.mScrollX; 24483 position[1] -= view.mScrollY; 24484 24485 if (!view.hasIdentityMatrix()) { 24486 view.getMatrix().mapPoints(position); 24487 } 24488 24489 position[0] += view.mLeft; 24490 position[1] += view.mTop; 24491 24492 viewParent = view.mParent; 24493 } 24494 24495 if (viewParent instanceof ViewRootImpl) { 24496 // *cough* 24497 final ViewRootImpl vr = (ViewRootImpl) viewParent; 24498 position[1] -= vr.mCurScrollY; 24499 } 24500 24501 inOutLocation[0] = Math.round(position[0]); 24502 inOutLocation[1] = Math.round(position[1]); 24503 } 24504 24505 /** 24506 * @param id the id of the view to be found 24507 * @return the view of the specified id, null if cannot be found 24508 * @hide 24509 */ findViewTraversal(@dRes int id)24510 protected <T extends View> T findViewTraversal(@IdRes int id) { 24511 if (id == mID) { 24512 return (T) this; 24513 } 24514 return null; 24515 } 24516 24517 /** 24518 * @param tag the tag of the view to be found 24519 * @return the view of specified tag, null if cannot be found 24520 * @hide 24521 */ findViewWithTagTraversal(Object tag)24522 protected <T extends View> T findViewWithTagTraversal(Object tag) { 24523 if (tag != null && tag.equals(mTag)) { 24524 return (T) this; 24525 } 24526 return null; 24527 } 24528 24529 /** 24530 * @param predicate The predicate to evaluate. 24531 * @param childToSkip If not null, ignores this child during the recursive traversal. 24532 * @return The first view that matches the predicate or null. 24533 * @hide 24534 */ findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip)24535 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 24536 View childToSkip) { 24537 if (predicate.test(this)) { 24538 return (T) this; 24539 } 24540 return null; 24541 } 24542 24543 /** 24544 * Finds the first descendant view with the given ID, the view itself if 24545 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid 24546 * (< 0) or there is no matching view in the hierarchy. 24547 * <p> 24548 * <strong>Note:</strong> In most cases -- depending on compiler support -- 24549 * the resulting view is automatically cast to the target class type. If 24550 * the target class type is unconstrained, an explicit cast may be 24551 * necessary. 24552 * 24553 * @param id the ID to search for 24554 * @return a view with given ID if found, or {@code null} otherwise 24555 * @see View#requireViewById(int) 24556 */ 24557 @Nullable findViewById(@dRes int id)24558 public final <T extends View> T findViewById(@IdRes int id) { 24559 if (id == NO_ID) { 24560 return null; 24561 } 24562 return findViewTraversal(id); 24563 } 24564 24565 /** 24566 * Finds the first descendant view with the given ID, the view itself if the ID matches 24567 * {@link #getId()}, or throws an IllegalArgumentException if the ID is invalid or there is no 24568 * matching view in the hierarchy. 24569 * <p> 24570 * <strong>Note:</strong> In most cases -- depending on compiler support -- 24571 * the resulting view is automatically cast to the target class type. If 24572 * the target class type is unconstrained, an explicit cast may be 24573 * necessary. 24574 * 24575 * @param id the ID to search for 24576 * @return a view with given ID 24577 * @see View#findViewById(int) 24578 */ 24579 @NonNull requireViewById(@dRes int id)24580 public final <T extends View> T requireViewById(@IdRes int id) { 24581 T view = findViewById(id); 24582 if (view == null) { 24583 throw new IllegalArgumentException("ID does not reference a View inside this View"); 24584 } 24585 return view; 24586 } 24587 24588 /** 24589 * Performs the traversal to find a view by its unique and stable accessibility id. 24590 * 24591 * <strong>Note:</strong>This method does not stop at the root namespace 24592 * boundary since the user can touch the screen at an arbitrary location 24593 * potentially crossing the root namespace boundary which will send an 24594 * accessibility event to accessibility services and they should be able 24595 * to obtain the event source. Also accessibility ids are guaranteed to be 24596 * unique in the window. 24597 * 24598 * @param accessibilityId The accessibility id. 24599 * @return The found view. 24600 * @hide 24601 */ findViewByAccessibilityIdTraversal(int accessibilityId)24602 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 24603 if (getAccessibilityViewId() == accessibilityId) { 24604 return (T) this; 24605 } 24606 return null; 24607 } 24608 24609 /** 24610 * Performs the traversal to find a view by its autofill id. 24611 * 24612 * <strong>Note:</strong>This method does not stop at the root namespace 24613 * boundary. 24614 * 24615 * @param autofillId The autofill id. 24616 * @return The found view. 24617 * @hide 24618 */ findViewByAutofillIdTraversal(int autofillId)24619 public <T extends View> T findViewByAutofillIdTraversal(int autofillId) { 24620 if (getAutofillViewId() == autofillId) { 24621 return (T) this; 24622 } 24623 return null; 24624 } 24625 24626 /** 24627 * Look for a child view with the given tag. If this view has the given 24628 * tag, return this view. 24629 * 24630 * @param tag The tag to search for, using "tag.equals(getTag())". 24631 * @return The View that has the given tag in the hierarchy or null 24632 */ findViewWithTag(Object tag)24633 public final <T extends View> T findViewWithTag(Object tag) { 24634 if (tag == null) { 24635 return null; 24636 } 24637 return findViewWithTagTraversal(tag); 24638 } 24639 24640 /** 24641 * Look for a child view that matches the specified predicate. 24642 * If this view matches the predicate, return this view. 24643 * 24644 * @param predicate The predicate to evaluate. 24645 * @return The first view that matches the predicate or null. 24646 * @hide 24647 */ findViewByPredicate(Predicate<View> predicate)24648 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 24649 return findViewByPredicateTraversal(predicate, null); 24650 } 24651 24652 /** 24653 * Look for a child view that matches the specified predicate, 24654 * starting with the specified view and its descendents and then 24655 * recusively searching the ancestors and siblings of that view 24656 * until this view is reached. 24657 * 24658 * This method is useful in cases where the predicate does not match 24659 * a single unique view (perhaps multiple views use the same id) 24660 * and we are trying to find the view that is "closest" in scope to the 24661 * starting view. 24662 * 24663 * @param start The view to start from. 24664 * @param predicate The predicate to evaluate. 24665 * @return The first view that matches the predicate or null. 24666 * @hide 24667 */ findViewByPredicateInsideOut( View start, Predicate<View> predicate)24668 public final <T extends View> T findViewByPredicateInsideOut( 24669 View start, Predicate<View> predicate) { 24670 View childToSkip = null; 24671 for (;;) { 24672 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 24673 if (view != null || start == this) { 24674 return view; 24675 } 24676 24677 ViewParent parent = start.getParent(); 24678 if (parent == null || !(parent instanceof View)) { 24679 return null; 24680 } 24681 24682 childToSkip = start; 24683 start = (View) parent; 24684 } 24685 } 24686 24687 /** 24688 * Sets the identifier for this view. The identifier does not have to be 24689 * unique in this view's hierarchy. The identifier should be a positive 24690 * number. 24691 * 24692 * @see #NO_ID 24693 * @see #getId() 24694 * @see #findViewById(int) 24695 * 24696 * @param id a number used to identify the view 24697 * 24698 * @attr ref android.R.styleable#View_id 24699 */ setId(@dRes int id)24700 public void setId(@IdRes int id) { 24701 mID = id; 24702 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 24703 mID = generateViewId(); 24704 } 24705 } 24706 24707 /** 24708 * {@hide} 24709 * 24710 * @param isRoot true if the view belongs to the root namespace, false 24711 * otherwise 24712 */ 24713 @UnsupportedAppUsage 24714 @TestApi setIsRootNamespace(boolean isRoot)24715 public void setIsRootNamespace(boolean isRoot) { 24716 if (isRoot) { 24717 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 24718 } else { 24719 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 24720 } 24721 } 24722 24723 /** 24724 * {@hide} 24725 * 24726 * @return true if the view belongs to the root namespace, false otherwise 24727 */ 24728 @UnsupportedAppUsage isRootNamespace()24729 public boolean isRootNamespace() { 24730 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 24731 } 24732 24733 /** 24734 * Returns this view's identifier. 24735 * 24736 * @return a positive integer used to identify the view or {@link #NO_ID} 24737 * if the view has no ID 24738 * 24739 * @see #setId(int) 24740 * @see #findViewById(int) 24741 * @attr ref android.R.styleable#View_id 24742 */ 24743 @IdRes 24744 @ViewDebug.CapturedViewProperty 24745 @InspectableProperty getId()24746 public int getId() { 24747 return mID; 24748 } 24749 24750 /** 24751 * Get the identifier used for this view by the drawing system. 24752 * 24753 * @see RenderNode#getUniqueId() 24754 * @return A long that uniquely identifies this view's drawing component 24755 */ getUniqueDrawingId()24756 public long getUniqueDrawingId() { 24757 return mRenderNode.getUniqueId(); 24758 } 24759 24760 /** 24761 * Returns this view's tag. 24762 * 24763 * @return the Object stored in this view as a tag, or {@code null} if not 24764 * set 24765 * 24766 * @see #setTag(Object) 24767 * @see #getTag(int) 24768 */ 24769 @ViewDebug.ExportedProperty 24770 @InspectableProperty getTag()24771 public Object getTag() { 24772 return mTag; 24773 } 24774 24775 /** 24776 * Sets the tag associated with this view. A tag can be used to mark 24777 * a view in its hierarchy and does not have to be unique within the 24778 * hierarchy. Tags can also be used to store data within a view without 24779 * resorting to another data structure. 24780 * 24781 * @param tag an Object to tag the view with 24782 * 24783 * @see #getTag() 24784 * @see #setTag(int, Object) 24785 */ setTag(final Object tag)24786 public void setTag(final Object tag) { 24787 mTag = tag; 24788 } 24789 24790 /** 24791 * Returns the tag associated with this view and the specified key. 24792 * 24793 * @param key The key identifying the tag 24794 * 24795 * @return the Object stored in this view as a tag, or {@code null} if not 24796 * set 24797 * 24798 * @see #setTag(int, Object) 24799 * @see #getTag() 24800 */ getTag(int key)24801 public Object getTag(int key) { 24802 if (mKeyedTags != null) return mKeyedTags.get(key); 24803 return null; 24804 } 24805 24806 /** 24807 * Sets a tag associated with this view and a key. A tag can be used 24808 * to mark a view in its hierarchy and does not have to be unique within 24809 * the hierarchy. Tags can also be used to store data within a view 24810 * without resorting to another data structure. 24811 * 24812 * The specified key should be an id declared in the resources of the 24813 * application to ensure it is unique (see the <a 24814 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 24815 * Keys identified as belonging to 24816 * the Android framework or not associated with any package will cause 24817 * an {@link IllegalArgumentException} to be thrown. 24818 * 24819 * @param key The key identifying the tag 24820 * @param tag An Object to tag the view with 24821 * 24822 * @throws IllegalArgumentException If they specified key is not valid 24823 * 24824 * @see #setTag(Object) 24825 * @see #getTag(int) 24826 */ setTag(int key, final Object tag)24827 public void setTag(int key, final Object tag) { 24828 // If the package id is 0x00 or 0x01, it's either an undefined package 24829 // or a framework id 24830 if ((key >>> 24) < 2) { 24831 throw new IllegalArgumentException("The key must be an application-specific " 24832 + "resource id."); 24833 } 24834 24835 setKeyedTag(key, tag); 24836 } 24837 24838 /** 24839 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 24840 * framework id. 24841 * 24842 * @hide 24843 */ 24844 @UnsupportedAppUsage setTagInternal(int key, Object tag)24845 public void setTagInternal(int key, Object tag) { 24846 if ((key >>> 24) != 0x1) { 24847 throw new IllegalArgumentException("The key must be a framework-specific " 24848 + "resource id."); 24849 } 24850 24851 setKeyedTag(key, tag); 24852 } 24853 setKeyedTag(int key, Object tag)24854 private void setKeyedTag(int key, Object tag) { 24855 if (mKeyedTags == null) { 24856 mKeyedTags = new SparseArray<Object>(2); 24857 } 24858 24859 mKeyedTags.put(key, tag); 24860 } 24861 24862 /** 24863 * Prints information about this view in the log output, with the tag 24864 * {@link #VIEW_LOG_TAG}. 24865 * 24866 * @hide 24867 */ 24868 @UnsupportedAppUsage debug()24869 public void debug() { 24870 debug(0); 24871 } 24872 24873 /** 24874 * Prints information about this view in the log output, with the tag 24875 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 24876 * indentation defined by the <code>depth</code>. 24877 * 24878 * @param depth the indentation level 24879 * 24880 * @hide 24881 */ 24882 @UnsupportedAppUsage debug(int depth)24883 protected void debug(int depth) { 24884 String output = debugIndent(depth - 1); 24885 24886 output += "+ " + this; 24887 int id = getId(); 24888 if (id != -1) { 24889 output += " (id=" + id + ")"; 24890 } 24891 Object tag = getTag(); 24892 if (tag != null) { 24893 output += " (tag=" + tag + ")"; 24894 } 24895 Log.d(VIEW_LOG_TAG, output); 24896 24897 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 24898 output = debugIndent(depth) + " FOCUSED"; 24899 Log.d(VIEW_LOG_TAG, output); 24900 } 24901 24902 output = debugIndent(depth); 24903 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 24904 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 24905 + "} "; 24906 Log.d(VIEW_LOG_TAG, output); 24907 24908 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 24909 || mPaddingBottom != 0) { 24910 output = debugIndent(depth); 24911 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 24912 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 24913 Log.d(VIEW_LOG_TAG, output); 24914 } 24915 24916 output = debugIndent(depth); 24917 output += "mMeasureWidth=" + mMeasuredWidth + 24918 " mMeasureHeight=" + mMeasuredHeight; 24919 Log.d(VIEW_LOG_TAG, output); 24920 24921 output = debugIndent(depth); 24922 if (mLayoutParams == null) { 24923 output += "BAD! no layout params"; 24924 } else { 24925 output = mLayoutParams.debug(output); 24926 } 24927 Log.d(VIEW_LOG_TAG, output); 24928 24929 output = debugIndent(depth); 24930 output += "flags={"; 24931 output += View.printFlags(mViewFlags); 24932 output += "}"; 24933 Log.d(VIEW_LOG_TAG, output); 24934 24935 output = debugIndent(depth); 24936 output += "privateFlags={"; 24937 output += View.printPrivateFlags(mPrivateFlags); 24938 output += "}"; 24939 Log.d(VIEW_LOG_TAG, output); 24940 } 24941 24942 /** 24943 * Creates a string of whitespaces used for indentation. 24944 * 24945 * @param depth the indentation level 24946 * @return a String containing (depth * 2 + 3) * 2 white spaces 24947 * 24948 * @hide 24949 */ debugIndent(int depth)24950 protected static String debugIndent(int depth) { 24951 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 24952 for (int i = 0; i < (depth * 2) + 3; i++) { 24953 spaces.append(' ').append(' '); 24954 } 24955 return spaces.toString(); 24956 } 24957 24958 /** 24959 * <p>Return the offset of the widget's text baseline from the widget's top 24960 * boundary. If this widget does not support baseline alignment, this 24961 * method returns -1. </p> 24962 * 24963 * @return the offset of the baseline within the widget's bounds or -1 24964 * if baseline alignment is not supported 24965 */ 24966 @ViewDebug.ExportedProperty(category = "layout") 24967 @InspectableProperty getBaseline()24968 public int getBaseline() { 24969 return -1; 24970 } 24971 24972 /** 24973 * Returns whether the view hierarchy is currently undergoing a layout pass. This 24974 * information is useful to avoid situations such as calling {@link #requestLayout()} during 24975 * a layout pass. 24976 * 24977 * @return whether the view hierarchy is currently undergoing a layout pass 24978 */ isInLayout()24979 public boolean isInLayout() { 24980 ViewRootImpl viewRoot = getViewRootImpl(); 24981 return (viewRoot != null && viewRoot.isInLayout()); 24982 } 24983 24984 /** 24985 * Call this when something has changed which has invalidated the 24986 * layout of this view. This will schedule a layout pass of the view 24987 * tree. This should not be called while the view hierarchy is currently in a layout 24988 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 24989 * end of the current layout pass (and then layout will run again) or after the current 24990 * frame is drawn and the next layout occurs. 24991 * 24992 * <p>Subclasses which override this method should call the superclass method to 24993 * handle possible request-during-layout errors correctly.</p> 24994 */ 24995 @CallSuper requestLayout()24996 public void requestLayout() { 24997 if (mMeasureCache != null) mMeasureCache.clear(); 24998 24999 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 25000 // Only trigger request-during-layout logic if this is the view requesting it, 25001 // not the views in its parent hierarchy 25002 ViewRootImpl viewRoot = getViewRootImpl(); 25003 if (viewRoot != null && viewRoot.isInLayout()) { 25004 if (!viewRoot.requestLayoutDuringLayout(this)) { 25005 return; 25006 } 25007 } 25008 mAttachInfo.mViewRequestingLayout = this; 25009 } 25010 25011 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 25012 mPrivateFlags |= PFLAG_INVALIDATED; 25013 25014 if (mParent != null && !mParent.isLayoutRequested()) { 25015 mParent.requestLayout(); 25016 } 25017 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 25018 mAttachInfo.mViewRequestingLayout = null; 25019 } 25020 } 25021 25022 /** 25023 * Forces this view to be laid out during the next layout pass. 25024 * This method does not call requestLayout() or forceLayout() 25025 * on the parent. 25026 */ forceLayout()25027 public void forceLayout() { 25028 if (mMeasureCache != null) mMeasureCache.clear(); 25029 25030 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 25031 mPrivateFlags |= PFLAG_INVALIDATED; 25032 } 25033 25034 /** 25035 * <p> 25036 * This is called to find out how big a view should be. The parent 25037 * supplies constraint information in the width and height parameters. 25038 * </p> 25039 * 25040 * <p> 25041 * The actual measurement work of a view is performed in 25042 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 25043 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 25044 * </p> 25045 * 25046 * 25047 * @param widthMeasureSpec Horizontal space requirements as imposed by the 25048 * parent 25049 * @param heightMeasureSpec Vertical space requirements as imposed by the 25050 * parent 25051 * 25052 * @see #onMeasure(int, int) 25053 */ measure(int widthMeasureSpec, int heightMeasureSpec)25054 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 25055 boolean optical = isLayoutModeOptical(this); 25056 if (optical != isLayoutModeOptical(mParent)) { 25057 Insets insets = getOpticalInsets(); 25058 int oWidth = insets.left + insets.right; 25059 int oHeight = insets.top + insets.bottom; 25060 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 25061 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 25062 } 25063 25064 // Suppress sign extension for the low bytes 25065 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 25066 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 25067 25068 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 25069 25070 // Optimize layout by avoiding an extra EXACTLY pass when the view is 25071 // already measured as the correct size. In API 23 and below, this 25072 // extra pass is required to make LinearLayout re-distribute weight. 25073 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 25074 || heightMeasureSpec != mOldHeightMeasureSpec; 25075 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 25076 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 25077 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 25078 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 25079 final boolean needsLayout = specChanged 25080 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 25081 25082 if (forceLayout || needsLayout) { 25083 // first clears the measured dimension flag 25084 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 25085 25086 resolveRtlPropertiesIfNeeded(); 25087 25088 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 25089 if (cacheIndex < 0 || sIgnoreMeasureCache) { 25090 // measure ourselves, this should set the measured dimension flag back 25091 onMeasure(widthMeasureSpec, heightMeasureSpec); 25092 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 25093 } else { 25094 long value = mMeasureCache.valueAt(cacheIndex); 25095 // Casting a long to int drops the high 32 bits, no mask needed 25096 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 25097 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 25098 } 25099 25100 // flag not set, setMeasuredDimension() was not invoked, we raise 25101 // an exception to warn the developer 25102 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 25103 throw new IllegalStateException("View with id " + getId() + ": " 25104 + getClass().getName() + "#onMeasure() did not set the" 25105 + " measured dimension by calling" 25106 + " setMeasuredDimension()"); 25107 } 25108 25109 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 25110 } 25111 25112 mOldWidthMeasureSpec = widthMeasureSpec; 25113 mOldHeightMeasureSpec = heightMeasureSpec; 25114 25115 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 25116 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 25117 } 25118 25119 /** 25120 * <p> 25121 * Measure the view and its content to determine the measured width and the 25122 * measured height. This method is invoked by {@link #measure(int, int)} and 25123 * should be overridden by subclasses to provide accurate and efficient 25124 * measurement of their contents. 25125 * </p> 25126 * 25127 * <p> 25128 * <strong>CONTRACT:</strong> When overriding this method, you 25129 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 25130 * measured width and height of this view. Failure to do so will trigger an 25131 * <code>IllegalStateException</code>, thrown by 25132 * {@link #measure(int, int)}. Calling the superclass' 25133 * {@link #onMeasure(int, int)} is a valid use. 25134 * </p> 25135 * 25136 * <p> 25137 * The base class implementation of measure defaults to the background size, 25138 * unless a larger size is allowed by the MeasureSpec. Subclasses should 25139 * override {@link #onMeasure(int, int)} to provide better measurements of 25140 * their content. 25141 * </p> 25142 * 25143 * <p> 25144 * If this method is overridden, it is the subclass's responsibility to make 25145 * sure the measured height and width are at least the view's minimum height 25146 * and width ({@link #getSuggestedMinimumHeight()} and 25147 * {@link #getSuggestedMinimumWidth()}). 25148 * </p> 25149 * 25150 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 25151 * The requirements are encoded with 25152 * {@link android.view.View.MeasureSpec}. 25153 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 25154 * The requirements are encoded with 25155 * {@link android.view.View.MeasureSpec}. 25156 * 25157 * @see #getMeasuredWidth() 25158 * @see #getMeasuredHeight() 25159 * @see #setMeasuredDimension(int, int) 25160 * @see #getSuggestedMinimumHeight() 25161 * @see #getSuggestedMinimumWidth() 25162 * @see android.view.View.MeasureSpec#getMode(int) 25163 * @see android.view.View.MeasureSpec#getSize(int) 25164 */ onMeasure(int widthMeasureSpec, int heightMeasureSpec)25165 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 25166 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 25167 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 25168 } 25169 25170 /** 25171 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 25172 * measured width and measured height. Failing to do so will trigger an 25173 * exception at measurement time.</p> 25174 * 25175 * @param measuredWidth The measured width of this view. May be a complex 25176 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25177 * {@link #MEASURED_STATE_TOO_SMALL}. 25178 * @param measuredHeight The measured height of this view. May be a complex 25179 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25180 * {@link #MEASURED_STATE_TOO_SMALL}. 25181 */ setMeasuredDimension(int measuredWidth, int measuredHeight)25182 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 25183 boolean optical = isLayoutModeOptical(this); 25184 if (optical != isLayoutModeOptical(mParent)) { 25185 Insets insets = getOpticalInsets(); 25186 int opticalWidth = insets.left + insets.right; 25187 int opticalHeight = insets.top + insets.bottom; 25188 25189 measuredWidth += optical ? opticalWidth : -opticalWidth; 25190 measuredHeight += optical ? opticalHeight : -opticalHeight; 25191 } 25192 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 25193 } 25194 25195 /** 25196 * Sets the measured dimension without extra processing for things like optical bounds. 25197 * Useful for reapplying consistent values that have already been cooked with adjustments 25198 * for optical bounds, etc. such as those from the measurement cache. 25199 * 25200 * @param measuredWidth The measured width of this view. May be a complex 25201 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25202 * {@link #MEASURED_STATE_TOO_SMALL}. 25203 * @param measuredHeight The measured height of this view. May be a complex 25204 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25205 * {@link #MEASURED_STATE_TOO_SMALL}. 25206 */ setMeasuredDimensionRaw(int measuredWidth, int measuredHeight)25207 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 25208 mMeasuredWidth = measuredWidth; 25209 mMeasuredHeight = measuredHeight; 25210 25211 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 25212 } 25213 25214 /** 25215 * Merge two states as returned by {@link #getMeasuredState()}. 25216 * @param curState The current state as returned from a view or the result 25217 * of combining multiple views. 25218 * @param newState The new view state to combine. 25219 * @return Returns a new integer reflecting the combination of the two 25220 * states. 25221 */ combineMeasuredStates(int curState, int newState)25222 public static int combineMeasuredStates(int curState, int newState) { 25223 return curState | newState; 25224 } 25225 25226 /** 25227 * Version of {@link #resolveSizeAndState(int, int, int)} 25228 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 25229 */ resolveSize(int size, int measureSpec)25230 public static int resolveSize(int size, int measureSpec) { 25231 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 25232 } 25233 25234 /** 25235 * Utility to reconcile a desired size and state, with constraints imposed 25236 * by a MeasureSpec. Will take the desired size, unless a different size 25237 * is imposed by the constraints. The returned value is a compound integer, 25238 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 25239 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 25240 * resulting size is smaller than the size the view wants to be. 25241 * 25242 * @param size How big the view wants to be. 25243 * @param measureSpec Constraints imposed by the parent. 25244 * @param childMeasuredState Size information bit mask for the view's 25245 * children. 25246 * @return Size information bit mask as defined by 25247 * {@link #MEASURED_SIZE_MASK} and 25248 * {@link #MEASURED_STATE_TOO_SMALL}. 25249 */ resolveSizeAndState(int size, int measureSpec, int childMeasuredState)25250 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 25251 final int specMode = MeasureSpec.getMode(measureSpec); 25252 final int specSize = MeasureSpec.getSize(measureSpec); 25253 final int result; 25254 switch (specMode) { 25255 case MeasureSpec.AT_MOST: 25256 if (specSize < size) { 25257 result = specSize | MEASURED_STATE_TOO_SMALL; 25258 } else { 25259 result = size; 25260 } 25261 break; 25262 case MeasureSpec.EXACTLY: 25263 result = specSize; 25264 break; 25265 case MeasureSpec.UNSPECIFIED: 25266 default: 25267 result = size; 25268 } 25269 return result | (childMeasuredState & MEASURED_STATE_MASK); 25270 } 25271 25272 /** 25273 * Utility to return a default size. Uses the supplied size if the 25274 * MeasureSpec imposed no constraints. Will get larger if allowed 25275 * by the MeasureSpec. 25276 * 25277 * @param size Default size for this view 25278 * @param measureSpec Constraints imposed by the parent 25279 * @return The size this view should be. 25280 */ getDefaultSize(int size, int measureSpec)25281 public static int getDefaultSize(int size, int measureSpec) { 25282 int result = size; 25283 int specMode = MeasureSpec.getMode(measureSpec); 25284 int specSize = MeasureSpec.getSize(measureSpec); 25285 25286 switch (specMode) { 25287 case MeasureSpec.UNSPECIFIED: 25288 result = size; 25289 break; 25290 case MeasureSpec.AT_MOST: 25291 case MeasureSpec.EXACTLY: 25292 result = specSize; 25293 break; 25294 } 25295 return result; 25296 } 25297 25298 /** 25299 * Returns the suggested minimum height that the view should use. This 25300 * returns the maximum of the view's minimum height 25301 * and the background's minimum height 25302 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 25303 * <p> 25304 * When being used in {@link #onMeasure(int, int)}, the caller should still 25305 * ensure the returned height is within the requirements of the parent. 25306 * 25307 * @return The suggested minimum height of the view. 25308 */ getSuggestedMinimumHeight()25309 protected int getSuggestedMinimumHeight() { 25310 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 25311 25312 } 25313 25314 /** 25315 * Returns the suggested minimum width that the view should use. This 25316 * returns the maximum of the view's minimum width 25317 * and the background's minimum width 25318 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 25319 * <p> 25320 * When being used in {@link #onMeasure(int, int)}, the caller should still 25321 * ensure the returned width is within the requirements of the parent. 25322 * 25323 * @return The suggested minimum width of the view. 25324 */ getSuggestedMinimumWidth()25325 protected int getSuggestedMinimumWidth() { 25326 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 25327 } 25328 25329 /** 25330 * Returns the minimum height of the view. 25331 * 25332 * @return the minimum height the view will try to be, in pixels 25333 * 25334 * @see #setMinimumHeight(int) 25335 * 25336 * @attr ref android.R.styleable#View_minHeight 25337 */ 25338 @InspectableProperty(name = "minHeight") getMinimumHeight()25339 public int getMinimumHeight() { 25340 return mMinHeight; 25341 } 25342 25343 /** 25344 * Sets the minimum height of the view. It is not guaranteed the view will 25345 * be able to achieve this minimum height (for example, if its parent layout 25346 * constrains it with less available height). 25347 * 25348 * @param minHeight The minimum height the view will try to be, in pixels 25349 * 25350 * @see #getMinimumHeight() 25351 * 25352 * @attr ref android.R.styleable#View_minHeight 25353 */ 25354 @RemotableViewMethod setMinimumHeight(int minHeight)25355 public void setMinimumHeight(int minHeight) { 25356 mMinHeight = minHeight; 25357 requestLayout(); 25358 } 25359 25360 /** 25361 * Returns the minimum width of the view. 25362 * 25363 * @return the minimum width the view will try to be, in pixels 25364 * 25365 * @see #setMinimumWidth(int) 25366 * 25367 * @attr ref android.R.styleable#View_minWidth 25368 */ 25369 @InspectableProperty(name = "minWidth") getMinimumWidth()25370 public int getMinimumWidth() { 25371 return mMinWidth; 25372 } 25373 25374 /** 25375 * Sets the minimum width of the view. It is not guaranteed the view will 25376 * be able to achieve this minimum width (for example, if its parent layout 25377 * constrains it with less available width). 25378 * 25379 * @param minWidth The minimum width the view will try to be, in pixels 25380 * 25381 * @see #getMinimumWidth() 25382 * 25383 * @attr ref android.R.styleable#View_minWidth 25384 */ setMinimumWidth(int minWidth)25385 public void setMinimumWidth(int minWidth) { 25386 mMinWidth = minWidth; 25387 requestLayout(); 25388 25389 } 25390 25391 /** 25392 * Get the animation currently associated with this view. 25393 * 25394 * @return The animation that is currently playing or 25395 * scheduled to play for this view. 25396 */ getAnimation()25397 public Animation getAnimation() { 25398 return mCurrentAnimation; 25399 } 25400 25401 /** 25402 * Start the specified animation now. 25403 * 25404 * @param animation the animation to start now 25405 */ startAnimation(Animation animation)25406 public void startAnimation(Animation animation) { 25407 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 25408 setAnimation(animation); 25409 invalidateParentCaches(); 25410 invalidate(true); 25411 } 25412 25413 /** 25414 * Cancels any animations for this view. 25415 */ clearAnimation()25416 public void clearAnimation() { 25417 if (mCurrentAnimation != null) { 25418 mCurrentAnimation.detach(); 25419 } 25420 mCurrentAnimation = null; 25421 invalidateParentIfNeeded(); 25422 } 25423 25424 /** 25425 * Sets the next animation to play for this view. 25426 * If you want the animation to play immediately, use 25427 * {@link #startAnimation(android.view.animation.Animation)} instead. 25428 * This method provides allows fine-grained 25429 * control over the start time and invalidation, but you 25430 * must make sure that 1) the animation has a start time set, and 25431 * 2) the view's parent (which controls animations on its children) 25432 * will be invalidated when the animation is supposed to 25433 * start. 25434 * 25435 * @param animation The next animation, or null. 25436 */ setAnimation(Animation animation)25437 public void setAnimation(Animation animation) { 25438 mCurrentAnimation = animation; 25439 25440 if (animation != null) { 25441 // If the screen is off assume the animation start time is now instead of 25442 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 25443 // would cause the animation to start when the screen turns back on 25444 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 25445 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 25446 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 25447 } 25448 animation.reset(); 25449 } 25450 } 25451 25452 /** 25453 * Invoked by a parent ViewGroup to notify the start of the animation 25454 * currently associated with this view. If you override this method, 25455 * always call super.onAnimationStart(); 25456 * 25457 * @see #setAnimation(android.view.animation.Animation) 25458 * @see #getAnimation() 25459 */ 25460 @CallSuper onAnimationStart()25461 protected void onAnimationStart() { 25462 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 25463 } 25464 25465 /** 25466 * Invoked by a parent ViewGroup to notify the end of the animation 25467 * currently associated with this view. If you override this method, 25468 * always call super.onAnimationEnd(); 25469 * 25470 * @see #setAnimation(android.view.animation.Animation) 25471 * @see #getAnimation() 25472 */ 25473 @CallSuper onAnimationEnd()25474 protected void onAnimationEnd() { 25475 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 25476 } 25477 25478 /** 25479 * Invoked if there is a Transform that involves alpha. Subclass that can 25480 * draw themselves with the specified alpha should return true, and then 25481 * respect that alpha when their onDraw() is called. If this returns false 25482 * then the view may be redirected to draw into an offscreen buffer to 25483 * fulfill the request, which will look fine, but may be slower than if the 25484 * subclass handles it internally. The default implementation returns false. 25485 * 25486 * @param alpha The alpha (0..255) to apply to the view's drawing 25487 * @return true if the view can draw with the specified alpha. 25488 */ onSetAlpha(int alpha)25489 protected boolean onSetAlpha(int alpha) { 25490 return false; 25491 } 25492 25493 /** 25494 * This is used by the RootView to perform an optimization when 25495 * the view hierarchy contains one or several SurfaceView. 25496 * SurfaceView is always considered transparent, but its children are not, 25497 * therefore all View objects remove themselves from the global transparent 25498 * region (passed as a parameter to this function). 25499 * 25500 * @param region The transparent region for this ViewAncestor (window). 25501 * 25502 * @return Returns true if the effective visibility of the view at this 25503 * point is opaque, regardless of the transparent region; returns false 25504 * if it is possible for underlying windows to be seen behind the view. 25505 * 25506 * {@hide} 25507 */ 25508 @UnsupportedAppUsage gatherTransparentRegion(Region region)25509 public boolean gatherTransparentRegion(Region region) { 25510 final AttachInfo attachInfo = mAttachInfo; 25511 if (region != null && attachInfo != null) { 25512 final int pflags = mPrivateFlags; 25513 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 25514 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 25515 // remove it from the transparent region. 25516 final int[] location = attachInfo.mTransparentLocation; 25517 getLocationInWindow(location); 25518 // When a view has Z value, then it will be better to leave some area below the view 25519 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 25520 // the bottom part needs more offset than the left, top and right parts due to the 25521 // spot light effects. 25522 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 25523 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 25524 location[0] + mRight - mLeft + shadowOffset, 25525 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 25526 } else { 25527 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 25528 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 25529 // the background drawable's non-transparent parts from this transparent region. 25530 applyDrawableToTransparentRegion(mBackground, region); 25531 } 25532 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 25533 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 25534 // Similarly, we remove the foreground drawable's non-transparent parts. 25535 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 25536 } 25537 if (mDefaultFocusHighlight != null 25538 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { 25539 // Similarly, we remove the default focus highlight's non-transparent parts. 25540 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); 25541 } 25542 } 25543 } 25544 return true; 25545 } 25546 25547 /** 25548 * Play a sound effect for this view. 25549 * 25550 * <p>The framework will play sound effects for some built in actions, such as 25551 * clicking, but you may wish to play these effects in your widget, 25552 * for instance, for internal navigation. 25553 * 25554 * <p>The sound effect will only be played if sound effects are enabled by the user, and 25555 * {@link #isSoundEffectsEnabled()} is true. 25556 * 25557 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 25558 */ playSoundEffect(int soundConstant)25559 public void playSoundEffect(int soundConstant) { 25560 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 25561 return; 25562 } 25563 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 25564 } 25565 25566 /** 25567 * BZZZTT!!1! 25568 * 25569 * <p>Provide haptic feedback to the user for this view. 25570 * 25571 * <p>The framework will provide haptic feedback for some built in actions, 25572 * such as long presses, but you may wish to provide feedback for your 25573 * own widget. 25574 * 25575 * <p>The feedback will only be performed if 25576 * {@link #isHapticFeedbackEnabled()} is true. 25577 * 25578 * @param feedbackConstant One of the constants defined in 25579 * {@link HapticFeedbackConstants} 25580 */ performHapticFeedback(int feedbackConstant)25581 public boolean performHapticFeedback(int feedbackConstant) { 25582 return performHapticFeedback(feedbackConstant, 0); 25583 } 25584 25585 /** 25586 * BZZZTT!!1! 25587 * 25588 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 25589 * 25590 * @param feedbackConstant One of the constants defined in 25591 * {@link HapticFeedbackConstants} 25592 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 25593 */ performHapticFeedback(int feedbackConstant, int flags)25594 public boolean performHapticFeedback(int feedbackConstant, int flags) { 25595 if (mAttachInfo == null) { 25596 return false; 25597 } 25598 //noinspection SimplifiableIfStatement 25599 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 25600 && !isHapticFeedbackEnabled()) { 25601 return false; 25602 } 25603 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 25604 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 25605 } 25606 25607 /** 25608 * Request that the visibility of the status bar or other screen/window 25609 * decorations be changed. 25610 * 25611 * <p>This method is used to put the over device UI into temporary modes 25612 * where the user's attention is focused more on the application content, 25613 * by dimming or hiding surrounding system affordances. This is typically 25614 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 25615 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 25616 * to be placed behind the action bar (and with these flags other system 25617 * affordances) so that smooth transitions between hiding and showing them 25618 * can be done. 25619 * 25620 * <p>Two representative examples of the use of system UI visibility is 25621 * implementing a content browsing application (like a magazine reader) 25622 * and a video playing application. 25623 * 25624 * <p>The first code shows a typical implementation of a View in a content 25625 * browsing application. In this implementation, the application goes 25626 * into a content-oriented mode by hiding the status bar and action bar, 25627 * and putting the navigation elements into lights out mode. The user can 25628 * then interact with content while in this mode. Such an application should 25629 * provide an easy way for the user to toggle out of the mode (such as to 25630 * check information in the status bar or access notifications). In the 25631 * implementation here, this is done simply by tapping on the content. 25632 * 25633 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 25634 * content} 25635 * 25636 * <p>This second code sample shows a typical implementation of a View 25637 * in a video playing application. In this situation, while the video is 25638 * playing the application would like to go into a complete full-screen mode, 25639 * to use as much of the display as possible for the video. When in this state 25640 * the user can not interact with the application; the system intercepts 25641 * touching on the screen to pop the UI out of full screen mode. See 25642 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 25643 * 25644 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 25645 * content} 25646 * 25647 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 25648 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 25649 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 25650 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 25651 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 25652 */ setSystemUiVisibility(int visibility)25653 public void setSystemUiVisibility(int visibility) { 25654 if (visibility != mSystemUiVisibility) { 25655 mSystemUiVisibility = visibility; 25656 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 25657 mParent.recomputeViewAttributes(this); 25658 } 25659 } 25660 } 25661 25662 /** 25663 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 25664 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 25665 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 25666 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 25667 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 25668 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 25669 */ getSystemUiVisibility()25670 public int getSystemUiVisibility() { 25671 return mSystemUiVisibility; 25672 } 25673 25674 /** 25675 * Returns the current system UI visibility that is currently set for 25676 * the entire window. This is the combination of the 25677 * {@link #setSystemUiVisibility(int)} values supplied by all of the 25678 * views in the window. 25679 */ getWindowSystemUiVisibility()25680 public int getWindowSystemUiVisibility() { 25681 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 25682 } 25683 25684 /** 25685 * Override to find out when the window's requested system UI visibility 25686 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 25687 * This is different from the callbacks received through 25688 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 25689 * in that this is only telling you about the local request of the window, 25690 * not the actual values applied by the system. 25691 */ onWindowSystemUiVisibilityChanged(int visible)25692 public void onWindowSystemUiVisibilityChanged(int visible) { 25693 } 25694 25695 /** 25696 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 25697 * the view hierarchy. 25698 */ dispatchWindowSystemUiVisiblityChanged(int visible)25699 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 25700 onWindowSystemUiVisibilityChanged(visible); 25701 } 25702 25703 /** 25704 * Set a listener to receive callbacks when the visibility of the system bar changes. 25705 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 25706 */ setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l)25707 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 25708 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 25709 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 25710 mParent.recomputeViewAttributes(this); 25711 } 25712 } 25713 25714 /** 25715 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 25716 * the view hierarchy. 25717 */ dispatchSystemUiVisibilityChanged(int visibility)25718 public void dispatchSystemUiVisibilityChanged(int visibility) { 25719 ListenerInfo li = mListenerInfo; 25720 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 25721 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 25722 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 25723 } 25724 } 25725 updateLocalSystemUiVisibility(int localValue, int localChanges)25726 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 25727 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 25728 if (val != mSystemUiVisibility) { 25729 setSystemUiVisibility(val); 25730 return true; 25731 } 25732 return false; 25733 } 25734 25735 /** @hide */ 25736 @UnsupportedAppUsage setDisabledSystemUiVisibility(int flags)25737 public void setDisabledSystemUiVisibility(int flags) { 25738 if (mAttachInfo != null) { 25739 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 25740 mAttachInfo.mDisabledSystemUiVisibility = flags; 25741 if (mParent != null) { 25742 mParent.recomputeViewAttributes(this); 25743 } 25744 } 25745 } 25746 } 25747 25748 /** 25749 * Creates an image that the system displays during the drag and drop 25750 * operation. This is called a "drag shadow". The default implementation 25751 * for a DragShadowBuilder based on a View returns an image that has exactly the same 25752 * appearance as the given View. The default also positions the center of the drag shadow 25753 * directly under the touch point. If no View is provided (the constructor with no parameters 25754 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 25755 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 25756 * default is an invisible drag shadow. 25757 * <p> 25758 * You are not required to use the View you provide to the constructor as the basis of the 25759 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 25760 * anything you want as the drag shadow. 25761 * </p> 25762 * <p> 25763 * You pass a DragShadowBuilder object to the system when you start the drag. The system 25764 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 25765 * size and position of the drag shadow. It uses this data to construct a 25766 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 25767 * so that your application can draw the shadow image in the Canvas. 25768 * </p> 25769 * 25770 * <div class="special reference"> 25771 * <h3>Developer Guides</h3> 25772 * <p>For a guide to implementing drag and drop features, read the 25773 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 25774 * </div> 25775 */ 25776 public static class DragShadowBuilder { 25777 @UnsupportedAppUsage 25778 private final WeakReference<View> mView; 25779 25780 /** 25781 * Constructs a shadow image builder based on a View. By default, the resulting drag 25782 * shadow will have the same appearance and dimensions as the View, with the touch point 25783 * over the center of the View. 25784 * @param view A View. Any View in scope can be used. 25785 */ DragShadowBuilder(View view)25786 public DragShadowBuilder(View view) { 25787 mView = new WeakReference<View>(view); 25788 } 25789 25790 /** 25791 * Construct a shadow builder object with no associated View. This 25792 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 25793 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 25794 * to supply the drag shadow's dimensions and appearance without 25795 * reference to any View object. 25796 */ DragShadowBuilder()25797 public DragShadowBuilder() { 25798 mView = new WeakReference<View>(null); 25799 } 25800 25801 /** 25802 * Returns the View object that had been passed to the 25803 * {@link #DragShadowBuilder(View)} 25804 * constructor. If that View parameter was {@code null} or if the 25805 * {@link #DragShadowBuilder()} 25806 * constructor was used to instantiate the builder object, this method will return 25807 * null. 25808 * 25809 * @return The View object associate with this builder object. 25810 */ 25811 @SuppressWarnings({"JavadocReference"}) getView()25812 final public View getView() { 25813 return mView.get(); 25814 } 25815 25816 /** 25817 * Provides the metrics for the shadow image. These include the dimensions of 25818 * the shadow image, and the point within that shadow that should 25819 * be centered under the touch location while dragging. 25820 * <p> 25821 * The default implementation sets the dimensions of the shadow to be the 25822 * same as the dimensions of the View itself and centers the shadow under 25823 * the touch point. 25824 * </p> 25825 * 25826 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 25827 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 25828 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 25829 * image. Since Android P, the width and height must be positive values. 25830 * 25831 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 25832 * shadow image that should be underneath the touch point during the drag and drop 25833 * operation. Your application must set {@link android.graphics.Point#x} to the 25834 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 25835 */ onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint)25836 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 25837 final View view = mView.get(); 25838 if (view != null) { 25839 outShadowSize.set(view.getWidth(), view.getHeight()); 25840 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 25841 } else { 25842 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 25843 } 25844 } 25845 25846 /** 25847 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 25848 * based on the dimensions it received from the 25849 * {@link #onProvideShadowMetrics(Point, Point)} callback. 25850 * 25851 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 25852 */ onDrawShadow(Canvas canvas)25853 public void onDrawShadow(Canvas canvas) { 25854 final View view = mView.get(); 25855 if (view != null) { 25856 view.draw(canvas); 25857 } else { 25858 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 25859 } 25860 } 25861 } 25862 25863 /** 25864 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 25865 * startDragAndDrop()} for newer platform versions. 25866 */ 25867 @Deprecated startDrag(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)25868 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 25869 Object myLocalState, int flags) { 25870 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 25871 } 25872 25873 /** 25874 * Starts a drag and drop operation. When your application calls this method, it passes a 25875 * {@link android.view.View.DragShadowBuilder} object to the system. The 25876 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 25877 * to get metrics for the drag shadow, and then calls the object's 25878 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 25879 * <p> 25880 * Once the system has the drag shadow, it begins the drag and drop operation by sending 25881 * drag events to all the View objects in your application that are currently visible. It does 25882 * this either by calling the View object's drag listener (an implementation of 25883 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 25884 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 25885 * Both are passed a {@link android.view.DragEvent} object that has a 25886 * {@link android.view.DragEvent#getAction()} value of 25887 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 25888 * </p> 25889 * <p> 25890 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 25891 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 25892 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 25893 * to the View the user selected for dragging. 25894 * </p> 25895 * @param data A {@link android.content.ClipData} object pointing to the data to be 25896 * transferred by the drag and drop operation. 25897 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 25898 * drag shadow. 25899 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 25900 * drop operation. When dispatching drag events to views in the same activity this object 25901 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 25902 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 25903 * will return null). 25904 * <p> 25905 * myLocalState is a lightweight mechanism for the sending information from the dragged View 25906 * to the target Views. For example, it can contain flags that differentiate between a 25907 * a copy operation and a move operation. 25908 * </p> 25909 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 25910 * flags, or any combination of the following: 25911 * <ul> 25912 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 25913 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 25914 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 25915 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 25916 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 25917 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 25918 * </ul> 25919 * @return {@code true} if the method completes successfully, or 25920 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 25921 * do a drag because of another ongoing operation or some other reasons. 25922 */ startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)25923 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 25924 Object myLocalState, int flags) { 25925 if (ViewDebug.DEBUG_DRAG) { 25926 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 25927 } 25928 if (mAttachInfo == null) { 25929 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 25930 return false; 25931 } 25932 if (!mAttachInfo.mViewRootImpl.mSurface.isValid()) { 25933 Log.w(VIEW_LOG_TAG, "startDragAndDrop called with an invalid surface."); 25934 return false; 25935 } 25936 25937 if (data != null) { 25938 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 25939 } 25940 25941 Point shadowSize = new Point(); 25942 Point shadowTouchPoint = new Point(); 25943 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 25944 25945 if ((shadowSize.x < 0) || (shadowSize.y < 0) 25946 || (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 25947 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 25948 } 25949 25950 // Create 1x1 surface when zero surface size is specified because SurfaceControl.Builder 25951 // does not accept zero size surface. 25952 if (shadowSize.x == 0 || shadowSize.y == 0) { 25953 if (!sAcceptZeroSizeDragShadow) { 25954 throw new IllegalStateException("Drag shadow dimensions must be positive"); 25955 } 25956 shadowSize.x = 1; 25957 shadowSize.y = 1; 25958 } 25959 25960 if (ViewDebug.DEBUG_DRAG) { 25961 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 25962 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 25963 } 25964 25965 final ViewRootImpl root = mAttachInfo.mViewRootImpl; 25966 final SurfaceSession session = new SurfaceSession(); 25967 final SurfaceControl surfaceControl = new SurfaceControl.Builder(session) 25968 .setName("drag surface") 25969 .setParent(root.getSurfaceControl()) 25970 .setBufferSize(shadowSize.x, shadowSize.y) 25971 .setFormat(PixelFormat.TRANSLUCENT) 25972 .build(); 25973 final Surface surface = new Surface(); 25974 surface.copyFrom(surfaceControl); 25975 IBinder token = null; 25976 try { 25977 final Canvas canvas = surface.lockCanvas(null); 25978 try { 25979 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 25980 shadowBuilder.onDrawShadow(canvas); 25981 } finally { 25982 surface.unlockCanvasAndPost(canvas); 25983 } 25984 25985 // repurpose 'shadowSize' for the last touch point 25986 root.getLastTouchPoint(shadowSize); 25987 25988 token = mAttachInfo.mSession.performDrag( 25989 mAttachInfo.mWindow, flags, surfaceControl, root.getLastTouchSource(), 25990 shadowSize.x, shadowSize.y, shadowTouchPoint.x, shadowTouchPoint.y, data); 25991 if (ViewDebug.DEBUG_DRAG) { 25992 Log.d(VIEW_LOG_TAG, "performDrag returned " + token); 25993 } 25994 if (token != null) { 25995 if (mAttachInfo.mDragSurface != null) { 25996 mAttachInfo.mDragSurface.release(); 25997 } 25998 mAttachInfo.mDragSurface = surface; 25999 mAttachInfo.mDragToken = token; 26000 // Cache the local state object for delivery with DragEvents 26001 root.setLocalDragState(myLocalState); 26002 } 26003 return token != null; 26004 } catch (Exception e) { 26005 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 26006 return false; 26007 } finally { 26008 if (token == null) { 26009 surface.destroy(); 26010 } 26011 session.kill(); 26012 } 26013 } 26014 26015 /** 26016 * Cancels an ongoing drag and drop operation. 26017 * <p> 26018 * A {@link android.view.DragEvent} object with 26019 * {@link android.view.DragEvent#getAction()} value of 26020 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 26021 * {@link android.view.DragEvent#getResult()} value of {@code false} 26022 * will be sent to every 26023 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 26024 * even if they are not currently visible. 26025 * </p> 26026 * <p> 26027 * This method can be called on any View in the same window as the View on which 26028 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 26029 * was called. 26030 * </p> 26031 */ cancelDragAndDrop()26032 public final void cancelDragAndDrop() { 26033 if (ViewDebug.DEBUG_DRAG) { 26034 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 26035 } 26036 if (mAttachInfo == null) { 26037 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 26038 return; 26039 } 26040 if (mAttachInfo.mDragToken != null) { 26041 try { 26042 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken, false); 26043 } catch (Exception e) { 26044 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 26045 } 26046 mAttachInfo.mDragToken = null; 26047 } else { 26048 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 26049 } 26050 } 26051 26052 /** 26053 * Updates the drag shadow for the ongoing drag and drop operation. 26054 * 26055 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 26056 * new drag shadow. 26057 */ updateDragShadow(DragShadowBuilder shadowBuilder)26058 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 26059 if (ViewDebug.DEBUG_DRAG) { 26060 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 26061 } 26062 if (mAttachInfo == null) { 26063 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 26064 return; 26065 } 26066 if (mAttachInfo.mDragToken != null) { 26067 try { 26068 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 26069 try { 26070 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 26071 shadowBuilder.onDrawShadow(canvas); 26072 } finally { 26073 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 26074 } 26075 } catch (Exception e) { 26076 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 26077 } 26078 } else { 26079 Log.e(VIEW_LOG_TAG, "No active drag"); 26080 } 26081 } 26082 26083 /** 26084 * Starts a move from {startX, startY}, the amount of the movement will be the offset 26085 * between {startX, startY} and the new cursor positon. 26086 * @param startX horizontal coordinate where the move started. 26087 * @param startY vertical coordinate where the move started. 26088 * @return whether moving was started successfully. 26089 * @hide 26090 */ startMovingTask(float startX, float startY)26091 public final boolean startMovingTask(float startX, float startY) { 26092 if (ViewDebug.DEBUG_POSITIONING) { 26093 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 26094 } 26095 try { 26096 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 26097 } catch (RemoteException e) { 26098 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 26099 } 26100 return false; 26101 } 26102 26103 /** 26104 * Finish a window move task. 26105 * @hide 26106 */ finishMovingTask()26107 public void finishMovingTask() { 26108 if (ViewDebug.DEBUG_POSITIONING) { 26109 Log.d(VIEW_LOG_TAG, "finishMovingTask"); 26110 } 26111 try { 26112 mAttachInfo.mSession.finishMovingTask(mAttachInfo.mWindow); 26113 } catch (RemoteException e) { 26114 Log.e(VIEW_LOG_TAG, "Unable to finish moving", e); 26115 } 26116 } 26117 26118 /** 26119 * Handles drag events sent by the system following a call to 26120 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 26121 * startDragAndDrop()}. 26122 *<p> 26123 * When the system calls this method, it passes a 26124 * {@link android.view.DragEvent} object. A call to 26125 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 26126 * in DragEvent. The method uses these to determine what is happening in the drag and drop 26127 * operation. 26128 * @param event The {@link android.view.DragEvent} sent by the system. 26129 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 26130 * in DragEvent, indicating the type of drag event represented by this object. 26131 * @return {@code true} if the method was successful, otherwise {@code false}. 26132 * <p> 26133 * The method should return {@code true} in response to an action type of 26134 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 26135 * operation. 26136 * </p> 26137 * <p> 26138 * The method should also return {@code true} in response to an action type of 26139 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 26140 * {@code false} if it didn't. 26141 * </p> 26142 * <p> 26143 * For all other events, the return value is ignored. 26144 * </p> 26145 */ onDragEvent(DragEvent event)26146 public boolean onDragEvent(DragEvent event) { 26147 return false; 26148 } 26149 26150 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. dispatchDragEnterExitInPreN(DragEvent event)26151 boolean dispatchDragEnterExitInPreN(DragEvent event) { 26152 return callDragEventHandler(event); 26153 } 26154 26155 /** 26156 * Detects if this View is enabled and has a drag event listener. 26157 * If both are true, then it calls the drag event listener with the 26158 * {@link android.view.DragEvent} it received. If the drag event listener returns 26159 * {@code true}, then dispatchDragEvent() returns {@code true}. 26160 * <p> 26161 * For all other cases, the method calls the 26162 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 26163 * method and returns its result. 26164 * </p> 26165 * <p> 26166 * This ensures that a drag event is always consumed, even if the View does not have a drag 26167 * event listener. However, if the View has a listener and the listener returns true, then 26168 * onDragEvent() is not called. 26169 * </p> 26170 */ dispatchDragEvent(DragEvent event)26171 public boolean dispatchDragEvent(DragEvent event) { 26172 event.mEventHandlerWasCalled = true; 26173 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 26174 event.mAction == DragEvent.ACTION_DROP) { 26175 // About to deliver an event with coordinates to this view. Notify that now this view 26176 // has drag focus. This will send exit/enter events as needed. 26177 getViewRootImpl().setDragFocus(this, event); 26178 } 26179 return callDragEventHandler(event); 26180 } 26181 callDragEventHandler(DragEvent event)26182 final boolean callDragEventHandler(DragEvent event) { 26183 final boolean result; 26184 26185 ListenerInfo li = mListenerInfo; 26186 //noinspection SimplifiableIfStatement 26187 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 26188 && li.mOnDragListener.onDrag(this, event)) { 26189 result = true; 26190 } else { 26191 result = onDragEvent(event); 26192 } 26193 26194 switch (event.mAction) { 26195 case DragEvent.ACTION_DRAG_ENTERED: { 26196 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 26197 refreshDrawableState(); 26198 } break; 26199 case DragEvent.ACTION_DRAG_EXITED: { 26200 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 26201 refreshDrawableState(); 26202 } break; 26203 case DragEvent.ACTION_DRAG_ENDED: { 26204 mPrivateFlags2 &= ~View.DRAG_MASK; 26205 refreshDrawableState(); 26206 } break; 26207 } 26208 26209 return result; 26210 } 26211 canAcceptDrag()26212 boolean canAcceptDrag() { 26213 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 26214 } 26215 26216 /** 26217 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 26218 * it is ever exposed at all. 26219 * @hide 26220 */ 26221 @UnsupportedAppUsage onCloseSystemDialogs(String reason)26222 public void onCloseSystemDialogs(String reason) { 26223 } 26224 26225 /** 26226 * Given a Drawable whose bounds have been set to draw into this view, 26227 * update a Region being computed for 26228 * {@link #gatherTransparentRegion(android.graphics.Region)} so 26229 * that any non-transparent parts of the Drawable are removed from the 26230 * given transparent region. 26231 * 26232 * @param dr The Drawable whose transparency is to be applied to the region. 26233 * @param region A Region holding the current transparency information, 26234 * where any parts of the region that are set are considered to be 26235 * transparent. On return, this region will be modified to have the 26236 * transparency information reduced by the corresponding parts of the 26237 * Drawable that are not transparent. 26238 * {@hide} 26239 */ 26240 @UnsupportedAppUsage applyDrawableToTransparentRegion(Drawable dr, Region region)26241 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 26242 if (DBG) { 26243 Log.i("View", "Getting transparent region for: " + this); 26244 } 26245 final Region r = dr.getTransparentRegion(); 26246 final Rect db = dr.getBounds(); 26247 final AttachInfo attachInfo = mAttachInfo; 26248 if (r != null && attachInfo != null) { 26249 final int w = getRight()-getLeft(); 26250 final int h = getBottom()-getTop(); 26251 if (db.left > 0) { 26252 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 26253 r.op(0, 0, db.left, h, Region.Op.UNION); 26254 } 26255 if (db.right < w) { 26256 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 26257 r.op(db.right, 0, w, h, Region.Op.UNION); 26258 } 26259 if (db.top > 0) { 26260 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 26261 r.op(0, 0, w, db.top, Region.Op.UNION); 26262 } 26263 if (db.bottom < h) { 26264 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 26265 r.op(0, db.bottom, w, h, Region.Op.UNION); 26266 } 26267 final int[] location = attachInfo.mTransparentLocation; 26268 getLocationInWindow(location); 26269 r.translate(location[0], location[1]); 26270 region.op(r, Region.Op.INTERSECT); 26271 } else { 26272 region.op(db, Region.Op.DIFFERENCE); 26273 } 26274 } 26275 checkForLongClick(long delay, float x, float y, int classification)26276 private void checkForLongClick(long delay, float x, float y, int classification) { 26277 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 26278 mHasPerformedLongPress = false; 26279 26280 if (mPendingCheckForLongPress == null) { 26281 mPendingCheckForLongPress = new CheckForLongPress(); 26282 } 26283 mPendingCheckForLongPress.setAnchor(x, y); 26284 mPendingCheckForLongPress.rememberWindowAttachCount(); 26285 mPendingCheckForLongPress.rememberPressedState(); 26286 mPendingCheckForLongPress.setClassification(classification); 26287 postDelayed(mPendingCheckForLongPress, delay); 26288 } 26289 } 26290 26291 /** 26292 * Inflate a view from an XML resource. This convenience method wraps the {@link 26293 * LayoutInflater} class, which provides a full range of options for view inflation. 26294 * 26295 * @param context The Context object for your activity or application. 26296 * @param resource The resource ID to inflate 26297 * @param root A view group that will be the parent. Used to properly inflate the 26298 * layout_* parameters. 26299 * @see LayoutInflater 26300 */ inflate(Context context, @LayoutRes int resource, ViewGroup root)26301 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 26302 LayoutInflater factory = LayoutInflater.from(context); 26303 return factory.inflate(resource, root); 26304 } 26305 26306 /** 26307 * Scroll the view with standard behavior for scrolling beyond the normal 26308 * content boundaries. Views that call this method should override 26309 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 26310 * results of an over-scroll operation. 26311 * 26312 * Views can use this method to handle any touch or fling-based scrolling. 26313 * 26314 * @param deltaX Change in X in pixels 26315 * @param deltaY Change in Y in pixels 26316 * @param scrollX Current X scroll value in pixels before applying deltaX 26317 * @param scrollY Current Y scroll value in pixels before applying deltaY 26318 * @param scrollRangeX Maximum content scroll range along the X axis 26319 * @param scrollRangeY Maximum content scroll range along the Y axis 26320 * @param maxOverScrollX Number of pixels to overscroll by in either direction 26321 * along the X axis. 26322 * @param maxOverScrollY Number of pixels to overscroll by in either direction 26323 * along the Y axis. 26324 * @param isTouchEvent true if this scroll operation is the result of a touch event. 26325 * @return true if scrolling was clamped to an over-scroll boundary along either 26326 * axis, false otherwise. 26327 */ 26328 @SuppressWarnings({"UnusedParameters"}) overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent)26329 protected boolean overScrollBy(int deltaX, int deltaY, 26330 int scrollX, int scrollY, 26331 int scrollRangeX, int scrollRangeY, 26332 int maxOverScrollX, int maxOverScrollY, 26333 boolean isTouchEvent) { 26334 final int overScrollMode = mOverScrollMode; 26335 final boolean canScrollHorizontal = 26336 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 26337 final boolean canScrollVertical = 26338 computeVerticalScrollRange() > computeVerticalScrollExtent(); 26339 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 26340 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 26341 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 26342 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 26343 26344 int newScrollX = scrollX + deltaX; 26345 if (!overScrollHorizontal) { 26346 maxOverScrollX = 0; 26347 } 26348 26349 int newScrollY = scrollY + deltaY; 26350 if (!overScrollVertical) { 26351 maxOverScrollY = 0; 26352 } 26353 26354 // Clamp values if at the limits and record 26355 final int left = -maxOverScrollX; 26356 final int right = maxOverScrollX + scrollRangeX; 26357 final int top = -maxOverScrollY; 26358 final int bottom = maxOverScrollY + scrollRangeY; 26359 26360 boolean clampedX = false; 26361 if (newScrollX > right) { 26362 newScrollX = right; 26363 clampedX = true; 26364 } else if (newScrollX < left) { 26365 newScrollX = left; 26366 clampedX = true; 26367 } 26368 26369 boolean clampedY = false; 26370 if (newScrollY > bottom) { 26371 newScrollY = bottom; 26372 clampedY = true; 26373 } else if (newScrollY < top) { 26374 newScrollY = top; 26375 clampedY = true; 26376 } 26377 26378 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 26379 26380 return clampedX || clampedY; 26381 } 26382 26383 /** 26384 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 26385 * respond to the results of an over-scroll operation. 26386 * 26387 * @param scrollX New X scroll value in pixels 26388 * @param scrollY New Y scroll value in pixels 26389 * @param clampedX True if scrollX was clamped to an over-scroll boundary 26390 * @param clampedY True if scrollY was clamped to an over-scroll boundary 26391 */ onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY)26392 protected void onOverScrolled(int scrollX, int scrollY, 26393 boolean clampedX, boolean clampedY) { 26394 // Intentionally empty. 26395 } 26396 26397 /** 26398 * Returns the over-scroll mode for this view. The result will be 26399 * one of {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 26400 * (allow over-scrolling only if the view content is larger than the container), 26401 * or {@link #OVER_SCROLL_NEVER}. 26402 * 26403 * @return This view's over-scroll mode. 26404 */ 26405 @InspectableProperty(enumMapping = { 26406 @EnumEntry(value = OVER_SCROLL_ALWAYS, name = "always"), 26407 @EnumEntry(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"), 26408 @EnumEntry(value = OVER_SCROLL_NEVER, name = "never") 26409 }) getOverScrollMode()26410 public int getOverScrollMode() { 26411 return mOverScrollMode; 26412 } 26413 26414 /** 26415 * Set the over-scroll mode for this view. Valid over-scroll modes are 26416 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 26417 * (allow over-scrolling only if the view content is larger than the container), 26418 * or {@link #OVER_SCROLL_NEVER}. 26419 * 26420 * Setting the over-scroll mode of a view will have an effect only if the 26421 * view is capable of scrolling. 26422 * 26423 * @param overScrollMode The new over-scroll mode for this view. 26424 */ setOverScrollMode(int overScrollMode)26425 public void setOverScrollMode(int overScrollMode) { 26426 if (overScrollMode != OVER_SCROLL_ALWAYS && 26427 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 26428 overScrollMode != OVER_SCROLL_NEVER) { 26429 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 26430 } 26431 mOverScrollMode = overScrollMode; 26432 } 26433 26434 /** 26435 * Enable or disable nested scrolling for this view. 26436 * 26437 * <p>If this property is set to true the view will be permitted to initiate nested 26438 * scrolling operations with a compatible parent view in the current hierarchy. If this 26439 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 26440 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 26441 * the nested scroll.</p> 26442 * 26443 * @param enabled true to enable nested scrolling, false to disable 26444 * 26445 * @see #isNestedScrollingEnabled() 26446 */ setNestedScrollingEnabled(boolean enabled)26447 public void setNestedScrollingEnabled(boolean enabled) { 26448 if (enabled) { 26449 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 26450 } else { 26451 stopNestedScroll(); 26452 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 26453 } 26454 } 26455 26456 /** 26457 * Returns true if nested scrolling is enabled for this view. 26458 * 26459 * <p>If nested scrolling is enabled and this View class implementation supports it, 26460 * this view will act as a nested scrolling child view when applicable, forwarding data 26461 * about the scroll operation in progress to a compatible and cooperating nested scrolling 26462 * parent.</p> 26463 * 26464 * @return true if nested scrolling is enabled 26465 * 26466 * @see #setNestedScrollingEnabled(boolean) 26467 */ 26468 @InspectableProperty isNestedScrollingEnabled()26469 public boolean isNestedScrollingEnabled() { 26470 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 26471 PFLAG3_NESTED_SCROLLING_ENABLED; 26472 } 26473 26474 /** 26475 * Begin a nestable scroll operation along the given axes. 26476 * 26477 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 26478 * 26479 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 26480 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 26481 * In the case of touch scrolling the nested scroll will be terminated automatically in 26482 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 26483 * In the event of programmatic scrolling the caller must explicitly call 26484 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 26485 * 26486 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 26487 * If it returns false the caller may ignore the rest of this contract until the next scroll. 26488 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 26489 * 26490 * <p>At each incremental step of the scroll the caller should invoke 26491 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 26492 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 26493 * parent at least partially consumed the scroll and the caller should adjust the amount it 26494 * scrolls by.</p> 26495 * 26496 * <p>After applying the remainder of the scroll delta the caller should invoke 26497 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 26498 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 26499 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 26500 * </p> 26501 * 26502 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 26503 * {@link #SCROLL_AXIS_VERTICAL}. 26504 * @return true if a cooperative parent was found and nested scrolling has been enabled for 26505 * the current gesture. 26506 * 26507 * @see #stopNestedScroll() 26508 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 26509 * @see #dispatchNestedScroll(int, int, int, int, int[]) 26510 */ startNestedScroll(int axes)26511 public boolean startNestedScroll(int axes) { 26512 if (hasNestedScrollingParent()) { 26513 // Already in progress 26514 return true; 26515 } 26516 if (isNestedScrollingEnabled()) { 26517 ViewParent p = getParent(); 26518 View child = this; 26519 while (p != null) { 26520 try { 26521 if (p.onStartNestedScroll(child, this, axes)) { 26522 mNestedScrollingParent = p; 26523 p.onNestedScrollAccepted(child, this, axes); 26524 return true; 26525 } 26526 } catch (AbstractMethodError e) { 26527 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 26528 "method onStartNestedScroll", e); 26529 // Allow the search upward to continue 26530 } 26531 if (p instanceof View) { 26532 child = (View) p; 26533 } 26534 p = p.getParent(); 26535 } 26536 } 26537 return false; 26538 } 26539 26540 /** 26541 * Stop a nested scroll in progress. 26542 * 26543 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 26544 * 26545 * @see #startNestedScroll(int) 26546 */ stopNestedScroll()26547 public void stopNestedScroll() { 26548 if (mNestedScrollingParent != null) { 26549 mNestedScrollingParent.onStopNestedScroll(this); 26550 mNestedScrollingParent = null; 26551 } 26552 } 26553 26554 /** 26555 * Returns true if this view has a nested scrolling parent. 26556 * 26557 * <p>The presence of a nested scrolling parent indicates that this view has initiated 26558 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 26559 * 26560 * @return whether this view has a nested scrolling parent 26561 */ hasNestedScrollingParent()26562 public boolean hasNestedScrollingParent() { 26563 return mNestedScrollingParent != null; 26564 } 26565 26566 /** 26567 * Dispatch one step of a nested scroll in progress. 26568 * 26569 * <p>Implementations of views that support nested scrolling should call this to report 26570 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 26571 * is not currently in progress or nested scrolling is not 26572 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 26573 * 26574 * <p>Compatible View implementations should also call 26575 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 26576 * consuming a component of the scroll event themselves.</p> 26577 * 26578 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 26579 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 26580 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 26581 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 26582 * @param offsetInWindow Optional. If not null, on return this will contain the offset 26583 * in local view coordinates of this view from before this operation 26584 * to after it completes. View implementations may use this to adjust 26585 * expected input coordinate tracking. 26586 * @return true if the event was dispatched, false if it could not be dispatched. 26587 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 26588 */ dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow)26589 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 26590 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 26591 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 26592 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 26593 int startX = 0; 26594 int startY = 0; 26595 if (offsetInWindow != null) { 26596 getLocationInWindow(offsetInWindow); 26597 startX = offsetInWindow[0]; 26598 startY = offsetInWindow[1]; 26599 } 26600 26601 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 26602 dxUnconsumed, dyUnconsumed); 26603 26604 if (offsetInWindow != null) { 26605 getLocationInWindow(offsetInWindow); 26606 offsetInWindow[0] -= startX; 26607 offsetInWindow[1] -= startY; 26608 } 26609 return true; 26610 } else if (offsetInWindow != null) { 26611 // No motion, no dispatch. Keep offsetInWindow up to date. 26612 offsetInWindow[0] = 0; 26613 offsetInWindow[1] = 0; 26614 } 26615 } 26616 return false; 26617 } 26618 26619 /** 26620 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 26621 * 26622 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 26623 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 26624 * scrolling operation to consume some or all of the scroll operation before the child view 26625 * consumes it.</p> 26626 * 26627 * @param dx Horizontal scroll distance in pixels 26628 * @param dy Vertical scroll distance in pixels 26629 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 26630 * and consumed[1] the consumed dy. 26631 * @param offsetInWindow Optional. If not null, on return this will contain the offset 26632 * in local view coordinates of this view from before this operation 26633 * to after it completes. View implementations may use this to adjust 26634 * expected input coordinate tracking. 26635 * @return true if the parent consumed some or all of the scroll delta 26636 * @see #dispatchNestedScroll(int, int, int, int, int[]) 26637 */ dispatchNestedPreScroll(int dx, int dy, @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow)26638 public boolean dispatchNestedPreScroll(int dx, int dy, 26639 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 26640 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 26641 if (dx != 0 || dy != 0) { 26642 int startX = 0; 26643 int startY = 0; 26644 if (offsetInWindow != null) { 26645 getLocationInWindow(offsetInWindow); 26646 startX = offsetInWindow[0]; 26647 startY = offsetInWindow[1]; 26648 } 26649 26650 if (consumed == null) { 26651 if (mTempNestedScrollConsumed == null) { 26652 mTempNestedScrollConsumed = new int[2]; 26653 } 26654 consumed = mTempNestedScrollConsumed; 26655 } 26656 consumed[0] = 0; 26657 consumed[1] = 0; 26658 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 26659 26660 if (offsetInWindow != null) { 26661 getLocationInWindow(offsetInWindow); 26662 offsetInWindow[0] -= startX; 26663 offsetInWindow[1] -= startY; 26664 } 26665 return consumed[0] != 0 || consumed[1] != 0; 26666 } else if (offsetInWindow != null) { 26667 offsetInWindow[0] = 0; 26668 offsetInWindow[1] = 0; 26669 } 26670 } 26671 return false; 26672 } 26673 26674 /** 26675 * Dispatch a fling to a nested scrolling parent. 26676 * 26677 * <p>This method should be used to indicate that a nested scrolling child has detected 26678 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 26679 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 26680 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 26681 * along a scrollable axis.</p> 26682 * 26683 * <p>If a nested scrolling child view would normally fling but it is at the edge of 26684 * its own content, it can use this method to delegate the fling to its nested scrolling 26685 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 26686 * 26687 * @param velocityX Horizontal fling velocity in pixels per second 26688 * @param velocityY Vertical fling velocity in pixels per second 26689 * @param consumed true if the child consumed the fling, false otherwise 26690 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 26691 */ dispatchNestedFling(float velocityX, float velocityY, boolean consumed)26692 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 26693 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 26694 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 26695 } 26696 return false; 26697 } 26698 26699 /** 26700 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 26701 * 26702 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 26703 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 26704 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 26705 * before the child view consumes it. If this method returns <code>true</code>, a nested 26706 * parent view consumed the fling and this view should not scroll as a result.</p> 26707 * 26708 * <p>For a better user experience, only one view in a nested scrolling chain should consume 26709 * the fling at a time. If a parent view consumed the fling this method will return false. 26710 * Custom view implementations should account for this in two ways:</p> 26711 * 26712 * <ul> 26713 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 26714 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 26715 * position regardless.</li> 26716 * <li>If a nested parent does consume the fling, this view should not scroll at all, 26717 * even to settle back to a valid idle position.</li> 26718 * </ul> 26719 * 26720 * <p>Views should also not offer fling velocities to nested parent views along an axis 26721 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 26722 * should not offer a horizontal fling velocity to its parents since scrolling along that 26723 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 26724 * 26725 * @param velocityX Horizontal fling velocity in pixels per second 26726 * @param velocityY Vertical fling velocity in pixels per second 26727 * @return true if a nested scrolling parent consumed the fling 26728 */ dispatchNestedPreFling(float velocityX, float velocityY)26729 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 26730 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 26731 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 26732 } 26733 return false; 26734 } 26735 26736 /** 26737 * Gets a scale factor that determines the distance the view should scroll 26738 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 26739 * @return The vertical scroll scale factor. 26740 * @hide 26741 */ 26742 @UnsupportedAppUsage getVerticalScrollFactor()26743 protected float getVerticalScrollFactor() { 26744 if (mVerticalScrollFactor == 0) { 26745 TypedValue outValue = new TypedValue(); 26746 if (!mContext.getTheme().resolveAttribute( 26747 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 26748 throw new IllegalStateException( 26749 "Expected theme to define listPreferredItemHeight."); 26750 } 26751 mVerticalScrollFactor = outValue.getDimension( 26752 mContext.getResources().getDisplayMetrics()); 26753 } 26754 return mVerticalScrollFactor; 26755 } 26756 26757 /** 26758 * Gets a scale factor that determines the distance the view should scroll 26759 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 26760 * @return The horizontal scroll scale factor. 26761 * @hide 26762 */ 26763 @UnsupportedAppUsage getHorizontalScrollFactor()26764 protected float getHorizontalScrollFactor() { 26765 // TODO: Should use something else. 26766 return getVerticalScrollFactor(); 26767 } 26768 26769 /** 26770 * Return the value specifying the text direction or policy that was set with 26771 * {@link #setTextDirection(int)}. 26772 * 26773 * @return the defined text direction. It can be one of: 26774 * 26775 * {@link #TEXT_DIRECTION_INHERIT}, 26776 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 26777 * {@link #TEXT_DIRECTION_ANY_RTL}, 26778 * {@link #TEXT_DIRECTION_LTR}, 26779 * {@link #TEXT_DIRECTION_RTL}, 26780 * {@link #TEXT_DIRECTION_LOCALE}, 26781 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 26782 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 26783 * 26784 * @attr ref android.R.styleable#View_textDirection 26785 * 26786 * @hide 26787 */ 26788 @ViewDebug.ExportedProperty(category = "text", mapping = { 26789 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 26790 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 26791 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 26792 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 26793 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 26794 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 26795 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 26796 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 26797 }) 26798 @InspectableProperty(hasAttributeId = false, enumMapping = { 26799 @EnumEntry(value = TEXT_DIRECTION_INHERIT, name = "inherit"), 26800 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 26801 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 26802 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 26803 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 26804 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 26805 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 26806 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 26807 }) 26808 @UnsupportedAppUsage getRawTextDirection()26809 public int getRawTextDirection() { 26810 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 26811 } 26812 26813 /** 26814 * Set the text direction. 26815 * 26816 * @param textDirection the direction to set. Should be one of: 26817 * 26818 * {@link #TEXT_DIRECTION_INHERIT}, 26819 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 26820 * {@link #TEXT_DIRECTION_ANY_RTL}, 26821 * {@link #TEXT_DIRECTION_LTR}, 26822 * {@link #TEXT_DIRECTION_RTL}, 26823 * {@link #TEXT_DIRECTION_LOCALE} 26824 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 26825 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 26826 * 26827 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 26828 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 26829 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 26830 * 26831 * @attr ref android.R.styleable#View_textDirection 26832 */ setTextDirection(int textDirection)26833 public void setTextDirection(int textDirection) { 26834 if (getRawTextDirection() != textDirection) { 26835 // Reset the current text direction and the resolved one 26836 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 26837 resetResolvedTextDirection(); 26838 // Set the new text direction 26839 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 26840 // Do resolution 26841 resolveTextDirection(); 26842 // Notify change 26843 onRtlPropertiesChanged(getLayoutDirection()); 26844 // Refresh 26845 requestLayout(); 26846 invalidate(true); 26847 } 26848 } 26849 26850 /** 26851 * Return the resolved text direction. 26852 * 26853 * @return the resolved text direction. Returns one of: 26854 * 26855 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 26856 * {@link #TEXT_DIRECTION_ANY_RTL}, 26857 * {@link #TEXT_DIRECTION_LTR}, 26858 * {@link #TEXT_DIRECTION_RTL}, 26859 * {@link #TEXT_DIRECTION_LOCALE}, 26860 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 26861 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 26862 * 26863 * @attr ref android.R.styleable#View_textDirection 26864 */ 26865 @ViewDebug.ExportedProperty(category = "text", mapping = { 26866 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 26867 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 26868 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 26869 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 26870 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 26871 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 26872 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 26873 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 26874 }) 26875 @InspectableProperty(hasAttributeId = false, enumMapping = { 26876 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 26877 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 26878 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 26879 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 26880 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 26881 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 26882 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 26883 }) getTextDirection()26884 public int getTextDirection() { 26885 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 26886 } 26887 26888 /** 26889 * Resolve the text direction. 26890 * 26891 * @return true if resolution has been done, false otherwise. 26892 * 26893 * @hide 26894 */ resolveTextDirection()26895 public boolean resolveTextDirection() { 26896 // Reset any previous text direction resolution 26897 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 26898 26899 if (hasRtlSupport()) { 26900 // Set resolved text direction flag depending on text direction flag 26901 final int textDirection = getRawTextDirection(); 26902 switch(textDirection) { 26903 case TEXT_DIRECTION_INHERIT: 26904 if (!canResolveTextDirection()) { 26905 // We cannot do the resolution if there is no parent, so use the default one 26906 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 26907 // Resolution will need to happen again later 26908 return false; 26909 } 26910 26911 // Parent has not yet resolved, so we still return the default 26912 try { 26913 if (!mParent.isTextDirectionResolved()) { 26914 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 26915 // Resolution will need to happen again later 26916 return false; 26917 } 26918 } catch (AbstractMethodError e) { 26919 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 26920 " does not fully implement ViewParent", e); 26921 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 26922 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 26923 return true; 26924 } 26925 26926 // Set current resolved direction to the same value as the parent's one 26927 int parentResolvedDirection; 26928 try { 26929 parentResolvedDirection = mParent.getTextDirection(); 26930 } catch (AbstractMethodError e) { 26931 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 26932 " does not fully implement ViewParent", e); 26933 parentResolvedDirection = TEXT_DIRECTION_LTR; 26934 } 26935 switch (parentResolvedDirection) { 26936 case TEXT_DIRECTION_FIRST_STRONG: 26937 case TEXT_DIRECTION_ANY_RTL: 26938 case TEXT_DIRECTION_LTR: 26939 case TEXT_DIRECTION_RTL: 26940 case TEXT_DIRECTION_LOCALE: 26941 case TEXT_DIRECTION_FIRST_STRONG_LTR: 26942 case TEXT_DIRECTION_FIRST_STRONG_RTL: 26943 mPrivateFlags2 |= 26944 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 26945 break; 26946 default: 26947 // Default resolved direction is "first strong" heuristic 26948 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 26949 } 26950 break; 26951 case TEXT_DIRECTION_FIRST_STRONG: 26952 case TEXT_DIRECTION_ANY_RTL: 26953 case TEXT_DIRECTION_LTR: 26954 case TEXT_DIRECTION_RTL: 26955 case TEXT_DIRECTION_LOCALE: 26956 case TEXT_DIRECTION_FIRST_STRONG_LTR: 26957 case TEXT_DIRECTION_FIRST_STRONG_RTL: 26958 // Resolved direction is the same as text direction 26959 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 26960 break; 26961 default: 26962 // Default resolved direction is "first strong" heuristic 26963 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 26964 } 26965 } else { 26966 // Default resolved direction is "first strong" heuristic 26967 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 26968 } 26969 26970 // Set to resolved 26971 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 26972 return true; 26973 } 26974 26975 /** 26976 * Check if text direction resolution can be done. 26977 * 26978 * @return true if text direction resolution can be done otherwise return false. 26979 */ canResolveTextDirection()26980 public boolean canResolveTextDirection() { 26981 switch (getRawTextDirection()) { 26982 case TEXT_DIRECTION_INHERIT: 26983 if (mParent != null) { 26984 try { 26985 return mParent.canResolveTextDirection(); 26986 } catch (AbstractMethodError e) { 26987 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 26988 " does not fully implement ViewParent", e); 26989 } 26990 } 26991 return false; 26992 26993 default: 26994 return true; 26995 } 26996 } 26997 26998 /** 26999 * Reset resolved text direction. Text direction will be resolved during a call to 27000 * {@link #onMeasure(int, int)}. 27001 * 27002 * @hide 27003 */ 27004 @TestApi resetResolvedTextDirection()27005 public void resetResolvedTextDirection() { 27006 // Reset any previous text direction resolution 27007 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 27008 // Set to default value 27009 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27010 } 27011 27012 /** 27013 * @return true if text direction is inherited. 27014 * 27015 * @hide 27016 */ isTextDirectionInherited()27017 public boolean isTextDirectionInherited() { 27018 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 27019 } 27020 27021 /** 27022 * @return true if text direction is resolved. 27023 */ isTextDirectionResolved()27024 public boolean isTextDirectionResolved() { 27025 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 27026 } 27027 27028 /** 27029 * Return the value specifying the text alignment or policy that was set with 27030 * {@link #setTextAlignment(int)}. 27031 * 27032 * @return the defined text alignment. It can be one of: 27033 * 27034 * {@link #TEXT_ALIGNMENT_INHERIT}, 27035 * {@link #TEXT_ALIGNMENT_GRAVITY}, 27036 * {@link #TEXT_ALIGNMENT_CENTER}, 27037 * {@link #TEXT_ALIGNMENT_TEXT_START}, 27038 * {@link #TEXT_ALIGNMENT_TEXT_END}, 27039 * {@link #TEXT_ALIGNMENT_VIEW_START}, 27040 * {@link #TEXT_ALIGNMENT_VIEW_END} 27041 * 27042 * @attr ref android.R.styleable#View_textAlignment 27043 * 27044 * @hide 27045 */ 27046 @ViewDebug.ExportedProperty(category = "text", mapping = { 27047 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 27048 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 27049 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 27050 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 27051 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 27052 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 27053 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 27054 }) 27055 @InspectableProperty(hasAttributeId = false, enumMapping = { 27056 @EnumEntry(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"), 27057 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 27058 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 27059 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 27060 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 27061 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 27062 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 27063 }) 27064 @TextAlignment 27065 @UnsupportedAppUsage getRawTextAlignment()27066 public int getRawTextAlignment() { 27067 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 27068 } 27069 27070 /** 27071 * Set the text alignment. 27072 * 27073 * @param textAlignment The text alignment to set. Should be one of 27074 * 27075 * {@link #TEXT_ALIGNMENT_INHERIT}, 27076 * {@link #TEXT_ALIGNMENT_GRAVITY}, 27077 * {@link #TEXT_ALIGNMENT_CENTER}, 27078 * {@link #TEXT_ALIGNMENT_TEXT_START}, 27079 * {@link #TEXT_ALIGNMENT_TEXT_END}, 27080 * {@link #TEXT_ALIGNMENT_VIEW_START}, 27081 * {@link #TEXT_ALIGNMENT_VIEW_END} 27082 * 27083 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 27084 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 27085 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 27086 * 27087 * @attr ref android.R.styleable#View_textAlignment 27088 */ setTextAlignment(@extAlignment int textAlignment)27089 public void setTextAlignment(@TextAlignment int textAlignment) { 27090 if (textAlignment != getRawTextAlignment()) { 27091 // Reset the current and resolved text alignment 27092 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 27093 resetResolvedTextAlignment(); 27094 // Set the new text alignment 27095 mPrivateFlags2 |= 27096 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 27097 // Do resolution 27098 resolveTextAlignment(); 27099 // Notify change 27100 onRtlPropertiesChanged(getLayoutDirection()); 27101 // Refresh 27102 requestLayout(); 27103 invalidate(true); 27104 } 27105 } 27106 27107 /** 27108 * Return the resolved text alignment. 27109 * 27110 * @return the resolved text alignment. Returns one of: 27111 * 27112 * {@link #TEXT_ALIGNMENT_GRAVITY}, 27113 * {@link #TEXT_ALIGNMENT_CENTER}, 27114 * {@link #TEXT_ALIGNMENT_TEXT_START}, 27115 * {@link #TEXT_ALIGNMENT_TEXT_END}, 27116 * {@link #TEXT_ALIGNMENT_VIEW_START}, 27117 * {@link #TEXT_ALIGNMENT_VIEW_END} 27118 * 27119 * @attr ref android.R.styleable#View_textAlignment 27120 */ 27121 @ViewDebug.ExportedProperty(category = "text", mapping = { 27122 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 27123 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 27124 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 27125 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 27126 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 27127 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 27128 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 27129 }) 27130 @InspectableProperty(enumMapping = { 27131 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 27132 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 27133 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 27134 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 27135 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 27136 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 27137 }) 27138 @TextAlignment getTextAlignment()27139 public int getTextAlignment() { 27140 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 27141 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 27142 } 27143 27144 /** 27145 * Resolve the text alignment. 27146 * 27147 * @return true if resolution has been done, false otherwise. 27148 * 27149 * @hide 27150 */ resolveTextAlignment()27151 public boolean resolveTextAlignment() { 27152 // Reset any previous text alignment resolution 27153 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 27154 27155 if (hasRtlSupport()) { 27156 // Set resolved text alignment flag depending on text alignment flag 27157 final int textAlignment = getRawTextAlignment(); 27158 switch (textAlignment) { 27159 case TEXT_ALIGNMENT_INHERIT: 27160 // Check if we can resolve the text alignment 27161 if (!canResolveTextAlignment()) { 27162 // We cannot do the resolution if there is no parent so use the default 27163 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27164 // Resolution will need to happen again later 27165 return false; 27166 } 27167 27168 // Parent has not yet resolved, so we still return the default 27169 try { 27170 if (!mParent.isTextAlignmentResolved()) { 27171 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27172 // Resolution will need to happen again later 27173 return false; 27174 } 27175 } catch (AbstractMethodError e) { 27176 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27177 " does not fully implement ViewParent", e); 27178 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 27179 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27180 return true; 27181 } 27182 27183 int parentResolvedTextAlignment; 27184 try { 27185 parentResolvedTextAlignment = mParent.getTextAlignment(); 27186 } catch (AbstractMethodError e) { 27187 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27188 " does not fully implement ViewParent", e); 27189 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 27190 } 27191 switch (parentResolvedTextAlignment) { 27192 case TEXT_ALIGNMENT_GRAVITY: 27193 case TEXT_ALIGNMENT_TEXT_START: 27194 case TEXT_ALIGNMENT_TEXT_END: 27195 case TEXT_ALIGNMENT_CENTER: 27196 case TEXT_ALIGNMENT_VIEW_START: 27197 case TEXT_ALIGNMENT_VIEW_END: 27198 // Resolved text alignment is the same as the parent resolved 27199 // text alignment 27200 mPrivateFlags2 |= 27201 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 27202 break; 27203 default: 27204 // Use default resolved text alignment 27205 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27206 } 27207 break; 27208 case TEXT_ALIGNMENT_GRAVITY: 27209 case TEXT_ALIGNMENT_TEXT_START: 27210 case TEXT_ALIGNMENT_TEXT_END: 27211 case TEXT_ALIGNMENT_CENTER: 27212 case TEXT_ALIGNMENT_VIEW_START: 27213 case TEXT_ALIGNMENT_VIEW_END: 27214 // Resolved text alignment is the same as text alignment 27215 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 27216 break; 27217 default: 27218 // Use default resolved text alignment 27219 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27220 } 27221 } else { 27222 // Use default resolved text alignment 27223 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27224 } 27225 27226 // Set the resolved 27227 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 27228 return true; 27229 } 27230 27231 /** 27232 * Check if text alignment resolution can be done. 27233 * 27234 * @return true if text alignment resolution can be done otherwise return false. 27235 */ canResolveTextAlignment()27236 public boolean canResolveTextAlignment() { 27237 switch (getRawTextAlignment()) { 27238 case TEXT_DIRECTION_INHERIT: 27239 if (mParent != null) { 27240 try { 27241 return mParent.canResolveTextAlignment(); 27242 } catch (AbstractMethodError e) { 27243 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27244 " does not fully implement ViewParent", e); 27245 } 27246 } 27247 return false; 27248 27249 default: 27250 return true; 27251 } 27252 } 27253 27254 /** 27255 * Reset resolved text alignment. Text alignment will be resolved during a call to 27256 * {@link #onMeasure(int, int)}. 27257 * 27258 * @hide 27259 */ 27260 @TestApi resetResolvedTextAlignment()27261 public void resetResolvedTextAlignment() { 27262 // Reset any previous text alignment resolution 27263 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 27264 // Set to default 27265 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27266 } 27267 27268 /** 27269 * @return true if text alignment is inherited. 27270 * 27271 * @hide 27272 */ isTextAlignmentInherited()27273 public boolean isTextAlignmentInherited() { 27274 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 27275 } 27276 27277 /** 27278 * @return true if text alignment is resolved. 27279 */ isTextAlignmentResolved()27280 public boolean isTextAlignmentResolved() { 27281 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 27282 } 27283 27284 /** 27285 * Generate a value suitable for use in {@link #setId(int)}. 27286 * This value will not collide with ID values generated at build time by aapt for R.id. 27287 * 27288 * @return a generated ID value 27289 */ generateViewId()27290 public static int generateViewId() { 27291 for (;;) { 27292 final int result = sNextGeneratedId.get(); 27293 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 27294 int newValue = result + 1; 27295 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 27296 if (sNextGeneratedId.compareAndSet(result, newValue)) { 27297 return result; 27298 } 27299 } 27300 } 27301 isViewIdGenerated(int id)27302 private static boolean isViewIdGenerated(int id) { 27303 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 27304 } 27305 27306 /** 27307 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 27308 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 27309 * a normal View or a ViewGroup with 27310 * {@link android.view.ViewGroup#isTransitionGroup()} true. 27311 * @hide 27312 */ captureTransitioningViews(List<View> transitioningViews)27313 public void captureTransitioningViews(List<View> transitioningViews) { 27314 if (getVisibility() == View.VISIBLE) { 27315 transitioningViews.add(this); 27316 } 27317 } 27318 27319 /** 27320 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 27321 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 27322 * @hide 27323 */ findNamedViews(Map<String, View> namedElements)27324 public void findNamedViews(Map<String, View> namedElements) { 27325 if (getVisibility() == VISIBLE || mGhostView != null) { 27326 String transitionName = getTransitionName(); 27327 if (transitionName != null) { 27328 namedElements.put(transitionName, this); 27329 } 27330 } 27331 } 27332 27333 /** 27334 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 27335 * The default implementation does not care the location or event types, but some subclasses 27336 * may use it (such as WebViews). 27337 * @param event The MotionEvent from a mouse 27338 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 27339 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 27340 * @see PointerIcon 27341 */ onResolvePointerIcon(MotionEvent event, int pointerIndex)27342 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 27343 final float x = event.getX(pointerIndex); 27344 final float y = event.getY(pointerIndex); 27345 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 27346 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 27347 } 27348 return mPointerIcon; 27349 } 27350 27351 /** 27352 * Set the pointer icon for the current view. 27353 * Passing {@code null} will restore the pointer icon to its default value. 27354 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 27355 */ setPointerIcon(PointerIcon pointerIcon)27356 public void setPointerIcon(PointerIcon pointerIcon) { 27357 mPointerIcon = pointerIcon; 27358 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 27359 return; 27360 } 27361 try { 27362 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 27363 } catch (RemoteException e) { 27364 } 27365 } 27366 27367 /** 27368 * Gets the pointer icon for the current view. 27369 */ 27370 @InspectableProperty getPointerIcon()27371 public PointerIcon getPointerIcon() { 27372 return mPointerIcon; 27373 } 27374 27375 /** 27376 * Checks pointer capture status. 27377 * 27378 * @return true if the view has pointer capture. 27379 * @see #requestPointerCapture() 27380 * @see #hasPointerCapture() 27381 */ hasPointerCapture()27382 public boolean hasPointerCapture() { 27383 final ViewRootImpl viewRootImpl = getViewRootImpl(); 27384 if (viewRootImpl == null) { 27385 return false; 27386 } 27387 return viewRootImpl.hasPointerCapture(); 27388 } 27389 27390 /** 27391 * Requests pointer capture mode. 27392 * <p> 27393 * When the window has pointer capture, the mouse pointer icon will disappear and will not 27394 * change its position. Further mouse will be dispatched with the source 27395 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be available 27396 * through {@link MotionEvent#getX} and {@link MotionEvent#getY}. Non-mouse events 27397 * (touchscreens, or stylus) will not be affected. 27398 * <p> 27399 * If the window already has pointer capture, this call does nothing. 27400 * <p> 27401 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 27402 * automatically when the window loses focus. 27403 * 27404 * @see #releasePointerCapture() 27405 * @see #hasPointerCapture() 27406 */ requestPointerCapture()27407 public void requestPointerCapture() { 27408 final ViewRootImpl viewRootImpl = getViewRootImpl(); 27409 if (viewRootImpl != null) { 27410 viewRootImpl.requestPointerCapture(true); 27411 } 27412 } 27413 27414 27415 /** 27416 * Releases the pointer capture. 27417 * <p> 27418 * If the window does not have pointer capture, this call will do nothing. 27419 * @see #requestPointerCapture() 27420 * @see #hasPointerCapture() 27421 */ releasePointerCapture()27422 public void releasePointerCapture() { 27423 final ViewRootImpl viewRootImpl = getViewRootImpl(); 27424 if (viewRootImpl != null) { 27425 viewRootImpl.requestPointerCapture(false); 27426 } 27427 } 27428 27429 /** 27430 * Called when the window has just acquired or lost pointer capture. 27431 * 27432 * @param hasCapture True if the view now has pointerCapture, false otherwise. 27433 */ 27434 @CallSuper onPointerCaptureChange(boolean hasCapture)27435 public void onPointerCaptureChange(boolean hasCapture) { 27436 } 27437 27438 /** 27439 * @see #onPointerCaptureChange 27440 */ dispatchPointerCaptureChanged(boolean hasCapture)27441 public void dispatchPointerCaptureChanged(boolean hasCapture) { 27442 onPointerCaptureChange(hasCapture); 27443 } 27444 27445 /** 27446 * Implement this method to handle captured pointer events 27447 * 27448 * @param event The captured pointer event. 27449 * @return True if the event was handled, false otherwise. 27450 * @see #requestPointerCapture() 27451 */ onCapturedPointerEvent(MotionEvent event)27452 public boolean onCapturedPointerEvent(MotionEvent event) { 27453 return false; 27454 } 27455 27456 /** 27457 * Interface definition for a callback to be invoked when a captured pointer event 27458 * is being dispatched this view. The callback will be invoked before the event is 27459 * given to the view. 27460 */ 27461 public interface OnCapturedPointerListener { 27462 /** 27463 * Called when a captured pointer event is dispatched to a view. 27464 * @param view The view this event has been dispatched to. 27465 * @param event The captured event. 27466 * @return True if the listener has consumed the event, false otherwise. 27467 */ onCapturedPointer(View view, MotionEvent event)27468 boolean onCapturedPointer(View view, MotionEvent event); 27469 } 27470 27471 /** 27472 * Set a listener to receive callbacks when the pointer capture state of a view changes. 27473 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 27474 */ setOnCapturedPointerListener(OnCapturedPointerListener l)27475 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 27476 getListenerInfo().mOnCapturedPointerListener = l; 27477 } 27478 27479 // Properties 27480 // 27481 /** 27482 * A Property wrapper around the <code>alpha</code> functionality handled by the 27483 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 27484 */ 27485 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 27486 @Override 27487 public void setValue(View object, float value) { 27488 object.setAlpha(value); 27489 } 27490 27491 @Override 27492 public Float get(View object) { 27493 return object.getAlpha(); 27494 } 27495 }; 27496 27497 /** 27498 * A Property wrapper around the <code>translationX</code> functionality handled by the 27499 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 27500 */ 27501 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 27502 @Override 27503 public void setValue(View object, float value) { 27504 object.setTranslationX(value); 27505 } 27506 27507 @Override 27508 public Float get(View object) { 27509 return object.getTranslationX(); 27510 } 27511 }; 27512 27513 /** 27514 * A Property wrapper around the <code>translationY</code> functionality handled by the 27515 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 27516 */ 27517 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 27518 @Override 27519 public void setValue(View object, float value) { 27520 object.setTranslationY(value); 27521 } 27522 27523 @Override 27524 public Float get(View object) { 27525 return object.getTranslationY(); 27526 } 27527 }; 27528 27529 /** 27530 * A Property wrapper around the <code>translationZ</code> functionality handled by the 27531 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 27532 */ 27533 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 27534 @Override 27535 public void setValue(View object, float value) { 27536 object.setTranslationZ(value); 27537 } 27538 27539 @Override 27540 public Float get(View object) { 27541 return object.getTranslationZ(); 27542 } 27543 }; 27544 27545 /** 27546 * A Property wrapper around the <code>x</code> functionality handled by the 27547 * {@link View#setX(float)} and {@link View#getX()} methods. 27548 */ 27549 public static final Property<View, Float> X = new FloatProperty<View>("x") { 27550 @Override 27551 public void setValue(View object, float value) { 27552 object.setX(value); 27553 } 27554 27555 @Override 27556 public Float get(View object) { 27557 return object.getX(); 27558 } 27559 }; 27560 27561 /** 27562 * A Property wrapper around the <code>y</code> functionality handled by the 27563 * {@link View#setY(float)} and {@link View#getY()} methods. 27564 */ 27565 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 27566 @Override 27567 public void setValue(View object, float value) { 27568 object.setY(value); 27569 } 27570 27571 @Override 27572 public Float get(View object) { 27573 return object.getY(); 27574 } 27575 }; 27576 27577 /** 27578 * A Property wrapper around the <code>z</code> functionality handled by the 27579 * {@link View#setZ(float)} and {@link View#getZ()} methods. 27580 */ 27581 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 27582 @Override 27583 public void setValue(View object, float value) { 27584 object.setZ(value); 27585 } 27586 27587 @Override 27588 public Float get(View object) { 27589 return object.getZ(); 27590 } 27591 }; 27592 27593 /** 27594 * A Property wrapper around the <code>rotation</code> functionality handled by the 27595 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 27596 */ 27597 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 27598 @Override 27599 public void setValue(View object, float value) { 27600 object.setRotation(value); 27601 } 27602 27603 @Override 27604 public Float get(View object) { 27605 return object.getRotation(); 27606 } 27607 }; 27608 27609 /** 27610 * A Property wrapper around the <code>rotationX</code> functionality handled by the 27611 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 27612 */ 27613 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 27614 @Override 27615 public void setValue(View object, float value) { 27616 object.setRotationX(value); 27617 } 27618 27619 @Override 27620 public Float get(View object) { 27621 return object.getRotationX(); 27622 } 27623 }; 27624 27625 /** 27626 * A Property wrapper around the <code>rotationY</code> functionality handled by the 27627 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 27628 */ 27629 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 27630 @Override 27631 public void setValue(View object, float value) { 27632 object.setRotationY(value); 27633 } 27634 27635 @Override 27636 public Float get(View object) { 27637 return object.getRotationY(); 27638 } 27639 }; 27640 27641 /** 27642 * A Property wrapper around the <code>scaleX</code> functionality handled by the 27643 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 27644 */ 27645 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 27646 @Override 27647 public void setValue(View object, float value) { 27648 object.setScaleX(value); 27649 } 27650 27651 @Override 27652 public Float get(View object) { 27653 return object.getScaleX(); 27654 } 27655 }; 27656 27657 /** 27658 * A Property wrapper around the <code>scaleY</code> functionality handled by the 27659 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 27660 */ 27661 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 27662 @Override 27663 public void setValue(View object, float value) { 27664 object.setScaleY(value); 27665 } 27666 27667 @Override 27668 public Float get(View object) { 27669 return object.getScaleY(); 27670 } 27671 }; 27672 27673 /** 27674 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 27675 * Each MeasureSpec represents a requirement for either the width or the height. 27676 * A MeasureSpec is comprised of a size and a mode. There are three possible 27677 * modes: 27678 * <dl> 27679 * <dt>UNSPECIFIED</dt> 27680 * <dd> 27681 * The parent has not imposed any constraint on the child. It can be whatever size 27682 * it wants. 27683 * </dd> 27684 * 27685 * <dt>EXACTLY</dt> 27686 * <dd> 27687 * The parent has determined an exact size for the child. The child is going to be 27688 * given those bounds regardless of how big it wants to be. 27689 * </dd> 27690 * 27691 * <dt>AT_MOST</dt> 27692 * <dd> 27693 * The child can be as large as it wants up to the specified size. 27694 * </dd> 27695 * </dl> 27696 * 27697 * MeasureSpecs are implemented as ints to reduce object allocation. This class 27698 * is provided to pack and unpack the <size, mode> tuple into the int. 27699 */ 27700 public static class MeasureSpec { 27701 private static final int MODE_SHIFT = 30; 27702 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 27703 27704 /** @hide */ 27705 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 27706 @Retention(RetentionPolicy.SOURCE) 27707 public @interface MeasureSpecMode {} 27708 27709 /** 27710 * Measure specification mode: The parent has not imposed any constraint 27711 * on the child. It can be whatever size it wants. 27712 */ 27713 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 27714 27715 /** 27716 * Measure specification mode: The parent has determined an exact size 27717 * for the child. The child is going to be given those bounds regardless 27718 * of how big it wants to be. 27719 */ 27720 public static final int EXACTLY = 1 << MODE_SHIFT; 27721 27722 /** 27723 * Measure specification mode: The child can be as large as it wants up 27724 * to the specified size. 27725 */ 27726 public static final int AT_MOST = 2 << MODE_SHIFT; 27727 27728 /** 27729 * Creates a measure specification based on the supplied size and mode. 27730 * 27731 * The mode must always be one of the following: 27732 * <ul> 27733 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 27734 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 27735 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 27736 * </ul> 27737 * 27738 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 27739 * implementation was such that the order of arguments did not matter 27740 * and overflow in either value could impact the resulting MeasureSpec. 27741 * {@link android.widget.RelativeLayout} was affected by this bug. 27742 * Apps targeting API levels greater than 17 will get the fixed, more strict 27743 * behavior.</p> 27744 * 27745 * @param size the size of the measure specification 27746 * @param mode the mode of the measure specification 27747 * @return the measure specification based on size and mode 27748 */ makeMeasureSpec(@ntRangefrom = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode)27749 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 27750 @MeasureSpecMode int mode) { 27751 if (sUseBrokenMakeMeasureSpec) { 27752 return size + mode; 27753 } else { 27754 return (size & ~MODE_MASK) | (mode & MODE_MASK); 27755 } 27756 } 27757 27758 /** 27759 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 27760 * will automatically get a size of 0. Older apps expect this. 27761 * 27762 * @hide internal use only for compatibility with system widgets and older apps 27763 */ 27764 @UnsupportedAppUsage makeSafeMeasureSpec(int size, int mode)27765 public static int makeSafeMeasureSpec(int size, int mode) { 27766 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 27767 return 0; 27768 } 27769 return makeMeasureSpec(size, mode); 27770 } 27771 27772 /** 27773 * Extracts the mode from the supplied measure specification. 27774 * 27775 * @param measureSpec the measure specification to extract the mode from 27776 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 27777 * {@link android.view.View.MeasureSpec#AT_MOST} or 27778 * {@link android.view.View.MeasureSpec#EXACTLY} 27779 */ 27780 @MeasureSpecMode getMode(int measureSpec)27781 public static int getMode(int measureSpec) { 27782 //noinspection ResourceType 27783 return (measureSpec & MODE_MASK); 27784 } 27785 27786 /** 27787 * Extracts the size from the supplied measure specification. 27788 * 27789 * @param measureSpec the measure specification to extract the size from 27790 * @return the size in pixels defined in the supplied measure specification 27791 */ getSize(int measureSpec)27792 public static int getSize(int measureSpec) { 27793 return (measureSpec & ~MODE_MASK); 27794 } 27795 adjust(int measureSpec, int delta)27796 static int adjust(int measureSpec, int delta) { 27797 final int mode = getMode(measureSpec); 27798 int size = getSize(measureSpec); 27799 if (mode == UNSPECIFIED) { 27800 // No need to adjust size for UNSPECIFIED mode. 27801 return makeMeasureSpec(size, UNSPECIFIED); 27802 } 27803 size += delta; 27804 if (size < 0) { 27805 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 27806 ") spec: " + toString(measureSpec) + " delta: " + delta); 27807 size = 0; 27808 } 27809 return makeMeasureSpec(size, mode); 27810 } 27811 27812 /** 27813 * Returns a String representation of the specified measure 27814 * specification. 27815 * 27816 * @param measureSpec the measure specification to convert to a String 27817 * @return a String with the following format: "MeasureSpec: MODE SIZE" 27818 */ toString(int measureSpec)27819 public static String toString(int measureSpec) { 27820 int mode = getMode(measureSpec); 27821 int size = getSize(measureSpec); 27822 27823 StringBuilder sb = new StringBuilder("MeasureSpec: "); 27824 27825 if (mode == UNSPECIFIED) 27826 sb.append("UNSPECIFIED "); 27827 else if (mode == EXACTLY) 27828 sb.append("EXACTLY "); 27829 else if (mode == AT_MOST) 27830 sb.append("AT_MOST "); 27831 else 27832 sb.append(mode).append(" "); 27833 27834 sb.append(size); 27835 return sb.toString(); 27836 } 27837 } 27838 27839 private final class CheckForLongPress implements Runnable { 27840 private int mOriginalWindowAttachCount; 27841 private float mX; 27842 private float mY; 27843 private boolean mOriginalPressedState; 27844 /** 27845 * The classification of the long click being checked: one of the 27846 * StatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__* constants. 27847 */ 27848 private int mClassification; 27849 27850 @UnsupportedAppUsage CheckForLongPress()27851 private CheckForLongPress() { 27852 } 27853 27854 @Override run()27855 public void run() { 27856 if ((mOriginalPressedState == isPressed()) && (mParent != null) 27857 && mOriginalWindowAttachCount == mWindowAttachCount) { 27858 recordGestureClassification(mClassification); 27859 if (performLongClick(mX, mY)) { 27860 mHasPerformedLongPress = true; 27861 } 27862 } 27863 } 27864 setAnchor(float x, float y)27865 public void setAnchor(float x, float y) { 27866 mX = x; 27867 mY = y; 27868 } 27869 rememberWindowAttachCount()27870 public void rememberWindowAttachCount() { 27871 mOriginalWindowAttachCount = mWindowAttachCount; 27872 } 27873 rememberPressedState()27874 public void rememberPressedState() { 27875 mOriginalPressedState = isPressed(); 27876 } 27877 setClassification(int classification)27878 public void setClassification(int classification) { 27879 mClassification = classification; 27880 } 27881 } 27882 27883 private final class CheckForTap implements Runnable { 27884 public float x; 27885 public float y; 27886 27887 @Override run()27888 public void run() { 27889 mPrivateFlags &= ~PFLAG_PREPRESSED; 27890 setPressed(true, x, y); 27891 final long delay = 27892 ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout(); 27893 checkForLongClick(delay, x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 27894 } 27895 } 27896 27897 private final class PerformClick implements Runnable { 27898 @Override run()27899 public void run() { 27900 recordGestureClassification(TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP); 27901 performClickInternal(); 27902 } 27903 } 27904 27905 /** Records a classification for the current event stream. */ recordGestureClassification(int classification)27906 private void recordGestureClassification(int classification) { 27907 if (classification == TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION) { 27908 return; 27909 } 27910 // To avoid negatively impacting View performance, the latency and displacement metrics 27911 // are omitted. 27912 StatsLog.write(StatsLog.TOUCH_GESTURE_CLASSIFIED, getClass().getName(), classification); 27913 } 27914 27915 /** 27916 * This method returns a ViewPropertyAnimator object, which can be used to animate 27917 * specific properties on this View. 27918 * 27919 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 27920 */ animate()27921 public ViewPropertyAnimator animate() { 27922 if (mAnimator == null) { 27923 mAnimator = new ViewPropertyAnimator(this); 27924 } 27925 return mAnimator; 27926 } 27927 27928 /** 27929 * Sets the name of the View to be used to identify Views in Transitions. 27930 * Names should be unique in the View hierarchy. 27931 * 27932 * @param transitionName The name of the View to uniquely identify it for Transitions. 27933 */ setTransitionName(String transitionName)27934 public final void setTransitionName(String transitionName) { 27935 mTransitionName = transitionName; 27936 } 27937 27938 /** 27939 * Returns the name of the View to be used to identify Views in Transitions. 27940 * Names should be unique in the View hierarchy. 27941 * 27942 * <p>This returns null if the View has not been given a name.</p> 27943 * 27944 * @return The name used of the View to be used to identify Views in Transitions or null 27945 * if no name has been given. 27946 */ 27947 @ViewDebug.ExportedProperty 27948 @InspectableProperty getTransitionName()27949 public String getTransitionName() { 27950 return mTransitionName; 27951 } 27952 27953 /** 27954 * @hide 27955 */ requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId)27956 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 27957 // Do nothing. 27958 } 27959 27960 /** 27961 * Interface definition for a callback to be invoked when a hardware key event is 27962 * dispatched to this view. The callback will be invoked before the key event is 27963 * given to the view. This is only useful for hardware keyboards; a software input 27964 * method has no obligation to trigger this listener. 27965 */ 27966 public interface OnKeyListener { 27967 /** 27968 * Called when a hardware key is dispatched to a view. This allows listeners to 27969 * get a chance to respond before the target view. 27970 * <p>Key presses in software keyboards will generally NOT trigger this method, 27971 * although some may elect to do so in some situations. Do not assume a 27972 * software input method has to be key-based; even if it is, it may use key presses 27973 * in a different way than you expect, so there is no way to reliably catch soft 27974 * input key presses. 27975 * 27976 * @param v The view the key has been dispatched to. 27977 * @param keyCode The code for the physical key that was pressed 27978 * @param event The KeyEvent object containing full information about 27979 * the event. 27980 * @return True if the listener has consumed the event, false otherwise. 27981 */ onKey(View v, int keyCode, KeyEvent event)27982 boolean onKey(View v, int keyCode, KeyEvent event); 27983 } 27984 27985 /** 27986 * Interface definition for a callback to be invoked when a hardware key event hasn't 27987 * been handled by the view hierarchy. 27988 */ 27989 public interface OnUnhandledKeyEventListener { 27990 /** 27991 * Called when a hardware key is dispatched to a view after being unhandled during normal 27992 * {@link KeyEvent} dispatch. 27993 * 27994 * @param v The view the key has been dispatched to. 27995 * @param event The KeyEvent object containing information about the event. 27996 * @return {@code true} if the listener has consumed the event, {@code false} otherwise. 27997 */ onUnhandledKeyEvent(View v, KeyEvent event)27998 boolean onUnhandledKeyEvent(View v, KeyEvent event); 27999 } 28000 28001 /** 28002 * Interface definition for a callback to be invoked when a touch event is 28003 * dispatched to this view. The callback will be invoked before the touch 28004 * event is given to the view. 28005 */ 28006 public interface OnTouchListener { 28007 /** 28008 * Called when a touch event is dispatched to a view. This allows listeners to 28009 * get a chance to respond before the target view. 28010 * 28011 * @param v The view the touch event has been dispatched to. 28012 * @param event The MotionEvent object containing full information about 28013 * the event. 28014 * @return True if the listener has consumed the event, false otherwise. 28015 */ onTouch(View v, MotionEvent event)28016 boolean onTouch(View v, MotionEvent event); 28017 } 28018 28019 /** 28020 * Interface definition for a callback to be invoked when a hover event is 28021 * dispatched to this view. The callback will be invoked before the hover 28022 * event is given to the view. 28023 */ 28024 public interface OnHoverListener { 28025 /** 28026 * Called when a hover event is dispatched to a view. This allows listeners to 28027 * get a chance to respond before the target view. 28028 * 28029 * @param v The view the hover event has been dispatched to. 28030 * @param event The MotionEvent object containing full information about 28031 * the event. 28032 * @return True if the listener has consumed the event, false otherwise. 28033 */ onHover(View v, MotionEvent event)28034 boolean onHover(View v, MotionEvent event); 28035 } 28036 28037 /** 28038 * Interface definition for a callback to be invoked when a generic motion event is 28039 * dispatched to this view. The callback will be invoked before the generic motion 28040 * event is given to the view. 28041 */ 28042 public interface OnGenericMotionListener { 28043 /** 28044 * Called when a generic motion event is dispatched to a view. This allows listeners to 28045 * get a chance to respond before the target view. 28046 * 28047 * @param v The view the generic motion event has been dispatched to. 28048 * @param event The MotionEvent object containing full information about 28049 * the event. 28050 * @return True if the listener has consumed the event, false otherwise. 28051 */ onGenericMotion(View v, MotionEvent event)28052 boolean onGenericMotion(View v, MotionEvent event); 28053 } 28054 28055 /** 28056 * Interface definition for a callback to be invoked when a view has been clicked and held. 28057 */ 28058 public interface OnLongClickListener { 28059 /** 28060 * Called when a view has been clicked and held. 28061 * 28062 * @param v The view that was clicked and held. 28063 * 28064 * @return true if the callback consumed the long click, false otherwise. 28065 */ onLongClick(View v)28066 boolean onLongClick(View v); 28067 } 28068 28069 /** 28070 * Interface definition for a callback to be invoked when a drag is being dispatched 28071 * to this view. The callback will be invoked before the hosting view's own 28072 * onDrag(event) method. If the listener wants to fall back to the hosting view's 28073 * onDrag(event) behavior, it should return 'false' from this callback. 28074 * 28075 * <div class="special reference"> 28076 * <h3>Developer Guides</h3> 28077 * <p>For a guide to implementing drag and drop features, read the 28078 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 28079 * </div> 28080 */ 28081 public interface OnDragListener { 28082 /** 28083 * Called when a drag event is dispatched to a view. This allows listeners 28084 * to get a chance to override base View behavior. 28085 * 28086 * @param v The View that received the drag event. 28087 * @param event The {@link android.view.DragEvent} object for the drag event. 28088 * @return {@code true} if the drag event was handled successfully, or {@code false} 28089 * if the drag event was not handled. Note that {@code false} will trigger the View 28090 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 28091 */ onDrag(View v, DragEvent event)28092 boolean onDrag(View v, DragEvent event); 28093 } 28094 28095 /** 28096 * Interface definition for a callback to be invoked when the focus state of 28097 * a view changed. 28098 */ 28099 public interface OnFocusChangeListener { 28100 /** 28101 * Called when the focus state of a view has changed. 28102 * 28103 * @param v The view whose state has changed. 28104 * @param hasFocus The new focus state of v. 28105 */ onFocusChange(View v, boolean hasFocus)28106 void onFocusChange(View v, boolean hasFocus); 28107 } 28108 28109 /** 28110 * Interface definition for a callback to be invoked when a view is clicked. 28111 */ 28112 public interface OnClickListener { 28113 /** 28114 * Called when a view has been clicked. 28115 * 28116 * @param v The view that was clicked. 28117 */ onClick(View v)28118 void onClick(View v); 28119 } 28120 28121 /** 28122 * Interface definition for a callback to be invoked when a view is context clicked. 28123 */ 28124 public interface OnContextClickListener { 28125 /** 28126 * Called when a view is context clicked. 28127 * 28128 * @param v The view that has been context clicked. 28129 * @return true if the callback consumed the context click, false otherwise. 28130 */ onContextClick(View v)28131 boolean onContextClick(View v); 28132 } 28133 28134 /** 28135 * Interface definition for a callback to be invoked when the context menu 28136 * for this view is being built. 28137 */ 28138 public interface OnCreateContextMenuListener { 28139 /** 28140 * Called when the context menu for this view is being built. It is not 28141 * safe to hold onto the menu after this method returns. 28142 * 28143 * @param menu The context menu that is being built 28144 * @param v The view for which the context menu is being built 28145 * @param menuInfo Extra information about the item for which the 28146 * context menu should be shown. This information will vary 28147 * depending on the class of v. 28148 */ onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)28149 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 28150 } 28151 28152 /** 28153 * Interface definition for a callback to be invoked when the status bar changes 28154 * visibility. This reports <strong>global</strong> changes to the system UI 28155 * state, not what the application is requesting. 28156 * 28157 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 28158 */ 28159 public interface OnSystemUiVisibilityChangeListener { 28160 /** 28161 * Called when the status bar changes visibility because of a call to 28162 * {@link View#setSystemUiVisibility(int)}. 28163 * 28164 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 28165 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 28166 * This tells you the <strong>global</strong> state of these UI visibility 28167 * flags, not what your app is currently applying. 28168 */ onSystemUiVisibilityChange(int visibility)28169 public void onSystemUiVisibilityChange(int visibility); 28170 } 28171 28172 /** 28173 * Interface definition for a callback to be invoked when this view is attached 28174 * or detached from its window. 28175 */ 28176 public interface OnAttachStateChangeListener { 28177 /** 28178 * Called when the view is attached to a window. 28179 * @param v The view that was attached 28180 */ onViewAttachedToWindow(View v)28181 public void onViewAttachedToWindow(View v); 28182 /** 28183 * Called when the view is detached from a window. 28184 * @param v The view that was detached 28185 */ onViewDetachedFromWindow(View v)28186 public void onViewDetachedFromWindow(View v); 28187 } 28188 28189 /** 28190 * Listener for applying window insets on a view in a custom way. 28191 * 28192 * <p>Apps may choose to implement this interface if they want to apply custom policy 28193 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 28194 * is set, its 28195 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 28196 * method will be called instead of the View's own 28197 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 28198 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 28199 * the View's normal behavior as part of its own.</p> 28200 */ 28201 public interface OnApplyWindowInsetsListener { 28202 /** 28203 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 28204 * on a View, this listener method will be called instead of the view's own 28205 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 28206 * 28207 * @param v The view applying window insets 28208 * @param insets The insets to apply 28209 * @return The insets supplied, minus any insets that were consumed 28210 */ onApplyWindowInsets(View v, WindowInsets insets)28211 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 28212 } 28213 28214 private final class UnsetPressedState implements Runnable { 28215 @Override run()28216 public void run() { 28217 setPressed(false); 28218 } 28219 } 28220 28221 /** 28222 * When a view becomes invisible checks if autofill considers the view invisible too. This 28223 * happens after the regular removal operation to make sure the operation is finished by the 28224 * time this is called. 28225 */ 28226 private static class VisibilityChangeForAutofillHandler extends Handler { 28227 private final AutofillManager mAfm; 28228 private final View mView; 28229 VisibilityChangeForAutofillHandler(@onNull AutofillManager afm, @NonNull View view)28230 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, 28231 @NonNull View view) { 28232 mAfm = afm; 28233 mView = view; 28234 } 28235 28236 @Override handleMessage(Message msg)28237 public void handleMessage(Message msg) { 28238 mAfm.notifyViewVisibilityChanged(mView, mView.isShown()); 28239 } 28240 } 28241 28242 /** 28243 * Base class for derived classes that want to save and restore their own 28244 * state in {@link android.view.View#onSaveInstanceState()}. 28245 */ 28246 public static class BaseSavedState extends AbsSavedState { 28247 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; 28248 static final int IS_AUTOFILLED = 0b10; 28249 static final int AUTOFILL_ID = 0b100; 28250 28251 // Flags that describe what data in this state is valid 28252 int mSavedData; 28253 String mStartActivityRequestWhoSaved; 28254 boolean mIsAutofilled; 28255 int mAutofillViewId; 28256 28257 /** 28258 * Constructor used when reading from a parcel. Reads the state of the superclass. 28259 * 28260 * @param source parcel to read from 28261 */ BaseSavedState(Parcel source)28262 public BaseSavedState(Parcel source) { 28263 this(source, null); 28264 } 28265 28266 /** 28267 * Constructor used when reading from a parcel using a given class loader. 28268 * Reads the state of the superclass. 28269 * 28270 * @param source parcel to read from 28271 * @param loader ClassLoader to use for reading 28272 */ BaseSavedState(Parcel source, ClassLoader loader)28273 public BaseSavedState(Parcel source, ClassLoader loader) { 28274 super(source, loader); 28275 mSavedData = source.readInt(); 28276 mStartActivityRequestWhoSaved = source.readString(); 28277 mIsAutofilled = source.readBoolean(); 28278 mAutofillViewId = source.readInt(); 28279 } 28280 28281 /** 28282 * Constructor called by derived classes when creating their SavedState objects 28283 * 28284 * @param superState The state of the superclass of this view 28285 */ BaseSavedState(Parcelable superState)28286 public BaseSavedState(Parcelable superState) { 28287 super(superState); 28288 } 28289 28290 @Override writeToParcel(Parcel out, int flags)28291 public void writeToParcel(Parcel out, int flags) { 28292 super.writeToParcel(out, flags); 28293 28294 out.writeInt(mSavedData); 28295 out.writeString(mStartActivityRequestWhoSaved); 28296 out.writeBoolean(mIsAutofilled); 28297 out.writeInt(mAutofillViewId); 28298 } 28299 28300 public static final @android.annotation.NonNull Parcelable.Creator<BaseSavedState> CREATOR 28301 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 28302 @Override 28303 public BaseSavedState createFromParcel(Parcel in) { 28304 return new BaseSavedState(in); 28305 } 28306 28307 @Override 28308 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 28309 return new BaseSavedState(in, loader); 28310 } 28311 28312 @Override 28313 public BaseSavedState[] newArray(int size) { 28314 return new BaseSavedState[size]; 28315 } 28316 }; 28317 } 28318 28319 /** 28320 * A set of information given to a view when it is attached to its parent 28321 * window. 28322 */ 28323 final static class AttachInfo { 28324 interface Callbacks { playSoundEffect(int effectId)28325 void playSoundEffect(int effectId); performHapticFeedback(int effectId, boolean always)28326 boolean performHapticFeedback(int effectId, boolean always); 28327 } 28328 28329 /** 28330 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 28331 * to a Handler. This class contains the target (View) to invalidate and 28332 * the coordinates of the dirty rectangle. 28333 * 28334 * For performance purposes, this class also implements a pool of up to 28335 * POOL_LIMIT objects that get reused. This reduces memory allocations 28336 * whenever possible. 28337 */ 28338 static class InvalidateInfo { 28339 28340 @UnsupportedAppUsage InvalidateInfo()28341 InvalidateInfo() { 28342 } 28343 28344 private static final int POOL_LIMIT = 10; 28345 28346 private static final SynchronizedPool<InvalidateInfo> sPool = 28347 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 28348 28349 @UnsupportedAppUsage 28350 View target; 28351 28352 @UnsupportedAppUsage 28353 int left; 28354 @UnsupportedAppUsage 28355 int top; 28356 @UnsupportedAppUsage 28357 int right; 28358 @UnsupportedAppUsage 28359 int bottom; 28360 obtain()28361 public static InvalidateInfo obtain() { 28362 InvalidateInfo instance = sPool.acquire(); 28363 return (instance != null) ? instance : new InvalidateInfo(); 28364 } 28365 recycle()28366 public void recycle() { 28367 target = null; 28368 sPool.release(this); 28369 } 28370 } 28371 28372 @UnsupportedAppUsage 28373 final IWindowSession mSession; 28374 28375 @UnsupportedAppUsage 28376 final IWindow mWindow; 28377 28378 final IBinder mWindowToken; 28379 28380 Display mDisplay; 28381 28382 final Callbacks mRootCallbacks; 28383 28384 IWindowId mIWindowId; 28385 WindowId mWindowId; 28386 28387 /** 28388 * The top view of the hierarchy. 28389 */ 28390 View mRootView; 28391 28392 IBinder mPanelParentWindowToken; 28393 28394 boolean mHardwareAccelerated; 28395 boolean mHardwareAccelerationRequested; 28396 ThreadedRenderer mThreadedRenderer; 28397 List<RenderNode> mPendingAnimatingRenderNodes; 28398 28399 /** 28400 * The state of the display to which the window is attached, as reported 28401 * by {@link Display#getState()}. Note that the display state constants 28402 * declared by {@link Display} do not exactly line up with the screen state 28403 * constants declared by {@link View} (there are more display states than 28404 * screen states). 28405 */ 28406 @UnsupportedAppUsage 28407 int mDisplayState = Display.STATE_UNKNOWN; 28408 28409 /** 28410 * Scale factor used by the compatibility mode 28411 */ 28412 @UnsupportedAppUsage 28413 float mApplicationScale; 28414 28415 /** 28416 * Indicates whether the application is in compatibility mode 28417 */ 28418 @UnsupportedAppUsage 28419 boolean mScalingRequired; 28420 28421 /** 28422 * Left position of this view's window 28423 */ 28424 int mWindowLeft; 28425 28426 /** 28427 * Top position of this view's window 28428 */ 28429 int mWindowTop; 28430 28431 /** 28432 * Indicates whether views need to use 32-bit drawing caches 28433 */ 28434 boolean mUse32BitDrawingCache; 28435 28436 /** 28437 * For windows that are full-screen but using insets to layout inside 28438 * of the screen areas, these are the current insets to appear inside 28439 * the overscan area of the display. 28440 */ 28441 final Rect mOverscanInsets = new Rect(); 28442 28443 /** 28444 * For windows that are full-screen but using insets to layout inside 28445 * of the screen decorations, these are the current insets for the 28446 * content of the window. 28447 */ 28448 @UnsupportedAppUsage 28449 final Rect mContentInsets = new Rect(); 28450 28451 /** 28452 * For windows that are full-screen but using insets to layout inside 28453 * of the screen decorations, these are the current insets for the 28454 * actual visible parts of the window. 28455 */ 28456 @UnsupportedAppUsage 28457 final Rect mVisibleInsets = new Rect(); 28458 28459 /** 28460 * For windows that are full-screen but using insets to layout inside 28461 * of the screen decorations, these are the current insets for the 28462 * stable system windows. 28463 */ 28464 @UnsupportedAppUsage 28465 final Rect mStableInsets = new Rect(); 28466 28467 final DisplayCutout.ParcelableWrapper mDisplayCutout = 28468 new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT); 28469 28470 /** 28471 * For windows that include areas that are not covered by real surface these are the outsets 28472 * for real surface. 28473 */ 28474 final Rect mOutsets = new Rect(); 28475 28476 /** 28477 * In multi-window we force show the system bars. Because we don't want that the surface 28478 * size changes in this mode, we instead have a flag whether the system bars sizes should 28479 * always be consumed, so the app is treated like there are no virtual system bars at all. 28480 */ 28481 boolean mAlwaysConsumeSystemBars; 28482 28483 /** 28484 * The internal insets given by this window. This value is 28485 * supplied by the client (through 28486 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 28487 * be given to the window manager when changed to be used in laying 28488 * out windows behind it. 28489 */ 28490 @UnsupportedAppUsage 28491 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 28492 = new ViewTreeObserver.InternalInsetsInfo(); 28493 28494 /** 28495 * Set to true when mGivenInternalInsets is non-empty. 28496 */ 28497 boolean mHasNonEmptyGivenInternalInsets; 28498 28499 /** 28500 * All views in the window's hierarchy that serve as scroll containers, 28501 * used to determine if the window can be resized or must be panned 28502 * to adjust for a soft input area. 28503 */ 28504 @UnsupportedAppUsage 28505 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 28506 28507 @UnsupportedAppUsage 28508 final KeyEvent.DispatcherState mKeyDispatchState 28509 = new KeyEvent.DispatcherState(); 28510 28511 /** 28512 * Indicates whether the view's window currently has the focus. 28513 */ 28514 @UnsupportedAppUsage 28515 boolean mHasWindowFocus; 28516 28517 /** 28518 * The current visibility of the window. 28519 */ 28520 int mWindowVisibility; 28521 28522 /** 28523 * Indicates the time at which drawing started to occur. 28524 */ 28525 @UnsupportedAppUsage 28526 long mDrawingTime; 28527 28528 /** 28529 * Indicates whether the view's window is currently in touch mode. 28530 */ 28531 @UnsupportedAppUsage 28532 boolean mInTouchMode; 28533 28534 /** 28535 * Indicates whether the view has requested unbuffered input dispatching for the current 28536 * event stream. 28537 */ 28538 boolean mUnbufferedDispatchRequested; 28539 28540 /** 28541 * Indicates that ViewAncestor should trigger a global layout change 28542 * the next time it performs a traversal 28543 */ 28544 @UnsupportedAppUsage 28545 boolean mRecomputeGlobalAttributes; 28546 28547 /** 28548 * Always report new attributes at next traversal. 28549 */ 28550 boolean mForceReportNewAttributes; 28551 28552 /** 28553 * Set during a traveral if any views want to keep the screen on. 28554 */ 28555 @UnsupportedAppUsage 28556 boolean mKeepScreenOn; 28557 28558 /** 28559 * Set during a traveral if the light center needs to be updated. 28560 */ 28561 boolean mNeedsUpdateLightCenter; 28562 28563 /** 28564 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 28565 */ 28566 int mSystemUiVisibility; 28567 28568 /** 28569 * Hack to force certain system UI visibility flags to be cleared. 28570 */ 28571 int mDisabledSystemUiVisibility; 28572 28573 /** 28574 * Last global system UI visibility reported by the window manager. 28575 */ 28576 int mGlobalSystemUiVisibility = -1; 28577 28578 /** 28579 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 28580 * attached. 28581 */ 28582 boolean mHasSystemUiListeners; 28583 28584 /** 28585 * Set if the window has requested to extend into the overscan region 28586 * via WindowManager.LayoutParams.FLAG_LAYOUT_IN_OVERSCAN. 28587 */ 28588 boolean mOverscanRequested; 28589 28590 /** 28591 * Set if the visibility of any views has changed. 28592 */ 28593 @UnsupportedAppUsage 28594 boolean mViewVisibilityChanged; 28595 28596 /** 28597 * Set to true if a view has been scrolled. 28598 */ 28599 @UnsupportedAppUsage 28600 boolean mViewScrollChanged; 28601 28602 /** 28603 * Set to true if a pointer event is currently being handled. 28604 */ 28605 boolean mHandlingPointerEvent; 28606 28607 /** 28608 * The offset of this view's window when it's on an embedded display that is re-parented 28609 * to another window. 28610 */ 28611 final Point mLocationInParentDisplay = new Point(); 28612 28613 /** 28614 * Global to the view hierarchy used as a temporary for dealing with 28615 * x/y points in the transparent region computations. 28616 */ 28617 final int[] mTransparentLocation = new int[2]; 28618 28619 /** 28620 * Global to the view hierarchy used as a temporary for dealing with 28621 * x/y points in the ViewGroup.invalidateChild implementation. 28622 */ 28623 final int[] mInvalidateChildLocation = new int[2]; 28624 28625 /** 28626 * Global to the view hierarchy used as a temporary for dealing with 28627 * computing absolute on-screen location. 28628 */ 28629 final int[] mTmpLocation = new int[2]; 28630 28631 /** 28632 * Global to the view hierarchy used as a temporary for dealing with 28633 * x/y location when view is transformed. 28634 */ 28635 final float[] mTmpTransformLocation = new float[2]; 28636 28637 /** 28638 * The view tree observer used to dispatch global events like 28639 * layout, pre-draw, touch mode change, etc. 28640 */ 28641 @UnsupportedAppUsage 28642 final ViewTreeObserver mTreeObserver; 28643 28644 /** 28645 * A Canvas used by the view hierarchy to perform bitmap caching. 28646 */ 28647 Canvas mCanvas; 28648 28649 /** 28650 * The view root impl. 28651 */ 28652 final ViewRootImpl mViewRootImpl; 28653 28654 /** 28655 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 28656 * handler can be used to pump events in the UI events queue. 28657 */ 28658 @UnsupportedAppUsage 28659 final Handler mHandler; 28660 28661 /** 28662 * Temporary for use in computing invalidate rectangles while 28663 * calling up the hierarchy. 28664 */ 28665 final Rect mTmpInvalRect = new Rect(); 28666 28667 /** 28668 * Temporary for use in computing hit areas with transformed views 28669 */ 28670 final RectF mTmpTransformRect = new RectF(); 28671 28672 /** 28673 * Temporary for use in computing hit areas with transformed views 28674 */ 28675 final RectF mTmpTransformRect1 = new RectF(); 28676 28677 /** 28678 * Temporary list of rectanges. 28679 */ 28680 final List<RectF> mTmpRectList = new ArrayList<>(); 28681 28682 /** 28683 * Temporary for use in transforming invalidation rect 28684 */ 28685 final Matrix mTmpMatrix = new Matrix(); 28686 28687 /** 28688 * Temporary for use in transforming invalidation rect 28689 */ 28690 final Transformation mTmpTransformation = new Transformation(); 28691 28692 /** 28693 * Temporary for use in querying outlines from OutlineProviders 28694 */ 28695 final Outline mTmpOutline = new Outline(); 28696 28697 /** 28698 * Temporary list for use in collecting focusable descendents of a view. 28699 */ 28700 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 28701 28702 /** 28703 * The id of the window for accessibility purposes. 28704 */ 28705 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 28706 28707 /** 28708 * Flags related to accessibility processing. 28709 * 28710 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 28711 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 28712 */ 28713 int mAccessibilityFetchFlags; 28714 28715 /** 28716 * The drawable for highlighting accessibility focus. 28717 */ 28718 Drawable mAccessibilityFocusDrawable; 28719 28720 /** 28721 * The drawable for highlighting autofilled views. 28722 * 28723 * @see #isAutofilled() 28724 */ 28725 Drawable mAutofilledDrawable; 28726 28727 /** 28728 * Show where the margins, bounds and layout bounds are for each view. 28729 */ 28730 boolean mDebugLayout = DisplayProperties.debug_layout().orElse(false); 28731 28732 /** 28733 * Point used to compute visible regions. 28734 */ 28735 final Point mPoint = new Point(); 28736 28737 /** 28738 * Used to track which View originated a requestLayout() call, used when 28739 * requestLayout() is called during layout. 28740 */ 28741 View mViewRequestingLayout; 28742 28743 /** 28744 * Used to track the identity of the current drag operation. 28745 */ 28746 IBinder mDragToken; 28747 28748 /** 28749 * The drag shadow surface for the current drag operation. 28750 */ 28751 public Surface mDragSurface; 28752 28753 28754 /** 28755 * The view that currently has a tooltip displayed. 28756 */ 28757 View mTooltipHost; 28758 28759 /** 28760 * The initial structure has been reported so the view is ready to report updates. 28761 */ 28762 boolean mReadyForContentCaptureUpdates; 28763 28764 /** 28765 * Map(keyed by session) of content capture events that need to be notified after the view 28766 * hierarchy is traversed: value is either the view itself for appearead events, or its 28767 * autofill id for disappeared. 28768 */ 28769 SparseArray<ArrayList<Object>> mContentCaptureEvents; 28770 28771 /** 28772 * Cached reference to the {@link ContentCaptureManager}. 28773 */ 28774 ContentCaptureManager mContentCaptureManager; 28775 28776 /** 28777 * Creates a new set of attachment information with the specified 28778 * events handler and thread. 28779 * 28780 * @param handler the events handler the view must use 28781 */ AttachInfo(IWindowSession session, IWindow window, Display display, ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, Context context)28782 AttachInfo(IWindowSession session, IWindow window, Display display, 28783 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 28784 Context context) { 28785 mSession = session; 28786 mWindow = window; 28787 mWindowToken = window.asBinder(); 28788 mDisplay = display; 28789 mViewRootImpl = viewRootImpl; 28790 mHandler = handler; 28791 mRootCallbacks = effectPlayer; 28792 mTreeObserver = new ViewTreeObserver(context); 28793 } 28794 delayNotifyContentCaptureEvent(@onNull ContentCaptureSession session, @NonNull View view, boolean appeared)28795 private void delayNotifyContentCaptureEvent(@NonNull ContentCaptureSession session, 28796 @NonNull View view, boolean appeared) { 28797 if (mContentCaptureEvents == null) { 28798 // Most of the time there will be just one session, so intial capacity is 1 28799 mContentCaptureEvents = new SparseArray<>(1); 28800 } 28801 int sessionId = session.getId(); 28802 // TODO: life would be much easier if we provided a MultiMap implementation somwhere... 28803 ArrayList<Object> events = mContentCaptureEvents.get(sessionId); 28804 if (events == null) { 28805 events = new ArrayList<>(); 28806 mContentCaptureEvents.put(sessionId, events); 28807 } 28808 events.add(appeared ? view : view.getAutofillId()); 28809 } 28810 28811 @Nullable getContentCaptureManager(@onNull Context context)28812 ContentCaptureManager getContentCaptureManager(@NonNull Context context) { 28813 if (mContentCaptureManager != null) { 28814 return mContentCaptureManager; 28815 } 28816 mContentCaptureManager = context.getSystemService(ContentCaptureManager.class); 28817 return mContentCaptureManager; 28818 } 28819 } 28820 28821 /** 28822 * <p>ScrollabilityCache holds various fields used by a View when scrolling 28823 * is supported. This avoids keeping too many unused fields in most 28824 * instances of View.</p> 28825 */ 28826 private static class ScrollabilityCache implements Runnable { 28827 28828 /** 28829 * Scrollbars are not visible 28830 */ 28831 public static final int OFF = 0; 28832 28833 /** 28834 * Scrollbars are visible 28835 */ 28836 public static final int ON = 1; 28837 28838 /** 28839 * Scrollbars are fading away 28840 */ 28841 public static final int FADING = 2; 28842 28843 public boolean fadeScrollBars; 28844 28845 public int fadingEdgeLength; 28846 public int scrollBarDefaultDelayBeforeFade; 28847 public int scrollBarFadeDuration; 28848 28849 public int scrollBarSize; 28850 public int scrollBarMinTouchTarget; 28851 @UnsupportedAppUsage 28852 public ScrollBarDrawable scrollBar; 28853 public float[] interpolatorValues; 28854 @UnsupportedAppUsage 28855 public View host; 28856 28857 public final Paint paint; 28858 public final Matrix matrix; 28859 public Shader shader; 28860 28861 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 28862 28863 private static final float[] OPAQUE = { 255 }; 28864 private static final float[] TRANSPARENT = { 0.0f }; 28865 28866 /** 28867 * When fading should start. This time moves into the future every time 28868 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 28869 */ 28870 public long fadeStartTime; 28871 28872 28873 /** 28874 * The current state of the scrollbars: ON, OFF, or FADING 28875 */ 28876 @UnsupportedAppUsage 28877 public int state = OFF; 28878 28879 private int mLastColor; 28880 28881 public final Rect mScrollBarBounds = new Rect(); 28882 public final Rect mScrollBarTouchBounds = new Rect(); 28883 28884 public static final int NOT_DRAGGING = 0; 28885 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 28886 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 28887 public int mScrollBarDraggingState = NOT_DRAGGING; 28888 28889 public float mScrollBarDraggingPos = 0; 28890 ScrollabilityCache(ViewConfiguration configuration, View host)28891 public ScrollabilityCache(ViewConfiguration configuration, View host) { 28892 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 28893 scrollBarSize = configuration.getScaledScrollBarSize(); 28894 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 28895 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 28896 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 28897 28898 paint = new Paint(); 28899 matrix = new Matrix(); 28900 // use use a height of 1, and then wack the matrix each time we 28901 // actually use it. 28902 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 28903 paint.setShader(shader); 28904 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 28905 28906 this.host = host; 28907 } 28908 setFadeColor(int color)28909 public void setFadeColor(int color) { 28910 if (color != mLastColor) { 28911 mLastColor = color; 28912 28913 if (color != 0) { 28914 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 28915 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 28916 paint.setShader(shader); 28917 // Restore the default transfer mode (src_over) 28918 paint.setXfermode(null); 28919 } else { 28920 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 28921 paint.setShader(shader); 28922 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 28923 } 28924 } 28925 } 28926 run()28927 public void run() { 28928 long now = AnimationUtils.currentAnimationTimeMillis(); 28929 if (now >= fadeStartTime) { 28930 28931 // the animation fades the scrollbars out by changing 28932 // the opacity (alpha) from fully opaque to fully 28933 // transparent 28934 int nextFrame = (int) now; 28935 int framesCount = 0; 28936 28937 Interpolator interpolator = scrollBarInterpolator; 28938 28939 // Start opaque 28940 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 28941 28942 // End transparent 28943 nextFrame += scrollBarFadeDuration; 28944 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 28945 28946 state = FADING; 28947 28948 // Kick off the fade animation 28949 host.invalidate(true); 28950 } 28951 } 28952 } 28953 28954 /** 28955 * Resuable callback for sending 28956 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 28957 */ 28958 private class SendViewScrolledAccessibilityEvent implements Runnable { 28959 public volatile boolean mIsPending; 28960 public int mDeltaX; 28961 public int mDeltaY; 28962 post(int dx, int dy)28963 public void post(int dx, int dy) { 28964 mDeltaX += dx; 28965 mDeltaY += dy; 28966 if (!mIsPending) { 28967 mIsPending = true; 28968 postDelayed(this, ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 28969 } 28970 } 28971 28972 @Override run()28973 public void run() { 28974 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 28975 AccessibilityEvent event = AccessibilityEvent.obtain( 28976 AccessibilityEvent.TYPE_VIEW_SCROLLED); 28977 event.setScrollDeltaX(mDeltaX); 28978 event.setScrollDeltaY(mDeltaY); 28979 sendAccessibilityEventUnchecked(event); 28980 } 28981 reset(); 28982 } 28983 reset()28984 private void reset() { 28985 mIsPending = false; 28986 mDeltaX = 0; 28987 mDeltaY = 0; 28988 } 28989 } 28990 28991 /** 28992 * Remove the pending callback for sending a 28993 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 28994 */ 28995 @UnsupportedAppUsage cancel(@ullable SendViewScrolledAccessibilityEvent callback)28996 private void cancel(@Nullable SendViewScrolledAccessibilityEvent callback) { 28997 if (callback == null || !callback.mIsPending) return; 28998 removeCallbacks(callback); 28999 callback.reset(); 29000 } 29001 29002 /** 29003 * <p> 29004 * This class represents a delegate that can be registered in a {@link View} 29005 * to enhance accessibility support via composition rather via inheritance. 29006 * It is specifically targeted to widget developers that extend basic View 29007 * classes i.e. classes in package android.view, that would like their 29008 * applications to be backwards compatible. 29009 * </p> 29010 * <div class="special reference"> 29011 * <h3>Developer Guides</h3> 29012 * <p>For more information about making applications accessible, read the 29013 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 29014 * developer guide.</p> 29015 * </div> 29016 * <p> 29017 * A scenario in which a developer would like to use an accessibility delegate 29018 * is overriding a method introduced in a later API version than the minimal API 29019 * version supported by the application. For example, the method 29020 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 29021 * in API version 4 when the accessibility APIs were first introduced. If a 29022 * developer would like their application to run on API version 4 devices (assuming 29023 * all other APIs used by the application are version 4 or lower) and take advantage 29024 * of this method, instead of overriding the method which would break the application's 29025 * backwards compatibility, they can override the corresponding method in this 29026 * delegate and register the delegate in the target View if the API version of 29027 * the system is high enough, i.e. the API version is the same as or higher than the API 29028 * version that introduced 29029 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 29030 * </p> 29031 * <p> 29032 * Here is an example implementation: 29033 * </p> 29034 * <code><pre><p> 29035 * if (Build.VERSION.SDK_INT >= 14) { 29036 * // If the API version is equal of higher than the version in 29037 * // which onInitializeAccessibilityNodeInfo was introduced we 29038 * // register a delegate with a customized implementation. 29039 * View view = findViewById(R.id.view_id); 29040 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 29041 * public void onInitializeAccessibilityNodeInfo(View host, 29042 * AccessibilityNodeInfo info) { 29043 * // Let the default implementation populate the info. 29044 * super.onInitializeAccessibilityNodeInfo(host, info); 29045 * // Set some other information. 29046 * info.setEnabled(host.isEnabled()); 29047 * } 29048 * }); 29049 * } 29050 * </code></pre></p> 29051 * <p> 29052 * This delegate contains methods that correspond to the accessibility methods 29053 * in View. If a delegate has been specified the implementation in View hands 29054 * off handling to the corresponding method in this delegate. The default 29055 * implementation the delegate methods behaves exactly as the corresponding 29056 * method in View for the case of no accessibility delegate been set. Hence, 29057 * to customize the behavior of a View method, clients can override only the 29058 * corresponding delegate method without altering the behavior of the rest 29059 * accessibility related methods of the host view. 29060 * </p> 29061 * <p> 29062 * <strong>Note:</strong> On platform versions prior to 29063 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 29064 * views in the {@code android.widget.*} package are called <i>before</i> 29065 * host methods. This prevents certain properties such as class name from 29066 * being modified by overriding 29067 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 29068 * as any changes will be overwritten by the host class. 29069 * <p> 29070 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 29071 * methods are called <i>after</i> host methods, which all properties to be 29072 * modified without being overwritten by the host class. 29073 */ 29074 public static class AccessibilityDelegate { 29075 29076 /** 29077 * Sends an accessibility event of the given type. If accessibility is not 29078 * enabled this method has no effect. 29079 * <p> 29080 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 29081 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 29082 * been set. 29083 * </p> 29084 * 29085 * @param host The View hosting the delegate. 29086 * @param eventType The type of the event to send. 29087 * 29088 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 29089 */ sendAccessibilityEvent(View host, int eventType)29090 public void sendAccessibilityEvent(View host, int eventType) { 29091 host.sendAccessibilityEventInternal(eventType); 29092 } 29093 29094 /** 29095 * Performs the specified accessibility action on the view. For 29096 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 29097 * <p> 29098 * The default implementation behaves as 29099 * {@link View#performAccessibilityAction(int, Bundle) 29100 * View#performAccessibilityAction(int, Bundle)} for the case of 29101 * no accessibility delegate been set. 29102 * </p> 29103 * 29104 * @param action The action to perform. 29105 * @return Whether the action was performed. 29106 * 29107 * @see View#performAccessibilityAction(int, Bundle) 29108 * View#performAccessibilityAction(int, Bundle) 29109 */ performAccessibilityAction(View host, int action, Bundle args)29110 public boolean performAccessibilityAction(View host, int action, Bundle args) { 29111 return host.performAccessibilityActionInternal(action, args); 29112 } 29113 29114 /** 29115 * Sends an accessibility event. This method behaves exactly as 29116 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 29117 * empty {@link AccessibilityEvent} and does not perform a check whether 29118 * accessibility is enabled. 29119 * <p> 29120 * The default implementation behaves as 29121 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 29122 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 29123 * the case of no accessibility delegate been set. 29124 * </p> 29125 * 29126 * @param host The View hosting the delegate. 29127 * @param event The event to send. 29128 * 29129 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 29130 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 29131 */ sendAccessibilityEventUnchecked(View host, AccessibilityEvent event)29132 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 29133 host.sendAccessibilityEventUncheckedInternal(event); 29134 } 29135 29136 /** 29137 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 29138 * to its children for adding their text content to the event. 29139 * <p> 29140 * The default implementation behaves as 29141 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 29142 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 29143 * the case of no accessibility delegate been set. 29144 * </p> 29145 * 29146 * @param host The View hosting the delegate. 29147 * @param event The event. 29148 * @return True if the event population was completed. 29149 * 29150 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 29151 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 29152 */ dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event)29153 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 29154 return host.dispatchPopulateAccessibilityEventInternal(event); 29155 } 29156 29157 /** 29158 * Gives a chance to the host View to populate the accessibility event with its 29159 * text content. 29160 * <p> 29161 * The default implementation behaves as 29162 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 29163 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 29164 * the case of no accessibility delegate been set. 29165 * </p> 29166 * 29167 * @param host The View hosting the delegate. 29168 * @param event The accessibility event which to populate. 29169 * 29170 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 29171 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 29172 */ onPopulateAccessibilityEvent(View host, AccessibilityEvent event)29173 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 29174 host.onPopulateAccessibilityEventInternal(event); 29175 } 29176 29177 /** 29178 * Initializes an {@link AccessibilityEvent} with information about the 29179 * the host View which is the event source. 29180 * <p> 29181 * The default implementation behaves as 29182 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 29183 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 29184 * the case of no accessibility delegate been set. 29185 * </p> 29186 * 29187 * @param host The View hosting the delegate. 29188 * @param event The event to initialize. 29189 * 29190 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 29191 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 29192 */ onInitializeAccessibilityEvent(View host, AccessibilityEvent event)29193 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 29194 host.onInitializeAccessibilityEventInternal(event); 29195 } 29196 29197 /** 29198 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 29199 * <p> 29200 * The default implementation behaves as 29201 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 29202 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 29203 * the case of no accessibility delegate been set. 29204 * </p> 29205 * 29206 * @param host The View hosting the delegate. 29207 * @param info The instance to initialize. 29208 * 29209 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 29210 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 29211 */ onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info)29212 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 29213 host.onInitializeAccessibilityNodeInfoInternal(info); 29214 } 29215 29216 /** 29217 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 29218 * additional data. 29219 * <p> 29220 * This method only needs to be implemented if the View offers to provide additional data. 29221 * </p> 29222 * <p> 29223 * The default implementation behaves as 29224 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle) 29225 * for the case where no accessibility delegate is set. 29226 * </p> 29227 * 29228 * @param host The View hosting the delegate. Never {@code null}. 29229 * @param info The info to which to add the extra data. Never {@code null}. 29230 * @param extraDataKey A key specifying the type of extra data to add to the info. The 29231 * extra data should be added to the {@link Bundle} returned by 29232 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 29233 * {@code null}. 29234 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 29235 * May be {@code null} if the if the service provided no arguments. 29236 * 29237 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 29238 */ addExtraDataToAccessibilityNodeInfo(@onNull View host, @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, @Nullable Bundle arguments)29239 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 29240 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 29241 @Nullable Bundle arguments) { 29242 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 29243 } 29244 29245 /** 29246 * Called when a child of the host View has requested sending an 29247 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 29248 * to augment the event. 29249 * <p> 29250 * The default implementation behaves as 29251 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 29252 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 29253 * the case of no accessibility delegate been set. 29254 * </p> 29255 * 29256 * @param host The View hosting the delegate. 29257 * @param child The child which requests sending the event. 29258 * @param event The event to be sent. 29259 * @return True if the event should be sent 29260 * 29261 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 29262 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 29263 */ onRequestSendAccessibilityEvent(ViewGroup host, View child, AccessibilityEvent event)29264 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 29265 AccessibilityEvent event) { 29266 return host.onRequestSendAccessibilityEventInternal(child, event); 29267 } 29268 29269 /** 29270 * Gets the provider for managing a virtual view hierarchy rooted at this View 29271 * and reported to {@link android.accessibilityservice.AccessibilityService}s 29272 * that explore the window content. 29273 * <p> 29274 * The default implementation behaves as 29275 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 29276 * the case of no accessibility delegate been set. 29277 * </p> 29278 * 29279 * @return The provider. 29280 * 29281 * @see AccessibilityNodeProvider 29282 */ getAccessibilityNodeProvider(View host)29283 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 29284 return null; 29285 } 29286 29287 /** 29288 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 29289 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 29290 * This method is responsible for obtaining an accessibility node info from a 29291 * pool of reusable instances and calling 29292 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 29293 * view to initialize the former. 29294 * <p> 29295 * <strong>Note:</strong> The client is responsible for recycling the obtained 29296 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 29297 * creation. 29298 * </p> 29299 * <p> 29300 * The default implementation behaves as 29301 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 29302 * the case of no accessibility delegate been set. 29303 * </p> 29304 * @return A populated {@link AccessibilityNodeInfo}. 29305 * 29306 * @see AccessibilityNodeInfo 29307 * 29308 * @hide 29309 */ 29310 @UnsupportedAppUsage createAccessibilityNodeInfo(View host)29311 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 29312 return host.createAccessibilityNodeInfoInternal(); 29313 } 29314 } 29315 29316 private static class MatchIdPredicate implements Predicate<View> { 29317 public int mId; 29318 29319 @Override test(View view)29320 public boolean test(View view) { 29321 return (view.mID == mId); 29322 } 29323 } 29324 29325 private static class MatchLabelForPredicate implements Predicate<View> { 29326 private int mLabeledId; 29327 29328 @Override test(View view)29329 public boolean test(View view) { 29330 return (view.mLabelForId == mLabeledId); 29331 } 29332 } 29333 29334 /** 29335 * Dump all private flags in readable format, useful for documentation and 29336 * consistency checking. 29337 */ dumpFlags()29338 private static void dumpFlags() { 29339 final HashMap<String, String> found = Maps.newHashMap(); 29340 try { 29341 for (Field field : View.class.getDeclaredFields()) { 29342 final int modifiers = field.getModifiers(); 29343 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 29344 if (field.getType().equals(int.class)) { 29345 final int value = field.getInt(null); 29346 dumpFlag(found, field.getName(), value); 29347 } else if (field.getType().equals(int[].class)) { 29348 final int[] values = (int[]) field.get(null); 29349 for (int i = 0; i < values.length; i++) { 29350 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 29351 } 29352 } 29353 } 29354 } 29355 } catch (IllegalAccessException e) { 29356 throw new RuntimeException(e); 29357 } 29358 29359 final ArrayList<String> keys = Lists.newArrayList(); 29360 keys.addAll(found.keySet()); 29361 Collections.sort(keys); 29362 for (String key : keys) { 29363 Log.d(VIEW_LOG_TAG, found.get(key)); 29364 } 29365 } 29366 dumpFlag(HashMap<String, String> found, String name, int value)29367 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 29368 // Sort flags by prefix, then by bits, always keeping unique keys 29369 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 29370 final int prefix = name.indexOf('_'); 29371 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 29372 final String output = bits + " " + name; 29373 found.put(key, output); 29374 } 29375 29376 /** {@hide} */ encode(@onNull ViewHierarchyEncoder stream)29377 public void encode(@NonNull ViewHierarchyEncoder stream) { 29378 stream.beginObject(this); 29379 encodeProperties(stream); 29380 stream.endObject(); 29381 } 29382 29383 /** {@hide} */ 29384 @CallSuper encodeProperties(@onNull ViewHierarchyEncoder stream)29385 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 29386 Object resolveId = ViewDebug.resolveId(getContext(), mID); 29387 if (resolveId instanceof String) { 29388 stream.addProperty("id", (String) resolveId); 29389 } else { 29390 stream.addProperty("id", mID); 29391 } 29392 29393 stream.addProperty("misc:transformation.alpha", 29394 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 29395 stream.addProperty("misc:transitionName", getTransitionName()); 29396 29397 // layout 29398 stream.addProperty("layout:left", mLeft); 29399 stream.addProperty("layout:right", mRight); 29400 stream.addProperty("layout:top", mTop); 29401 stream.addProperty("layout:bottom", mBottom); 29402 stream.addProperty("layout:width", getWidth()); 29403 stream.addProperty("layout:height", getHeight()); 29404 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 29405 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 29406 stream.addProperty("layout:hasTransientState", hasTransientState()); 29407 stream.addProperty("layout:baseline", getBaseline()); 29408 29409 // layout params 29410 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 29411 if (layoutParams != null) { 29412 stream.addPropertyKey("layoutParams"); 29413 layoutParams.encode(stream); 29414 } 29415 29416 // scrolling 29417 stream.addProperty("scrolling:scrollX", mScrollX); 29418 stream.addProperty("scrolling:scrollY", mScrollY); 29419 29420 // padding 29421 stream.addProperty("padding:paddingLeft", mPaddingLeft); 29422 stream.addProperty("padding:paddingRight", mPaddingRight); 29423 stream.addProperty("padding:paddingTop", mPaddingTop); 29424 stream.addProperty("padding:paddingBottom", mPaddingBottom); 29425 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 29426 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 29427 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 29428 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 29429 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 29430 29431 // measurement 29432 stream.addProperty("measurement:minHeight", mMinHeight); 29433 stream.addProperty("measurement:minWidth", mMinWidth); 29434 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 29435 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 29436 29437 // drawing 29438 stream.addProperty("drawing:elevation", getElevation()); 29439 stream.addProperty("drawing:translationX", getTranslationX()); 29440 stream.addProperty("drawing:translationY", getTranslationY()); 29441 stream.addProperty("drawing:translationZ", getTranslationZ()); 29442 stream.addProperty("drawing:rotation", getRotation()); 29443 stream.addProperty("drawing:rotationX", getRotationX()); 29444 stream.addProperty("drawing:rotationY", getRotationY()); 29445 stream.addProperty("drawing:scaleX", getScaleX()); 29446 stream.addProperty("drawing:scaleY", getScaleY()); 29447 stream.addProperty("drawing:pivotX", getPivotX()); 29448 stream.addProperty("drawing:pivotY", getPivotY()); 29449 stream.addProperty("drawing:clipBounds", 29450 mClipBounds == null ? null : mClipBounds.toString()); 29451 stream.addProperty("drawing:opaque", isOpaque()); 29452 stream.addProperty("drawing:alpha", getAlpha()); 29453 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 29454 stream.addProperty("drawing:shadow", hasShadow()); 29455 stream.addProperty("drawing:solidColor", getSolidColor()); 29456 stream.addProperty("drawing:layerType", mLayerType); 29457 stream.addProperty("drawing:willNotDraw", willNotDraw()); 29458 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 29459 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 29460 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 29461 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 29462 stream.addProperty("drawing:outlineAmbientShadowColor", getOutlineAmbientShadowColor()); 29463 stream.addProperty("drawing:outlineSpotShadowColor", getOutlineSpotShadowColor()); 29464 29465 // focus 29466 stream.addProperty("focus:hasFocus", hasFocus()); 29467 stream.addProperty("focus:isFocused", isFocused()); 29468 stream.addProperty("focus:focusable", getFocusable()); 29469 stream.addProperty("focus:isFocusable", isFocusable()); 29470 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 29471 29472 stream.addProperty("misc:clickable", isClickable()); 29473 stream.addProperty("misc:pressed", isPressed()); 29474 stream.addProperty("misc:selected", isSelected()); 29475 stream.addProperty("misc:touchMode", isInTouchMode()); 29476 stream.addProperty("misc:hovered", isHovered()); 29477 stream.addProperty("misc:activated", isActivated()); 29478 29479 stream.addProperty("misc:visibility", getVisibility()); 29480 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 29481 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 29482 29483 stream.addProperty("misc:enabled", isEnabled()); 29484 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 29485 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 29486 29487 // theme attributes 29488 Resources.Theme theme = getContext().getTheme(); 29489 if (theme != null) { 29490 stream.addPropertyKey("theme"); 29491 theme.encode(stream); 29492 } 29493 29494 // view attribute information 29495 int n = mAttributes != null ? mAttributes.length : 0; 29496 stream.addProperty("meta:__attrCount__", n/2); 29497 for (int i = 0; i < n; i += 2) { 29498 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 29499 } 29500 29501 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 29502 29503 // text 29504 stream.addProperty("text:textDirection", getTextDirection()); 29505 stream.addProperty("text:textAlignment", getTextAlignment()); 29506 29507 // accessibility 29508 CharSequence contentDescription = getContentDescription(); 29509 stream.addProperty("accessibility:contentDescription", 29510 contentDescription == null ? "" : contentDescription.toString()); 29511 stream.addProperty("accessibility:labelFor", getLabelFor()); 29512 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 29513 } 29514 29515 /** 29516 * Determine if this view is rendered on a round wearable device and is the main view 29517 * on the screen. 29518 */ shouldDrawRoundScrollbar()29519 boolean shouldDrawRoundScrollbar() { 29520 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 29521 return false; 29522 } 29523 29524 final View rootView = getRootView(); 29525 final WindowInsets insets = getRootWindowInsets(); 29526 29527 int height = getHeight(); 29528 int width = getWidth(); 29529 int displayHeight = rootView.getHeight(); 29530 int displayWidth = rootView.getWidth(); 29531 29532 if (height != displayHeight || width != displayWidth) { 29533 return false; 29534 } 29535 29536 getLocationInWindow(mAttachInfo.mTmpLocation); 29537 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 29538 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 29539 } 29540 29541 /** 29542 * Sets the tooltip text which will be displayed in a small popup next to the view. 29543 * <p> 29544 * The tooltip will be displayed: 29545 * <ul> 29546 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context 29547 * menu). </li> 29548 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 29549 * </ul> 29550 * <p> 29551 * <strong>Note:</strong> Do not override this method, as it will have no 29552 * effect on the text displayed in the tooltip. 29553 * 29554 * @param tooltipText the tooltip text, or null if no tooltip is required 29555 * @see #getTooltipText() 29556 * @attr ref android.R.styleable#View_tooltipText 29557 */ setTooltipText(@ullable CharSequence tooltipText)29558 public void setTooltipText(@Nullable CharSequence tooltipText) { 29559 if (TextUtils.isEmpty(tooltipText)) { 29560 setFlags(0, TOOLTIP); 29561 hideTooltip(); 29562 mTooltipInfo = null; 29563 } else { 29564 setFlags(TOOLTIP, TOOLTIP); 29565 if (mTooltipInfo == null) { 29566 mTooltipInfo = new TooltipInfo(); 29567 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 29568 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 29569 mTooltipInfo.mHoverSlop = ViewConfiguration.get(mContext).getScaledHoverSlop(); 29570 mTooltipInfo.clearAnchorPos(); 29571 } 29572 mTooltipInfo.mTooltipText = tooltipText; 29573 } 29574 } 29575 29576 /** 29577 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 29578 */ 29579 @UnsupportedAppUsage setTooltip(@ullable CharSequence tooltipText)29580 public void setTooltip(@Nullable CharSequence tooltipText) { 29581 setTooltipText(tooltipText); 29582 } 29583 29584 /** 29585 * Returns the view's tooltip text. 29586 * 29587 * <strong>Note:</strong> Do not override this method, as it will have no 29588 * effect on the text displayed in the tooltip. You must call 29589 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 29590 * 29591 * @return the tooltip text 29592 * @see #setTooltipText(CharSequence) 29593 * @attr ref android.R.styleable#View_tooltipText 29594 */ 29595 @InspectableProperty 29596 @Nullable getTooltipText()29597 public CharSequence getTooltipText() { 29598 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 29599 } 29600 29601 /** 29602 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 29603 */ 29604 @Nullable getTooltip()29605 public CharSequence getTooltip() { 29606 return getTooltipText(); 29607 } 29608 showTooltip(int x, int y, boolean fromLongClick)29609 private boolean showTooltip(int x, int y, boolean fromLongClick) { 29610 if (mAttachInfo == null || mTooltipInfo == null) { 29611 return false; 29612 } 29613 if (fromLongClick && (mViewFlags & ENABLED_MASK) != ENABLED) { 29614 return false; 29615 } 29616 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 29617 return false; 29618 } 29619 hideTooltip(); 29620 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 29621 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 29622 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 29623 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 29624 mAttachInfo.mTooltipHost = this; 29625 // The available accessibility actions have changed 29626 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 29627 return true; 29628 } 29629 29630 @UnsupportedAppUsage hideTooltip()29631 void hideTooltip() { 29632 if (mTooltipInfo == null) { 29633 return; 29634 } 29635 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 29636 if (mTooltipInfo.mTooltipPopup == null) { 29637 return; 29638 } 29639 mTooltipInfo.mTooltipPopup.hide(); 29640 mTooltipInfo.mTooltipPopup = null; 29641 mTooltipInfo.mTooltipFromLongClick = false; 29642 mTooltipInfo.clearAnchorPos(); 29643 if (mAttachInfo != null) { 29644 mAttachInfo.mTooltipHost = null; 29645 } 29646 // The available accessibility actions have changed 29647 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 29648 } 29649 showLongClickTooltip(int x, int y)29650 private boolean showLongClickTooltip(int x, int y) { 29651 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 29652 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 29653 return showTooltip(x, y, true); 29654 } 29655 showHoverTooltip()29656 private boolean showHoverTooltip() { 29657 return showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 29658 } 29659 dispatchTooltipHoverEvent(MotionEvent event)29660 boolean dispatchTooltipHoverEvent(MotionEvent event) { 29661 if (mTooltipInfo == null) { 29662 return false; 29663 } 29664 switch(event.getAction()) { 29665 case MotionEvent.ACTION_HOVER_MOVE: 29666 if ((mViewFlags & TOOLTIP) != TOOLTIP) { 29667 break; 29668 } 29669 if (!mTooltipInfo.mTooltipFromLongClick && mTooltipInfo.updateAnchorPos(event)) { 29670 if (mTooltipInfo.mTooltipPopup == null) { 29671 // Schedule showing the tooltip after a timeout. 29672 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 29673 postDelayed(mTooltipInfo.mShowTooltipRunnable, 29674 ViewConfiguration.getHoverTooltipShowTimeout()); 29675 } 29676 29677 // Hide hover-triggered tooltip after a period of inactivity. 29678 // Match the timeout used by NativeInputManager to hide the mouse pointer 29679 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 29680 final int timeout; 29681 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 29682 == SYSTEM_UI_FLAG_LOW_PROFILE) { 29683 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 29684 } else { 29685 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 29686 } 29687 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 29688 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 29689 } 29690 return true; 29691 29692 case MotionEvent.ACTION_HOVER_EXIT: 29693 mTooltipInfo.clearAnchorPos(); 29694 if (!mTooltipInfo.mTooltipFromLongClick) { 29695 hideTooltip(); 29696 } 29697 break; 29698 } 29699 return false; 29700 } 29701 handleTooltipKey(KeyEvent event)29702 void handleTooltipKey(KeyEvent event) { 29703 switch (event.getAction()) { 29704 case KeyEvent.ACTION_DOWN: 29705 if (event.getRepeatCount() == 0) { 29706 hideTooltip(); 29707 } 29708 break; 29709 29710 case KeyEvent.ACTION_UP: 29711 handleTooltipUp(); 29712 break; 29713 } 29714 } 29715 handleTooltipUp()29716 private void handleTooltipUp() { 29717 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 29718 return; 29719 } 29720 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 29721 postDelayed(mTooltipInfo.mHideTooltipRunnable, 29722 ViewConfiguration.getLongPressTooltipHideTimeout()); 29723 } 29724 getFocusableAttribute(TypedArray attributes)29725 private int getFocusableAttribute(TypedArray attributes) { 29726 TypedValue val = new TypedValue(); 29727 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 29728 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 29729 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 29730 } else { 29731 return val.data; 29732 } 29733 } else { 29734 return FOCUSABLE_AUTO; 29735 } 29736 } 29737 29738 /** 29739 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 29740 * is not showing. 29741 * @hide 29742 */ 29743 @TestApi getTooltipView()29744 public View getTooltipView() { 29745 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 29746 return null; 29747 } 29748 return mTooltipInfo.mTooltipPopup.getContentView(); 29749 } 29750 29751 /** 29752 * @return {@code true} if the default focus highlight is enabled, {@code false} otherwies. 29753 * @hide 29754 */ 29755 @TestApi isDefaultFocusHighlightEnabled()29756 public static boolean isDefaultFocusHighlightEnabled() { 29757 return sUseDefaultFocusHighlight; 29758 } 29759 29760 /** 29761 * Dispatch a previously unhandled {@link KeyEvent} to this view. Unlike normal key dispatch, 29762 * this dispatches to ALL child views until it is consumed. The dispatch order is z-order 29763 * (visually on-top views first). 29764 * 29765 * @param evt the previously unhandled {@link KeyEvent}. 29766 * @return the {@link View} which consumed the event or {@code null} if not consumed. 29767 */ dispatchUnhandledKeyEvent(KeyEvent evt)29768 View dispatchUnhandledKeyEvent(KeyEvent evt) { 29769 if (onUnhandledKeyEvent(evt)) { 29770 return this; 29771 } 29772 return null; 29773 } 29774 29775 /** 29776 * Allows this view to handle {@link KeyEvent}s which weren't handled by normal dispatch. This 29777 * occurs after the normal view hierarchy dispatch, but before the window callback. By default, 29778 * this will dispatch into all the listeners registered via 29779 * {@link #addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener)} in last-in-first-out 29780 * order (most recently added will receive events first). 29781 * 29782 * @param event An unhandled event. 29783 * @return {@code true} if the event was handled, {@code false} otherwise. 29784 * @see #addOnUnhandledKeyEventListener 29785 */ onUnhandledKeyEvent(@onNull KeyEvent event)29786 boolean onUnhandledKeyEvent(@NonNull KeyEvent event) { 29787 if (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null) { 29788 for (int i = mListenerInfo.mUnhandledKeyListeners.size() - 1; i >= 0; --i) { 29789 if (mListenerInfo.mUnhandledKeyListeners.get(i).onUnhandledKeyEvent(this, event)) { 29790 return true; 29791 } 29792 } 29793 } 29794 return false; 29795 } 29796 hasUnhandledKeyListener()29797 boolean hasUnhandledKeyListener() { 29798 return (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null 29799 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()); 29800 } 29801 29802 /** 29803 * Adds a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 29804 * UI thread. 29805 * 29806 * @param listener a receiver of unhandled {@link KeyEvent}s. 29807 * @see #removeOnUnhandledKeyEventListener 29808 */ addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)29809 public void addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 29810 ArrayList<OnUnhandledKeyEventListener> listeners = getListenerInfo().mUnhandledKeyListeners; 29811 if (listeners == null) { 29812 listeners = new ArrayList<>(); 29813 getListenerInfo().mUnhandledKeyListeners = listeners; 29814 } 29815 listeners.add(listener); 29816 if (listeners.size() == 1 && mParent instanceof ViewGroup) { 29817 ((ViewGroup) mParent).incrementChildUnhandledKeyListeners(); 29818 } 29819 } 29820 29821 /** 29822 * Removes a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 29823 * UI thread. 29824 * 29825 * @param listener a receiver of unhandled {@link KeyEvent}s. 29826 * @see #addOnUnhandledKeyEventListener 29827 */ removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)29828 public void removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 29829 if (mListenerInfo != null) { 29830 if (mListenerInfo.mUnhandledKeyListeners != null 29831 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 29832 mListenerInfo.mUnhandledKeyListeners.remove(listener); 29833 if (mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 29834 mListenerInfo.mUnhandledKeyListeners = null; 29835 if (mParent instanceof ViewGroup) { 29836 ((ViewGroup) mParent).decrementChildUnhandledKeyListeners(); 29837 } 29838 } 29839 } 29840 } 29841 } 29842 } 29843