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.view.ViewRootImpl.NEW_INSETS_MODE_FULL; 21 import static android.view.accessibility.AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED; 22 23 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS; 24 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS; 25 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP; 26 import static com.android.internal.util.FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION; 27 28 import static java.lang.Math.max; 29 30 import android.animation.AnimatorInflater; 31 import android.animation.StateListAnimator; 32 import android.annotation.AttrRes; 33 import android.annotation.CallSuper; 34 import android.annotation.ColorInt; 35 import android.annotation.DrawableRes; 36 import android.annotation.FloatRange; 37 import android.annotation.IdRes; 38 import android.annotation.IntDef; 39 import android.annotation.IntRange; 40 import android.annotation.LayoutRes; 41 import android.annotation.NonNull; 42 import android.annotation.Nullable; 43 import android.annotation.Size; 44 import android.annotation.StyleRes; 45 import android.annotation.TestApi; 46 import android.annotation.UiThread; 47 import android.compat.annotation.UnsupportedAppUsage; 48 import android.content.AutofillOptions; 49 import android.content.ClipData; 50 import android.content.Context; 51 import android.content.ContextWrapper; 52 import android.content.Intent; 53 import android.content.res.ColorStateList; 54 import android.content.res.Configuration; 55 import android.content.res.Resources; 56 import android.content.res.TypedArray; 57 import android.graphics.Bitmap; 58 import android.graphics.BlendMode; 59 import android.graphics.Canvas; 60 import android.graphics.Color; 61 import android.graphics.Insets; 62 import android.graphics.Interpolator; 63 import android.graphics.LinearGradient; 64 import android.graphics.Matrix; 65 import android.graphics.Outline; 66 import android.graphics.Paint; 67 import android.graphics.PixelFormat; 68 import android.graphics.Point; 69 import android.graphics.PorterDuff; 70 import android.graphics.PorterDuffXfermode; 71 import android.graphics.RecordingCanvas; 72 import android.graphics.Rect; 73 import android.graphics.RectF; 74 import android.graphics.Region; 75 import android.graphics.RenderNode; 76 import android.graphics.Shader; 77 import android.graphics.drawable.ColorDrawable; 78 import android.graphics.drawable.Drawable; 79 import android.graphics.drawable.GradientDrawable; 80 import android.hardware.display.DisplayManagerGlobal; 81 import android.net.Uri; 82 import android.os.Build; 83 import android.os.Build.VERSION_CODES; 84 import android.os.Bundle; 85 import android.os.Handler; 86 import android.os.IBinder; 87 import android.os.Message; 88 import android.os.Parcel; 89 import android.os.Parcelable; 90 import android.os.RemoteException; 91 import android.os.SystemClock; 92 import android.os.Trace; 93 import android.sysprop.DisplayProperties; 94 import android.text.InputType; 95 import android.text.TextUtils; 96 import android.util.AttributeSet; 97 import android.util.FloatProperty; 98 import android.util.LayoutDirection; 99 import android.util.Log; 100 import android.util.LongSparseLongArray; 101 import android.util.Pair; 102 import android.util.Pools.SynchronizedPool; 103 import android.util.Property; 104 import android.util.SparseArray; 105 import android.util.SparseIntArray; 106 import android.util.StateSet; 107 import android.util.SuperNotCalledException; 108 import android.util.TypedValue; 109 import android.view.AccessibilityIterators.CharacterTextSegmentIterator; 110 import android.view.AccessibilityIterators.ParagraphTextSegmentIterator; 111 import android.view.AccessibilityIterators.TextSegmentIterator; 112 import android.view.AccessibilityIterators.WordTextSegmentIterator; 113 import android.view.ContextMenu.ContextMenuInfo; 114 import android.view.InputDevice.InputSourceClass; 115 import android.view.Window.OnContentApplyWindowInsetsListener; 116 import android.view.WindowInsets.Type; 117 import android.view.WindowInsetsAnimation.Bounds; 118 import android.view.WindowManager.LayoutParams; 119 import android.view.accessibility.AccessibilityEvent; 120 import android.view.accessibility.AccessibilityEventSource; 121 import android.view.accessibility.AccessibilityManager; 122 import android.view.accessibility.AccessibilityNodeIdManager; 123 import android.view.accessibility.AccessibilityNodeInfo; 124 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; 125 import android.view.accessibility.AccessibilityNodeProvider; 126 import android.view.accessibility.AccessibilityWindowInfo; 127 import android.view.animation.Animation; 128 import android.view.animation.AnimationUtils; 129 import android.view.animation.Transformation; 130 import android.view.autofill.AutofillId; 131 import android.view.autofill.AutofillManager; 132 import android.view.autofill.AutofillValue; 133 import android.view.contentcapture.ContentCaptureContext; 134 import android.view.contentcapture.ContentCaptureManager; 135 import android.view.contentcapture.ContentCaptureSession; 136 import android.view.inputmethod.EditorInfo; 137 import android.view.inputmethod.InputConnection; 138 import android.view.inspector.InspectableProperty; 139 import android.view.inspector.InspectableProperty.EnumEntry; 140 import android.view.inspector.InspectableProperty.FlagEntry; 141 import android.widget.Checkable; 142 import android.widget.FrameLayout; 143 import android.widget.ScrollBarDrawable; 144 145 import com.android.internal.R; 146 import com.android.internal.util.FrameworkStatsLog; 147 import com.android.internal.view.ScrollCaptureInternal; 148 import com.android.internal.view.TooltipPopup; 149 import com.android.internal.view.menu.MenuBuilder; 150 import com.android.internal.widget.ScrollBarUtils; 151 152 import com.google.android.collect.Lists; 153 import com.google.android.collect.Maps; 154 155 import java.lang.annotation.Retention; 156 import java.lang.annotation.RetentionPolicy; 157 import java.lang.ref.WeakReference; 158 import java.lang.reflect.Field; 159 import java.lang.reflect.InvocationTargetException; 160 import java.lang.reflect.Method; 161 import java.lang.reflect.Modifier; 162 import java.util.ArrayList; 163 import java.util.Arrays; 164 import java.util.Calendar; 165 import java.util.Collection; 166 import java.util.Collections; 167 import java.util.HashMap; 168 import java.util.List; 169 import java.util.Locale; 170 import java.util.Map; 171 import java.util.Queue; 172 import java.util.concurrent.CopyOnWriteArrayList; 173 import java.util.concurrent.atomic.AtomicInteger; 174 import java.util.function.Predicate; 175 176 /** 177 * <p> 178 * This class represents the basic building block for user interface components. A View 179 * occupies a rectangular area on the screen and is responsible for drawing and 180 * event handling. View is the base class for <em>widgets</em>, which are 181 * used to create interactive UI components (buttons, text fields, etc.). The 182 * {@link android.view.ViewGroup} subclass is the base class for <em>layouts</em>, which 183 * are invisible containers that hold other Views (or other ViewGroups) and define 184 * their layout properties. 185 * </p> 186 * 187 * <div class="special reference"> 188 * <h3>Developer Guides</h3> 189 * <p>For information about using this class to develop your application's user interface, 190 * read the <a href="{@docRoot}guide/topics/ui/index.html">User Interface</a> developer guide. 191 * </div> 192 * 193 * <a name="Using"></a> 194 * <h3>Using Views</h3> 195 * <p> 196 * All of the views in a window are arranged in a single tree. You can add views 197 * either from code or by specifying a tree of views in one or more XML layout 198 * files. There are many specialized subclasses of views that act as controls or 199 * are capable of displaying text, images, or other content. 200 * </p> 201 * <p> 202 * Once you have created a tree of views, there are typically a few types of 203 * common operations you may wish to perform: 204 * <ul> 205 * <li><strong>Set properties:</strong> for example setting the text of a 206 * {@link android.widget.TextView}. The available properties and the methods 207 * that set them will vary among the different subclasses of views. Note that 208 * properties that are known at build time can be set in the XML layout 209 * files.</li> 210 * <li><strong>Set focus:</strong> The framework will handle moving focus in 211 * response to user input. To force focus to a specific view, call 212 * {@link #requestFocus}.</li> 213 * <li><strong>Set up listeners:</strong> Views allow clients to set listeners 214 * that will be notified when something interesting happens to the view. For 215 * example, all views will let you set a listener to be notified when the view 216 * gains or loses focus. You can register such a listener using 217 * {@link #setOnFocusChangeListener(android.view.View.OnFocusChangeListener)}. 218 * Other view subclasses offer more specialized listeners. For example, a Button 219 * exposes a listener to notify clients when the button is clicked.</li> 220 * <li><strong>Set visibility:</strong> You can hide or show views using 221 * {@link #setVisibility(int)}.</li> 222 * </ul> 223 * </p> 224 * <p><em> 225 * Note: The Android framework is responsible for measuring, laying out and 226 * drawing views. You should not call methods that perform these actions on 227 * views yourself unless you are actually implementing a 228 * {@link android.view.ViewGroup}. 229 * </em></p> 230 * 231 * <a name="Lifecycle"></a> 232 * <h3>Implementing a Custom View</h3> 233 * 234 * <p> 235 * To implement a custom view, you will usually begin by providing overrides for 236 * some of the standard methods that the framework calls on all views. You do 237 * not need to override all of these methods. In fact, you can start by just 238 * overriding {@link #onDraw(android.graphics.Canvas)}. 239 * <table border="2" width="85%" align="center" cellpadding="5"> 240 * <thead> 241 * <tr><th>Category</th> <th>Methods</th> <th>Description</th></tr> 242 * </thead> 243 * 244 * <tbody> 245 * <tr> 246 * <td rowspan="2">Creation</td> 247 * <td>Constructors</td> 248 * <td>There is a form of the constructor that are called when the view 249 * is created from code and a form that is called when the view is 250 * inflated from a layout file. The second form should parse and apply 251 * any attributes defined in the layout file. 252 * </td> 253 * </tr> 254 * <tr> 255 * <td><code>{@link #onFinishInflate()}</code></td> 256 * <td>Called after a view and all of its children has been inflated 257 * from XML.</td> 258 * </tr> 259 * 260 * <tr> 261 * <td rowspan="3">Layout</td> 262 * <td><code>{@link #onMeasure(int, int)}</code></td> 263 * <td>Called to determine the size requirements for this view and all 264 * of its children. 265 * </td> 266 * </tr> 267 * <tr> 268 * <td><code>{@link #onLayout(boolean, int, int, int, int)}</code></td> 269 * <td>Called when this view should assign a size and position to all 270 * of its children. 271 * </td> 272 * </tr> 273 * <tr> 274 * <td><code>{@link #onSizeChanged(int, int, int, int)}</code></td> 275 * <td>Called when the size of this view has changed. 276 * </td> 277 * </tr> 278 * 279 * <tr> 280 * <td>Drawing</td> 281 * <td><code>{@link #onDraw(android.graphics.Canvas)}</code></td> 282 * <td>Called when the view should render its content. 283 * </td> 284 * </tr> 285 * 286 * <tr> 287 * <td rowspan="4">Event processing</td> 288 * <td><code>{@link #onKeyDown(int, KeyEvent)}</code></td> 289 * <td>Called when a new hardware key event occurs. 290 * </td> 291 * </tr> 292 * <tr> 293 * <td><code>{@link #onKeyUp(int, KeyEvent)}</code></td> 294 * <td>Called when a hardware key up event occurs. 295 * </td> 296 * </tr> 297 * <tr> 298 * <td><code>{@link #onTrackballEvent(MotionEvent)}</code></td> 299 * <td>Called when a trackball motion event occurs. 300 * </td> 301 * </tr> 302 * <tr> 303 * <td><code>{@link #onTouchEvent(MotionEvent)}</code></td> 304 * <td>Called when a touch screen motion event occurs. 305 * </td> 306 * </tr> 307 * 308 * <tr> 309 * <td rowspan="2">Focus</td> 310 * <td><code>{@link #onFocusChanged(boolean, int, android.graphics.Rect)}</code></td> 311 * <td>Called when the view gains or loses focus. 312 * </td> 313 * </tr> 314 * 315 * <tr> 316 * <td><code>{@link #onWindowFocusChanged(boolean)}</code></td> 317 * <td>Called when the window containing the view gains or loses focus. 318 * </td> 319 * </tr> 320 * 321 * <tr> 322 * <td rowspan="3">Attaching</td> 323 * <td><code>{@link #onAttachedToWindow()}</code></td> 324 * <td>Called when the view is attached to a window. 325 * </td> 326 * </tr> 327 * 328 * <tr> 329 * <td><code>{@link #onDetachedFromWindow}</code></td> 330 * <td>Called when the view is detached from its window. 331 * </td> 332 * </tr> 333 * 334 * <tr> 335 * <td><code>{@link #onWindowVisibilityChanged(int)}</code></td> 336 * <td>Called when the visibility of the window containing the view 337 * has changed. 338 * </td> 339 * </tr> 340 * </tbody> 341 * 342 * </table> 343 * </p> 344 * 345 * <a name="IDs"></a> 346 * <h3>IDs</h3> 347 * Views may have an integer id associated with them. These ids are typically 348 * assigned in the layout XML files, and are used to find specific views within 349 * the view tree. A common pattern is to: 350 * <ul> 351 * <li>Define a Button in the layout file and assign it a unique ID. 352 * <pre> 353 * <Button 354 * android:id="@+id/my_button" 355 * android:layout_width="wrap_content" 356 * android:layout_height="wrap_content" 357 * android:text="@string/my_button_text"/> 358 * </pre></li> 359 * <li>From the onCreate method of an Activity, find the Button 360 * <pre class="prettyprint"> 361 * Button myButton = findViewById(R.id.my_button); 362 * </pre></li> 363 * </ul> 364 * <p> 365 * View IDs need not be unique throughout the tree, but it is good practice to 366 * ensure that they are at least unique within the part of the tree you are 367 * searching. 368 * </p> 369 * 370 * <a name="Position"></a> 371 * <h3>Position</h3> 372 * <p> 373 * The geometry of a view is that of a rectangle. A view has a location, 374 * expressed as a pair of <em>left</em> and <em>top</em> coordinates, and 375 * two dimensions, expressed as a width and a height. The unit for location 376 * and dimensions is the pixel. 377 * </p> 378 * 379 * <p> 380 * It is possible to retrieve the location of a view by invoking the methods 381 * {@link #getLeft()} and {@link #getTop()}. The former returns the left, or X, 382 * coordinate of the rectangle representing the view. The latter returns the 383 * top, or Y, coordinate of the rectangle representing the view. These methods 384 * both return the location of the view relative to its parent. For instance, 385 * when getLeft() returns 20, that means the view is located 20 pixels to the 386 * right of the left edge of its direct parent. 387 * </p> 388 * 389 * <p> 390 * In addition, several convenience methods are offered to avoid unnecessary 391 * computations, namely {@link #getRight()} and {@link #getBottom()}. 392 * These methods return the coordinates of the right and bottom edges of the 393 * rectangle representing the view. For instance, calling {@link #getRight()} 394 * is similar to the following computation: <code>getLeft() + getWidth()</code> 395 * (see <a href="#SizePaddingMargins">Size</a> for more information about the width.) 396 * </p> 397 * 398 * <a name="SizePaddingMargins"></a> 399 * <h3>Size, padding and margins</h3> 400 * <p> 401 * The size of a view is expressed with a width and a height. A view actually 402 * possess two pairs of width and height values. 403 * </p> 404 * 405 * <p> 406 * The first pair is known as <em>measured width</em> and 407 * <em>measured height</em>. These dimensions define how big a view wants to be 408 * within its parent (see <a href="#Layout">Layout</a> for more details.) The 409 * measured dimensions can be obtained by calling {@link #getMeasuredWidth()} 410 * and {@link #getMeasuredHeight()}. 411 * </p> 412 * 413 * <p> 414 * The second pair is simply known as <em>width</em> and <em>height</em>, or 415 * sometimes <em>drawing width</em> and <em>drawing height</em>. These 416 * dimensions define the actual size of the view on screen, at drawing time and 417 * after layout. These values may, but do not have to, be different from the 418 * measured width and height. The width and height can be obtained by calling 419 * {@link #getWidth()} and {@link #getHeight()}. 420 * </p> 421 * 422 * <p> 423 * To measure its dimensions, a view takes into account its padding. The padding 424 * is expressed in pixels for the left, top, right and bottom parts of the view. 425 * Padding can be used to offset the content of the view by a specific amount of 426 * pixels. For instance, a left padding of 2 will push the view's content by 427 * 2 pixels to the right of the left edge. Padding can be set using the 428 * {@link #setPadding(int, int, int, int)} or {@link #setPaddingRelative(int, int, int, int)} 429 * method and queried by calling {@link #getPaddingLeft()}, {@link #getPaddingTop()}, 430 * {@link #getPaddingRight()}, {@link #getPaddingBottom()}, {@link #getPaddingStart()}, 431 * {@link #getPaddingEnd()}. 432 * </p> 433 * 434 * <p> 435 * Even though a view can define a padding, it does not provide any support for 436 * margins. However, view groups provide such a support. Refer to 437 * {@link android.view.ViewGroup} and 438 * {@link android.view.ViewGroup.MarginLayoutParams} for further information. 439 * </p> 440 * 441 * <a name="Layout"></a> 442 * <h3>Layout</h3> 443 * <p> 444 * Layout is a two pass process: a measure pass and a layout pass. The measuring 445 * pass is implemented in {@link #measure(int, int)} and is a top-down traversal 446 * of the view tree. Each view pushes dimension specifications down the tree 447 * during the recursion. At the end of the measure pass, every view has stored 448 * its measurements. The second pass happens in 449 * {@link #layout(int,int,int,int)} and is also top-down. During 450 * this pass each parent is responsible for positioning all of its children 451 * using the sizes computed in the measure pass. 452 * </p> 453 * 454 * <p> 455 * When a view's measure() method returns, its {@link #getMeasuredWidth()} and 456 * {@link #getMeasuredHeight()} values must be set, along with those for all of 457 * that view's descendants. A view's measured width and measured height values 458 * must respect the constraints imposed by the view's parents. This guarantees 459 * that at the end of the measure pass, all parents accept all of their 460 * children's measurements. A parent view may call measure() more than once on 461 * its children. For example, the parent may measure each child once with 462 * unspecified dimensions to find out how big they want to be, then call 463 * measure() on them again with actual numbers if the sum of all the children's 464 * unconstrained sizes is too big or too small. 465 * </p> 466 * 467 * <p> 468 * The measure pass uses two classes to communicate dimensions. The 469 * {@link MeasureSpec} class is used by views to tell their parents how they 470 * want to be measured and positioned. The base LayoutParams class just 471 * describes how big the view wants to be for both width and height. For each 472 * dimension, it can specify one of: 473 * <ul> 474 * <li> an exact number 475 * <li>MATCH_PARENT, which means the view wants to be as big as its parent 476 * (minus padding) 477 * <li> WRAP_CONTENT, which means that the view wants to be just big enough to 478 * enclose its content (plus padding). 479 * </ul> 480 * There are subclasses of LayoutParams for different subclasses of ViewGroup. 481 * For example, AbsoluteLayout has its own subclass of LayoutParams which adds 482 * an X and Y value. 483 * </p> 484 * 485 * <p> 486 * MeasureSpecs are used to push requirements down the tree from parent to 487 * child. A MeasureSpec can be in one of three modes: 488 * <ul> 489 * <li>UNSPECIFIED: This is used by a parent to determine the desired dimension 490 * of a child view. For example, a LinearLayout may call measure() on its child 491 * with the height set to UNSPECIFIED and a width of EXACTLY 240 to find out how 492 * tall the child view wants to be given a width of 240 pixels. 493 * <li>EXACTLY: This is used by the parent to impose an exact size on the 494 * child. The child must use this size, and guarantee that all of its 495 * descendants will fit within this size. 496 * <li>AT_MOST: This is used by the parent to impose a maximum size on the 497 * child. The child must guarantee that it and all of its descendants will fit 498 * within this size. 499 * </ul> 500 * </p> 501 * 502 * <p> 503 * To initiate a layout, call {@link #requestLayout}. This method is typically 504 * called by a view on itself when it believes that it can no longer fit within 505 * its current bounds. 506 * </p> 507 * 508 * <a name="Drawing"></a> 509 * <h3>Drawing</h3> 510 * <p> 511 * Drawing is handled by walking the tree and recording the drawing commands of 512 * any View that needs to update. After this, the drawing commands of the 513 * entire tree are issued to screen, clipped to the newly damaged area. 514 * </p> 515 * 516 * <p> 517 * The tree is largely recorded and drawn in order, with parents drawn before 518 * (i.e., behind) their children, with siblings drawn in the order they appear 519 * in the tree. If you set a background drawable for a View, then the View will 520 * draw it before calling back to its <code>onDraw()</code> method. The child 521 * drawing order can be overridden with 522 * {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean) custom child drawing order} 523 * in a ViewGroup, and with {@link #setZ(float)} custom Z values} set on Views. 524 * </p> 525 * 526 * <p> 527 * To force a view to draw, call {@link #invalidate()}. 528 * </p> 529 * 530 * <a name="EventHandlingThreading"></a> 531 * <h3>Event Handling and Threading</h3> 532 * <p> 533 * The basic cycle of a view is as follows: 534 * <ol> 535 * <li>An event comes in and is dispatched to the appropriate view. The view 536 * handles the event and notifies any listeners.</li> 537 * <li>If in the course of processing the event, the view's bounds may need 538 * to be changed, the view will call {@link #requestLayout()}.</li> 539 * <li>Similarly, if in the course of processing the event the view's appearance 540 * may need to be changed, the view will call {@link #invalidate()}.</li> 541 * <li>If either {@link #requestLayout()} or {@link #invalidate()} were called, 542 * the framework will take care of measuring, laying out, and drawing the tree 543 * as appropriate.</li> 544 * </ol> 545 * </p> 546 * 547 * <p><em>Note: The entire view tree is single threaded. You must always be on 548 * the UI thread when calling any method on any view.</em> 549 * If you are doing work on other threads and want to update the state of a view 550 * from that thread, you should use a {@link Handler}. 551 * </p> 552 * 553 * <a name="FocusHandling"></a> 554 * <h3>Focus Handling</h3> 555 * <p> 556 * The framework will handle routine focus movement in response to user input. 557 * This includes changing the focus as views are removed or hidden, or as new 558 * views become available. Views indicate their willingness to take focus 559 * through the {@link #isFocusable} method. To change whether a view can take 560 * focus, call {@link #setFocusable(boolean)}. When in touch mode (see notes below) 561 * views indicate whether they still would like focus via {@link #isFocusableInTouchMode} 562 * and can change this via {@link #setFocusableInTouchMode(boolean)}. 563 * </p> 564 * <p> 565 * Focus movement is based on an algorithm which finds the nearest neighbor in a 566 * given direction. In rare cases, the default algorithm may not match the 567 * intended behavior of the developer. In these situations, you can provide 568 * explicit overrides by using these XML attributes in the layout file: 569 * <pre> 570 * nextFocusDown 571 * nextFocusLeft 572 * nextFocusRight 573 * nextFocusUp 574 * </pre> 575 * </p> 576 * 577 * 578 * <p> 579 * To get a particular view to take focus, call {@link #requestFocus()}. 580 * </p> 581 * 582 * <a name="TouchMode"></a> 583 * <h3>Touch Mode</h3> 584 * <p> 585 * When a user is navigating a user interface via directional keys such as a D-pad, it is 586 * necessary to give focus to actionable items such as buttons so the user can see 587 * what will take input. If the device has touch capabilities, however, and the user 588 * begins interacting with the interface by touching it, it is no longer necessary to 589 * always highlight, or give focus to, a particular view. This motivates a mode 590 * for interaction named 'touch mode'. 591 * </p> 592 * <p> 593 * For a touch capable device, once the user touches the screen, the device 594 * will enter touch mode. From this point onward, only views for which 595 * {@link #isFocusableInTouchMode} is true will be focusable, such as text editing widgets. 596 * Other views that are touchable, like buttons, will not take focus when touched; they will 597 * only fire the on click listeners. 598 * </p> 599 * <p> 600 * Any time a user hits a directional key, such as a D-pad direction, the view device will 601 * exit touch mode, and find a view to take focus, so that the user may resume interacting 602 * with the user interface without touching the screen again. 603 * </p> 604 * <p> 605 * The touch mode state is maintained across {@link android.app.Activity}s. Call 606 * {@link #isInTouchMode} to see whether the device is currently in touch mode. 607 * </p> 608 * 609 * <a name="Scrolling"></a> 610 * <h3>Scrolling</h3> 611 * <p> 612 * The framework provides basic support for views that wish to internally 613 * scroll their content. This includes keeping track of the X and Y scroll 614 * offset as well as mechanisms for drawing scrollbars. See 615 * {@link #scrollBy(int, int)}, {@link #scrollTo(int, int)}, and 616 * {@link #awakenScrollBars()} for more details. 617 * </p> 618 * 619 * <a name="Tags"></a> 620 * <h3>Tags</h3> 621 * <p> 622 * Unlike IDs, tags are not used to identify views. Tags are essentially an 623 * extra piece of information that can be associated with a view. They are most 624 * often used as a convenience to store data related to views in the views 625 * themselves rather than by putting them in a separate structure. 626 * </p> 627 * <p> 628 * Tags may be specified with character sequence values in layout XML as either 629 * a single tag using the {@link android.R.styleable#View_tag android:tag} 630 * attribute or multiple tags using the {@code <tag>} child element: 631 * <pre> 632 * <View ... 633 * android:tag="@string/mytag_value" /> 634 * <View ...> 635 * <tag android:id="@+id/mytag" 636 * android:value="@string/mytag_value" /> 637 * </View> 638 * </pre> 639 * </p> 640 * <p> 641 * Tags may also be specified with arbitrary objects from code using 642 * {@link #setTag(Object)} or {@link #setTag(int, Object)}. 643 * </p> 644 * 645 * <a name="Themes"></a> 646 * <h3>Themes</h3> 647 * <p> 648 * By default, Views are created using the theme of the Context object supplied 649 * to their constructor; however, a different theme may be specified by using 650 * the {@link android.R.styleable#View_theme android:theme} attribute in layout 651 * XML or by passing a {@link ContextThemeWrapper} to the constructor from 652 * code. 653 * </p> 654 * <p> 655 * When the {@link android.R.styleable#View_theme android:theme} attribute is 656 * used in XML, the specified theme is applied on top of the inflation 657 * context's theme (see {@link LayoutInflater}) and used for the view itself as 658 * well as any child elements. 659 * </p> 660 * <p> 661 * In the following example, both views will be created using the Material dark 662 * color scheme; however, because an overlay theme is used which only defines a 663 * subset of attributes, the value of 664 * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on 665 * the inflation context's theme (e.g. the Activity theme) will be preserved. 666 * <pre> 667 * <LinearLayout 668 * ... 669 * android:theme="@android:theme/ThemeOverlay.Material.Dark"> 670 * <View ...> 671 * </LinearLayout> 672 * </pre> 673 * </p> 674 * 675 * <a name="Properties"></a> 676 * <h3>Properties</h3> 677 * <p> 678 * The View class exposes an {@link #ALPHA} property, as well as several transform-related 679 * properties, such as {@link #TRANSLATION_X} and {@link #TRANSLATION_Y}. These properties are 680 * available both in the {@link Property} form as well as in similarly-named setter/getter 681 * methods (such as {@link #setAlpha(float)} for {@link #ALPHA}). These properties can 682 * be used to set persistent state associated with these rendering-related properties on the view. 683 * The properties and methods can also be used in conjunction with 684 * {@link android.animation.Animator Animator}-based animations, described more in the 685 * <a href="#Animation">Animation</a> section. 686 * </p> 687 * 688 * <a name="Animation"></a> 689 * <h3>Animation</h3> 690 * <p> 691 * Starting with Android 3.0, the preferred way of animating views is to use the 692 * {@link android.animation} package APIs. These {@link android.animation.Animator Animator}-based 693 * classes change actual properties of the View object, such as {@link #setAlpha(float) alpha} and 694 * {@link #setTranslationX(float) translationX}. This behavior is contrasted to that of the pre-3.0 695 * {@link android.view.animation.Animation Animation}-based classes, which instead animate only 696 * how the view is drawn on the display. In particular, the {@link ViewPropertyAnimator} class 697 * makes animating these View properties particularly easy and efficient. 698 * </p> 699 * <p> 700 * Alternatively, you can use the pre-3.0 animation classes to animate how Views are rendered. 701 * You can attach an {@link Animation} object to a view using 702 * {@link #setAnimation(Animation)} or 703 * {@link #startAnimation(Animation)}. The animation can alter the scale, 704 * rotation, translation and alpha of a view over time. If the animation is 705 * attached to a view that has children, the animation will affect the entire 706 * subtree rooted by that node. When an animation is started, the framework will 707 * take care of redrawing the appropriate views until the animation completes. 708 * </p> 709 * 710 * <a name="Security"></a> 711 * <h3>Security</h3> 712 * <p> 713 * Sometimes it is essential that an application be able to verify that an action 714 * is being performed with the full knowledge and consent of the user, such as 715 * granting a permission request, making a purchase or clicking on an advertisement. 716 * Unfortunately, a malicious application could try to spoof the user into 717 * performing these actions, unaware, by concealing the intended purpose of the view. 718 * As a remedy, the framework offers a touch filtering mechanism that can be used to 719 * improve the security of views that provide access to sensitive functionality. 720 * </p><p> 721 * To enable touch filtering, call {@link #setFilterTouchesWhenObscured(boolean)} or set the 722 * android:filterTouchesWhenObscured layout attribute to true. When enabled, the framework 723 * will discard touches that are received whenever the view's window is obscured by 724 * another visible window. As a result, the view will not receive touches whenever a 725 * toast, dialog or other window appears above the view's window. 726 * </p><p> 727 * For more fine-grained control over security, consider overriding the 728 * {@link #onFilterTouchEventForSecurity(MotionEvent)} method to implement your own 729 * security policy. See also {@link MotionEvent#FLAG_WINDOW_IS_OBSCURED}. 730 * </p> 731 * 732 * @attr ref android.R.styleable#View_accessibilityHeading 733 * @attr ref android.R.styleable#View_alpha 734 * @attr ref android.R.styleable#View_background 735 * @attr ref android.R.styleable#View_clickable 736 * @attr ref android.R.styleable#View_contentDescription 737 * @attr ref android.R.styleable#View_drawingCacheQuality 738 * @attr ref android.R.styleable#View_duplicateParentState 739 * @attr ref android.R.styleable#View_id 740 * @attr ref android.R.styleable#View_requiresFadingEdge 741 * @attr ref android.R.styleable#View_fadeScrollbars 742 * @attr ref android.R.styleable#View_fadingEdgeLength 743 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 744 * @attr ref android.R.styleable#View_fitsSystemWindows 745 * @attr ref android.R.styleable#View_isScrollContainer 746 * @attr ref android.R.styleable#View_focusable 747 * @attr ref android.R.styleable#View_focusableInTouchMode 748 * @attr ref android.R.styleable#View_focusedByDefault 749 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 750 * @attr ref android.R.styleable#View_keepScreenOn 751 * @attr ref android.R.styleable#View_keyboardNavigationCluster 752 * @attr ref android.R.styleable#View_layerType 753 * @attr ref android.R.styleable#View_layoutDirection 754 * @attr ref android.R.styleable#View_longClickable 755 * @attr ref android.R.styleable#View_minHeight 756 * @attr ref android.R.styleable#View_minWidth 757 * @attr ref android.R.styleable#View_nextClusterForward 758 * @attr ref android.R.styleable#View_nextFocusDown 759 * @attr ref android.R.styleable#View_nextFocusLeft 760 * @attr ref android.R.styleable#View_nextFocusRight 761 * @attr ref android.R.styleable#View_nextFocusUp 762 * @attr ref android.R.styleable#View_onClick 763 * @attr ref android.R.styleable#View_outlineSpotShadowColor 764 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 765 * @attr ref android.R.styleable#View_padding 766 * @attr ref android.R.styleable#View_paddingHorizontal 767 * @attr ref android.R.styleable#View_paddingVertical 768 * @attr ref android.R.styleable#View_paddingBottom 769 * @attr ref android.R.styleable#View_paddingLeft 770 * @attr ref android.R.styleable#View_paddingRight 771 * @attr ref android.R.styleable#View_paddingTop 772 * @attr ref android.R.styleable#View_paddingStart 773 * @attr ref android.R.styleable#View_paddingEnd 774 * @attr ref android.R.styleable#View_saveEnabled 775 * @attr ref android.R.styleable#View_rotation 776 * @attr ref android.R.styleable#View_rotationX 777 * @attr ref android.R.styleable#View_rotationY 778 * @attr ref android.R.styleable#View_scaleX 779 * @attr ref android.R.styleable#View_scaleY 780 * @attr ref android.R.styleable#View_scrollX 781 * @attr ref android.R.styleable#View_scrollY 782 * @attr ref android.R.styleable#View_scrollbarSize 783 * @attr ref android.R.styleable#View_scrollbarStyle 784 * @attr ref android.R.styleable#View_scrollbars 785 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 786 * @attr ref android.R.styleable#View_scrollbarFadeDuration 787 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 788 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 789 * @attr ref android.R.styleable#View_scrollbarThumbVertical 790 * @attr ref android.R.styleable#View_scrollbarTrackVertical 791 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack 792 * @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack 793 * @attr ref android.R.styleable#View_stateListAnimator 794 * @attr ref android.R.styleable#View_transitionName 795 * @attr ref android.R.styleable#View_soundEffectsEnabled 796 * @attr ref android.R.styleable#View_tag 797 * @attr ref android.R.styleable#View_textAlignment 798 * @attr ref android.R.styleable#View_textDirection 799 * @attr ref android.R.styleable#View_transformPivotX 800 * @attr ref android.R.styleable#View_transformPivotY 801 * @attr ref android.R.styleable#View_translationX 802 * @attr ref android.R.styleable#View_translationY 803 * @attr ref android.R.styleable#View_translationZ 804 * @attr ref android.R.styleable#View_visibility 805 * @attr ref android.R.styleable#View_theme 806 * 807 * @see android.view.ViewGroup 808 */ 809 @UiThread 810 public class View implements Drawable.Callback, KeyEvent.Callback, 811 AccessibilityEventSource { 812 @UnsupportedAppUsage 813 private static final boolean DBG = false; 814 815 /** @hide */ 816 public static boolean DEBUG_DRAW = false; 817 818 /** 819 * The logging tag used by this class with android.util.Log. 820 */ 821 protected static final String VIEW_LOG_TAG = "View"; 822 823 /** 824 * The logging tag used by this class when logging verbose, autofill-related messages. 825 */ 826 // NOTE: We cannot use android.view.autofill.Helper.sVerbose because that variable is not 827 // set if a session is not started. 828 private static final String AUTOFILL_LOG_TAG = "View.Autofill"; 829 830 /** 831 * The logging tag used by this class when logging content capture-related messages. 832 */ 833 private static final String CONTENT_CAPTURE_LOG_TAG = "View.ContentCapture"; 834 835 private static final boolean DEBUG_CONTENT_CAPTURE = false; 836 837 /** 838 * When set to true, this view will save its attribute data. 839 * 840 * @hide 841 */ 842 public static boolean sDebugViewAttributes = false; 843 844 /** 845 * When set to this application package view will save its attribute data. 846 * 847 * @hide 848 */ 849 public static String sDebugViewAttributesApplicationPackage; 850 851 /** 852 * Used to mark a View that has no ID. 853 */ 854 public static final int NO_ID = -1; 855 856 /** 857 * Last ID that is given to Views that are no part of activities. 858 * 859 * {@hide} 860 */ 861 public static final int LAST_APP_AUTOFILL_ID = Integer.MAX_VALUE / 2; 862 863 /** 864 * Attribute to find the autofilled highlight 865 * 866 * @see #getAutofilledDrawable() 867 */ 868 private static final int[] AUTOFILL_HIGHLIGHT_ATTR = 869 new int[]{android.R.attr.autofilledHighlight}; 870 871 /** 872 * Signals that compatibility booleans have been initialized according to 873 * target SDK versions. 874 */ 875 private static boolean sCompatibilityDone = false; 876 877 /** 878 * Use the old (broken) way of building MeasureSpecs. 879 */ 880 private static boolean sUseBrokenMakeMeasureSpec = false; 881 882 /** 883 * Always return a size of 0 for MeasureSpec values with a mode of UNSPECIFIED 884 */ 885 static boolean sUseZeroUnspecifiedMeasureSpec = false; 886 887 /** 888 * Ignore any optimizations using the measure cache. 889 */ 890 private static boolean sIgnoreMeasureCache = false; 891 892 /** 893 * Ignore an optimization that skips unnecessary EXACTLY layout passes. 894 */ 895 private static boolean sAlwaysRemeasureExactly = false; 896 897 /** 898 * Allow setForeground/setBackground to be called (and ignored) on a textureview, 899 * without throwing 900 */ 901 static boolean sTextureViewIgnoresDrawableSetters = false; 902 903 /** 904 * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend 905 * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to 906 * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API 907 * check is implemented for backwards compatibility. 908 * 909 * {@hide} 910 */ 911 protected static boolean sPreserveMarginParamsInLayoutParamConversion; 912 913 /** 914 * Prior to N, when drag enters into child of a view that has already received an 915 * ACTION_DRAG_ENTERED event, the parent doesn't get a ACTION_DRAG_EXITED event. 916 * ACTION_DRAG_LOCATION and ACTION_DROP were delivered to the parent of a view that returned 917 * false from its event handler for these events. 918 * Starting from N, the parent will get ACTION_DRAG_EXITED event before the child gets its 919 * ACTION_DRAG_ENTERED. ACTION_DRAG_LOCATION and ACTION_DROP are never propagated to the parent. 920 * sCascadedDragDrop is true for pre-N apps for backwards compatibility implementation. 921 */ 922 static boolean sCascadedDragDrop; 923 924 /** 925 * Prior to O, auto-focusable didn't exist and widgets such as ListView use hasFocusable 926 * to determine things like whether or not to permit item click events. We can't break 927 * apps that do this just because more things (clickable things) are now auto-focusable 928 * and they would get different results, so give old behavior to old apps. 929 */ 930 static boolean sHasFocusableExcludeAutoFocusable; 931 932 /** 933 * Prior to O, auto-focusable didn't exist and views marked as clickable weren't implicitly 934 * made focusable by default. As a result, apps could (incorrectly) change the clickable 935 * setting of views off the UI thread. Now that clickable can effect the focusable state, 936 * changing the clickable attribute off the UI thread will cause an exception (since changing 937 * the focusable state checks). In order to prevent apps from crashing, we will handle this 938 * specific case and just not notify parents on new focusables resulting from marking views 939 * clickable from outside the UI thread. 940 */ 941 private static boolean sAutoFocusableOffUIThreadWontNotifyParents; 942 943 /** 944 * Prior to P things like setScaleX() allowed passing float values that were bogus such as 945 * Float.NaN. If the app is targetting P or later then passing these values will result in an 946 * exception being thrown. If the app is targetting an earlier SDK version, then we will 947 * silently clamp these values to avoid crashes elsewhere when the rendering code hits 948 * these bogus values. 949 */ 950 private static boolean sThrowOnInvalidFloatProperties; 951 952 /** 953 * Prior to P, {@code #startDragAndDrop} accepts a builder which produces an empty drag shadow. 954 * Currently zero size SurfaceControl cannot be created thus we create a dummy 1x1 surface 955 * instead. 956 */ 957 private static boolean sAcceptZeroSizeDragShadow; 958 959 /** 960 * Prior to R, {@link #dispatchApplyWindowInsets} had an issue: 961 * <p>The modified insets changed by {@link #onApplyWindowInsets} were passed to the 962 * entire view hierarchy in prefix order, including siblings as well as siblings of parents 963 * further down the hierarchy. This violates the basic concepts of the view hierarchy, and 964 * thus, the hierarchical dispatching mechanism was hard to use for apps. 965 * <p> 966 * In order to make window inset dispatching work properly, we dispatch window insets 967 * in the view hierarchy in a proper hierarchical manner if this flag is set to {@code false}. 968 */ 969 static boolean sBrokenInsetsDispatch; 970 971 /** 972 * Prior to Q, calling 973 * {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} 974 * did not call update the window format so the opacity of the background was not correctly 975 * applied to the window. Some applications rely on this misbehavior to work properly. 976 * <p> 977 * From Q, {@link com.android.internal.policy.DecorView#setBackgroundDrawable(Drawable)} is 978 * the same as {@link com.android.internal.policy.DecorView#setWindowBackground(Drawable)} 979 * which updates the window format. 980 * @hide 981 */ 982 protected static boolean sBrokenWindowBackground; 983 984 /** 985 * Prior to R, we were always forcing a layout of the entire hierarchy when insets changed from 986 * the server. This is inefficient and not all apps use it. Instead, we want to rely on apps 987 * calling {@link #requestLayout} when they need to relayout based on an insets change. 988 */ 989 static boolean sForceLayoutWhenInsetsChanged; 990 991 /** @hide */ 992 @IntDef({NOT_FOCUSABLE, FOCUSABLE, FOCUSABLE_AUTO}) 993 @Retention(RetentionPolicy.SOURCE) 994 public @interface Focusable {} 995 996 /** 997 * This view does not want keystrokes. 998 * <p> 999 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1000 * android:focusable}. 1001 */ 1002 public static final int NOT_FOCUSABLE = 0x00000000; 1003 1004 /** 1005 * This view wants keystrokes. 1006 * <p> 1007 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1008 * android:focusable}. 1009 */ 1010 public static final int FOCUSABLE = 0x00000001; 1011 1012 /** 1013 * This view determines focusability automatically. This is the default. 1014 * <p> 1015 * Use with {@link #setFocusable(int)} and <a href="#attr_android:focusable">{@code 1016 * android:focusable}. 1017 */ 1018 public static final int FOCUSABLE_AUTO = 0x00000010; 1019 1020 /** 1021 * Mask for use with setFlags indicating bits used for focus. 1022 */ 1023 private static final int FOCUSABLE_MASK = 0x00000011; 1024 1025 /** 1026 * This view will adjust its padding to fit sytem windows (e.g. status bar) 1027 */ 1028 private static final int FITS_SYSTEM_WINDOWS = 0x00000002; 1029 1030 /** @hide */ 1031 @IntDef({VISIBLE, INVISIBLE, GONE}) 1032 @Retention(RetentionPolicy.SOURCE) 1033 public @interface Visibility {} 1034 1035 /** 1036 * This view is visible. 1037 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1038 * android:visibility}. 1039 */ 1040 public static final int VISIBLE = 0x00000000; 1041 1042 /** 1043 * This view is invisible, but it still takes up space for layout purposes. 1044 * Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1045 * android:visibility}. 1046 */ 1047 public static final int INVISIBLE = 0x00000004; 1048 1049 /** 1050 * This view is invisible, and it doesn't take any space for layout 1051 * purposes. Use with {@link #setVisibility} and <a href="#attr_android:visibility">{@code 1052 * android:visibility}. 1053 */ 1054 public static final int GONE = 0x00000008; 1055 1056 /** 1057 * Mask for use with setFlags indicating bits used for visibility. 1058 * {@hide} 1059 */ 1060 static final int VISIBILITY_MASK = 0x0000000C; 1061 1062 private static final int[] VISIBILITY_FLAGS = {VISIBLE, INVISIBLE, GONE}; 1063 1064 /** 1065 * Hint indicating that this view can be autofilled with an email address. 1066 * 1067 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1068 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1069 * value should be <code>{@value #AUTOFILL_HINT_EMAIL_ADDRESS}</code>). 1070 * 1071 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1072 */ 1073 public static final String AUTOFILL_HINT_EMAIL_ADDRESS = "emailAddress"; 1074 1075 /** 1076 * Hint indicating that this view can be autofilled with a user's real name. 1077 * 1078 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1079 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1080 * value should be <code>{@value #AUTOFILL_HINT_NAME}</code>). 1081 * 1082 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1083 */ 1084 public static final String AUTOFILL_HINT_NAME = "name"; 1085 1086 /** 1087 * Hint indicating that this view can be autofilled with a username. 1088 * 1089 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1090 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1091 * value should be <code>{@value #AUTOFILL_HINT_USERNAME}</code>). 1092 * 1093 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1094 */ 1095 public static final String AUTOFILL_HINT_USERNAME = "username"; 1096 1097 /** 1098 * Hint indicating that this view can be autofilled with a password. 1099 * 1100 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1101 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1102 * value should be <code>{@value #AUTOFILL_HINT_PASSWORD}</code>). 1103 * 1104 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1105 */ 1106 public static final String AUTOFILL_HINT_PASSWORD = "password"; 1107 1108 /** 1109 * Hint indicating that this view can be autofilled with a phone number. 1110 * 1111 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1112 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1113 * value should be <code>{@value #AUTOFILL_HINT_PHONE}</code>). 1114 * 1115 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1116 */ 1117 public static final String AUTOFILL_HINT_PHONE = "phone"; 1118 1119 /** 1120 * Hint indicating that this view can be autofilled with a postal address. 1121 * 1122 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1123 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1124 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_ADDRESS}</code>). 1125 * 1126 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1127 */ 1128 public static final String AUTOFILL_HINT_POSTAL_ADDRESS = "postalAddress"; 1129 1130 /** 1131 * Hint indicating that this view can be autofilled with a postal code. 1132 * 1133 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1134 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1135 * value should be <code>{@value #AUTOFILL_HINT_POSTAL_CODE}</code>). 1136 * 1137 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1138 */ 1139 public static final String AUTOFILL_HINT_POSTAL_CODE = "postalCode"; 1140 1141 /** 1142 * Hint indicating that this view can be autofilled with a credit card number. 1143 * 1144 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1145 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1146 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_NUMBER}</code>). 1147 * 1148 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1149 */ 1150 public static final String AUTOFILL_HINT_CREDIT_CARD_NUMBER = "creditCardNumber"; 1151 1152 /** 1153 * Hint indicating that this view can be autofilled with a credit card security code. 1154 * 1155 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1156 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1157 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}</code>). 1158 * 1159 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1160 */ 1161 public static final String AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE = "creditCardSecurityCode"; 1162 1163 /** 1164 * Hint indicating that this view can be autofilled with a credit card expiration date. 1165 * 1166 * <p>It should be used when the credit card expiration date is represented by just one view; 1167 * if it is represented by more than one (for example, one view for the month and another view 1168 * for the year), then each of these views should use the hint specific for the unit 1169 * ({@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 1170 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}, 1171 * or {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}). 1172 * 1173 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1174 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1175 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}</code>). 1176 * 1177 * <p>When annotating a view with this hint, it's recommended to use a date autofill value to 1178 * avoid ambiguity when the autofill service provides a value for it. To understand why a 1179 * value can be ambiguous, consider "April of 2020", which could be represented as either of 1180 * the following options: 1181 * 1182 * <ul> 1183 * <li>{@code "04/2020"} 1184 * <li>{@code "4/2020"} 1185 * <li>{@code "2020/04"} 1186 * <li>{@code "2020/4"} 1187 * <li>{@code "April/2020"} 1188 * <li>{@code "Apr/2020"} 1189 * </ul> 1190 * 1191 * <p>You define a date autofill value for the view by overriding the following methods: 1192 * 1193 * <ol> 1194 * <li>{@link #getAutofillType()} to return {@link #AUTOFILL_TYPE_DATE}. 1195 * <li>{@link #getAutofillValue()} to return a 1196 * {@link AutofillValue#forDate(long) date autofillvalue}. 1197 * <li>{@link #autofill(AutofillValue)} to expect a data autofillvalue. 1198 * </ol> 1199 * 1200 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1201 */ 1202 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE = 1203 "creditCardExpirationDate"; 1204 1205 /** 1206 * Hint indicating that this view can be autofilled with a credit card expiration month. 1207 * 1208 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1209 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1210 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH}</code>). 1211 * 1212 * <p>When annotating a view with this hint, it's recommended to use a text autofill value 1213 * whose value is the numerical representation of the month, starting on {@code 1} to avoid 1214 * ambiguity when the autofill service provides a value for it. To understand why a 1215 * value can be ambiguous, consider "January", which could be represented as either of 1216 * 1217 * <ul> 1218 * <li>{@code "1"}: recommended way. 1219 * <li>{@code "0"}: if following the {@link Calendar#MONTH} convention. 1220 * <li>{@code "January"}: full name, in English. 1221 * <li>{@code "jan"}: abbreviated name, in English. 1222 * <li>{@code "Janeiro"}: full name, in another language. 1223 * </ul> 1224 * 1225 * <p>Another recommended approach is to use a date autofill value - see 1226 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE} for more details. 1227 * 1228 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1229 */ 1230 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH = 1231 "creditCardExpirationMonth"; 1232 1233 /** 1234 * Hint indicating that this view can be autofilled with a credit card expiration year. 1235 * 1236 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1237 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1238 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}</code>). 1239 * 1240 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1241 */ 1242 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR = 1243 "creditCardExpirationYear"; 1244 1245 /** 1246 * Hint indicating that this view can be autofilled with a credit card expiration day. 1247 * 1248 * <p>Can be used with either {@link #setAutofillHints(String[])} or 1249 * <a href="#attr_android:autofillHint"> {@code android:autofillHint}</a> (in which case the 1250 * value should be <code>{@value #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}</code>). 1251 * 1252 * <p>See {@link #setAutofillHints(String...)} for more info about autofill hints. 1253 */ 1254 public static final String AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY = "creditCardExpirationDay"; 1255 1256 /** 1257 * Hints for the autofill services that describes the content of the view. 1258 */ 1259 private @Nullable String[] mAutofillHints; 1260 1261 /** 1262 * Autofill id, lazily created on calls to {@link #getAutofillId()}. 1263 */ 1264 private AutofillId mAutofillId; 1265 1266 /** @hide */ 1267 @IntDef(prefix = { "AUTOFILL_TYPE_" }, value = { 1268 AUTOFILL_TYPE_NONE, 1269 AUTOFILL_TYPE_TEXT, 1270 AUTOFILL_TYPE_TOGGLE, 1271 AUTOFILL_TYPE_LIST, 1272 AUTOFILL_TYPE_DATE 1273 }) 1274 @Retention(RetentionPolicy.SOURCE) 1275 public @interface AutofillType {} 1276 1277 /** 1278 * Autofill type for views that cannot be autofilled. 1279 * 1280 * <p>Typically used when the view is read-only; for example, a text label. 1281 * 1282 * @see #getAutofillType() 1283 */ 1284 public static final int AUTOFILL_TYPE_NONE = 0; 1285 1286 /** 1287 * Autofill type for a text field, which is filled by a {@link CharSequence}. 1288 * 1289 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1290 * {@link AutofillValue#forText(CharSequence)}, and the value passed to autofill a 1291 * {@link View} can be fetched through {@link AutofillValue#getTextValue()}. 1292 * 1293 * @see #getAutofillType() 1294 */ 1295 public static final int AUTOFILL_TYPE_TEXT = 1; 1296 1297 /** 1298 * Autofill type for a togglable field, which is filled by a {@code boolean}. 1299 * 1300 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1301 * {@link AutofillValue#forToggle(boolean)}, and the value passed to autofill a 1302 * {@link View} can be fetched through {@link AutofillValue#getToggleValue()}. 1303 * 1304 * @see #getAutofillType() 1305 */ 1306 public static final int AUTOFILL_TYPE_TOGGLE = 2; 1307 1308 /** 1309 * Autofill type for a selection list field, which is filled by an {@code int} 1310 * representing the element index inside the list (starting at {@code 0}). 1311 * 1312 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1313 * {@link AutofillValue#forList(int)}, and the value passed to autofill a 1314 * {@link View} can be fetched through {@link AutofillValue#getListValue()}. 1315 * 1316 * <p>The available options in the selection list are typically provided by 1317 * {@link android.app.assist.AssistStructure.ViewNode#getAutofillOptions()}. 1318 * 1319 * @see #getAutofillType() 1320 */ 1321 public static final int AUTOFILL_TYPE_LIST = 3; 1322 1323 /** 1324 * Autofill type for a field that contains a date, which is represented by a long representing 1325 * the number of milliseconds since the standard base time known as "the epoch", namely 1326 * January 1, 1970, 00:00:00 GMT (see {@link java.util.Date#getTime()}. 1327 * 1328 * <p>{@link AutofillValue} instances for autofilling a {@link View} can be obtained through 1329 * {@link AutofillValue#forDate(long)}, and the values passed to 1330 * autofill a {@link View} can be fetched through {@link AutofillValue#getDateValue()}. 1331 * 1332 * @see #getAutofillType() 1333 */ 1334 public static final int AUTOFILL_TYPE_DATE = 4; 1335 1336 /** @hide */ 1337 @IntDef(prefix = { "IMPORTANT_FOR_AUTOFILL_" }, value = { 1338 IMPORTANT_FOR_AUTOFILL_AUTO, 1339 IMPORTANT_FOR_AUTOFILL_YES, 1340 IMPORTANT_FOR_AUTOFILL_NO, 1341 IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 1342 IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 1343 }) 1344 @Retention(RetentionPolicy.SOURCE) 1345 public @interface AutofillImportance {} 1346 1347 /** 1348 * Automatically determine whether a view is important for autofill. 1349 * 1350 * @see #isImportantForAutofill() 1351 * @see #setImportantForAutofill(int) 1352 */ 1353 public static final int IMPORTANT_FOR_AUTOFILL_AUTO = 0x0; 1354 1355 /** 1356 * The view is important for autofill, and its children (if any) will be traversed. 1357 * 1358 * @see #isImportantForAutofill() 1359 * @see #setImportantForAutofill(int) 1360 */ 1361 public static final int IMPORTANT_FOR_AUTOFILL_YES = 0x1; 1362 1363 /** 1364 * The view is not important for autofill, but its children (if any) will be traversed. 1365 * 1366 * @see #isImportantForAutofill() 1367 * @see #setImportantForAutofill(int) 1368 */ 1369 public static final int IMPORTANT_FOR_AUTOFILL_NO = 0x2; 1370 1371 /** 1372 * The view is important for autofill, but 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_YES_EXCLUDE_DESCENDANTS = 0x4; 1378 1379 /** 1380 * The view is not important for autofill, and its children (if any) will not be traversed. 1381 * 1382 * @see #isImportantForAutofill() 1383 * @see #setImportantForAutofill(int) 1384 */ 1385 public static final int IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS = 0x8; 1386 1387 /** @hide */ 1388 @IntDef(flag = true, prefix = { "AUTOFILL_FLAG_" }, value = { 1389 AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 1390 }) 1391 @Retention(RetentionPolicy.SOURCE) 1392 public @interface AutofillFlags {} 1393 1394 /** 1395 * Flag requesting you to add views that are marked as not important for autofill 1396 * (see {@link #setImportantForAutofill(int)}) to a {@link ViewStructure}. 1397 */ 1398 public static final int AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS = 0x1; 1399 1400 /** @hide */ 1401 @IntDef(prefix = { "IMPORTANT_FOR_CONTENT_CAPTURE_" }, value = { 1402 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, 1403 IMPORTANT_FOR_CONTENT_CAPTURE_YES, 1404 IMPORTANT_FOR_CONTENT_CAPTURE_NO, 1405 IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 1406 IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 1407 }) 1408 @Retention(RetentionPolicy.SOURCE) 1409 public @interface ContentCaptureImportance {} 1410 1411 /** 1412 * Automatically determine whether a view is important for content capture. 1413 * 1414 * @see #isImportantForContentCapture() 1415 * @see #setImportantForContentCapture(int) 1416 */ 1417 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_AUTO = 0x0; 1418 1419 /** 1420 * The view is important for content capture, and its children (if any) will be traversed. 1421 * 1422 * @see #isImportantForContentCapture() 1423 * @see #setImportantForContentCapture(int) 1424 */ 1425 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES = 0x1; 1426 1427 /** 1428 * The view is not important for content capture, but its children (if any) will be traversed. 1429 * 1430 * @see #isImportantForContentCapture() 1431 * @see #setImportantForContentCapture(int) 1432 */ 1433 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO = 0x2; 1434 1435 /** 1436 * The view is important for content capture, but its children (if any) will not be traversed. 1437 * 1438 * @see #isImportantForContentCapture() 1439 * @see #setImportantForContentCapture(int) 1440 */ 1441 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS = 0x4; 1442 1443 /** 1444 * The view is not important for content capture, and its children (if any) will not be 1445 * traversed. 1446 * 1447 * @see #isImportantForContentCapture() 1448 * @see #setImportantForContentCapture(int) 1449 */ 1450 public static final int IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS = 0x8; 1451 1452 /** {@hide} */ 1453 @IntDef(flag = true, prefix = {"SCROLL_CAPTURE_HINT_"}, 1454 value = { 1455 SCROLL_CAPTURE_HINT_AUTO, 1456 SCROLL_CAPTURE_HINT_EXCLUDE, 1457 SCROLL_CAPTURE_HINT_INCLUDE, 1458 SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS 1459 }) 1460 @Retention(RetentionPolicy.SOURCE) 1461 public @interface ScrollCaptureHint {} 1462 1463 /** 1464 * The content of this view will be considered for scroll capture if scrolling is possible. 1465 * 1466 * @see #getScrollCaptureHint() 1467 * @see #setScrollCaptureHint(int) 1468 * @hide 1469 */ 1470 public static final int SCROLL_CAPTURE_HINT_AUTO = 0; 1471 1472 /** 1473 * Explicitly exclcude this view as a potential scroll capture target. The system will not 1474 * consider it. Mutually exclusive with {@link #SCROLL_CAPTURE_HINT_INCLUDE}, which this flag 1475 * takes precedence over. 1476 * 1477 * @see #getScrollCaptureHint() 1478 * @see #setScrollCaptureHint(int) 1479 * @hide 1480 */ 1481 public static final int SCROLL_CAPTURE_HINT_EXCLUDE = 0x1; 1482 1483 /** 1484 * Explicitly include this view as a potential scroll capture target. When locating a scroll 1485 * capture target, this view will be prioritized before others without this flag. Mutually 1486 * exclusive with {@link #SCROLL_CAPTURE_HINT_EXCLUDE}, which takes precedence. 1487 * 1488 * @see #getScrollCaptureHint() 1489 * @see #setScrollCaptureHint(int) 1490 * @hide 1491 */ 1492 public static final int SCROLL_CAPTURE_HINT_INCLUDE = 0x2; 1493 1494 /** 1495 * Explicitly exclude all children of this view as potential scroll capture targets. This view 1496 * is unaffected. Note: Excluded children are not considered, regardless of {@link 1497 * #SCROLL_CAPTURE_HINT_INCLUDE}. 1498 * 1499 * @see #getScrollCaptureHint() 1500 * @see #setScrollCaptureHint(int) 1501 * @hide 1502 */ 1503 public static final int SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS = 0x4; 1504 1505 /** 1506 * This view is enabled. Interpretation varies by subclass. 1507 * Use with ENABLED_MASK when calling setFlags. 1508 * {@hide} 1509 */ 1510 static final int ENABLED = 0x00000000; 1511 1512 /** 1513 * This view is disabled. Interpretation varies by subclass. 1514 * Use with ENABLED_MASK when calling setFlags. 1515 * {@hide} 1516 */ 1517 static final int DISABLED = 0x00000020; 1518 1519 /** 1520 * Mask for use with setFlags indicating bits used for indicating whether 1521 * this view is enabled 1522 * {@hide} 1523 */ 1524 static final int ENABLED_MASK = 0x00000020; 1525 1526 /** 1527 * This view won't draw. {@link #onDraw(android.graphics.Canvas)} won't be 1528 * called and further optimizations will be performed. It is okay to have 1529 * this flag set and a background. Use with DRAW_MASK when calling setFlags. 1530 * {@hide} 1531 */ 1532 static final int WILL_NOT_DRAW = 0x00000080; 1533 1534 /** 1535 * Mask for use with setFlags indicating bits used for indicating whether 1536 * this view is will draw 1537 * {@hide} 1538 */ 1539 static final int DRAW_MASK = 0x00000080; 1540 1541 /** 1542 * <p>This view doesn't show scrollbars.</p> 1543 * {@hide} 1544 */ 1545 static final int SCROLLBARS_NONE = 0x00000000; 1546 1547 /** 1548 * <p>This view shows horizontal scrollbars.</p> 1549 * {@hide} 1550 */ 1551 static final int SCROLLBARS_HORIZONTAL = 0x00000100; 1552 1553 /** 1554 * <p>This view shows vertical scrollbars.</p> 1555 * {@hide} 1556 */ 1557 static final int SCROLLBARS_VERTICAL = 0x00000200; 1558 1559 /** 1560 * <p>Mask for use with setFlags indicating bits used for indicating which 1561 * scrollbars are enabled.</p> 1562 * {@hide} 1563 */ 1564 static final int SCROLLBARS_MASK = 0x00000300; 1565 1566 /** 1567 * Indicates that the view should filter touches when its window is obscured. 1568 * Refer to the class comments for more information about this security feature. 1569 * {@hide} 1570 */ 1571 static final int FILTER_TOUCHES_WHEN_OBSCURED = 0x00000400; 1572 1573 /** 1574 * Set for framework elements that use FITS_SYSTEM_WINDOWS, to indicate 1575 * that they are optional and should be skipped if the window has 1576 * requested system UI flags that ignore those insets for layout. 1577 * <p> 1578 * This is only used for support library as of Android R. The framework now uses 1579 * {@link #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS} such that it can skip the legacy 1580 * insets path that loses insets information. 1581 */ 1582 static final int OPTIONAL_FITS_SYSTEM_WINDOWS = 0x00000800; 1583 1584 /** 1585 * <p>This view doesn't show fading edges.</p> 1586 * {@hide} 1587 */ 1588 static final int FADING_EDGE_NONE = 0x00000000; 1589 1590 /** 1591 * <p>This view shows horizontal fading edges.</p> 1592 * {@hide} 1593 */ 1594 static final int FADING_EDGE_HORIZONTAL = 0x00001000; 1595 1596 /** 1597 * <p>This view shows vertical fading edges.</p> 1598 * {@hide} 1599 */ 1600 static final int FADING_EDGE_VERTICAL = 0x00002000; 1601 1602 /** 1603 * <p>Mask for use with setFlags indicating bits used for indicating which 1604 * fading edges are enabled.</p> 1605 * {@hide} 1606 */ 1607 static final int FADING_EDGE_MASK = 0x00003000; 1608 1609 /** 1610 * <p>Indicates this view can be clicked. When clickable, a View reacts 1611 * to clicks by notifying the OnClickListener.<p> 1612 * {@hide} 1613 */ 1614 static final int CLICKABLE = 0x00004000; 1615 1616 /** 1617 * <p>Indicates this view is caching its drawing into a bitmap.</p> 1618 * {@hide} 1619 */ 1620 static final int DRAWING_CACHE_ENABLED = 0x00008000; 1621 1622 /** 1623 * <p>Indicates that no icicle should be saved for this view.<p> 1624 * {@hide} 1625 */ 1626 static final int SAVE_DISABLED = 0x000010000; 1627 1628 /** 1629 * <p>Mask for use with setFlags indicating bits used for the saveEnabled 1630 * property.</p> 1631 * {@hide} 1632 */ 1633 static final int SAVE_DISABLED_MASK = 0x000010000; 1634 1635 /** 1636 * <p>Indicates that no drawing cache should ever be created for this view.<p> 1637 * {@hide} 1638 */ 1639 static final int WILL_NOT_CACHE_DRAWING = 0x000020000; 1640 1641 /** 1642 * <p>Indicates this view can take / keep focus when int touch mode.</p> 1643 * {@hide} 1644 */ 1645 static final int FOCUSABLE_IN_TOUCH_MODE = 0x00040000; 1646 1647 /** @hide */ 1648 @Retention(RetentionPolicy.SOURCE) 1649 @IntDef(prefix = { "DRAWING_CACHE_QUALITY_" }, value = { 1650 DRAWING_CACHE_QUALITY_LOW, 1651 DRAWING_CACHE_QUALITY_HIGH, 1652 DRAWING_CACHE_QUALITY_AUTO 1653 }) 1654 public @interface DrawingCacheQuality {} 1655 1656 /** 1657 * <p>Enables low quality mode for the drawing cache.</p> 1658 * 1659 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1660 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1661 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1662 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1663 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1664 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1665 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1666 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1667 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1668 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1669 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1670 * reports or unit testing the {@link PixelCopy} API is recommended. 1671 */ 1672 @Deprecated 1673 public static final int DRAWING_CACHE_QUALITY_LOW = 0x00080000; 1674 1675 /** 1676 * <p>Enables high quality mode for the drawing cache.</p> 1677 * 1678 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1679 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1680 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1681 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1682 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1683 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1684 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1685 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1686 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1687 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1688 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1689 * reports or unit testing the {@link PixelCopy} API is recommended. 1690 */ 1691 @Deprecated 1692 public static final int DRAWING_CACHE_QUALITY_HIGH = 0x00100000; 1693 1694 /** 1695 * <p>Enables automatic quality mode for the drawing cache.</p> 1696 * 1697 * @deprecated The view drawing cache was largely made obsolete with the introduction of 1698 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 1699 * layers are largely unnecessary and can easily result in a net loss in performance due to the 1700 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 1701 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 1702 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 1703 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 1704 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 1705 * software-rendered usages are discouraged and have compatibility issues with hardware-only 1706 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 1707 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 1708 * reports or unit testing the {@link PixelCopy} API is recommended. 1709 */ 1710 @Deprecated 1711 public static final int DRAWING_CACHE_QUALITY_AUTO = 0x00000000; 1712 1713 private static final int[] DRAWING_CACHE_QUALITY_FLAGS = { 1714 DRAWING_CACHE_QUALITY_AUTO, DRAWING_CACHE_QUALITY_LOW, DRAWING_CACHE_QUALITY_HIGH 1715 }; 1716 1717 /** 1718 * <p>Mask for use with setFlags indicating bits used for the cache 1719 * quality property.</p> 1720 * {@hide} 1721 */ 1722 static final int DRAWING_CACHE_QUALITY_MASK = 0x00180000; 1723 1724 /** 1725 * <p> 1726 * Indicates this view can be long clicked. When long clickable, a View 1727 * reacts to long clicks by notifying the OnLongClickListener or showing a 1728 * context menu. 1729 * </p> 1730 * {@hide} 1731 */ 1732 static final int LONG_CLICKABLE = 0x00200000; 1733 1734 /** 1735 * <p>Indicates that this view gets its drawable states from its direct parent 1736 * and ignores its original internal states.</p> 1737 * 1738 * @hide 1739 */ 1740 static final int DUPLICATE_PARENT_STATE = 0x00400000; 1741 1742 /** 1743 * <p> 1744 * Indicates this view can be context clicked. When context clickable, a View reacts to a 1745 * context click (e.g. a primary stylus button press or right mouse click) by notifying the 1746 * OnContextClickListener. 1747 * </p> 1748 * {@hide} 1749 */ 1750 static final int CONTEXT_CLICKABLE = 0x00800000; 1751 1752 /** @hide */ 1753 @IntDef(prefix = { "SCROLLBARS_" }, value = { 1754 SCROLLBARS_INSIDE_OVERLAY, 1755 SCROLLBARS_INSIDE_INSET, 1756 SCROLLBARS_OUTSIDE_OVERLAY, 1757 SCROLLBARS_OUTSIDE_INSET 1758 }) 1759 @Retention(RetentionPolicy.SOURCE) 1760 public @interface ScrollBarStyle {} 1761 1762 /** 1763 * The scrollbar style to display the scrollbars inside the content area, 1764 * without increasing the padding. The scrollbars will be overlaid with 1765 * translucency on the view's content. 1766 */ 1767 public static final int SCROLLBARS_INSIDE_OVERLAY = 0; 1768 1769 /** 1770 * The scrollbar style to display the scrollbars inside the padded area, 1771 * increasing the padding of the view. The scrollbars will not overlap the 1772 * content area of the view. 1773 */ 1774 public static final int SCROLLBARS_INSIDE_INSET = 0x01000000; 1775 1776 /** 1777 * The scrollbar style to display the scrollbars at the edge of the view, 1778 * without increasing the padding. The scrollbars will be overlaid with 1779 * translucency. 1780 */ 1781 public static final int SCROLLBARS_OUTSIDE_OVERLAY = 0x02000000; 1782 1783 /** 1784 * The scrollbar style to display the scrollbars at the edge of the view, 1785 * increasing the padding of the view. The scrollbars will only overlap the 1786 * background, if any. 1787 */ 1788 public static final int SCROLLBARS_OUTSIDE_INSET = 0x03000000; 1789 1790 /** 1791 * Mask to check if the scrollbar style is overlay or inset. 1792 * {@hide} 1793 */ 1794 static final int SCROLLBARS_INSET_MASK = 0x01000000; 1795 1796 /** 1797 * Mask to check if the scrollbar style is inside or outside. 1798 * {@hide} 1799 */ 1800 static final int SCROLLBARS_OUTSIDE_MASK = 0x02000000; 1801 1802 /** 1803 * Mask for scrollbar style. 1804 * {@hide} 1805 */ 1806 static final int SCROLLBARS_STYLE_MASK = 0x03000000; 1807 1808 /** 1809 * View flag indicating that the screen should remain on while the 1810 * window containing this view is visible to the user. This effectively 1811 * takes care of automatically setting the WindowManager's 1812 * {@link WindowManager.LayoutParams#FLAG_KEEP_SCREEN_ON}. 1813 */ 1814 public static final int KEEP_SCREEN_ON = 0x04000000; 1815 1816 /** 1817 * View flag indicating whether this view should have sound effects enabled 1818 * for events such as clicking and touching. 1819 */ 1820 public static final int SOUND_EFFECTS_ENABLED = 0x08000000; 1821 1822 /** 1823 * View flag indicating whether this view should have haptic feedback 1824 * enabled for events such as long presses. 1825 */ 1826 public static final int HAPTIC_FEEDBACK_ENABLED = 0x10000000; 1827 1828 /** 1829 * <p>Indicates that the view hierarchy should stop saving state when 1830 * it reaches this view. If state saving is initiated immediately at 1831 * the view, it will be allowed. 1832 * {@hide} 1833 */ 1834 static final int PARENT_SAVE_DISABLED = 0x20000000; 1835 1836 /** 1837 * <p>Mask for use with setFlags indicating bits used for PARENT_SAVE_DISABLED.</p> 1838 * {@hide} 1839 */ 1840 static final int PARENT_SAVE_DISABLED_MASK = 0x20000000; 1841 1842 private static Paint sDebugPaint; 1843 1844 /** 1845 * <p>Indicates this view can display a tooltip on hover or long press.</p> 1846 * {@hide} 1847 */ 1848 static final int TOOLTIP = 0x40000000; 1849 1850 /** @hide */ 1851 @IntDef(flag = true, prefix = { "FOCUSABLES_" }, value = { 1852 FOCUSABLES_ALL, 1853 FOCUSABLES_TOUCH_MODE 1854 }) 1855 @Retention(RetentionPolicy.SOURCE) 1856 public @interface FocusableMode {} 1857 1858 /** 1859 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1860 * should add all focusable Views regardless if they are focusable in touch mode. 1861 */ 1862 public static final int FOCUSABLES_ALL = 0x00000000; 1863 1864 /** 1865 * View flag indicating whether {@link #addFocusables(ArrayList, int, int)} 1866 * should add only Views focusable in touch mode. 1867 */ 1868 public static final int FOCUSABLES_TOUCH_MODE = 0x00000001; 1869 1870 /** @hide */ 1871 @IntDef(prefix = { "FOCUS_" }, value = { 1872 FOCUS_BACKWARD, 1873 FOCUS_FORWARD, 1874 FOCUS_LEFT, 1875 FOCUS_UP, 1876 FOCUS_RIGHT, 1877 FOCUS_DOWN 1878 }) 1879 @Retention(RetentionPolicy.SOURCE) 1880 public @interface FocusDirection {} 1881 1882 /** @hide */ 1883 @IntDef(prefix = { "FOCUS_" }, value = { 1884 FOCUS_LEFT, 1885 FOCUS_UP, 1886 FOCUS_RIGHT, 1887 FOCUS_DOWN 1888 }) 1889 @Retention(RetentionPolicy.SOURCE) 1890 public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward 1891 1892 /** 1893 * Use with {@link #focusSearch(int)}. Move focus to the previous selectable 1894 * item. 1895 */ 1896 public static final int FOCUS_BACKWARD = 0x00000001; 1897 1898 /** 1899 * Use with {@link #focusSearch(int)}. Move focus to the next selectable 1900 * item. 1901 */ 1902 public static final int FOCUS_FORWARD = 0x00000002; 1903 1904 /** 1905 * Use with {@link #focusSearch(int)}. Move focus to the left. 1906 */ 1907 public static final int FOCUS_LEFT = 0x00000011; 1908 1909 /** 1910 * Use with {@link #focusSearch(int)}. Move focus up. 1911 */ 1912 public static final int FOCUS_UP = 0x00000021; 1913 1914 /** 1915 * Use with {@link #focusSearch(int)}. Move focus to the right. 1916 */ 1917 public static final int FOCUS_RIGHT = 0x00000042; 1918 1919 /** 1920 * Use with {@link #focusSearch(int)}. Move focus down. 1921 */ 1922 public static final int FOCUS_DOWN = 0x00000082; 1923 1924 /** 1925 * Bits of {@link #getMeasuredWidthAndState()} and 1926 * {@link #getMeasuredWidthAndState()} that provide the actual measured size. 1927 */ 1928 public static final int MEASURED_SIZE_MASK = 0x00ffffff; 1929 1930 /** 1931 * Bits of {@link #getMeasuredWidthAndState()} and 1932 * {@link #getMeasuredWidthAndState()} that provide the additional state bits. 1933 */ 1934 public static final int MEASURED_STATE_MASK = 0xff000000; 1935 1936 /** 1937 * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits 1938 * for functions that combine both width and height into a single int, 1939 * such as {@link #getMeasuredState()} and the childState argument of 1940 * {@link #resolveSizeAndState(int, int, int)}. 1941 */ 1942 public static final int MEASURED_HEIGHT_STATE_SHIFT = 16; 1943 1944 /** 1945 * Bit of {@link #getMeasuredWidthAndState()} and 1946 * {@link #getMeasuredWidthAndState()} that indicates the measured size 1947 * is smaller that the space the view would like to have. 1948 */ 1949 public static final int MEASURED_STATE_TOO_SMALL = 0x01000000; 1950 1951 /** 1952 * Base View state sets 1953 */ 1954 // Singles 1955 /** 1956 * Indicates the view has no states set. States are used with 1957 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1958 * view depending on its state. 1959 * 1960 * @see android.graphics.drawable.Drawable 1961 * @see #getDrawableState() 1962 */ 1963 protected static final int[] EMPTY_STATE_SET; 1964 /** 1965 * Indicates the view is enabled. States are used with 1966 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1967 * view depending on its state. 1968 * 1969 * @see android.graphics.drawable.Drawable 1970 * @see #getDrawableState() 1971 */ 1972 protected static final int[] ENABLED_STATE_SET; 1973 /** 1974 * Indicates the view is focused. States are used with 1975 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1976 * view depending on its state. 1977 * 1978 * @see android.graphics.drawable.Drawable 1979 * @see #getDrawableState() 1980 */ 1981 protected static final int[] FOCUSED_STATE_SET; 1982 /** 1983 * Indicates the view is selected. States are used with 1984 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1985 * view depending on its state. 1986 * 1987 * @see android.graphics.drawable.Drawable 1988 * @see #getDrawableState() 1989 */ 1990 protected static final int[] SELECTED_STATE_SET; 1991 /** 1992 * Indicates the view is pressed. States are used with 1993 * {@link android.graphics.drawable.Drawable} to change the drawing of the 1994 * view depending on its state. 1995 * 1996 * @see android.graphics.drawable.Drawable 1997 * @see #getDrawableState() 1998 */ 1999 protected static final int[] PRESSED_STATE_SET; 2000 /** 2001 * Indicates the view's window has focus. States are used with 2002 * {@link android.graphics.drawable.Drawable} to change the drawing of the 2003 * view depending on its state. 2004 * 2005 * @see android.graphics.drawable.Drawable 2006 * @see #getDrawableState() 2007 */ 2008 protected static final int[] WINDOW_FOCUSED_STATE_SET; 2009 // Doubles 2010 /** 2011 * Indicates the view is enabled and has the focus. 2012 * 2013 * @see #ENABLED_STATE_SET 2014 * @see #FOCUSED_STATE_SET 2015 */ 2016 protected static final int[] ENABLED_FOCUSED_STATE_SET; 2017 /** 2018 * Indicates the view is enabled and selected. 2019 * 2020 * @see #ENABLED_STATE_SET 2021 * @see #SELECTED_STATE_SET 2022 */ 2023 protected static final int[] ENABLED_SELECTED_STATE_SET; 2024 /** 2025 * Indicates the view is enabled and that its window has focus. 2026 * 2027 * @see #ENABLED_STATE_SET 2028 * @see #WINDOW_FOCUSED_STATE_SET 2029 */ 2030 protected static final int[] ENABLED_WINDOW_FOCUSED_STATE_SET; 2031 /** 2032 * Indicates the view is focused and selected. 2033 * 2034 * @see #FOCUSED_STATE_SET 2035 * @see #SELECTED_STATE_SET 2036 */ 2037 protected static final int[] FOCUSED_SELECTED_STATE_SET; 2038 /** 2039 * Indicates the view has the focus and that its window has the focus. 2040 * 2041 * @see #FOCUSED_STATE_SET 2042 * @see #WINDOW_FOCUSED_STATE_SET 2043 */ 2044 protected static final int[] FOCUSED_WINDOW_FOCUSED_STATE_SET; 2045 /** 2046 * Indicates the view is selected and that its window has the focus. 2047 * 2048 * @see #SELECTED_STATE_SET 2049 * @see #WINDOW_FOCUSED_STATE_SET 2050 */ 2051 protected static final int[] SELECTED_WINDOW_FOCUSED_STATE_SET; 2052 // Triples 2053 /** 2054 * Indicates the view is enabled, focused and selected. 2055 * 2056 * @see #ENABLED_STATE_SET 2057 * @see #FOCUSED_STATE_SET 2058 * @see #SELECTED_STATE_SET 2059 */ 2060 protected static final int[] ENABLED_FOCUSED_SELECTED_STATE_SET; 2061 /** 2062 * Indicates the view is enabled, focused and its window has the focus. 2063 * 2064 * @see #ENABLED_STATE_SET 2065 * @see #FOCUSED_STATE_SET 2066 * @see #WINDOW_FOCUSED_STATE_SET 2067 */ 2068 protected static final int[] ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2069 /** 2070 * Indicates the view is enabled, selected and its window has the focus. 2071 * 2072 * @see #ENABLED_STATE_SET 2073 * @see #SELECTED_STATE_SET 2074 * @see #WINDOW_FOCUSED_STATE_SET 2075 */ 2076 protected static final int[] ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2077 /** 2078 * Indicates the view is focused, selected and its window has the focus. 2079 * 2080 * @see #FOCUSED_STATE_SET 2081 * @see #SELECTED_STATE_SET 2082 * @see #WINDOW_FOCUSED_STATE_SET 2083 */ 2084 protected static final int[] FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2085 /** 2086 * Indicates the view is enabled, focused, selected and its window 2087 * has the focus. 2088 * 2089 * @see #ENABLED_STATE_SET 2090 * @see #FOCUSED_STATE_SET 2091 * @see #SELECTED_STATE_SET 2092 * @see #WINDOW_FOCUSED_STATE_SET 2093 */ 2094 protected static final int[] ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2095 /** 2096 * Indicates the view is pressed and its window has the focus. 2097 * 2098 * @see #PRESSED_STATE_SET 2099 * @see #WINDOW_FOCUSED_STATE_SET 2100 */ 2101 protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; 2102 /** 2103 * Indicates the view is pressed and selected. 2104 * 2105 * @see #PRESSED_STATE_SET 2106 * @see #SELECTED_STATE_SET 2107 */ 2108 protected static final int[] PRESSED_SELECTED_STATE_SET; 2109 /** 2110 * Indicates the view is pressed, selected and its window has the focus. 2111 * 2112 * @see #PRESSED_STATE_SET 2113 * @see #SELECTED_STATE_SET 2114 * @see #WINDOW_FOCUSED_STATE_SET 2115 */ 2116 protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2117 /** 2118 * Indicates the view is pressed and focused. 2119 * 2120 * @see #PRESSED_STATE_SET 2121 * @see #FOCUSED_STATE_SET 2122 */ 2123 protected static final int[] PRESSED_FOCUSED_STATE_SET; 2124 /** 2125 * Indicates the view is pressed, focused and its window has the focus. 2126 * 2127 * @see #PRESSED_STATE_SET 2128 * @see #FOCUSED_STATE_SET 2129 * @see #WINDOW_FOCUSED_STATE_SET 2130 */ 2131 protected static final int[] PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2132 /** 2133 * Indicates the view is pressed, focused and selected. 2134 * 2135 * @see #PRESSED_STATE_SET 2136 * @see #SELECTED_STATE_SET 2137 * @see #FOCUSED_STATE_SET 2138 */ 2139 protected static final int[] PRESSED_FOCUSED_SELECTED_STATE_SET; 2140 /** 2141 * Indicates the view is pressed, focused, selected and its window has the focus. 2142 * 2143 * @see #PRESSED_STATE_SET 2144 * @see #FOCUSED_STATE_SET 2145 * @see #SELECTED_STATE_SET 2146 * @see #WINDOW_FOCUSED_STATE_SET 2147 */ 2148 protected static final int[] PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2149 /** 2150 * Indicates the view is pressed and enabled. 2151 * 2152 * @see #PRESSED_STATE_SET 2153 * @see #ENABLED_STATE_SET 2154 */ 2155 protected static final int[] PRESSED_ENABLED_STATE_SET; 2156 /** 2157 * Indicates the view is pressed, enabled and its window has the focus. 2158 * 2159 * @see #PRESSED_STATE_SET 2160 * @see #ENABLED_STATE_SET 2161 * @see #WINDOW_FOCUSED_STATE_SET 2162 */ 2163 protected static final int[] PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET; 2164 /** 2165 * Indicates the view is pressed, enabled and selected. 2166 * 2167 * @see #PRESSED_STATE_SET 2168 * @see #ENABLED_STATE_SET 2169 * @see #SELECTED_STATE_SET 2170 */ 2171 protected static final int[] PRESSED_ENABLED_SELECTED_STATE_SET; 2172 /** 2173 * Indicates the view is pressed, enabled, selected and its window has the 2174 * focus. 2175 * 2176 * @see #PRESSED_STATE_SET 2177 * @see #ENABLED_STATE_SET 2178 * @see #SELECTED_STATE_SET 2179 * @see #WINDOW_FOCUSED_STATE_SET 2180 */ 2181 protected static final int[] PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2182 /** 2183 * Indicates the view is pressed, enabled and focused. 2184 * 2185 * @see #PRESSED_STATE_SET 2186 * @see #ENABLED_STATE_SET 2187 * @see #FOCUSED_STATE_SET 2188 */ 2189 protected static final int[] PRESSED_ENABLED_FOCUSED_STATE_SET; 2190 /** 2191 * Indicates the view is pressed, enabled, focused and its window has the 2192 * focus. 2193 * 2194 * @see #PRESSED_STATE_SET 2195 * @see #ENABLED_STATE_SET 2196 * @see #FOCUSED_STATE_SET 2197 * @see #WINDOW_FOCUSED_STATE_SET 2198 */ 2199 protected static final int[] PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET; 2200 /** 2201 * Indicates the view is pressed, enabled, focused and selected. 2202 * 2203 * @see #PRESSED_STATE_SET 2204 * @see #ENABLED_STATE_SET 2205 * @see #SELECTED_STATE_SET 2206 * @see #FOCUSED_STATE_SET 2207 */ 2208 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET; 2209 /** 2210 * Indicates the view is pressed, enabled, focused, selected and its window 2211 * has the focus. 2212 * 2213 * @see #PRESSED_STATE_SET 2214 * @see #ENABLED_STATE_SET 2215 * @see #SELECTED_STATE_SET 2216 * @see #FOCUSED_STATE_SET 2217 * @see #WINDOW_FOCUSED_STATE_SET 2218 */ 2219 protected static final int[] PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET; 2220 2221 static { 2222 EMPTY_STATE_SET = StateSet.get(0); 2223 2224 WINDOW_FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_WINDOW_FOCUSED); 2225 2226 SELECTED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_SELECTED); 2227 SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2228 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED); 2229 2230 FOCUSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_FOCUSED); 2231 FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2232 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED); 2233 FOCUSED_SELECTED_STATE_SET = StateSet.get( 2234 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED); 2235 FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2236 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2237 | StateSet.VIEW_STATE_FOCUSED); 2238 2239 ENABLED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_ENABLED); 2240 ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2241 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2242 ENABLED_SELECTED_STATE_SET = StateSet.get( 2243 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED); 2244 ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2245 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2246 | StateSet.VIEW_STATE_ENABLED); 2247 ENABLED_FOCUSED_STATE_SET = StateSet.get( 2248 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED); 2249 ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2250 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2251 | StateSet.VIEW_STATE_ENABLED); 2252 ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2253 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2254 | StateSet.VIEW_STATE_ENABLED); 2255 ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2256 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2257 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED); 2258 2259 PRESSED_STATE_SET = StateSet.get(StateSet.VIEW_STATE_PRESSED); 2260 PRESSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2261 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2262 PRESSED_SELECTED_STATE_SET = StateSet.get( 2263 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_PRESSED); 2264 PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2265 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2266 | StateSet.VIEW_STATE_PRESSED); 2267 PRESSED_FOCUSED_STATE_SET = StateSet.get( 2268 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2269 PRESSED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2270 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2271 | StateSet.VIEW_STATE_PRESSED); 2272 PRESSED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2273 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2274 | StateSet.VIEW_STATE_PRESSED); 2275 PRESSED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2276 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2277 | StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_PRESSED); 2278 PRESSED_ENABLED_STATE_SET = StateSet.get( 2279 StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2280 PRESSED_ENABLED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2281 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_ENABLED 2282 | StateSet.VIEW_STATE_PRESSED); 2283 PRESSED_ENABLED_SELECTED_STATE_SET = StateSet.get( 2284 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_ENABLED 2285 | StateSet.VIEW_STATE_PRESSED); 2286 PRESSED_ENABLED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2287 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2288 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2289 PRESSED_ENABLED_FOCUSED_STATE_SET = StateSet.get( 2290 StateSet.VIEW_STATE_FOCUSED | StateSet.VIEW_STATE_ENABLED 2291 | StateSet.VIEW_STATE_PRESSED); 2292 PRESSED_ENABLED_FOCUSED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2293 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_FOCUSED 2294 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2295 PRESSED_ENABLED_FOCUSED_SELECTED_STATE_SET = StateSet.get( 2296 StateSet.VIEW_STATE_SELECTED | StateSet.VIEW_STATE_FOCUSED 2297 | StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_PRESSED); 2298 PRESSED_ENABLED_FOCUSED_SELECTED_WINDOW_FOCUSED_STATE_SET = StateSet.get( 2299 StateSet.VIEW_STATE_WINDOW_FOCUSED | StateSet.VIEW_STATE_SELECTED 2300 | StateSet.VIEW_STATE_FOCUSED| StateSet.VIEW_STATE_ENABLED 2301 | StateSet.VIEW_STATE_PRESSED); 2302 } 2303 2304 /** 2305 * Accessibility event types that are dispatched for text population. 2306 */ 2307 private static final int POPULATING_ACCESSIBILITY_EVENT_TYPES = 2308 AccessibilityEvent.TYPE_VIEW_CLICKED 2309 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED 2310 | AccessibilityEvent.TYPE_VIEW_SELECTED 2311 | AccessibilityEvent.TYPE_VIEW_FOCUSED 2312 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED 2313 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 2314 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 2315 | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 2316 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 2317 | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED 2318 | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY; 2319 2320 static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255); 2321 2322 static final int DEBUG_CORNERS_SIZE_DIP = 8; 2323 2324 /** 2325 * Temporary Rect currently for use in setBackground(). This will probably 2326 * be extended in the future to hold our own class with more than just 2327 * a Rect. :) 2328 */ 2329 static final ThreadLocal<Rect> sThreadLocal = ThreadLocal.withInitial(Rect::new); 2330 2331 /** 2332 * Map used to store views' tags. 2333 */ 2334 @UnsupportedAppUsage 2335 private SparseArray<Object> mKeyedTags; 2336 2337 /** 2338 * The next available accessibility id. 2339 */ 2340 private static int sNextAccessibilityViewId; 2341 2342 /** 2343 * The animation currently associated with this view. 2344 * @hide 2345 */ 2346 protected Animation mCurrentAnimation = null; 2347 2348 /** 2349 * Width as measured during measure pass. 2350 * {@hide} 2351 */ 2352 @ViewDebug.ExportedProperty(category = "measurement") 2353 @UnsupportedAppUsage 2354 int mMeasuredWidth; 2355 2356 /** 2357 * Height as measured during measure pass. 2358 * {@hide} 2359 */ 2360 @ViewDebug.ExportedProperty(category = "measurement") 2361 @UnsupportedAppUsage 2362 int mMeasuredHeight; 2363 2364 /** 2365 * Flag to indicate that this view was marked INVALIDATED, or had its display list 2366 * invalidated, prior to the current drawing iteration. If true, the view must re-draw 2367 * its display list. This flag, used only when hw accelerated, allows us to clear the 2368 * flag while retaining this information until it's needed (at getDisplayList() time and 2369 * in drawChild(), when we decide to draw a view's children's display lists into our own). 2370 * 2371 * {@hide} 2372 */ 2373 @UnsupportedAppUsage 2374 boolean mRecreateDisplayList = false; 2375 2376 /** 2377 * The view's identifier. 2378 * {@hide} 2379 * 2380 * @see #setId(int) 2381 * @see #getId() 2382 */ 2383 @IdRes 2384 @ViewDebug.ExportedProperty(resolveId = true) 2385 int mID = NO_ID; 2386 2387 /** The ID of this view for autofill purposes. 2388 * <ul> 2389 * <li>== {@link #NO_ID}: ID has not been assigned yet 2390 * <li>≤ {@link #LAST_APP_AUTOFILL_ID}: View is not part of a activity. The ID is 2391 * unique in the process. This might change 2392 * over activity lifecycle events. 2393 * <li>> {@link #LAST_APP_AUTOFILL_ID}: View is part of a activity. The ID is 2394 * unique in the activity. This stays the same 2395 * over activity lifecycle events. 2396 */ 2397 private int mAutofillViewId = NO_ID; 2398 2399 // ID for accessibility purposes. This ID must be unique for every window 2400 @UnsupportedAppUsage 2401 private int mAccessibilityViewId = NO_ID; 2402 2403 private int mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 2404 2405 /** 2406 * The view's tag. 2407 * {@hide} 2408 * 2409 * @see #setTag(Object) 2410 * @see #getTag() 2411 */ 2412 @UnsupportedAppUsage 2413 protected Object mTag = null; 2414 2415 /* 2416 * Masks for mPrivateFlags, as generated by dumpFlags(): 2417 * 2418 * |-------|-------|-------|-------| 2419 * 1 PFLAG_WANTS_FOCUS 2420 * 1 PFLAG_FOCUSED 2421 * 1 PFLAG_SELECTED 2422 * 1 PFLAG_IS_ROOT_NAMESPACE 2423 * 1 PFLAG_HAS_BOUNDS 2424 * 1 PFLAG_DRAWN 2425 * 1 PFLAG_DRAW_ANIMATION 2426 * 1 PFLAG_SKIP_DRAW 2427 * 1 PFLAG_REQUEST_TRANSPARENT_REGIONS 2428 * 1 PFLAG_DRAWABLE_STATE_DIRTY 2429 * 1 PFLAG_MEASURED_DIMENSION_SET 2430 * 1 PFLAG_FORCE_LAYOUT 2431 * 1 PFLAG_LAYOUT_REQUIRED 2432 * 1 PFLAG_PRESSED 2433 * 1 PFLAG_DRAWING_CACHE_VALID 2434 * 1 PFLAG_ANIMATION_STARTED 2435 * 1 PFLAG_SAVE_STATE_CALLED 2436 * 1 PFLAG_ALPHA_SET 2437 * 1 PFLAG_SCROLL_CONTAINER 2438 * 1 PFLAG_SCROLL_CONTAINER_ADDED 2439 * 1 PFLAG_DIRTY 2440 * 1 PFLAG_DIRTY_MASK 2441 * 1 PFLAG_OPAQUE_BACKGROUND 2442 * 1 PFLAG_OPAQUE_SCROLLBARS 2443 * 11 PFLAG_OPAQUE_MASK 2444 * 1 PFLAG_PREPRESSED 2445 * 1 PFLAG_CANCEL_NEXT_UP_EVENT 2446 * 1 PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH 2447 * 1 PFLAG_HOVERED 2448 * 1 PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK 2449 * 1 PFLAG_ACTIVATED 2450 * 1 PFLAG_INVALIDATED 2451 * |-------|-------|-------|-------| 2452 */ 2453 /** {@hide} */ 2454 static final int PFLAG_WANTS_FOCUS = 0x00000001; 2455 /** {@hide} */ 2456 static final int PFLAG_FOCUSED = 0x00000002; 2457 /** {@hide} */ 2458 static final int PFLAG_SELECTED = 0x00000004; 2459 /** {@hide} */ 2460 static final int PFLAG_IS_ROOT_NAMESPACE = 0x00000008; 2461 /** {@hide} */ 2462 static final int PFLAG_HAS_BOUNDS = 0x00000010; 2463 /** {@hide} */ 2464 static final int PFLAG_DRAWN = 0x00000020; 2465 /** 2466 * When this flag is set, this view is running an animation on behalf of its 2467 * children and should therefore not cancel invalidate requests, even if they 2468 * lie outside of this view's bounds. 2469 * 2470 * {@hide} 2471 */ 2472 static final int PFLAG_DRAW_ANIMATION = 0x00000040; 2473 /** {@hide} */ 2474 static final int PFLAG_SKIP_DRAW = 0x00000080; 2475 /** {@hide} */ 2476 static final int PFLAG_REQUEST_TRANSPARENT_REGIONS = 0x00000200; 2477 /** {@hide} */ 2478 static final int PFLAG_DRAWABLE_STATE_DIRTY = 0x00000400; 2479 /** {@hide} */ 2480 static final int PFLAG_MEASURED_DIMENSION_SET = 0x00000800; 2481 /** {@hide} */ 2482 static final int PFLAG_FORCE_LAYOUT = 0x00001000; 2483 /** {@hide} */ 2484 static final int PFLAG_LAYOUT_REQUIRED = 0x00002000; 2485 2486 private static final int PFLAG_PRESSED = 0x00004000; 2487 2488 /** {@hide} */ 2489 static final int PFLAG_DRAWING_CACHE_VALID = 0x00008000; 2490 /** 2491 * Flag used to indicate that this view should be drawn once more (and only once 2492 * more) after its animation has completed. 2493 * {@hide} 2494 */ 2495 static final int PFLAG_ANIMATION_STARTED = 0x00010000; 2496 2497 private static final int PFLAG_SAVE_STATE_CALLED = 0x00020000; 2498 2499 /** 2500 * Indicates that the View returned true when onSetAlpha() was called and that 2501 * the alpha must be restored. 2502 * {@hide} 2503 */ 2504 static final int PFLAG_ALPHA_SET = 0x00040000; 2505 2506 /** 2507 * Set by {@link #setScrollContainer(boolean)}. 2508 */ 2509 static final int PFLAG_SCROLL_CONTAINER = 0x00080000; 2510 2511 /** 2512 * Set by {@link #setScrollContainer(boolean)}. 2513 */ 2514 static final int PFLAG_SCROLL_CONTAINER_ADDED = 0x00100000; 2515 2516 /** 2517 * View flag indicating whether this view was invalidated (fully or partially.) 2518 * 2519 * @hide 2520 */ 2521 static final int PFLAG_DIRTY = 0x00200000; 2522 2523 /** 2524 * Mask for {@link #PFLAG_DIRTY}. 2525 * 2526 * @hide 2527 */ 2528 static final int PFLAG_DIRTY_MASK = 0x00200000; 2529 2530 /** 2531 * Indicates whether the background is opaque. 2532 * 2533 * @hide 2534 */ 2535 static final int PFLAG_OPAQUE_BACKGROUND = 0x00800000; 2536 2537 /** 2538 * Indicates whether the scrollbars are opaque. 2539 * 2540 * @hide 2541 */ 2542 static final int PFLAG_OPAQUE_SCROLLBARS = 0x01000000; 2543 2544 /** 2545 * Indicates whether the view is opaque. 2546 * 2547 * @hide 2548 */ 2549 static final int PFLAG_OPAQUE_MASK = 0x01800000; 2550 2551 /** 2552 * Indicates a prepressed state; 2553 * the short time between ACTION_DOWN and recognizing 2554 * a 'real' press. Prepressed is used to recognize quick taps 2555 * even when they are shorter than ViewConfiguration.getTapTimeout(). 2556 * 2557 * @hide 2558 */ 2559 private static final int PFLAG_PREPRESSED = 0x02000000; 2560 2561 /** 2562 * Indicates whether the view is temporarily detached. 2563 * 2564 * @hide 2565 */ 2566 static final int PFLAG_CANCEL_NEXT_UP_EVENT = 0x04000000; 2567 2568 /** 2569 * Indicates that we should awaken scroll bars once attached 2570 * 2571 * PLEASE NOTE: This flag is now unused as we now send onVisibilityChanged 2572 * during window attachment and it is no longer needed. Feel free to repurpose it. 2573 * 2574 * @hide 2575 */ 2576 private static final int PFLAG_AWAKEN_SCROLL_BARS_ON_ATTACH = 0x08000000; 2577 2578 /** 2579 * Indicates that the view has received HOVER_ENTER. Cleared on HOVER_EXIT. 2580 * @hide 2581 */ 2582 private static final int PFLAG_HOVERED = 0x10000000; 2583 2584 /** 2585 * Flag set by {@link AutofillManager} if it needs to be notified when this view is clicked. 2586 */ 2587 private static final int PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK = 0x20000000; 2588 2589 /** {@hide} */ 2590 static final int PFLAG_ACTIVATED = 0x40000000; 2591 2592 /** 2593 * Indicates that this view was specifically invalidated, not just dirtied because some 2594 * child view was invalidated. The flag is used to determine when we need to recreate 2595 * a view's display list (as opposed to just returning a reference to its existing 2596 * display list). 2597 * 2598 * @hide 2599 */ 2600 static final int PFLAG_INVALIDATED = 0x80000000; 2601 2602 /* End of masks for mPrivateFlags */ 2603 2604 /* 2605 * Masks for mPrivateFlags2, as generated by dumpFlags(): 2606 * 2607 * |-------|-------|-------|-------| 2608 * 1 PFLAG2_DRAG_CAN_ACCEPT 2609 * 1 PFLAG2_DRAG_HOVERED 2610 * 11 PFLAG2_LAYOUT_DIRECTION_MASK 2611 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL 2612 * 1 PFLAG2_LAYOUT_DIRECTION_RESOLVED 2613 * 11 PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK 2614 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[1] 2615 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[2] 2616 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[3] 2617 * 1 PFLAG2_TEXT_DIRECTION_FLAGS[4] 2618 * 1 1 PFLAG2_TEXT_DIRECTION_FLAGS[5] 2619 * 11 PFLAG2_TEXT_DIRECTION_FLAGS[6] 2620 * 111 PFLAG2_TEXT_DIRECTION_FLAGS[7] 2621 * 111 PFLAG2_TEXT_DIRECTION_MASK 2622 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED 2623 * 1 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT 2624 * 111 PFLAG2_TEXT_DIRECTION_RESOLVED_MASK 2625 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[1] 2626 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[2] 2627 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[3] 2628 * 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[4] 2629 * 1 1 PFLAG2_TEXT_ALIGNMENT_FLAGS[5] 2630 * 11 PFLAG2_TEXT_ALIGNMENT_FLAGS[6] 2631 * 111 PFLAG2_TEXT_ALIGNMENT_MASK 2632 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED 2633 * 1 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT 2634 * 111 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK 2635 * 111 PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK 2636 * 11 PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK 2637 * 1 PFLAG2_ACCESSIBILITY_FOCUSED 2638 * 1 PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED 2639 * 1 PFLAG2_VIEW_QUICK_REJECTED 2640 * 1 PFLAG2_PADDING_RESOLVED 2641 * 1 PFLAG2_DRAWABLE_RESOLVED 2642 * 1 PFLAG2_HAS_TRANSIENT_STATE 2643 * |-------|-------|-------|-------| 2644 */ 2645 2646 /** 2647 * Indicates that this view has reported that it can accept the current drag's content. 2648 * Cleared when the drag operation concludes. 2649 * @hide 2650 */ 2651 static final int PFLAG2_DRAG_CAN_ACCEPT = 0x00000001; 2652 2653 /** 2654 * Indicates that this view is currently directly under the drag location in a 2655 * drag-and-drop operation involving content that it can accept. Cleared when 2656 * the drag exits the view, or when the drag operation concludes. 2657 * @hide 2658 */ 2659 static final int PFLAG2_DRAG_HOVERED = 0x00000002; 2660 2661 /** @hide */ 2662 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2663 LAYOUT_DIRECTION_LTR, 2664 LAYOUT_DIRECTION_RTL, 2665 LAYOUT_DIRECTION_INHERIT, 2666 LAYOUT_DIRECTION_LOCALE 2667 }) 2668 @Retention(RetentionPolicy.SOURCE) 2669 // Not called LayoutDirection to avoid conflict with android.util.LayoutDirection 2670 public @interface LayoutDir {} 2671 2672 /** @hide */ 2673 @IntDef(prefix = { "LAYOUT_DIRECTION_" }, value = { 2674 LAYOUT_DIRECTION_LTR, 2675 LAYOUT_DIRECTION_RTL 2676 }) 2677 @Retention(RetentionPolicy.SOURCE) 2678 public @interface ResolvedLayoutDir {} 2679 2680 /** 2681 * A flag to indicate that the layout direction of this view has not been defined yet. 2682 * @hide 2683 */ 2684 public static final int LAYOUT_DIRECTION_UNDEFINED = LayoutDirection.UNDEFINED; 2685 2686 /** 2687 * Horizontal layout direction of this view is from Left to Right. 2688 * Use with {@link #setLayoutDirection}. 2689 */ 2690 public static final int LAYOUT_DIRECTION_LTR = LayoutDirection.LTR; 2691 2692 /** 2693 * Horizontal layout direction of this view is from Right to Left. 2694 * Use with {@link #setLayoutDirection}. 2695 */ 2696 public static final int LAYOUT_DIRECTION_RTL = LayoutDirection.RTL; 2697 2698 /** 2699 * Horizontal layout direction of this view is inherited from its parent. 2700 * Use with {@link #setLayoutDirection}. 2701 */ 2702 public static final int LAYOUT_DIRECTION_INHERIT = LayoutDirection.INHERIT; 2703 2704 /** 2705 * Horizontal layout direction of this view is from deduced from the default language 2706 * script for the locale. Use with {@link #setLayoutDirection}. 2707 */ 2708 public static final int LAYOUT_DIRECTION_LOCALE = LayoutDirection.LOCALE; 2709 2710 /** 2711 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2712 * @hide 2713 */ 2714 static final int PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT = 2; 2715 2716 /** 2717 * Mask for use with private flags indicating bits used for horizontal layout direction. 2718 * @hide 2719 */ 2720 static final int PFLAG2_LAYOUT_DIRECTION_MASK = 0x00000003 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2721 2722 /** 2723 * Indicates whether the view horizontal layout direction has been resolved and drawn to the 2724 * right-to-left direction. 2725 * @hide 2726 */ 2727 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL = 4 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2728 2729 /** 2730 * Indicates whether the view horizontal layout direction has been resolved. 2731 * @hide 2732 */ 2733 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED = 8 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2734 2735 /** 2736 * Mask for use with private flags indicating bits used for resolved horizontal layout direction. 2737 * @hide 2738 */ 2739 static final int PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK = 0x0000000C 2740 << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 2741 2742 /* 2743 * Array of horizontal layout direction flags for mapping attribute "layoutDirection" to correct 2744 * flag value. 2745 * @hide 2746 */ 2747 private static final int[] LAYOUT_DIRECTION_FLAGS = { 2748 LAYOUT_DIRECTION_LTR, 2749 LAYOUT_DIRECTION_RTL, 2750 LAYOUT_DIRECTION_INHERIT, 2751 LAYOUT_DIRECTION_LOCALE 2752 }; 2753 2754 /** 2755 * Default horizontal layout direction. 2756 */ 2757 private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT; 2758 2759 /** 2760 * Default horizontal layout direction. 2761 * @hide 2762 */ 2763 static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR; 2764 2765 /** 2766 * Text direction is inherited through {@link ViewGroup} 2767 */ 2768 public static final int TEXT_DIRECTION_INHERIT = 0; 2769 2770 /** 2771 * Text direction is using "first strong algorithm". The first strong directional character 2772 * determines the paragraph direction. If there is no strong directional character, the 2773 * paragraph direction is the view's resolved layout direction. 2774 */ 2775 public static final int TEXT_DIRECTION_FIRST_STRONG = 1; 2776 2777 /** 2778 * Text direction is using "any-RTL" algorithm. The paragraph direction is RTL if it contains 2779 * any strong RTL character, otherwise it is LTR if it contains any strong LTR characters. 2780 * If there are neither, the paragraph direction is the view's resolved layout direction. 2781 */ 2782 public static final int TEXT_DIRECTION_ANY_RTL = 2; 2783 2784 /** 2785 * Text direction is forced to LTR. 2786 */ 2787 public static final int TEXT_DIRECTION_LTR = 3; 2788 2789 /** 2790 * Text direction is forced to RTL. 2791 */ 2792 public static final int TEXT_DIRECTION_RTL = 4; 2793 2794 /** 2795 * Text direction is coming from the system Locale. 2796 */ 2797 public static final int TEXT_DIRECTION_LOCALE = 5; 2798 2799 /** 2800 * Text direction is using "first strong algorithm". The first strong directional character 2801 * determines the paragraph direction. If there is no strong directional character, the 2802 * paragraph direction is LTR. 2803 */ 2804 public static final int TEXT_DIRECTION_FIRST_STRONG_LTR = 6; 2805 2806 /** 2807 * Text direction is using "first strong algorithm". The first strong directional character 2808 * determines the paragraph direction. If there is no strong directional character, the 2809 * paragraph direction is RTL. 2810 */ 2811 public static final int TEXT_DIRECTION_FIRST_STRONG_RTL = 7; 2812 2813 /** 2814 * Default text direction is inherited 2815 */ 2816 private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT; 2817 2818 /** 2819 * Default resolved text direction 2820 * @hide 2821 */ 2822 static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG; 2823 2824 /** 2825 * Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED) 2826 * @hide 2827 */ 2828 static final int PFLAG2_TEXT_DIRECTION_MASK_SHIFT = 6; 2829 2830 /** 2831 * Mask for use with private flags indicating bits used for text direction. 2832 * @hide 2833 */ 2834 static final int PFLAG2_TEXT_DIRECTION_MASK = 0x00000007 2835 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2836 2837 /** 2838 * Array of text direction flags for mapping attribute "textDirection" to correct 2839 * flag value. 2840 * @hide 2841 */ 2842 private static final int[] PFLAG2_TEXT_DIRECTION_FLAGS = { 2843 TEXT_DIRECTION_INHERIT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2844 TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2845 TEXT_DIRECTION_ANY_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2846 TEXT_DIRECTION_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2847 TEXT_DIRECTION_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2848 TEXT_DIRECTION_LOCALE << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2849 TEXT_DIRECTION_FIRST_STRONG_LTR << PFLAG2_TEXT_DIRECTION_MASK_SHIFT, 2850 TEXT_DIRECTION_FIRST_STRONG_RTL << PFLAG2_TEXT_DIRECTION_MASK_SHIFT 2851 }; 2852 2853 /** 2854 * Indicates whether the view text direction has been resolved. 2855 * @hide 2856 */ 2857 static final int PFLAG2_TEXT_DIRECTION_RESOLVED = 0x00000008 2858 << PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 2859 2860 /** 2861 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2862 * @hide 2863 */ 2864 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT = 10; 2865 2866 /** 2867 * Mask for use with private flags indicating bits used for resolved text direction. 2868 * @hide 2869 */ 2870 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_MASK = 0x00000007 2871 << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2872 2873 /** 2874 * Indicates whether the view text direction has been resolved to the "first strong" heuristic. 2875 * @hide 2876 */ 2877 static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT = 2878 TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 2879 2880 /** @hide */ 2881 @IntDef(prefix = { "TEXT_ALIGNMENT_" }, value = { 2882 TEXT_ALIGNMENT_INHERIT, 2883 TEXT_ALIGNMENT_GRAVITY, 2884 TEXT_ALIGNMENT_CENTER, 2885 TEXT_ALIGNMENT_TEXT_START, 2886 TEXT_ALIGNMENT_TEXT_END, 2887 TEXT_ALIGNMENT_VIEW_START, 2888 TEXT_ALIGNMENT_VIEW_END 2889 }) 2890 @Retention(RetentionPolicy.SOURCE) 2891 public @interface TextAlignment {} 2892 2893 /** 2894 * Default text alignment. The text alignment of this View is inherited from its parent. 2895 * Use with {@link #setTextAlignment(int)} 2896 */ 2897 public static final int TEXT_ALIGNMENT_INHERIT = 0; 2898 2899 /** 2900 * Default for the root view. The gravity determines the text alignment, ALIGN_NORMAL, 2901 * ALIGN_CENTER, or ALIGN_OPPOSITE, which are relative to each paragraph's text direction. 2902 * 2903 * Use with {@link #setTextAlignment(int)} 2904 */ 2905 public static final int TEXT_ALIGNMENT_GRAVITY = 1; 2906 2907 /** 2908 * Align to the start of the paragraph, e.g. ALIGN_NORMAL. 2909 * 2910 * Use with {@link #setTextAlignment(int)} 2911 */ 2912 public static final int TEXT_ALIGNMENT_TEXT_START = 2; 2913 2914 /** 2915 * Align to the end of the paragraph, e.g. ALIGN_OPPOSITE. 2916 * 2917 * Use with {@link #setTextAlignment(int)} 2918 */ 2919 public static final int TEXT_ALIGNMENT_TEXT_END = 3; 2920 2921 /** 2922 * Center the paragraph, e.g. ALIGN_CENTER. 2923 * 2924 * Use with {@link #setTextAlignment(int)} 2925 */ 2926 public static final int TEXT_ALIGNMENT_CENTER = 4; 2927 2928 /** 2929 * Align to the start of the view, which is ALIGN_LEFT if the view's resolved 2930 * layoutDirection is LTR, and ALIGN_RIGHT otherwise. 2931 * 2932 * Use with {@link #setTextAlignment(int)} 2933 */ 2934 public static final int TEXT_ALIGNMENT_VIEW_START = 5; 2935 2936 /** 2937 * Align to the end of the view, which is ALIGN_RIGHT if the view's resolved 2938 * layoutDirection is LTR, and ALIGN_LEFT otherwise. 2939 * 2940 * Use with {@link #setTextAlignment(int)} 2941 */ 2942 public static final int TEXT_ALIGNMENT_VIEW_END = 6; 2943 2944 /** 2945 * Default text alignment is inherited 2946 */ 2947 private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2948 2949 /** 2950 * Default resolved text alignment 2951 * @hide 2952 */ 2953 static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY; 2954 2955 /** 2956 * Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED) 2957 * @hide 2958 */ 2959 static final int PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT = 13; 2960 2961 /** 2962 * Mask for use with private flags indicating bits used for text alignment. 2963 * @hide 2964 */ 2965 static final int PFLAG2_TEXT_ALIGNMENT_MASK = 0x00000007 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2966 2967 /** 2968 * Array of text direction flags for mapping attribute "textAlignment" to correct 2969 * flag value. 2970 * @hide 2971 */ 2972 private static final int[] PFLAG2_TEXT_ALIGNMENT_FLAGS = { 2973 TEXT_ALIGNMENT_INHERIT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2974 TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2975 TEXT_ALIGNMENT_TEXT_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2976 TEXT_ALIGNMENT_TEXT_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2977 TEXT_ALIGNMENT_CENTER << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2978 TEXT_ALIGNMENT_VIEW_START << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT, 2979 TEXT_ALIGNMENT_VIEW_END << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT 2980 }; 2981 2982 /** 2983 * Indicates whether the view text alignment has been resolved. 2984 * @hide 2985 */ 2986 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED = 0x00000008 << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 2987 2988 /** 2989 * Bit shift to get the resolved text alignment. 2990 * @hide 2991 */ 2992 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT = 17; 2993 2994 /** 2995 * Mask for use with private flags indicating bits used for text alignment. 2996 * @hide 2997 */ 2998 static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK = 0x00000007 2999 << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 3000 3001 /** 3002 * Indicates whether if the view text alignment has been resolved to gravity 3003 */ 3004 private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT = 3005 TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 3006 3007 // Accessiblity constants for mPrivateFlags2 3008 3009 /** 3010 * Shift for the bits in {@link #mPrivateFlags2} related to the 3011 * "importantForAccessibility" attribute. 3012 */ 3013 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT = 20; 3014 3015 /** 3016 * Automatically determine whether a view is important for accessibility. 3017 */ 3018 public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000; 3019 3020 /** 3021 * The view is important for accessibility. 3022 */ 3023 public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001; 3024 3025 /** 3026 * The view is not important for accessibility. 3027 */ 3028 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002; 3029 3030 /** 3031 * The view is not important for accessibility, nor are any of its 3032 * descendant views. 3033 */ 3034 public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004; 3035 3036 /** 3037 * The default whether the view is important for accessibility. 3038 */ 3039 static final int IMPORTANT_FOR_ACCESSIBILITY_DEFAULT = IMPORTANT_FOR_ACCESSIBILITY_AUTO; 3040 3041 /** 3042 * Mask for obtaining the bits which specify how to determine 3043 * whether a view is important for accessibility. 3044 */ 3045 static final int PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK = (IMPORTANT_FOR_ACCESSIBILITY_AUTO 3046 | IMPORTANT_FOR_ACCESSIBILITY_YES | IMPORTANT_FOR_ACCESSIBILITY_NO 3047 | IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) 3048 << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 3049 3050 /** 3051 * Shift for the bits in {@link #mPrivateFlags2} related to the 3052 * "accessibilityLiveRegion" attribute. 3053 */ 3054 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT = 23; 3055 3056 /** 3057 * Live region mode specifying that accessibility services should not 3058 * automatically announce changes to this view. This is the default live 3059 * region mode for most views. 3060 * <p> 3061 * Use with {@link #setAccessibilityLiveRegion(int)}. 3062 */ 3063 public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000; 3064 3065 /** 3066 * Live region mode specifying that accessibility services should announce 3067 * changes to this view. 3068 * <p> 3069 * Use with {@link #setAccessibilityLiveRegion(int)}. 3070 */ 3071 public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001; 3072 3073 /** 3074 * Live region mode specifying that accessibility services should interrupt 3075 * ongoing speech to immediately announce changes to this view. 3076 * <p> 3077 * Use with {@link #setAccessibilityLiveRegion(int)}. 3078 */ 3079 public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002; 3080 3081 /** 3082 * The default whether the view is important for accessibility. 3083 */ 3084 static final int ACCESSIBILITY_LIVE_REGION_DEFAULT = ACCESSIBILITY_LIVE_REGION_NONE; 3085 3086 /** 3087 * Mask for obtaining the bits which specify a view's accessibility live 3088 * region mode. 3089 */ 3090 static final int PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK = (ACCESSIBILITY_LIVE_REGION_NONE 3091 | ACCESSIBILITY_LIVE_REGION_POLITE | ACCESSIBILITY_LIVE_REGION_ASSERTIVE) 3092 << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 3093 3094 /** 3095 * Flag indicating whether a view has accessibility focus. 3096 */ 3097 static final int PFLAG2_ACCESSIBILITY_FOCUSED = 0x04000000; 3098 3099 /** 3100 * Flag whether the accessibility state of the subtree rooted at this view changed. 3101 */ 3102 static final int PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED = 0x08000000; 3103 3104 /** 3105 * Flag indicating whether a view failed the quickReject() check in draw(). This condition 3106 * is used to check whether later changes to the view's transform should invalidate the 3107 * view to force the quickReject test to run again. 3108 */ 3109 static final int PFLAG2_VIEW_QUICK_REJECTED = 0x10000000; 3110 3111 /** 3112 * Flag indicating that start/end padding has been resolved into left/right padding 3113 * for use in measurement, layout, drawing, etc. This is set by {@link #resolvePadding()} 3114 * and checked by {@link #measure(int, int)} to determine if padding needs to be resolved 3115 * during measurement. In some special cases this is required such as when an adapter-based 3116 * view measures prospective children without attaching them to a window. 3117 */ 3118 static final int PFLAG2_PADDING_RESOLVED = 0x20000000; 3119 3120 /** 3121 * Flag indicating that the start/end drawables has been resolved into left/right ones. 3122 */ 3123 static final int PFLAG2_DRAWABLE_RESOLVED = 0x40000000; 3124 3125 /** 3126 * Indicates that the view is tracking some sort of transient state 3127 * that the app should not need to be aware of, but that the framework 3128 * should take special care to preserve. 3129 */ 3130 static final int PFLAG2_HAS_TRANSIENT_STATE = 0x80000000; 3131 3132 /** 3133 * Group of bits indicating that RTL properties resolution is done. 3134 */ 3135 static final int ALL_RTL_PROPERTIES_RESOLVED = PFLAG2_LAYOUT_DIRECTION_RESOLVED | 3136 PFLAG2_TEXT_DIRECTION_RESOLVED | 3137 PFLAG2_TEXT_ALIGNMENT_RESOLVED | 3138 PFLAG2_PADDING_RESOLVED | 3139 PFLAG2_DRAWABLE_RESOLVED; 3140 3141 // There are a couple of flags left in mPrivateFlags2 3142 3143 /* End of masks for mPrivateFlags2 */ 3144 3145 /* 3146 * Masks for mPrivateFlags3, as generated by dumpFlags(): 3147 * 3148 * |-------|-------|-------|-------| 3149 * 1 PFLAG3_VIEW_IS_ANIMATING_TRANSFORM 3150 * 1 PFLAG3_VIEW_IS_ANIMATING_ALPHA 3151 * 1 PFLAG3_IS_LAID_OUT 3152 * 1 PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT 3153 * 1 PFLAG3_CALLED_SUPER 3154 * 1 PFLAG3_APPLYING_INSETS 3155 * 1 PFLAG3_FITTING_SYSTEM_WINDOWS 3156 * 1 PFLAG3_NESTED_SCROLLING_ENABLED 3157 * 1 PFLAG3_SCROLL_INDICATOR_TOP 3158 * 1 PFLAG3_SCROLL_INDICATOR_BOTTOM 3159 * 1 PFLAG3_SCROLL_INDICATOR_LEFT 3160 * 1 PFLAG3_SCROLL_INDICATOR_RIGHT 3161 * 1 PFLAG3_SCROLL_INDICATOR_START 3162 * 1 PFLAG3_SCROLL_INDICATOR_END 3163 * 1 PFLAG3_ASSIST_BLOCKED 3164 * 1 PFLAG3_CLUSTER 3165 * 1 PFLAG3_IS_AUTOFILLED 3166 * 1 PFLAG3_FINGER_DOWN 3167 * 1 PFLAG3_FOCUSED_BY_DEFAULT 3168 * 1111 PFLAG3_IMPORTANT_FOR_AUTOFILL 3169 * 1 PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE 3170 * 1 PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED 3171 * 1 PFLAG3_TEMPORARY_DETACH 3172 * 1 PFLAG3_NO_REVEAL_ON_FOCUS 3173 * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT 3174 * 1 PFLAG3_SCREEN_READER_FOCUSABLE 3175 * 1 PFLAG3_AGGREGATED_VISIBLE 3176 * 1 PFLAG3_AUTOFILLID_EXPLICITLY_SET 3177 * 1 PFLAG3_ACCESSIBILITY_HEADING 3178 * |-------|-------|-------|-------| 3179 */ 3180 3181 /** 3182 * Flag indicating that view has a transform animation set on it. This is used to track whether 3183 * an animation is cleared between successive frames, in order to tell the associated 3184 * DisplayList to clear its animation matrix. 3185 */ 3186 static final int PFLAG3_VIEW_IS_ANIMATING_TRANSFORM = 0x1; 3187 3188 /** 3189 * Flag indicating that view has an alpha animation set on it. This is used to track whether an 3190 * animation is cleared between successive frames, in order to tell the associated 3191 * DisplayList to restore its alpha value. 3192 */ 3193 static final int PFLAG3_VIEW_IS_ANIMATING_ALPHA = 0x2; 3194 3195 /** 3196 * Flag indicating that the view has been through at least one layout since it 3197 * was last attached to a window. 3198 */ 3199 static final int PFLAG3_IS_LAID_OUT = 0x4; 3200 3201 /** 3202 * Flag indicating that a call to measure() was skipped and should be done 3203 * instead when layout() is invoked. 3204 */ 3205 static final int PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT = 0x8; 3206 3207 /** 3208 * Flag indicating that an overridden method correctly called down to 3209 * the superclass implementation as required by the API spec. 3210 */ 3211 static final int PFLAG3_CALLED_SUPER = 0x10; 3212 3213 /** 3214 * Flag indicating that we're in the process of applying window insets. 3215 */ 3216 static final int PFLAG3_APPLYING_INSETS = 0x20; 3217 3218 /** 3219 * Flag indicating that we're in the process of fitting system windows using the old method. 3220 */ 3221 static final int PFLAG3_FITTING_SYSTEM_WINDOWS = 0x40; 3222 3223 /** 3224 * Flag indicating that nested scrolling is enabled for this view. 3225 * The view will optionally cooperate with views up its parent chain to allow for 3226 * integrated nested scrolling along the same axis. 3227 */ 3228 static final int PFLAG3_NESTED_SCROLLING_ENABLED = 0x80; 3229 3230 /** 3231 * Flag indicating that the bottom scroll indicator should be displayed 3232 * when this view can scroll up. 3233 */ 3234 static final int PFLAG3_SCROLL_INDICATOR_TOP = 0x0100; 3235 3236 /** 3237 * Flag indicating that the bottom scroll indicator should be displayed 3238 * when this view can scroll down. 3239 */ 3240 static final int PFLAG3_SCROLL_INDICATOR_BOTTOM = 0x0200; 3241 3242 /** 3243 * Flag indicating that the left scroll indicator should be displayed 3244 * when this view can scroll left. 3245 */ 3246 static final int PFLAG3_SCROLL_INDICATOR_LEFT = 0x0400; 3247 3248 /** 3249 * Flag indicating that the right scroll indicator should be displayed 3250 * when this view can scroll right. 3251 */ 3252 static final int PFLAG3_SCROLL_INDICATOR_RIGHT = 0x0800; 3253 3254 /** 3255 * Flag indicating that the start scroll indicator should be displayed 3256 * when this view can scroll in the start direction. 3257 */ 3258 static final int PFLAG3_SCROLL_INDICATOR_START = 0x1000; 3259 3260 /** 3261 * Flag indicating that the end scroll indicator should be displayed 3262 * when this view can scroll in the end direction. 3263 */ 3264 static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000; 3265 3266 static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED; 3267 3268 static final int SCROLL_INDICATORS_NONE = 0x0000; 3269 3270 /** 3271 * Mask for use with setFlags indicating bits used for indicating which 3272 * scroll indicators are enabled. 3273 */ 3274 static final int SCROLL_INDICATORS_PFLAG3_MASK = PFLAG3_SCROLL_INDICATOR_TOP 3275 | PFLAG3_SCROLL_INDICATOR_BOTTOM | PFLAG3_SCROLL_INDICATOR_LEFT 3276 | PFLAG3_SCROLL_INDICATOR_RIGHT | PFLAG3_SCROLL_INDICATOR_START 3277 | PFLAG3_SCROLL_INDICATOR_END; 3278 3279 /** 3280 * Left-shift required to translate between public scroll indicator flags 3281 * and internal PFLAGS3 flags. When used as a right-shift, translates 3282 * PFLAGS3 flags to public flags. 3283 */ 3284 static final int SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT = 8; 3285 3286 /** @hide */ 3287 @Retention(RetentionPolicy.SOURCE) 3288 @IntDef(flag = true, prefix = { "SCROLL_INDICATOR_" }, value = { 3289 SCROLL_INDICATOR_TOP, 3290 SCROLL_INDICATOR_BOTTOM, 3291 SCROLL_INDICATOR_LEFT, 3292 SCROLL_INDICATOR_RIGHT, 3293 SCROLL_INDICATOR_START, 3294 SCROLL_INDICATOR_END, 3295 }) 3296 public @interface ScrollIndicators {} 3297 3298 /** 3299 * Scroll indicator direction for the top edge of the view. 3300 * 3301 * @see #setScrollIndicators(int) 3302 * @see #setScrollIndicators(int, int) 3303 * @see #getScrollIndicators() 3304 */ 3305 public static final int SCROLL_INDICATOR_TOP = 3306 PFLAG3_SCROLL_INDICATOR_TOP >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3307 3308 /** 3309 * Scroll indicator direction for the bottom edge of the view. 3310 * 3311 * @see #setScrollIndicators(int) 3312 * @see #setScrollIndicators(int, int) 3313 * @see #getScrollIndicators() 3314 */ 3315 public static final int SCROLL_INDICATOR_BOTTOM = 3316 PFLAG3_SCROLL_INDICATOR_BOTTOM >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3317 3318 /** 3319 * Scroll indicator direction for the left edge of the view. 3320 * 3321 * @see #setScrollIndicators(int) 3322 * @see #setScrollIndicators(int, int) 3323 * @see #getScrollIndicators() 3324 */ 3325 public static final int SCROLL_INDICATOR_LEFT = 3326 PFLAG3_SCROLL_INDICATOR_LEFT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3327 3328 /** 3329 * Scroll indicator direction for the right edge of the view. 3330 * 3331 * @see #setScrollIndicators(int) 3332 * @see #setScrollIndicators(int, int) 3333 * @see #getScrollIndicators() 3334 */ 3335 public static final int SCROLL_INDICATOR_RIGHT = 3336 PFLAG3_SCROLL_INDICATOR_RIGHT >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3337 3338 /** 3339 * Scroll indicator direction for the starting edge of the view. 3340 * <p> 3341 * Resolved according to the view's layout direction, see 3342 * {@link #getLayoutDirection()} for more information. 3343 * 3344 * @see #setScrollIndicators(int) 3345 * @see #setScrollIndicators(int, int) 3346 * @see #getScrollIndicators() 3347 */ 3348 public static final int SCROLL_INDICATOR_START = 3349 PFLAG3_SCROLL_INDICATOR_START >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3350 3351 /** 3352 * Scroll indicator direction for the ending edge of the view. 3353 * <p> 3354 * Resolved according to the view's layout direction, see 3355 * {@link #getLayoutDirection()} for more information. 3356 * 3357 * @see #setScrollIndicators(int) 3358 * @see #setScrollIndicators(int, int) 3359 * @see #getScrollIndicators() 3360 */ 3361 public static final int SCROLL_INDICATOR_END = 3362 PFLAG3_SCROLL_INDICATOR_END >> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 3363 3364 /** 3365 * <p>Indicates that we are allowing {@link ViewStructure} to traverse 3366 * into this view.<p> 3367 */ 3368 static final int PFLAG3_ASSIST_BLOCKED = 0x4000; 3369 3370 /** 3371 * Flag indicating that the view is a root of a keyboard navigation cluster. 3372 * 3373 * @see #isKeyboardNavigationCluster() 3374 * @see #setKeyboardNavigationCluster(boolean) 3375 */ 3376 private static final int PFLAG3_CLUSTER = 0x8000; 3377 3378 /** 3379 * Flag indicating that the view is autofilled 3380 * 3381 * @see #isAutofilled() 3382 * @see #setAutofilled(boolean, boolean) 3383 */ 3384 private static final int PFLAG3_IS_AUTOFILLED = 0x10000; 3385 3386 /** 3387 * Indicates that the user is currently touching the screen. 3388 * Currently used for the tooltip positioning only. 3389 */ 3390 private static final int PFLAG3_FINGER_DOWN = 0x20000; 3391 3392 /** 3393 * Flag indicating that this view is the default-focus view. 3394 * 3395 * @see #isFocusedByDefault() 3396 * @see #setFocusedByDefault(boolean) 3397 */ 3398 private static final int PFLAG3_FOCUSED_BY_DEFAULT = 0x40000; 3399 3400 /** 3401 * Shift for the bits in {@link #mPrivateFlags3} related to the 3402 * "importantForAutofill" attribute. 3403 */ 3404 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT = 19; 3405 3406 /** 3407 * Mask for obtaining the bits which specify how to determine 3408 * whether a view is important for autofill. 3409 */ 3410 static final int PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK = (IMPORTANT_FOR_AUTOFILL_AUTO 3411 | IMPORTANT_FOR_AUTOFILL_YES | IMPORTANT_FOR_AUTOFILL_NO 3412 | IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 3413 | IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS) 3414 << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 3415 3416 /** 3417 * Whether this view has rendered elements that overlap (see {@link 3418 * #hasOverlappingRendering()}, {@link #forceHasOverlappingRendering(boolean)}, and 3419 * {@link #getHasOverlappingRendering()} ). The value in this bit is only valid when 3420 * PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED has been set. Otherwise, the value is 3421 * determined by whatever {@link #hasOverlappingRendering()} returns. 3422 */ 3423 private static final int PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE = 0x800000; 3424 3425 /** 3426 * Whether {@link #forceHasOverlappingRendering(boolean)} has been called. When true, value 3427 * in PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE is valid. 3428 */ 3429 private static final int PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED = 0x1000000; 3430 3431 /** 3432 * Flag indicating that the view is temporarily detached from the parent view. 3433 * 3434 * @see #onStartTemporaryDetach() 3435 * @see #onFinishTemporaryDetach() 3436 */ 3437 static final int PFLAG3_TEMPORARY_DETACH = 0x2000000; 3438 3439 /** 3440 * Flag indicating that the view does not wish to be revealed within its parent 3441 * hierarchy when it gains focus. Expressed in the negative since the historical 3442 * default behavior is to reveal on focus; this flag suppresses that behavior. 3443 * 3444 * @see #setRevealOnFocusHint(boolean) 3445 * @see #getRevealOnFocusHint() 3446 */ 3447 private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000; 3448 3449 /** 3450 * Flag indicating that when layout is completed we should notify 3451 * that the view was entered for autofill purposes. To minimize 3452 * showing autofill for views not visible to the user we evaluate 3453 * user visibility which cannot be done until the view is laid out. 3454 */ 3455 static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000; 3456 3457 /** 3458 * Works like focusable for screen readers, but without the side effects on input focus. 3459 * @see #setScreenReaderFocusable(boolean) 3460 */ 3461 private static final int PFLAG3_SCREEN_READER_FOCUSABLE = 0x10000000; 3462 3463 /** 3464 * The last aggregated visibility. Used to detect when it truly changes. 3465 */ 3466 private static final int PFLAG3_AGGREGATED_VISIBLE = 0x20000000; 3467 3468 /** 3469 * Used to indicate that {@link #mAutofillId} was explicitly set through 3470 * {@link #setAutofillId(AutofillId)}. 3471 */ 3472 private static final int PFLAG3_AUTOFILLID_EXPLICITLY_SET = 0x40000000; 3473 3474 /** 3475 * Indicates if the View is a heading for accessibility purposes 3476 */ 3477 private static final int PFLAG3_ACCESSIBILITY_HEADING = 0x80000000; 3478 3479 /* End of masks for mPrivateFlags3 */ 3480 3481 /* 3482 * Masks for mPrivateFlags4, as generated by dumpFlags(): 3483 * 3484 * |-------|-------|-------|-------| 3485 * 1111 PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK 3486 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED 3487 * 1 PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED 3488 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3489 * 1 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE 3490 * 11 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK 3491 * 1 PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS 3492 * 1 PFLAG4_AUTOFILL_HIDE_HIGHLIGHT 3493 * 11 PFLAG4_SCROLL_CAPTURE_HINT_MASK 3494 * |-------|-------|-------|-------| 3495 */ 3496 3497 /** 3498 * Mask for obtaining the bits which specify how to determine 3499 * whether a view is important for autofill. 3500 * 3501 * <p>NOTE: the important for content capture values were the first flags added and are set in 3502 * the rightmost position, so we don't need to shift them 3503 */ 3504 private static final int PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK = 3505 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO | IMPORTANT_FOR_CONTENT_CAPTURE_YES 3506 | IMPORTANT_FOR_CONTENT_CAPTURE_NO 3507 | IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 3508 | IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS; 3509 3510 /* 3511 * Variables used to control when the IntelligenceManager.notifyNodeAdded()/removed() methods 3512 * should be called. 3513 * 3514 * The idea is to call notifyAppeared() after the view is layout and visible, then call 3515 * notifyDisappeared() when it's gone (without known when it was removed from the parent). 3516 */ 3517 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED = 0x10; 3518 private static final int PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED = 0x20; 3519 3520 /* 3521 * Flags used to cache the value returned by isImportantForContentCapture while the view 3522 * hierarchy is being traversed. 3523 */ 3524 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED = 0x40; 3525 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE = 0x80; 3526 3527 private static final int PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK = 3528 PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED 3529 | PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 3530 3531 /** 3532 * @see #OPTIONAL_FITS_SYSTEM_WINDOWS 3533 */ 3534 static final int PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS = 0x000000100; 3535 3536 /** 3537 * Flag indicating the field should not have yellow highlight when autofilled. 3538 */ 3539 private static final int PFLAG4_AUTOFILL_HIDE_HIGHLIGHT = 0x200; 3540 3541 /** 3542 * Shift for the bits in {@link #mPrivateFlags4} related to scroll capture. 3543 */ 3544 static final int PFLAG4_SCROLL_CAPTURE_HINT_SHIFT = 10; 3545 3546 static final int PFLAG4_SCROLL_CAPTURE_HINT_MASK = (SCROLL_CAPTURE_HINT_INCLUDE 3547 | SCROLL_CAPTURE_HINT_EXCLUDE | SCROLL_CAPTURE_HINT_EXCLUDE_DESCENDANTS) 3548 << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; 3549 3550 /* End of masks for mPrivateFlags4 */ 3551 3552 /** @hide */ 3553 protected static final int VIEW_STRUCTURE_FOR_ASSIST = 0; 3554 /** @hide */ 3555 protected static final int VIEW_STRUCTURE_FOR_AUTOFILL = 1; 3556 /** @hide */ 3557 protected static final int VIEW_STRUCTURE_FOR_CONTENT_CAPTURE = 2; 3558 3559 /** @hide */ 3560 @IntDef(flag = true, prefix = { "VIEW_STRUCTURE_FOR" }, value = { 3561 VIEW_STRUCTURE_FOR_ASSIST, 3562 VIEW_STRUCTURE_FOR_AUTOFILL, 3563 VIEW_STRUCTURE_FOR_CONTENT_CAPTURE 3564 }) 3565 @Retention(RetentionPolicy.SOURCE) 3566 public @interface ViewStructureType {} 3567 3568 /** 3569 * Always allow a user to over-scroll this view, provided it is a 3570 * view that can scroll. 3571 * 3572 * @see #getOverScrollMode() 3573 * @see #setOverScrollMode(int) 3574 */ 3575 public static final int OVER_SCROLL_ALWAYS = 0; 3576 3577 /** 3578 * Allow a user to over-scroll this view only if the content is large 3579 * enough to meaningfully scroll, provided it is a view that can scroll. 3580 * 3581 * @see #getOverScrollMode() 3582 * @see #setOverScrollMode(int) 3583 */ 3584 public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1; 3585 3586 /** 3587 * Never allow a user to over-scroll this view. 3588 * 3589 * @see #getOverScrollMode() 3590 * @see #setOverScrollMode(int) 3591 */ 3592 public static final int OVER_SCROLL_NEVER = 2; 3593 3594 /** 3595 * Special constant for {@link #setSystemUiVisibility(int)}: View has 3596 * requested the system UI (status bar) to be visible (the default). 3597 * 3598 * @see #setSystemUiVisibility(int) 3599 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 3600 * instead. 3601 */ 3602 @Deprecated 3603 public static final int SYSTEM_UI_FLAG_VISIBLE = 0; 3604 3605 /** 3606 * Flag for {@link #setSystemUiVisibility(int)}: View has requested the 3607 * system UI to enter an unobtrusive "low profile" mode. 3608 * 3609 * <p>This is for use in games, book readers, video players, or any other 3610 * "immersive" application where the usual system chrome is deemed too distracting. 3611 * 3612 * <p>In low profile mode, the status bar and/or navigation icons may dim. 3613 * 3614 * @see #setSystemUiVisibility(int) 3615 * @deprecated Low profile mode is deprecated. Hide the system bars instead if the application 3616 * needs to be in a unobtrusive mode. Use {@link WindowInsetsController#hide(int)} with 3617 * {@link Type#systemBars()}. 3618 */ 3619 @Deprecated 3620 public static final int SYSTEM_UI_FLAG_LOW_PROFILE = 0x00000001; 3621 3622 /** 3623 * Flag for {@link #setSystemUiVisibility(int)}: View has requested that the 3624 * system navigation be temporarily hidden. 3625 * 3626 * <p>This is an even less obtrusive state than that called for by 3627 * {@link #SYSTEM_UI_FLAG_LOW_PROFILE}; on devices that draw essential navigation controls 3628 * (Home, Back, and the like) on screen, <code>SYSTEM_UI_FLAG_HIDE_NAVIGATION</code> will cause 3629 * those to disappear. This is useful (in conjunction with the 3630 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN FLAG_FULLSCREEN} and 3631 * {@link android.view.WindowManager.LayoutParams#FLAG_LAYOUT_IN_SCREEN FLAG_LAYOUT_IN_SCREEN} 3632 * window flags) for displaying content using every last pixel on the display. 3633 * 3634 * <p>There is a limitation: because navigation controls are so important, the least user 3635 * interaction will cause them to reappear immediately. When this happens, both 3636 * this flag and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be cleared automatically, 3637 * so that both elements reappear at the same time. 3638 * 3639 * @see #setSystemUiVisibility(int) 3640 * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#navigationBars()} 3641 * instead. 3642 */ 3643 @Deprecated 3644 public static final int SYSTEM_UI_FLAG_HIDE_NAVIGATION = 0x00000002; 3645 3646 /** 3647 * Flag for {@link #setSystemUiVisibility(int)}: View has requested to go 3648 * into the normal fullscreen mode so that its content can take over the screen 3649 * while still allowing the user to interact with the application. 3650 * 3651 * <p>This has the same visual effect as 3652 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN 3653 * WindowManager.LayoutParams.FLAG_FULLSCREEN}, 3654 * meaning that non-critical screen decorations (such as the status bar) will be 3655 * hidden while the user is in the View's window, focusing the experience on 3656 * that content. Unlike the window flag, if you are using ActionBar in 3657 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3658 * Window.FEATURE_ACTION_BAR_OVERLAY}, then enabling this flag will also 3659 * hide the action bar. 3660 * 3661 * <p>This approach to going fullscreen is best used over the window flag when 3662 * it is a transient state -- that is, the application does this at certain 3663 * points in its user interaction where it wants to allow the user to focus 3664 * on content, but not as a continuous state. For situations where the application 3665 * would like to simply stay full screen the entire time (such as a game that 3666 * wants to take over the screen), the 3667 * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN window flag} 3668 * is usually a better approach. The state set here will be removed by the system 3669 * in various situations (such as the user moving to another application) like 3670 * the other system UI states. 3671 * 3672 * <p>When using this flag, the application should provide some easy facility 3673 * for the user to go out of it. A common example would be in an e-book 3674 * reader, where tapping on the screen brings back whatever screen and UI 3675 * decorations that had been hidden while the user was immersed in reading 3676 * the book. 3677 * 3678 * @see #setSystemUiVisibility(int) 3679 * @deprecated Use {@link WindowInsetsController#hide(int)} with {@link Type#statusBars()} 3680 * instead. 3681 */ 3682 @Deprecated 3683 public static final int SYSTEM_UI_FLAG_FULLSCREEN = 0x00000004; 3684 3685 /** 3686 * Flag for {@link #setSystemUiVisibility(int)}: When using other layout 3687 * flags, we would like a stable view of the content insets given to 3688 * {@link #fitSystemWindows(Rect)}. This means that the insets seen there 3689 * will always represent the worst case that the application can expect 3690 * as a continuous state. In the stock Android UI this is the space for 3691 * the system bar, nav bar, and status bar, but not more transient elements 3692 * such as an input method. 3693 * 3694 * The stable layout your UI sees is based on the system UI modes you can 3695 * switch to. That is, if you specify {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 3696 * then you will get a stable layout for changes of the 3697 * {@link #SYSTEM_UI_FLAG_FULLSCREEN} mode; if you specify 3698 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} and 3699 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, then you can transition 3700 * to {@link #SYSTEM_UI_FLAG_FULLSCREEN} and {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} 3701 * with a stable layout. (Note that you should avoid using 3702 * {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} by itself.) 3703 * 3704 * If you have set the window flag {@link WindowManager.LayoutParams#FLAG_FULLSCREEN} 3705 * to hide the status bar (instead of using {@link #SYSTEM_UI_FLAG_FULLSCREEN}), 3706 * then a hidden status bar will be considered a "stable" state for purposes 3707 * here. This allows your UI to continually hide the status bar, while still 3708 * using the system UI flags to hide the action bar while still retaining 3709 * a stable layout. Note that changing the window fullscreen flag will never 3710 * provide a stable layout for a clean transition. 3711 * 3712 * <p>If you are using ActionBar in 3713 * overlay mode with {@link Window#FEATURE_ACTION_BAR_OVERLAY 3714 * Window.FEATURE_ACTION_BAR_OVERLAY}, this flag will also impact the 3715 * insets it adds to those given to the application. 3716 * 3717 * @deprecated Use {@link WindowInsets#getInsetsIgnoringVisibility(int)} instead to retrieve 3718 * insets that don't change when system bars change visibility state. 3719 */ 3720 @Deprecated 3721 public static final int SYSTEM_UI_FLAG_LAYOUT_STABLE = 0x00000100; 3722 3723 /** 3724 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3725 * to be laid out as if it has requested 3726 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, even if it currently hasn't. This 3727 * allows it to avoid artifacts when switching in and out of that mode, at 3728 * the expense that some of its user interface may be covered by screen 3729 * decorations when they are shown. You can perform layout of your inner 3730 * UI elements to account for the navigation system UI through the 3731 * {@link #fitSystemWindows(Rect)} method. 3732 * 3733 * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with 3734 * {@link Type#navigationBars()}. For non-floating windows that fill the screen, call 3735 * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. 3736 */ 3737 public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200; 3738 3739 /** 3740 * Flag for {@link #setSystemUiVisibility(int)}: View would like its window 3741 * to be laid out as if it has requested 3742 * {@link #SYSTEM_UI_FLAG_FULLSCREEN}, even if it currently hasn't. This 3743 * allows it to avoid artifacts when switching in and out of that mode, at 3744 * the expense that some of its user interface may be covered by screen 3745 * decorations when they are shown. You can perform layout of your inner 3746 * UI elements to account for non-fullscreen system UI through the 3747 * {@link #fitSystemWindows(Rect)} method. 3748 * 3749 * <p>Note: on displays that have a {@link DisplayCutout}, the window may still be placed 3750 * differently than if {@link #SYSTEM_UI_FLAG_FULLSCREEN} was set, if the 3751 * window's {@link WindowManager.LayoutParams#layoutInDisplayCutoutMode 3752 * layoutInDisplayCutoutMode} is 3753 * {@link WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3754 * LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT}. To avoid this, use either of the other modes. 3755 * 3756 * @see WindowManager.LayoutParams#layoutInDisplayCutoutMode 3757 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 3758 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 3759 * @see WindowManager.LayoutParams#LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 3760 * 3761 * @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with 3762 * {@link Type#statusBars()} ()}. For non-floating windows that fill the screen, call 3763 * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}. 3764 */ 3765 @Deprecated 3766 public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400; 3767 3768 /** 3769 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3770 * hiding the navigation bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. If this flag is 3771 * not set, {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any 3772 * user interaction. 3773 * <p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only 3774 * has an effect when used in combination with that flag.</p> 3775 * 3776 * @deprecated Use {@link WindowInsetsController#BEHAVIOR_SHOW_BARS_BY_SWIPE} instead. 3777 */ 3778 @Deprecated 3779 public static final int SYSTEM_UI_FLAG_IMMERSIVE = 0x00000800; 3780 3781 /** 3782 * Flag for {@link #setSystemUiVisibility(int)}: View would like to remain interactive when 3783 * hiding the status bar with {@link #SYSTEM_UI_FLAG_FULLSCREEN} and/or hiding the navigation 3784 * bar with {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}. Use this flag to create an immersive 3785 * experience while also hiding the system bars. If this flag is not set, 3786 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION} will be force cleared by the system on any user 3787 * interaction, and {@link #SYSTEM_UI_FLAG_FULLSCREEN} will be force-cleared by the system 3788 * if the user swipes from the top of the screen. 3789 * <p>When system bars are hidden in immersive mode, they can be revealed temporarily with 3790 * system gestures, such as swiping from the top of the screen. These transient system bars 3791 * will overlay app's content, may have some degree of transparency, and will automatically 3792 * hide after a short timeout. 3793 * </p><p>Since this flag is a modifier for {@link #SYSTEM_UI_FLAG_FULLSCREEN} and 3794 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, it only has an effect when used in combination 3795 * with one or both of those flags.</p> 3796 * 3797 * @deprecated Use {@link WindowInsetsController#BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE} instead. 3798 */ 3799 @Deprecated 3800 public static final int SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000; 3801 3802 /** 3803 * Flag for {@link #setSystemUiVisibility(int)}: Requests the status bar to draw in a mode that 3804 * is compatible with light status bar backgrounds. 3805 * 3806 * <p>For this to take effect, the window must request 3807 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3808 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3809 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_STATUS 3810 * FLAG_TRANSLUCENT_STATUS}. 3811 * 3812 * @see android.R.attr#windowLightStatusBar 3813 * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_STATUS_BARS} instead. 3814 */ 3815 @Deprecated 3816 public static final int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0x00002000; 3817 3818 /** 3819 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3820 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3821 */ 3822 private static final int SYSTEM_UI_RESERVED_LEGACY1 = 0x00004000; 3823 3824 /** 3825 * This flag was previously used for a private API. DO NOT reuse it for a public API as it might 3826 * trigger undefined behavior on older platforms with apps compiled against a new SDK. 3827 */ 3828 private static final int SYSTEM_UI_RESERVED_LEGACY2 = 0x00010000; 3829 3830 /** 3831 * Flag for {@link #setSystemUiVisibility(int)}: Requests the navigation bar to draw in a mode 3832 * that is compatible with light navigation bar backgrounds. 3833 * 3834 * <p>For this to take effect, the window must request 3835 * {@link android.view.WindowManager.LayoutParams#FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 3836 * FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS} but not 3837 * {@link android.view.WindowManager.LayoutParams#FLAG_TRANSLUCENT_NAVIGATION 3838 * FLAG_TRANSLUCENT_NAVIGATION}. 3839 * 3840 * @see android.R.attr#windowLightNavigationBar 3841 * @deprecated Use {@link WindowInsetsController#APPEARANCE_LIGHT_NAVIGATION_BARS} instead. 3842 */ 3843 @Deprecated 3844 public static final int SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR = 0x00000010; 3845 3846 /** 3847 * @deprecated Use {@link #SYSTEM_UI_FLAG_LOW_PROFILE} instead. 3848 */ 3849 @Deprecated 3850 public static final int STATUS_BAR_HIDDEN = SYSTEM_UI_FLAG_LOW_PROFILE; 3851 3852 /** 3853 * @deprecated Use {@link #SYSTEM_UI_FLAG_VISIBLE} instead. 3854 */ 3855 @Deprecated 3856 public static final int STATUS_BAR_VISIBLE = SYSTEM_UI_FLAG_VISIBLE; 3857 3858 /** 3859 * @hide 3860 * 3861 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3862 * out of the public fields to keep the undefined bits out of the developer's way. 3863 * 3864 * Flag to make the status bar not expandable. Unless you also 3865 * set {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS}, new notifications will continue to show. 3866 */ 3867 @UnsupportedAppUsage 3868 public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000; 3869 3870 /** 3871 * @hide 3872 * 3873 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3874 * out of the public fields to keep the undefined bits out of the developer's way. 3875 * 3876 * Flag to hide notification icons and scrolling ticker text. 3877 */ 3878 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ICONS = 0x00020000; 3879 3880 /** 3881 * @hide 3882 * 3883 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3884 * out of the public fields to keep the undefined bits out of the developer's way. 3885 * 3886 * Flag to disable incoming notification alerts. This will not block 3887 * icons, but it will block sound, vibrating and other visual or aural notifications. 3888 */ 3889 public static final int STATUS_BAR_DISABLE_NOTIFICATION_ALERTS = 0x00040000; 3890 3891 /** 3892 * @hide 3893 * 3894 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3895 * out of the public fields to keep the undefined bits out of the developer's way. 3896 * 3897 * Flag to hide only the scrolling ticker. Note that 3898 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_ICONS} implies 3899 * {@link #STATUS_BAR_DISABLE_NOTIFICATION_TICKER}. 3900 */ 3901 public static final int STATUS_BAR_DISABLE_NOTIFICATION_TICKER = 0x00080000; 3902 3903 /** 3904 * @hide 3905 * 3906 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3907 * out of the public fields to keep the undefined bits out of the developer's way. 3908 * 3909 * Flag to hide the center system info area. 3910 */ 3911 public static final int STATUS_BAR_DISABLE_SYSTEM_INFO = 0x00100000; 3912 3913 /** 3914 * @hide 3915 * 3916 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3917 * out of the public fields to keep the undefined bits out of the developer's way. 3918 * 3919 * Flag to hide only the home button. Don't use this 3920 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3921 */ 3922 @UnsupportedAppUsage 3923 public static final int STATUS_BAR_DISABLE_HOME = 0x00200000; 3924 3925 /** 3926 * @hide 3927 * 3928 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3929 * out of the public fields to keep the undefined bits out of the developer's way. 3930 * 3931 * Flag to hide only the back button. Don't use this 3932 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3933 */ 3934 @UnsupportedAppUsage 3935 public static final int STATUS_BAR_DISABLE_BACK = 0x00400000; 3936 3937 /** 3938 * @hide 3939 * 3940 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3941 * out of the public fields to keep the undefined bits out of the developer's way. 3942 * 3943 * Flag to hide only the clock. You might use this if your activity has 3944 * its own clock making the status bar's clock redundant. 3945 */ 3946 public static final int STATUS_BAR_DISABLE_CLOCK = 0x00800000; 3947 3948 /** 3949 * @hide 3950 * 3951 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3952 * out of the public fields to keep the undefined bits out of the developer's way. 3953 * 3954 * Flag to hide only the recent apps button. Don't use this 3955 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3956 */ 3957 @UnsupportedAppUsage 3958 public static final int STATUS_BAR_DISABLE_RECENT = 0x01000000; 3959 3960 /** 3961 * @hide 3962 * 3963 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3964 * out of the public fields to keep the undefined bits out of the developer's way. 3965 * 3966 * Flag to disable the global search gesture. Don't use this 3967 * unless you're a special part of the system UI (i.e., setup wizard, keyguard). 3968 */ 3969 public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000; 3970 3971 /** 3972 * @hide 3973 * 3974 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3975 * out of the public fields to keep the undefined bits out of the developer's way. 3976 * 3977 * Flag to specify that the status bar is displayed in transient mode. 3978 */ 3979 public static final int STATUS_BAR_TRANSIENT = 0x04000000; 3980 3981 /** 3982 * @hide 3983 * 3984 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3985 * out of the public fields to keep the undefined bits out of the developer's way. 3986 * 3987 * Flag to specify that the navigation bar is displayed in transient mode. 3988 */ 3989 @UnsupportedAppUsage 3990 public static final int NAVIGATION_BAR_TRANSIENT = 0x08000000; 3991 3992 /** 3993 * @hide 3994 * 3995 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 3996 * out of the public fields to keep the undefined bits out of the developer's way. 3997 * 3998 * Flag to specify that the hidden status bar would like to be shown. 3999 */ 4000 public static final int STATUS_BAR_UNHIDE = 0x10000000; 4001 4002 /** 4003 * @hide 4004 * 4005 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4006 * out of the public fields to keep the undefined bits out of the developer's way. 4007 * 4008 * Flag to specify that the hidden navigation bar would like to be shown. 4009 */ 4010 public static final int NAVIGATION_BAR_UNHIDE = 0x20000000; 4011 4012 /** 4013 * @hide 4014 * 4015 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4016 * out of the public fields to keep the undefined bits out of the developer's way. 4017 * 4018 * Flag to specify that the status bar is displayed in translucent mode. 4019 */ 4020 public static final int STATUS_BAR_TRANSLUCENT = 0x40000000; 4021 4022 /** 4023 * @hide 4024 * 4025 * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked 4026 * out of the public fields to keep the undefined bits out of the developer's way. 4027 * 4028 * Flag to specify that the navigation bar is displayed in translucent mode. 4029 */ 4030 public static final int NAVIGATION_BAR_TRANSLUCENT = 0x80000000; 4031 4032 /** 4033 * @hide 4034 * 4035 * Makes navigation bar transparent (but not the status bar). 4036 */ 4037 public static final int NAVIGATION_BAR_TRANSPARENT = 0x00008000; 4038 4039 /** 4040 * @hide 4041 * 4042 * Makes status bar transparent (but not the navigation bar). 4043 */ 4044 public static final int STATUS_BAR_TRANSPARENT = 0x00000008; 4045 4046 /** 4047 * @hide 4048 * 4049 * Makes both status bar and navigation bar transparent. 4050 */ 4051 public static final int SYSTEM_UI_TRANSPARENT = NAVIGATION_BAR_TRANSPARENT 4052 | STATUS_BAR_TRANSPARENT; 4053 4054 /** 4055 * @hide 4056 */ 4057 public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x00003FF7; 4058 4059 /** 4060 * These are the system UI flags that can be cleared by events outside 4061 * of an application. Currently this is just the ability to tap on the 4062 * screen while hiding the navigation bar to have it return. 4063 * @hide 4064 */ 4065 public static final int SYSTEM_UI_CLEARABLE_FLAGS = 4066 SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_HIDE_NAVIGATION 4067 | SYSTEM_UI_FLAG_FULLSCREEN; 4068 4069 /** 4070 * Flags that can impact the layout in relation to system UI. 4071 * 4072 * @deprecated System UI layout flags are deprecated. 4073 */ 4074 @Deprecated 4075 public static final int SYSTEM_UI_LAYOUT_FLAGS = 4076 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 4077 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; 4078 4079 /** @hide */ 4080 @IntDef(flag = true, prefix = { "FIND_VIEWS_" }, value = { 4081 FIND_VIEWS_WITH_TEXT, 4082 FIND_VIEWS_WITH_CONTENT_DESCRIPTION 4083 }) 4084 @Retention(RetentionPolicy.SOURCE) 4085 public @interface FindViewFlags {} 4086 4087 /** 4088 * Find views that render the specified text. 4089 * 4090 * @see #findViewsWithText(ArrayList, CharSequence, int) 4091 */ 4092 public static final int FIND_VIEWS_WITH_TEXT = 0x00000001; 4093 4094 /** 4095 * Find find views that contain the specified content description. 4096 * 4097 * @see #findViewsWithText(ArrayList, CharSequence, int) 4098 */ 4099 public static final int FIND_VIEWS_WITH_CONTENT_DESCRIPTION = 0x00000002; 4100 4101 /** 4102 * Find views that contain {@link AccessibilityNodeProvider}. Such 4103 * a View is a root of virtual view hierarchy and may contain the searched 4104 * text. If this flag is set Views with providers are automatically 4105 * added and it is a responsibility of the client to call the APIs of 4106 * the provider to determine whether the virtual tree rooted at this View 4107 * contains the text, i.e. getting the list of {@link AccessibilityNodeInfo}s 4108 * representing the virtual views with this text. 4109 * 4110 * @see #findViewsWithText(ArrayList, CharSequence, int) 4111 * 4112 * @hide 4113 */ 4114 public static final int FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS = 0x00000004; 4115 4116 /** 4117 * The undefined cursor position. 4118 * 4119 * @hide 4120 */ 4121 public static final int ACCESSIBILITY_CURSOR_POSITION_UNDEFINED = -1; 4122 4123 /** 4124 * Indicates that the screen has changed state and is now off. 4125 * 4126 * @see #onScreenStateChanged(int) 4127 */ 4128 public static final int SCREEN_STATE_OFF = 0x0; 4129 4130 /** 4131 * Indicates that the screen has changed state and is now on. 4132 * 4133 * @see #onScreenStateChanged(int) 4134 */ 4135 public static final int SCREEN_STATE_ON = 0x1; 4136 4137 /** 4138 * Indicates no axis of view scrolling. 4139 */ 4140 public static final int SCROLL_AXIS_NONE = 0; 4141 4142 /** 4143 * Indicates scrolling along the horizontal axis. 4144 */ 4145 public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0; 4146 4147 /** 4148 * Indicates scrolling along the vertical axis. 4149 */ 4150 public static final int SCROLL_AXIS_VERTICAL = 1 << 1; 4151 4152 /** 4153 * Controls the over-scroll mode for this view. 4154 * See {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)}, 4155 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}, 4156 * and {@link #OVER_SCROLL_NEVER}. 4157 */ 4158 private int mOverScrollMode; 4159 4160 /** 4161 * The parent this view is attached to. 4162 * {@hide} 4163 * 4164 * @see #getParent() 4165 */ 4166 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4167 protected ViewParent mParent; 4168 4169 /** 4170 * {@hide} 4171 * 4172 * Not available for general use. If you need help, hang up and then dial one of the following 4173 * public APIs: 4174 * 4175 * @see #isAttachedToWindow() for current attach state 4176 * @see #onAttachedToWindow() for subclasses performing work when becoming attached 4177 * @see #onDetachedFromWindow() for subclasses performing work when becoming detached 4178 * @see OnAttachStateChangeListener for other code performing work on attach/detach 4179 * @see #getHandler() for posting messages to this view's UI thread/looper 4180 * @see #getParent() for interacting with the parent chain 4181 * @see #getWindowToken() for the current window token 4182 * @see #getRootView() for the view at the root of the attached hierarchy 4183 * @see #getDisplay() for the Display this view is presented on 4184 * @see #getRootWindowInsets() for the current insets applied to the whole attached window 4185 * @see #hasWindowFocus() for whether the attached window is currently focused 4186 * @see #getWindowVisibility() for checking the visibility of the attached window 4187 */ 4188 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4189 AttachInfo mAttachInfo; 4190 4191 /** 4192 * {@hide} 4193 */ 4194 @ViewDebug.ExportedProperty(flagMapping = { 4195 @ViewDebug.FlagToString(mask = PFLAG_FORCE_LAYOUT, equals = PFLAG_FORCE_LAYOUT, 4196 name = "FORCE_LAYOUT"), 4197 @ViewDebug.FlagToString(mask = PFLAG_LAYOUT_REQUIRED, equals = PFLAG_LAYOUT_REQUIRED, 4198 name = "LAYOUT_REQUIRED"), 4199 @ViewDebug.FlagToString(mask = PFLAG_DRAWING_CACHE_VALID, equals = PFLAG_DRAWING_CACHE_VALID, 4200 name = "DRAWING_CACHE_INVALID", outputIf = false), 4201 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "DRAWN", outputIf = true), 4202 @ViewDebug.FlagToString(mask = PFLAG_DRAWN, equals = PFLAG_DRAWN, name = "NOT_DRAWN", outputIf = false), 4203 @ViewDebug.FlagToString(mask = PFLAG_DIRTY_MASK, equals = PFLAG_DIRTY, name = "DIRTY") 4204 }, formatToHexString = true) 4205 4206 /* @hide */ 4207 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769414) 4208 public int mPrivateFlags; 4209 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768943) 4210 int mPrivateFlags2; 4211 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 129147060) 4212 int mPrivateFlags3; 4213 4214 private int mPrivateFlags4; 4215 4216 /** 4217 * This view's request for the visibility of the status bar. 4218 * @hide 4219 */ 4220 @ViewDebug.ExportedProperty(flagMapping = { 4221 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LOW_PROFILE, 4222 equals = SYSTEM_UI_FLAG_LOW_PROFILE, 4223 name = "LOW_PROFILE"), 4224 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4225 equals = SYSTEM_UI_FLAG_HIDE_NAVIGATION, 4226 name = "HIDE_NAVIGATION"), 4227 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_FULLSCREEN, 4228 equals = SYSTEM_UI_FLAG_FULLSCREEN, 4229 name = "FULLSCREEN"), 4230 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4231 equals = SYSTEM_UI_FLAG_LAYOUT_STABLE, 4232 name = "LAYOUT_STABLE"), 4233 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4234 equals = SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION, 4235 name = "LAYOUT_HIDE_NAVIGATION"), 4236 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4237 equals = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN, 4238 name = "LAYOUT_FULLSCREEN"), 4239 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE, 4240 equals = SYSTEM_UI_FLAG_IMMERSIVE, 4241 name = "IMMERSIVE"), 4242 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4243 equals = SYSTEM_UI_FLAG_IMMERSIVE_STICKY, 4244 name = "IMMERSIVE_STICKY"), 4245 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4246 equals = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR, 4247 name = "LIGHT_STATUS_BAR"), 4248 @ViewDebug.FlagToString(mask = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4249 equals = SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR, 4250 name = "LIGHT_NAVIGATION_BAR"), 4251 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_EXPAND, 4252 equals = STATUS_BAR_DISABLE_EXPAND, 4253 name = "STATUS_BAR_DISABLE_EXPAND"), 4254 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4255 equals = STATUS_BAR_DISABLE_NOTIFICATION_ICONS, 4256 name = "STATUS_BAR_DISABLE_NOTIFICATION_ICONS"), 4257 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4258 equals = STATUS_BAR_DISABLE_NOTIFICATION_ALERTS, 4259 name = "STATUS_BAR_DISABLE_NOTIFICATION_ALERTS"), 4260 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4261 equals = STATUS_BAR_DISABLE_NOTIFICATION_TICKER, 4262 name = "STATUS_BAR_DISABLE_NOTIFICATION_TICKER"), 4263 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SYSTEM_INFO, 4264 equals = STATUS_BAR_DISABLE_SYSTEM_INFO, 4265 name = "STATUS_BAR_DISABLE_SYSTEM_INFO"), 4266 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_HOME, 4267 equals = STATUS_BAR_DISABLE_HOME, 4268 name = "STATUS_BAR_DISABLE_HOME"), 4269 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_BACK, 4270 equals = STATUS_BAR_DISABLE_BACK, 4271 name = "STATUS_BAR_DISABLE_BACK"), 4272 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_CLOCK, 4273 equals = STATUS_BAR_DISABLE_CLOCK, 4274 name = "STATUS_BAR_DISABLE_CLOCK"), 4275 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_RECENT, 4276 equals = STATUS_BAR_DISABLE_RECENT, 4277 name = "STATUS_BAR_DISABLE_RECENT"), 4278 @ViewDebug.FlagToString(mask = STATUS_BAR_DISABLE_SEARCH, 4279 equals = STATUS_BAR_DISABLE_SEARCH, 4280 name = "STATUS_BAR_DISABLE_SEARCH"), 4281 @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSIENT, 4282 equals = STATUS_BAR_TRANSIENT, 4283 name = "STATUS_BAR_TRANSIENT"), 4284 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSIENT, 4285 equals = NAVIGATION_BAR_TRANSIENT, 4286 name = "NAVIGATION_BAR_TRANSIENT"), 4287 @ViewDebug.FlagToString(mask = STATUS_BAR_UNHIDE, 4288 equals = STATUS_BAR_UNHIDE, 4289 name = "STATUS_BAR_UNHIDE"), 4290 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_UNHIDE, 4291 equals = NAVIGATION_BAR_UNHIDE, 4292 name = "NAVIGATION_BAR_UNHIDE"), 4293 @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSLUCENT, 4294 equals = STATUS_BAR_TRANSLUCENT, 4295 name = "STATUS_BAR_TRANSLUCENT"), 4296 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSLUCENT, 4297 equals = NAVIGATION_BAR_TRANSLUCENT, 4298 name = "NAVIGATION_BAR_TRANSLUCENT"), 4299 @ViewDebug.FlagToString(mask = NAVIGATION_BAR_TRANSPARENT, 4300 equals = NAVIGATION_BAR_TRANSPARENT, 4301 name = "NAVIGATION_BAR_TRANSPARENT"), 4302 @ViewDebug.FlagToString(mask = STATUS_BAR_TRANSPARENT, 4303 equals = STATUS_BAR_TRANSPARENT, 4304 name = "STATUS_BAR_TRANSPARENT") 4305 }, formatToHexString = true) 4306 int mSystemUiVisibility; 4307 4308 /** 4309 * Reference count for transient state. 4310 * @see #setHasTransientState(boolean) 4311 */ 4312 int mTransientStateCount = 0; 4313 4314 /** 4315 * Count of how many windows this view has been attached to. 4316 */ 4317 int mWindowAttachCount; 4318 4319 /** 4320 * The layout parameters associated with this view and used by the parent 4321 * {@link android.view.ViewGroup} to determine how this view should be 4322 * laid out. 4323 * 4324 * The field should not be used directly. Instead {@link #getLayoutParams()} and {@link 4325 * #setLayoutParams(ViewGroup.LayoutParams)} should be used. The setter guarantees internal 4326 * state correctness of the class. 4327 * {@hide} 4328 */ 4329 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4330 protected ViewGroup.LayoutParams mLayoutParams; 4331 4332 /** 4333 * The view flags hold various views states. 4334 * 4335 * Use {@link #setTransitionVisibility(int)} to change the visibility of this view without 4336 * triggering updates. 4337 * {@hide} 4338 */ 4339 @ViewDebug.ExportedProperty(formatToHexString = true) 4340 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4341 int mViewFlags; 4342 4343 static class TransformationInfo { 4344 /** 4345 * The transform matrix for the View. This transform is calculated internally 4346 * based on the translation, rotation, and scale properties. 4347 * 4348 * Do *not* use this variable directly; instead call getMatrix(), which will 4349 * load the value from the View's RenderNode. 4350 */ 4351 private final Matrix mMatrix = new Matrix(); 4352 4353 /** 4354 * The inverse transform matrix for the View. This transform is calculated 4355 * internally based on the translation, rotation, and scale properties. 4356 * 4357 * Do *not* use this variable directly; instead call getInverseMatrix(), 4358 * which will load the value from the View's RenderNode. 4359 */ 4360 private Matrix mInverseMatrix; 4361 4362 /** 4363 * The opacity of the View. This is a value from 0 to 1, where 0 means 4364 * completely transparent and 1 means completely opaque. 4365 */ 4366 @ViewDebug.ExportedProperty 4367 private float mAlpha = 1f; 4368 4369 /** 4370 * The opacity of the view as manipulated by the Fade transition. This is a 4371 * property only used by transitions, which is composited with the other alpha 4372 * values to calculate the final visual alpha value. 4373 */ 4374 float mTransitionAlpha = 1f; 4375 } 4376 4377 /** @hide */ 4378 @UnsupportedAppUsage 4379 public TransformationInfo mTransformationInfo; 4380 4381 /** 4382 * Current clip bounds. to which all drawing of this view are constrained. 4383 */ 4384 @ViewDebug.ExportedProperty(category = "drawing") 4385 Rect mClipBounds = null; 4386 4387 private boolean mLastIsOpaque; 4388 4389 /** 4390 * The distance in pixels from the left edge of this view's parent 4391 * to the left edge of this view. 4392 * {@hide} 4393 */ 4394 @ViewDebug.ExportedProperty(category = "layout") 4395 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4396 protected int mLeft; 4397 /** 4398 * The distance in pixels from the left edge of this view's parent 4399 * to the right edge of this view. 4400 * {@hide} 4401 */ 4402 @ViewDebug.ExportedProperty(category = "layout") 4403 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4404 protected int mRight; 4405 /** 4406 * The distance in pixels from the top edge of this view's parent 4407 * to the top edge of this view. 4408 * {@hide} 4409 */ 4410 @ViewDebug.ExportedProperty(category = "layout") 4411 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4412 protected int mTop; 4413 /** 4414 * The distance in pixels from the top edge of this view's parent 4415 * to the bottom edge of this view. 4416 * {@hide} 4417 */ 4418 @ViewDebug.ExportedProperty(category = "layout") 4419 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4420 protected int mBottom; 4421 4422 /** 4423 * The offset, in pixels, by which the content of this view is scrolled 4424 * horizontally. 4425 * Please use {@link View#getScrollX()} and {@link View#setScrollX(int)} instead of 4426 * accessing these directly. 4427 * {@hide} 4428 */ 4429 @ViewDebug.ExportedProperty(category = "scrolling") 4430 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4431 protected int mScrollX; 4432 /** 4433 * The offset, in pixels, by which the content of this view is scrolled 4434 * vertically. 4435 * Please use {@link View#getScrollY()} and {@link View#setScrollY(int)} instead of 4436 * accessing these directly. 4437 * {@hide} 4438 */ 4439 @ViewDebug.ExportedProperty(category = "scrolling") 4440 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4441 protected int mScrollY; 4442 4443 /** 4444 * The final computed left padding in pixels that is used for drawing. This is the distance in 4445 * pixels between the left edge of this view and the left edge of its content. 4446 * {@hide} 4447 */ 4448 @ViewDebug.ExportedProperty(category = "padding") 4449 @UnsupportedAppUsage 4450 protected int mPaddingLeft = 0; 4451 /** 4452 * The final computed right padding in pixels that is used for drawing. This is the distance in 4453 * pixels between the right edge of this view and the right edge of its content. 4454 * {@hide} 4455 */ 4456 @ViewDebug.ExportedProperty(category = "padding") 4457 @UnsupportedAppUsage 4458 protected int mPaddingRight = 0; 4459 /** 4460 * The final computed top padding in pixels that is used for drawing. This is the distance in 4461 * pixels between the top edge of this view and the top edge of its content. 4462 * {@hide} 4463 */ 4464 @ViewDebug.ExportedProperty(category = "padding") 4465 @UnsupportedAppUsage 4466 protected int mPaddingTop; 4467 /** 4468 * The final computed bottom padding in pixels that is used for drawing. This is the distance in 4469 * pixels between the bottom edge of this view and the bottom edge of its content. 4470 * {@hide} 4471 */ 4472 @ViewDebug.ExportedProperty(category = "padding") 4473 @UnsupportedAppUsage 4474 protected int mPaddingBottom; 4475 4476 /** 4477 * The layout insets in pixels, that is the distance in pixels between the 4478 * visible edges of this view its bounds. 4479 */ 4480 private Insets mLayoutInsets; 4481 4482 /** 4483 * Briefly describes the state of the view and is primarily used for accessibility support. 4484 */ 4485 private CharSequence mStateDescription; 4486 4487 /** 4488 * Briefly describes the view and is primarily used for accessibility support. 4489 */ 4490 private CharSequence mContentDescription; 4491 4492 /** 4493 * If this view represents a distinct part of the window, it can have a title that labels the 4494 * area. 4495 */ 4496 private CharSequence mAccessibilityPaneTitle; 4497 4498 /** 4499 * Specifies the id of a view for which this view serves as a label for 4500 * accessibility purposes. 4501 */ 4502 private int mLabelForId = View.NO_ID; 4503 4504 /** 4505 * Predicate for matching labeled view id with its label for 4506 * accessibility purposes. 4507 */ 4508 private MatchLabelForPredicate mMatchLabelForPredicate; 4509 4510 /** 4511 * Specifies a view before which this one is visited in accessibility traversal. 4512 */ 4513 private int mAccessibilityTraversalBeforeId = NO_ID; 4514 4515 /** 4516 * Specifies a view after which this one is visited in accessibility traversal. 4517 */ 4518 private int mAccessibilityTraversalAfterId = NO_ID; 4519 4520 /** 4521 * Predicate for matching a view by its id. 4522 */ 4523 private MatchIdPredicate mMatchIdPredicate; 4524 4525 /** 4526 * The right padding after RTL resolution, but before taking account of scroll bars. 4527 * 4528 * @hide 4529 */ 4530 @ViewDebug.ExportedProperty(category = "padding") 4531 protected int mUserPaddingRight; 4532 4533 /** 4534 * The resolved bottom padding before taking account of scroll bars. 4535 * 4536 * @hide 4537 */ 4538 @ViewDebug.ExportedProperty(category = "padding") 4539 protected int mUserPaddingBottom; 4540 4541 /** 4542 * The left padding after RTL resolution, but before taking account of scroll bars. 4543 * 4544 * @hide 4545 */ 4546 @ViewDebug.ExportedProperty(category = "padding") 4547 protected int mUserPaddingLeft; 4548 4549 /** 4550 * Cache the paddingStart set by the user to append to the scrollbar's size. 4551 * 4552 */ 4553 @ViewDebug.ExportedProperty(category = "padding") 4554 int mUserPaddingStart; 4555 4556 /** 4557 * Cache the paddingEnd set by the user to append to the scrollbar's size. 4558 * 4559 */ 4560 @ViewDebug.ExportedProperty(category = "padding") 4561 int mUserPaddingEnd; 4562 4563 /** 4564 * The left padding as set by a setter method, a background's padding, or via XML property 4565 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4566 * 4567 * @hide 4568 */ 4569 int mUserPaddingLeftInitial; 4570 4571 /** 4572 * The right padding as set by a setter method, a background's padding, or via XML property 4573 * resolution. This value is the padding before LTR resolution or taking account of scrollbars. 4574 * 4575 * @hide 4576 */ 4577 int mUserPaddingRightInitial; 4578 4579 /** 4580 * Default undefined padding 4581 */ 4582 private static final int UNDEFINED_PADDING = Integer.MIN_VALUE; 4583 4584 /** 4585 * Cache if a left padding has been defined explicitly via padding, horizontal padding, 4586 * or leftPadding in XML, or by setPadding(...) or setRelativePadding(...) 4587 */ 4588 private boolean mLeftPaddingDefined = false; 4589 4590 /** 4591 * Cache if a right padding has been defined explicitly via padding, horizontal padding, 4592 * or rightPadding in XML, or by setPadding(...) or setRelativePadding(...) 4593 */ 4594 private boolean mRightPaddingDefined = false; 4595 4596 /** 4597 * @hide 4598 */ 4599 int mOldWidthMeasureSpec = Integer.MIN_VALUE; 4600 /** 4601 * @hide 4602 */ 4603 int mOldHeightMeasureSpec = Integer.MIN_VALUE; 4604 4605 private LongSparseLongArray mMeasureCache; 4606 4607 @ViewDebug.ExportedProperty(deepExport = true, prefix = "bg_") 4608 @UnsupportedAppUsage 4609 private Drawable mBackground; 4610 private TintInfo mBackgroundTint; 4611 4612 @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") 4613 private ForegroundInfo mForegroundInfo; 4614 4615 private Drawable mScrollIndicatorDrawable; 4616 4617 /** 4618 * RenderNode used for backgrounds. 4619 * <p> 4620 * When non-null and valid, this is expected to contain an up-to-date copy 4621 * of the background drawable. It is cleared on temporary detach, and reset 4622 * on cleanup. 4623 * @hide 4624 */ 4625 RenderNode mBackgroundRenderNode; 4626 4627 @UnsupportedAppUsage 4628 private int mBackgroundResource; 4629 private boolean mBackgroundSizeChanged; 4630 4631 /** The default focus highlight. 4632 * @see #mDefaultFocusHighlightEnabled 4633 * @see Drawable#hasFocusStateSpecified() 4634 */ 4635 private Drawable mDefaultFocusHighlight; 4636 private Drawable mDefaultFocusHighlightCache; 4637 private boolean mDefaultFocusHighlightSizeChanged; 4638 /** 4639 * True if the default focus highlight is needed on the target device. 4640 */ 4641 private static boolean sUseDefaultFocusHighlight; 4642 4643 /** 4644 * True if zero-sized views can be focused. 4645 */ 4646 private static boolean sCanFocusZeroSized; 4647 4648 /** 4649 * Always assign focus if a focusable View is available. 4650 */ 4651 private static boolean sAlwaysAssignFocus; 4652 4653 private String mTransitionName; 4654 4655 static class TintInfo { 4656 ColorStateList mTintList; 4657 BlendMode mBlendMode; 4658 boolean mHasTintMode; 4659 boolean mHasTintList; 4660 } 4661 4662 private static class ForegroundInfo { 4663 private Drawable mDrawable; 4664 private TintInfo mTintInfo; 4665 private int mGravity = Gravity.FILL; 4666 private boolean mInsidePadding = true; 4667 private boolean mBoundsChanged = true; 4668 private final Rect mSelfBounds = new Rect(); 4669 private final Rect mOverlayBounds = new Rect(); 4670 } 4671 4672 static class ListenerInfo { 4673 4674 @UnsupportedAppUsage ListenerInfo()4675 ListenerInfo() { 4676 } 4677 4678 /** 4679 * Listener used to dispatch focus change events. 4680 * This field should be made private, so it is hidden from the SDK. 4681 * {@hide} 4682 */ 4683 @UnsupportedAppUsage 4684 protected OnFocusChangeListener mOnFocusChangeListener; 4685 4686 /** 4687 * Listeners for layout change events. 4688 */ 4689 private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners; 4690 4691 protected OnScrollChangeListener mOnScrollChangeListener; 4692 4693 /** 4694 * Listeners for attach events. 4695 */ 4696 private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners; 4697 4698 /** 4699 * Listener used to dispatch click events. 4700 * This field should be made private, so it is hidden from the SDK. 4701 * {@hide} 4702 */ 4703 @UnsupportedAppUsage 4704 public OnClickListener mOnClickListener; 4705 4706 /** 4707 * Listener used to dispatch long click events. 4708 * This field should be made private, so it is hidden from the SDK. 4709 * {@hide} 4710 */ 4711 @UnsupportedAppUsage 4712 protected OnLongClickListener mOnLongClickListener; 4713 4714 /** 4715 * Listener used to dispatch context click events. This field should be made private, so it 4716 * is hidden from the SDK. 4717 * {@hide} 4718 */ 4719 protected OnContextClickListener mOnContextClickListener; 4720 4721 /** 4722 * Listener used to build the context menu. 4723 * This field should be made private, so it is hidden from the SDK. 4724 * {@hide} 4725 */ 4726 @UnsupportedAppUsage 4727 protected OnCreateContextMenuListener mOnCreateContextMenuListener; 4728 4729 @UnsupportedAppUsage 4730 private OnKeyListener mOnKeyListener; 4731 4732 @UnsupportedAppUsage 4733 private OnTouchListener mOnTouchListener; 4734 4735 @UnsupportedAppUsage 4736 private OnHoverListener mOnHoverListener; 4737 4738 @UnsupportedAppUsage 4739 private OnGenericMotionListener mOnGenericMotionListener; 4740 4741 @UnsupportedAppUsage 4742 private OnDragListener mOnDragListener; 4743 4744 private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener; 4745 4746 OnApplyWindowInsetsListener mOnApplyWindowInsetsListener; 4747 4748 OnCapturedPointerListener mOnCapturedPointerListener; 4749 4750 private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners; 4751 4752 WindowInsetsAnimation.Callback mWindowInsetsAnimationCallback; 4753 4754 /** 4755 * This lives here since it's only valid for interactive views. 4756 */ 4757 private List<Rect> mSystemGestureExclusionRects; 4758 4759 /** 4760 * Used to track {@link #mSystemGestureExclusionRects} 4761 */ 4762 public RenderNode.PositionUpdateListener mPositionUpdateListener; 4763 4764 /** 4765 * Allows the application to implement custom scroll capture support. 4766 */ 4767 ScrollCaptureCallback mScrollCaptureCallback; 4768 } 4769 4770 @UnsupportedAppUsage 4771 ListenerInfo mListenerInfo; 4772 4773 private static class TooltipInfo { 4774 /** 4775 * Text to be displayed in a tooltip popup. 4776 */ 4777 @Nullable 4778 CharSequence mTooltipText; 4779 4780 /** 4781 * View-relative position of the tooltip anchor point. 4782 */ 4783 int mAnchorX; 4784 int mAnchorY; 4785 4786 /** 4787 * The tooltip popup. 4788 */ 4789 @Nullable 4790 TooltipPopup mTooltipPopup; 4791 4792 /** 4793 * Set to true if the tooltip was shown as a result of a long click. 4794 */ 4795 boolean mTooltipFromLongClick; 4796 4797 /** 4798 * Keep these Runnables so that they can be used to reschedule. 4799 */ 4800 Runnable mShowTooltipRunnable; 4801 Runnable mHideTooltipRunnable; 4802 4803 /** 4804 * Hover move is ignored if it is within this distance in pixels from the previous one. 4805 */ 4806 int mHoverSlop; 4807 4808 /** 4809 * Update the anchor position if it significantly (that is by at least mHoverSlop) 4810 * different from the previously stored position. Ignoring insignificant changes 4811 * filters out the jitter which is typical for such input sources as stylus. 4812 * 4813 * @return True if the position has been updated. 4814 */ updateAnchorPos(MotionEvent event)4815 private boolean updateAnchorPos(MotionEvent event) { 4816 final int newAnchorX = (int) event.getX(); 4817 final int newAnchorY = (int) event.getY(); 4818 if (Math.abs(newAnchorX - mAnchorX) <= mHoverSlop 4819 && Math.abs(newAnchorY - mAnchorY) <= mHoverSlop) { 4820 return false; 4821 } 4822 mAnchorX = newAnchorX; 4823 mAnchorY = newAnchorY; 4824 return true; 4825 } 4826 4827 /** 4828 * Clear the anchor position to ensure that the next change is considered significant. 4829 */ clearAnchorPos()4830 private void clearAnchorPos() { 4831 mAnchorX = Integer.MAX_VALUE; 4832 mAnchorY = Integer.MAX_VALUE; 4833 } 4834 } 4835 4836 TooltipInfo mTooltipInfo; 4837 4838 // Temporary values used to hold (x,y) coordinates when delegating from the 4839 // two-arg performLongClick() method to the legacy no-arg version. 4840 private float mLongClickX = Float.NaN; 4841 private float mLongClickY = Float.NaN; 4842 4843 /** 4844 * The application environment this view lives in. 4845 * This field should be made private, so it is hidden from the SDK. 4846 * {@hide} 4847 */ 4848 @ViewDebug.ExportedProperty(deepExport = true) 4849 @UnsupportedAppUsage 4850 protected Context mContext; 4851 4852 @UnsupportedAppUsage 4853 private final Resources mResources; 4854 4855 @UnsupportedAppUsage 4856 private ScrollabilityCache mScrollCache; 4857 4858 private int[] mDrawableState = null; 4859 4860 ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; 4861 4862 /** 4863 * Animator that automatically runs based on state changes. 4864 */ 4865 private StateListAnimator mStateListAnimator; 4866 4867 /** 4868 * When this view has focus and the next focus is {@link #FOCUS_LEFT}, 4869 * the user may specify which view to go to next. 4870 */ 4871 private int mNextFocusLeftId = View.NO_ID; 4872 4873 /** 4874 * When this view has focus and the next focus is {@link #FOCUS_RIGHT}, 4875 * the user may specify which view to go to next. 4876 */ 4877 private int mNextFocusRightId = View.NO_ID; 4878 4879 /** 4880 * When this view has focus and the next focus is {@link #FOCUS_UP}, 4881 * the user may specify which view to go to next. 4882 */ 4883 private int mNextFocusUpId = View.NO_ID; 4884 4885 /** 4886 * When this view has focus and the next focus is {@link #FOCUS_DOWN}, 4887 * the user may specify which view to go to next. 4888 */ 4889 private int mNextFocusDownId = View.NO_ID; 4890 4891 /** 4892 * When this view has focus and the next focus is {@link #FOCUS_FORWARD}, 4893 * the user may specify which view to go to next. 4894 */ 4895 int mNextFocusForwardId = View.NO_ID; 4896 4897 /** 4898 * User-specified next keyboard navigation cluster in the {@link #FOCUS_FORWARD} direction. 4899 * 4900 * @see #findUserSetNextKeyboardNavigationCluster(View, int) 4901 */ 4902 int mNextClusterForwardId = View.NO_ID; 4903 4904 /** 4905 * Whether this View should use a default focus highlight when it gets focused but doesn't 4906 * have {@link android.R.attr#state_focused} defined in its background. 4907 */ 4908 boolean mDefaultFocusHighlightEnabled = true; 4909 4910 private CheckForLongPress mPendingCheckForLongPress; 4911 @UnsupportedAppUsage 4912 private CheckForTap mPendingCheckForTap = null; 4913 private PerformClick mPerformClick; 4914 private SendViewScrolledAccessibilityEvent mSendViewScrolledAccessibilityEvent; 4915 private SendAccessibilityEventThrottle mSendStateChangedAccessibilityEvent; 4916 private UnsetPressedState mUnsetPressedState; 4917 4918 /** 4919 * Whether the long press's action has been invoked. The tap's action is invoked on the 4920 * up event while a long press is invoked as soon as the long press duration is reached, so 4921 * a long press could be performed before the tap is checked, in which case the tap's action 4922 * should not be invoked. 4923 */ 4924 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 4925 private boolean mHasPerformedLongPress; 4926 4927 /** 4928 * Whether a context click button is currently pressed down. This is true when the stylus is 4929 * touching the screen and the primary button has been pressed, or if a mouse's right button is 4930 * pressed. This is false once the button is released or if the stylus has been lifted. 4931 */ 4932 private boolean mInContextButtonPress; 4933 4934 /** 4935 * Whether the next up event should be ignored for the purposes of gesture recognition. This is 4936 * true after a stylus button press has occured, when the next up event should not be recognized 4937 * as a tap. 4938 */ 4939 private boolean mIgnoreNextUpEvent; 4940 4941 /** 4942 * The minimum height of the view. We'll try our best to have the height 4943 * of this view to at least this amount. 4944 */ 4945 @ViewDebug.ExportedProperty(category = "measurement") 4946 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4947 private int mMinHeight; 4948 4949 /** 4950 * The minimum width of the view. We'll try our best to have the width 4951 * of this view to at least this amount. 4952 */ 4953 @ViewDebug.ExportedProperty(category = "measurement") 4954 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) 4955 private int mMinWidth; 4956 4957 /** 4958 * The delegate to handle touch events that are physically in this view 4959 * but should be handled by another view. 4960 */ 4961 private TouchDelegate mTouchDelegate = null; 4962 4963 /** 4964 * While touch exploration is in use, set to true when hovering across boundaries and 4965 * inside the touch area of the delegate at receiving {@link MotionEvent#ACTION_HOVER_ENTER} 4966 * or {@link MotionEvent#ACTION_HOVER_MOVE}. False when leaving boundaries or receiving a 4967 * {@link MotionEvent#ACTION_HOVER_EXIT}. 4968 * Note that children of view group are excluded in the touch area. 4969 * @see #dispatchTouchExplorationHoverEvent 4970 */ 4971 private boolean mHoveringTouchDelegate = false; 4972 4973 /** 4974 * Solid color to use as a background when creating the drawing cache. Enables 4975 * the cache to use 16 bit bitmaps instead of 32 bit. 4976 */ 4977 private int mDrawingCacheBackgroundColor = 0; 4978 4979 /** 4980 * Special tree observer used when mAttachInfo is null. 4981 */ 4982 private ViewTreeObserver mFloatingTreeObserver; 4983 4984 /** 4985 * Cache the touch slop from the context that created the view. 4986 */ 4987 private int mTouchSlop; 4988 4989 /** 4990 * Cache the ambiguous gesture multiplier from the context that created the view. 4991 */ 4992 private float mAmbiguousGestureMultiplier; 4993 4994 /** 4995 * Object that handles automatic animation of view properties. 4996 */ 4997 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 4998 private ViewPropertyAnimator mAnimator = null; 4999 5000 /** 5001 * List of registered FrameMetricsObservers. 5002 */ 5003 private ArrayList<FrameMetricsObserver> mFrameMetricsObservers; 5004 5005 /** 5006 * Flag indicating that a drag can cross window boundaries. When 5007 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 5008 * with this flag set, all visible applications with targetSdkVersion >= 5009 * {@link android.os.Build.VERSION_CODES#N API 24} will be able to participate 5010 * in the drag operation and receive the dragged content. 5011 * 5012 * <p>If this is the only flag set, then the drag recipient will only have access to text data 5013 * and intents contained in the {@link ClipData} object. Access to URIs contained in the 5014 * {@link ClipData} is determined by other DRAG_FLAG_GLOBAL_* flags</p> 5015 */ 5016 public static final int DRAG_FLAG_GLOBAL = 1 << 8; // 256 5017 5018 /** 5019 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 5020 * request read access to the content URI(s) contained in the {@link ClipData} object. 5021 * @see android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION 5022 */ 5023 public static final int DRAG_FLAG_GLOBAL_URI_READ = Intent.FLAG_GRANT_READ_URI_PERMISSION; 5024 5025 /** 5026 * When this flag is used with {@link #DRAG_FLAG_GLOBAL}, the drag recipient will be able to 5027 * request write access to the content URI(s) contained in the {@link ClipData} object. 5028 * @see android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION 5029 */ 5030 public static final int DRAG_FLAG_GLOBAL_URI_WRITE = Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 5031 5032 /** 5033 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 5034 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant can be persisted across device 5035 * reboots until explicitly revoked with 5036 * {@link android.content.Context#revokeUriPermission(Uri, int)} Context.revokeUriPermission}. 5037 * @see android.content.Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION 5038 */ 5039 public static final int DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION = 5040 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 5041 5042 /** 5043 * When this flag is used with {@link #DRAG_FLAG_GLOBAL_URI_READ} and/or {@link 5044 * #DRAG_FLAG_GLOBAL_URI_WRITE}, the URI permission grant applies to any URI that is a prefix 5045 * match against the original granted URI. 5046 * @see android.content.Intent#FLAG_GRANT_PREFIX_URI_PERMISSION 5047 */ 5048 public static final int DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION = 5049 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION; 5050 5051 /** 5052 * Flag indicating that the drag shadow will be opaque. When 5053 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int)} is called 5054 * with this flag set, the drag shadow will be opaque, otherwise, it will be semitransparent. 5055 */ 5056 public static final int DRAG_FLAG_OPAQUE = 1 << 9; 5057 5058 /** 5059 * Vertical scroll factor cached by {@link #getVerticalScrollFactor}. 5060 */ 5061 private float mVerticalScrollFactor; 5062 5063 /** 5064 * Position of the vertical scroll bar. 5065 */ 5066 @UnsupportedAppUsage 5067 private int mVerticalScrollbarPosition; 5068 5069 /** 5070 * Position the scroll bar at the default position as determined by the system. 5071 */ 5072 public static final int SCROLLBAR_POSITION_DEFAULT = 0; 5073 5074 /** 5075 * Position the scroll bar along the left edge. 5076 */ 5077 public static final int SCROLLBAR_POSITION_LEFT = 1; 5078 5079 /** 5080 * Position the scroll bar along the right edge. 5081 */ 5082 public static final int SCROLLBAR_POSITION_RIGHT = 2; 5083 5084 /** 5085 * Indicates that the view does not have a layer. 5086 * 5087 * @see #getLayerType() 5088 * @see #setLayerType(int, android.graphics.Paint) 5089 * @see #LAYER_TYPE_SOFTWARE 5090 * @see #LAYER_TYPE_HARDWARE 5091 */ 5092 public static final int LAYER_TYPE_NONE = 0; 5093 5094 /** 5095 * <p>Indicates that the view has a software layer. A software layer is backed 5096 * by a bitmap and causes the view to be rendered using Android's software 5097 * rendering pipeline, even if hardware acceleration is enabled.</p> 5098 * 5099 * <p>Software layers have various usages:</p> 5100 * <p>When the application is not using hardware acceleration, a software layer 5101 * is useful to apply a specific color filter and/or blending mode and/or 5102 * translucency to a view and all its children.</p> 5103 * <p>When the application is using hardware acceleration, a software layer 5104 * is useful to render drawing primitives not supported by the hardware 5105 * accelerated pipeline. It can also be used to cache a complex view tree 5106 * into a texture and reduce the complexity of drawing operations. For instance, 5107 * when animating a complex view tree with a translation, a software layer can 5108 * be used to render the view tree only once.</p> 5109 * <p>Software layers should be avoided when the affected view tree updates 5110 * often. Every update will require to re-render the software layer, which can 5111 * potentially be slow (particularly when hardware acceleration is turned on 5112 * since the layer will have to be uploaded into a hardware texture after every 5113 * update.)</p> 5114 * 5115 * @see #getLayerType() 5116 * @see #setLayerType(int, android.graphics.Paint) 5117 * @see #LAYER_TYPE_NONE 5118 * @see #LAYER_TYPE_HARDWARE 5119 */ 5120 public static final int LAYER_TYPE_SOFTWARE = 1; 5121 5122 /** 5123 * <p>Indicates that the view has a hardware layer. A hardware layer is backed 5124 * by a hardware specific texture (generally Frame Buffer Objects or FBO on 5125 * OpenGL hardware) and causes the view to be rendered using Android's hardware 5126 * rendering pipeline, but only if hardware acceleration is turned on for the 5127 * view hierarchy. When hardware acceleration is turned off, hardware layers 5128 * behave exactly as {@link #LAYER_TYPE_SOFTWARE software layers}.</p> 5129 * 5130 * <p>A hardware layer is useful to apply a specific color filter and/or 5131 * blending mode and/or translucency to a view and all its children.</p> 5132 * <p>A hardware layer can be used to cache a complex view tree into a 5133 * texture and reduce the complexity of drawing operations. For instance, 5134 * when animating a complex view tree with a translation, a hardware layer can 5135 * be used to render the view tree only once.</p> 5136 * <p>A hardware layer can also be used to increase the rendering quality when 5137 * rotation transformations are applied on a view. It can also be used to 5138 * prevent potential clipping issues when applying 3D transforms on a view.</p> 5139 * 5140 * @see #getLayerType() 5141 * @see #setLayerType(int, android.graphics.Paint) 5142 * @see #LAYER_TYPE_NONE 5143 * @see #LAYER_TYPE_SOFTWARE 5144 */ 5145 public static final int LAYER_TYPE_HARDWARE = 2; 5146 5147 /** @hide */ 5148 @IntDef(prefix = { "LAYER_TYPE_" }, value = { 5149 LAYER_TYPE_NONE, 5150 LAYER_TYPE_SOFTWARE, 5151 LAYER_TYPE_HARDWARE 5152 }) 5153 @Retention(RetentionPolicy.SOURCE) 5154 public @interface LayerType {} 5155 5156 @ViewDebug.ExportedProperty(category = "drawing", mapping = { 5157 @ViewDebug.IntToString(from = LAYER_TYPE_NONE, to = "NONE"), 5158 @ViewDebug.IntToString(from = LAYER_TYPE_SOFTWARE, to = "SOFTWARE"), 5159 @ViewDebug.IntToString(from = LAYER_TYPE_HARDWARE, to = "HARDWARE") 5160 }) 5161 int mLayerType = LAYER_TYPE_NONE; 5162 Paint mLayerPaint; 5163 5164 /** 5165 * Set to true when drawing cache is enabled and cannot be created. 5166 * 5167 * @hide 5168 */ 5169 @UnsupportedAppUsage 5170 public boolean mCachingFailed; 5171 @UnsupportedAppUsage 5172 private Bitmap mDrawingCache; 5173 @UnsupportedAppUsage 5174 private Bitmap mUnscaledDrawingCache; 5175 5176 /** 5177 * RenderNode holding View properties, potentially holding a DisplayList of View content. 5178 * <p> 5179 * When non-null and valid, this is expected to contain an up-to-date copy 5180 * of the View content. Its DisplayList content is cleared on temporary detach and reset on 5181 * cleanup. 5182 */ 5183 @UnsupportedAppUsage 5184 final RenderNode mRenderNode; 5185 5186 /** 5187 * Set to true when the view is sending hover accessibility events because it 5188 * is the innermost hovered view. 5189 */ 5190 private boolean mSendingHoverAccessibilityEvents; 5191 5192 /** 5193 * Delegate for injecting accessibility functionality. 5194 */ 5195 @UnsupportedAppUsage 5196 AccessibilityDelegate mAccessibilityDelegate; 5197 5198 /** 5199 * The view's overlay layer. Developers get a reference to the overlay via getOverlay() 5200 * and add/remove objects to/from the overlay directly through the Overlay methods. 5201 */ 5202 ViewOverlay mOverlay; 5203 5204 /** 5205 * The currently active parent view for receiving delegated nested scrolling events. 5206 * This is set by {@link #startNestedScroll(int)} during a touch interaction and cleared 5207 * by {@link #stopNestedScroll()} at the same point where we clear 5208 * requestDisallowInterceptTouchEvent. 5209 */ 5210 private ViewParent mNestedScrollingParent; 5211 5212 /** 5213 * Consistency verifier for debugging purposes. 5214 * @hide 5215 */ 5216 protected final InputEventConsistencyVerifier mInputEventConsistencyVerifier = 5217 InputEventConsistencyVerifier.isInstrumentationEnabled() ? 5218 new InputEventConsistencyVerifier(this, 0) : null; 5219 5220 private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1); 5221 5222 private int[] mTempNestedScrollConsumed; 5223 5224 /** 5225 * An overlay is going to draw this View instead of being drawn as part of this 5226 * View's parent. mGhostView is the View in the Overlay that must be invalidated 5227 * when this view is invalidated. 5228 */ 5229 GhostView mGhostView; 5230 5231 /** 5232 * Holds pairs of adjacent attribute data: attribute name followed by its value. 5233 * @hide 5234 */ 5235 @ViewDebug.ExportedProperty(category = "attributes", hasAdjacentMapping = true) 5236 public String[] mAttributes; 5237 5238 /** 5239 * Maps a Resource id to its name. 5240 */ 5241 private static SparseArray<String> mAttributeMap; 5242 5243 /** 5244 * Queue of pending runnables. Used to postpone calls to post() until this 5245 * view is attached and has a handler. 5246 */ 5247 private HandlerActionQueue mRunQueue; 5248 5249 /** 5250 * The pointer icon when the mouse hovers on this view. The default is null. 5251 */ 5252 private PointerIcon mPointerIcon; 5253 5254 /** 5255 * @hide 5256 */ 5257 @UnsupportedAppUsage 5258 String mStartActivityRequestWho; 5259 5260 @Nullable 5261 private RoundScrollbarRenderer mRoundScrollbarRenderer; 5262 5263 /** Used to delay visibility updates sent to the autofill manager */ 5264 private Handler mVisibilityChangeForAutofillHandler; 5265 5266 /** 5267 * Used when app developers explicitly set the {@link ContentCaptureSession} associated with the 5268 * view (through {@link #setContentCaptureSession(ContentCaptureSession)}. 5269 */ 5270 @Nullable 5271 private ContentCaptureSession mContentCaptureSession; 5272 5273 /** 5274 * Whether {@link ContentCaptureSession} is cached, resets on {@link #invalidate()}. 5275 */ 5276 private boolean mContentCaptureSessionCached; 5277 5278 @LayoutRes 5279 private int mSourceLayoutId = ID_NULL; 5280 5281 @Nullable 5282 private SparseIntArray mAttributeSourceResId; 5283 5284 @Nullable 5285 private SparseArray<int[]> mAttributeResolutionStacks; 5286 5287 @StyleRes 5288 private int mExplicitStyle; 5289 5290 /** 5291 * Specifies which input source classes should provide unbuffered input events to this view 5292 * 5293 * @see View#requestUnbufferedDispatch(int) 5294 */ 5295 @InputSourceClass 5296 int mUnbufferedInputSource = InputDevice.SOURCE_CLASS_NONE; 5297 5298 /** 5299 * Simple constructor to use when creating a view from code. 5300 * 5301 * @param context The Context the view is running in, through which it can 5302 * access the current theme, resources, etc. 5303 */ View(Context context)5304 public View(Context context) { 5305 mContext = context; 5306 mResources = context != null ? context.getResources() : null; 5307 mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | FOCUSABLE_AUTO; 5308 // Set some flags defaults 5309 mPrivateFlags2 = 5310 (LAYOUT_DIRECTION_DEFAULT << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) | 5311 (TEXT_DIRECTION_DEFAULT << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) | 5312 (PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT) | 5313 (TEXT_ALIGNMENT_DEFAULT << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) | 5314 (PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT) | 5315 (IMPORTANT_FOR_ACCESSIBILITY_DEFAULT << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT); 5316 5317 final ViewConfiguration configuration = ViewConfiguration.get(context); 5318 mTouchSlop = configuration.getScaledTouchSlop(); 5319 mAmbiguousGestureMultiplier = configuration.getScaledAmbiguousGestureMultiplier(); 5320 5321 setOverScrollMode(OVER_SCROLL_IF_CONTENT_SCROLLS); 5322 mUserPaddingStart = UNDEFINED_PADDING; 5323 mUserPaddingEnd = UNDEFINED_PADDING; 5324 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 5325 5326 if (!sCompatibilityDone && context != null) { 5327 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5328 5329 // Older apps may need this compatibility hack for measurement. 5330 sUseBrokenMakeMeasureSpec = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1; 5331 5332 // Older apps expect onMeasure() to always be called on a layout pass, regardless 5333 // of whether a layout was requested on that View. 5334 sIgnoreMeasureCache = targetSdkVersion < Build.VERSION_CODES.KITKAT; 5335 5336 Canvas.sCompatibilityRestore = targetSdkVersion < Build.VERSION_CODES.M; 5337 Canvas.sCompatibilitySetBitmap = targetSdkVersion < Build.VERSION_CODES.O; 5338 Canvas.setCompatibilityVersion(targetSdkVersion); 5339 5340 // In M and newer, our widgets can pass a "hint" value in the size 5341 // for UNSPECIFIED MeasureSpecs. This lets child views of scrolling containers 5342 // know what the expected parent size is going to be, so e.g. list items can size 5343 // themselves at 1/3 the size of their container. It breaks older apps though, 5344 // specifically apps that use some popular open source libraries. 5345 sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < Build.VERSION_CODES.M; 5346 5347 // Old versions of the platform would give different results from 5348 // LinearLayout measurement passes using EXACTLY and non-EXACTLY 5349 // modes, so we always need to run an additional EXACTLY pass. 5350 sAlwaysRemeasureExactly = targetSdkVersion <= Build.VERSION_CODES.M; 5351 5352 // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. 5353 // On N+, we throw, but that breaks compatibility with apps that use these methods. 5354 sTextureViewIgnoresDrawableSetters = targetSdkVersion <= Build.VERSION_CODES.M; 5355 5356 // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs 5357 // in apps so we target check it to avoid breaking existing apps. 5358 sPreserveMarginParamsInLayoutParamConversion = 5359 targetSdkVersion >= Build.VERSION_CODES.N; 5360 5361 sCascadedDragDrop = targetSdkVersion < Build.VERSION_CODES.N; 5362 5363 sHasFocusableExcludeAutoFocusable = targetSdkVersion < Build.VERSION_CODES.O; 5364 5365 sAutoFocusableOffUIThreadWontNotifyParents = targetSdkVersion < Build.VERSION_CODES.O; 5366 5367 sUseDefaultFocusHighlight = context.getResources().getBoolean( 5368 com.android.internal.R.bool.config_useDefaultFocusHighlight); 5369 5370 sThrowOnInvalidFloatProperties = targetSdkVersion >= Build.VERSION_CODES.P; 5371 5372 sCanFocusZeroSized = targetSdkVersion < Build.VERSION_CODES.P; 5373 5374 sAlwaysAssignFocus = targetSdkVersion < Build.VERSION_CODES.P; 5375 5376 sAcceptZeroSizeDragShadow = targetSdkVersion < Build.VERSION_CODES.P; 5377 5378 sBrokenInsetsDispatch = ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL 5379 || targetSdkVersion < Build.VERSION_CODES.R; 5380 5381 sBrokenWindowBackground = targetSdkVersion < Build.VERSION_CODES.Q; 5382 5383 GradientDrawable.sWrapNegativeAngleMeasurements = 5384 targetSdkVersion >= Build.VERSION_CODES.Q; 5385 5386 sForceLayoutWhenInsetsChanged = targetSdkVersion < Build.VERSION_CODES.R; 5387 5388 sCompatibilityDone = true; 5389 } 5390 } 5391 5392 /** 5393 * Constructor that is called when inflating a view from XML. This is called 5394 * when a view is being constructed from an XML file, supplying attributes 5395 * that were specified in the XML file. This version uses a default style of 5396 * 0, so the only attribute values applied are those in the Context's Theme 5397 * and the given AttributeSet. 5398 * 5399 * <p> 5400 * The method onFinishInflate() will be called after all children have been 5401 * added. 5402 * 5403 * @param context The Context the view is running in, through which it can 5404 * access the current theme, resources, etc. 5405 * @param attrs The attributes of the XML tag that is inflating the view. 5406 * @see #View(Context, AttributeSet, int) 5407 */ 5408 public View(Context context, @Nullable AttributeSet attrs) { 5409 this(context, attrs, 0); 5410 } 5411 5412 /** 5413 * Perform inflation from XML and apply a class-specific base style from a 5414 * theme attribute. This constructor of View allows subclasses to use their 5415 * own base style when they are inflating. For example, a Button class's 5416 * constructor would call this version of the super class constructor and 5417 * supply <code>R.attr.buttonStyle</code> for <var>defStyleAttr</var>; this 5418 * allows the theme's button style to modify all of the base view attributes 5419 * (in particular its background) as well as the Button class's attributes. 5420 * 5421 * @param context The Context the view is running in, through which it can 5422 * access the current theme, resources, etc. 5423 * @param attrs The attributes of the XML tag that is inflating the view. 5424 * @param defStyleAttr An attribute in the current theme that contains a 5425 * reference to a style resource that supplies default values for 5426 * the view. Can be 0 to not look for defaults. 5427 * @see #View(Context, AttributeSet) 5428 */ 5429 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 5430 this(context, attrs, defStyleAttr, 0); 5431 } 5432 5433 /** 5434 * Perform inflation from XML and apply a class-specific base style from a 5435 * theme attribute or style resource. This constructor of View allows 5436 * subclasses to use their own base style when they are inflating. 5437 * <p> 5438 * When determining the final value of a particular attribute, there are 5439 * four inputs that come into play: 5440 * <ol> 5441 * <li>Any attribute values in the given AttributeSet. 5442 * <li>The style resource specified in the AttributeSet (named "style"). 5443 * <li>The default style specified by <var>defStyleAttr</var>. 5444 * <li>The default style specified by <var>defStyleRes</var>. 5445 * <li>The base values in this theme. 5446 * </ol> 5447 * <p> 5448 * Each of these inputs is considered in-order, with the first listed taking 5449 * precedence over the following ones. In other words, if in the 5450 * AttributeSet you have supplied <code><Button * textColor="#ff000000"></code> 5451 * , then the button's text will <em>always</em> be black, regardless of 5452 * what is specified in any of the styles. 5453 * 5454 * @param context The Context the view is running in, through which it can 5455 * access the current theme, resources, etc. 5456 * @param attrs The attributes of the XML tag that is inflating the view. 5457 * @param defStyleAttr An attribute in the current theme that contains a 5458 * reference to a style resource that supplies default values for 5459 * the view. Can be 0 to not look for defaults. 5460 * @param defStyleRes A resource identifier of a style resource that 5461 * supplies default values for the view, used only if 5462 * defStyleAttr is 0 or can not be found in the theme. Can be 0 5463 * to not look for defaults. 5464 * @see #View(Context, AttributeSet, int) 5465 */ 5466 public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { 5467 this(context); 5468 5469 mSourceLayoutId = Resources.getAttributeSetSourceResId(attrs); 5470 5471 final TypedArray a = context.obtainStyledAttributes( 5472 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes); 5473 5474 retrieveExplicitStyle(context.getTheme(), attrs); 5475 saveAttributeDataForStyleable(context, com.android.internal.R.styleable.View, attrs, a, 5476 defStyleAttr, defStyleRes); 5477 5478 if (sDebugViewAttributes) { 5479 saveAttributeData(attrs, a); 5480 } 5481 5482 Drawable background = null; 5483 5484 int leftPadding = -1; 5485 int topPadding = -1; 5486 int rightPadding = -1; 5487 int bottomPadding = -1; 5488 int startPadding = UNDEFINED_PADDING; 5489 int endPadding = UNDEFINED_PADDING; 5490 5491 int padding = -1; 5492 int paddingHorizontal = -1; 5493 int paddingVertical = -1; 5494 5495 int viewFlagValues = 0; 5496 int viewFlagMasks = 0; 5497 5498 boolean setScrollContainer = false; 5499 5500 int x = 0; 5501 int y = 0; 5502 5503 float tx = 0; 5504 float ty = 0; 5505 float tz = 0; 5506 float elevation = 0; 5507 float rotation = 0; 5508 float rotationX = 0; 5509 float rotationY = 0; 5510 float sx = 1f; 5511 float sy = 1f; 5512 boolean transformSet = false; 5513 5514 int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY; 5515 int overScrollMode = mOverScrollMode; 5516 boolean initializeScrollbars = false; 5517 boolean initializeScrollIndicators = false; 5518 5519 boolean startPaddingDefined = false; 5520 boolean endPaddingDefined = false; 5521 boolean leftPaddingDefined = false; 5522 boolean rightPaddingDefined = false; 5523 5524 final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion; 5525 5526 // Set default values. 5527 viewFlagValues |= FOCUSABLE_AUTO; 5528 viewFlagMasks |= FOCUSABLE_AUTO; 5529 5530 final int N = a.getIndexCount(); 5531 for (int i = 0; i < N; i++) { 5532 int attr = a.getIndex(i); 5533 switch (attr) { 5534 case com.android.internal.R.styleable.View_background: 5535 background = a.getDrawable(attr); 5536 break; 5537 case com.android.internal.R.styleable.View_padding: 5538 padding = a.getDimensionPixelSize(attr, -1); 5539 mUserPaddingLeftInitial = padding; 5540 mUserPaddingRightInitial = padding; 5541 leftPaddingDefined = true; 5542 rightPaddingDefined = true; 5543 break; 5544 case com.android.internal.R.styleable.View_paddingHorizontal: 5545 paddingHorizontal = a.getDimensionPixelSize(attr, -1); 5546 mUserPaddingLeftInitial = paddingHorizontal; 5547 mUserPaddingRightInitial = paddingHorizontal; 5548 leftPaddingDefined = true; 5549 rightPaddingDefined = true; 5550 break; 5551 case com.android.internal.R.styleable.View_paddingVertical: 5552 paddingVertical = a.getDimensionPixelSize(attr, -1); 5553 break; 5554 case com.android.internal.R.styleable.View_paddingLeft: 5555 leftPadding = a.getDimensionPixelSize(attr, -1); 5556 mUserPaddingLeftInitial = leftPadding; 5557 leftPaddingDefined = true; 5558 break; 5559 case com.android.internal.R.styleable.View_paddingTop: 5560 topPadding = a.getDimensionPixelSize(attr, -1); 5561 break; 5562 case com.android.internal.R.styleable.View_paddingRight: 5563 rightPadding = a.getDimensionPixelSize(attr, -1); 5564 mUserPaddingRightInitial = rightPadding; 5565 rightPaddingDefined = true; 5566 break; 5567 case com.android.internal.R.styleable.View_paddingBottom: 5568 bottomPadding = a.getDimensionPixelSize(attr, -1); 5569 break; 5570 case com.android.internal.R.styleable.View_paddingStart: 5571 startPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5572 startPaddingDefined = (startPadding != UNDEFINED_PADDING); 5573 break; 5574 case com.android.internal.R.styleable.View_paddingEnd: 5575 endPadding = a.getDimensionPixelSize(attr, UNDEFINED_PADDING); 5576 endPaddingDefined = (endPadding != UNDEFINED_PADDING); 5577 break; 5578 case com.android.internal.R.styleable.View_scrollX: 5579 x = a.getDimensionPixelOffset(attr, 0); 5580 break; 5581 case com.android.internal.R.styleable.View_scrollY: 5582 y = a.getDimensionPixelOffset(attr, 0); 5583 break; 5584 case com.android.internal.R.styleable.View_alpha: 5585 setAlpha(a.getFloat(attr, 1f)); 5586 break; 5587 case com.android.internal.R.styleable.View_transformPivotX: 5588 setPivotX(a.getDimension(attr, 0)); 5589 break; 5590 case com.android.internal.R.styleable.View_transformPivotY: 5591 setPivotY(a.getDimension(attr, 0)); 5592 break; 5593 case com.android.internal.R.styleable.View_translationX: 5594 tx = a.getDimension(attr, 0); 5595 transformSet = true; 5596 break; 5597 case com.android.internal.R.styleable.View_translationY: 5598 ty = a.getDimension(attr, 0); 5599 transformSet = true; 5600 break; 5601 case com.android.internal.R.styleable.View_translationZ: 5602 tz = a.getDimension(attr, 0); 5603 transformSet = true; 5604 break; 5605 case com.android.internal.R.styleable.View_elevation: 5606 elevation = a.getDimension(attr, 0); 5607 transformSet = true; 5608 break; 5609 case com.android.internal.R.styleable.View_rotation: 5610 rotation = a.getFloat(attr, 0); 5611 transformSet = true; 5612 break; 5613 case com.android.internal.R.styleable.View_rotationX: 5614 rotationX = a.getFloat(attr, 0); 5615 transformSet = true; 5616 break; 5617 case com.android.internal.R.styleable.View_rotationY: 5618 rotationY = a.getFloat(attr, 0); 5619 transformSet = true; 5620 break; 5621 case com.android.internal.R.styleable.View_scaleX: 5622 sx = a.getFloat(attr, 1f); 5623 transformSet = true; 5624 break; 5625 case com.android.internal.R.styleable.View_scaleY: 5626 sy = a.getFloat(attr, 1f); 5627 transformSet = true; 5628 break; 5629 case com.android.internal.R.styleable.View_id: 5630 mID = a.getResourceId(attr, NO_ID); 5631 break; 5632 case com.android.internal.R.styleable.View_tag: 5633 mTag = a.getText(attr); 5634 break; 5635 case com.android.internal.R.styleable.View_fitsSystemWindows: 5636 if (a.getBoolean(attr, false)) { 5637 viewFlagValues |= FITS_SYSTEM_WINDOWS; 5638 viewFlagMasks |= FITS_SYSTEM_WINDOWS; 5639 } 5640 break; 5641 case com.android.internal.R.styleable.View_focusable: 5642 viewFlagValues = (viewFlagValues & ~FOCUSABLE_MASK) | getFocusableAttribute(a); 5643 if ((viewFlagValues & FOCUSABLE_AUTO) == 0) { 5644 viewFlagMasks |= FOCUSABLE_MASK; 5645 } 5646 break; 5647 case com.android.internal.R.styleable.View_focusableInTouchMode: 5648 if (a.getBoolean(attr, false)) { 5649 // unset auto focus since focusableInTouchMode implies explicit focusable 5650 viewFlagValues &= ~FOCUSABLE_AUTO; 5651 viewFlagValues |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE; 5652 viewFlagMasks |= FOCUSABLE_IN_TOUCH_MODE | FOCUSABLE_MASK; 5653 } 5654 break; 5655 case com.android.internal.R.styleable.View_clickable: 5656 if (a.getBoolean(attr, false)) { 5657 viewFlagValues |= CLICKABLE; 5658 viewFlagMasks |= CLICKABLE; 5659 } 5660 break; 5661 case com.android.internal.R.styleable.View_longClickable: 5662 if (a.getBoolean(attr, false)) { 5663 viewFlagValues |= LONG_CLICKABLE; 5664 viewFlagMasks |= LONG_CLICKABLE; 5665 } 5666 break; 5667 case com.android.internal.R.styleable.View_contextClickable: 5668 if (a.getBoolean(attr, false)) { 5669 viewFlagValues |= CONTEXT_CLICKABLE; 5670 viewFlagMasks |= CONTEXT_CLICKABLE; 5671 } 5672 break; 5673 case com.android.internal.R.styleable.View_saveEnabled: 5674 if (!a.getBoolean(attr, true)) { 5675 viewFlagValues |= SAVE_DISABLED; 5676 viewFlagMasks |= SAVE_DISABLED_MASK; 5677 } 5678 break; 5679 case com.android.internal.R.styleable.View_duplicateParentState: 5680 if (a.getBoolean(attr, false)) { 5681 viewFlagValues |= DUPLICATE_PARENT_STATE; 5682 viewFlagMasks |= DUPLICATE_PARENT_STATE; 5683 } 5684 break; 5685 case com.android.internal.R.styleable.View_visibility: 5686 final int visibility = a.getInt(attr, 0); 5687 if (visibility != 0) { 5688 viewFlagValues |= VISIBILITY_FLAGS[visibility]; 5689 viewFlagMasks |= VISIBILITY_MASK; 5690 } 5691 break; 5692 case com.android.internal.R.styleable.View_layoutDirection: 5693 // Clear any layout direction flags (included resolved bits) already set 5694 mPrivateFlags2 &= 5695 ~(PFLAG2_LAYOUT_DIRECTION_MASK | PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK); 5696 // Set the layout direction flags depending on the value of the attribute 5697 final int layoutDirection = a.getInt(attr, -1); 5698 final int value = (layoutDirection != -1) ? 5699 LAYOUT_DIRECTION_FLAGS[layoutDirection] : LAYOUT_DIRECTION_DEFAULT; 5700 mPrivateFlags2 |= (value << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT); 5701 break; 5702 case com.android.internal.R.styleable.View_drawingCacheQuality: 5703 final int cacheQuality = a.getInt(attr, 0); 5704 if (cacheQuality != 0) { 5705 viewFlagValues |= DRAWING_CACHE_QUALITY_FLAGS[cacheQuality]; 5706 viewFlagMasks |= DRAWING_CACHE_QUALITY_MASK; 5707 } 5708 break; 5709 case com.android.internal.R.styleable.View_contentDescription: 5710 setContentDescription(a.getString(attr)); 5711 break; 5712 case com.android.internal.R.styleable.View_accessibilityTraversalBefore: 5713 setAccessibilityTraversalBefore(a.getResourceId(attr, NO_ID)); 5714 break; 5715 case com.android.internal.R.styleable.View_accessibilityTraversalAfter: 5716 setAccessibilityTraversalAfter(a.getResourceId(attr, NO_ID)); 5717 break; 5718 case com.android.internal.R.styleable.View_labelFor: 5719 setLabelFor(a.getResourceId(attr, NO_ID)); 5720 break; 5721 case com.android.internal.R.styleable.View_soundEffectsEnabled: 5722 if (!a.getBoolean(attr, true)) { 5723 viewFlagValues &= ~SOUND_EFFECTS_ENABLED; 5724 viewFlagMasks |= SOUND_EFFECTS_ENABLED; 5725 } 5726 break; 5727 case com.android.internal.R.styleable.View_hapticFeedbackEnabled: 5728 if (!a.getBoolean(attr, true)) { 5729 viewFlagValues &= ~HAPTIC_FEEDBACK_ENABLED; 5730 viewFlagMasks |= HAPTIC_FEEDBACK_ENABLED; 5731 } 5732 break; 5733 case R.styleable.View_scrollbars: 5734 final int scrollbars = a.getInt(attr, SCROLLBARS_NONE); 5735 if (scrollbars != SCROLLBARS_NONE) { 5736 viewFlagValues |= scrollbars; 5737 viewFlagMasks |= SCROLLBARS_MASK; 5738 initializeScrollbars = true; 5739 } 5740 break; 5741 //noinspection deprecation 5742 case R.styleable.View_fadingEdge: 5743 if (targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { 5744 // Ignore the attribute starting with ICS 5745 break; 5746 } 5747 // With builds < ICS, fall through and apply fading edges 5748 case R.styleable.View_requiresFadingEdge: 5749 final int fadingEdge = a.getInt(attr, FADING_EDGE_NONE); 5750 if (fadingEdge != FADING_EDGE_NONE) { 5751 viewFlagValues |= fadingEdge; 5752 viewFlagMasks |= FADING_EDGE_MASK; 5753 initializeFadingEdgeInternal(a); 5754 } 5755 break; 5756 case R.styleable.View_scrollbarStyle: 5757 scrollbarStyle = a.getInt(attr, SCROLLBARS_INSIDE_OVERLAY); 5758 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 5759 viewFlagValues |= scrollbarStyle & SCROLLBARS_STYLE_MASK; 5760 viewFlagMasks |= SCROLLBARS_STYLE_MASK; 5761 } 5762 break; 5763 case R.styleable.View_isScrollContainer: 5764 setScrollContainer = true; 5765 if (a.getBoolean(attr, false)) { 5766 setScrollContainer(true); 5767 } 5768 break; 5769 case com.android.internal.R.styleable.View_keepScreenOn: 5770 if (a.getBoolean(attr, false)) { 5771 viewFlagValues |= KEEP_SCREEN_ON; 5772 viewFlagMasks |= KEEP_SCREEN_ON; 5773 } 5774 break; 5775 case R.styleable.View_filterTouchesWhenObscured: 5776 if (a.getBoolean(attr, false)) { 5777 viewFlagValues |= FILTER_TOUCHES_WHEN_OBSCURED; 5778 viewFlagMasks |= FILTER_TOUCHES_WHEN_OBSCURED; 5779 } 5780 break; 5781 case R.styleable.View_nextFocusLeft: 5782 mNextFocusLeftId = a.getResourceId(attr, View.NO_ID); 5783 break; 5784 case R.styleable.View_nextFocusRight: 5785 mNextFocusRightId = a.getResourceId(attr, View.NO_ID); 5786 break; 5787 case R.styleable.View_nextFocusUp: 5788 mNextFocusUpId = a.getResourceId(attr, View.NO_ID); 5789 break; 5790 case R.styleable.View_nextFocusDown: 5791 mNextFocusDownId = a.getResourceId(attr, View.NO_ID); 5792 break; 5793 case R.styleable.View_nextFocusForward: 5794 mNextFocusForwardId = a.getResourceId(attr, View.NO_ID); 5795 break; 5796 case R.styleable.View_nextClusterForward: 5797 mNextClusterForwardId = a.getResourceId(attr, View.NO_ID); 5798 break; 5799 case R.styleable.View_minWidth: 5800 mMinWidth = a.getDimensionPixelSize(attr, 0); 5801 break; 5802 case R.styleable.View_minHeight: 5803 mMinHeight = a.getDimensionPixelSize(attr, 0); 5804 break; 5805 case R.styleable.View_onClick: 5806 if (context.isRestricted()) { 5807 throw new IllegalStateException("The android:onClick attribute cannot " 5808 + "be used within a restricted context"); 5809 } 5810 5811 final String handlerName = a.getString(attr); 5812 if (handlerName != null) { 5813 setOnClickListener(new DeclaredOnClickListener(this, handlerName)); 5814 } 5815 break; 5816 case R.styleable.View_overScrollMode: 5817 overScrollMode = a.getInt(attr, OVER_SCROLL_IF_CONTENT_SCROLLS); 5818 break; 5819 case R.styleable.View_verticalScrollbarPosition: 5820 mVerticalScrollbarPosition = a.getInt(attr, SCROLLBAR_POSITION_DEFAULT); 5821 break; 5822 case R.styleable.View_layerType: 5823 setLayerType(a.getInt(attr, LAYER_TYPE_NONE), null); 5824 break; 5825 case R.styleable.View_textDirection: 5826 // Clear any text direction flag already set 5827 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 5828 // Set the text direction flags depending on the value of the attribute 5829 final int textDirection = a.getInt(attr, -1); 5830 if (textDirection != -1) { 5831 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_FLAGS[textDirection]; 5832 } 5833 break; 5834 case R.styleable.View_textAlignment: 5835 // Clear any text alignment flag already set 5836 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 5837 // Set the text alignment flag depending on the value of the attribute 5838 final int textAlignment = a.getInt(attr, TEXT_ALIGNMENT_DEFAULT); 5839 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_FLAGS[textAlignment]; 5840 break; 5841 case R.styleable.View_importantForAccessibility: 5842 setImportantForAccessibility(a.getInt(attr, 5843 IMPORTANT_FOR_ACCESSIBILITY_DEFAULT)); 5844 break; 5845 case R.styleable.View_accessibilityLiveRegion: 5846 setAccessibilityLiveRegion(a.getInt(attr, ACCESSIBILITY_LIVE_REGION_DEFAULT)); 5847 break; 5848 case R.styleable.View_transitionName: 5849 setTransitionName(a.getString(attr)); 5850 break; 5851 case R.styleable.View_nestedScrollingEnabled: 5852 setNestedScrollingEnabled(a.getBoolean(attr, false)); 5853 break; 5854 case R.styleable.View_stateListAnimator: 5855 setStateListAnimator(AnimatorInflater.loadStateListAnimator(context, 5856 a.getResourceId(attr, 0))); 5857 break; 5858 case R.styleable.View_backgroundTint: 5859 // This will get applied later during setBackground(). 5860 if (mBackgroundTint == null) { 5861 mBackgroundTint = new TintInfo(); 5862 } 5863 mBackgroundTint.mTintList = a.getColorStateList( 5864 R.styleable.View_backgroundTint); 5865 mBackgroundTint.mHasTintList = true; 5866 break; 5867 case R.styleable.View_backgroundTintMode: 5868 // This will get applied later during setBackground(). 5869 if (mBackgroundTint == null) { 5870 mBackgroundTint = new TintInfo(); 5871 } 5872 mBackgroundTint.mBlendMode = Drawable.parseBlendMode(a.getInt( 5873 R.styleable.View_backgroundTintMode, -1), null); 5874 mBackgroundTint.mHasTintMode = true; 5875 break; 5876 case R.styleable.View_outlineProvider: 5877 setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, 5878 PROVIDER_BACKGROUND)); 5879 break; 5880 case R.styleable.View_foreground: 5881 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5882 setForeground(a.getDrawable(attr)); 5883 } 5884 break; 5885 case R.styleable.View_foregroundGravity: 5886 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5887 setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); 5888 } 5889 break; 5890 case R.styleable.View_foregroundTintMode: 5891 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5892 setForegroundTintBlendMode( 5893 Drawable.parseBlendMode(a.getInt(attr, -1), 5894 null)); 5895 } 5896 break; 5897 case R.styleable.View_foregroundTint: 5898 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5899 setForegroundTintList(a.getColorStateList(attr)); 5900 } 5901 break; 5902 case R.styleable.View_foregroundInsidePadding: 5903 if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) { 5904 if (mForegroundInfo == null) { 5905 mForegroundInfo = new ForegroundInfo(); 5906 } 5907 mForegroundInfo.mInsidePadding = a.getBoolean(attr, 5908 mForegroundInfo.mInsidePadding); 5909 } 5910 break; 5911 case R.styleable.View_scrollIndicators: 5912 final int scrollIndicators = 5913 (a.getInt(attr, 0) << SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT) 5914 & SCROLL_INDICATORS_PFLAG3_MASK; 5915 if (scrollIndicators != 0) { 5916 mPrivateFlags3 |= scrollIndicators; 5917 initializeScrollIndicators = true; 5918 } 5919 break; 5920 case R.styleable.View_pointerIcon: 5921 final int resourceId = a.getResourceId(attr, 0); 5922 if (resourceId != 0) { 5923 setPointerIcon(PointerIcon.load( 5924 context.getResources(), resourceId)); 5925 } else { 5926 final int pointerType = a.getInt(attr, PointerIcon.TYPE_NOT_SPECIFIED); 5927 if (pointerType != PointerIcon.TYPE_NOT_SPECIFIED) { 5928 setPointerIcon(PointerIcon.getSystemIcon(context, pointerType)); 5929 } 5930 } 5931 break; 5932 case R.styleable.View_forceHasOverlappingRendering: 5933 if (a.peekValue(attr) != null) { 5934 forceHasOverlappingRendering(a.getBoolean(attr, true)); 5935 } 5936 break; 5937 case R.styleable.View_tooltipText: 5938 setTooltipText(a.getText(attr)); 5939 break; 5940 case R.styleable.View_keyboardNavigationCluster: 5941 if (a.peekValue(attr) != null) { 5942 setKeyboardNavigationCluster(a.getBoolean(attr, true)); 5943 } 5944 break; 5945 case R.styleable.View_focusedByDefault: 5946 if (a.peekValue(attr) != null) { 5947 setFocusedByDefault(a.getBoolean(attr, true)); 5948 } 5949 break; 5950 case R.styleable.View_autofillHints: 5951 if (a.peekValue(attr) != null) { 5952 CharSequence[] rawHints = null; 5953 String rawString = null; 5954 5955 if (a.getType(attr) == TypedValue.TYPE_REFERENCE) { 5956 int resId = a.getResourceId(attr, 0); 5957 5958 try { 5959 rawHints = a.getTextArray(attr); 5960 } catch (Resources.NotFoundException e) { 5961 rawString = getResources().getString(resId); 5962 } 5963 } else { 5964 rawString = a.getString(attr); 5965 } 5966 5967 if (rawHints == null) { 5968 if (rawString == null) { 5969 throw new IllegalArgumentException( 5970 "Could not resolve autofillHints"); 5971 } else { 5972 rawHints = rawString.split(","); 5973 } 5974 } 5975 5976 String[] hints = new String[rawHints.length]; 5977 5978 int numHints = rawHints.length; 5979 for (int rawHintNum = 0; rawHintNum < numHints; rawHintNum++) { 5980 hints[rawHintNum] = rawHints[rawHintNum].toString().trim(); 5981 } 5982 setAutofillHints(hints); 5983 } 5984 break; 5985 case R.styleable.View_importantForAutofill: 5986 if (a.peekValue(attr) != null) { 5987 setImportantForAutofill(a.getInt(attr, IMPORTANT_FOR_AUTOFILL_AUTO)); 5988 } 5989 break; 5990 case R.styleable.View_importantForContentCapture: 5991 if (a.peekValue(attr) != null) { 5992 setImportantForContentCapture(a.getInt(attr, 5993 IMPORTANT_FOR_CONTENT_CAPTURE_AUTO)); 5994 } 5995 case R.styleable.View_defaultFocusHighlightEnabled: 5996 if (a.peekValue(attr) != null) { 5997 setDefaultFocusHighlightEnabled(a.getBoolean(attr, true)); 5998 } 5999 break; 6000 case R.styleable.View_screenReaderFocusable: 6001 if (a.peekValue(attr) != null) { 6002 setScreenReaderFocusable(a.getBoolean(attr, false)); 6003 } 6004 break; 6005 case R.styleable.View_accessibilityPaneTitle: 6006 if (a.peekValue(attr) != null) { 6007 setAccessibilityPaneTitle(a.getString(attr)); 6008 } 6009 break; 6010 case R.styleable.View_outlineSpotShadowColor: 6011 setOutlineSpotShadowColor(a.getColor(attr, Color.BLACK)); 6012 break; 6013 case R.styleable.View_outlineAmbientShadowColor: 6014 setOutlineAmbientShadowColor(a.getColor(attr, Color.BLACK)); 6015 break; 6016 case com.android.internal.R.styleable.View_accessibilityHeading: 6017 setAccessibilityHeading(a.getBoolean(attr, false)); 6018 break; 6019 case R.styleable.View_forceDarkAllowed: 6020 mRenderNode.setForceDarkAllowed(a.getBoolean(attr, true)); 6021 break; 6022 case R.styleable.View_scrollCaptureHint: 6023 setScrollCaptureHint((a.getInt(attr, SCROLL_CAPTURE_HINT_AUTO))); 6024 break; 6025 } 6026 } 6027 6028 setOverScrollMode(overScrollMode); 6029 6030 // Cache start/end user padding as we cannot fully resolve padding here (we don't have yet 6031 // the resolved layout direction). Those cached values will be used later during padding 6032 // resolution. 6033 mUserPaddingStart = startPadding; 6034 mUserPaddingEnd = endPadding; 6035 6036 if (background != null) { 6037 setBackground(background); 6038 } 6039 6040 // setBackground above will record that padding is currently provided by the background. 6041 // If we have padding specified via xml, record that here instead and use it. 6042 mLeftPaddingDefined = leftPaddingDefined; 6043 mRightPaddingDefined = rightPaddingDefined; 6044 6045 // Valid paddingHorizontal/paddingVertical beats leftPadding, rightPadding, topPadding, 6046 // bottomPadding, and padding set by background. Valid padding beats everything. 6047 if (padding >= 0) { 6048 leftPadding = padding; 6049 topPadding = padding; 6050 rightPadding = padding; 6051 bottomPadding = padding; 6052 mUserPaddingLeftInitial = padding; 6053 mUserPaddingRightInitial = padding; 6054 } else { 6055 if (paddingHorizontal >= 0) { 6056 leftPadding = paddingHorizontal; 6057 rightPadding = paddingHorizontal; 6058 mUserPaddingLeftInitial = paddingHorizontal; 6059 mUserPaddingRightInitial = paddingHorizontal; 6060 } 6061 if (paddingVertical >= 0) { 6062 topPadding = paddingVertical; 6063 bottomPadding = paddingVertical; 6064 } 6065 } 6066 6067 if (isRtlCompatibilityMode()) { 6068 // RTL compatibility mode: pre Jelly Bean MR1 case OR no RTL support case. 6069 // left / right padding are used if defined (meaning here nothing to do). If they are not 6070 // defined and start / end padding are defined (e.g. in Frameworks resources), then we use 6071 // start / end and resolve them as left / right (layout direction is not taken into account). 6072 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 6073 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 6074 // defined. 6075 if (!mLeftPaddingDefined && startPaddingDefined) { 6076 leftPadding = startPadding; 6077 } 6078 mUserPaddingLeftInitial = (leftPadding >= 0) ? leftPadding : mUserPaddingLeftInitial; 6079 if (!mRightPaddingDefined && endPaddingDefined) { 6080 rightPadding = endPadding; 6081 } 6082 mUserPaddingRightInitial = (rightPadding >= 0) ? rightPadding : mUserPaddingRightInitial; 6083 } else { 6084 // Jelly Bean MR1 and after case: if start/end defined, they will override any left/right 6085 // values defined. Otherwise, left /right values are used. 6086 // Padding from the background drawable is stored at this point in mUserPaddingLeftInitial 6087 // and mUserPaddingRightInitial) so drawable padding will be used as ultimate default if 6088 // defined. 6089 final boolean hasRelativePadding = startPaddingDefined || endPaddingDefined; 6090 6091 if (mLeftPaddingDefined && !hasRelativePadding) { 6092 mUserPaddingLeftInitial = leftPadding; 6093 } 6094 if (mRightPaddingDefined && !hasRelativePadding) { 6095 mUserPaddingRightInitial = rightPadding; 6096 } 6097 } 6098 6099 // mPaddingTop and mPaddingBottom may have been set by setBackground(Drawable) so must pass 6100 // them on if topPadding or bottomPadding are not valid. 6101 internalSetPadding( 6102 mUserPaddingLeftInitial, 6103 topPadding >= 0 ? topPadding : mPaddingTop, 6104 mUserPaddingRightInitial, 6105 bottomPadding >= 0 ? bottomPadding : mPaddingBottom); 6106 6107 if (viewFlagMasks != 0) { 6108 setFlags(viewFlagValues, viewFlagMasks); 6109 } 6110 6111 if (initializeScrollbars) { 6112 initializeScrollbarsInternal(a); 6113 } 6114 6115 if (initializeScrollIndicators) { 6116 initializeScrollIndicatorsInternal(); 6117 } 6118 6119 a.recycle(); 6120 6121 // Needs to be called after mViewFlags is set 6122 if (scrollbarStyle != SCROLLBARS_INSIDE_OVERLAY) { 6123 recomputePadding(); 6124 } 6125 6126 if (x != 0 || y != 0) { 6127 scrollTo(x, y); 6128 } 6129 6130 if (transformSet) { 6131 setTranslationX(tx); 6132 setTranslationY(ty); 6133 setTranslationZ(tz); 6134 setElevation(elevation); 6135 setRotation(rotation); 6136 setRotationX(rotationX); 6137 setRotationY(rotationY); 6138 setScaleX(sx); 6139 setScaleY(sy); 6140 } 6141 6142 if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) { 6143 setScrollContainer(true); 6144 } 6145 6146 computeOpaqueFlags(); 6147 } 6148 6149 /** 6150 * Returns the ordered list of resource ID that are considered when resolving attribute values 6151 * for this {@link View}. The list will include layout resource ID if the View is inflated from 6152 * XML. It will also include a set of explicit styles if specified in XML using 6153 * {@code style="..."}. Finally, it will include the default styles resolved from the theme. 6154 * 6155 * <p> 6156 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6157 * is enabled in Android developer options. 6158 * 6159 * @param attribute Attribute resource ID for which the resolution stack should be returned. 6160 * @return ordered list of resource ID that are considered when resolving attribute values for 6161 * this {@link View}. 6162 */ 6163 @NonNull 6164 public int[] getAttributeResolutionStack(@AttrRes int attribute) { 6165 if (!sDebugViewAttributes 6166 || mAttributeResolutionStacks == null 6167 || mAttributeResolutionStacks.get(attribute) == null) { 6168 return new int[0]; 6169 } 6170 int[] attributeResolutionStack = mAttributeResolutionStacks.get(attribute); 6171 int stackSize = attributeResolutionStack.length; 6172 if (mSourceLayoutId != ID_NULL) { 6173 stackSize++; 6174 } 6175 6176 int currentIndex = 0; 6177 int[] stack = new int[stackSize]; 6178 6179 if (mSourceLayoutId != ID_NULL) { 6180 stack[currentIndex] = mSourceLayoutId; 6181 currentIndex++; 6182 } 6183 for (int i = 0; i < attributeResolutionStack.length; i++) { 6184 stack[currentIndex] = attributeResolutionStack[i]; 6185 currentIndex++; 6186 } 6187 return stack; 6188 } 6189 6190 /** 6191 * Returns the mapping of attribute resource ID to source resource ID where the attribute value 6192 * was set. Source resource ID can either be a layout resource ID, if the value was set in XML 6193 * within the View tag, or a style resource ID, if the attribute was set in a style. The source 6194 * resource value will be one of the resource IDs from {@link #getAttributeSourceResourceMap()}. 6195 * 6196 * <p> 6197 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6198 * is enabled in Android developer options. 6199 * 6200 * @return mapping of attribute resource ID to source resource ID where the attribute value 6201 * was set. 6202 */ 6203 @NonNull 6204 public Map<Integer, Integer> getAttributeSourceResourceMap() { 6205 HashMap<Integer, Integer> map = new HashMap<>(); 6206 if (!sDebugViewAttributes || mAttributeSourceResId == null) { 6207 return map; 6208 } 6209 for (int i = 0; i < mAttributeSourceResId.size(); i++) { 6210 map.put(mAttributeSourceResId.keyAt(i), mAttributeSourceResId.valueAt(i)); 6211 } 6212 return map; 6213 } 6214 6215 /** 6216 * Returns the resource ID for the style specified using {@code style="..."} in the 6217 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise if not 6218 * specified or otherwise not applicable. 6219 * <p> 6220 * Each {@link View} can have an explicit style specified in the layout file. 6221 * This style is used first during the {@link View} attribute resolution, then if an attribute 6222 * is not defined there the resource system looks at default style and theme as fallbacks. 6223 * 6224 * <p> 6225 * <b>Note:</b> this method will only return actual values if the view attribute debugging 6226 * is enabled in Android developer options. 6227 * 6228 * @return The resource ID for the style specified using {@code style="..."} in the 6229 * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise 6230 * if not specified or otherwise not applicable. 6231 */ 6232 @StyleRes 6233 public int getExplicitStyle() { 6234 if (!sDebugViewAttributes) { 6235 return ID_NULL; 6236 } 6237 return mExplicitStyle; 6238 } 6239 6240 /** 6241 * An implementation of OnClickListener that attempts to lazily load a 6242 * named click handling method from a parent or ancestor context. 6243 */ 6244 private static class DeclaredOnClickListener implements OnClickListener { 6245 private final View mHostView; 6246 private final String mMethodName; 6247 6248 private Method mResolvedMethod; 6249 private Context mResolvedContext; 6250 6251 public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { 6252 mHostView = hostView; 6253 mMethodName = methodName; 6254 } 6255 6256 @Override 6257 public void onClick(@NonNull View v) { 6258 if (mResolvedMethod == null) { 6259 resolveMethod(mHostView.getContext(), mMethodName); 6260 } 6261 6262 try { 6263 mResolvedMethod.invoke(mResolvedContext, v); 6264 } catch (IllegalAccessException e) { 6265 throw new IllegalStateException( 6266 "Could not execute non-public method for android:onClick", e); 6267 } catch (InvocationTargetException e) { 6268 throw new IllegalStateException( 6269 "Could not execute method for android:onClick", e); 6270 } 6271 } 6272 6273 @NonNull 6274 private void resolveMethod(@Nullable Context context, @NonNull String name) { 6275 while (context != null) { 6276 try { 6277 if (!context.isRestricted()) { 6278 final Method method = context.getClass().getMethod(mMethodName, View.class); 6279 if (method != null) { 6280 mResolvedMethod = method; 6281 mResolvedContext = context; 6282 return; 6283 } 6284 } 6285 } catch (NoSuchMethodException e) { 6286 // Failed to find method, keep searching up the hierarchy. 6287 } 6288 6289 if (context instanceof ContextWrapper) { 6290 context = ((ContextWrapper) context).getBaseContext(); 6291 } else { 6292 // Can't search up the hierarchy, null out and fail. 6293 context = null; 6294 } 6295 } 6296 6297 final int id = mHostView.getId(); 6298 final String idText = id == NO_ID ? "" : " with id '" 6299 + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 6300 throw new IllegalStateException("Could not find method " + mMethodName 6301 + "(View) in a parent or ancestor Context for android:onClick " 6302 + "attribute defined on view " + mHostView.getClass() + idText); 6303 } 6304 } 6305 6306 /** 6307 * Non-public constructor for use in testing 6308 */ 6309 @UnsupportedAppUsage 6310 View() { 6311 mResources = null; 6312 mRenderNode = RenderNode.create(getClass().getName(), new ViewAnimationHostBridge(this)); 6313 } 6314 6315 /** 6316 * Returns {@code true} when the View is attached and the system developer setting to show 6317 * the layout bounds is enabled or {@code false} otherwise. 6318 */ 6319 public final boolean isShowingLayoutBounds() { 6320 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout; 6321 } 6322 6323 /** 6324 * Used to test isShowingLayoutBounds(). This sets the local value used 6325 * by that function. This method does nothing if the layout isn't attached. 6326 * 6327 * @hide 6328 */ 6329 @TestApi 6330 public final void setShowingLayoutBounds(boolean debugLayout) { 6331 if (mAttachInfo != null) { 6332 mAttachInfo.mDebugLayout = debugLayout; 6333 } 6334 } 6335 6336 private static SparseArray<String> getAttributeMap() { 6337 if (mAttributeMap == null) { 6338 mAttributeMap = new SparseArray<>(); 6339 } 6340 return mAttributeMap; 6341 } 6342 6343 private void retrieveExplicitStyle(@NonNull Resources.Theme theme, 6344 @Nullable AttributeSet attrs) { 6345 if (!sDebugViewAttributes) { 6346 return; 6347 } 6348 mExplicitStyle = theme.getExplicitStyle(attrs); 6349 } 6350 6351 /** 6352 * Stores debugging information about attributes. This should be called in a constructor by 6353 * every custom {@link View} that uses a custom styleable. If the custom view does not call it, 6354 * then the custom attributes used by this view will not be visible in layout inspection tools. 6355 * 6356 * @param context Context under which this view is created. 6357 * @param styleable A reference to styleable array R.styleable.Foo 6358 * @param attrs AttributeSet used to construct this view. 6359 * @param t Resolved {@link TypedArray} returned by a call to 6360 * {@link Resources#obtainAttributes(AttributeSet, int[])}. 6361 * @param defStyleAttr Default style attribute passed into the view constructor. 6362 * @param defStyleRes Default style resource passed into the view constructor. 6363 */ 6364 public final void saveAttributeDataForStyleable(@NonNull Context context, 6365 @NonNull int[] styleable, @Nullable AttributeSet attrs, @NonNull TypedArray t, 6366 int defStyleAttr, int defStyleRes) { 6367 if (!sDebugViewAttributes) { 6368 return; 6369 } 6370 6371 int[] attributeResolutionStack = context.getTheme().getAttributeResolutionStack( 6372 defStyleAttr, defStyleRes, mExplicitStyle); 6373 6374 if (mAttributeResolutionStacks == null) { 6375 mAttributeResolutionStacks = new SparseArray<>(); 6376 } 6377 6378 if (mAttributeSourceResId == null) { 6379 mAttributeSourceResId = new SparseIntArray(); 6380 } 6381 6382 final int indexCount = t.getIndexCount(); 6383 for (int j = 0; j < indexCount; ++j) { 6384 final int index = t.getIndex(j); 6385 mAttributeSourceResId.append(styleable[index], t.getSourceResourceId(index, 0)); 6386 mAttributeResolutionStacks.append(styleable[index], attributeResolutionStack); 6387 } 6388 } 6389 6390 private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) { 6391 final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount(); 6392 final int indexCount = t.getIndexCount(); 6393 final String[] attributes = new String[(attrsCount + indexCount) * 2]; 6394 6395 int i = 0; 6396 6397 // Store raw XML attributes. 6398 for (int j = 0; j < attrsCount; ++j) { 6399 attributes[i] = attrs.getAttributeName(j); 6400 attributes[i + 1] = attrs.getAttributeValue(j); 6401 i += 2; 6402 } 6403 6404 // Store resolved styleable attributes. 6405 final Resources res = t.getResources(); 6406 final SparseArray<String> attributeMap = getAttributeMap(); 6407 for (int j = 0; j < indexCount; ++j) { 6408 final int index = t.getIndex(j); 6409 if (!t.hasValueOrEmpty(index)) { 6410 // Value is undefined. Skip it. 6411 continue; 6412 } 6413 6414 final int resourceId = t.getResourceId(index, 0); 6415 if (resourceId == 0) { 6416 // Value is not a reference. Skip it. 6417 continue; 6418 } 6419 6420 String resourceName = attributeMap.get(resourceId); 6421 if (resourceName == null) { 6422 try { 6423 resourceName = res.getResourceName(resourceId); 6424 } catch (Resources.NotFoundException e) { 6425 resourceName = "0x" + Integer.toHexString(resourceId); 6426 } 6427 attributeMap.put(resourceId, resourceName); 6428 } 6429 6430 attributes[i] = resourceName; 6431 attributes[i + 1] = t.getString(index); 6432 i += 2; 6433 } 6434 6435 // Trim to fit contents. 6436 final String[] trimmed = new String[i]; 6437 System.arraycopy(attributes, 0, trimmed, 0, i); 6438 mAttributes = trimmed; 6439 } 6440 6441 @Override 6442 public String toString() { 6443 StringBuilder out = new StringBuilder(128); 6444 out.append(getClass().getName()); 6445 out.append('{'); 6446 out.append(Integer.toHexString(System.identityHashCode(this))); 6447 out.append(' '); 6448 switch (mViewFlags&VISIBILITY_MASK) { 6449 case VISIBLE: out.append('V'); break; 6450 case INVISIBLE: out.append('I'); break; 6451 case GONE: out.append('G'); break; 6452 default: out.append('.'); break; 6453 } 6454 out.append((mViewFlags & FOCUSABLE) == FOCUSABLE ? 'F' : '.'); 6455 out.append((mViewFlags&ENABLED_MASK) == ENABLED ? 'E' : '.'); 6456 out.append((mViewFlags&DRAW_MASK) == WILL_NOT_DRAW ? '.' : 'D'); 6457 out.append((mViewFlags&SCROLLBARS_HORIZONTAL) != 0 ? 'H' : '.'); 6458 out.append((mViewFlags&SCROLLBARS_VERTICAL) != 0 ? 'V' : '.'); 6459 out.append((mViewFlags&CLICKABLE) != 0 ? 'C' : '.'); 6460 out.append((mViewFlags&LONG_CLICKABLE) != 0 ? 'L' : '.'); 6461 out.append((mViewFlags&CONTEXT_CLICKABLE) != 0 ? 'X' : '.'); 6462 out.append(' '); 6463 out.append((mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0 ? 'R' : '.'); 6464 out.append((mPrivateFlags&PFLAG_FOCUSED) != 0 ? 'F' : '.'); 6465 out.append((mPrivateFlags&PFLAG_SELECTED) != 0 ? 'S' : '.'); 6466 if ((mPrivateFlags&PFLAG_PREPRESSED) != 0) { 6467 out.append('p'); 6468 } else { 6469 out.append((mPrivateFlags&PFLAG_PRESSED) != 0 ? 'P' : '.'); 6470 } 6471 out.append((mPrivateFlags&PFLAG_HOVERED) != 0 ? 'H' : '.'); 6472 out.append((mPrivateFlags&PFLAG_ACTIVATED) != 0 ? 'A' : '.'); 6473 out.append((mPrivateFlags&PFLAG_INVALIDATED) != 0 ? 'I' : '.'); 6474 out.append((mPrivateFlags&PFLAG_DIRTY_MASK) != 0 ? 'D' : '.'); 6475 out.append(' '); 6476 out.append(mLeft); 6477 out.append(','); 6478 out.append(mTop); 6479 out.append('-'); 6480 out.append(mRight); 6481 out.append(','); 6482 out.append(mBottom); 6483 final int id = getId(); 6484 if (id != NO_ID) { 6485 out.append(" #"); 6486 out.append(Integer.toHexString(id)); 6487 final Resources r = mResources; 6488 if (id > 0 && Resources.resourceHasPackage(id) && r != null) { 6489 try { 6490 String pkgname; 6491 switch (id&0xff000000) { 6492 case 0x7f000000: 6493 pkgname="app"; 6494 break; 6495 case 0x01000000: 6496 pkgname="android"; 6497 break; 6498 default: 6499 pkgname = r.getResourcePackageName(id); 6500 break; 6501 } 6502 String typename = r.getResourceTypeName(id); 6503 String entryname = r.getResourceEntryName(id); 6504 out.append(" "); 6505 out.append(pkgname); 6506 out.append(":"); 6507 out.append(typename); 6508 out.append("/"); 6509 out.append(entryname); 6510 } catch (Resources.NotFoundException e) { 6511 } 6512 } 6513 } 6514 if (mAutofillId != null) { 6515 out.append(" aid="); out.append(mAutofillId); 6516 } 6517 out.append("}"); 6518 return out.toString(); 6519 } 6520 6521 /** 6522 * <p> 6523 * Initializes the fading edges from a given set of styled attributes. This 6524 * method should be called by subclasses that need fading edges and when an 6525 * instance of these subclasses is created programmatically rather than 6526 * being inflated from XML. This method is automatically called when the XML 6527 * is inflated. 6528 * </p> 6529 * 6530 * @param a the styled attributes set to initialize the fading edges from 6531 * 6532 * @removed 6533 */ 6534 protected void initializeFadingEdge(TypedArray a) { 6535 // This method probably shouldn't have been included in the SDK to begin with. 6536 // It relies on 'a' having been initialized using an attribute filter array that is 6537 // not publicly available to the SDK. The old method has been renamed 6538 // to initializeFadingEdgeInternal and hidden for framework use only; 6539 // this one initializes using defaults to make it safe to call for apps. 6540 6541 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 6542 6543 initializeFadingEdgeInternal(arr); 6544 6545 arr.recycle(); 6546 } 6547 6548 /** 6549 * <p> 6550 * Initializes the fading edges from a given set of styled attributes. This 6551 * method should be called by subclasses that need fading edges and when an 6552 * instance of these subclasses is created programmatically rather than 6553 * being inflated from XML. This method is automatically called when the XML 6554 * is inflated. 6555 * </p> 6556 * 6557 * @param a the styled attributes set to initialize the fading edges from 6558 * @hide This is the real method; the public one is shimmed to be safe to call from apps. 6559 */ 6560 protected void initializeFadingEdgeInternal(TypedArray a) { 6561 initScrollCache(); 6562 6563 mScrollCache.fadingEdgeLength = a.getDimensionPixelSize( 6564 R.styleable.View_fadingEdgeLength, 6565 ViewConfiguration.get(mContext).getScaledFadingEdgeLength()); 6566 } 6567 6568 /** 6569 * Returns the size of the vertical faded edges used to indicate that more 6570 * content in this view is visible. 6571 * 6572 * @return The size in pixels of the vertical faded edge or 0 if vertical 6573 * faded edges are not enabled for this view. 6574 * @attr ref android.R.styleable#View_fadingEdgeLength 6575 */ 6576 public int getVerticalFadingEdgeLength() { 6577 if (isVerticalFadingEdgeEnabled()) { 6578 ScrollabilityCache cache = mScrollCache; 6579 if (cache != null) { 6580 return cache.fadingEdgeLength; 6581 } 6582 } 6583 return 0; 6584 } 6585 6586 /** 6587 * Set the size of the faded edge used to indicate that more content in this 6588 * view is available. Will not change whether the fading edge is enabled; use 6589 * {@link #setVerticalFadingEdgeEnabled(boolean)} or 6590 * {@link #setHorizontalFadingEdgeEnabled(boolean)} to enable the fading edge 6591 * for the vertical or horizontal fading edges. 6592 * 6593 * @param length The size in pixels of the faded edge used to indicate that more 6594 * content in this view is visible. 6595 */ 6596 public void setFadingEdgeLength(int length) { 6597 initScrollCache(); 6598 mScrollCache.fadingEdgeLength = length; 6599 } 6600 6601 /** 6602 * Returns the size of the horizontal faded edges used to indicate that more 6603 * content in this view is visible. 6604 * 6605 * @return The size in pixels of the horizontal faded edge or 0 if horizontal 6606 * faded edges are not enabled for this view. 6607 * @attr ref android.R.styleable#View_fadingEdgeLength 6608 */ 6609 public int getHorizontalFadingEdgeLength() { 6610 if (isHorizontalFadingEdgeEnabled()) { 6611 ScrollabilityCache cache = mScrollCache; 6612 if (cache != null) { 6613 return cache.fadingEdgeLength; 6614 } 6615 } 6616 return 0; 6617 } 6618 6619 /** 6620 * Returns the width of the vertical scrollbar. 6621 * 6622 * @return The width in pixels of the vertical scrollbar or 0 if there 6623 * is no vertical scrollbar. 6624 */ 6625 public int getVerticalScrollbarWidth() { 6626 ScrollabilityCache cache = mScrollCache; 6627 if (cache != null) { 6628 ScrollBarDrawable scrollBar = cache.scrollBar; 6629 if (scrollBar != null) { 6630 int size = scrollBar.getSize(true); 6631 if (size <= 0) { 6632 size = cache.scrollBarSize; 6633 } 6634 return size; 6635 } 6636 return 0; 6637 } 6638 return 0; 6639 } 6640 6641 /** 6642 * Returns the height of the horizontal scrollbar. 6643 * 6644 * @return The height in pixels of the horizontal scrollbar or 0 if 6645 * there is no horizontal scrollbar. 6646 */ 6647 protected int getHorizontalScrollbarHeight() { 6648 ScrollabilityCache cache = mScrollCache; 6649 if (cache != null) { 6650 ScrollBarDrawable scrollBar = cache.scrollBar; 6651 if (scrollBar != null) { 6652 int size = scrollBar.getSize(false); 6653 if (size <= 0) { 6654 size = cache.scrollBarSize; 6655 } 6656 return size; 6657 } 6658 return 0; 6659 } 6660 return 0; 6661 } 6662 6663 /** 6664 * <p> 6665 * Initializes the scrollbars from a given set of styled attributes. This 6666 * method should be called by subclasses that need scrollbars and when an 6667 * instance of these subclasses is created programmatically rather than 6668 * being inflated from XML. This method is automatically called when the XML 6669 * is inflated. 6670 * </p> 6671 * 6672 * @param a the styled attributes set to initialize the scrollbars from 6673 * 6674 * @removed 6675 */ 6676 protected void initializeScrollbars(TypedArray a) { 6677 // It's not safe to use this method from apps. The parameter 'a' must have been obtained 6678 // using the View filter array which is not available to the SDK. As such, internal 6679 // framework usage now uses initializeScrollbarsInternal and we grab a default 6680 // TypedArray with the right filter instead here. 6681 TypedArray arr = mContext.obtainStyledAttributes(com.android.internal.R.styleable.View); 6682 6683 initializeScrollbarsInternal(arr); 6684 6685 // We ignored the method parameter. Recycle the one we actually did use. 6686 arr.recycle(); 6687 } 6688 6689 private void initializeScrollBarDrawable() { 6690 initScrollCache(); 6691 6692 if (mScrollCache.scrollBar == null) { 6693 mScrollCache.scrollBar = new ScrollBarDrawable(); 6694 mScrollCache.scrollBar.setState(getDrawableState()); 6695 mScrollCache.scrollBar.setCallback(this); 6696 } 6697 } 6698 6699 /** 6700 * <p> 6701 * Initializes the scrollbars from a given set of styled attributes. This 6702 * method should be called by subclasses that need scrollbars and when an 6703 * instance of these subclasses is created programmatically rather than 6704 * being inflated from XML. This method is automatically called when the XML 6705 * is inflated. 6706 * </p> 6707 * 6708 * @param a the styled attributes set to initialize the scrollbars from 6709 * @hide 6710 */ 6711 @UnsupportedAppUsage 6712 protected void initializeScrollbarsInternal(TypedArray a) { 6713 initScrollCache(); 6714 6715 final ScrollabilityCache scrollabilityCache = mScrollCache; 6716 6717 if (scrollabilityCache.scrollBar == null) { 6718 scrollabilityCache.scrollBar = new ScrollBarDrawable(); 6719 scrollabilityCache.scrollBar.setState(getDrawableState()); 6720 scrollabilityCache.scrollBar.setCallback(this); 6721 } 6722 6723 final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true); 6724 6725 if (!fadeScrollbars) { 6726 scrollabilityCache.state = ScrollabilityCache.ON; 6727 } 6728 scrollabilityCache.fadeScrollBars = fadeScrollbars; 6729 6730 6731 scrollabilityCache.scrollBarFadeDuration = a.getInt( 6732 R.styleable.View_scrollbarFadeDuration, ViewConfiguration 6733 .getScrollBarFadeDuration()); 6734 scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt( 6735 R.styleable.View_scrollbarDefaultDelayBeforeFade, 6736 ViewConfiguration.getScrollDefaultDelay()); 6737 6738 6739 scrollabilityCache.scrollBarSize = a.getDimensionPixelSize( 6740 com.android.internal.R.styleable.View_scrollbarSize, 6741 ViewConfiguration.get(mContext).getScaledScrollBarSize()); 6742 6743 Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal); 6744 scrollabilityCache.scrollBar.setHorizontalTrackDrawable(track); 6745 6746 Drawable thumb = a.getDrawable(R.styleable.View_scrollbarThumbHorizontal); 6747 if (thumb != null) { 6748 scrollabilityCache.scrollBar.setHorizontalThumbDrawable(thumb); 6749 } 6750 6751 boolean alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawHorizontalTrack, 6752 false); 6753 if (alwaysDraw) { 6754 scrollabilityCache.scrollBar.setAlwaysDrawHorizontalTrack(true); 6755 } 6756 6757 track = a.getDrawable(R.styleable.View_scrollbarTrackVertical); 6758 scrollabilityCache.scrollBar.setVerticalTrackDrawable(track); 6759 6760 thumb = a.getDrawable(R.styleable.View_scrollbarThumbVertical); 6761 if (thumb != null) { 6762 scrollabilityCache.scrollBar.setVerticalThumbDrawable(thumb); 6763 } 6764 6765 alwaysDraw = a.getBoolean(R.styleable.View_scrollbarAlwaysDrawVerticalTrack, 6766 false); 6767 if (alwaysDraw) { 6768 scrollabilityCache.scrollBar.setAlwaysDrawVerticalTrack(true); 6769 } 6770 6771 // Apply layout direction to the new Drawables if needed 6772 final int layoutDirection = getLayoutDirection(); 6773 if (track != null) { 6774 track.setLayoutDirection(layoutDirection); 6775 } 6776 if (thumb != null) { 6777 thumb.setLayoutDirection(layoutDirection); 6778 } 6779 6780 // Re-apply user/background padding so that scrollbar(s) get added 6781 resolvePadding(); 6782 } 6783 6784 /** 6785 * Defines the vertical scrollbar thumb drawable 6786 * @attr ref android.R.styleable#View_scrollbarThumbVertical 6787 * 6788 * @see #awakenScrollBars(int) 6789 * @see #isVerticalScrollBarEnabled() 6790 * @see #setVerticalScrollBarEnabled(boolean) 6791 */ 6792 public void setVerticalScrollbarThumbDrawable(@Nullable Drawable drawable) { 6793 initializeScrollBarDrawable(); 6794 mScrollCache.scrollBar.setVerticalThumbDrawable(drawable); 6795 } 6796 6797 /** 6798 * Defines the vertical scrollbar track drawable 6799 * @attr ref android.R.styleable#View_scrollbarTrackVertical 6800 * 6801 * @see #awakenScrollBars(int) 6802 * @see #isVerticalScrollBarEnabled() 6803 * @see #setVerticalScrollBarEnabled(boolean) 6804 */ 6805 public void setVerticalScrollbarTrackDrawable(@Nullable Drawable drawable) { 6806 initializeScrollBarDrawable(); 6807 mScrollCache.scrollBar.setVerticalTrackDrawable(drawable); 6808 } 6809 6810 /** 6811 * Defines the horizontal thumb drawable 6812 * @attr ref android.R.styleable#View_scrollbarThumbHorizontal 6813 * 6814 * @see #awakenScrollBars(int) 6815 * @see #isHorizontalScrollBarEnabled() 6816 * @see #setHorizontalScrollBarEnabled(boolean) 6817 */ 6818 public void setHorizontalScrollbarThumbDrawable(@Nullable Drawable drawable) { 6819 initializeScrollBarDrawable(); 6820 mScrollCache.scrollBar.setHorizontalThumbDrawable(drawable); 6821 } 6822 6823 /** 6824 * Defines the horizontal track drawable 6825 * @attr ref android.R.styleable#View_scrollbarTrackHorizontal 6826 * 6827 * @see #awakenScrollBars(int) 6828 * @see #isHorizontalScrollBarEnabled() 6829 * @see #setHorizontalScrollBarEnabled(boolean) 6830 */ 6831 public void setHorizontalScrollbarTrackDrawable(@Nullable Drawable drawable) { 6832 initializeScrollBarDrawable(); 6833 mScrollCache.scrollBar.setHorizontalTrackDrawable(drawable); 6834 } 6835 6836 /** 6837 * Returns the currently configured Drawable for the thumb of the vertical scroll bar if it 6838 * exists, null otherwise. 6839 * 6840 * @see #awakenScrollBars(int) 6841 * @see #isVerticalScrollBarEnabled() 6842 * @see #setVerticalScrollBarEnabled(boolean) 6843 */ 6844 public @Nullable Drawable getVerticalScrollbarThumbDrawable() { 6845 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalThumbDrawable() : null; 6846 } 6847 6848 /** 6849 * Returns the currently configured Drawable for the track of the vertical scroll bar if it 6850 * exists, null otherwise. 6851 * 6852 * @see #awakenScrollBars(int) 6853 * @see #isVerticalScrollBarEnabled() 6854 * @see #setVerticalScrollBarEnabled(boolean) 6855 */ 6856 public @Nullable Drawable getVerticalScrollbarTrackDrawable() { 6857 return mScrollCache != null ? mScrollCache.scrollBar.getVerticalTrackDrawable() : null; 6858 } 6859 6860 /** 6861 * Returns the currently configured Drawable for the thumb of the horizontal scroll bar if it 6862 * exists, null otherwise. 6863 * 6864 * @see #awakenScrollBars(int) 6865 * @see #isHorizontalScrollBarEnabled() 6866 * @see #setHorizontalScrollBarEnabled(boolean) 6867 */ 6868 public @Nullable Drawable getHorizontalScrollbarThumbDrawable() { 6869 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalThumbDrawable() : null; 6870 } 6871 6872 /** 6873 * Returns the currently configured Drawable for the track of the horizontal scroll bar if it 6874 * exists, null otherwise. 6875 * 6876 * @see #awakenScrollBars(int) 6877 * @see #isHorizontalScrollBarEnabled() 6878 * @see #setHorizontalScrollBarEnabled(boolean) 6879 */ 6880 public @Nullable Drawable getHorizontalScrollbarTrackDrawable() { 6881 return mScrollCache != null ? mScrollCache.scrollBar.getHorizontalTrackDrawable() : null; 6882 } 6883 6884 private void initializeScrollIndicatorsInternal() { 6885 // Some day maybe we'll break this into top/left/start/etc. and let the 6886 // client control it. Until then, you can have any scroll indicator you 6887 // want as long as it's a 1dp foreground-colored rectangle. 6888 if (mScrollIndicatorDrawable == null) { 6889 mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material); 6890 } 6891 } 6892 6893 /** 6894 * <p> 6895 * Initalizes the scrollability cache if necessary. 6896 * </p> 6897 */ 6898 private void initScrollCache() { 6899 if (mScrollCache == null) { 6900 mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this); 6901 } 6902 } 6903 6904 @UnsupportedAppUsage 6905 private ScrollabilityCache getScrollCache() { 6906 initScrollCache(); 6907 return mScrollCache; 6908 } 6909 6910 /** 6911 * Set the position of the vertical scroll bar. Should be one of 6912 * {@link #SCROLLBAR_POSITION_DEFAULT}, {@link #SCROLLBAR_POSITION_LEFT} or 6913 * {@link #SCROLLBAR_POSITION_RIGHT}. 6914 * 6915 * @param position Where the vertical scroll bar should be positioned. 6916 */ 6917 public void setVerticalScrollbarPosition(int position) { 6918 if (mVerticalScrollbarPosition != position) { 6919 mVerticalScrollbarPosition = position; 6920 computeOpaqueFlags(); 6921 resolvePadding(); 6922 } 6923 } 6924 6925 /** 6926 * @return The position where the vertical scroll bar will show, if applicable. 6927 * @see #setVerticalScrollbarPosition(int) 6928 */ 6929 public int getVerticalScrollbarPosition() { 6930 return mVerticalScrollbarPosition; 6931 } 6932 6933 boolean isOnScrollbar(float x, float y) { 6934 if (mScrollCache == null) { 6935 return false; 6936 } 6937 x += getScrollX(); 6938 y += getScrollY(); 6939 final boolean canScrollVertically = 6940 computeVerticalScrollRange() > computeVerticalScrollExtent(); 6941 if (isVerticalScrollBarEnabled() && !isVerticalScrollBarHidden() && canScrollVertically) { 6942 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6943 getVerticalScrollBarBounds(null, touchBounds); 6944 if (touchBounds.contains((int) x, (int) y)) { 6945 return true; 6946 } 6947 } 6948 final boolean canScrollHorizontally = 6949 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 6950 if (isHorizontalScrollBarEnabled() && canScrollHorizontally) { 6951 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6952 getHorizontalScrollBarBounds(null, touchBounds); 6953 if (touchBounds.contains((int) x, (int) y)) { 6954 return true; 6955 } 6956 } 6957 return false; 6958 } 6959 6960 @UnsupportedAppUsage 6961 boolean isOnScrollbarThumb(float x, float y) { 6962 return isOnVerticalScrollbarThumb(x, y) || isOnHorizontalScrollbarThumb(x, y); 6963 } 6964 6965 private boolean isOnVerticalScrollbarThumb(float x, float y) { 6966 if (mScrollCache == null || !isVerticalScrollBarEnabled() || isVerticalScrollBarHidden()) { 6967 return false; 6968 } 6969 final int range = computeVerticalScrollRange(); 6970 final int extent = computeVerticalScrollExtent(); 6971 if (range > extent) { 6972 x += getScrollX(); 6973 y += getScrollY(); 6974 final Rect bounds = mScrollCache.mScrollBarBounds; 6975 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 6976 getVerticalScrollBarBounds(bounds, touchBounds); 6977 final int offset = computeVerticalScrollOffset(); 6978 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.height(), bounds.width(), 6979 extent, range); 6980 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.height(), thumbLength, 6981 extent, range, offset); 6982 final int thumbTop = bounds.top + thumbOffset; 6983 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 6984 if (x >= touchBounds.left && x <= touchBounds.right 6985 && y >= thumbTop - adjust && y <= thumbTop + thumbLength + adjust) { 6986 return true; 6987 } 6988 } 6989 return false; 6990 } 6991 6992 private boolean isOnHorizontalScrollbarThumb(float x, float y) { 6993 if (mScrollCache == null || !isHorizontalScrollBarEnabled()) { 6994 return false; 6995 } 6996 final int range = computeHorizontalScrollRange(); 6997 final int extent = computeHorizontalScrollExtent(); 6998 if (range > extent) { 6999 x += getScrollX(); 7000 y += getScrollY(); 7001 final Rect bounds = mScrollCache.mScrollBarBounds; 7002 final Rect touchBounds = mScrollCache.mScrollBarTouchBounds; 7003 getHorizontalScrollBarBounds(bounds, touchBounds); 7004 final int offset = computeHorizontalScrollOffset(); 7005 7006 final int thumbLength = ScrollBarUtils.getThumbLength(bounds.width(), bounds.height(), 7007 extent, range); 7008 final int thumbOffset = ScrollBarUtils.getThumbOffset(bounds.width(), thumbLength, 7009 extent, range, offset); 7010 final int thumbLeft = bounds.left + thumbOffset; 7011 final int adjust = Math.max(mScrollCache.scrollBarMinTouchTarget - thumbLength, 0) / 2; 7012 if (x >= thumbLeft - adjust && x <= thumbLeft + thumbLength + adjust 7013 && y >= touchBounds.top && y <= touchBounds.bottom) { 7014 return true; 7015 } 7016 } 7017 return false; 7018 } 7019 7020 @UnsupportedAppUsage 7021 boolean isDraggingScrollBar() { 7022 return mScrollCache != null 7023 && mScrollCache.mScrollBarDraggingState != ScrollabilityCache.NOT_DRAGGING; 7024 } 7025 7026 /** 7027 * Sets the state of all scroll indicators. 7028 * <p> 7029 * See {@link #setScrollIndicators(int, int)} for usage information. 7030 * 7031 * @param indicators a bitmask of indicators that should be enabled, or 7032 * {@code 0} to disable all indicators 7033 * @see #setScrollIndicators(int, int) 7034 * @see #getScrollIndicators() 7035 * @attr ref android.R.styleable#View_scrollIndicators 7036 */ 7037 public void setScrollIndicators(@ScrollIndicators int indicators) { 7038 setScrollIndicators(indicators, 7039 SCROLL_INDICATORS_PFLAG3_MASK >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT); 7040 } 7041 7042 /** 7043 * Sets the state of the scroll indicators specified by the mask. To change 7044 * all scroll indicators at once, see {@link #setScrollIndicators(int)}. 7045 * <p> 7046 * When a scroll indicator is enabled, it will be displayed if the view 7047 * can scroll in the direction of the indicator. 7048 * <p> 7049 * Multiple indicator types may be enabled or disabled by passing the 7050 * logical OR of the desired types. If multiple types are specified, they 7051 * will all be set to the same enabled state. 7052 * <p> 7053 * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators 7054 * 7055 * @param indicators the indicator direction, or the logical OR of multiple 7056 * indicator directions. One or more of: 7057 * <ul> 7058 * <li>{@link #SCROLL_INDICATOR_TOP}</li> 7059 * <li>{@link #SCROLL_INDICATOR_BOTTOM}</li> 7060 * <li>{@link #SCROLL_INDICATOR_LEFT}</li> 7061 * <li>{@link #SCROLL_INDICATOR_RIGHT}</li> 7062 * <li>{@link #SCROLL_INDICATOR_START}</li> 7063 * <li>{@link #SCROLL_INDICATOR_END}</li> 7064 * </ul> 7065 * @see #setScrollIndicators(int) 7066 * @see #getScrollIndicators() 7067 * @attr ref android.R.styleable#View_scrollIndicators 7068 */ 7069 public void setScrollIndicators(@ScrollIndicators int indicators, @ScrollIndicators int mask) { 7070 // Shift and sanitize mask. 7071 mask <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7072 mask &= SCROLL_INDICATORS_PFLAG3_MASK; 7073 7074 // Shift and mask indicators. 7075 indicators <<= SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7076 indicators &= mask; 7077 7078 // Merge with non-masked flags. 7079 final int updatedFlags = indicators | (mPrivateFlags3 & ~mask); 7080 7081 if (mPrivateFlags3 != updatedFlags) { 7082 mPrivateFlags3 = updatedFlags; 7083 7084 if (indicators != 0) { 7085 initializeScrollIndicatorsInternal(); 7086 } 7087 invalidate(); 7088 } 7089 } 7090 7091 /** 7092 * Returns a bitmask representing the enabled scroll indicators. 7093 * <p> 7094 * For example, if the top and left scroll indicators are enabled and all 7095 * other indicators are disabled, the return value will be 7096 * {@code View.SCROLL_INDICATOR_TOP | View.SCROLL_INDICATOR_LEFT}. 7097 * <p> 7098 * To check whether the bottom scroll indicator is enabled, use the value 7099 * of {@code (getScrollIndicators() & View.SCROLL_INDICATOR_BOTTOM) != 0}. 7100 * 7101 * @return a bitmask representing the enabled scroll indicators 7102 */ 7103 @InspectableProperty(flagMapping = { 7104 @FlagEntry(target = SCROLL_INDICATORS_NONE, mask = 0xffff_ffff, name = "none"), 7105 @FlagEntry(target = SCROLL_INDICATOR_TOP, name = "top"), 7106 @FlagEntry(target = SCROLL_INDICATOR_BOTTOM, name = "bottom"), 7107 @FlagEntry(target = SCROLL_INDICATOR_LEFT, name = "left"), 7108 @FlagEntry(target = SCROLL_INDICATOR_RIGHT, name = "right"), 7109 @FlagEntry(target = SCROLL_INDICATOR_START, name = "start"), 7110 @FlagEntry(target = SCROLL_INDICATOR_END, name = "end") 7111 }) 7112 @ScrollIndicators 7113 public int getScrollIndicators() { 7114 return (mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) 7115 >>> SCROLL_INDICATORS_TO_PFLAGS3_LSHIFT; 7116 } 7117 7118 @UnsupportedAppUsage 7119 ListenerInfo getListenerInfo() { 7120 if (mListenerInfo != null) { 7121 return mListenerInfo; 7122 } 7123 mListenerInfo = new ListenerInfo(); 7124 return mListenerInfo; 7125 } 7126 7127 /** 7128 * Register a callback to be invoked when the scroll X or Y positions of 7129 * this view change. 7130 * <p> 7131 * <b>Note:</b> Some views handle scrolling independently from View and may 7132 * have their own separate listeners for scroll-type events. For example, 7133 * {@link android.widget.ListView ListView} allows clients to register an 7134 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 7135 * to listen for changes in list scroll position. 7136 * 7137 * @param l The listener to notify when the scroll X or Y position changes. 7138 * @see android.view.View#getScrollX() 7139 * @see android.view.View#getScrollY() 7140 */ 7141 public void setOnScrollChangeListener(OnScrollChangeListener l) { 7142 getListenerInfo().mOnScrollChangeListener = l; 7143 } 7144 7145 /** 7146 * Register a callback to be invoked when focus of this view changed. 7147 * 7148 * @param l The callback that will run. 7149 */ 7150 public void setOnFocusChangeListener(OnFocusChangeListener l) { 7151 getListenerInfo().mOnFocusChangeListener = l; 7152 } 7153 7154 /** 7155 * Add a listener that will be called when the bounds of the view change due to 7156 * layout processing. 7157 * 7158 * @param listener The listener that will be called when layout bounds change. 7159 */ 7160 public void addOnLayoutChangeListener(OnLayoutChangeListener listener) { 7161 ListenerInfo li = getListenerInfo(); 7162 if (li.mOnLayoutChangeListeners == null) { 7163 li.mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>(); 7164 } 7165 if (!li.mOnLayoutChangeListeners.contains(listener)) { 7166 li.mOnLayoutChangeListeners.add(listener); 7167 } 7168 } 7169 7170 /** 7171 * Remove a listener for layout changes. 7172 * 7173 * @param listener The listener for layout bounds change. 7174 */ 7175 public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) { 7176 ListenerInfo li = mListenerInfo; 7177 if (li == null || li.mOnLayoutChangeListeners == null) { 7178 return; 7179 } 7180 li.mOnLayoutChangeListeners.remove(listener); 7181 } 7182 7183 /** 7184 * Add a listener for attach state changes. 7185 * 7186 * This listener will be called whenever this view is attached or detached 7187 * from a window. Remove the listener using 7188 * {@link #removeOnAttachStateChangeListener(OnAttachStateChangeListener)}. 7189 * 7190 * @param listener Listener to attach 7191 * @see #removeOnAttachStateChangeListener(OnAttachStateChangeListener) 7192 */ 7193 public void addOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7194 ListenerInfo li = getListenerInfo(); 7195 if (li.mOnAttachStateChangeListeners == null) { 7196 li.mOnAttachStateChangeListeners 7197 = new CopyOnWriteArrayList<OnAttachStateChangeListener>(); 7198 } 7199 li.mOnAttachStateChangeListeners.add(listener); 7200 } 7201 7202 /** 7203 * Remove a listener for attach state changes. The listener will receive no further 7204 * notification of window attach/detach events. 7205 * 7206 * @param listener Listener to remove 7207 * @see #addOnAttachStateChangeListener(OnAttachStateChangeListener) 7208 */ 7209 public void removeOnAttachStateChangeListener(OnAttachStateChangeListener listener) { 7210 ListenerInfo li = mListenerInfo; 7211 if (li == null || li.mOnAttachStateChangeListeners == null) { 7212 return; 7213 } 7214 li.mOnAttachStateChangeListeners.remove(listener); 7215 } 7216 7217 /** 7218 * Returns the focus-change callback registered for this view. 7219 * 7220 * @return The callback, or null if one is not registered. 7221 */ 7222 public OnFocusChangeListener getOnFocusChangeListener() { 7223 ListenerInfo li = mListenerInfo; 7224 return li != null ? li.mOnFocusChangeListener : null; 7225 } 7226 7227 /** 7228 * Register a callback to be invoked when this view is clicked. If this view is not 7229 * clickable, it becomes clickable. 7230 * 7231 * @param l The callback that will run 7232 * 7233 * @see #setClickable(boolean) 7234 */ 7235 public void setOnClickListener(@Nullable OnClickListener l) { 7236 if (!isClickable()) { 7237 setClickable(true); 7238 } 7239 getListenerInfo().mOnClickListener = l; 7240 } 7241 7242 /** 7243 * Return whether this view has an attached OnClickListener. Returns 7244 * true if there is a listener, false if there is none. 7245 */ 7246 public boolean hasOnClickListeners() { 7247 ListenerInfo li = mListenerInfo; 7248 return (li != null && li.mOnClickListener != null); 7249 } 7250 7251 /** 7252 * Register a callback to be invoked when this view is clicked and held. If this view is not 7253 * long clickable, it becomes long clickable. 7254 * 7255 * @param l The callback that will run 7256 * 7257 * @see #setLongClickable(boolean) 7258 */ 7259 public void setOnLongClickListener(@Nullable OnLongClickListener l) { 7260 if (!isLongClickable()) { 7261 setLongClickable(true); 7262 } 7263 getListenerInfo().mOnLongClickListener = l; 7264 } 7265 7266 /** 7267 * Return whether this view has an attached OnLongClickListener. Returns 7268 * true if there is a listener, false if there is none. 7269 */ 7270 public boolean hasOnLongClickListeners() { 7271 ListenerInfo li = mListenerInfo; 7272 return (li != null && li.mOnLongClickListener != null); 7273 } 7274 7275 /** 7276 * @return the registered {@link OnLongClickListener} if there is one, {@code null} otherwise. 7277 * @hide 7278 */ 7279 @Nullable 7280 public OnLongClickListener getOnLongClickListener() { 7281 ListenerInfo li = mListenerInfo; 7282 return (li != null) ? li.mOnLongClickListener : null; 7283 } 7284 7285 /** 7286 * Register a callback to be invoked when this view is context clicked. If the view is not 7287 * context clickable, it becomes context clickable. 7288 * 7289 * @param l The callback that will run 7290 * @see #setContextClickable(boolean) 7291 */ 7292 public void setOnContextClickListener(@Nullable OnContextClickListener l) { 7293 if (!isContextClickable()) { 7294 setContextClickable(true); 7295 } 7296 getListenerInfo().mOnContextClickListener = l; 7297 } 7298 7299 /** 7300 * Register a callback to be invoked when the context menu for this view is 7301 * being built. If this view is not long clickable, it becomes long clickable. 7302 * 7303 * @param l The callback that will run 7304 * 7305 */ 7306 public void setOnCreateContextMenuListener(OnCreateContextMenuListener l) { 7307 if (!isLongClickable()) { 7308 setLongClickable(true); 7309 } 7310 getListenerInfo().mOnCreateContextMenuListener = l; 7311 } 7312 7313 /** 7314 * Set an observer to collect stats for each frame rendered for this view. 7315 * 7316 * @hide 7317 */ 7318 public void addFrameMetricsListener(Window window, 7319 Window.OnFrameMetricsAvailableListener listener, 7320 Handler handler) { 7321 if (mAttachInfo != null) { 7322 if (mAttachInfo.mThreadedRenderer != null) { 7323 if (mFrameMetricsObservers == null) { 7324 mFrameMetricsObservers = new ArrayList<>(); 7325 } 7326 7327 FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); 7328 mFrameMetricsObservers.add(fmo); 7329 mAttachInfo.mThreadedRenderer.addObserver(fmo.getRendererObserver()); 7330 } else { 7331 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7332 } 7333 } else { 7334 if (mFrameMetricsObservers == null) { 7335 mFrameMetricsObservers = new ArrayList<>(); 7336 } 7337 7338 FrameMetricsObserver fmo = new FrameMetricsObserver(window, handler, listener); 7339 mFrameMetricsObservers.add(fmo); 7340 } 7341 } 7342 7343 /** 7344 * Remove observer configured to collect frame stats for this view. 7345 * 7346 * @hide 7347 */ 7348 public void removeFrameMetricsListener( 7349 Window.OnFrameMetricsAvailableListener listener) { 7350 ThreadedRenderer renderer = getThreadedRenderer(); 7351 FrameMetricsObserver fmo = findFrameMetricsObserver(listener); 7352 if (fmo == null) { 7353 throw new IllegalArgumentException( 7354 "attempt to remove OnFrameMetricsAvailableListener that was never added"); 7355 } 7356 7357 if (mFrameMetricsObservers != null) { 7358 mFrameMetricsObservers.remove(fmo); 7359 if (renderer != null) { 7360 renderer.removeObserver(fmo.getRendererObserver()); 7361 } 7362 } 7363 } 7364 7365 private void registerPendingFrameMetricsObservers() { 7366 if (mFrameMetricsObservers != null) { 7367 ThreadedRenderer renderer = getThreadedRenderer(); 7368 if (renderer != null) { 7369 for (FrameMetricsObserver fmo : mFrameMetricsObservers) { 7370 renderer.addObserver(fmo.getRendererObserver()); 7371 } 7372 } else { 7373 Log.w(VIEW_LOG_TAG, "View not hardware-accelerated. Unable to observe frame stats"); 7374 } 7375 } 7376 } 7377 7378 private FrameMetricsObserver findFrameMetricsObserver( 7379 Window.OnFrameMetricsAvailableListener listener) { 7380 if (mFrameMetricsObservers != null) { 7381 for (int i = 0; i < mFrameMetricsObservers.size(); i++) { 7382 FrameMetricsObserver observer = mFrameMetricsObservers.get(i); 7383 if (observer.mListener == listener) { 7384 return observer; 7385 } 7386 } 7387 } 7388 7389 return null; 7390 } 7391 7392 /** @hide */ 7393 public void setNotifyAutofillManagerOnClick(boolean notify) { 7394 if (notify) { 7395 mPrivateFlags |= PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7396 } else { 7397 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7398 } 7399 } 7400 7401 private void notifyAutofillManagerOnClick() { 7402 if ((mPrivateFlags & PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK) != 0) { 7403 try { 7404 getAutofillManager().notifyViewClicked(this); 7405 } finally { 7406 // Set it to already called so it's not called twice when called by 7407 // performClickInternal() 7408 mPrivateFlags &= ~PFLAG_NOTIFY_AUTOFILL_MANAGER_ON_CLICK; 7409 } 7410 } 7411 } 7412 7413 /** 7414 * Entry point for {@link #performClick()} - other methods on View should call it instead of 7415 * {@code performClick()} directly to make sure the autofill manager is notified when 7416 * necessary (as subclasses could extend {@code performClick()} without calling the parent's 7417 * method). 7418 */ 7419 private boolean performClickInternal() { 7420 // Must notify autofill manager before performing the click actions to avoid scenarios where 7421 // the app has a click listener that changes the state of views the autofill service might 7422 // be interested on. 7423 notifyAutofillManagerOnClick(); 7424 7425 return performClick(); 7426 } 7427 7428 /** 7429 * Call this view's OnClickListener, if it is defined. Performs all normal 7430 * actions associated with clicking: reporting accessibility event, playing 7431 * a sound, etc. 7432 * 7433 * @return True there was an assigned OnClickListener that was called, false 7434 * otherwise is returned. 7435 */ 7436 // NOTE: other methods on View should not call this method directly, but performClickInternal() 7437 // instead, to guarantee that the autofill manager is notified when necessary (as subclasses 7438 // could extend this method without calling super.performClick()). 7439 public boolean performClick() { 7440 // We still need to call this method to handle the cases where performClick() was called 7441 // externally, instead of through performClickInternal() 7442 notifyAutofillManagerOnClick(); 7443 7444 final boolean result; 7445 final ListenerInfo li = mListenerInfo; 7446 if (li != null && li.mOnClickListener != null) { 7447 playSoundEffect(SoundEffectConstants.CLICK); 7448 li.mOnClickListener.onClick(this); 7449 result = true; 7450 } else { 7451 result = false; 7452 } 7453 7454 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); 7455 7456 notifyEnterOrExitForAutoFillIfNeeded(true); 7457 7458 return result; 7459 } 7460 7461 /** 7462 * Directly call any attached OnClickListener. Unlike {@link #performClick()}, 7463 * this only calls the listener, and does not do any associated clicking 7464 * actions like reporting an accessibility event. 7465 * 7466 * @return True there was an assigned OnClickListener that was called, false 7467 * otherwise is returned. 7468 */ 7469 public boolean callOnClick() { 7470 ListenerInfo li = mListenerInfo; 7471 if (li != null && li.mOnClickListener != null) { 7472 li.mOnClickListener.onClick(this); 7473 return true; 7474 } 7475 return false; 7476 } 7477 7478 /** 7479 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7480 * context menu if the OnLongClickListener did not consume the event. 7481 * 7482 * @return {@code true} if one of the above receivers consumed the event, 7483 * {@code false} otherwise 7484 */ 7485 public boolean performLongClick() { 7486 return performLongClickInternal(mLongClickX, mLongClickY); 7487 } 7488 7489 /** 7490 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7491 * context menu if the OnLongClickListener did not consume the event, 7492 * anchoring it to an (x,y) coordinate. 7493 * 7494 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 7495 * to disable anchoring 7496 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 7497 * to disable anchoring 7498 * @return {@code true} if one of the above receivers consumed the event, 7499 * {@code false} otherwise 7500 */ 7501 public boolean performLongClick(float x, float y) { 7502 mLongClickX = x; 7503 mLongClickY = y; 7504 final boolean handled = performLongClick(); 7505 mLongClickX = Float.NaN; 7506 mLongClickY = Float.NaN; 7507 return handled; 7508 } 7509 7510 /** 7511 * Calls this view's OnLongClickListener, if it is defined. Invokes the 7512 * context menu if the OnLongClickListener did not consume the event, 7513 * optionally anchoring it to an (x,y) coordinate. 7514 * 7515 * @param x x coordinate of the anchoring touch event, or {@link Float#NaN} 7516 * to disable anchoring 7517 * @param y y coordinate of the anchoring touch event, or {@link Float#NaN} 7518 * to disable anchoring 7519 * @return {@code true} if one of the above receivers consumed the event, 7520 * {@code false} otherwise 7521 */ 7522 private boolean performLongClickInternal(float x, float y) { 7523 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED); 7524 7525 boolean handled = false; 7526 final ListenerInfo li = mListenerInfo; 7527 if (li != null && li.mOnLongClickListener != null) { 7528 handled = li.mOnLongClickListener.onLongClick(View.this); 7529 } 7530 if (!handled) { 7531 final boolean isAnchored = !Float.isNaN(x) && !Float.isNaN(y); 7532 handled = isAnchored ? showContextMenu(x, y) : showContextMenu(); 7533 } 7534 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 7535 if (!handled) { 7536 handled = showLongClickTooltip((int) x, (int) y); 7537 } 7538 } 7539 if (handled) { 7540 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); 7541 } 7542 return handled; 7543 } 7544 7545 /** 7546 * Call this view's OnContextClickListener, if it is defined. 7547 * 7548 * @param x the x coordinate of the context click 7549 * @param y the y coordinate of the context click 7550 * @return True if there was an assigned OnContextClickListener that consumed the event, false 7551 * otherwise. 7552 */ 7553 public boolean performContextClick(float x, float y) { 7554 return performContextClick(); 7555 } 7556 7557 /** 7558 * Call this view's OnContextClickListener, if it is defined. 7559 * 7560 * @return True if there was an assigned OnContextClickListener that consumed the event, false 7561 * otherwise. 7562 */ 7563 public boolean performContextClick() { 7564 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CONTEXT_CLICKED); 7565 7566 boolean handled = false; 7567 ListenerInfo li = mListenerInfo; 7568 if (li != null && li.mOnContextClickListener != null) { 7569 handled = li.mOnContextClickListener.onContextClick(View.this); 7570 } 7571 if (handled) { 7572 performHapticFeedback(HapticFeedbackConstants.CONTEXT_CLICK); 7573 } 7574 return handled; 7575 } 7576 7577 /** 7578 * Performs button-related actions during a touch down event. 7579 * 7580 * @param event The event. 7581 * @return True if the down was consumed. 7582 * 7583 * @hide 7584 */ 7585 protected boolean performButtonActionOnTouchDown(MotionEvent event) { 7586 if (event.isFromSource(InputDevice.SOURCE_MOUSE) && 7587 (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) { 7588 showContextMenu(event.getX(), event.getY()); 7589 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 7590 return true; 7591 } 7592 return false; 7593 } 7594 7595 /** 7596 * Shows the context menu for this view. 7597 * 7598 * @return {@code true} if the context menu was shown, {@code false} 7599 * otherwise 7600 * @see #showContextMenu(float, float) 7601 */ 7602 public boolean showContextMenu() { 7603 return getParent().showContextMenuForChild(this); 7604 } 7605 7606 /** 7607 * Shows the context menu for this view anchored to the specified 7608 * view-relative coordinate. 7609 * 7610 * @param x the X coordinate in pixels relative to the view to which the 7611 * menu should be anchored, or {@link Float#NaN} to disable anchoring 7612 * @param y the Y coordinate in pixels relative to the view to which the 7613 * menu should be anchored, or {@link Float#NaN} to disable anchoring 7614 * @return {@code true} if the context menu was shown, {@code false} 7615 * otherwise 7616 */ 7617 public boolean showContextMenu(float x, float y) { 7618 return getParent().showContextMenuForChild(this, x, y); 7619 } 7620 7621 /** 7622 * Start an action mode with the default type {@link ActionMode#TYPE_PRIMARY}. 7623 * 7624 * @param callback Callback that will control the lifecycle of the action mode 7625 * @return The new action mode if it is started, null otherwise 7626 * 7627 * @see ActionMode 7628 * @see #startActionMode(android.view.ActionMode.Callback, int) 7629 */ 7630 public ActionMode startActionMode(ActionMode.Callback callback) { 7631 return startActionMode(callback, ActionMode.TYPE_PRIMARY); 7632 } 7633 7634 /** 7635 * Start an action mode with the given type. 7636 * 7637 * @param callback Callback that will control the lifecycle of the action mode 7638 * @param type One of {@link ActionMode#TYPE_PRIMARY} or {@link ActionMode#TYPE_FLOATING}. 7639 * @return The new action mode if it is started, null otherwise 7640 * 7641 * @see ActionMode 7642 */ 7643 public ActionMode startActionMode(ActionMode.Callback callback, int type) { 7644 ViewParent parent = getParent(); 7645 if (parent == null) return null; 7646 try { 7647 return parent.startActionModeForChild(this, callback, type); 7648 } catch (AbstractMethodError ame) { 7649 // Older implementations of custom views might not implement this. 7650 return parent.startActionModeForChild(this, callback); 7651 } 7652 } 7653 7654 /** 7655 * Call {@link Context#startActivityForResult(String, Intent, int, Bundle)} for the View's 7656 * Context, creating a unique View identifier to retrieve the result. 7657 * 7658 * @param intent The Intent to be started. 7659 * @param requestCode The request code to use. 7660 * @hide 7661 */ 7662 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 7663 public void startActivityForResult(Intent intent, int requestCode) { 7664 mStartActivityRequestWho = "@android:view:" + System.identityHashCode(this); 7665 getContext().startActivityForResult(mStartActivityRequestWho, intent, requestCode, null); 7666 } 7667 7668 /** 7669 * If this View corresponds to the calling who, dispatches the activity result. 7670 * @param who The identifier for the targeted View to receive the result. 7671 * @param requestCode The integer request code originally supplied to 7672 * startActivityForResult(), allowing you to identify who this 7673 * result came from. 7674 * @param resultCode The integer result code returned by the child activity 7675 * through its setResult(). 7676 * @param data An Intent, which can return result data to the caller 7677 * (various data can be attached to Intent "extras"). 7678 * @return {@code true} if the activity result was dispatched. 7679 * @hide 7680 */ 7681 public boolean dispatchActivityResult( 7682 String who, int requestCode, int resultCode, Intent data) { 7683 if (mStartActivityRequestWho != null && mStartActivityRequestWho.equals(who)) { 7684 onActivityResult(requestCode, resultCode, data); 7685 mStartActivityRequestWho = null; 7686 return true; 7687 } 7688 return false; 7689 } 7690 7691 /** 7692 * Receive the result from a previous call to {@link #startActivityForResult(Intent, int)}. 7693 * 7694 * @param requestCode The integer request code originally supplied to 7695 * startActivityForResult(), allowing you to identify who this 7696 * result came from. 7697 * @param resultCode The integer result code returned by the child activity 7698 * through its setResult(). 7699 * @param data An Intent, which can return result data to the caller 7700 * (various data can be attached to Intent "extras"). 7701 * @hide 7702 */ 7703 public void onActivityResult(int requestCode, int resultCode, Intent data) { 7704 // Do nothing. 7705 } 7706 7707 /** 7708 * Register a callback to be invoked when a hardware key is pressed in this view. 7709 * Key presses in software input methods will generally not trigger the methods of 7710 * this listener. 7711 * @param l the key listener to attach to this view 7712 */ 7713 public void setOnKeyListener(OnKeyListener l) { 7714 getListenerInfo().mOnKeyListener = l; 7715 } 7716 7717 /** 7718 * Register a callback to be invoked when a touch event is sent to this view. 7719 * @param l the touch listener to attach to this view 7720 */ 7721 public void setOnTouchListener(OnTouchListener l) { 7722 getListenerInfo().mOnTouchListener = l; 7723 } 7724 7725 /** 7726 * Register a callback to be invoked when a generic motion event is sent to this view. 7727 * @param l the generic motion listener to attach to this view 7728 */ 7729 public void setOnGenericMotionListener(OnGenericMotionListener l) { 7730 getListenerInfo().mOnGenericMotionListener = l; 7731 } 7732 7733 /** 7734 * Register a callback to be invoked when a hover event is sent to this view. 7735 * @param l the hover listener to attach to this view 7736 */ 7737 public void setOnHoverListener(OnHoverListener l) { 7738 getListenerInfo().mOnHoverListener = l; 7739 } 7740 7741 /** 7742 * Register a drag event listener callback object for this View. The parameter is 7743 * an implementation of {@link android.view.View.OnDragListener}. To send a drag event to a 7744 * View, the system calls the 7745 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent)} method. 7746 * @param l An implementation of {@link android.view.View.OnDragListener}. 7747 */ 7748 public void setOnDragListener(OnDragListener l) { 7749 getListenerInfo().mOnDragListener = l; 7750 } 7751 7752 /** 7753 * Give this view focus. This will cause 7754 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} to be called. 7755 * 7756 * Note: this does not check whether this {@link View} should get focus, it just 7757 * gives it focus no matter what. It should only be called internally by framework 7758 * code that knows what it is doing, namely {@link #requestFocus(int, Rect)}. 7759 * 7760 * @param direction values are {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN}, 7761 * {@link View#FOCUS_LEFT} or {@link View#FOCUS_RIGHT}. This is the direction which 7762 * focus moved when requestFocus() is called. It may not always 7763 * apply, in which case use the default View.FOCUS_DOWN. 7764 * @param previouslyFocusedRect The rectangle of the view that had focus 7765 * prior in this View's coordinate system. 7766 */ 7767 void handleFocusGainInternal(@FocusRealDirection int direction, Rect previouslyFocusedRect) { 7768 if (DBG) { 7769 System.out.println(this + " requestFocus()"); 7770 } 7771 7772 if ((mPrivateFlags & PFLAG_FOCUSED) == 0) { 7773 mPrivateFlags |= PFLAG_FOCUSED; 7774 7775 View oldFocus = (mAttachInfo != null) ? getRootView().findFocus() : null; 7776 7777 if (mParent != null) { 7778 mParent.requestChildFocus(this, this); 7779 updateFocusedInCluster(oldFocus, direction); 7780 } 7781 7782 if (mAttachInfo != null) { 7783 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, this); 7784 } 7785 7786 onFocusChanged(true, direction, previouslyFocusedRect); 7787 refreshDrawableState(); 7788 } 7789 } 7790 7791 /** 7792 * Sets this view's preference for reveal behavior when it gains focus. 7793 * 7794 * <p>When set to true, this is a signal to ancestor views in the hierarchy that 7795 * this view would prefer to be brought fully into view when it gains focus. 7796 * For example, a text field that a user is meant to type into. Other views such 7797 * as scrolling containers may prefer to opt-out of this behavior.</p> 7798 * 7799 * <p>The default value for views is true, though subclasses may change this 7800 * based on their preferred behavior.</p> 7801 * 7802 * @param revealOnFocus true to request reveal on focus in ancestors, false otherwise 7803 * 7804 * @see #getRevealOnFocusHint() 7805 */ 7806 public final void setRevealOnFocusHint(boolean revealOnFocus) { 7807 if (revealOnFocus) { 7808 mPrivateFlags3 &= ~PFLAG3_NO_REVEAL_ON_FOCUS; 7809 } else { 7810 mPrivateFlags3 |= PFLAG3_NO_REVEAL_ON_FOCUS; 7811 } 7812 } 7813 7814 /** 7815 * Returns this view's preference for reveal behavior when it gains focus. 7816 * 7817 * <p>When this method returns true for a child view requesting focus, ancestor 7818 * views responding to a focus change in {@link ViewParent#requestChildFocus(View, View)} 7819 * should make a best effort to make the newly focused child fully visible to the user. 7820 * When it returns false, ancestor views should preferably not disrupt scroll positioning or 7821 * other properties affecting visibility to the user as part of the focus change.</p> 7822 * 7823 * @return true if this view would prefer to become fully visible when it gains focus, 7824 * false if it would prefer not to disrupt scroll positioning 7825 * 7826 * @see #setRevealOnFocusHint(boolean) 7827 */ 7828 public final boolean getRevealOnFocusHint() { 7829 return (mPrivateFlags3 & PFLAG3_NO_REVEAL_ON_FOCUS) == 0; 7830 } 7831 7832 /** 7833 * Populates <code>outRect</code> with the hotspot bounds. By default, 7834 * the hotspot bounds are identical to the screen bounds. 7835 * 7836 * @param outRect rect to populate with hotspot bounds 7837 * @hide Only for internal use by views and widgets. 7838 */ 7839 public void getHotspotBounds(Rect outRect) { 7840 final Drawable background = getBackground(); 7841 if (background != null) { 7842 background.getHotspotBounds(outRect); 7843 } else { 7844 getBoundsOnScreen(outRect); 7845 } 7846 } 7847 7848 /** 7849 * Request that a rectangle of this view be visible on the screen, 7850 * scrolling if necessary just enough. 7851 * 7852 * <p>A View should call this if it maintains some notion of which part 7853 * of its content is interesting. For example, a text editing view 7854 * should call this when its cursor moves. 7855 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 7856 * It should not be affected by which part of the View is currently visible or its scroll 7857 * position. 7858 * 7859 * @param rectangle The rectangle in the View's content coordinate space 7860 * @return Whether any parent scrolled. 7861 */ 7862 public boolean requestRectangleOnScreen(Rect rectangle) { 7863 return requestRectangleOnScreen(rectangle, false); 7864 } 7865 7866 /** 7867 * Request that a rectangle of this view be visible on the screen, 7868 * scrolling if necessary just enough. 7869 * 7870 * <p>A View should call this if it maintains some notion of which part 7871 * of its content is interesting. For example, a text editing view 7872 * should call this when its cursor moves. 7873 * <p>The Rectangle passed into this method should be in the View's content coordinate space. 7874 * It should not be affected by which part of the View is currently visible or its scroll 7875 * position. 7876 * <p>When <code>immediate</code> is set to true, scrolling will not be 7877 * animated. 7878 * 7879 * @param rectangle The rectangle in the View's content coordinate space 7880 * @param immediate True to forbid animated scrolling, false otherwise 7881 * @return Whether any parent scrolled. 7882 */ 7883 public boolean requestRectangleOnScreen(Rect rectangle, boolean immediate) { 7884 if (mParent == null) { 7885 return false; 7886 } 7887 7888 View child = this; 7889 7890 RectF position = (mAttachInfo != null) ? mAttachInfo.mTmpTransformRect : new RectF(); 7891 position.set(rectangle); 7892 7893 ViewParent parent = mParent; 7894 boolean scrolled = false; 7895 while (parent != null) { 7896 rectangle.set((int) position.left, (int) position.top, 7897 (int) position.right, (int) position.bottom); 7898 7899 scrolled |= parent.requestChildRectangleOnScreen(child, rectangle, immediate); 7900 7901 if (!(parent instanceof View)) { 7902 break; 7903 } 7904 7905 // move it from child's content coordinate space to parent's content coordinate space 7906 position.offset(child.mLeft - child.getScrollX(), child.mTop -child.getScrollY()); 7907 7908 child = (View) parent; 7909 parent = child.getParent(); 7910 } 7911 7912 return scrolled; 7913 } 7914 7915 /** 7916 * Called when this view wants to give up focus. If focus is cleared 7917 * {@link #onFocusChanged(boolean, int, android.graphics.Rect)} is called. 7918 * <p> 7919 * <strong>Note:</strong> When not in touch-mode, the framework will try to give focus 7920 * to the first focusable View from the top after focus is cleared. Hence, if this 7921 * View is the first from the top that can take focus, then all callbacks 7922 * related to clearing focus will be invoked after which the framework will 7923 * give focus to this view. 7924 * </p> 7925 */ 7926 public void clearFocus() { 7927 if (DBG) { 7928 System.out.println(this + " clearFocus()"); 7929 } 7930 7931 final boolean refocus = sAlwaysAssignFocus || !isInTouchMode(); 7932 clearFocusInternal(null, true, refocus); 7933 } 7934 7935 /** 7936 * Clears focus from the view, optionally propagating the change up through 7937 * the parent hierarchy and requesting that the root view place new focus. 7938 * 7939 * @param propagate whether to propagate the change up through the parent 7940 * hierarchy 7941 * @param refocus when propagate is true, specifies whether to request the 7942 * root view place new focus 7943 */ 7944 void clearFocusInternal(View focused, boolean propagate, boolean refocus) { 7945 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 7946 mPrivateFlags &= ~PFLAG_FOCUSED; 7947 clearParentsWantFocus(); 7948 7949 if (propagate && mParent != null) { 7950 mParent.clearChildFocus(this); 7951 } 7952 7953 onFocusChanged(false, 0, null); 7954 refreshDrawableState(); 7955 7956 if (propagate && (!refocus || !rootViewRequestFocus())) { 7957 notifyGlobalFocusCleared(this); 7958 } 7959 } 7960 } 7961 7962 void notifyGlobalFocusCleared(View oldFocus) { 7963 if (oldFocus != null && mAttachInfo != null) { 7964 mAttachInfo.mTreeObserver.dispatchOnGlobalFocusChange(oldFocus, null); 7965 } 7966 } 7967 7968 boolean rootViewRequestFocus() { 7969 final View root = getRootView(); 7970 return root != null && root.requestFocus(); 7971 } 7972 7973 /** 7974 * Called internally by the view system when a new view is getting focus. 7975 * This is what clears the old focus. 7976 * <p> 7977 * <b>NOTE:</b> The parent view's focused child must be updated manually 7978 * after calling this method. Otherwise, the view hierarchy may be left in 7979 * an inconstent state. 7980 */ 7981 void unFocus(View focused) { 7982 if (DBG) { 7983 System.out.println(this + " unFocus()"); 7984 } 7985 7986 clearFocusInternal(focused, false, false); 7987 } 7988 7989 /** 7990 * Returns true if this view has focus itself, or is the ancestor of the 7991 * view that has focus. 7992 * 7993 * @return True if this view has or contains focus, false otherwise. 7994 */ 7995 @ViewDebug.ExportedProperty(category = "focus") 7996 public boolean hasFocus() { 7997 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 7998 } 7999 8000 /** 8001 * Returns true if this view is focusable or if it contains a reachable View 8002 * for which {@link #hasFocusable()} returns {@code true}. A "reachable hasFocusable()" 8003 * is a view whose parents do not block descendants focus. 8004 * Only {@link #VISIBLE} views are considered focusable. 8005 * 8006 * <p>As of {@link Build.VERSION_CODES#O} views that are determined to be focusable 8007 * through {@link #FOCUSABLE_AUTO} will also cause this method to return {@code true}. 8008 * Apps that declare a {@link android.content.pm.ApplicationInfo#targetSdkVersion} of 8009 * earlier than {@link Build.VERSION_CODES#O} will continue to see this method return 8010 * {@code false} for views not explicitly marked as focusable. 8011 * Use {@link #hasExplicitFocusable()} if you require the pre-{@link Build.VERSION_CODES#O} 8012 * behavior.</p> 8013 * 8014 * @return {@code true} if the view is focusable or if the view contains a focusable 8015 * view, {@code false} otherwise 8016 * 8017 * @see ViewGroup#FOCUS_BLOCK_DESCENDANTS 8018 * @see ViewGroup#getTouchscreenBlocksFocus() 8019 * @see #hasExplicitFocusable() 8020 */ 8021 public boolean hasFocusable() { 8022 return hasFocusable(!sHasFocusableExcludeAutoFocusable, false); 8023 } 8024 8025 /** 8026 * Returns true if this view is focusable or if it contains a reachable View 8027 * for which {@link #hasExplicitFocusable()} returns {@code true}. 8028 * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus. 8029 * Only {@link #VISIBLE} views for which {@link #getFocusable()} would return 8030 * {@link #FOCUSABLE} are considered focusable. 8031 * 8032 * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of 8033 * {@link #hasFocusable()} in that only views explicitly set focusable will cause 8034 * this method to return true. A view set to {@link #FOCUSABLE_AUTO} that resolves 8035 * to focusable will not.</p> 8036 * 8037 * @return {@code true} if the view is focusable or if the view contains a focusable 8038 * view, {@code false} otherwise 8039 * 8040 * @see #hasFocusable() 8041 */ 8042 public boolean hasExplicitFocusable() { 8043 return hasFocusable(false, true); 8044 } 8045 8046 boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) { 8047 if (!isFocusableInTouchMode()) { 8048 for (ViewParent p = mParent; p instanceof ViewGroup; p = p.getParent()) { 8049 final ViewGroup g = (ViewGroup) p; 8050 if (g.shouldBlockFocusForTouchscreen()) { 8051 return false; 8052 } 8053 } 8054 } 8055 8056 // Invisible, gone, or disabled views are never focusable. 8057 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE 8058 || (mViewFlags & ENABLED_MASK) != ENABLED) { 8059 return false; 8060 } 8061 8062 // Only use effective focusable value when allowed. 8063 if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) { 8064 return true; 8065 } 8066 8067 return false; 8068 } 8069 8070 /** 8071 * Called by the view system when the focus state of this view changes. 8072 * When the focus change event is caused by directional navigation, direction 8073 * and previouslyFocusedRect provide insight into where the focus is coming from. 8074 * When overriding, be sure to call up through to the super class so that 8075 * the standard focus handling will occur. 8076 * 8077 * @param gainFocus True if the View has focus; false otherwise. 8078 * @param direction The direction focus has moved when requestFocus() 8079 * is called to give this view focus. Values are 8080 * {@link #FOCUS_UP}, {@link #FOCUS_DOWN}, {@link #FOCUS_LEFT}, 8081 * {@link #FOCUS_RIGHT}, {@link #FOCUS_FORWARD}, or {@link #FOCUS_BACKWARD}. 8082 * It may not always apply, in which case use the default. 8083 * @param previouslyFocusedRect The rectangle, in this view's coordinate 8084 * system, of the previously focused view. If applicable, this will be 8085 * passed in as finer grained information about where the focus is coming 8086 * from (in addition to direction). Will be <code>null</code> otherwise. 8087 */ 8088 @CallSuper 8089 protected void onFocusChanged(boolean gainFocus, @FocusDirection int direction, 8090 @Nullable Rect previouslyFocusedRect) { 8091 if (gainFocus) { 8092 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 8093 } else { 8094 notifyViewAccessibilityStateChangedIfNeeded( 8095 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 8096 } 8097 8098 // Here we check whether we still need the default focus highlight, and switch it on/off. 8099 switchDefaultFocusHighlight(); 8100 8101 if (!gainFocus) { 8102 if (isPressed()) { 8103 setPressed(false); 8104 } 8105 if (hasWindowFocus()) { 8106 notifyFocusChangeToImeFocusController(false /* hasFocus */); 8107 } 8108 onFocusLost(); 8109 } else if (hasWindowFocus()) { 8110 notifyFocusChangeToImeFocusController(true /* hasFocus */); 8111 } 8112 8113 invalidate(true); 8114 ListenerInfo li = mListenerInfo; 8115 if (li != null && li.mOnFocusChangeListener != null) { 8116 li.mOnFocusChangeListener.onFocusChange(this, gainFocus); 8117 } 8118 8119 if (mAttachInfo != null) { 8120 mAttachInfo.mKeyDispatchState.reset(this); 8121 } 8122 8123 if (mParent != null) { 8124 mParent.onDescendantUnbufferedRequested(); 8125 } 8126 8127 notifyEnterOrExitForAutoFillIfNeeded(gainFocus); 8128 } 8129 8130 /** 8131 * Notify {@link ImeFocusController} about the focus change of the {@link View}. 8132 * 8133 * @param hasFocus {@code true} when the {@link View} is being focused. 8134 */ 8135 private void notifyFocusChangeToImeFocusController(boolean hasFocus) { 8136 if (mAttachInfo == null) { 8137 return; 8138 } 8139 mAttachInfo.mViewRootImpl.getImeFocusController().onViewFocusChanged(this, hasFocus); 8140 } 8141 8142 /** @hide */ 8143 public void notifyEnterOrExitForAutoFillIfNeeded(boolean enter) { 8144 if (canNotifyAutofillEnterExitEvent()) { 8145 AutofillManager afm = getAutofillManager(); 8146 if (afm != null) { 8147 if (enter && isFocused()) { 8148 // We have not been laid out yet, hence cannot evaluate 8149 // whether this view is visible to the user, we will do 8150 // the evaluation once layout is complete. 8151 if (!isLaidOut()) { 8152 mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 8153 } else if (isVisibleToUser()) { 8154 // TODO This is a potential problem that View gets focus before it's visible 8155 // to User. Ideally View should handle the event when isVisibleToUser() 8156 // becomes true where it should issue notifyViewEntered(). 8157 afm.notifyViewEntered(this); 8158 } 8159 } else if (!enter && !isFocused()) { 8160 afm.notifyViewExited(this); 8161 } 8162 } 8163 } 8164 } 8165 8166 /** 8167 * Visually distinct portion of a window with window-like semantics are considered panes for 8168 * accessibility purposes. One example is the content view of a fragment that is replaced. 8169 * In order for accessibility services to understand a pane's window-like behavior, panes 8170 * should have descriptive titles. Views with pane titles produce {@link AccessibilityEvent}s 8171 * when they appear, disappear, or change title. 8172 * 8173 * @param accessibilityPaneTitle The pane's title. Setting to {@code null} indicates that this 8174 * View is not a pane. 8175 * 8176 * {@see AccessibilityNodeInfo#setPaneTitle(CharSequence)} 8177 * 8178 * @attr ref android.R.styleable#View_accessibilityPaneTitle 8179 */ 8180 public void setAccessibilityPaneTitle(@Nullable CharSequence accessibilityPaneTitle) { 8181 if (!TextUtils.equals(accessibilityPaneTitle, mAccessibilityPaneTitle)) { 8182 mAccessibilityPaneTitle = accessibilityPaneTitle; 8183 notifyViewAccessibilityStateChangedIfNeeded( 8184 AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_TITLE); 8185 } 8186 } 8187 8188 /** 8189 * Get the title of the pane for purposes of accessibility. 8190 * 8191 * @return The current pane title. 8192 * 8193 * {@see #setAccessibilityPaneTitle}. 8194 * 8195 * @attr ref android.R.styleable#View_accessibilityPaneTitle 8196 */ 8197 @InspectableProperty 8198 @Nullable 8199 public CharSequence getAccessibilityPaneTitle() { 8200 return mAccessibilityPaneTitle; 8201 } 8202 8203 private boolean isAccessibilityPane() { 8204 return mAccessibilityPaneTitle != null; 8205 } 8206 8207 /** 8208 * Sends an accessibility event of the given type. If accessibility is 8209 * not enabled this method has no effect. The default implementation calls 8210 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)} first 8211 * to populate information about the event source (this View), then calls 8212 * {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} to 8213 * populate the text content of the event source including its descendants, 8214 * and last calls 8215 * {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)} 8216 * on its parent to request sending of the event to interested parties. 8217 * <p> 8218 * If an {@link AccessibilityDelegate} has been specified via calling 8219 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8220 * {@link AccessibilityDelegate#sendAccessibilityEvent(View, int)} is 8221 * responsible for handling this call. 8222 * </p> 8223 * 8224 * @param eventType The type of the event to send, as defined by several types from 8225 * {@link android.view.accessibility.AccessibilityEvent}, such as 8226 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} or 8227 * {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}. 8228 * 8229 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 8230 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8231 * @see ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent) 8232 * @see AccessibilityDelegate 8233 */ 8234 public void sendAccessibilityEvent(int eventType) { 8235 if (mAccessibilityDelegate != null) { 8236 mAccessibilityDelegate.sendAccessibilityEvent(this, eventType); 8237 } else { 8238 sendAccessibilityEventInternal(eventType); 8239 } 8240 } 8241 8242 /** 8243 * Convenience method for sending a {@link AccessibilityEvent#TYPE_ANNOUNCEMENT} 8244 * {@link AccessibilityEvent} to suggest that an accessibility service announce the 8245 * specified text to its users. 8246 * <p> 8247 * Note: The event generated with this API carries no semantic meaning, and is appropriate only 8248 * in exceptional situations. Apps can generally achieve correct behavior for accessibility by 8249 * accurately supplying the semantics of their UI. 8250 * They should not need to specify what exactly is announced to users. 8251 * 8252 * @param text The announcement text. 8253 */ 8254 public void announceForAccessibility(CharSequence text) { 8255 if (AccessibilityManager.getInstance(mContext).isEnabled() && mParent != null) { 8256 AccessibilityEvent event = AccessibilityEvent.obtain( 8257 AccessibilityEvent.TYPE_ANNOUNCEMENT); 8258 onInitializeAccessibilityEvent(event); 8259 event.getText().add(text); 8260 event.setContentDescription(null); 8261 mParent.requestSendAccessibilityEvent(this, event); 8262 } 8263 } 8264 8265 /** 8266 * @see #sendAccessibilityEvent(int) 8267 * 8268 * Note: Called from the default {@link AccessibilityDelegate}. 8269 * 8270 * @hide 8271 */ 8272 public void sendAccessibilityEventInternal(int eventType) { 8273 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 8274 sendAccessibilityEventUnchecked(AccessibilityEvent.obtain(eventType)); 8275 } 8276 } 8277 8278 /** 8279 * This method behaves exactly as {@link #sendAccessibilityEvent(int)} but 8280 * takes as an argument an empty {@link AccessibilityEvent} and does not 8281 * perform a check whether accessibility is enabled. 8282 * <p> 8283 * If an {@link AccessibilityDelegate} has been specified via calling 8284 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8285 * {@link AccessibilityDelegate#sendAccessibilityEventUnchecked(View, AccessibilityEvent)} 8286 * is responsible for handling this call. 8287 * </p> 8288 * 8289 * @param event The event to send. 8290 * 8291 * @see #sendAccessibilityEvent(int) 8292 */ 8293 public void sendAccessibilityEventUnchecked(AccessibilityEvent event) { 8294 if (mAccessibilityDelegate != null) { 8295 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 8296 } else { 8297 sendAccessibilityEventUncheckedInternal(event); 8298 } 8299 } 8300 8301 /** 8302 * @see #sendAccessibilityEventUnchecked(AccessibilityEvent) 8303 * 8304 * Note: Called from the default {@link AccessibilityDelegate}. 8305 * 8306 * @hide 8307 */ 8308 public void sendAccessibilityEventUncheckedInternal(AccessibilityEvent event) { 8309 // Panes disappearing are relevant even if though the view is no longer visible. 8310 boolean isWindowStateChanged = 8311 (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 8312 boolean isWindowDisappearedEvent = isWindowStateChanged && ((event.getContentChangeTypes() 8313 & AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED) != 0); 8314 if (!isShown() && !isWindowDisappearedEvent) { 8315 return; 8316 } 8317 onInitializeAccessibilityEvent(event); 8318 // Only a subset of accessibility events populates text content. 8319 if ((event.getEventType() & POPULATING_ACCESSIBILITY_EVENT_TYPES) != 0) { 8320 dispatchPopulateAccessibilityEvent(event); 8321 } 8322 SendAccessibilityEventThrottle throttle = getThrottleForAccessibilityEvent(event); 8323 if (throttle != null) { 8324 throttle.post(event); 8325 } else { 8326 requestParentSendAccessibilityEvent(event); 8327 } 8328 } 8329 8330 private void requestParentSendAccessibilityEvent(AccessibilityEvent event) { 8331 ViewParent parent = getParent(); 8332 if (parent != null) { 8333 getParent().requestSendAccessibilityEvent(this, event); 8334 } 8335 } 8336 8337 private SendAccessibilityEventThrottle getThrottleForAccessibilityEvent( 8338 AccessibilityEvent event) { 8339 if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { 8340 if (mSendViewScrolledAccessibilityEvent == null) { 8341 mSendViewScrolledAccessibilityEvent = new SendViewScrolledAccessibilityEvent(); 8342 } 8343 return mSendViewScrolledAccessibilityEvent; 8344 } 8345 boolean isStateContentChanged = (event.getContentChangeTypes() 8346 & AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION) != 0; 8347 if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 8348 && isStateContentChanged) { 8349 if (mSendStateChangedAccessibilityEvent == null) { 8350 mSendStateChangedAccessibilityEvent = new SendAccessibilityEventThrottle(); 8351 } 8352 return mSendStateChangedAccessibilityEvent; 8353 } 8354 return null; 8355 } 8356 8357 private void clearAccessibilityThrottles() { 8358 cancel(mSendViewScrolledAccessibilityEvent); 8359 cancel(mSendStateChangedAccessibilityEvent); 8360 } 8361 8362 /** 8363 * Dispatches an {@link AccessibilityEvent} to the {@link View} first and then 8364 * to its children for adding their text content to the event. Note that the 8365 * event text is populated in a separate dispatch path since we add to the 8366 * event not only the text of the source but also the text of all its descendants. 8367 * A typical implementation will call 8368 * {@link #onPopulateAccessibilityEvent(AccessibilityEvent)} on the this view 8369 * and then call the {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 8370 * on each child. Override this method if custom population of the event text 8371 * content is required. 8372 * <p> 8373 * If an {@link AccessibilityDelegate} has been specified via calling 8374 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8375 * {@link AccessibilityDelegate#dispatchPopulateAccessibilityEvent(View, AccessibilityEvent)} 8376 * is responsible for handling this call. 8377 * </p> 8378 * <p> 8379 * <em>Note:</em> Accessibility events of certain types are not dispatched for 8380 * populating the event text via this method. For details refer to {@link AccessibilityEvent}. 8381 * </p> 8382 * 8383 * @param event The event. 8384 * 8385 * @return True if the event population was completed. 8386 */ 8387 public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { 8388 if (mAccessibilityDelegate != null) { 8389 return mAccessibilityDelegate.dispatchPopulateAccessibilityEvent(this, event); 8390 } else { 8391 return dispatchPopulateAccessibilityEventInternal(event); 8392 } 8393 } 8394 8395 /** 8396 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8397 * 8398 * Note: Called from the default {@link AccessibilityDelegate}. 8399 * 8400 * @hide 8401 */ 8402 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) { 8403 onPopulateAccessibilityEvent(event); 8404 return false; 8405 } 8406 8407 /** 8408 * Called from {@link #dispatchPopulateAccessibilityEvent(AccessibilityEvent)} 8409 * giving a chance to this View to populate the accessibility event with its 8410 * text content. While this method is free to modify event 8411 * attributes other than text content, doing so should normally be performed in 8412 * {@link #onInitializeAccessibilityEvent(AccessibilityEvent)}. 8413 * <p> 8414 * Example: Adding formatted date string to an accessibility event in addition 8415 * to the text added by the super implementation: 8416 * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 8417 * super.onPopulateAccessibilityEvent(event); 8418 * final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY; 8419 * String selectedDateUtterance = DateUtils.formatDateTime(mContext, 8420 * mCurrentDate.getTimeInMillis(), flags); 8421 * event.getText().add(selectedDateUtterance); 8422 * }</pre> 8423 * <p> 8424 * If an {@link AccessibilityDelegate} has been specified via calling 8425 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8426 * {@link AccessibilityDelegate#onPopulateAccessibilityEvent(View, AccessibilityEvent)} 8427 * is responsible for handling this call. 8428 * </p> 8429 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 8430 * information to the event, in case the default implementation has basic information to add. 8431 * </p> 8432 * 8433 * @param event The accessibility event which to populate. 8434 * 8435 * @see #sendAccessibilityEvent(int) 8436 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8437 */ 8438 @CallSuper 8439 public void onPopulateAccessibilityEvent(AccessibilityEvent event) { 8440 if (mAccessibilityDelegate != null) { 8441 mAccessibilityDelegate.onPopulateAccessibilityEvent(this, event); 8442 } else { 8443 onPopulateAccessibilityEventInternal(event); 8444 } 8445 } 8446 8447 /** 8448 * @see #onPopulateAccessibilityEvent(AccessibilityEvent) 8449 * 8450 * Note: Called from the default {@link AccessibilityDelegate}. 8451 * 8452 * @hide 8453 */ 8454 public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) { 8455 if ((event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) 8456 && isAccessibilityPane()) { 8457 event.getText().add(getAccessibilityPaneTitle()); 8458 } 8459 } 8460 8461 /** 8462 * Initializes an {@link AccessibilityEvent} with information about 8463 * this View which is the event source. In other words, the source of 8464 * an accessibility event is the view whose state change triggered firing 8465 * the event. 8466 * <p> 8467 * Example: Setting the password property of an event in addition 8468 * to properties set by the super implementation: 8469 * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 8470 * super.onInitializeAccessibilityEvent(event); 8471 * event.setPassword(true); 8472 * }</pre> 8473 * <p> 8474 * If an {@link AccessibilityDelegate} has been specified via calling 8475 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8476 * {@link AccessibilityDelegate#onInitializeAccessibilityEvent(View, AccessibilityEvent)} 8477 * is responsible for handling this call. 8478 * </p> 8479 * <p class="note"><strong>Note:</strong> Always call the super implementation before adding 8480 * information to the event, in case the default implementation has basic information to add. 8481 * </p> 8482 * @param event The event to initialize. 8483 * 8484 * @see #sendAccessibilityEvent(int) 8485 * @see #dispatchPopulateAccessibilityEvent(AccessibilityEvent) 8486 */ 8487 @CallSuper 8488 public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 8489 if (mAccessibilityDelegate != null) { 8490 mAccessibilityDelegate.onInitializeAccessibilityEvent(this, event); 8491 } else { 8492 onInitializeAccessibilityEventInternal(event); 8493 } 8494 } 8495 8496 /** 8497 * @see #onInitializeAccessibilityEvent(AccessibilityEvent) 8498 * 8499 * Note: Called from the default {@link AccessibilityDelegate}. 8500 * 8501 * @hide 8502 */ 8503 @UnsupportedAppUsage 8504 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) { 8505 event.setSource(this); 8506 event.setClassName(getAccessibilityClassName()); 8507 event.setPackageName(getContext().getPackageName()); 8508 event.setEnabled(isEnabled()); 8509 event.setContentDescription(mContentDescription); 8510 event.setScrollX(getScrollX()); 8511 event.setScrollY(getScrollY()); 8512 8513 switch (event.getEventType()) { 8514 case AccessibilityEvent.TYPE_VIEW_FOCUSED: { 8515 ArrayList<View> focusablesTempList = (mAttachInfo != null) 8516 ? mAttachInfo.mTempArrayList : new ArrayList<View>(); 8517 getRootView().addFocusables(focusablesTempList, View.FOCUS_FORWARD, FOCUSABLES_ALL); 8518 event.setItemCount(focusablesTempList.size()); 8519 event.setCurrentItemIndex(focusablesTempList.indexOf(this)); 8520 if (mAttachInfo != null) { 8521 focusablesTempList.clear(); 8522 } 8523 } break; 8524 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: { 8525 CharSequence text = getIterableTextForAccessibility(); 8526 if (text != null && text.length() > 0) { 8527 event.setFromIndex(getAccessibilitySelectionStart()); 8528 event.setToIndex(getAccessibilitySelectionEnd()); 8529 event.setItemCount(text.length()); 8530 } 8531 } break; 8532 } 8533 } 8534 8535 /** 8536 * Returns an {@link AccessibilityNodeInfo} representing this view from the 8537 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 8538 * This method is responsible for obtaining an accessibility node info from a 8539 * pool of reusable instances and calling 8540 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on this view to 8541 * initialize the former. 8542 * <p> 8543 * Note: The client is responsible for recycling the obtained instance by calling 8544 * {@link AccessibilityNodeInfo#recycle()} to minimize object creation. 8545 * </p> 8546 * 8547 * @return A populated {@link AccessibilityNodeInfo}. 8548 * 8549 * @see AccessibilityNodeInfo 8550 */ 8551 public AccessibilityNodeInfo createAccessibilityNodeInfo() { 8552 if (mAccessibilityDelegate != null) { 8553 return mAccessibilityDelegate.createAccessibilityNodeInfo(this); 8554 } else { 8555 return createAccessibilityNodeInfoInternal(); 8556 } 8557 } 8558 8559 /** 8560 * @see #createAccessibilityNodeInfo() 8561 * 8562 * @hide 8563 */ 8564 public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { 8565 AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8566 if (provider != null) { 8567 return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID); 8568 } else { 8569 AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this); 8570 onInitializeAccessibilityNodeInfo(info); 8571 return info; 8572 } 8573 } 8574 8575 /** 8576 * Initializes an {@link AccessibilityNodeInfo} with information about this view. 8577 * The base implementation sets: 8578 * <ul> 8579 * <li>{@link AccessibilityNodeInfo#setParent(View)},</li> 8580 * <li>{@link AccessibilityNodeInfo#setBoundsInParent(Rect)},</li> 8581 * <li>{@link AccessibilityNodeInfo#setBoundsInScreen(Rect)},</li> 8582 * <li>{@link AccessibilityNodeInfo#setPackageName(CharSequence)},</li> 8583 * <li>{@link AccessibilityNodeInfo#setClassName(CharSequence)},</li> 8584 * <li>{@link AccessibilityNodeInfo#setContentDescription(CharSequence)},</li> 8585 * <li>{@link AccessibilityNodeInfo#setEnabled(boolean)},</li> 8586 * <li>{@link AccessibilityNodeInfo#setClickable(boolean)},</li> 8587 * <li>{@link AccessibilityNodeInfo#setFocusable(boolean)},</li> 8588 * <li>{@link AccessibilityNodeInfo#setFocused(boolean)},</li> 8589 * <li>{@link AccessibilityNodeInfo#setLongClickable(boolean)},</li> 8590 * <li>{@link AccessibilityNodeInfo#setSelected(boolean)},</li> 8591 * <li>{@link AccessibilityNodeInfo#setContextClickable(boolean)}</li> 8592 * </ul> 8593 * <p> 8594 * Subclasses should override this method, call the super implementation, 8595 * and set additional attributes. 8596 * </p> 8597 * <p> 8598 * If an {@link AccessibilityDelegate} has been specified via calling 8599 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 8600 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)} 8601 * is responsible for handling this call. 8602 * </p> 8603 * 8604 * @param info The instance to initialize. 8605 */ 8606 @CallSuper 8607 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 8608 if (mAccessibilityDelegate != null) { 8609 mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(this, info); 8610 } else { 8611 onInitializeAccessibilityNodeInfoInternal(info); 8612 } 8613 } 8614 8615 /** 8616 * Gets the location of this view in screen coordinates. 8617 * 8618 * @param outRect The output location 8619 * @hide 8620 */ 8621 @UnsupportedAppUsage 8622 public void getBoundsOnScreen(Rect outRect) { 8623 getBoundsOnScreen(outRect, false); 8624 } 8625 8626 /** 8627 * Gets the location of this view in screen coordinates. 8628 * 8629 * @param outRect The output location 8630 * @param clipToParent Whether to clip child bounds to the parent ones. 8631 * @hide 8632 */ 8633 @UnsupportedAppUsage 8634 public void getBoundsOnScreen(Rect outRect, boolean clipToParent) { 8635 if (mAttachInfo == null) { 8636 return; 8637 } 8638 8639 RectF position = mAttachInfo.mTmpTransformRect; 8640 position.set(0, 0, mRight - mLeft, mBottom - mTop); 8641 mapRectFromViewToScreenCoords(position, clipToParent); 8642 outRect.set(Math.round(position.left), Math.round(position.top), 8643 Math.round(position.right), Math.round(position.bottom)); 8644 } 8645 8646 /** 8647 * Map a rectangle from view-relative coordinates to screen-relative coordinates 8648 * 8649 * @param rect The rectangle to be mapped 8650 * @param clipToParent Whether to clip child bounds to the parent ones. 8651 * @hide 8652 */ 8653 public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) { 8654 if (!hasIdentityMatrix()) { 8655 getMatrix().mapRect(rect); 8656 } 8657 8658 rect.offset(mLeft, mTop); 8659 8660 ViewParent parent = mParent; 8661 while (parent instanceof View) { 8662 View parentView = (View) parent; 8663 8664 rect.offset(-parentView.mScrollX, -parentView.mScrollY); 8665 8666 if (clipToParent) { 8667 rect.left = Math.max(rect.left, 0); 8668 rect.top = Math.max(rect.top, 0); 8669 rect.right = Math.min(rect.right, parentView.getWidth()); 8670 rect.bottom = Math.min(rect.bottom, parentView.getHeight()); 8671 } 8672 8673 if (!parentView.hasIdentityMatrix()) { 8674 parentView.getMatrix().mapRect(rect); 8675 } 8676 8677 rect.offset(parentView.mLeft, parentView.mTop); 8678 8679 parent = parentView.mParent; 8680 } 8681 8682 if (parent instanceof ViewRootImpl) { 8683 ViewRootImpl viewRootImpl = (ViewRootImpl) parent; 8684 rect.offset(0, -viewRootImpl.mCurScrollY); 8685 } 8686 8687 rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop); 8688 } 8689 8690 /** 8691 * Return the class name of this object to be used for accessibility purposes. 8692 * Subclasses should only override this if they are implementing something that 8693 * should be seen as a completely new class of view when used by accessibility, 8694 * unrelated to the class it is deriving from. This is used to fill in 8695 * {@link AccessibilityNodeInfo#setClassName AccessibilityNodeInfo.setClassName}. 8696 */ 8697 public CharSequence getAccessibilityClassName() { 8698 return View.class.getName(); 8699 } 8700 8701 /** 8702 * Called when assist structure is being retrieved from a view as part of 8703 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}. 8704 * @param structure Fill in with structured view data. The default implementation 8705 * fills in all data that can be inferred from the view itself. 8706 */ 8707 public void onProvideStructure(ViewStructure structure) { 8708 onProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 8709 } 8710 8711 /** 8712 * Populates a {@link ViewStructure} to fullfil an autofill request. 8713 * 8714 * <p>The structure should contain at least the following properties: 8715 * <ul> 8716 * <li>Autofill id ({@link ViewStructure#setAutofillId(AutofillId, int)}). 8717 * <li>Autofill type ({@link ViewStructure#setAutofillType(int)}). 8718 * <li>Autofill value ({@link ViewStructure#setAutofillValue(AutofillValue)}). 8719 * <li>Whether the data is sensitive ({@link ViewStructure#setDataIsSensitive(boolean)}). 8720 * </ul> 8721 * 8722 * <p>It's also recommended to set the following properties - the more properties the structure 8723 * has, the higher the chances of an {@link android.service.autofill.AutofillService} properly 8724 * using the structure: 8725 * 8726 * <ul> 8727 * <li>Autofill hints ({@link ViewStructure#setAutofillHints(String[])}). 8728 * <li>Autofill options ({@link ViewStructure#setAutofillOptions(CharSequence[])}) when the 8729 * view can only be filled with predefined values (typically used when the autofill type 8730 * is {@link #AUTOFILL_TYPE_LIST}). 8731 * <li>Resource id ({@link ViewStructure#setId(int, String, String, String)}). 8732 * <li>Class name ({@link ViewStructure#setClassName(String)}). 8733 * <li>Content description ({@link ViewStructure#setContentDescription(CharSequence)}). 8734 * <li>Visual properties such as visibility ({@link ViewStructure#setVisibility(int)}), 8735 * dimensions ({@link ViewStructure#setDimens(int, int, int, int, int, int)}), and 8736 * opacity ({@link ViewStructure#setOpaque(boolean)}). 8737 * <li>For views representing text fields, text properties such as the text itself 8738 * ({@link ViewStructure#setText(CharSequence)}), text hints 8739 * ({@link ViewStructure#setHint(CharSequence)}, input type 8740 * ({@link ViewStructure#setInputType(int)}), 8741 * <li>For views representing HTML nodes, its web domain 8742 * ({@link ViewStructure#setWebDomain(String)}) and HTML properties 8743 * (({@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}). 8744 * </ul> 8745 * 8746 * <p>The default implementation of this method already sets most of these properties based on 8747 * related {@link View} methods (for example, the autofill id is set using 8748 * {@link #getAutofillId()}, the autofill type set using {@link #getAutofillType()}, etc.), 8749 * and views in the standard Android widgets library also override it to set their 8750 * relevant properties (for example, {@link android.widget.TextView} already sets the text 8751 * properties), so it's recommended to only override this method 8752 * (and call {@code super.onProvideAutofillStructure()}) when: 8753 * 8754 * <ul> 8755 * <li>The view contents does not include PII (Personally Identifiable Information), so it 8756 * can call {@link ViewStructure#setDataIsSensitive(boolean)} passing {@code false}. 8757 * <li>The view can only be autofilled with predefined options, so it can call 8758 * {@link ViewStructure#setAutofillOptions(CharSequence[])}. 8759 * </ul> 8760 * 8761 * <p><b>Note:</b> The {@code left} and {@code top} values set in 8762 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the next 8763 * {@link ViewGroup#isImportantForAutofill()} predecessor view included in the structure. 8764 * 8765 * <p>Views support the Autofill Framework mainly by: 8766 * <ul> 8767 * <li>Providing the metadata defining what the view means and how it can be autofilled. 8768 * <li>Notifying the Android System when the view value changed by calling 8769 * {@link AutofillManager#notifyValueChanged(View)}. 8770 * <li>Implementing the methods that autofill the view. 8771 * </ul> 8772 * <p>This method is responsible for the former; {@link #autofill(AutofillValue)} is responsible 8773 * for the latter. 8774 * 8775 * @param structure fill in with structured view data for autofill purposes. 8776 * @param flags optional flags. 8777 * 8778 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 8779 */ 8780 public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) { 8781 onProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 8782 } 8783 8784 /** 8785 * Populates a {@link ViewStructure} for content capture. 8786 * 8787 * <p>This method is called after a view is that is eligible for content capture 8788 * (for example, if it {@link #isImportantForAutofill()}, an intelligence service is enabled for 8789 * the user, and the activity rendering the view is enabled for content capture) is laid out and 8790 * is visible. 8791 * 8792 * <p>The populated structure is then passed to the service through 8793 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}. 8794 * 8795 * <p><b>Note: </b>views that manage a virtual structure under this view must populate just 8796 * the node representing this view and return right away, then asynchronously report (not 8797 * necessarily in the UI thread) when the children nodes appear, disappear or have their text 8798 * changed by calling 8799 * {@link ContentCaptureSession#notifyViewAppeared(ViewStructure)}, 8800 * {@link ContentCaptureSession#notifyViewDisappeared(AutofillId)}, and 8801 * {@link ContentCaptureSession#notifyViewTextChanged(AutofillId, CharSequence)} 8802 * respectively. The structure for the a child must be created using 8803 * {@link ContentCaptureSession#newVirtualViewStructure(AutofillId, long)}, and the 8804 * {@code autofillId} for a child can be obtained either through 8805 * {@code childStructure.getAutofillId()} or 8806 * {@link ContentCaptureSession#newAutofillId(AutofillId, long)}. 8807 * 8808 * <p>When the virtual view hierarchy represents a web page, you should also: 8809 * 8810 * <ul> 8811 * <li>Call {@link ContentCaptureManager#getContentCaptureConditions()} to infer content 8812 * capture events should be generate for that URL. 8813 * <li>Create a new {@link ContentCaptureSession} child for every HTML element that 8814 * renders a new URL (like an {@code IFRAME}) and use that session to notify events from 8815 * that subtree. 8816 * </ul> 8817 * 8818 * <p><b>Note: </b>the following methods of the {@code structure} will be ignored: 8819 * <ul> 8820 * <li>{@link ViewStructure#setChildCount(int)} 8821 * <li>{@link ViewStructure#addChildCount(int)} 8822 * <li>{@link ViewStructure#getChildCount()} 8823 * <li>{@link ViewStructure#newChild(int)} 8824 * <li>{@link ViewStructure#asyncNewChild(int)} 8825 * <li>{@link ViewStructure#asyncCommit()} 8826 * <li>{@link ViewStructure#setWebDomain(String)} 8827 * <li>{@link ViewStructure#newHtmlInfoBuilder(String)} 8828 * <li>{@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)} 8829 * <li>{@link ViewStructure#setDataIsSensitive(boolean)} 8830 * <li>{@link ViewStructure#setAlpha(float)} 8831 * <li>{@link ViewStructure#setElevation(float)} 8832 * <li>{@link ViewStructure#setTransformation(Matrix)} 8833 * 8834 * </ul> 8835 */ 8836 public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) { 8837 onProvideStructure(structure, VIEW_STRUCTURE_FOR_CONTENT_CAPTURE, flags); 8838 } 8839 8840 /** @hide */ 8841 protected void onProvideStructure(@NonNull ViewStructure structure, 8842 @ViewStructureType int viewFor, int flags) { 8843 final int id = mID; 8844 if (id != NO_ID && !isViewIdGenerated(id)) { 8845 String pkg, type, entry; 8846 try { 8847 final Resources res = getResources(); 8848 entry = res.getResourceEntryName(id); 8849 type = res.getResourceTypeName(id); 8850 pkg = res.getResourcePackageName(id); 8851 } catch (Resources.NotFoundException e) { 8852 entry = type = pkg = null; 8853 } 8854 structure.setId(id, pkg, type, entry); 8855 } else { 8856 structure.setId(id, null, null, null); 8857 } 8858 8859 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 8860 || viewFor == VIEW_STRUCTURE_FOR_CONTENT_CAPTURE) { 8861 final @AutofillType int autofillType = getAutofillType(); 8862 // Don't need to fill autofill info if view does not support it. 8863 // For example, only TextViews that are editable support autofill 8864 if (autofillType != AUTOFILL_TYPE_NONE) { 8865 structure.setAutofillType(autofillType); 8866 structure.setAutofillHints(getAutofillHints()); 8867 structure.setAutofillValue(getAutofillValue()); 8868 } 8869 structure.setImportantForAutofill(getImportantForAutofill()); 8870 } 8871 8872 int ignoredParentLeft = 0; 8873 int ignoredParentTop = 0; 8874 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL 8875 && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) { 8876 View parentGroup = null; 8877 8878 ViewParent viewParent = getParent(); 8879 if (viewParent instanceof View) { 8880 parentGroup = (View) viewParent; 8881 } 8882 8883 while (parentGroup != null && !parentGroup.isImportantForAutofill()) { 8884 ignoredParentLeft += parentGroup.mLeft; 8885 ignoredParentTop += parentGroup.mTop; 8886 8887 viewParent = parentGroup.getParent(); 8888 if (viewParent instanceof View) { 8889 parentGroup = (View) viewParent; 8890 } else { 8891 break; 8892 } 8893 } 8894 } 8895 8896 structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY, 8897 mRight - mLeft, mBottom - mTop); 8898 if (viewFor == VIEW_STRUCTURE_FOR_ASSIST) { 8899 if (!hasIdentityMatrix()) { 8900 structure.setTransformation(getMatrix()); 8901 } 8902 structure.setElevation(getZ()); 8903 } 8904 structure.setVisibility(getVisibility()); 8905 structure.setEnabled(isEnabled()); 8906 if (isClickable()) { 8907 structure.setClickable(true); 8908 } 8909 if (isFocusable()) { 8910 structure.setFocusable(true); 8911 } 8912 if (isFocused()) { 8913 structure.setFocused(true); 8914 } 8915 if (isAccessibilityFocused()) { 8916 structure.setAccessibilityFocused(true); 8917 } 8918 if (isSelected()) { 8919 structure.setSelected(true); 8920 } 8921 if (isActivated()) { 8922 structure.setActivated(true); 8923 } 8924 if (isLongClickable()) { 8925 structure.setLongClickable(true); 8926 } 8927 if (this instanceof Checkable) { 8928 structure.setCheckable(true); 8929 if (((Checkable)this).isChecked()) { 8930 structure.setChecked(true); 8931 } 8932 } 8933 if (isOpaque()) { 8934 structure.setOpaque(true); 8935 } 8936 if (isContextClickable()) { 8937 structure.setContextClickable(true); 8938 } 8939 structure.setClassName(getAccessibilityClassName().toString()); 8940 structure.setContentDescription(getContentDescription()); 8941 } 8942 8943 /** 8944 * Called when assist structure is being retrieved from a view as part of 8945 * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData} to 8946 * generate additional virtual structure under this view. The defaullt implementation 8947 * uses {@link #getAccessibilityNodeProvider()} to try to generate this from the 8948 * view's virtual accessibility nodes, if any. You can override this for a more 8949 * optimal implementation providing this data. 8950 */ 8951 public void onProvideVirtualStructure(ViewStructure structure) { 8952 onProvideVirtualStructureCompat(structure, false); 8953 } 8954 8955 /** 8956 * Fallback implementation to populate a ViewStructure from accessibility state. 8957 * 8958 * @param structure The structure to populate. 8959 * @param forAutofill Whether the structure is needed for autofill. 8960 */ 8961 private void onProvideVirtualStructureCompat(ViewStructure structure, boolean forAutofill) { 8962 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 8963 if (provider != null) { 8964 if (forAutofill && Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 8965 Log.v(AUTOFILL_LOG_TAG, "onProvideVirtualStructureCompat() for " + this); 8966 } 8967 final AccessibilityNodeInfo info = createAccessibilityNodeInfo(); 8968 structure.setChildCount(1); 8969 final ViewStructure root = structure.newChild(0); 8970 populateVirtualStructure(root, provider, info, forAutofill); 8971 info.recycle(); 8972 } 8973 } 8974 8975 /** 8976 * Populates a {@link ViewStructure} containing virtual children to fullfil an autofill 8977 * request. 8978 * 8979 * <p>This method should be used when the view manages a virtual structure under this view. For 8980 * example, a view that draws input fields using {@link #draw(Canvas)}. 8981 * 8982 * <p>When implementing this method, subclasses must follow the rules below: 8983 * 8984 * <ul> 8985 * <li>Add virtual children by calling the {@link ViewStructure#newChild(int)} or 8986 * {@link ViewStructure#asyncNewChild(int)} methods, where the {@code id} is an unique id 8987 * identifying the children in the virtual structure. 8988 * <li>The children hierarchy can have multiple levels if necessary, but ideally it should 8989 * exclude intermediate levels that are irrelevant for autofill; that would improve the 8990 * autofill performance. 8991 * <li>Also implement {@link #autofill(SparseArray)} to autofill the virtual 8992 * children. 8993 * <li>Set the autofill properties of the child structure as defined by 8994 * {@link #onProvideAutofillStructure(ViewStructure, int)}, using 8995 * {@link ViewStructure#setAutofillId(AutofillId, int)} to set its autofill id. 8996 * <li>Call {@link android.view.autofill.AutofillManager#notifyViewEntered(View, int, Rect)} 8997 * and/or {@link android.view.autofill.AutofillManager#notifyViewExited(View, int)} 8998 * when the focused virtual child changed. 8999 * <li>Override {@link #isVisibleToUserForAutofill(int)} to allow the platform to query 9000 * whether a given virtual view is visible to the user in order to support triggering 9001 * save when all views of interest go away. 9002 * <li>Call 9003 * {@link android.view.autofill.AutofillManager#notifyValueChanged(View, int, AutofillValue)} 9004 * when the value of a virtual child changed. 9005 * <li>Call {@link 9006 * android.view.autofill.AutofillManager#notifyViewVisibilityChanged(View, int, boolean)} 9007 * when the visibility of a virtual child changed. 9008 * <li>Call 9009 * {@link android.view.autofill.AutofillManager#notifyViewClicked(View, int)} when a virtual 9010 * child is clicked. 9011 * <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure 9012 * changed and the current context should be committed (for example, when the user tapped 9013 * a {@code SUBMIT} button in an HTML page). 9014 * <li>Call {@link AutofillManager#cancel()} when the autofill context of the view structure 9015 * changed and the current context should be canceled (for example, when the user tapped 9016 * a {@code CANCEL} button in an HTML page). 9017 * <li>Provide ways for users to manually request autofill by calling 9018 * {@link AutofillManager#requestAutofill(View, int, Rect)}. 9019 * <li>The {@code left} and {@code top} values set in 9020 * {@link ViewStructure#setDimens(int, int, int, int, int, int)} must be relative to the 9021 * next {@link ViewGroup#isImportantForAutofill()} predecessor view included in the 9022 * structure. 9023 * </ul> 9024 * 9025 * <p>Views with virtual children support the Autofill Framework mainly by: 9026 * <ul> 9027 * <li>Providing the metadata defining what the virtual children mean and how they can be 9028 * autofilled. 9029 * <li>Implementing the methods that autofill the virtual children. 9030 * </ul> 9031 * <p>This method is responsible for the former; {@link #autofill(SparseArray)} is responsible 9032 * for the latter. 9033 * 9034 * @param structure fill in with virtual children data for autofill purposes. 9035 * @param flags optional flags. 9036 * 9037 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 9038 */ 9039 public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) { 9040 if (mContext.isAutofillCompatibilityEnabled()) { 9041 onProvideVirtualStructureCompat(structure, true); 9042 } 9043 } 9044 9045 /** 9046 * Automatically fills the content of this view with the {@code value}. 9047 * 9048 * <p>Views support the Autofill Framework mainly by: 9049 * <ul> 9050 * <li>Providing the metadata defining what the view means and how it can be autofilled. 9051 * <li>Implementing the methods that autofill the view. 9052 * </ul> 9053 * <p>{@link #onProvideAutofillStructure(ViewStructure, int)} is responsible for the former, 9054 * this method is responsible for latter. 9055 * 9056 * <p>This method does nothing by default, but when overridden it typically: 9057 * <ol> 9058 * <li>Checks if the provided value matches the expected type (which is defined by 9059 * {@link #getAutofillType()}). 9060 * <li>Checks if the view is editable - if it isn't, it should return right away. 9061 * <li>Call the proper getter method on {@link AutofillValue} to fetch the actual value. 9062 * <li>Pass the actual value to the equivalent setter in the view. 9063 * </ol> 9064 * 9065 * <p>For example, a text-field view could implement the method this way: 9066 * 9067 * <pre class="prettyprint"> 9068 * @Override 9069 * public void autofill(AutofillValue value) { 9070 * if (!value.isText() || !this.isEditable()) { 9071 * return; 9072 * } 9073 * CharSequence text = value.getTextValue(); 9074 * if (text != null) { 9075 * this.setText(text); 9076 * } 9077 * } 9078 * </pre> 9079 * 9080 * <p>If the value is updated asynchronously, the next call to 9081 * {@link AutofillManager#notifyValueChanged(View)} must happen <b>after</b> the value was 9082 * changed to the autofilled value. If not, the view will not be considered autofilled. 9083 * 9084 * <p><b>Note:</b> After this method is called, the value returned by 9085 * {@link #getAutofillValue()} must be equal to the {@code value} passed to it, otherwise the 9086 * view will not be highlighted as autofilled. 9087 * 9088 * @param value value to be autofilled. 9089 */ 9090 public void autofill(@SuppressWarnings("unused") AutofillValue value) { 9091 } 9092 9093 /** 9094 * Automatically fills the content of the virtual children within this view. 9095 * 9096 * <p>Views with virtual children support the Autofill Framework mainly by: 9097 * <ul> 9098 * <li>Providing the metadata defining what the virtual children mean and how they can be 9099 * autofilled. 9100 * <li>Implementing the methods that autofill the virtual children. 9101 * </ul> 9102 * <p>{@link #onProvideAutofillVirtualStructure(ViewStructure, int)} is responsible for the 9103 * former, this method is responsible for the latter - see {@link #autofill(AutofillValue)} and 9104 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} for more info about autofill. 9105 * 9106 * <p>If a child value is updated asynchronously, the next call to 9107 * {@link AutofillManager#notifyValueChanged(View, int, AutofillValue)} must happen 9108 * <b>after</b> the value was changed to the autofilled value. If not, the child will not be 9109 * considered autofilled. 9110 * 9111 * <p><b>Note:</b> To indicate that a virtual view was autofilled, 9112 * <code>?android:attr/autofilledHighlight</code> should be drawn over it until the data 9113 * changes. 9114 * 9115 * @param values map of values to be autofilled, keyed by virtual child id. 9116 * 9117 * @attr ref android.R.styleable#Theme_autofilledHighlight 9118 */ 9119 public void autofill(@NonNull @SuppressWarnings("unused") SparseArray<AutofillValue> values) { 9120 if (!mContext.isAutofillCompatibilityEnabled()) { 9121 return; 9122 } 9123 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 9124 if (provider == null) { 9125 return; 9126 } 9127 final int valueCount = values.size(); 9128 for (int i = 0; i < valueCount; i++) { 9129 final AutofillValue value = values.valueAt(i); 9130 if (value.isText()) { 9131 final int virtualId = values.keyAt(i); 9132 final CharSequence text = value.getTextValue(); 9133 final Bundle arguments = new Bundle(); 9134 arguments.putCharSequence( 9135 AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text); 9136 provider.performAction(virtualId, AccessibilityNodeInfo.ACTION_SET_TEXT, arguments); 9137 } 9138 } 9139 } 9140 9141 /** 9142 * Gets the unique, logical identifier of this view in the activity, for autofill purposes. 9143 * 9144 * <p>The autofill id is created on demand, unless it is explicitly set by 9145 * {@link #setAutofillId(AutofillId)}. 9146 * 9147 * <p>See {@link #setAutofillId(AutofillId)} for more info. 9148 * 9149 * @return The View's autofill id. 9150 */ 9151 public final AutofillId getAutofillId() { 9152 if (mAutofillId == null) { 9153 // The autofill id needs to be unique, but its value doesn't matter, 9154 // so it's better to reuse the accessibility id to save space. 9155 mAutofillId = new AutofillId(getAutofillViewId()); 9156 } 9157 return mAutofillId; 9158 } 9159 9160 /** 9161 * Sets the unique, logical identifier of this view in the activity, for autofill purposes. 9162 * 9163 * <p>The autofill id is created on demand, and this method should only be called when a view is 9164 * reused after {@link #dispatchProvideAutofillStructure(ViewStructure, int)} is called, as 9165 * that method creates a snapshot of the view that is passed along to the autofill service. 9166 * 9167 * <p>This method is typically used when view subtrees are recycled to represent different 9168 * content* —in this case, the autofill id can be saved before the view content is swapped 9169 * out, and restored later when it's swapped back in. For example: 9170 * 9171 * <pre> 9172 * EditText reusableView = ...; 9173 * ViewGroup parentView = ...; 9174 * AutofillManager afm = ...; 9175 * 9176 * // Swap out the view and change its contents 9177 * AutofillId oldId = reusableView.getAutofillId(); 9178 * CharSequence oldText = reusableView.getText(); 9179 * parentView.removeView(reusableView); 9180 * AutofillId newId = afm.getNextAutofillId(); 9181 * reusableView.setText("New I am"); 9182 * reusableView.setAutofillId(newId); 9183 * parentView.addView(reusableView); 9184 * 9185 * // Later, swap the old content back in 9186 * parentView.removeView(reusableView); 9187 * reusableView.setAutofillId(oldId); 9188 * reusableView.setText(oldText); 9189 * parentView.addView(reusableView); 9190 * </pre> 9191 * 9192 * @param id an autofill ID that is unique in the {@link android.app.Activity} hosting the view, 9193 * or {@code null} to reset it. Usually it's an id previously allocated to another view (and 9194 * obtained through {@link #getAutofillId()}), or a new value obtained through 9195 * {@link AutofillManager#getNextAutofillId()}. 9196 * 9197 * @throws IllegalStateException if the view is already {@link #isAttachedToWindow() attached to 9198 * a window}. 9199 * 9200 * @throws IllegalArgumentException if the id is an autofill id associated with a virtual view. 9201 */ 9202 public void setAutofillId(@Nullable AutofillId id) { 9203 // TODO(b/37566627): add unit / CTS test for all possible combinations below 9204 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9205 Log.v(AUTOFILL_LOG_TAG, "setAutofill(): from " + mAutofillId + " to " + id); 9206 } 9207 if (isAttachedToWindow()) { 9208 throw new IllegalStateException("Cannot set autofill id when view is attached"); 9209 } 9210 if (id != null && !id.isNonVirtual()) { 9211 throw new IllegalStateException("Cannot set autofill id assigned to virtual views"); 9212 } 9213 if (id == null && (mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) == 0) { 9214 // Ignore reset because it was never explicitly set before. 9215 return; 9216 } 9217 mAutofillId = id; 9218 if (id != null) { 9219 mAutofillViewId = id.getViewId(); 9220 mPrivateFlags3 |= PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9221 } else { 9222 mAutofillViewId = NO_ID; 9223 mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; 9224 } 9225 } 9226 9227 /** 9228 * Describes the autofill type of this view, so an 9229 * {@link android.service.autofill.AutofillService} can create the proper {@link AutofillValue} 9230 * when autofilling the view. 9231 * 9232 * <p>By default returns {@link #AUTOFILL_TYPE_NONE}, but views should override it to properly 9233 * support the Autofill Framework. 9234 * 9235 * @return either {@link #AUTOFILL_TYPE_NONE}, {@link #AUTOFILL_TYPE_TEXT}, 9236 * {@link #AUTOFILL_TYPE_LIST}, {@link #AUTOFILL_TYPE_DATE}, or {@link #AUTOFILL_TYPE_TOGGLE}. 9237 * 9238 * @see #onProvideAutofillStructure(ViewStructure, int) 9239 * @see #autofill(AutofillValue) 9240 */ 9241 public @AutofillType int getAutofillType() { 9242 return AUTOFILL_TYPE_NONE; 9243 } 9244 9245 /** 9246 * Gets the hints that help an {@link android.service.autofill.AutofillService} determine how 9247 * to autofill the view with the user's data. 9248 * 9249 * <p>See {@link #setAutofillHints(String...)} for more info about these hints. 9250 * 9251 * @return The hints set via the attribute or {@link #setAutofillHints(String...)}, or 9252 * {@code null} if no hints were set. 9253 * 9254 * @attr ref android.R.styleable#View_autofillHints 9255 */ 9256 @ViewDebug.ExportedProperty() 9257 @InspectableProperty 9258 @Nullable public String[] getAutofillHints() { 9259 return mAutofillHints; 9260 } 9261 9262 /** 9263 * @hide 9264 */ 9265 @TestApi 9266 public boolean isAutofilled() { 9267 return (mPrivateFlags3 & PFLAG3_IS_AUTOFILLED) != 0; 9268 } 9269 9270 /** 9271 * @hide 9272 */ 9273 public boolean hideAutofillHighlight() { 9274 return (mPrivateFlags4 & PFLAG4_AUTOFILL_HIDE_HIGHLIGHT) != 0; 9275 } 9276 9277 /** 9278 * Gets the {@link View}'s current autofill value. 9279 * 9280 * <p>By default returns {@code null}, but subclasses should override it and return an 9281 * appropriate value to properly support the Autofill Framework. 9282 * 9283 * @see #onProvideAutofillStructure(ViewStructure, int) 9284 * @see #autofill(AutofillValue) 9285 */ 9286 @Nullable 9287 public AutofillValue getAutofillValue() { 9288 return null; 9289 } 9290 9291 /** 9292 * Gets the mode for determining whether this view is important for autofill. 9293 * 9294 * <p>See {@link #setImportantForAutofill(int)} and {@link #isImportantForAutofill()} for more 9295 * info about this mode. 9296 * 9297 * @return {@link #IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to 9298 * {@link #setImportantForAutofill(int)}. 9299 * 9300 * @attr ref android.R.styleable#View_importantForAutofill 9301 */ 9302 @ViewDebug.ExportedProperty(mapping = { 9303 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_AUTO, to = "auto"), 9304 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES, to = "yes"), 9305 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO, to = "no"), 9306 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 9307 to = "yesExcludeDescendants"), 9308 @ViewDebug.IntToString(from = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 9309 to = "noExcludeDescendants")}) 9310 @InspectableProperty(enumMapping = { 9311 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_AUTO, name = "auto"), 9312 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES, name = "yes"), 9313 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO, name = "no"), 9314 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS, 9315 name = "yesExcludeDescendants"), 9316 @EnumEntry(value = IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS, 9317 name = "noExcludeDescendants"), 9318 }) 9319 public @AutofillImportance int getImportantForAutofill() { 9320 return (mPrivateFlags3 9321 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK) >> PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT; 9322 } 9323 9324 /** 9325 * Sets the mode for determining whether this view is considered important for autofill. 9326 * 9327 * <p>The platform determines the importance for autofill automatically but you 9328 * can use this method to customize the behavior. For example: 9329 * 9330 * <ol> 9331 * <li>When the view contents is irrelevant for autofill (for example, a text field used in a 9332 * "Captcha" challenge), it should be {@link #IMPORTANT_FOR_AUTOFILL_NO}. 9333 * <li>When both the view and its children are irrelevant for autofill (for example, the root 9334 * view of an activity containing a spreadhseet editor), it should be 9335 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 9336 * <li>When the view content is relevant for autofill but its children aren't (for example, 9337 * a credit card expiration date represented by a custom view that overrides the proper 9338 * autofill methods and has 2 children representing the month and year), it should 9339 * be {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}. 9340 * </ol> 9341 * 9342 * <p><b>Note:</b> Setting the mode as {@link #IMPORTANT_FOR_AUTOFILL_NO} or 9343 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and its 9344 * children) will be always be considered not important; for example, when the user explicitly 9345 * makes an autofill request, all views are considered important. See 9346 * {@link #isImportantForAutofill()} for more details about how the View's importance for 9347 * autofill is used. 9348 * 9349 * @param mode {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, {@link #IMPORTANT_FOR_AUTOFILL_YES}, 9350 * {@link #IMPORTANT_FOR_AUTOFILL_NO}, {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, 9351 * or {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}. 9352 * 9353 * @attr ref android.R.styleable#View_importantForAutofill 9354 */ 9355 public void setImportantForAutofill(@AutofillImportance int mode) { 9356 mPrivateFlags3 &= ~PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 9357 mPrivateFlags3 |= (mode << PFLAG3_IMPORTANT_FOR_AUTOFILL_SHIFT) 9358 & PFLAG3_IMPORTANT_FOR_AUTOFILL_MASK; 9359 } 9360 9361 /** 9362 * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode} 9363 * associated with this view is considered important for autofill purposes. 9364 * 9365 * <p>Generally speaking, a view is important for autofill if: 9366 * <ol> 9367 * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}. 9368 * <li>The view contents can help an {@link android.service.autofill.AutofillService} 9369 * determine how other views can be autofilled. 9370 * <ol> 9371 * 9372 * <p>For example, view containers should typically return {@code false} for performance reasons 9373 * (since the important info is provided by their children), but if its properties have relevant 9374 * information (for example, a resource id called {@code credentials}, it should return 9375 * {@code true}. On the other hand, views representing labels or editable fields should 9376 * typically return {@code true}, but in some cases they could return {@code false} 9377 * (for example, if they're part of a "Captcha" mechanism). 9378 * 9379 * <p>The value returned by this method depends on the value returned by 9380 * {@link #getImportantForAutofill()}: 9381 * 9382 * <ol> 9383 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_YES} or 9384 * {@link #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}, then it returns {@code true} 9385 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_NO} or 9386 * {@link #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}, then it returns {@code false} 9387 * <li>if it returns {@link #IMPORTANT_FOR_AUTOFILL_AUTO}, then it uses some simple heuristics 9388 * that can return {@code true} in some cases (like a container with a resource id), 9389 * but {@code false} in most. 9390 * <li>otherwise, it returns {@code false}. 9391 * </ol> 9392 * 9393 * <p>When a view is considered important for autofill: 9394 * <ul> 9395 * <li>The view might automatically trigger an autofill request when focused on. 9396 * <li>The contents of the view are included in the {@link ViewStructure} used in an autofill 9397 * request. 9398 * </ul> 9399 * 9400 * <p>On the other hand, when a view is considered not important for autofill: 9401 * <ul> 9402 * <li>The view never automatically triggers autofill requests, but it can trigger a manual 9403 * request through {@link AutofillManager#requestAutofill(View)}. 9404 * <li>The contents of the view are not included in the {@link ViewStructure} used in an 9405 * autofill request, unless the request has the 9406 * {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag. 9407 * </ul> 9408 * 9409 * @return whether the view is considered important for autofill. 9410 * 9411 * @see #setImportantForAutofill(int) 9412 * @see #IMPORTANT_FOR_AUTOFILL_AUTO 9413 * @see #IMPORTANT_FOR_AUTOFILL_YES 9414 * @see #IMPORTANT_FOR_AUTOFILL_NO 9415 * @see #IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 9416 * @see #IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9417 * @see AutofillManager#requestAutofill(View) 9418 */ 9419 public final boolean isImportantForAutofill() { 9420 // Check parent mode to ensure we're not hidden. 9421 ViewParent parent = mParent; 9422 while (parent instanceof View) { 9423 final int parentImportance = ((View) parent).getImportantForAutofill(); 9424 if (parentImportance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9425 || parentImportance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS) { 9426 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9427 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 9428 + "because parent " + parent + "'s importance is " + parentImportance); 9429 } 9430 return false; 9431 } 9432 parent = parent.getParent(); 9433 } 9434 9435 final int importance = getImportantForAutofill(); 9436 9437 // First, check the explicit states. 9438 if (importance == IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS 9439 || importance == IMPORTANT_FOR_AUTOFILL_YES) { 9440 return true; 9441 } 9442 if (importance == IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS 9443 || importance == IMPORTANT_FOR_AUTOFILL_NO) { 9444 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.VERBOSE)) { 9445 Log.v(AUTOFILL_LOG_TAG, "View (" + this + ") is not important for autofill " 9446 + "because its importance is " + importance); 9447 } 9448 return false; 9449 } 9450 9451 // Then use some heuristics to handle AUTO. 9452 if (importance != IMPORTANT_FOR_AUTOFILL_AUTO) { 9453 Log.w(AUTOFILL_LOG_TAG, "invalid autofill importance (" + importance + " on view " 9454 + this); 9455 return false; 9456 } 9457 9458 // Always include views that have an explicit resource id. 9459 final int id = mID; 9460 if (id != NO_ID && !isViewIdGenerated(id)) { 9461 final Resources res = getResources(); 9462 String entry = null; 9463 String pkg = null; 9464 try { 9465 entry = res.getResourceEntryName(id); 9466 pkg = res.getResourcePackageName(id); 9467 } catch (Resources.NotFoundException e) { 9468 // ignore 9469 } 9470 if (entry != null && pkg != null && pkg.equals(mContext.getPackageName())) { 9471 return true; 9472 } 9473 } 9474 9475 // If the app developer explicitly set hints for it, it's important. 9476 if (getAutofillHints() != null) { 9477 return true; 9478 } 9479 9480 // Otherwise, assume it's not important... 9481 return false; 9482 } 9483 9484 /** 9485 * Gets the mode for determining whether this view is important for content capture. 9486 * 9487 * <p>See {@link #setImportantForContentCapture(int)} and 9488 * {@link #isImportantForContentCapture()} for more info about this mode. 9489 * 9490 * @return {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO} by default, or value passed to 9491 * {@link #setImportantForContentCapture(int)}. 9492 * 9493 * @attr ref android.R.styleable#View_importantForContentCapture 9494 */ 9495 @ViewDebug.ExportedProperty(mapping = { 9496 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, to = "auto"), 9497 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES, to = "yes"), 9498 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO, to = "no"), 9499 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 9500 to = "yesExcludeDescendants"), 9501 @ViewDebug.IntToString(from = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 9502 to = "noExcludeDescendants")}) 9503 @InspectableProperty(enumMapping = { 9504 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_AUTO, name = "auto"), 9505 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES, name = "yes"), 9506 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO, name = "no"), 9507 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS, 9508 name = "yesExcludeDescendants"), 9509 @EnumEntry(value = IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS, 9510 name = "noExcludeDescendants"), 9511 }) 9512 public @ContentCaptureImportance int getImportantForContentCapture() { 9513 // NOTE: the important for content capture values were the first flags added and are set in 9514 // the rightmost position, so we don't need to shift them 9515 return mPrivateFlags4 & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 9516 } 9517 9518 /** 9519 * Sets the mode for determining whether this view is considered important for content capture. 9520 * 9521 * <p>The platform determines the importance for autofill automatically but you 9522 * can use this method to customize the behavior. Typically, a view that provides text should 9523 * be marked as {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}. 9524 * 9525 * @param mode {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}, 9526 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES}, {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO}, 9527 * {@link #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS}, 9528 * or {@link #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS}. 9529 * 9530 * @attr ref android.R.styleable#View_importantForContentCapture 9531 */ 9532 public void setImportantForContentCapture(@ContentCaptureImportance int mode) { 9533 // Reset first 9534 mPrivateFlags4 &= ~PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK; 9535 // Then set again 9536 // NOTE: the important for content capture values were the first flags added and are set in 9537 // the rightmost position, so we don't need to shift them 9538 mPrivateFlags4 |= (mode & PFLAG4_IMPORTANT_FOR_CONTENT_CAPTURE_MASK); 9539 } 9540 9541 /** 9542 * Hints the Android System whether this view is considered important for content capture, based 9543 * on the value explicitly set by {@link #setImportantForContentCapture(int)} and heuristics 9544 * when it's {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}. 9545 * 9546 * <p>See {@link ContentCaptureManager} for more info about content capture. 9547 * 9548 * @return whether the view is considered important for content capture. 9549 * 9550 * @see #setImportantForContentCapture(int) 9551 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO 9552 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES 9553 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO 9554 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 9555 * @see #IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 9556 */ 9557 public final boolean isImportantForContentCapture() { 9558 boolean isImportant; 9559 if ((mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED) != 0) { 9560 isImportant = (mPrivateFlags4 & PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE) != 0; 9561 return isImportant; 9562 } 9563 9564 isImportant = calculateIsImportantForContentCapture(); 9565 9566 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 9567 if (isImportant) { 9568 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_CACHED_VALUE; 9569 } 9570 mPrivateFlags4 |= PFLAG4_CONTENT_CAPTURE_IMPORTANCE_IS_CACHED; 9571 return isImportant; 9572 } 9573 9574 /** 9575 * Calculates whether the flag is important for content capture so it can be used by 9576 * {@link #isImportantForContentCapture()} while the tree is traversed. 9577 */ 9578 private boolean calculateIsImportantForContentCapture() { 9579 // Check parent mode to ensure we're important 9580 ViewParent parent = mParent; 9581 while (parent instanceof View) { 9582 final int parentImportance = ((View) parent).getImportantForContentCapture(); 9583 if (parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 9584 || parentImportance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS) { 9585 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 9586 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for " 9587 + "content capture because parent " + parent + "'s importance is " 9588 + parentImportance); 9589 } 9590 return false; 9591 } 9592 parent = parent.getParent(); 9593 } 9594 9595 final int importance = getImportantForContentCapture(); 9596 9597 // First, check the explicit states. 9598 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES_EXCLUDE_DESCENDANTS 9599 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_YES) { 9600 return true; 9601 } 9602 if (importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO_EXCLUDE_DESCENDANTS 9603 || importance == IMPORTANT_FOR_CONTENT_CAPTURE_NO) { 9604 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.VERBOSE)) { 9605 Log.v(CONTENT_CAPTURE_LOG_TAG, "View (" + this + ") is not important for content " 9606 + "capture because its importance is " + importance); 9607 } 9608 return false; 9609 } 9610 9611 // Then use some heuristics to handle AUTO. 9612 if (importance != IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) { 9613 Log.w(CONTENT_CAPTURE_LOG_TAG, "invalid content capture importance (" + importance 9614 + " on view " + this); 9615 return false; 9616 } 9617 9618 // View group is important if at least one children also is 9619 if (this instanceof ViewGroup) { 9620 final ViewGroup group = (ViewGroup) this; 9621 for (int i = 0; i < group.getChildCount(); i++) { 9622 final View child = group.getChildAt(i); 9623 if (child.isImportantForContentCapture()) { 9624 return true; 9625 } 9626 } 9627 } 9628 9629 // If the app developer explicitly set hints or autofill hintsfor it, it's important. 9630 if (getAutofillHints() != null) { 9631 return true; 9632 } 9633 9634 // Otherwise, assume it's not important... 9635 return false; 9636 } 9637 9638 /** 9639 * Helper used to notify the {@link ContentCaptureManager} when the view is removed or 9640 * added, based on whether it's laid out and visible, and without knowing if the parent removed 9641 * it from the view hierarchy. 9642 * 9643 * <p>This method is called from many places (visibility changed, view laid out, view attached 9644 * or detached to/from window, etc...) and hence must contain the logic to call the manager, as 9645 * described below: 9646 * 9647 * <ol> 9648 * <li>It should only be called when content capture is enabled for the view. 9649 * <li>It must call viewAppeared() before viewDisappeared() 9650 * <li>viewAppearead() can only be called when the view is visible and laidout 9651 * <li>It should not call the same event twice. 9652 * </ol> 9653 */ 9654 private void notifyAppearedOrDisappearedForContentCaptureIfNeeded(boolean appeared) { 9655 AttachInfo ai = mAttachInfo; 9656 // Skip it while the view is being laided out for the first time 9657 if (ai != null && !ai.mReadyForContentCaptureUpdates) return; 9658 9659 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 9660 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 9661 "notifyContentCapture(" + appeared + ") for " + getClass().getSimpleName()); 9662 } 9663 try { 9664 notifyAppearedOrDisappearedForContentCaptureIfNeededNoTrace(appeared); 9665 } finally { 9666 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 9667 } 9668 } 9669 9670 private void notifyAppearedOrDisappearedForContentCaptureIfNeededNoTrace(boolean appeared) { 9671 AttachInfo ai = mAttachInfo; 9672 9673 // First check if context has client, so it saves a service lookup when it doesn't 9674 if (mContext.getContentCaptureOptions() == null) return; 9675 9676 if (appeared) { 9677 if (!isLaidOut() || getVisibility() != VISIBLE 9678 || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) { 9679 if (DEBUG_CONTENT_CAPTURE) { 9680 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'appeared' on " + this + ": laid=" 9681 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 9682 + ", visible=" + (getVisibility() == VISIBLE) 9683 + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4 9684 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) 9685 + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4 9686 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0)); 9687 } 9688 return; 9689 } 9690 } else { 9691 if ((mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) == 0 9692 || (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0) { 9693 if (DEBUG_CONTENT_CAPTURE) { 9694 Log.v(CONTENT_CAPTURE_LOG_TAG, "Ignoring 'disappeared' on " + this + ": laid=" 9695 + isLaidOut() + ", visibleToUser=" + isVisibleToUser() 9696 + ", visible=" + (getVisibility() == VISIBLE) 9697 + ": alreadyNotifiedAppeared=" + ((mPrivateFlags4 9698 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0) 9699 + ", alreadyNotifiedDisappeared=" + ((mPrivateFlags4 9700 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED) != 0)); 9701 } 9702 return; 9703 } 9704 } 9705 9706 ContentCaptureSession session = getContentCaptureSession(); 9707 if (session == null) return; 9708 9709 // ... and finally at the view level 9710 // NOTE: isImportantForContentCapture() is more expensive than cm.isContentCaptureEnabled() 9711 if (!isImportantForContentCapture()) return; 9712 9713 if (appeared) { 9714 setNotifiedContentCaptureAppeared(); 9715 9716 if (ai != null) { 9717 ai.delayNotifyContentCaptureEvent(session, this, appeared); 9718 } else { 9719 if (DEBUG_CONTENT_CAPTURE) { 9720 Log.w(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on appeared for " + this); 9721 } 9722 } 9723 } else { 9724 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 9725 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 9726 9727 if (ai != null) { 9728 ai.delayNotifyContentCaptureEvent(session, this, appeared); 9729 } else { 9730 if (DEBUG_CONTENT_CAPTURE) { 9731 Log.v(CONTENT_CAPTURE_LOG_TAG, "no AttachInfo on disappeared for " + this); 9732 } 9733 } 9734 } 9735 } 9736 9737 private void setNotifiedContentCaptureAppeared() { 9738 mPrivateFlags4 |= PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED; 9739 mPrivateFlags4 &= ~PFLAG4_NOTIFIED_CONTENT_CAPTURE_DISAPPEARED; 9740 } 9741 9742 /** @hide */ 9743 protected boolean getNotifiedContentCaptureAppeared() { 9744 return (mPrivateFlags4 & PFLAG4_NOTIFIED_CONTENT_CAPTURE_APPEARED) != 0; 9745 } 9746 9747 9748 /** 9749 * Sets the (optional) {@link ContentCaptureSession} associated with this view. 9750 * 9751 * <p>This method should be called when you need to associate a {@link ContentCaptureContext} to 9752 * the content capture events associated with this view or its view hierarchy (if it's a 9753 * {@link ViewGroup}). 9754 * 9755 * <p>For example, if your activity is associated with a web domain, first you would need to 9756 * set the context for the main DOM: 9757 * 9758 * <pre> 9759 * ContentCaptureSession mainSession = rootView.getContentCaptureSession(); 9760 * mainSession.setContentCaptureContext(ContentCaptureContext.forLocusId(Uri.parse(myUrl)); 9761 * </pre> 9762 * 9763 * <p>Then if the page had an {@code IFRAME}, you would create a new session for it: 9764 * 9765 * <pre> 9766 * ContentCaptureSession iframeSession = mainSession.createContentCaptureSession( 9767 * ContentCaptureContext.forLocusId(Uri.parse(iframeUrl))); 9768 * iframeView.setContentCaptureSession(iframeSession); 9769 * </pre> 9770 * 9771 * @param contentCaptureSession a session created by 9772 * {@link ContentCaptureSession#createContentCaptureSession( 9773 * android.view.contentcapture.ContentCaptureContext)}. 9774 */ 9775 public void setContentCaptureSession(@Nullable ContentCaptureSession contentCaptureSession) { 9776 mContentCaptureSession = contentCaptureSession; 9777 } 9778 9779 /** 9780 * Gets the session used to notify content capture events. 9781 * 9782 * @return session explicitly set by {@link #setContentCaptureSession(ContentCaptureSession)}, 9783 * inherited by ancestors, default session or {@code null} if content capture is disabled for 9784 * this view. 9785 */ 9786 @Nullable 9787 public final ContentCaptureSession getContentCaptureSession() { 9788 if (mContentCaptureSessionCached) { 9789 return mContentCaptureSession; 9790 } 9791 9792 mContentCaptureSession = getAndCacheContentCaptureSession(); 9793 mContentCaptureSessionCached = true; 9794 return mContentCaptureSession; 9795 } 9796 9797 @Nullable 9798 private ContentCaptureSession getAndCacheContentCaptureSession() { 9799 // First try the session explicitly set by setContentCaptureSession() 9800 if (mContentCaptureSession != null) { 9801 return mContentCaptureSession; 9802 } 9803 9804 // Then the session explicitly set in an ancestor 9805 ContentCaptureSession session = null; 9806 if (mParent instanceof View) { 9807 session = ((View) mParent).getContentCaptureSession(); 9808 } 9809 9810 // Finally, if no session was explicitly set, use the context's default session. 9811 if (session == null) { 9812 final ContentCaptureManager ccm = mContext 9813 .getSystemService(ContentCaptureManager.class); 9814 return ccm == null ? null : ccm.getMainContentCaptureSession(); 9815 } 9816 return session; 9817 } 9818 9819 @Nullable 9820 private AutofillManager getAutofillManager() { 9821 return mContext.getSystemService(AutofillManager.class); 9822 } 9823 9824 private boolean isAutofillable() { 9825 if (getAutofillType() == AUTOFILL_TYPE_NONE) return false; 9826 9827 if (!isImportantForAutofill()) { 9828 // View is not important for "regular" autofill, so we must check if Augmented Autofill 9829 // is enabled for the activity 9830 final AutofillOptions options = mContext.getAutofillOptions(); 9831 if (options == null || !options.isAugmentedAutofillEnabled(mContext)) { 9832 return false; 9833 } 9834 final AutofillManager afm = getAutofillManager(); 9835 if (afm == null) return false; 9836 afm.notifyViewEnteredForAugmentedAutofill(this); 9837 } 9838 9839 return getAutofillViewId() > LAST_APP_AUTOFILL_ID; 9840 } 9841 9842 /** @hide */ 9843 public boolean canNotifyAutofillEnterExitEvent() { 9844 return isAutofillable() && isAttachedToWindow(); 9845 } 9846 9847 private void populateVirtualStructure(ViewStructure structure, 9848 AccessibilityNodeProvider provider, AccessibilityNodeInfo info, 9849 boolean forAutofill) { 9850 structure.setId(AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()), 9851 null, null, info.getViewIdResourceName()); 9852 Rect rect = structure.getTempRect(); 9853 info.getBoundsInParent(rect); 9854 structure.setDimens(rect.left, rect.top, 0, 0, rect.width(), rect.height()); 9855 structure.setVisibility(VISIBLE); 9856 structure.setEnabled(info.isEnabled()); 9857 if (info.isClickable()) { 9858 structure.setClickable(true); 9859 } 9860 if (info.isFocusable()) { 9861 structure.setFocusable(true); 9862 } 9863 if (info.isFocused()) { 9864 structure.setFocused(true); 9865 } 9866 if (info.isAccessibilityFocused()) { 9867 structure.setAccessibilityFocused(true); 9868 } 9869 if (info.isSelected()) { 9870 structure.setSelected(true); 9871 } 9872 if (info.isLongClickable()) { 9873 structure.setLongClickable(true); 9874 } 9875 if (info.isCheckable()) { 9876 structure.setCheckable(true); 9877 if (info.isChecked()) { 9878 structure.setChecked(true); 9879 } 9880 } 9881 if (info.isContextClickable()) { 9882 structure.setContextClickable(true); 9883 } 9884 if (forAutofill) { 9885 structure.setAutofillId(new AutofillId(getAutofillId(), 9886 AccessibilityNodeInfo.getVirtualDescendantId(info.getSourceNodeId()))); 9887 } 9888 CharSequence cname = info.getClassName(); 9889 structure.setClassName(cname != null ? cname.toString() : null); 9890 structure.setContentDescription(info.getContentDescription()); 9891 if (forAutofill) { 9892 final int maxTextLength = info.getMaxTextLength(); 9893 if (maxTextLength != -1) { 9894 structure.setMaxTextLength(maxTextLength); 9895 } 9896 structure.setHint(info.getHintText()); 9897 } 9898 CharSequence text = info.getText(); 9899 boolean hasText = text != null || info.getError() != null; 9900 if (hasText) { 9901 structure.setText(text, info.getTextSelectionStart(), info.getTextSelectionEnd()); 9902 } 9903 if (forAutofill) { 9904 if (info.isEditable()) { 9905 structure.setDataIsSensitive(true); 9906 if (hasText) { 9907 structure.setAutofillType(AUTOFILL_TYPE_TEXT); 9908 structure.setAutofillValue(AutofillValue.forText(text)); 9909 } 9910 int inputType = info.getInputType(); 9911 if (inputType == 0 && info.isPassword()) { 9912 inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD; 9913 } 9914 structure.setInputType(inputType); 9915 } else { 9916 structure.setDataIsSensitive(false); 9917 } 9918 } 9919 final int NCHILDREN = info.getChildCount(); 9920 if (NCHILDREN > 0) { 9921 structure.setChildCount(NCHILDREN); 9922 for (int i=0; i<NCHILDREN; i++) { 9923 if (AccessibilityNodeInfo.getVirtualDescendantId(info.getChildNodeIds().get(i)) 9924 == AccessibilityNodeProvider.HOST_VIEW_ID) { 9925 Log.e(VIEW_LOG_TAG, "Virtual view pointing to its host. Ignoring"); 9926 continue; 9927 } 9928 AccessibilityNodeInfo cinfo = provider.createAccessibilityNodeInfo( 9929 AccessibilityNodeInfo.getVirtualDescendantId(info.getChildId(i))); 9930 ViewStructure child = structure.newChild(i); 9931 populateVirtualStructure(child, provider, cinfo, forAutofill); 9932 cinfo.recycle(); 9933 } 9934 } 9935 } 9936 9937 /** 9938 * Dispatch creation of {@link ViewStructure} down the hierarchy. The default 9939 * implementation calls {@link #onProvideStructure} and 9940 * {@link #onProvideVirtualStructure}. 9941 */ 9942 public void dispatchProvideStructure(ViewStructure structure) { 9943 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_ASSIST, /* flags= */ 0); 9944 } 9945 9946 /** 9947 * Dispatches creation of a {@link ViewStructure}s for autofill purposes down the hierarchy, 9948 * when an Assist structure is being created as part of an autofill request. 9949 * 9950 * <p>The default implementation does the following: 9951 * <ul> 9952 * <li>Sets the {@link AutofillId} in the structure. 9953 * <li>Calls {@link #onProvideAutofillStructure(ViewStructure, int)}. 9954 * <li>Calls {@link #onProvideAutofillVirtualStructure(ViewStructure, int)}. 9955 * </ul> 9956 * 9957 * <p>Typically, this method should only be overridden by subclasses that provide a view 9958 * hierarchy (such as {@link ViewGroup}) - other classes should override 9959 * {@link #onProvideAutofillStructure(ViewStructure, int)} or 9960 * {@link #onProvideAutofillVirtualStructure(ViewStructure, int)} instead. 9961 * 9962 * <p>When overridden, it must: 9963 * 9964 * <ul> 9965 * <li>Either call 9966 * {@code super.dispatchProvideAutofillStructure(structure, flags)} or explicitly 9967 * set the {@link AutofillId} in the structure (for example, by calling 9968 * {@code structure.setAutofillId(getAutofillId())}). 9969 * <li>Decide how to handle the {@link #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag - when 9970 * set, all views in the structure should be considered important for autofill, 9971 * regardless of what {@link #isImportantForAutofill()} returns. We encourage you to 9972 * respect this flag to provide a better user experience - this flag is typically used 9973 * when an user explicitly requested autofill. If the flag is not set, 9974 * then only views marked as important for autofill should be included in the 9975 * structure - skipping non-important views optimizes the overall autofill performance. 9976 * </ul> 9977 * 9978 * @param structure fill in with structured view data for autofill purposes. 9979 * @param flags optional flags. 9980 * 9981 * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 9982 */ 9983 public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure, 9984 @AutofillFlags int flags) { 9985 dispatchProvideStructure(structure, VIEW_STRUCTURE_FOR_AUTOFILL, flags); 9986 } 9987 9988 private void dispatchProvideStructure(@NonNull ViewStructure structure, 9989 @ViewStructureType int viewFor, @AutofillFlags int flags) { 9990 if (viewFor == VIEW_STRUCTURE_FOR_AUTOFILL) { 9991 structure.setAutofillId(getAutofillId()); 9992 onProvideAutofillStructure(structure, flags); 9993 onProvideAutofillVirtualStructure(structure, flags); 9994 } else if (!isAssistBlocked()) { 9995 onProvideStructure(structure); 9996 onProvideVirtualStructure(structure); 9997 } else { 9998 structure.setClassName(getAccessibilityClassName().toString()); 9999 structure.setAssistBlocked(true); 10000 } 10001 } 10002 10003 /** 10004 * Dispatches the initial content capture events for a view structure. 10005 * 10006 * @hide 10007 */ 10008 public void dispatchInitialProvideContentCaptureStructure() { 10009 AttachInfo ai = mAttachInfo; 10010 if (ai == null) { 10011 Log.w(CONTENT_CAPTURE_LOG_TAG, 10012 "dispatchProvideContentCaptureStructure(): no AttachInfo for " + this); 10013 return; 10014 } 10015 ContentCaptureManager ccm = ai.mContentCaptureManager; 10016 if (ccm == null) { 10017 Log.w(CONTENT_CAPTURE_LOG_TAG, "dispatchProvideContentCaptureStructure(): " 10018 + "no ContentCaptureManager for " + this); 10019 return; 10020 } 10021 10022 // We must set it before checkign if the view itself is important, because it might 10023 // initially not be (for example, if it's empty), although that might change later (for 10024 // example, if important views are added) 10025 ai.mReadyForContentCaptureUpdates = true; 10026 10027 if (!isImportantForContentCapture()) { 10028 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 10029 Log.d(CONTENT_CAPTURE_LOG_TAG, 10030 "dispatchProvideContentCaptureStructure(): decorView is not important"); 10031 } 10032 return; 10033 } 10034 10035 ai.mContentCaptureManager = ccm; 10036 10037 ContentCaptureSession session = getContentCaptureSession(); 10038 if (session == null) { 10039 if (Log.isLoggable(CONTENT_CAPTURE_LOG_TAG, Log.DEBUG)) { 10040 Log.d(CONTENT_CAPTURE_LOG_TAG, 10041 "dispatchProvideContentCaptureStructure(): no session for " + this); 10042 } 10043 return; 10044 } 10045 10046 session.internalNotifyViewTreeEvent(/* started= */ true); 10047 try { 10048 dispatchProvideContentCaptureStructure(); 10049 } finally { 10050 session.internalNotifyViewTreeEvent(/* started= */ false); 10051 } 10052 } 10053 10054 /** @hide */ 10055 void dispatchProvideContentCaptureStructure() { 10056 ContentCaptureSession session = getContentCaptureSession(); 10057 if (session != null) { 10058 ViewStructure structure = session.newViewStructure(this); 10059 onProvideContentCaptureStructure(structure, /* flags= */ 0); 10060 setNotifiedContentCaptureAppeared(); 10061 session.notifyViewAppeared(structure); 10062 } 10063 } 10064 10065 /** 10066 * @see #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 10067 * 10068 * Note: Called from the default {@link AccessibilityDelegate}. 10069 * 10070 * @hide 10071 */ 10072 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) { 10073 if (mAttachInfo == null) { 10074 return; 10075 } 10076 10077 Rect bounds = mAttachInfo.mTmpInvalRect; 10078 10079 getDrawingRect(bounds); 10080 info.setBoundsInParent(bounds); 10081 10082 getBoundsOnScreen(bounds, true); 10083 info.setBoundsInScreen(bounds); 10084 10085 ViewParent parent = getParentForAccessibility(); 10086 if (parent instanceof View) { 10087 info.setParent((View) parent); 10088 } 10089 10090 if (mID != View.NO_ID) { 10091 View rootView = getRootView(); 10092 if (rootView == null) { 10093 rootView = this; 10094 } 10095 10096 View label = rootView.findLabelForView(this, mID); 10097 if (label != null) { 10098 info.setLabeledBy(label); 10099 } 10100 10101 if ((mAttachInfo.mAccessibilityFetchFlags 10102 & AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS) != 0 10103 && Resources.resourceHasPackage(mID)) { 10104 try { 10105 String viewId = getResources().getResourceName(mID); 10106 info.setViewIdResourceName(viewId); 10107 } catch (Resources.NotFoundException nfe) { 10108 /* ignore */ 10109 } 10110 } 10111 } 10112 10113 if (mLabelForId != View.NO_ID) { 10114 View rootView = getRootView(); 10115 if (rootView == null) { 10116 rootView = this; 10117 } 10118 View labeled = rootView.findViewInsideOutShouldExist(this, mLabelForId); 10119 if (labeled != null) { 10120 info.setLabelFor(labeled); 10121 } 10122 } 10123 10124 if (mAccessibilityTraversalBeforeId != View.NO_ID) { 10125 View rootView = getRootView(); 10126 if (rootView == null) { 10127 rootView = this; 10128 } 10129 View next = rootView.findViewInsideOutShouldExist(this, 10130 mAccessibilityTraversalBeforeId); 10131 if (next != null && next.includeForAccessibility()) { 10132 info.setTraversalBefore(next); 10133 } 10134 } 10135 10136 if (mAccessibilityTraversalAfterId != View.NO_ID) { 10137 View rootView = getRootView(); 10138 if (rootView == null) { 10139 rootView = this; 10140 } 10141 View next = rootView.findViewInsideOutShouldExist(this, 10142 mAccessibilityTraversalAfterId); 10143 if (next != null && next.includeForAccessibility()) { 10144 info.setTraversalAfter(next); 10145 } 10146 } 10147 10148 info.setVisibleToUser(isVisibleToUser()); 10149 10150 info.setImportantForAccessibility(isImportantForAccessibility()); 10151 info.setPackageName(mContext.getPackageName()); 10152 info.setClassName(getAccessibilityClassName()); 10153 info.setStateDescription(getStateDescription()); 10154 info.setContentDescription(getContentDescription()); 10155 10156 info.setEnabled(isEnabled()); 10157 info.setClickable(isClickable()); 10158 info.setFocusable(isFocusable()); 10159 info.setScreenReaderFocusable(isScreenReaderFocusable()); 10160 info.setFocused(isFocused()); 10161 info.setAccessibilityFocused(isAccessibilityFocused()); 10162 info.setSelected(isSelected()); 10163 info.setLongClickable(isLongClickable()); 10164 info.setContextClickable(isContextClickable()); 10165 info.setLiveRegion(getAccessibilityLiveRegion()); 10166 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipText != null)) { 10167 info.setTooltipText(mTooltipInfo.mTooltipText); 10168 info.addAction((mTooltipInfo.mTooltipPopup == null) 10169 ? AccessibilityNodeInfo.AccessibilityAction.ACTION_SHOW_TOOLTIP 10170 : AccessibilityNodeInfo.AccessibilityAction.ACTION_HIDE_TOOLTIP); 10171 } 10172 10173 // TODO: These make sense only if we are in an AdapterView but all 10174 // views can be selected. Maybe from accessibility perspective 10175 // we should report as selectable view in an AdapterView. 10176 info.addAction(AccessibilityNodeInfo.ACTION_SELECT); 10177 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_SELECTION); 10178 10179 if (isFocusable()) { 10180 if (isFocused()) { 10181 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_FOCUS); 10182 } else { 10183 info.addAction(AccessibilityNodeInfo.ACTION_FOCUS); 10184 } 10185 } 10186 10187 if (!isAccessibilityFocused()) { 10188 info.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); 10189 } else { 10190 info.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); 10191 } 10192 10193 if (isClickable() && isEnabled()) { 10194 info.addAction(AccessibilityNodeInfo.ACTION_CLICK); 10195 } 10196 10197 if (isLongClickable() && isEnabled()) { 10198 info.addAction(AccessibilityNodeInfo.ACTION_LONG_CLICK); 10199 } 10200 10201 if (isContextClickable() && isEnabled()) { 10202 info.addAction(AccessibilityAction.ACTION_CONTEXT_CLICK); 10203 } 10204 10205 CharSequence text = getIterableTextForAccessibility(); 10206 if (text != null && text.length() > 0) { 10207 info.setTextSelection(getAccessibilitySelectionStart(), getAccessibilitySelectionEnd()); 10208 10209 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION); 10210 info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY); 10211 info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY); 10212 info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER 10213 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD 10214 | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH); 10215 } 10216 10217 info.addAction(AccessibilityAction.ACTION_SHOW_ON_SCREEN); 10218 populateAccessibilityNodeInfoDrawingOrderInParent(info); 10219 info.setPaneTitle(mAccessibilityPaneTitle); 10220 info.setHeading(isAccessibilityHeading()); 10221 10222 if (mTouchDelegate != null) { 10223 info.setTouchDelegateInfo(mTouchDelegate.getTouchDelegateInfo()); 10224 } 10225 } 10226 10227 /** 10228 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 10229 * additional data. 10230 * <p> 10231 * This method only needs overloading if the node is marked as having extra data available. 10232 * </p> 10233 * 10234 * @param info The info to which to add the extra data. Never {@code null}. 10235 * @param extraDataKey A key specifying the type of extra data to add to the info. The 10236 * extra data should be added to the {@link Bundle} returned by 10237 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 10238 * {@code null}. 10239 * @param arguments A {@link Bundle} holding any arguments relevant for this request. May be 10240 * {@code null} if the service provided no arguments. 10241 * 10242 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 10243 */ 10244 public void addExtraDataToAccessibilityNodeInfo( 10245 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 10246 @Nullable Bundle arguments) { 10247 } 10248 10249 /** 10250 * Determine the order in which this view will be drawn relative to its siblings for a11y 10251 * 10252 * @param info The info whose drawing order should be populated 10253 */ 10254 private void populateAccessibilityNodeInfoDrawingOrderInParent(AccessibilityNodeInfo info) { 10255 /* 10256 * If the view's bounds haven't been set yet, layout has not completed. In that situation, 10257 * drawing order may not be well-defined, and some Views with custom drawing order may 10258 * not be initialized sufficiently to respond properly getChildDrawingOrder. 10259 */ 10260 if ((mPrivateFlags & PFLAG_HAS_BOUNDS) == 0) { 10261 info.setDrawingOrder(0); 10262 return; 10263 } 10264 int drawingOrderInParent = 1; 10265 // Iterate up the hierarchy if parents are not important for a11y 10266 View viewAtDrawingLevel = this; 10267 final ViewParent parent = getParentForAccessibility(); 10268 while (viewAtDrawingLevel != parent) { 10269 final ViewParent currentParent = viewAtDrawingLevel.getParent(); 10270 if (!(currentParent instanceof ViewGroup)) { 10271 // Should only happen for the Decor 10272 drawingOrderInParent = 0; 10273 break; 10274 } else { 10275 final ViewGroup parentGroup = (ViewGroup) currentParent; 10276 final int childCount = parentGroup.getChildCount(); 10277 if (childCount > 1) { 10278 List<View> preorderedList = parentGroup.buildOrderedChildList(); 10279 if (preorderedList != null) { 10280 final int childDrawIndex = preorderedList.indexOf(viewAtDrawingLevel); 10281 for (int i = 0; i < childDrawIndex; i++) { 10282 drawingOrderInParent += numViewsForAccessibility(preorderedList.get(i)); 10283 } 10284 } else { 10285 final int childIndex = parentGroup.indexOfChild(viewAtDrawingLevel); 10286 final boolean customOrder = parentGroup.isChildrenDrawingOrderEnabled(); 10287 final int childDrawIndex = ((childIndex >= 0) && customOrder) ? parentGroup 10288 .getChildDrawingOrder(childCount, childIndex) : childIndex; 10289 final int numChildrenToIterate = customOrder ? childCount : childDrawIndex; 10290 if (childDrawIndex != 0) { 10291 for (int i = 0; i < numChildrenToIterate; i++) { 10292 final int otherDrawIndex = (customOrder ? 10293 parentGroup.getChildDrawingOrder(childCount, i) : i); 10294 if (otherDrawIndex < childDrawIndex) { 10295 drawingOrderInParent += 10296 numViewsForAccessibility(parentGroup.getChildAt(i)); 10297 } 10298 } 10299 } 10300 } 10301 } 10302 } 10303 viewAtDrawingLevel = (View) currentParent; 10304 } 10305 info.setDrawingOrder(drawingOrderInParent); 10306 } 10307 10308 private static int numViewsForAccessibility(View view) { 10309 if (view != null) { 10310 if (view.includeForAccessibility()) { 10311 return 1; 10312 } else if (view instanceof ViewGroup) { 10313 return ((ViewGroup) view).getNumChildrenForAccessibility(); 10314 } 10315 } 10316 return 0; 10317 } 10318 10319 private View findLabelForView(View view, int labeledId) { 10320 if (mMatchLabelForPredicate == null) { 10321 mMatchLabelForPredicate = new MatchLabelForPredicate(); 10322 } 10323 mMatchLabelForPredicate.mLabeledId = labeledId; 10324 return findViewByPredicateInsideOut(view, mMatchLabelForPredicate); 10325 } 10326 10327 /** 10328 * Computes whether this virtual autofill view is visible to the user. 10329 * 10330 * <p><b>Note: </b>By default it returns {@code true}, but views providing a virtual hierarchy 10331 * view must override it. 10332 * 10333 * @return Whether the view is visible on the screen. 10334 */ 10335 public boolean isVisibleToUserForAutofill(int virtualId) { 10336 if (mContext.isAutofillCompatibilityEnabled()) { 10337 final AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); 10338 if (provider != null) { 10339 final AccessibilityNodeInfo node = provider.createAccessibilityNodeInfo(virtualId); 10340 if (node != null) { 10341 return node.isVisibleToUser(); 10342 } 10343 // if node is null, assume it's not visible anymore 10344 } else { 10345 Log.w(VIEW_LOG_TAG, "isVisibleToUserForAutofill(" + virtualId + "): no provider"); 10346 } 10347 return false; 10348 } 10349 return true; 10350 } 10351 10352 /** 10353 * Computes whether this view is visible to the user. Such a view is 10354 * attached, visible, all its predecessors are visible, it is not clipped 10355 * entirely by its predecessors, and has an alpha greater than zero. 10356 * 10357 * @return Whether the view is visible on the screen. 10358 * 10359 * @hide 10360 */ 10361 @UnsupportedAppUsage 10362 public boolean isVisibleToUser() { 10363 return isVisibleToUser(null); 10364 } 10365 10366 /** 10367 * Computes whether the given portion of this view is visible to the user. 10368 * Such a view is attached, visible, all its predecessors are visible, 10369 * has an alpha greater than zero, and the specified portion is not 10370 * clipped entirely by its predecessors. 10371 * 10372 * @param boundInView the portion of the view to test; coordinates should be relative; may be 10373 * <code>null</code>, and the entire view will be tested in this case. 10374 * When <code>true</code> is returned by the function, the actual visible 10375 * region will be stored in this parameter; that is, if boundInView is fully 10376 * contained within the view, no modification will be made, otherwise regions 10377 * outside of the visible area of the view will be clipped. 10378 * 10379 * @return Whether the specified portion of the view is visible on the screen. 10380 * 10381 * @hide 10382 */ 10383 @UnsupportedAppUsage 10384 protected boolean isVisibleToUser(Rect boundInView) { 10385 if (mAttachInfo != null) { 10386 // Attached to invisible window means this view is not visible. 10387 if (mAttachInfo.mWindowVisibility != View.VISIBLE) { 10388 return false; 10389 } 10390 // An invisible predecessor or one with alpha zero means 10391 // that this view is not visible to the user. 10392 Object current = this; 10393 while (current instanceof View) { 10394 View view = (View) current; 10395 // We have attach info so this view is attached and there is no 10396 // need to check whether we reach to ViewRootImpl on the way up. 10397 if (view.getAlpha() <= 0 || view.getTransitionAlpha() <= 0 || 10398 view.getVisibility() != VISIBLE) { 10399 return false; 10400 } 10401 current = view.mParent; 10402 } 10403 // Check if the view is entirely covered by its predecessors. 10404 Rect visibleRect = mAttachInfo.mTmpInvalRect; 10405 Point offset = mAttachInfo.mPoint; 10406 if (!getGlobalVisibleRect(visibleRect, offset)) { 10407 return false; 10408 } 10409 // Check if the visible portion intersects the rectangle of interest. 10410 if (boundInView != null) { 10411 visibleRect.offset(-offset.x, -offset.y); 10412 return boundInView.intersect(visibleRect); 10413 } 10414 return true; 10415 } 10416 return false; 10417 } 10418 10419 /** 10420 * Returns the delegate for implementing accessibility support via 10421 * composition. For more details see {@link AccessibilityDelegate}. 10422 * 10423 * @return The delegate, or null if none set. 10424 */ 10425 public AccessibilityDelegate getAccessibilityDelegate() { 10426 return mAccessibilityDelegate; 10427 } 10428 10429 /** 10430 * Sets a delegate for implementing accessibility support via composition 10431 * (as opposed to inheritance). For more details, see 10432 * {@link AccessibilityDelegate}. 10433 * <p> 10434 * <strong>Note:</strong> On platform versions prior to 10435 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 10436 * views in the {@code android.widget.*} package are called <i>before</i> 10437 * host methods. This prevents certain properties such as class name from 10438 * being modified by overriding 10439 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 10440 * as any changes will be overwritten by the host class. 10441 * <p> 10442 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 10443 * methods are called <i>after</i> host methods, which all properties to be 10444 * modified without being overwritten by the host class. 10445 * 10446 * @param delegate the object to which accessibility method calls should be 10447 * delegated 10448 * @see AccessibilityDelegate 10449 */ 10450 public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) { 10451 mAccessibilityDelegate = delegate; 10452 } 10453 10454 /** 10455 * Gets the provider for managing a virtual view hierarchy rooted at this View 10456 * and reported to {@link android.accessibilityservice.AccessibilityService}s 10457 * that explore the window content. 10458 * <p> 10459 * If this method returns an instance, this instance is responsible for managing 10460 * {@link AccessibilityNodeInfo}s describing the virtual sub-tree rooted at this 10461 * View including the one representing the View itself. Similarly the returned 10462 * instance is responsible for performing accessibility actions on any virtual 10463 * view or the root view itself. 10464 * </p> 10465 * <p> 10466 * If an {@link AccessibilityDelegate} has been specified via calling 10467 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 10468 * {@link AccessibilityDelegate#getAccessibilityNodeProvider(View)} 10469 * is responsible for handling this call. 10470 * </p> 10471 * 10472 * @return The provider. 10473 * 10474 * @see AccessibilityNodeProvider 10475 */ 10476 public AccessibilityNodeProvider getAccessibilityNodeProvider() { 10477 if (mAccessibilityDelegate != null) { 10478 return mAccessibilityDelegate.getAccessibilityNodeProvider(this); 10479 } else { 10480 return null; 10481 } 10482 } 10483 10484 /** 10485 * Gets the unique identifier of this view on the screen for accessibility purposes. 10486 * 10487 * @return The view accessibility id. 10488 * 10489 * @hide 10490 */ 10491 @UnsupportedAppUsage 10492 public int getAccessibilityViewId() { 10493 if (mAccessibilityViewId == NO_ID) { 10494 mAccessibilityViewId = sNextAccessibilityViewId++; 10495 } 10496 return mAccessibilityViewId; 10497 } 10498 10499 /** 10500 * Gets the unique identifier of this view on the screen for autofill purposes. 10501 * 10502 * @return The view autofill id. 10503 * 10504 * @hide 10505 */ 10506 public int getAutofillViewId() { 10507 if (mAutofillViewId == NO_ID) { 10508 mAutofillViewId = mContext.getNextAutofillId(); 10509 } 10510 return mAutofillViewId; 10511 } 10512 10513 /** 10514 * Gets the unique identifier of the window in which this View resides. 10515 * 10516 * @return The window accessibility id. 10517 * 10518 * @hide 10519 */ 10520 public int getAccessibilityWindowId() { 10521 return mAttachInfo != null ? mAttachInfo.mAccessibilityWindowId 10522 : AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 10523 } 10524 10525 /** 10526 * Returns the {@link View}'s state description. 10527 * <p> 10528 * <strong>Note:</strong> Do not override this method, as it will have no 10529 * effect on the state description presented to accessibility services. 10530 * You must call {@link #setStateDescription(CharSequence)} to modify the 10531 * state description. 10532 * 10533 * @return the state description 10534 * @see #setStateDescription(CharSequence) 10535 */ 10536 @ViewDebug.ExportedProperty(category = "accessibility") 10537 public final @Nullable CharSequence getStateDescription() { 10538 return mStateDescription; 10539 } 10540 10541 /** 10542 * Returns the {@link View}'s content description. 10543 * <p> 10544 * <strong>Note:</strong> Do not override this method, as it will have no 10545 * effect on the content description presented to accessibility services. 10546 * You must call {@link #setContentDescription(CharSequence)} to modify the 10547 * content description. 10548 * 10549 * @return the content description 10550 * @see #setContentDescription(CharSequence) 10551 * @attr ref android.R.styleable#View_contentDescription 10552 */ 10553 @ViewDebug.ExportedProperty(category = "accessibility") 10554 @InspectableProperty 10555 public CharSequence getContentDescription() { 10556 return mContentDescription; 10557 } 10558 10559 /** 10560 * Sets the {@link View}'s state description. 10561 * <p> 10562 * A state description briefly describes the states of the view and is primarily used 10563 * for accessibility support to determine how the states of a view should be presented to 10564 * the user. It is a supplement to the boolean states (for example, checked/unchecked) and 10565 * it is used for customized state description (for example, "wifi, connected, three bars"). 10566 * State description changes frequently while content description should change less often. 10567 * State description should be localized. For android widgets which have default state 10568 * descriptions, app developers can call this method to override the state descriptions. 10569 * Setting state description to null restores the default behavior. 10570 * 10571 * @param stateDescription The state description. 10572 * @see #getStateDescription() 10573 */ 10574 @RemotableViewMethod 10575 public void setStateDescription(@Nullable CharSequence stateDescription) { 10576 if (mStateDescription == null) { 10577 if (stateDescription == null) { 10578 return; 10579 } 10580 } else if (mStateDescription.equals(stateDescription)) { 10581 return; 10582 } 10583 mStateDescription = stateDescription; 10584 if (!TextUtils.isEmpty(stateDescription) 10585 && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 10586 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 10587 } 10588 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 10589 AccessibilityEvent event = AccessibilityEvent.obtain(); 10590 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 10591 event.setContentChangeTypes(AccessibilityEvent.CONTENT_CHANGE_TYPE_STATE_DESCRIPTION); 10592 sendAccessibilityEventUnchecked(event); 10593 } 10594 } 10595 10596 /** 10597 * Sets the {@link View}'s content description. 10598 * <p> 10599 * A content description briefly describes the view and is primarily used 10600 * for accessibility support to determine how a view should be presented to 10601 * the user. In the case of a view with no textual representation, such as 10602 * {@link android.widget.ImageButton}, a useful content description 10603 * explains what the view does. For example, an image button with a phone 10604 * icon that is used to place a call may use "Call" as its content 10605 * description. An image of a floppy disk that is used to save a file may 10606 * use "Save". 10607 * 10608 * @param contentDescription The content description. 10609 * @see #getContentDescription() 10610 * @attr ref android.R.styleable#View_contentDescription 10611 */ 10612 @RemotableViewMethod 10613 public void setContentDescription(CharSequence contentDescription) { 10614 if (mContentDescription == null) { 10615 if (contentDescription == null) { 10616 return; 10617 } 10618 } else if (mContentDescription.equals(contentDescription)) { 10619 return; 10620 } 10621 mContentDescription = contentDescription; 10622 final boolean nonEmptyDesc = contentDescription != null && contentDescription.length() > 0; 10623 if (nonEmptyDesc && getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { 10624 setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); 10625 notifySubtreeAccessibilityStateChangedIfNeeded(); 10626 } else { 10627 notifyViewAccessibilityStateChangedIfNeeded( 10628 AccessibilityEvent.CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION); 10629 } 10630 } 10631 10632 /** 10633 * Sets the id of a view before which this one is visited in accessibility traversal. 10634 * A screen-reader must visit the content of this view before the content of the one 10635 * it precedes. For example, if view B is set to be before view A, then a screen-reader 10636 * will traverse the entire content of B before traversing the entire content of A, 10637 * regardles of what traversal strategy it is using. 10638 * <p> 10639 * Views that do not have specified before/after relationships are traversed in order 10640 * determined by the screen-reader. 10641 * </p> 10642 * <p> 10643 * Setting that this view is before a view that is not important for accessibility 10644 * or if this view is not important for accessibility will have no effect as the 10645 * screen-reader is not aware of unimportant views. 10646 * </p> 10647 * 10648 * @param beforeId The id of a view this one precedes in accessibility traversal. 10649 * 10650 * @attr ref android.R.styleable#View_accessibilityTraversalBefore 10651 * 10652 * @see #setImportantForAccessibility(int) 10653 */ 10654 @RemotableViewMethod 10655 public void setAccessibilityTraversalBefore(@IdRes int beforeId) { 10656 if (mAccessibilityTraversalBeforeId == beforeId) { 10657 return; 10658 } 10659 mAccessibilityTraversalBeforeId = beforeId; 10660 notifyViewAccessibilityStateChangedIfNeeded( 10661 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10662 } 10663 10664 /** 10665 * Gets the id of a view before which this one is visited in accessibility traversal. 10666 * 10667 * @return The id of a view this one precedes in accessibility traversal if 10668 * specified, otherwise {@link #NO_ID}. 10669 * 10670 * @see #setAccessibilityTraversalBefore(int) 10671 */ 10672 @IdRes 10673 @InspectableProperty 10674 public int getAccessibilityTraversalBefore() { 10675 return mAccessibilityTraversalBeforeId; 10676 } 10677 10678 /** 10679 * Sets the id of a view after which this one is visited in accessibility traversal. 10680 * A screen-reader must visit the content of the other view before the content of this 10681 * one. For example, if view B is set to be after view A, then a screen-reader 10682 * will traverse the entire content of A before traversing the entire content of B, 10683 * regardles of what traversal strategy it is using. 10684 * <p> 10685 * Views that do not have specified before/after relationships are traversed in order 10686 * determined by the screen-reader. 10687 * </p> 10688 * <p> 10689 * Setting that this view is after a view that is not important for accessibility 10690 * or if this view is not important for accessibility will have no effect as the 10691 * screen-reader is not aware of unimportant views. 10692 * </p> 10693 * 10694 * @param afterId The id of a view this one succedees in accessibility traversal. 10695 * 10696 * @attr ref android.R.styleable#View_accessibilityTraversalAfter 10697 * 10698 * @see #setImportantForAccessibility(int) 10699 */ 10700 @RemotableViewMethod 10701 public void setAccessibilityTraversalAfter(@IdRes int afterId) { 10702 if (mAccessibilityTraversalAfterId == afterId) { 10703 return; 10704 } 10705 mAccessibilityTraversalAfterId = afterId; 10706 notifyViewAccessibilityStateChangedIfNeeded( 10707 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10708 } 10709 10710 /** 10711 * Gets the id of a view after which this one is visited in accessibility traversal. 10712 * 10713 * @return The id of a view this one succeedes in accessibility traversal if 10714 * specified, otherwise {@link #NO_ID}. 10715 * 10716 * @see #setAccessibilityTraversalAfter(int) 10717 */ 10718 @IdRes 10719 @InspectableProperty 10720 public int getAccessibilityTraversalAfter() { 10721 return mAccessibilityTraversalAfterId; 10722 } 10723 10724 /** 10725 * Gets the id of a view for which this view serves as a label for 10726 * accessibility purposes. 10727 * 10728 * @return The labeled view id. 10729 */ 10730 @IdRes 10731 @ViewDebug.ExportedProperty(category = "accessibility") 10732 @InspectableProperty 10733 public int getLabelFor() { 10734 return mLabelForId; 10735 } 10736 10737 /** 10738 * Sets the id of a view for which this view serves as a label for 10739 * accessibility purposes. 10740 * 10741 * @param id The labeled view id. 10742 */ 10743 @RemotableViewMethod 10744 public void setLabelFor(@IdRes int id) { 10745 if (mLabelForId == id) { 10746 return; 10747 } 10748 mLabelForId = id; 10749 if (mLabelForId != View.NO_ID 10750 && mID == View.NO_ID) { 10751 mID = generateViewId(); 10752 } 10753 notifyViewAccessibilityStateChangedIfNeeded( 10754 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 10755 } 10756 10757 /** 10758 * Invoked whenever this view loses focus, either by losing window focus or by losing 10759 * focus within its window. This method can be used to clear any state tied to the 10760 * focus. For instance, if a button is held pressed with the trackball and the window 10761 * loses focus, this method can be used to cancel the press. 10762 * 10763 * Subclasses of View overriding this method should always call super.onFocusLost(). 10764 * 10765 * @see #onFocusChanged(boolean, int, android.graphics.Rect) 10766 * @see #onWindowFocusChanged(boolean) 10767 * 10768 * @hide pending API council approval 10769 */ 10770 @CallSuper 10771 @UnsupportedAppUsage 10772 protected void onFocusLost() { 10773 resetPressedState(); 10774 } 10775 10776 private void resetPressedState() { 10777 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 10778 return; 10779 } 10780 10781 if (isPressed()) { 10782 setPressed(false); 10783 10784 if (!mHasPerformedLongPress) { 10785 removeLongPressCallback(); 10786 } 10787 } 10788 } 10789 10790 /** 10791 * Returns true if this view has focus 10792 * 10793 * @return True if this view has focus, false otherwise. 10794 */ 10795 @ViewDebug.ExportedProperty(category = "focus") 10796 @InspectableProperty(hasAttributeId = false) 10797 public boolean isFocused() { 10798 return (mPrivateFlags & PFLAG_FOCUSED) != 0; 10799 } 10800 10801 /** 10802 * Find the view in the hierarchy rooted at this view that currently has 10803 * focus. 10804 * 10805 * @return The view that currently has focus, or null if no focused view can 10806 * be found. 10807 */ 10808 public View findFocus() { 10809 return (mPrivateFlags & PFLAG_FOCUSED) != 0 ? this : null; 10810 } 10811 10812 /** 10813 * Indicates whether this view is one of the set of scrollable containers in 10814 * its window. 10815 * 10816 * @return whether this view is one of the set of scrollable containers in 10817 * its window 10818 * 10819 * @attr ref android.R.styleable#View_isScrollContainer 10820 */ 10821 @InspectableProperty(name = "isScrollContainer") 10822 public boolean isScrollContainer() { 10823 return (mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0; 10824 } 10825 10826 /** 10827 * Change whether this view is one of the set of scrollable containers in 10828 * its window. This will be used to determine whether the window can 10829 * resize or must pan when a soft input area is open -- scrollable 10830 * containers allow the window to use resize mode since the container 10831 * will appropriately shrink. 10832 * 10833 * @attr ref android.R.styleable#View_isScrollContainer 10834 */ 10835 public void setScrollContainer(boolean isScrollContainer) { 10836 if (isScrollContainer) { 10837 if (mAttachInfo != null && (mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) == 0) { 10838 mAttachInfo.mScrollContainers.add(this); 10839 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 10840 } 10841 mPrivateFlags |= PFLAG_SCROLL_CONTAINER; 10842 } else { 10843 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 10844 mAttachInfo.mScrollContainers.remove(this); 10845 } 10846 mPrivateFlags &= ~(PFLAG_SCROLL_CONTAINER|PFLAG_SCROLL_CONTAINER_ADDED); 10847 } 10848 } 10849 10850 /** 10851 * Returns the quality of the drawing cache. 10852 * 10853 * @return One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 10854 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 10855 * 10856 * @see #setDrawingCacheQuality(int) 10857 * @see #setDrawingCacheEnabled(boolean) 10858 * @see #isDrawingCacheEnabled() 10859 * 10860 * @attr ref android.R.styleable#View_drawingCacheQuality 10861 * 10862 * @deprecated The view drawing cache was largely made obsolete with the introduction of 10863 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 10864 * layers are largely unnecessary and can easily result in a net loss in performance due to the 10865 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 10866 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 10867 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 10868 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 10869 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 10870 * software-rendered usages are discouraged and have compatibility issues with hardware-only 10871 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 10872 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 10873 * reports or unit testing the {@link PixelCopy} API is recommended. 10874 */ 10875 @Deprecated 10876 @DrawingCacheQuality 10877 @InspectableProperty(enumMapping = { 10878 @EnumEntry(value = DRAWING_CACHE_QUALITY_LOW, name = "low"), 10879 @EnumEntry(value = DRAWING_CACHE_QUALITY_HIGH, name = "high"), 10880 @EnumEntry(value = DRAWING_CACHE_QUALITY_AUTO, name = "auto") 10881 }) 10882 public int getDrawingCacheQuality() { 10883 return mViewFlags & DRAWING_CACHE_QUALITY_MASK; 10884 } 10885 10886 /** 10887 * Set the drawing cache quality of this view. This value is used only when the 10888 * drawing cache is enabled 10889 * 10890 * @param quality One of {@link #DRAWING_CACHE_QUALITY_AUTO}, 10891 * {@link #DRAWING_CACHE_QUALITY_LOW}, or {@link #DRAWING_CACHE_QUALITY_HIGH} 10892 * 10893 * @see #getDrawingCacheQuality() 10894 * @see #setDrawingCacheEnabled(boolean) 10895 * @see #isDrawingCacheEnabled() 10896 * 10897 * @attr ref android.R.styleable#View_drawingCacheQuality 10898 * 10899 * @deprecated The view drawing cache was largely made obsolete with the introduction of 10900 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 10901 * layers are largely unnecessary and can easily result in a net loss in performance due to the 10902 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 10903 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 10904 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 10905 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 10906 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 10907 * software-rendered usages are discouraged and have compatibility issues with hardware-only 10908 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 10909 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 10910 * reports or unit testing the {@link PixelCopy} API is recommended. 10911 */ 10912 @Deprecated 10913 public void setDrawingCacheQuality(@DrawingCacheQuality int quality) { 10914 setFlags(quality, DRAWING_CACHE_QUALITY_MASK); 10915 } 10916 10917 /** 10918 * Returns whether the screen should remain on, corresponding to the current 10919 * value of {@link #KEEP_SCREEN_ON}. 10920 * 10921 * @return Returns true if {@link #KEEP_SCREEN_ON} is set. 10922 * 10923 * @see #setKeepScreenOn(boolean) 10924 * 10925 * @attr ref android.R.styleable#View_keepScreenOn 10926 */ 10927 @InspectableProperty 10928 public boolean getKeepScreenOn() { 10929 return (mViewFlags & KEEP_SCREEN_ON) != 0; 10930 } 10931 10932 /** 10933 * Controls whether the screen should remain on, modifying the 10934 * value of {@link #KEEP_SCREEN_ON}. 10935 * 10936 * @param keepScreenOn Supply true to set {@link #KEEP_SCREEN_ON}. 10937 * 10938 * @see #getKeepScreenOn() 10939 * 10940 * @attr ref android.R.styleable#View_keepScreenOn 10941 */ 10942 public void setKeepScreenOn(boolean keepScreenOn) { 10943 setFlags(keepScreenOn ? KEEP_SCREEN_ON : 0, KEEP_SCREEN_ON); 10944 } 10945 10946 /** 10947 * Gets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 10948 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 10949 * 10950 * @attr ref android.R.styleable#View_nextFocusLeft 10951 */ 10952 @IdRes 10953 @InspectableProperty(name = "nextFocusLeft") 10954 public int getNextFocusLeftId() { 10955 return mNextFocusLeftId; 10956 } 10957 10958 /** 10959 * Sets the id of the view to use when the next focus is {@link #FOCUS_LEFT}. 10960 * @param nextFocusLeftId The next focus ID, or {@link #NO_ID} if the framework should 10961 * decide automatically. 10962 * 10963 * @attr ref android.R.styleable#View_nextFocusLeft 10964 */ 10965 public void setNextFocusLeftId(@IdRes int nextFocusLeftId) { 10966 mNextFocusLeftId = nextFocusLeftId; 10967 } 10968 10969 /** 10970 * Gets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 10971 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 10972 * 10973 * @attr ref android.R.styleable#View_nextFocusRight 10974 */ 10975 @IdRes 10976 @InspectableProperty(name = "nextFocusRight") 10977 public int getNextFocusRightId() { 10978 return mNextFocusRightId; 10979 } 10980 10981 /** 10982 * Sets the id of the view to use when the next focus is {@link #FOCUS_RIGHT}. 10983 * @param nextFocusRightId The next focus ID, or {@link #NO_ID} if the framework should 10984 * decide automatically. 10985 * 10986 * @attr ref android.R.styleable#View_nextFocusRight 10987 */ 10988 public void setNextFocusRightId(@IdRes int nextFocusRightId) { 10989 mNextFocusRightId = nextFocusRightId; 10990 } 10991 10992 /** 10993 * Gets the id of the view to use when the next focus is {@link #FOCUS_UP}. 10994 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 10995 * 10996 * @attr ref android.R.styleable#View_nextFocusUp 10997 */ 10998 @IdRes 10999 @InspectableProperty(name = "nextFocusUp") 11000 public int getNextFocusUpId() { 11001 return mNextFocusUpId; 11002 } 11003 11004 /** 11005 * Sets the id of the view to use when the next focus is {@link #FOCUS_UP}. 11006 * @param nextFocusUpId The next focus ID, or {@link #NO_ID} if the framework should 11007 * decide automatically. 11008 * 11009 * @attr ref android.R.styleable#View_nextFocusUp 11010 */ 11011 public void setNextFocusUpId(@IdRes int nextFocusUpId) { 11012 mNextFocusUpId = nextFocusUpId; 11013 } 11014 11015 /** 11016 * Gets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 11017 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11018 * 11019 * @attr ref android.R.styleable#View_nextFocusDown 11020 */ 11021 @IdRes 11022 @InspectableProperty(name = "nextFocusDown") 11023 public int getNextFocusDownId() { 11024 return mNextFocusDownId; 11025 } 11026 11027 /** 11028 * Sets the id of the view to use when the next focus is {@link #FOCUS_DOWN}. 11029 * @param nextFocusDownId The next focus ID, or {@link #NO_ID} if the framework should 11030 * decide automatically. 11031 * 11032 * @attr ref android.R.styleable#View_nextFocusDown 11033 */ 11034 public void setNextFocusDownId(@IdRes int nextFocusDownId) { 11035 mNextFocusDownId = nextFocusDownId; 11036 } 11037 11038 /** 11039 * Gets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 11040 * @return The next focus ID, or {@link #NO_ID} if the framework should decide automatically. 11041 * 11042 * @attr ref android.R.styleable#View_nextFocusForward 11043 */ 11044 @IdRes 11045 @InspectableProperty(name = "nextFocusForward") 11046 public int getNextFocusForwardId() { 11047 return mNextFocusForwardId; 11048 } 11049 11050 /** 11051 * Sets the id of the view to use when the next focus is {@link #FOCUS_FORWARD}. 11052 * @param nextFocusForwardId The next focus ID, or {@link #NO_ID} if the framework should 11053 * decide automatically. 11054 * 11055 * @attr ref android.R.styleable#View_nextFocusForward 11056 */ 11057 public void setNextFocusForwardId(@IdRes int nextFocusForwardId) { 11058 mNextFocusForwardId = nextFocusForwardId; 11059 } 11060 11061 /** 11062 * Gets the id of the root of the next keyboard navigation cluster. 11063 * @return The next keyboard navigation cluster ID, or {@link #NO_ID} if the framework should 11064 * decide automatically. 11065 * 11066 * @attr ref android.R.styleable#View_nextClusterForward 11067 */ 11068 @IdRes 11069 @InspectableProperty(name = "nextClusterForward") 11070 public int getNextClusterForwardId() { 11071 return mNextClusterForwardId; 11072 } 11073 11074 /** 11075 * Sets the id of the view to use as the root of the next keyboard navigation cluster. 11076 * @param nextClusterForwardId The next cluster ID, or {@link #NO_ID} if the framework should 11077 * decide automatically. 11078 * 11079 * @attr ref android.R.styleable#View_nextClusterForward 11080 */ 11081 public void setNextClusterForwardId(@IdRes int nextClusterForwardId) { 11082 mNextClusterForwardId = nextClusterForwardId; 11083 } 11084 11085 /** 11086 * Returns the visibility of this view and all of its ancestors 11087 * 11088 * @return True if this view and all of its ancestors are {@link #VISIBLE} 11089 */ 11090 public boolean isShown() { 11091 View current = this; 11092 //noinspection ConstantConditions 11093 do { 11094 if ((current.mViewFlags & VISIBILITY_MASK) != VISIBLE) { 11095 return false; 11096 } 11097 ViewParent parent = current.mParent; 11098 if (parent == null) { 11099 return false; // We are not attached to the view root 11100 } 11101 if (!(parent instanceof View)) { 11102 return true; 11103 } 11104 current = (View) parent; 11105 } while (current != null); 11106 11107 return false; 11108 } 11109 11110 /** 11111 * Called by the view hierarchy when the content insets for a window have 11112 * changed, to allow it to adjust its content to fit within those windows. 11113 * The content insets tell you the space that the status bar, input method, 11114 * and other system windows infringe on the application's window. 11115 * 11116 * <p>You do not normally need to deal with this function, since the default 11117 * window decoration given to applications takes care of applying it to the 11118 * content of the window. If you use {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN} 11119 * or {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION} this will not be the case, 11120 * and your content can be placed under those system elements. You can then 11121 * use this method within your view hierarchy if you have parts of your UI 11122 * which you would like to ensure are not being covered. 11123 * 11124 * <p>The default implementation of this method simply applies the content 11125 * insets to the view's padding, consuming that content (modifying the 11126 * insets to be 0), and returning true. This behavior is off by default, but can 11127 * be enabled through {@link #setFitsSystemWindows(boolean)}. 11128 * 11129 * <p>This function's traversal down the hierarchy is depth-first. The same content 11130 * insets object is propagated down the hierarchy, so any changes made to it will 11131 * be seen by all following views (including potentially ones above in 11132 * the hierarchy since this is a depth-first traversal). The first view 11133 * that returns true will abort the entire traversal. 11134 * 11135 * <p>The default implementation works well for a situation where it is 11136 * used with a container that covers the entire window, allowing it to 11137 * apply the appropriate insets to its content on all edges. If you need 11138 * a more complicated layout (such as two different views fitting system 11139 * windows, one on the top of the window, and one on the bottom), 11140 * you can override the method and handle the insets however you would like. 11141 * Note that the insets provided by the framework are always relative to the 11142 * far edges of the window, not accounting for the location of the called view 11143 * within that window. (In fact when this method is called you do not yet know 11144 * where the layout will place the view, as it is done before layout happens.) 11145 * 11146 * <p>Note: unlike many View methods, there is no dispatch phase to this 11147 * call. If you are overriding it in a ViewGroup and want to allow the 11148 * call to continue to your children, you must be sure to call the super 11149 * implementation. 11150 * 11151 * <p>Here is a sample layout that makes use of fitting system windows 11152 * to have controls for a video view placed inside of the window decorations 11153 * that it hides and shows. This can be used with code like the second 11154 * sample (video player) shown in {@link #setSystemUiVisibility(int)}. 11155 * 11156 * {@sample development/samples/ApiDemos/res/layout/video_player.xml complete} 11157 * 11158 * @param insets Current content insets of the window. Prior to 11159 * {@link android.os.Build.VERSION_CODES#JELLY_BEAN} you must not modify 11160 * the insets or else you and Android will be unhappy. 11161 * 11162 * @return {@code true} if this view applied the insets and it should not 11163 * continue propagating further down the hierarchy, {@code false} otherwise. 11164 * @see #getFitsSystemWindows() 11165 * @see #setFitsSystemWindows(boolean) 11166 * @see #setSystemUiVisibility(int) 11167 * 11168 * @deprecated As of API 20 use {@link #dispatchApplyWindowInsets(WindowInsets)} to apply 11169 * insets to views. Views should override {@link #onApplyWindowInsets(WindowInsets)} or use 11170 * {@link #setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener)} 11171 * to implement handling their own insets. 11172 */ 11173 @Deprecated 11174 protected boolean fitSystemWindows(Rect insets) { 11175 if ((mPrivateFlags3 & PFLAG3_APPLYING_INSETS) == 0) { 11176 if (insets == null) { 11177 // Null insets by definition have already been consumed. 11178 // This call cannot apply insets since there are none to apply, 11179 // so return false. 11180 return false; 11181 } 11182 // If we're not in the process of dispatching the newer apply insets call, 11183 // that means we're not in the compatibility path. Dispatch into the newer 11184 // apply insets path and take things from there. 11185 try { 11186 mPrivateFlags3 |= PFLAG3_FITTING_SYSTEM_WINDOWS; 11187 return dispatchApplyWindowInsets(new WindowInsets(insets)).isConsumed(); 11188 } finally { 11189 mPrivateFlags3 &= ~PFLAG3_FITTING_SYSTEM_WINDOWS; 11190 } 11191 } else { 11192 // We're being called from the newer apply insets path. 11193 // Perform the standard fallback behavior. 11194 return fitSystemWindowsInt(insets); 11195 } 11196 } 11197 11198 private boolean fitSystemWindowsInt(Rect insets) { 11199 if ((mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS) { 11200 Rect localInsets = sThreadLocal.get(); 11201 boolean res = computeFitSystemWindows(insets, localInsets); 11202 applyInsets(localInsets); 11203 return res; 11204 } 11205 return false; 11206 } 11207 11208 private void applyInsets(Rect insets) { 11209 mUserPaddingStart = UNDEFINED_PADDING; 11210 mUserPaddingEnd = UNDEFINED_PADDING; 11211 mUserPaddingLeftInitial = insets.left; 11212 mUserPaddingRightInitial = insets.right; 11213 internalSetPadding(insets.left, insets.top, insets.right, insets.bottom); 11214 } 11215 11216 /** 11217 * Called when the view should apply {@link WindowInsets} according to its internal policy. 11218 * 11219 * <p>This method should be overridden by views that wish to apply a policy different from or 11220 * in addition to the default behavior. Clients that wish to force a view subtree 11221 * to apply insets should call {@link #dispatchApplyWindowInsets(WindowInsets)}.</p> 11222 * 11223 * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set 11224 * it will be called during dispatch instead of this method. The listener may optionally 11225 * call this method from its own implementation if it wishes to apply the view's default 11226 * insets policy in addition to its own.</p> 11227 * 11228 * <p>Implementations of this method should either return the insets parameter unchanged 11229 * or a new {@link WindowInsets} cloned from the supplied insets with any insets consumed 11230 * that this view applied itself. This allows new inset types added in future platform 11231 * versions to pass through existing implementations unchanged without being erroneously 11232 * consumed.</p> 11233 * 11234 * <p>By default if a view's {@link #setFitsSystemWindows(boolean) fitsSystemWindows} 11235 * property is set then the view will consume the system window insets and apply them 11236 * as padding for the view.</p> 11237 * 11238 * @param insets Insets to apply 11239 * @return The supplied insets with any applied insets consumed 11240 */ 11241 public WindowInsets onApplyWindowInsets(WindowInsets insets) { 11242 if ((mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 11243 && (mViewFlags & FITS_SYSTEM_WINDOWS) != 0) { 11244 return onApplyFrameworkOptionalFitSystemWindows(insets); 11245 } 11246 if ((mPrivateFlags3 & PFLAG3_FITTING_SYSTEM_WINDOWS) == 0) { 11247 // We weren't called from within a direct call to fitSystemWindows, 11248 // call into it as a fallback in case we're in a class that overrides it 11249 // and has logic to perform. 11250 if (fitSystemWindows(insets.getSystemWindowInsetsAsRect())) { 11251 return insets.consumeSystemWindowInsets(); 11252 } 11253 } else { 11254 // We were called from within a direct call to fitSystemWindows. 11255 if (fitSystemWindowsInt(insets.getSystemWindowInsetsAsRect())) { 11256 return insets.consumeSystemWindowInsets(); 11257 } 11258 } 11259 return insets; 11260 } 11261 11262 private WindowInsets onApplyFrameworkOptionalFitSystemWindows(WindowInsets insets) { 11263 Rect localInsets = sThreadLocal.get(); 11264 WindowInsets result = computeSystemWindowInsets(insets, localInsets); 11265 applyInsets(localInsets); 11266 return result; 11267 } 11268 11269 /** 11270 * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying 11271 * window insets to this view. The listener's 11272 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 11273 * method will be called instead of the view's 11274 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 11275 * 11276 * @param listener Listener to set 11277 * 11278 * @see #onApplyWindowInsets(WindowInsets) 11279 */ 11280 public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) { 11281 getListenerInfo().mOnApplyWindowInsetsListener = listener; 11282 } 11283 11284 /** 11285 * Request to apply the given window insets to this view or another view in its subtree. 11286 * 11287 * <p>This method should be called by clients wishing to apply insets corresponding to areas 11288 * obscured by window decorations or overlays. This can include the status and navigation bars, 11289 * action bars, input methods and more. New inset categories may be added in the future. 11290 * The method returns the insets provided minus any that were applied by this view or its 11291 * children.</p> 11292 * 11293 * <p>Clients wishing to provide custom behavior should override the 11294 * {@link #onApplyWindowInsets(WindowInsets)} method or alternatively provide a 11295 * {@link OnApplyWindowInsetsListener} via the 11296 * {@link #setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) setOnApplyWindowInsetsListener} 11297 * method.</p> 11298 * 11299 * <p>This method replaces the older {@link #fitSystemWindows(Rect) fitSystemWindows} method. 11300 * </p> 11301 * 11302 * @param insets Insets to apply 11303 * @return The provided insets minus the insets that were consumed 11304 */ 11305 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { 11306 try { 11307 mPrivateFlags3 |= PFLAG3_APPLYING_INSETS; 11308 if (mListenerInfo != null && mListenerInfo.mOnApplyWindowInsetsListener != null) { 11309 return mListenerInfo.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets); 11310 } else { 11311 return onApplyWindowInsets(insets); 11312 } 11313 } finally { 11314 mPrivateFlags3 &= ~PFLAG3_APPLYING_INSETS; 11315 } 11316 } 11317 11318 /** 11319 * Sets a {@link WindowInsetsAnimation.Callback} to be notified about animations of windows that 11320 * cause insets. 11321 * <p> 11322 * The callback's {@link WindowInsetsAnimation.Callback#getDispatchMode() 11323 * dispatch mode} will affect whether animation callbacks are dispatched to the children of 11324 * this view. 11325 * </p> 11326 * @param callback The callback to set. 11327 */ 11328 public void setWindowInsetsAnimationCallback( 11329 @Nullable WindowInsetsAnimation.Callback callback) { 11330 getListenerInfo().mWindowInsetsAnimationCallback = callback; 11331 } 11332 11333 /** 11334 * @return {@code true} if any {@link WindowInsetsAnimation.Callback} is registered on the view 11335 * or view tree of the sub-hierarchy {@code false} otherwise. 11336 * @hide 11337 */ 11338 public boolean hasWindowInsetsAnimationCallback() { 11339 return getListenerInfo().mWindowInsetsAnimationCallback != null; 11340 } 11341 11342 /** 11343 * Dispatches {@link WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation)} 11344 * when Window Insets animation is being prepared. 11345 * @param animation current animation 11346 * 11347 * @see WindowInsetsAnimation.Callback#onPrepare(WindowInsetsAnimation) 11348 */ 11349 public void dispatchWindowInsetsAnimationPrepare( 11350 @NonNull WindowInsetsAnimation animation) { 11351 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11352 mListenerInfo.mWindowInsetsAnimationCallback.onPrepare(animation); 11353 } 11354 } 11355 11356 /** 11357 * Dispatches {@link WindowInsetsAnimation.Callback#onStart(WindowInsetsAnimation, Bounds)} 11358 * when Window Insets animation is started. 11359 * @param animation current animation 11360 * @param bounds the upper and lower {@link Bounds} that provides range of 11361 * {@link WindowInsetsAnimation}. 11362 * @return the upper and lower {@link Bounds}. 11363 */ 11364 @NonNull 11365 public Bounds dispatchWindowInsetsAnimationStart( 11366 @NonNull WindowInsetsAnimation animation, @NonNull Bounds bounds) { 11367 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11368 return mListenerInfo.mWindowInsetsAnimationCallback.onStart(animation, bounds); 11369 } 11370 return bounds; 11371 } 11372 11373 /** 11374 * Dispatches {@link WindowInsetsAnimation.Callback#onProgress(WindowInsets, List)} 11375 * when Window Insets animation makes progress. 11376 * @param insets The current {@link WindowInsets}. 11377 * @param runningAnimations The currently running {@link WindowInsetsAnimation}s. 11378 * @return current {@link WindowInsets}. 11379 */ 11380 @NonNull 11381 public WindowInsets dispatchWindowInsetsAnimationProgress(@NonNull WindowInsets insets, 11382 @NonNull List<WindowInsetsAnimation> runningAnimations) { 11383 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11384 return mListenerInfo.mWindowInsetsAnimationCallback.onProgress(insets, 11385 runningAnimations); 11386 } else { 11387 return insets; 11388 } 11389 } 11390 11391 /** 11392 * Dispatches {@link WindowInsetsAnimation.Callback#onEnd(WindowInsetsAnimation)} 11393 * when Window Insets animation ends. 11394 * @param animation The current ongoing {@link WindowInsetsAnimation}. 11395 */ 11396 public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) { 11397 if (mListenerInfo != null && mListenerInfo.mWindowInsetsAnimationCallback != null) { 11398 mListenerInfo.mWindowInsetsAnimationCallback.onEnd(animation); 11399 } 11400 } 11401 11402 /** 11403 * Sets a list of areas within this view's post-layout coordinate space where the system 11404 * should not intercept touch or other pointing device gestures. <em>This method should 11405 * be called by {@link #onLayout(boolean, int, int, int, int)} or {@link #onDraw(Canvas)}.</em> 11406 * 11407 * <p>Use this to tell the system which specific sub-areas of a view need to receive gesture 11408 * input in order to function correctly in the presence of global system gestures that may 11409 * conflict. For example, if the system wishes to capture swipe-in-from-screen-edge gestures 11410 * to provide system-level navigation functionality, a view such as a navigation drawer 11411 * container can mark the left (or starting) edge of itself as requiring gesture capture 11412 * priority using this API. The system may then choose to relax its own gesture recognition 11413 * to allow the app to consume the user's gesture. It is not necessary for an app to register 11414 * exclusion rects for broadly spanning regions such as the entirety of a 11415 * <code>ScrollView</code> or for simple press and release click targets such as 11416 * <code>Button</code>. Mark an exclusion rect when interacting with a view requires 11417 * a precision touch gesture in a small area in either the X or Y dimension, such as 11418 * an edge swipe or dragging a <code>SeekBar</code> thumb.</p> 11419 * 11420 * <p>Do not modify the provided list after this method is called.</p> 11421 * 11422 * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the 11423 * exclusions it takes into account. The limit does not apply while the navigation 11424 * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the 11425 * {@link android.inputmethodservice.InputMethodService input method} and 11426 * {@link Intent#CATEGORY_HOME home activity}. 11427 * </p> 11428 * 11429 * @param rects A list of precision gesture regions that this view needs to function correctly 11430 */ 11431 public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) { 11432 if (rects.isEmpty() && mListenerInfo == null) return; 11433 11434 final ListenerInfo info = getListenerInfo(); 11435 if (rects.isEmpty()) { 11436 info.mSystemGestureExclusionRects = null; 11437 if (info.mPositionUpdateListener != null) { 11438 mRenderNode.removePositionUpdateListener(info.mPositionUpdateListener); 11439 } 11440 } else { 11441 info.mSystemGestureExclusionRects = rects; 11442 if (info.mPositionUpdateListener == null) { 11443 info.mPositionUpdateListener = new RenderNode.PositionUpdateListener() { 11444 @Override 11445 public void positionChanged(long n, int l, int t, int r, int b) { 11446 postUpdateSystemGestureExclusionRects(); 11447 } 11448 11449 @Override 11450 public void positionLost(long frameNumber) { 11451 postUpdateSystemGestureExclusionRects(); 11452 } 11453 }; 11454 mRenderNode.addPositionUpdateListener(info.mPositionUpdateListener); 11455 } 11456 } 11457 postUpdateSystemGestureExclusionRects(); 11458 } 11459 11460 /** 11461 * WARNING: this can be called by a hwui worker thread, not just the UI thread! 11462 */ 11463 void postUpdateSystemGestureExclusionRects() { 11464 // Potentially racey from a background thread. It's ok if it's not perfect. 11465 final Handler h = getHandler(); 11466 if (h != null) { 11467 h.postAtFrontOfQueue(this::updateSystemGestureExclusionRects); 11468 } 11469 } 11470 11471 void updateSystemGestureExclusionRects() { 11472 final AttachInfo ai = mAttachInfo; 11473 if (ai != null) { 11474 ai.mViewRootImpl.updateSystemGestureExclusionRectsForView(this); 11475 } 11476 } 11477 11478 /** 11479 * Retrieve the list of areas within this view's post-layout coordinate space where the system 11480 * should not intercept touch or other pointing device gestures. 11481 * 11482 * <p>Do not modify the returned list.</p> 11483 * 11484 * @return the list set by {@link #setSystemGestureExclusionRects(List)} 11485 */ 11486 @NonNull 11487 public List<Rect> getSystemGestureExclusionRects() { 11488 final ListenerInfo info = mListenerInfo; 11489 if (info != null) { 11490 final List<Rect> list = info.mSystemGestureExclusionRects; 11491 if (list != null) { 11492 return list; 11493 } 11494 } 11495 return Collections.emptyList(); 11496 } 11497 11498 /** 11499 * Compute the view's coordinate within the surface. 11500 * 11501 * <p>Computes the coordinates of this view in its surface. The argument 11502 * must be an array of two integers. After the method returns, the array 11503 * contains the x and y location in that order.</p> 11504 * 11505 * @param location an array of two integers in which to hold the coordinates 11506 */ 11507 public void getLocationInSurface(@NonNull @Size(2) int[] location) { 11508 getLocationInWindow(location); 11509 if (mAttachInfo != null && mAttachInfo.mViewRootImpl != null) { 11510 location[0] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.left; 11511 location[1] += mAttachInfo.mViewRootImpl.mWindowAttributes.surfaceInsets.top; 11512 } 11513 } 11514 11515 /** 11516 * Provide original WindowInsets that are dispatched to the view hierarchy. The insets are 11517 * only available if the view is attached. 11518 * 11519 * @return WindowInsets from the top of the view hierarchy or null if View is detached 11520 */ 11521 public WindowInsets getRootWindowInsets() { 11522 if (mAttachInfo != null) { 11523 return mAttachInfo.mViewRootImpl.getWindowInsets(false /* forceConstruct */); 11524 } 11525 return null; 11526 } 11527 11528 /** 11529 * Retrieves the single {@link WindowInsetsController} of the window this view is attached to. 11530 * 11531 * @return The {@link WindowInsetsController} or {@code null} if the view is neither attached to 11532 * a window nor a view tree with a decor. 11533 * @see Window#getInsetsController() 11534 */ 11535 public @Nullable WindowInsetsController getWindowInsetsController() { 11536 if (mAttachInfo != null) { 11537 return mAttachInfo.mViewRootImpl.getInsetsController(); 11538 } 11539 ViewParent parent = getParent(); 11540 if (parent instanceof View) { 11541 return ((View) parent).getWindowInsetsController(); 11542 } else if (parent instanceof ViewRootImpl) { 11543 // Between WindowManager.addView() and the first traversal AttachInfo isn't set yet. 11544 return ((ViewRootImpl) parent).getInsetsController(); 11545 } 11546 return null; 11547 } 11548 11549 /** 11550 * @hide Compute the insets that should be consumed by this view and the ones 11551 * that should propagate to those under it. 11552 * 11553 * Note: This is used by appcompat's ActionBarOverlayLayout through reflection. 11554 * 11555 * @param inoutInsets the insets given to this view 11556 * @param outLocalInsets the insets that should be applied to this view 11557 * @deprecated use {@link #computeSystemWindowInsets} 11558 * @return 11559 */ 11560 @Deprecated 11561 @UnsupportedAppUsage 11562 protected boolean computeFitSystemWindows(Rect inoutInsets, Rect outLocalInsets) { 11563 WindowInsets innerInsets = computeSystemWindowInsets(new WindowInsets(inoutInsets), 11564 outLocalInsets); 11565 inoutInsets.set(innerInsets.getSystemWindowInsetsAsRect()); 11566 return innerInsets.isSystemWindowInsetsConsumed(); 11567 } 11568 11569 /** 11570 * Compute insets that should be consumed by this view and the ones that should propagate 11571 * to those under it. 11572 * 11573 * @param in Insets currently being processed by this View, likely received as a parameter 11574 * to {@link #onApplyWindowInsets(WindowInsets)}. 11575 * @param outLocalInsets A Rect that will receive the insets that should be consumed 11576 * by this view 11577 * @return Insets that should be passed along to views under this one 11578 */ 11579 public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) { 11580 boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 11581 || (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; 11582 if (isOptionalFitSystemWindows && mAttachInfo != null) { 11583 OnContentApplyWindowInsetsListener listener = 11584 mAttachInfo.mContentOnApplyWindowInsetsListener; 11585 if (listener == null) { 11586 // The application wants to take care of fitting system window for 11587 // the content. 11588 outLocalInsets.setEmpty(); 11589 return in; 11590 } 11591 Pair<Insets, WindowInsets> result = listener.onContentApplyWindowInsets(this, in); 11592 outLocalInsets.set(result.first.toRect()); 11593 return result.second; 11594 } else { 11595 outLocalInsets.set(in.getSystemWindowInsetsAsRect()); 11596 return in.consumeSystemWindowInsets().inset(outLocalInsets); 11597 } 11598 } 11599 11600 /** 11601 * Sets whether or not this view should account for system screen decorations 11602 * such as the status bar and inset its content; that is, controlling whether 11603 * the default implementation of {@link #fitSystemWindows(Rect)} will be 11604 * executed. See that method for more details. 11605 * 11606 * <p>Note that if you are providing your own implementation of 11607 * {@link #fitSystemWindows(Rect)}, then there is no need to set this 11608 * flag to true -- your implementation will be overriding the default 11609 * implementation that checks this flag. 11610 * 11611 * @param fitSystemWindows If true, then the default implementation of 11612 * {@link #fitSystemWindows(Rect)} will be executed. 11613 * 11614 * @attr ref android.R.styleable#View_fitsSystemWindows 11615 * @see #getFitsSystemWindows() 11616 * @see #fitSystemWindows(Rect) 11617 * @see #setSystemUiVisibility(int) 11618 */ 11619 public void setFitsSystemWindows(boolean fitSystemWindows) { 11620 setFlags(fitSystemWindows ? FITS_SYSTEM_WINDOWS : 0, FITS_SYSTEM_WINDOWS); 11621 } 11622 11623 /** 11624 * Check for state of {@link #setFitsSystemWindows(boolean)}. If this method 11625 * returns {@code true}, the default implementation of {@link #fitSystemWindows(Rect)} 11626 * will be executed. 11627 * 11628 * @return {@code true} if the default implementation of 11629 * {@link #fitSystemWindows(Rect)} will be executed. 11630 * 11631 * @attr ref android.R.styleable#View_fitsSystemWindows 11632 * @see #setFitsSystemWindows(boolean) 11633 * @see #fitSystemWindows(Rect) 11634 * @see #setSystemUiVisibility(int) 11635 */ 11636 @ViewDebug.ExportedProperty 11637 @InspectableProperty 11638 public boolean getFitsSystemWindows() { 11639 return (mViewFlags & FITS_SYSTEM_WINDOWS) == FITS_SYSTEM_WINDOWS; 11640 } 11641 11642 /** @hide */ 11643 @UnsupportedAppUsage 11644 public boolean fitsSystemWindows() { 11645 return getFitsSystemWindows(); 11646 } 11647 11648 /** 11649 * Ask that a new dispatch of {@link #fitSystemWindows(Rect)} be performed. 11650 * @deprecated Use {@link #requestApplyInsets()} for newer platform versions. 11651 */ 11652 @Deprecated 11653 public void requestFitSystemWindows() { 11654 if (mParent != null) { 11655 mParent.requestFitSystemWindows(); 11656 } 11657 } 11658 11659 /** 11660 * Ask that a new dispatch of {@link #onApplyWindowInsets(WindowInsets)} be performed. 11661 */ 11662 public void requestApplyInsets() { 11663 requestFitSystemWindows(); 11664 } 11665 11666 /** 11667 * @see #OPTIONAL_FITS_SYSTEM_WINDOWS 11668 * @hide 11669 */ 11670 @UnsupportedAppUsage 11671 public void makeOptionalFitsSystemWindows() { 11672 setFlags(OPTIONAL_FITS_SYSTEM_WINDOWS, OPTIONAL_FITS_SYSTEM_WINDOWS); 11673 } 11674 11675 /** 11676 * @see #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS 11677 * @hide 11678 */ 11679 public void makeFrameworkOptionalFitsSystemWindows() { 11680 mPrivateFlags4 |= PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS; 11681 } 11682 11683 /** 11684 * @hide 11685 */ 11686 public boolean isFrameworkOptionalFitsSystemWindows() { 11687 return (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0; 11688 } 11689 11690 /** 11691 * Returns the visibility status for this view. 11692 * 11693 * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 11694 * @attr ref android.R.styleable#View_visibility 11695 */ 11696 @ViewDebug.ExportedProperty(mapping = { 11697 @ViewDebug.IntToString(from = VISIBLE, to = "VISIBLE"), 11698 @ViewDebug.IntToString(from = INVISIBLE, to = "INVISIBLE"), 11699 @ViewDebug.IntToString(from = GONE, to = "GONE") 11700 }) 11701 @InspectableProperty(enumMapping = { 11702 @EnumEntry(value = VISIBLE, name = "visible"), 11703 @EnumEntry(value = INVISIBLE, name = "invisible"), 11704 @EnumEntry(value = GONE, name = "gone") 11705 }) 11706 @Visibility 11707 public int getVisibility() { 11708 return mViewFlags & VISIBILITY_MASK; 11709 } 11710 11711 /** 11712 * Set the visibility state of this view. 11713 * 11714 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 11715 * @attr ref android.R.styleable#View_visibility 11716 */ 11717 @RemotableViewMethod 11718 public void setVisibility(@Visibility int visibility) { 11719 setFlags(visibility, VISIBILITY_MASK); 11720 } 11721 11722 /** 11723 * Returns the enabled status for this view. The interpretation of the 11724 * enabled state varies by subclass. 11725 * 11726 * @return True if this view is enabled, false otherwise. 11727 */ 11728 @ViewDebug.ExportedProperty 11729 @InspectableProperty 11730 public boolean isEnabled() { 11731 return (mViewFlags & ENABLED_MASK) == ENABLED; 11732 } 11733 11734 /** 11735 * Set the enabled state of this view. The interpretation of the enabled 11736 * state varies by subclass. 11737 * 11738 * @param enabled True if this view is enabled, false otherwise. 11739 */ 11740 @RemotableViewMethod 11741 public void setEnabled(boolean enabled) { 11742 if (enabled == isEnabled()) return; 11743 11744 setFlags(enabled ? ENABLED : DISABLED, ENABLED_MASK); 11745 11746 /* 11747 * The View most likely has to change its appearance, so refresh 11748 * the drawable state. 11749 */ 11750 refreshDrawableState(); 11751 11752 // Invalidate too, since the default behavior for views is to be 11753 // be drawn at 50% alpha rather than to change the drawable. 11754 invalidate(true); 11755 11756 if (!enabled) { 11757 cancelPendingInputEvents(); 11758 } 11759 } 11760 11761 /** 11762 * Set whether this view can receive the focus. 11763 * <p> 11764 * Setting this to false will also ensure that this view is not focusable 11765 * in touch mode. 11766 * 11767 * @param focusable If true, this view can receive the focus. 11768 * 11769 * @see #setFocusableInTouchMode(boolean) 11770 * @see #setFocusable(int) 11771 * @attr ref android.R.styleable#View_focusable 11772 */ 11773 public void setFocusable(boolean focusable) { 11774 setFocusable(focusable ? FOCUSABLE : NOT_FOCUSABLE); 11775 } 11776 11777 /** 11778 * Sets whether this view can receive focus. 11779 * <p> 11780 * Setting this to {@link #FOCUSABLE_AUTO} tells the framework to determine focusability 11781 * automatically based on the view's interactivity. This is the default. 11782 * <p> 11783 * Setting this to NOT_FOCUSABLE will ensure that this view is also not focusable 11784 * in touch mode. 11785 * 11786 * @param focusable One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, 11787 * or {@link #FOCUSABLE_AUTO}. 11788 * @see #setFocusableInTouchMode(boolean) 11789 * @attr ref android.R.styleable#View_focusable 11790 */ 11791 public void setFocusable(@Focusable int focusable) { 11792 if ((focusable & (FOCUSABLE_AUTO | FOCUSABLE)) == 0) { 11793 setFlags(0, FOCUSABLE_IN_TOUCH_MODE); 11794 } 11795 setFlags(focusable, FOCUSABLE_MASK); 11796 } 11797 11798 /** 11799 * Set whether this view can receive focus while in touch mode. 11800 * 11801 * Setting this to true will also ensure that this view is focusable. 11802 * 11803 * @param focusableInTouchMode If true, this view can receive the focus while 11804 * in touch mode. 11805 * 11806 * @see #setFocusable(boolean) 11807 * @attr ref android.R.styleable#View_focusableInTouchMode 11808 */ 11809 public void setFocusableInTouchMode(boolean focusableInTouchMode) { 11810 // Focusable in touch mode should always be set before the focusable flag 11811 // otherwise, setting the focusable flag will trigger a focusableViewAvailable() 11812 // which, in touch mode, will not successfully request focus on this view 11813 // because the focusable in touch mode flag is not set 11814 setFlags(focusableInTouchMode ? FOCUSABLE_IN_TOUCH_MODE : 0, FOCUSABLE_IN_TOUCH_MODE); 11815 11816 // Clear FOCUSABLE_AUTO if set. 11817 if (focusableInTouchMode) { 11818 // Clears FOCUSABLE_AUTO if set. 11819 setFlags(FOCUSABLE, FOCUSABLE_MASK); 11820 } 11821 } 11822 11823 /** 11824 * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how 11825 * to autofill the view with the user's data. 11826 * 11827 * <p>Typically, there is only one way to autofill a view, but there could be more than one. 11828 * For example, if the application accepts either an username or email address to identify 11829 * an user. 11830 * 11831 * <p>These hints are not validated by the Android System, but passed "as is" to the service. 11832 * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_} 11833 * constants such as: 11834 * {@link #AUTOFILL_HINT_USERNAME}, {@link #AUTOFILL_HINT_PASSWORD}, 11835 * {@link #AUTOFILL_HINT_EMAIL_ADDRESS}, 11836 * {@link #AUTOFILL_HINT_NAME}, 11837 * {@link #AUTOFILL_HINT_PHONE}, 11838 * {@link #AUTOFILL_HINT_POSTAL_ADDRESS}, {@link #AUTOFILL_HINT_POSTAL_CODE}, 11839 * {@link #AUTOFILL_HINT_CREDIT_CARD_NUMBER}, {@link #AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE}, 11840 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE}, 11841 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY}, 11842 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or 11843 * {@link #AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}. 11844 * 11845 * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set. 11846 * @attr ref android.R.styleable#View_autofillHints 11847 */ 11848 public void setAutofillHints(@Nullable String... autofillHints) { 11849 if (autofillHints == null || autofillHints.length == 0) { 11850 mAutofillHints = null; 11851 } else { 11852 mAutofillHints = autofillHints; 11853 } 11854 } 11855 11856 /** 11857 * @hide 11858 */ 11859 @TestApi 11860 public void setAutofilled(boolean isAutofilled, boolean hideHighlight) { 11861 boolean wasChanged = isAutofilled != isAutofilled(); 11862 11863 if (wasChanged) { 11864 if (isAutofilled) { 11865 mPrivateFlags3 |= PFLAG3_IS_AUTOFILLED; 11866 } else { 11867 mPrivateFlags3 &= ~PFLAG3_IS_AUTOFILLED; 11868 } 11869 11870 if (hideHighlight) { 11871 mPrivateFlags4 |= PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; 11872 } else { 11873 mPrivateFlags4 &= ~PFLAG4_AUTOFILL_HIDE_HIGHLIGHT; 11874 } 11875 11876 invalidate(); 11877 } 11878 } 11879 11880 /** 11881 * Set whether this view should have sound effects enabled for events such as 11882 * clicking and touching. 11883 * 11884 * <p>You may wish to disable sound effects for a view if you already play sounds, 11885 * for instance, a dial key that plays dtmf tones. 11886 * 11887 * @param soundEffectsEnabled whether sound effects are enabled for this view. 11888 * @see #isSoundEffectsEnabled() 11889 * @see #playSoundEffect(int) 11890 * @attr ref android.R.styleable#View_soundEffectsEnabled 11891 */ 11892 public void setSoundEffectsEnabled(boolean soundEffectsEnabled) { 11893 setFlags(soundEffectsEnabled ? SOUND_EFFECTS_ENABLED: 0, SOUND_EFFECTS_ENABLED); 11894 } 11895 11896 /** 11897 * @return whether this view should have sound effects enabled for events such as 11898 * clicking and touching. 11899 * 11900 * @see #setSoundEffectsEnabled(boolean) 11901 * @see #playSoundEffect(int) 11902 * @attr ref android.R.styleable#View_soundEffectsEnabled 11903 */ 11904 @ViewDebug.ExportedProperty 11905 @InspectableProperty 11906 public boolean isSoundEffectsEnabled() { 11907 return SOUND_EFFECTS_ENABLED == (mViewFlags & SOUND_EFFECTS_ENABLED); 11908 } 11909 11910 /** 11911 * Set whether this view should have haptic feedback for events such as 11912 * long presses. 11913 * 11914 * <p>You may wish to disable haptic feedback if your view already controls 11915 * its own haptic feedback. 11916 * 11917 * @param hapticFeedbackEnabled whether haptic feedback enabled for this view. 11918 * @see #isHapticFeedbackEnabled() 11919 * @see #performHapticFeedback(int) 11920 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 11921 */ 11922 public void setHapticFeedbackEnabled(boolean hapticFeedbackEnabled) { 11923 setFlags(hapticFeedbackEnabled ? HAPTIC_FEEDBACK_ENABLED: 0, HAPTIC_FEEDBACK_ENABLED); 11924 } 11925 11926 /** 11927 * @return whether this view should have haptic feedback enabled for events 11928 * long presses. 11929 * 11930 * @see #setHapticFeedbackEnabled(boolean) 11931 * @see #performHapticFeedback(int) 11932 * @attr ref android.R.styleable#View_hapticFeedbackEnabled 11933 */ 11934 @ViewDebug.ExportedProperty 11935 @InspectableProperty 11936 public boolean isHapticFeedbackEnabled() { 11937 return HAPTIC_FEEDBACK_ENABLED == (mViewFlags & HAPTIC_FEEDBACK_ENABLED); 11938 } 11939 11940 /** 11941 * Returns the layout direction for this view. 11942 * 11943 * @return One of {@link #LAYOUT_DIRECTION_LTR}, 11944 * {@link #LAYOUT_DIRECTION_RTL}, 11945 * {@link #LAYOUT_DIRECTION_INHERIT} or 11946 * {@link #LAYOUT_DIRECTION_LOCALE}. 11947 * 11948 * @attr ref android.R.styleable#View_layoutDirection 11949 * 11950 * @hide 11951 */ 11952 @ViewDebug.ExportedProperty(category = "layout", mapping = { 11953 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "LTR"), 11954 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RTL"), 11955 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_INHERIT, to = "INHERIT"), 11956 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LOCALE, to = "LOCALE") 11957 }) 11958 @InspectableProperty(hasAttributeId = false, enumMapping = { 11959 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 11960 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl"), 11961 @EnumEntry(value = LAYOUT_DIRECTION_INHERIT, name = "inherit"), 11962 @EnumEntry(value = LAYOUT_DIRECTION_LOCALE, name = "locale") 11963 }) 11964 @LayoutDir 11965 public int getRawLayoutDirection() { 11966 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT; 11967 } 11968 11969 /** 11970 * Set the layout direction for this view. This will propagate a reset of layout direction 11971 * resolution to the view's children and resolve layout direction for this view. 11972 * 11973 * @param layoutDirection the layout direction to set. Should be one of: 11974 * 11975 * {@link #LAYOUT_DIRECTION_LTR}, 11976 * {@link #LAYOUT_DIRECTION_RTL}, 11977 * {@link #LAYOUT_DIRECTION_INHERIT}, 11978 * {@link #LAYOUT_DIRECTION_LOCALE}. 11979 * 11980 * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution 11981 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 11982 * will return the default {@link #LAYOUT_DIRECTION_LTR}. 11983 * 11984 * @attr ref android.R.styleable#View_layoutDirection 11985 */ 11986 @RemotableViewMethod 11987 public void setLayoutDirection(@LayoutDir int layoutDirection) { 11988 if (getRawLayoutDirection() != layoutDirection) { 11989 // Reset the current layout direction and the resolved one 11990 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_MASK; 11991 resetRtlProperties(); 11992 // Set the new layout direction (filtered) 11993 mPrivateFlags2 |= 11994 ((layoutDirection << PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) & PFLAG2_LAYOUT_DIRECTION_MASK); 11995 // We need to resolve all RTL properties as they all depend on layout direction 11996 resolveRtlPropertiesIfNeeded(); 11997 requestLayout(); 11998 invalidate(true); 11999 } 12000 } 12001 12002 /** 12003 * Returns the resolved layout direction for this view. 12004 * 12005 * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns 12006 * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL. 12007 * 12008 * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version 12009 * is lower than {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}. 12010 * 12011 * @attr ref android.R.styleable#View_layoutDirection 12012 */ 12013 @ViewDebug.ExportedProperty(category = "layout", mapping = { 12014 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_LTR, to = "RESOLVED_DIRECTION_LTR"), 12015 @ViewDebug.IntToString(from = LAYOUT_DIRECTION_RTL, to = "RESOLVED_DIRECTION_RTL") 12016 }) 12017 @InspectableProperty(enumMapping = { 12018 @EnumEntry(value = LAYOUT_DIRECTION_LTR, name = "ltr"), 12019 @EnumEntry(value = LAYOUT_DIRECTION_RTL, name = "rtl") 12020 }) 12021 @ResolvedLayoutDir 12022 public int getLayoutDirection() { 12023 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 12024 if (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1) { 12025 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 12026 return LAYOUT_DIRECTION_RESOLVED_DEFAULT; 12027 } 12028 return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) == 12029 PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR; 12030 } 12031 12032 /** 12033 * Indicates whether or not this view's layout is right-to-left. This is resolved from 12034 * layout attribute and/or the inherited value from the parent 12035 * 12036 * @return true if the layout is right-to-left. 12037 * 12038 * @hide 12039 */ 12040 @ViewDebug.ExportedProperty(category = "layout") 12041 @UnsupportedAppUsage 12042 public boolean isLayoutRtl() { 12043 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL); 12044 } 12045 12046 /** 12047 * Indicates whether the view is currently tracking transient state that the 12048 * app should not need to concern itself with saving and restoring, but that 12049 * the framework should take special note to preserve when possible. 12050 * 12051 * <p>A view with transient state cannot be trivially rebound from an external 12052 * data source, such as an adapter binding item views in a list. This may be 12053 * because the view is performing an animation, tracking user selection 12054 * of content, or similar.</p> 12055 * 12056 * @return true if the view has transient state 12057 */ 12058 @ViewDebug.ExportedProperty(category = "layout") 12059 public boolean hasTransientState() { 12060 return (mPrivateFlags2 & PFLAG2_HAS_TRANSIENT_STATE) == PFLAG2_HAS_TRANSIENT_STATE; 12061 } 12062 12063 /** 12064 * Set whether this view is currently tracking transient state that the 12065 * framework should attempt to preserve when possible. This flag is reference counted, 12066 * so every call to setHasTransientState(true) should be paired with a later call 12067 * to setHasTransientState(false). 12068 * 12069 * <p>A view with transient state cannot be trivially rebound from an external 12070 * data source, such as an adapter binding item views in a list. This may be 12071 * because the view is performing an animation, tracking user selection 12072 * of content, or similar.</p> 12073 * 12074 * @param hasTransientState true if this view has transient state 12075 */ 12076 public void setHasTransientState(boolean hasTransientState) { 12077 final boolean oldHasTransientState = hasTransientState(); 12078 mTransientStateCount = hasTransientState ? mTransientStateCount + 1 : 12079 mTransientStateCount - 1; 12080 if (mTransientStateCount < 0) { 12081 mTransientStateCount = 0; 12082 Log.e(VIEW_LOG_TAG, "hasTransientState decremented below 0: " + 12083 "unmatched pair of setHasTransientState calls"); 12084 } else if ((hasTransientState && mTransientStateCount == 1) || 12085 (!hasTransientState && mTransientStateCount == 0)) { 12086 // update flag if we've just incremented up from 0 or decremented down to 0 12087 mPrivateFlags2 = (mPrivateFlags2 & ~PFLAG2_HAS_TRANSIENT_STATE) | 12088 (hasTransientState ? PFLAG2_HAS_TRANSIENT_STATE : 0); 12089 final boolean newHasTransientState = hasTransientState(); 12090 if (mParent != null && newHasTransientState != oldHasTransientState) { 12091 try { 12092 mParent.childHasTransientStateChanged(this, newHasTransientState); 12093 } catch (AbstractMethodError e) { 12094 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 12095 " does not fully implement ViewParent", e); 12096 } 12097 } 12098 } 12099 } 12100 12101 /** 12102 * Returns true if this view is currently attached to a window. 12103 */ 12104 public boolean isAttachedToWindow() { 12105 return mAttachInfo != null; 12106 } 12107 12108 /** 12109 * Returns true if this view has been through at least one layout since it 12110 * was last attached to or detached from a window. 12111 */ 12112 public boolean isLaidOut() { 12113 return (mPrivateFlags3 & PFLAG3_IS_LAID_OUT) == PFLAG3_IS_LAID_OUT; 12114 } 12115 12116 /** 12117 * @return {@code true} if laid-out and not about to do another layout. 12118 */ 12119 boolean isLayoutValid() { 12120 return isLaidOut() && ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == 0); 12121 } 12122 12123 /** 12124 * If this view doesn't do any drawing on its own, set this flag to 12125 * allow further optimizations. By default, this flag is not set on 12126 * View, but could be set on some View subclasses such as ViewGroup. 12127 * 12128 * Typically, if you override {@link #onDraw(android.graphics.Canvas)} 12129 * you should clear this flag. 12130 * 12131 * @param willNotDraw whether or not this View draw on its own 12132 */ 12133 public void setWillNotDraw(boolean willNotDraw) { 12134 setFlags(willNotDraw ? WILL_NOT_DRAW : 0, DRAW_MASK); 12135 } 12136 12137 /** 12138 * Returns whether or not this View draws on its own. 12139 * 12140 * @return true if this view has nothing to draw, false otherwise 12141 */ 12142 @ViewDebug.ExportedProperty(category = "drawing") 12143 public boolean willNotDraw() { 12144 return (mViewFlags & DRAW_MASK) == WILL_NOT_DRAW; 12145 } 12146 12147 /** 12148 * When a View's drawing cache is enabled, drawing is redirected to an 12149 * offscreen bitmap. Some views, like an ImageView, must be able to 12150 * bypass this mechanism if they already draw a single bitmap, to avoid 12151 * unnecessary usage of the memory. 12152 * 12153 * @param willNotCacheDrawing true if this view does not cache its 12154 * drawing, false otherwise 12155 * 12156 * @deprecated The view drawing cache was largely made obsolete with the introduction of 12157 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 12158 * layers are largely unnecessary and can easily result in a net loss in performance due to the 12159 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 12160 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 12161 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 12162 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 12163 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 12164 * software-rendered usages are discouraged and have compatibility issues with hardware-only 12165 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 12166 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 12167 * reports or unit testing the {@link PixelCopy} API is recommended. 12168 */ 12169 @Deprecated 12170 public void setWillNotCacheDrawing(boolean willNotCacheDrawing) { 12171 setFlags(willNotCacheDrawing ? WILL_NOT_CACHE_DRAWING : 0, WILL_NOT_CACHE_DRAWING); 12172 } 12173 12174 /** 12175 * Returns whether or not this View can cache its drawing or not. 12176 * 12177 * @return true if this view does not cache its drawing, false otherwise 12178 * 12179 * @deprecated The view drawing cache was largely made obsolete with the introduction of 12180 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 12181 * layers are largely unnecessary and can easily result in a net loss in performance due to the 12182 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 12183 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 12184 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 12185 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 12186 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 12187 * software-rendered usages are discouraged and have compatibility issues with hardware-only 12188 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 12189 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 12190 * reports or unit testing the {@link PixelCopy} API is recommended. 12191 */ 12192 @ViewDebug.ExportedProperty(category = "drawing") 12193 @Deprecated 12194 public boolean willNotCacheDrawing() { 12195 return (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING; 12196 } 12197 12198 /** 12199 * Indicates whether this view reacts to click events or not. 12200 * 12201 * @return true if the view is clickable, false otherwise 12202 * 12203 * @see #setClickable(boolean) 12204 * @attr ref android.R.styleable#View_clickable 12205 */ 12206 @ViewDebug.ExportedProperty 12207 @InspectableProperty 12208 public boolean isClickable() { 12209 return (mViewFlags & CLICKABLE) == CLICKABLE; 12210 } 12211 12212 /** 12213 * Enables or disables click events for this view. When a view 12214 * is clickable it will change its state to "pressed" on every click. 12215 * Subclasses should set the view clickable to visually react to 12216 * user's clicks. 12217 * 12218 * @param clickable true to make the view clickable, false otherwise 12219 * 12220 * @see #isClickable() 12221 * @attr ref android.R.styleable#View_clickable 12222 */ 12223 public void setClickable(boolean clickable) { 12224 setFlags(clickable ? CLICKABLE : 0, CLICKABLE); 12225 } 12226 12227 /** 12228 * Indicates whether this view reacts to long click events or not. 12229 * 12230 * @return true if the view is long clickable, false otherwise 12231 * 12232 * @see #setLongClickable(boolean) 12233 * @attr ref android.R.styleable#View_longClickable 12234 */ 12235 @InspectableProperty 12236 public boolean isLongClickable() { 12237 return (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 12238 } 12239 12240 /** 12241 * Enables or disables long click events for this view. When a view is long 12242 * clickable it reacts to the user holding down the button for a longer 12243 * duration than a tap. This event can either launch the listener or a 12244 * context menu. 12245 * 12246 * @param longClickable true to make the view long clickable, false otherwise 12247 * @see #isLongClickable() 12248 * @attr ref android.R.styleable#View_longClickable 12249 */ 12250 public void setLongClickable(boolean longClickable) { 12251 setFlags(longClickable ? LONG_CLICKABLE : 0, LONG_CLICKABLE); 12252 } 12253 12254 /** 12255 * Indicates whether this view reacts to context clicks or not. 12256 * 12257 * @return true if the view is context clickable, false otherwise 12258 * @see #setContextClickable(boolean) 12259 * @attr ref android.R.styleable#View_contextClickable 12260 */ 12261 @InspectableProperty 12262 public boolean isContextClickable() { 12263 return (mViewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 12264 } 12265 12266 /** 12267 * Enables or disables context clicking for this view. This event can launch the listener. 12268 * 12269 * @param contextClickable true to make the view react to a context click, false otherwise 12270 * @see #isContextClickable() 12271 * @attr ref android.R.styleable#View_contextClickable 12272 */ 12273 public void setContextClickable(boolean contextClickable) { 12274 setFlags(contextClickable ? CONTEXT_CLICKABLE : 0, CONTEXT_CLICKABLE); 12275 } 12276 12277 /** 12278 * Sets the pressed state for this view and provides a touch coordinate for 12279 * animation hinting. 12280 * 12281 * @param pressed Pass true to set the View's internal state to "pressed", 12282 * or false to reverts the View's internal state from a 12283 * previously set "pressed" state. 12284 * @param x The x coordinate of the touch that caused the press 12285 * @param y The y coordinate of the touch that caused the press 12286 */ 12287 private void setPressed(boolean pressed, float x, float y) { 12288 if (pressed) { 12289 drawableHotspotChanged(x, y); 12290 } 12291 12292 setPressed(pressed); 12293 } 12294 12295 /** 12296 * Sets the pressed state for this view. 12297 * 12298 * @see #isClickable() 12299 * @see #setClickable(boolean) 12300 * 12301 * @param pressed Pass true to set the View's internal state to "pressed", or false to reverts 12302 * the View's internal state from a previously set "pressed" state. 12303 */ 12304 public void setPressed(boolean pressed) { 12305 final boolean needsRefresh = pressed != ((mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED); 12306 12307 if (pressed) { 12308 mPrivateFlags |= PFLAG_PRESSED; 12309 } else { 12310 mPrivateFlags &= ~PFLAG_PRESSED; 12311 } 12312 12313 if (needsRefresh) { 12314 refreshDrawableState(); 12315 } 12316 dispatchSetPressed(pressed); 12317 } 12318 12319 /** 12320 * Dispatch setPressed to all of this View's children. 12321 * 12322 * @see #setPressed(boolean) 12323 * 12324 * @param pressed The new pressed state 12325 */ 12326 protected void dispatchSetPressed(boolean pressed) { 12327 } 12328 12329 /** 12330 * Indicates whether the view is currently in pressed state. Unless 12331 * {@link #setPressed(boolean)} is explicitly called, only clickable views can enter 12332 * the pressed state. 12333 * 12334 * @see #setPressed(boolean) 12335 * @see #isClickable() 12336 * @see #setClickable(boolean) 12337 * 12338 * @return true if the view is currently pressed, false otherwise 12339 */ 12340 @ViewDebug.ExportedProperty 12341 @InspectableProperty(hasAttributeId = false) 12342 public boolean isPressed() { 12343 return (mPrivateFlags & PFLAG_PRESSED) == PFLAG_PRESSED; 12344 } 12345 12346 /** 12347 * @hide 12348 * Indicates whether this view will participate in data collection through 12349 * {@link ViewStructure}. If true, it will not provide any data 12350 * for itself or its children. If false, the normal data collection will be allowed. 12351 * 12352 * @return Returns false if assist data collection is not blocked, else true. 12353 * 12354 * @see #setAssistBlocked(boolean) 12355 * @attr ref android.R.styleable#View_assistBlocked 12356 */ 12357 public boolean isAssistBlocked() { 12358 return (mPrivateFlags3 & PFLAG3_ASSIST_BLOCKED) != 0; 12359 } 12360 12361 /** 12362 * @hide 12363 * Controls whether assist data collection from this view and its children is enabled 12364 * (that is, whether {@link #onProvideStructure} and 12365 * {@link #onProvideVirtualStructure} will be called). The default value is false, 12366 * allowing normal assist collection. Setting this to false will disable assist collection. 12367 * 12368 * @param enabled Set to true to <em>disable</em> assist data collection, or false 12369 * (the default) to allow it. 12370 * 12371 * @see #isAssistBlocked() 12372 * @see #onProvideStructure 12373 * @see #onProvideVirtualStructure 12374 * @attr ref android.R.styleable#View_assistBlocked 12375 */ 12376 @UnsupportedAppUsage 12377 public void setAssistBlocked(boolean enabled) { 12378 if (enabled) { 12379 mPrivateFlags3 |= PFLAG3_ASSIST_BLOCKED; 12380 } else { 12381 mPrivateFlags3 &= ~PFLAG3_ASSIST_BLOCKED; 12382 } 12383 } 12384 12385 /** 12386 * Indicates whether this view will save its state (that is, 12387 * whether its {@link #onSaveInstanceState} method will be called). 12388 * 12389 * @return Returns true if the view state saving is enabled, else false. 12390 * 12391 * @see #setSaveEnabled(boolean) 12392 * @attr ref android.R.styleable#View_saveEnabled 12393 */ 12394 @InspectableProperty 12395 public boolean isSaveEnabled() { 12396 return (mViewFlags & SAVE_DISABLED_MASK) != SAVE_DISABLED; 12397 } 12398 12399 /** 12400 * Controls whether the saving of this view's state is 12401 * enabled (that is, whether its {@link #onSaveInstanceState} method 12402 * will be called). Note that even if freezing is enabled, the 12403 * view still must have an id assigned to it (via {@link #setId(int)}) 12404 * for its state to be saved. This flag can only disable the 12405 * saving of this view; any child views may still have their state saved. 12406 * 12407 * @param enabled Set to false to <em>disable</em> state saving, or true 12408 * (the default) to allow it. 12409 * 12410 * @see #isSaveEnabled() 12411 * @see #setId(int) 12412 * @see #onSaveInstanceState() 12413 * @attr ref android.R.styleable#View_saveEnabled 12414 */ 12415 public void setSaveEnabled(boolean enabled) { 12416 setFlags(enabled ? 0 : SAVE_DISABLED, SAVE_DISABLED_MASK); 12417 } 12418 12419 /** 12420 * Gets whether the framework should discard touches when the view's 12421 * window is obscured by another visible window. 12422 * Refer to the {@link View} security documentation for more details. 12423 * 12424 * @return True if touch filtering is enabled. 12425 * 12426 * @see #setFilterTouchesWhenObscured(boolean) 12427 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 12428 */ 12429 @ViewDebug.ExportedProperty 12430 @InspectableProperty 12431 public boolean getFilterTouchesWhenObscured() { 12432 return (mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0; 12433 } 12434 12435 /** 12436 * Sets whether the framework should discard touches when the view's 12437 * window is obscured by another visible window. 12438 * Refer to the {@link View} security documentation for more details. 12439 * 12440 * @param enabled True if touch filtering should be enabled. 12441 * 12442 * @see #getFilterTouchesWhenObscured 12443 * @attr ref android.R.styleable#View_filterTouchesWhenObscured 12444 */ 12445 public void setFilterTouchesWhenObscured(boolean enabled) { 12446 setFlags(enabled ? FILTER_TOUCHES_WHEN_OBSCURED : 0, 12447 FILTER_TOUCHES_WHEN_OBSCURED); 12448 } 12449 12450 /** 12451 * Indicates whether the entire hierarchy under this view will save its 12452 * state when a state saving traversal occurs from its parent. The default 12453 * is true; if false, these views will not be saved unless 12454 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 12455 * 12456 * @return Returns true if the view state saving from parent is enabled, else false. 12457 * 12458 * @see #setSaveFromParentEnabled(boolean) 12459 */ 12460 public boolean isSaveFromParentEnabled() { 12461 return (mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED; 12462 } 12463 12464 /** 12465 * Controls whether the entire hierarchy under this view will save its 12466 * state when a state saving traversal occurs from its parent. The default 12467 * is true; if false, these views will not be saved unless 12468 * {@link #saveHierarchyState(SparseArray)} is called directly on this view. 12469 * 12470 * @param enabled Set to false to <em>disable</em> state saving, or true 12471 * (the default) to allow it. 12472 * 12473 * @see #isSaveFromParentEnabled() 12474 * @see #setId(int) 12475 * @see #onSaveInstanceState() 12476 */ 12477 public void setSaveFromParentEnabled(boolean enabled) { 12478 setFlags(enabled ? 0 : PARENT_SAVE_DISABLED, PARENT_SAVE_DISABLED_MASK); 12479 } 12480 12481 12482 /** 12483 * Returns whether this View is currently able to take focus. 12484 * 12485 * @return True if this view can take focus, or false otherwise. 12486 */ 12487 @ViewDebug.ExportedProperty(category = "focus") 12488 public final boolean isFocusable() { 12489 return FOCUSABLE == (mViewFlags & FOCUSABLE); 12490 } 12491 12492 /** 12493 * Returns the focusable setting for this view. 12494 * 12495 * @return One of {@link #NOT_FOCUSABLE}, {@link #FOCUSABLE}, or {@link #FOCUSABLE_AUTO}. 12496 * @attr ref android.R.styleable#View_focusable 12497 */ 12498 @ViewDebug.ExportedProperty(mapping = { 12499 @ViewDebug.IntToString(from = NOT_FOCUSABLE, to = "NOT_FOCUSABLE"), 12500 @ViewDebug.IntToString(from = FOCUSABLE, to = "FOCUSABLE"), 12501 @ViewDebug.IntToString(from = FOCUSABLE_AUTO, to = "FOCUSABLE_AUTO") 12502 }, category = "focus") 12503 @InspectableProperty(enumMapping = { 12504 @EnumEntry(value = NOT_FOCUSABLE, name = "false"), 12505 @EnumEntry(value = FOCUSABLE, name = "true"), 12506 @EnumEntry(value = FOCUSABLE_AUTO, name = "auto") 12507 }) 12508 @Focusable 12509 public int getFocusable() { 12510 return (mViewFlags & FOCUSABLE_AUTO) > 0 ? FOCUSABLE_AUTO : mViewFlags & FOCUSABLE; 12511 } 12512 12513 /** 12514 * When a view is focusable, it may not want to take focus when in touch mode. 12515 * For example, a button would like focus when the user is navigating via a D-pad 12516 * so that the user can click on it, but once the user starts touching the screen, 12517 * the button shouldn't take focus 12518 * @return Whether the view is focusable in touch mode. 12519 * @attr ref android.R.styleable#View_focusableInTouchMode 12520 */ 12521 @ViewDebug.ExportedProperty(category = "focus") 12522 @InspectableProperty 12523 public final boolean isFocusableInTouchMode() { 12524 return FOCUSABLE_IN_TOUCH_MODE == (mViewFlags & FOCUSABLE_IN_TOUCH_MODE); 12525 } 12526 12527 /** 12528 * Returns whether the view should be treated as a focusable unit by screen reader 12529 * accessibility tools. 12530 * @see #setScreenReaderFocusable(boolean) 12531 * 12532 * @return Whether the view should be treated as a focusable unit by screen reader. 12533 * 12534 * @attr ref android.R.styleable#View_screenReaderFocusable 12535 */ 12536 @InspectableProperty 12537 public boolean isScreenReaderFocusable() { 12538 return (mPrivateFlags3 & PFLAG3_SCREEN_READER_FOCUSABLE) != 0; 12539 } 12540 12541 /** 12542 * Sets whether this View should be a focusable element for screen readers 12543 * and include non-focusable Views from its subtree when providing feedback. 12544 * <p> 12545 * Note: this is similar to using <a href="#attr_android:focusable">{@code android:focusable}, 12546 * but does not impact input focus behavior. 12547 * 12548 * @param screenReaderFocusable Whether the view should be treated as a unit by screen reader 12549 * accessibility tools. 12550 * 12551 * @attr ref android.R.styleable#View_screenReaderFocusable 12552 */ 12553 public void setScreenReaderFocusable(boolean screenReaderFocusable) { 12554 updatePflags3AndNotifyA11yIfChanged(PFLAG3_SCREEN_READER_FOCUSABLE, screenReaderFocusable); 12555 } 12556 12557 /** 12558 * Gets whether this view is a heading for accessibility purposes. 12559 * 12560 * @return {@code true} if the view is a heading, {@code false} otherwise. 12561 * 12562 * @attr ref android.R.styleable#View_accessibilityHeading 12563 */ 12564 @InspectableProperty 12565 public boolean isAccessibilityHeading() { 12566 return (mPrivateFlags3 & PFLAG3_ACCESSIBILITY_HEADING) != 0; 12567 } 12568 12569 /** 12570 * Set if view is a heading for a section of content for accessibility purposes. 12571 * 12572 * @param isHeading {@code true} if the view is a heading, {@code false} otherwise. 12573 * 12574 * @attr ref android.R.styleable#View_accessibilityHeading 12575 */ 12576 public void setAccessibilityHeading(boolean isHeading) { 12577 updatePflags3AndNotifyA11yIfChanged(PFLAG3_ACCESSIBILITY_HEADING, isHeading); 12578 } 12579 12580 private void updatePflags3AndNotifyA11yIfChanged(int mask, boolean newValue) { 12581 int pflags3 = mPrivateFlags3; 12582 if (newValue) { 12583 pflags3 |= mask; 12584 } else { 12585 pflags3 &= ~mask; 12586 } 12587 12588 if (pflags3 != mPrivateFlags3) { 12589 mPrivateFlags3 = pflags3; 12590 notifyViewAccessibilityStateChangedIfNeeded( 12591 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 12592 } 12593 } 12594 12595 /** 12596 * Find the nearest view in the specified direction that can take focus. 12597 * This does not actually give focus to that view. 12598 * 12599 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 12600 * 12601 * @return The nearest focusable in the specified direction, or null if none 12602 * can be found. 12603 */ 12604 public View focusSearch(@FocusRealDirection int direction) { 12605 if (mParent != null) { 12606 return mParent.focusSearch(this, direction); 12607 } else { 12608 return null; 12609 } 12610 } 12611 12612 /** 12613 * Returns whether this View is a root of a keyboard navigation cluster. 12614 * 12615 * @return True if this view is a root of a cluster, or false otherwise. 12616 * @attr ref android.R.styleable#View_keyboardNavigationCluster 12617 */ 12618 @ViewDebug.ExportedProperty(category = "focus") 12619 @InspectableProperty 12620 public final boolean isKeyboardNavigationCluster() { 12621 return (mPrivateFlags3 & PFLAG3_CLUSTER) != 0; 12622 } 12623 12624 /** 12625 * Searches up the view hierarchy to find the top-most cluster. All deeper/nested clusters 12626 * will be ignored. 12627 * 12628 * @return the keyboard navigation cluster that this view is in (can be this view) 12629 * or {@code null} if not in one 12630 */ 12631 View findKeyboardNavigationCluster() { 12632 if (mParent instanceof View) { 12633 View cluster = ((View) mParent).findKeyboardNavigationCluster(); 12634 if (cluster != null) { 12635 return cluster; 12636 } else if (isKeyboardNavigationCluster()) { 12637 return this; 12638 } 12639 } 12640 return null; 12641 } 12642 12643 /** 12644 * Set whether this view is a root of a keyboard navigation cluster. 12645 * 12646 * @param isCluster If true, this view is a root of a cluster. 12647 * 12648 * @attr ref android.R.styleable#View_keyboardNavigationCluster 12649 */ 12650 public void setKeyboardNavigationCluster(boolean isCluster) { 12651 if (isCluster) { 12652 mPrivateFlags3 |= PFLAG3_CLUSTER; 12653 } else { 12654 mPrivateFlags3 &= ~PFLAG3_CLUSTER; 12655 } 12656 } 12657 12658 /** 12659 * Sets this View as the one which receives focus the next time cluster navigation jumps 12660 * to the cluster containing this View. This does NOT change focus even if the cluster 12661 * containing this view is current. 12662 * 12663 * @hide 12664 */ 12665 @TestApi 12666 public final void setFocusedInCluster() { 12667 setFocusedInCluster(findKeyboardNavigationCluster()); 12668 } 12669 12670 private void setFocusedInCluster(View cluster) { 12671 if (this instanceof ViewGroup) { 12672 ((ViewGroup) this).mFocusedInCluster = null; 12673 } 12674 if (cluster == this) { 12675 return; 12676 } 12677 ViewParent parent = mParent; 12678 View child = this; 12679 while (parent instanceof ViewGroup) { 12680 ((ViewGroup) parent).mFocusedInCluster = child; 12681 if (parent == cluster) { 12682 break; 12683 } 12684 child = (View) parent; 12685 parent = parent.getParent(); 12686 } 12687 } 12688 12689 private void updateFocusedInCluster(View oldFocus, @FocusDirection int direction) { 12690 if (oldFocus != null) { 12691 View oldCluster = oldFocus.findKeyboardNavigationCluster(); 12692 View cluster = findKeyboardNavigationCluster(); 12693 if (oldCluster != cluster) { 12694 // Going from one cluster to another, so save last-focused. 12695 // This covers cluster jumps because they are always FOCUS_DOWN 12696 oldFocus.setFocusedInCluster(oldCluster); 12697 if (!(oldFocus.mParent instanceof ViewGroup)) { 12698 return; 12699 } 12700 if (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) { 12701 // This is a result of ordered navigation so consider navigation through 12702 // the previous cluster "complete" and clear its last-focused memory. 12703 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 12704 } else if (oldFocus instanceof ViewGroup 12705 && ((ViewGroup) oldFocus).getDescendantFocusability() 12706 == ViewGroup.FOCUS_AFTER_DESCENDANTS 12707 && ViewRootImpl.isViewDescendantOf(this, oldFocus)) { 12708 // This means oldFocus is not focusable since it obviously has a focusable 12709 // child (this). Don't restore focus to it in the future. 12710 ((ViewGroup) oldFocus.mParent).clearFocusedInCluster(oldFocus); 12711 } 12712 } 12713 } 12714 } 12715 12716 /** 12717 * Returns whether this View should receive focus when the focus is restored for the view 12718 * hierarchy containing this view. 12719 * <p> 12720 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 12721 * window or serves as a target of cluster navigation. 12722 * 12723 * @see #restoreDefaultFocus() 12724 * 12725 * @return {@code true} if this view is the default-focus view, {@code false} otherwise 12726 * @attr ref android.R.styleable#View_focusedByDefault 12727 */ 12728 @ViewDebug.ExportedProperty(category = "focus") 12729 @InspectableProperty 12730 public final boolean isFocusedByDefault() { 12731 return (mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0; 12732 } 12733 12734 /** 12735 * Sets whether this View should receive focus when the focus is restored for the view 12736 * hierarchy containing this view. 12737 * <p> 12738 * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a 12739 * window or serves as a target of cluster navigation. 12740 * 12741 * @param isFocusedByDefault {@code true} to set this view as the default-focus view, 12742 * {@code false} otherwise. 12743 * 12744 * @see #restoreDefaultFocus() 12745 * 12746 * @attr ref android.R.styleable#View_focusedByDefault 12747 */ 12748 public void setFocusedByDefault(boolean isFocusedByDefault) { 12749 if (isFocusedByDefault == ((mPrivateFlags3 & PFLAG3_FOCUSED_BY_DEFAULT) != 0)) { 12750 return; 12751 } 12752 12753 if (isFocusedByDefault) { 12754 mPrivateFlags3 |= PFLAG3_FOCUSED_BY_DEFAULT; 12755 } else { 12756 mPrivateFlags3 &= ~PFLAG3_FOCUSED_BY_DEFAULT; 12757 } 12758 12759 if (mParent instanceof ViewGroup) { 12760 if (isFocusedByDefault) { 12761 ((ViewGroup) mParent).setDefaultFocus(this); 12762 } else { 12763 ((ViewGroup) mParent).clearDefaultFocus(this); 12764 } 12765 } 12766 } 12767 12768 /** 12769 * Returns whether the view hierarchy with this view as a root contain a default-focus view. 12770 * 12771 * @return {@code true} if this view has default focus, {@code false} otherwise 12772 */ 12773 boolean hasDefaultFocus() { 12774 return isFocusedByDefault(); 12775 } 12776 12777 /** 12778 * Find the nearest keyboard navigation cluster in the specified direction. 12779 * This does not actually give focus to that cluster. 12780 * 12781 * @param currentCluster The starting point of the search. Null means the current cluster is not 12782 * found yet 12783 * @param direction Direction to look 12784 * 12785 * @return The nearest keyboard navigation cluster in the specified direction, or null if none 12786 * can be found 12787 */ 12788 public View keyboardNavigationClusterSearch(View currentCluster, 12789 @FocusDirection int direction) { 12790 if (isKeyboardNavigationCluster()) { 12791 currentCluster = this; 12792 } 12793 if (isRootNamespace()) { 12794 // Root namespace means we should consider ourselves the top of the 12795 // tree for group searching; otherwise we could be group searching 12796 // into other tabs. see LocalActivityManager and TabHost for more info. 12797 return FocusFinder.getInstance().findNextKeyboardNavigationCluster( 12798 this, currentCluster, direction); 12799 } else if (mParent != null) { 12800 return mParent.keyboardNavigationClusterSearch(currentCluster, direction); 12801 } 12802 return null; 12803 } 12804 12805 /** 12806 * This method is the last chance for the focused view and its ancestors to 12807 * respond to an arrow key. This is called when the focused view did not 12808 * consume the key internally, nor could the view system find a new view in 12809 * the requested direction to give focus to. 12810 * 12811 * @param focused The currently focused view. 12812 * @param direction The direction focus wants to move. One of FOCUS_UP, 12813 * FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT. 12814 * @return True if the this view consumed this unhandled move. 12815 */ 12816 public boolean dispatchUnhandledMove(View focused, @FocusRealDirection int direction) { 12817 return false; 12818 } 12819 12820 /** 12821 * Sets whether this View should use a default focus highlight when it gets focused but doesn't 12822 * have {@link android.R.attr#state_focused} defined in its background. 12823 * 12824 * @param defaultFocusHighlightEnabled {@code true} to set this view to use a default focus 12825 * highlight, {@code false} otherwise. 12826 * 12827 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 12828 */ 12829 public void setDefaultFocusHighlightEnabled(boolean defaultFocusHighlightEnabled) { 12830 mDefaultFocusHighlightEnabled = defaultFocusHighlightEnabled; 12831 } 12832 12833 /** 12834 12835 /** 12836 * Returns whether this View should use a default focus highlight when it gets focused but 12837 * doesn't have {@link android.R.attr#state_focused} defined in its background. 12838 * 12839 * @return True if this View should use a default focus highlight. 12840 * @attr ref android.R.styleable#View_defaultFocusHighlightEnabled 12841 */ 12842 @ViewDebug.ExportedProperty(category = "focus") 12843 @InspectableProperty 12844 public final boolean getDefaultFocusHighlightEnabled() { 12845 return mDefaultFocusHighlightEnabled; 12846 } 12847 12848 /** 12849 * If a user manually specified the next view id for a particular direction, 12850 * use the root to look up the view. 12851 * @param root The root view of the hierarchy containing this view. 12852 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, FOCUS_RIGHT, FOCUS_FORWARD, 12853 * or FOCUS_BACKWARD. 12854 * @return The user specified next view, or null if there is none. 12855 */ 12856 View findUserSetNextFocus(View root, @FocusDirection int direction) { 12857 switch (direction) { 12858 case FOCUS_LEFT: 12859 if (mNextFocusLeftId == View.NO_ID) return null; 12860 return findViewInsideOutShouldExist(root, mNextFocusLeftId); 12861 case FOCUS_RIGHT: 12862 if (mNextFocusRightId == View.NO_ID) return null; 12863 return findViewInsideOutShouldExist(root, mNextFocusRightId); 12864 case FOCUS_UP: 12865 if (mNextFocusUpId == View.NO_ID) return null; 12866 return findViewInsideOutShouldExist(root, mNextFocusUpId); 12867 case FOCUS_DOWN: 12868 if (mNextFocusDownId == View.NO_ID) return null; 12869 return findViewInsideOutShouldExist(root, mNextFocusDownId); 12870 case FOCUS_FORWARD: 12871 if (mNextFocusForwardId == View.NO_ID) return null; 12872 return findViewInsideOutShouldExist(root, mNextFocusForwardId); 12873 case FOCUS_BACKWARD: { 12874 if (mID == View.NO_ID) return null; 12875 final View rootView = root; 12876 final View startView = this; 12877 // Since we have forward links but no backward links, we need to find the view that 12878 // forward links to this view. We can't just find the view with the specified ID 12879 // because view IDs need not be unique throughout the tree. 12880 return root.findViewByPredicateInsideOut(startView, 12881 t -> findViewInsideOutShouldExist(rootView, t, t.mNextFocusForwardId) 12882 == startView); 12883 } 12884 } 12885 return null; 12886 } 12887 12888 /** 12889 * If a user manually specified the next keyboard-navigation cluster for a particular direction, 12890 * use the root to look up the view. 12891 * 12892 * @param root the root view of the hierarchy containing this view 12893 * @param direction {@link #FOCUS_FORWARD} or {@link #FOCUS_BACKWARD} 12894 * @return the user-specified next cluster, or {@code null} if there is none 12895 */ 12896 View findUserSetNextKeyboardNavigationCluster(View root, @FocusDirection int direction) { 12897 switch (direction) { 12898 case FOCUS_FORWARD: 12899 if (mNextClusterForwardId == View.NO_ID) return null; 12900 return findViewInsideOutShouldExist(root, mNextClusterForwardId); 12901 case FOCUS_BACKWARD: { 12902 if (mID == View.NO_ID) return null; 12903 final int id = mID; 12904 return root.findViewByPredicateInsideOut(this, 12905 (Predicate<View>) t -> t.mNextClusterForwardId == id); 12906 } 12907 } 12908 return null; 12909 } 12910 12911 private View findViewInsideOutShouldExist(View root, int id) { 12912 return findViewInsideOutShouldExist(root, this, id); 12913 } 12914 12915 private View findViewInsideOutShouldExist(View root, View start, int id) { 12916 if (mMatchIdPredicate == null) { 12917 mMatchIdPredicate = new MatchIdPredicate(); 12918 } 12919 mMatchIdPredicate.mId = id; 12920 View result = root.findViewByPredicateInsideOut(start, mMatchIdPredicate); 12921 if (result == null) { 12922 Log.w(VIEW_LOG_TAG, "couldn't find view with id " + id); 12923 } 12924 return result; 12925 } 12926 12927 /** 12928 * Find and return all focusable views that are descendants of this view, 12929 * possibly including this view if it is focusable itself. 12930 * 12931 * @param direction The direction of the focus 12932 * @return A list of focusable views 12933 */ 12934 public ArrayList<View> getFocusables(@FocusDirection int direction) { 12935 ArrayList<View> result = new ArrayList<View>(24); 12936 addFocusables(result, direction); 12937 return result; 12938 } 12939 12940 /** 12941 * Add any focusable views that are descendants of this view (possibly 12942 * including this view if it is focusable itself) to views. If we are in touch mode, 12943 * only add views that are also focusable in touch mode. 12944 * 12945 * @param views Focusable views found so far 12946 * @param direction The direction of the focus 12947 */ 12948 public void addFocusables(ArrayList<View> views, @FocusDirection int direction) { 12949 addFocusables(views, direction, isInTouchMode() ? FOCUSABLES_TOUCH_MODE : FOCUSABLES_ALL); 12950 } 12951 12952 /** 12953 * Adds any focusable views that are descendants of this view (possibly 12954 * including this view if it is focusable itself) to views. This method 12955 * adds all focusable views regardless if we are in touch mode or 12956 * only views focusable in touch mode if we are in touch mode or 12957 * only views that can take accessibility focus if accessibility is enabled 12958 * depending on the focusable mode parameter. 12959 * 12960 * @param views Focusable views found so far or null if all we are interested is 12961 * the number of focusables. 12962 * @param direction The direction of the focus. 12963 * @param focusableMode The type of focusables to be added. 12964 * 12965 * @see #FOCUSABLES_ALL 12966 * @see #FOCUSABLES_TOUCH_MODE 12967 */ 12968 public void addFocusables(ArrayList<View> views, @FocusDirection int direction, 12969 @FocusableMode int focusableMode) { 12970 if (views == null) { 12971 return; 12972 } 12973 if (!canTakeFocus()) { 12974 return; 12975 } 12976 if ((focusableMode & FOCUSABLES_TOUCH_MODE) == FOCUSABLES_TOUCH_MODE 12977 && !isFocusableInTouchMode()) { 12978 return; 12979 } 12980 views.add(this); 12981 } 12982 12983 /** 12984 * Adds any keyboard navigation cluster roots that are descendants of this view (possibly 12985 * including this view if it is a cluster root itself) to views. 12986 * 12987 * @param views Keyboard navigation cluster roots found so far 12988 * @param direction Direction to look 12989 */ 12990 public void addKeyboardNavigationClusters( 12991 @NonNull Collection<View> views, 12992 int direction) { 12993 if (!isKeyboardNavigationCluster()) { 12994 return; 12995 } 12996 if (!hasFocusable()) { 12997 return; 12998 } 12999 views.add(this); 13000 } 13001 13002 /** 13003 * Finds the Views that contain given text. The containment is case insensitive. 13004 * The search is performed by either the text that the View renders or the content 13005 * description that describes the view for accessibility purposes and the view does 13006 * not render or both. Clients can specify how the search is to be performed via 13007 * passing the {@link #FIND_VIEWS_WITH_TEXT} and 13008 * {@link #FIND_VIEWS_WITH_CONTENT_DESCRIPTION} flags. 13009 * 13010 * @param outViews The output list of matching Views. 13011 * @param searched The text to match against. 13012 * 13013 * @see #FIND_VIEWS_WITH_TEXT 13014 * @see #FIND_VIEWS_WITH_CONTENT_DESCRIPTION 13015 * @see #setContentDescription(CharSequence) 13016 */ 13017 public void findViewsWithText(ArrayList<View> outViews, CharSequence searched, 13018 @FindViewFlags int flags) { 13019 if (getAccessibilityNodeProvider() != null) { 13020 if ((flags & FIND_VIEWS_WITH_ACCESSIBILITY_NODE_PROVIDERS) != 0) { 13021 outViews.add(this); 13022 } 13023 } else if ((flags & FIND_VIEWS_WITH_CONTENT_DESCRIPTION) != 0 13024 && (searched != null && searched.length() > 0) 13025 && (mContentDescription != null && mContentDescription.length() > 0)) { 13026 String searchedLowerCase = searched.toString().toLowerCase(); 13027 String contentDescriptionLowerCase = mContentDescription.toString().toLowerCase(); 13028 if (contentDescriptionLowerCase.contains(searchedLowerCase)) { 13029 outViews.add(this); 13030 } 13031 } 13032 } 13033 13034 /** 13035 * Find and return all touchable views that are descendants of this view, 13036 * possibly including this view if it is touchable itself. 13037 * 13038 * @return A list of touchable views 13039 */ 13040 public ArrayList<View> getTouchables() { 13041 ArrayList<View> result = new ArrayList<View>(); 13042 addTouchables(result); 13043 return result; 13044 } 13045 13046 /** 13047 * Add any touchable views that are descendants of this view (possibly 13048 * including this view if it is touchable itself) to views. 13049 * 13050 * @param views Touchable views found so far 13051 */ 13052 public void addTouchables(ArrayList<View> views) { 13053 final int viewFlags = mViewFlags; 13054 13055 if (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 13056 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) 13057 && (viewFlags & ENABLED_MASK) == ENABLED) { 13058 views.add(this); 13059 } 13060 } 13061 13062 /** 13063 * Returns whether this View is accessibility focused. 13064 * 13065 * @return True if this View is accessibility focused. 13066 */ 13067 @InspectableProperty(hasAttributeId = false) 13068 public boolean isAccessibilityFocused() { 13069 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0; 13070 } 13071 13072 /** 13073 * Call this to try to give accessibility focus to this view. 13074 * 13075 * A view will not actually take focus if {@link AccessibilityManager#isEnabled()} 13076 * returns false or the view is no visible or the view already has accessibility 13077 * focus. 13078 * 13079 * See also {@link #focusSearch(int)}, which is what you call to say that you 13080 * have focus, and you want your parent to look for the next one. 13081 * 13082 * @return Whether this view actually took accessibility focus. 13083 * 13084 * @hide 13085 */ 13086 @UnsupportedAppUsage 13087 public boolean requestAccessibilityFocus() { 13088 AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 13089 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 13090 return false; 13091 } 13092 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) { 13093 return false; 13094 } 13095 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) == 0) { 13096 mPrivateFlags2 |= PFLAG2_ACCESSIBILITY_FOCUSED; 13097 ViewRootImpl viewRootImpl = getViewRootImpl(); 13098 if (viewRootImpl != null) { 13099 viewRootImpl.setAccessibilityFocus(this, null); 13100 } 13101 invalidate(); 13102 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED); 13103 return true; 13104 } 13105 return false; 13106 } 13107 13108 /** 13109 * Call this to try to clear accessibility focus of this view. 13110 * 13111 * See also {@link #focusSearch(int)}, which is what you call to say that you 13112 * have focus, and you want your parent to look for the next one. 13113 * 13114 * @hide 13115 */ 13116 @UnsupportedAppUsage 13117 public void clearAccessibilityFocus() { 13118 clearAccessibilityFocusNoCallbacks(0); 13119 13120 // Clear the global reference of accessibility focus if this view or 13121 // any of its descendants had accessibility focus. This will NOT send 13122 // an event or update internal state if focus is cleared from a 13123 // descendant view, which may leave views in inconsistent states. 13124 final ViewRootImpl viewRootImpl = getViewRootImpl(); 13125 if (viewRootImpl != null) { 13126 final View focusHost = viewRootImpl.getAccessibilityFocusedHost(); 13127 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 13128 viewRootImpl.setAccessibilityFocus(null, null); 13129 } 13130 } 13131 } 13132 13133 private void sendAccessibilityHoverEvent(int eventType) { 13134 // Since we are not delivering to a client accessibility events from not 13135 // important views (unless the clinet request that) we need to fire the 13136 // event from the deepest view exposed to the client. As a consequence if 13137 // the user crosses a not exposed view the client will see enter and exit 13138 // of the exposed predecessor followed by and enter and exit of that same 13139 // predecessor when entering and exiting the not exposed descendant. This 13140 // is fine since the client has a clear idea which view is hovered at the 13141 // price of a couple more events being sent. This is a simple and 13142 // working solution. 13143 View source = this; 13144 while (true) { 13145 if (source.includeForAccessibility()) { 13146 source.sendAccessibilityEvent(eventType); 13147 return; 13148 } 13149 ViewParent parent = source.getParent(); 13150 if (parent instanceof View) { 13151 source = (View) parent; 13152 } else { 13153 return; 13154 } 13155 } 13156 } 13157 13158 /** 13159 * Clears accessibility focus without calling any callback methods 13160 * normally invoked in {@link #clearAccessibilityFocus()}. This method 13161 * is used separately from that one for clearing accessibility focus when 13162 * giving this focus to another view. 13163 * 13164 * @param action The action, if any, that led to focus being cleared. Set to 13165 * AccessibilityNodeInfo#ACTION_ACCESSIBILITY_FOCUS to specify that focus is moving within 13166 * the window. 13167 */ 13168 void clearAccessibilityFocusNoCallbacks(int action) { 13169 if ((mPrivateFlags2 & PFLAG2_ACCESSIBILITY_FOCUSED) != 0) { 13170 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_FOCUSED; 13171 invalidate(); 13172 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 13173 AccessibilityEvent event = AccessibilityEvent.obtain( 13174 AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED); 13175 event.setAction(action); 13176 if (mAccessibilityDelegate != null) { 13177 mAccessibilityDelegate.sendAccessibilityEventUnchecked(this, event); 13178 } else { 13179 sendAccessibilityEventUnchecked(event); 13180 } 13181 } 13182 } 13183 } 13184 13185 /** 13186 * Call this to try to give focus to a specific view or to one of its 13187 * descendants. 13188 * 13189 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 13190 * false), or if it can't be focused due to other conditions (not focusable in touch mode 13191 * ({@link #isFocusableInTouchMode}) while the device is in touch mode, not visible, not 13192 * enabled, or has no size). 13193 * 13194 * See also {@link #focusSearch(int)}, which is what you call to say that you 13195 * have focus, and you want your parent to look for the next one. 13196 * 13197 * This is equivalent to calling {@link #requestFocus(int, Rect)} with arguments 13198 * {@link #FOCUS_DOWN} and <code>null</code>. 13199 * 13200 * @return Whether this view or one of its descendants actually took focus. 13201 */ 13202 public final boolean requestFocus() { 13203 return requestFocus(View.FOCUS_DOWN); 13204 } 13205 13206 /** 13207 * This will request focus for whichever View was last focused within this 13208 * cluster before a focus-jump out of it. 13209 * 13210 * @hide 13211 */ 13212 @TestApi 13213 public boolean restoreFocusInCluster(@FocusRealDirection int direction) { 13214 // Prioritize focusableByDefault over algorithmic focus selection. 13215 if (restoreDefaultFocus()) { 13216 return true; 13217 } 13218 return requestFocus(direction); 13219 } 13220 13221 /** 13222 * This will request focus for whichever View not in a cluster was last focused before a 13223 * focus-jump to a cluster. If no non-cluster View has previously had focus, this will focus 13224 * the "first" focusable view it finds. 13225 * 13226 * @hide 13227 */ 13228 @TestApi 13229 public boolean restoreFocusNotInCluster() { 13230 return requestFocus(View.FOCUS_DOWN); 13231 } 13232 13233 /** 13234 * Gives focus to the default-focus view in the view hierarchy that has this view as a root. 13235 * If the default-focus view cannot be found, falls back to calling {@link #requestFocus(int)}. 13236 * 13237 * @return Whether this view or one of its descendants actually took focus 13238 */ 13239 public boolean restoreDefaultFocus() { 13240 return requestFocus(View.FOCUS_DOWN); 13241 } 13242 13243 /** 13244 * Call this to try to give focus to a specific view or to one of its 13245 * descendants and give it a hint about what direction focus is heading. 13246 * 13247 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 13248 * false), or if it is focusable and it is not focusable in touch mode 13249 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 13250 * 13251 * See also {@link #focusSearch(int)}, which is what you call to say that you 13252 * have focus, and you want your parent to look for the next one. 13253 * 13254 * This is equivalent to calling {@link #requestFocus(int, Rect)} with 13255 * <code>null</code> set for the previously focused rectangle. 13256 * 13257 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 13258 * @return Whether this view or one of its descendants actually took focus. 13259 */ 13260 public final boolean requestFocus(int direction) { 13261 return requestFocus(direction, null); 13262 } 13263 13264 /** 13265 * Call this to try to give focus to a specific view or to one of its descendants 13266 * and give it hints about the direction and a specific rectangle that the focus 13267 * is coming from. The rectangle can help give larger views a finer grained hint 13268 * about where focus is coming from, and therefore, where to show selection, or 13269 * forward focus change internally. 13270 * 13271 * A view will not actually take focus if it is not focusable ({@link #isFocusable} returns 13272 * false), or if it is focusable and it is not focusable in touch mode 13273 * ({@link #isFocusableInTouchMode}) while the device is in touch mode. 13274 * 13275 * A View will not take focus if it is not visible. 13276 * 13277 * A View will not take focus if one of its parents has 13278 * {@link android.view.ViewGroup#getDescendantFocusability()} equal to 13279 * {@link ViewGroup#FOCUS_BLOCK_DESCENDANTS}. 13280 * 13281 * See also {@link #focusSearch(int)}, which is what you call to say that you 13282 * have focus, and you want your parent to look for the next one. 13283 * 13284 * You may wish to override this method if your custom {@link View} has an internal 13285 * {@link View} that it wishes to forward the request to. 13286 * 13287 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT 13288 * @param previouslyFocusedRect The rectangle (in this View's coordinate system) 13289 * to give a finer grained hint about where focus is coming from. May be null 13290 * if there is no hint. 13291 * @return Whether this view or one of its descendants actually took focus. 13292 */ 13293 public boolean requestFocus(int direction, Rect previouslyFocusedRect) { 13294 return requestFocusNoSearch(direction, previouslyFocusedRect); 13295 } 13296 13297 private boolean requestFocusNoSearch(int direction, Rect previouslyFocusedRect) { 13298 // need to be focusable 13299 if (!canTakeFocus()) { 13300 return false; 13301 } 13302 13303 // need to be focusable in touch mode if in touch mode 13304 if (isInTouchMode() && 13305 (FOCUSABLE_IN_TOUCH_MODE != (mViewFlags & FOCUSABLE_IN_TOUCH_MODE))) { 13306 return false; 13307 } 13308 13309 // need to not have any parents blocking us 13310 if (hasAncestorThatBlocksDescendantFocus()) { 13311 return false; 13312 } 13313 13314 if (!isLayoutValid()) { 13315 mPrivateFlags |= PFLAG_WANTS_FOCUS; 13316 } else { 13317 clearParentsWantFocus(); 13318 } 13319 13320 handleFocusGainInternal(direction, previouslyFocusedRect); 13321 return true; 13322 } 13323 13324 void clearParentsWantFocus() { 13325 if (mParent instanceof View) { 13326 ((View) mParent).mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 13327 ((View) mParent).clearParentsWantFocus(); 13328 } 13329 } 13330 13331 /** 13332 * Call this to try to give focus to a specific view or to one of its descendants. This is a 13333 * special variant of {@link #requestFocus() } that will allow views that are not focusable in 13334 * touch mode to request focus when they are touched. 13335 * 13336 * @return Whether this view or one of its descendants actually took focus. 13337 * 13338 * @see #isInTouchMode() 13339 * 13340 */ 13341 public final boolean requestFocusFromTouch() { 13342 // Leave touch mode if we need to 13343 if (isInTouchMode()) { 13344 ViewRootImpl viewRoot = getViewRootImpl(); 13345 if (viewRoot != null) { 13346 viewRoot.ensureTouchMode(false); 13347 } 13348 } 13349 return requestFocus(View.FOCUS_DOWN); 13350 } 13351 13352 /** 13353 * @return Whether any ancestor of this view blocks descendant focus. 13354 */ 13355 private boolean hasAncestorThatBlocksDescendantFocus() { 13356 final boolean focusableInTouchMode = isFocusableInTouchMode(); 13357 ViewParent ancestor = mParent; 13358 while (ancestor instanceof ViewGroup) { 13359 final ViewGroup vgAncestor = (ViewGroup) ancestor; 13360 if (vgAncestor.getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS 13361 || (!focusableInTouchMode && vgAncestor.shouldBlockFocusForTouchscreen())) { 13362 return true; 13363 } else { 13364 ancestor = vgAncestor.getParent(); 13365 } 13366 } 13367 return false; 13368 } 13369 13370 /** 13371 * Gets the mode for determining whether this View is important for accessibility. 13372 * A view is important for accessibility if it fires accessibility events and if it 13373 * is reported to accessibility services that query the screen. 13374 * 13375 * @return The mode for determining whether a view is important for accessibility, one 13376 * of {@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, {@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, 13377 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO}, or 13378 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}. 13379 * 13380 * @attr ref android.R.styleable#View_importantForAccessibility 13381 * 13382 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 13383 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 13384 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 13385 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 13386 */ 13387 @ViewDebug.ExportedProperty(category = "accessibility", mapping = { 13388 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_AUTO, to = "auto"), 13389 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_YES, to = "yes"), 13390 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO, to = "no"), 13391 @ViewDebug.IntToString(from = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 13392 to = "noHideDescendants") 13393 }) 13394 @InspectableProperty(enumMapping = { 13395 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_AUTO, name = "auto"), 13396 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_YES, name = "yes"), 13397 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO, name = "no"), 13398 @EnumEntry(value = IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS, 13399 name = "noHideDescendants"), 13400 }) 13401 public int getImportantForAccessibility() { 13402 return (mPrivateFlags2 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK) 13403 >> PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT; 13404 } 13405 13406 /** 13407 * Sets the live region mode for this view. This indicates to accessibility 13408 * services whether they should automatically notify the user about changes 13409 * to the view's content description or text, or to the content descriptions 13410 * or text of the view's children (where applicable). 13411 * <p> 13412 * For example, in a login screen with a TextView that displays an "incorrect 13413 * password" notification, that view should be marked as a live region with 13414 * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 13415 * <p> 13416 * To disable change notifications for this view, use 13417 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region 13418 * mode for most views. 13419 * <p> 13420 * To indicate that the user should be notified of changes, use 13421 * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}. 13422 * <p> 13423 * If the view's changes should interrupt ongoing speech and notify the user 13424 * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}. 13425 * 13426 * @param mode The live region mode for this view, one of: 13427 * <ul> 13428 * <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE} 13429 * <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE} 13430 * <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE} 13431 * </ul> 13432 * @attr ref android.R.styleable#View_accessibilityLiveRegion 13433 */ 13434 public void setAccessibilityLiveRegion(int mode) { 13435 if (mode != getAccessibilityLiveRegion()) { 13436 mPrivateFlags2 &= ~PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 13437 mPrivateFlags2 |= (mode << PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT) 13438 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK; 13439 notifyViewAccessibilityStateChangedIfNeeded( 13440 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13441 } 13442 } 13443 13444 /** 13445 * Gets the live region mode for this View. 13446 * 13447 * @return The live region mode for the view. 13448 * 13449 * @attr ref android.R.styleable#View_accessibilityLiveRegion 13450 * 13451 * @see #setAccessibilityLiveRegion(int) 13452 */ 13453 @InspectableProperty(enumMapping = { 13454 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_NONE, name = "none"), 13455 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_POLITE, name = "polite"), 13456 @EnumEntry(value = ACCESSIBILITY_LIVE_REGION_ASSERTIVE, name = "assertive") 13457 }) 13458 public int getAccessibilityLiveRegion() { 13459 return (mPrivateFlags2 & PFLAG2_ACCESSIBILITY_LIVE_REGION_MASK) 13460 >> PFLAG2_ACCESSIBILITY_LIVE_REGION_SHIFT; 13461 } 13462 13463 /** 13464 * Sets how to determine whether this view is important for accessibility 13465 * which is if it fires accessibility events and if it is reported to 13466 * accessibility services that query the screen. 13467 * 13468 * @param mode How to determine whether this view is important for accessibility. 13469 * 13470 * @attr ref android.R.styleable#View_importantForAccessibility 13471 * 13472 * @see #IMPORTANT_FOR_ACCESSIBILITY_YES 13473 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO 13474 * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS 13475 * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO 13476 */ 13477 public void setImportantForAccessibility(int mode) { 13478 final int oldMode = getImportantForAccessibility(); 13479 if (mode != oldMode) { 13480 final boolean hideDescendants = 13481 mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS; 13482 13483 // If this node or its descendants are no longer important, try to 13484 // clear accessibility focus. 13485 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO || hideDescendants) { 13486 final View focusHost = findAccessibilityFocusHost(hideDescendants); 13487 if (focusHost != null) { 13488 focusHost.clearAccessibilityFocus(); 13489 } 13490 } 13491 13492 // If we're moving between AUTO and another state, we might not need 13493 // to send a subtree changed notification. We'll store the computed 13494 // importance, since we'll need to check it later to make sure. 13495 final boolean maySkipNotify = oldMode == IMPORTANT_FOR_ACCESSIBILITY_AUTO 13496 || mode == IMPORTANT_FOR_ACCESSIBILITY_AUTO; 13497 final boolean oldIncludeForAccessibility = maySkipNotify && includeForAccessibility(); 13498 mPrivateFlags2 &= ~PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 13499 mPrivateFlags2 |= (mode << PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_SHIFT) 13500 & PFLAG2_IMPORTANT_FOR_ACCESSIBILITY_MASK; 13501 if (!maySkipNotify || oldIncludeForAccessibility != includeForAccessibility()) { 13502 notifySubtreeAccessibilityStateChangedIfNeeded(); 13503 } else { 13504 notifyViewAccessibilityStateChangedIfNeeded( 13505 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13506 } 13507 } 13508 } 13509 13510 /** 13511 * Returns the view within this view's hierarchy that is hosting 13512 * accessibility focus. 13513 * 13514 * @param searchDescendants whether to search for focus in descendant views 13515 * @return the view hosting accessibility focus, or {@code null} 13516 */ 13517 private View findAccessibilityFocusHost(boolean searchDescendants) { 13518 if (isAccessibilityFocusedViewOrHost()) { 13519 return this; 13520 } 13521 13522 if (searchDescendants) { 13523 final ViewRootImpl viewRoot = getViewRootImpl(); 13524 if (viewRoot != null) { 13525 final View focusHost = viewRoot.getAccessibilityFocusedHost(); 13526 if (focusHost != null && ViewRootImpl.isViewDescendantOf(focusHost, this)) { 13527 return focusHost; 13528 } 13529 } 13530 } 13531 13532 return null; 13533 } 13534 13535 /** 13536 * Computes whether this view should be exposed for accessibility. In 13537 * general, views that are interactive or provide information are exposed 13538 * while views that serve only as containers are hidden. 13539 * <p> 13540 * If an ancestor of this view has importance 13541 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method 13542 * returns <code>false</code>. 13543 * <p> 13544 * Otherwise, the value is computed according to the view's 13545 * {@link #getImportantForAccessibility()} value: 13546 * <ol> 13547 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or 13548 * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false 13549 * </code> 13550 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code> 13551 * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if 13552 * view satisfies any of the following: 13553 * <ul> 13554 * <li>Is actionable, e.g. {@link #isClickable()}, 13555 * {@link #isLongClickable()}, or {@link #isFocusable()} 13556 * <li>Has an {@link AccessibilityDelegate} 13557 * <li>Has an interaction listener, e.g. {@link OnTouchListener}, 13558 * {@link OnKeyListener}, etc. 13559 * <li>Is an accessibility live region, e.g. 13560 * {@link #getAccessibilityLiveRegion()} is not 13561 * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. 13562 * </ul> 13563 * <li>Has an accessibility pane title, see {@link #setAccessibilityPaneTitle}</li> 13564 * </ol> 13565 * 13566 * @return Whether the view is exposed for accessibility. 13567 * @see #setImportantForAccessibility(int) 13568 * @see #getImportantForAccessibility() 13569 */ 13570 public boolean isImportantForAccessibility() { 13571 final int mode = getImportantForAccessibility(); 13572 if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO 13573 || mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 13574 return false; 13575 } 13576 13577 // Check parent mode to ensure we're not hidden. 13578 ViewParent parent = mParent; 13579 while (parent instanceof View) { 13580 if (((View) parent).getImportantForAccessibility() 13581 == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) { 13582 return false; 13583 } 13584 parent = parent.getParent(); 13585 } 13586 13587 return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() 13588 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null 13589 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE 13590 || isAccessibilityPane(); 13591 } 13592 13593 /** 13594 * Gets the parent for accessibility purposes. Note that the parent for 13595 * accessibility is not necessary the immediate parent. It is the first 13596 * predecessor that is important for accessibility. 13597 * 13598 * @return The parent for accessibility purposes. 13599 */ 13600 public ViewParent getParentForAccessibility() { 13601 if (mParent instanceof View) { 13602 View parentView = (View) mParent; 13603 if (parentView.includeForAccessibility()) { 13604 return mParent; 13605 } else { 13606 return mParent.getParentForAccessibility(); 13607 } 13608 } 13609 return null; 13610 } 13611 13612 /** @hide */ 13613 View getSelfOrParentImportantForA11y() { 13614 if (isImportantForAccessibility()) return this; 13615 ViewParent parent = getParentForAccessibility(); 13616 if (parent instanceof View) return (View) parent; 13617 return null; 13618 } 13619 13620 /** 13621 * Adds the children of this View relevant for accessibility to the given list 13622 * as output. Since some Views are not important for accessibility the added 13623 * child views are not necessarily direct children of this view, rather they are 13624 * the first level of descendants important for accessibility. 13625 * 13626 * @param outChildren The output list that will receive children for accessibility. 13627 */ 13628 public void addChildrenForAccessibility(ArrayList<View> outChildren) { 13629 13630 } 13631 13632 /** 13633 * Whether to regard this view for accessibility. A view is regarded for 13634 * accessibility if it is important for accessibility or the querying 13635 * accessibility service has explicitly requested that view not 13636 * important for accessibility are regarded. 13637 * 13638 * @return Whether to regard the view for accessibility. 13639 * 13640 * @hide 13641 */ 13642 @UnsupportedAppUsage 13643 public boolean includeForAccessibility() { 13644 if (mAttachInfo != null) { 13645 return (mAttachInfo.mAccessibilityFetchFlags 13646 & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0 13647 || isImportantForAccessibility(); 13648 } 13649 return false; 13650 } 13651 13652 /** 13653 * Returns whether the View is considered actionable from 13654 * accessibility perspective. Such view are important for 13655 * accessibility. 13656 * 13657 * @return True if the view is actionable for accessibility. 13658 * 13659 * @hide 13660 */ 13661 public boolean isActionableForAccessibility() { 13662 return (isClickable() || isLongClickable() || isFocusable()); 13663 } 13664 13665 /** 13666 * Returns whether the View has registered callbacks which makes it 13667 * important for accessibility. 13668 * 13669 * @return True if the view is actionable for accessibility. 13670 */ 13671 private boolean hasListenersForAccessibility() { 13672 ListenerInfo info = getListenerInfo(); 13673 return mTouchDelegate != null || info.mOnKeyListener != null 13674 || info.mOnTouchListener != null || info.mOnGenericMotionListener != null 13675 || info.mOnHoverListener != null || info.mOnDragListener != null; 13676 } 13677 13678 /** 13679 * Notifies that the accessibility state of this view changed. The change 13680 * is local to this view and does not represent structural changes such 13681 * as children and parent. For example, the view became focusable. The 13682 * notification is at at most once every 13683 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 13684 * to avoid unnecessary load to the system. Also once a view has a pending 13685 * notification this method is a NOP until the notification has been sent. 13686 * 13687 * @hide 13688 */ 13689 @UnsupportedAppUsage 13690 public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) { 13691 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 13692 return; 13693 } 13694 13695 // Changes to views with a pane title count as window state changes, as the pane title 13696 // marks them as significant parts of the UI. 13697 if ((changeType != AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE) 13698 && isAccessibilityPane()) { 13699 // If the pane isn't visible, content changed events are sufficient unless we're 13700 // reporting that the view just disappeared 13701 if ((getVisibility() == VISIBLE) 13702 || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)) { 13703 final AccessibilityEvent event = AccessibilityEvent.obtain(); 13704 onInitializeAccessibilityEvent(event); 13705 event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED); 13706 event.setContentChangeTypes(changeType); 13707 event.setSource(this); 13708 onPopulateAccessibilityEvent(event); 13709 if (mParent != null) { 13710 try { 13711 mParent.requestSendAccessibilityEvent(this, event); 13712 } catch (AbstractMethodError e) { 13713 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() 13714 + " does not fully implement ViewParent", e); 13715 } 13716 } 13717 return; 13718 } 13719 } 13720 13721 // If this is a live region, we should send a subtree change event 13722 // from this view immediately. Otherwise, we can let it propagate up. 13723 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) { 13724 final AccessibilityEvent event = AccessibilityEvent.obtain(); 13725 event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); 13726 event.setContentChangeTypes(changeType); 13727 sendAccessibilityEventUnchecked(event); 13728 } else if (mParent != null) { 13729 try { 13730 mParent.notifySubtreeAccessibilityStateChanged(this, this, changeType); 13731 } catch (AbstractMethodError e) { 13732 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 13733 " does not fully implement ViewParent", e); 13734 } 13735 } 13736 } 13737 13738 /** 13739 * Notifies that the accessibility state of this view changed. The change 13740 * is *not* local to this view and does represent structural changes such 13741 * as children and parent. For example, the view size changed. The 13742 * notification is at at most once every 13743 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()} 13744 * to avoid unnecessary load to the system. Also once a view has a pending 13745 * notification this method is a NOP until the notification has been sent. 13746 * 13747 * @hide 13748 */ 13749 @UnsupportedAppUsage 13750 public void notifySubtreeAccessibilityStateChangedIfNeeded() { 13751 if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) { 13752 return; 13753 } 13754 13755 if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) { 13756 mPrivateFlags2 |= PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 13757 if (mParent != null) { 13758 try { 13759 mParent.notifySubtreeAccessibilityStateChanged( 13760 this, this, AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE); 13761 } catch (AbstractMethodError e) { 13762 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 13763 " does not fully implement ViewParent", e); 13764 } 13765 } 13766 } 13767 } 13768 13769 /** 13770 * Changes the visibility of this View without triggering any other changes. This should only 13771 * be used by animation frameworks, such as {@link android.transition.Transition}, where 13772 * visibility changes should not adjust focus or trigger a new layout. Application developers 13773 * should use {@link #setVisibility} instead to ensure that the hierarchy is correctly updated. 13774 * 13775 * <p>Only call this method when a temporary visibility must be applied during an 13776 * animation and the original visibility value is guaranteed to be reset after the 13777 * animation completes. Use {@link #setVisibility} in all other cases.</p> 13778 * 13779 * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. 13780 * @see #setVisibility(int) 13781 */ 13782 public void setTransitionVisibility(@Visibility int visibility) { 13783 mViewFlags = (mViewFlags & ~View.VISIBILITY_MASK) | visibility; 13784 } 13785 13786 /** 13787 * Reset the flag indicating the accessibility state of the subtree rooted 13788 * at this view changed. 13789 */ 13790 void resetSubtreeAccessibilityStateChanged() { 13791 mPrivateFlags2 &= ~PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED; 13792 } 13793 13794 /** 13795 * Report an accessibility action to this view's parents for delegated processing. 13796 * 13797 * <p>Implementations of {@link #performAccessibilityAction(int, Bundle)} may internally 13798 * call this method to delegate an accessibility action to a supporting parent. If the parent 13799 * returns true from its 13800 * {@link ViewParent#onNestedPrePerformAccessibilityAction(View, int, android.os.Bundle)} 13801 * method this method will return true to signify that the action was consumed.</p> 13802 * 13803 * <p>This method is useful for implementing nested scrolling child views. If 13804 * {@link #isNestedScrollingEnabled()} returns true and the action is a scrolling action 13805 * a custom view implementation may invoke this method to allow a parent to consume the 13806 * scroll first. If this method returns true the custom view should skip its own scrolling 13807 * behavior.</p> 13808 * 13809 * @param action Accessibility action to delegate 13810 * @param arguments Optional action arguments 13811 * @return true if the action was consumed by a parent 13812 */ 13813 public boolean dispatchNestedPrePerformAccessibilityAction(int action, Bundle arguments) { 13814 for (ViewParent p = getParent(); p != null; p = p.getParent()) { 13815 if (p.onNestedPrePerformAccessibilityAction(this, action, arguments)) { 13816 return true; 13817 } 13818 } 13819 return false; 13820 } 13821 13822 /** 13823 * Performs the specified accessibility action on the view. For 13824 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 13825 * <p> 13826 * If an {@link AccessibilityDelegate} has been specified via calling 13827 * {@link #setAccessibilityDelegate(AccessibilityDelegate)} its 13828 * {@link AccessibilityDelegate#performAccessibilityAction(View, int, Bundle)} 13829 * is responsible for handling this call. 13830 * </p> 13831 * 13832 * <p>The default implementation will delegate 13833 * {@link AccessibilityNodeInfo#ACTION_SCROLL_BACKWARD} and 13834 * {@link AccessibilityNodeInfo#ACTION_SCROLL_FORWARD} to nested scrolling parents if 13835 * {@link #isNestedScrollingEnabled() nested scrolling is enabled} on this view.</p> 13836 * 13837 * @param action The action to perform. 13838 * @param arguments Optional action arguments. 13839 * @return Whether the action was performed. 13840 */ 13841 public boolean performAccessibilityAction(int action, Bundle arguments) { 13842 if (mAccessibilityDelegate != null) { 13843 return mAccessibilityDelegate.performAccessibilityAction(this, action, arguments); 13844 } else { 13845 return performAccessibilityActionInternal(action, arguments); 13846 } 13847 } 13848 13849 /** 13850 * @see #performAccessibilityAction(int, Bundle) 13851 * 13852 * Note: Called from the default {@link AccessibilityDelegate}. 13853 * 13854 * @hide 13855 */ 13856 @UnsupportedAppUsage 13857 public boolean performAccessibilityActionInternal(int action, Bundle arguments) { 13858 if (isNestedScrollingEnabled() 13859 && (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD 13860 || action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD 13861 || action == R.id.accessibilityActionScrollUp 13862 || action == R.id.accessibilityActionScrollLeft 13863 || action == R.id.accessibilityActionScrollDown 13864 || action == R.id.accessibilityActionScrollRight)) { 13865 if (dispatchNestedPrePerformAccessibilityAction(action, arguments)) { 13866 return true; 13867 } 13868 } 13869 13870 switch (action) { 13871 case AccessibilityNodeInfo.ACTION_CLICK: { 13872 if (isClickable()) { 13873 performClickInternal(); 13874 return true; 13875 } 13876 } break; 13877 case AccessibilityNodeInfo.ACTION_LONG_CLICK: { 13878 if (isLongClickable()) { 13879 performLongClick(); 13880 return true; 13881 } 13882 } break; 13883 case AccessibilityNodeInfo.ACTION_FOCUS: { 13884 if (!hasFocus()) { 13885 // Get out of touch mode since accessibility 13886 // wants to move focus around. 13887 getViewRootImpl().ensureTouchMode(false); 13888 return requestFocus(); 13889 } 13890 } break; 13891 case AccessibilityNodeInfo.ACTION_CLEAR_FOCUS: { 13892 if (hasFocus()) { 13893 clearFocus(); 13894 return !isFocused(); 13895 } 13896 } break; 13897 case AccessibilityNodeInfo.ACTION_SELECT: { 13898 if (!isSelected()) { 13899 setSelected(true); 13900 return isSelected(); 13901 } 13902 } break; 13903 case AccessibilityNodeInfo.ACTION_CLEAR_SELECTION: { 13904 if (isSelected()) { 13905 setSelected(false); 13906 return !isSelected(); 13907 } 13908 } break; 13909 case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: { 13910 if (!isAccessibilityFocused()) { 13911 return requestAccessibilityFocus(); 13912 } 13913 } break; 13914 case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: { 13915 if (isAccessibilityFocused()) { 13916 clearAccessibilityFocus(); 13917 return true; 13918 } 13919 } break; 13920 case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: { 13921 if (arguments != null) { 13922 final int granularity = arguments.getInt( 13923 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 13924 final boolean extendSelection = arguments.getBoolean( 13925 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 13926 return traverseAtGranularity(granularity, true, extendSelection); 13927 } 13928 } break; 13929 case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { 13930 if (arguments != null) { 13931 final int granularity = arguments.getInt( 13932 AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT); 13933 final boolean extendSelection = arguments.getBoolean( 13934 AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN); 13935 return traverseAtGranularity(granularity, false, extendSelection); 13936 } 13937 } break; 13938 case AccessibilityNodeInfo.ACTION_SET_SELECTION: { 13939 CharSequence text = getIterableTextForAccessibility(); 13940 if (text == null) { 13941 return false; 13942 } 13943 final int start = (arguments != null) ? arguments.getInt( 13944 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_START_INT, -1) : -1; 13945 final int end = (arguments != null) ? arguments.getInt( 13946 AccessibilityNodeInfo.ACTION_ARGUMENT_SELECTION_END_INT, -1) : -1; 13947 // Only cursor position can be specified (selection length == 0) 13948 if ((getAccessibilitySelectionStart() != start 13949 || getAccessibilitySelectionEnd() != end) 13950 && (start == end)) { 13951 setAccessibilitySelection(start, end); 13952 notifyViewAccessibilityStateChangedIfNeeded( 13953 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 13954 return true; 13955 } 13956 } break; 13957 case R.id.accessibilityActionShowOnScreen: { 13958 if (mAttachInfo != null) { 13959 final Rect r = mAttachInfo.mTmpInvalRect; 13960 getDrawingRect(r); 13961 return requestRectangleOnScreen(r, true); 13962 } 13963 } break; 13964 case R.id.accessibilityActionContextClick: { 13965 if (isContextClickable()) { 13966 performContextClick(); 13967 return true; 13968 } 13969 } break; 13970 case R.id.accessibilityActionShowTooltip: { 13971 if ((mTooltipInfo != null) && (mTooltipInfo.mTooltipPopup != null)) { 13972 // Tooltip already showing 13973 return false; 13974 } 13975 return showLongClickTooltip(0, 0); 13976 } 13977 case R.id.accessibilityActionHideTooltip: { 13978 if ((mTooltipInfo == null) || (mTooltipInfo.mTooltipPopup == null)) { 13979 // No tooltip showing 13980 return false; 13981 } 13982 hideTooltip(); 13983 return true; 13984 } 13985 } 13986 return false; 13987 } 13988 13989 private boolean traverseAtGranularity(int granularity, boolean forward, 13990 boolean extendSelection) { 13991 CharSequence text = getIterableTextForAccessibility(); 13992 if (text == null || text.length() == 0) { 13993 return false; 13994 } 13995 TextSegmentIterator iterator = getIteratorForGranularity(granularity); 13996 if (iterator == null) { 13997 return false; 13998 } 13999 int current = getAccessibilitySelectionEnd(); 14000 if (current == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 14001 current = forward ? 0 : text.length(); 14002 } 14003 final int[] range = forward ? iterator.following(current) : iterator.preceding(current); 14004 if (range == null) { 14005 return false; 14006 } 14007 final int segmentStart = range[0]; 14008 final int segmentEnd = range[1]; 14009 int selectionStart; 14010 int selectionEnd; 14011 if (extendSelection && isAccessibilitySelectionExtendable()) { 14012 selectionStart = getAccessibilitySelectionStart(); 14013 if (selectionStart == ACCESSIBILITY_CURSOR_POSITION_UNDEFINED) { 14014 selectionStart = forward ? segmentStart : segmentEnd; 14015 } 14016 selectionEnd = forward ? segmentEnd : segmentStart; 14017 } else { 14018 selectionStart = selectionEnd= forward ? segmentEnd : segmentStart; 14019 } 14020 setAccessibilitySelection(selectionStart, selectionEnd); 14021 final int action = forward ? AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY 14022 : AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY; 14023 sendViewTextTraversedAtGranularityEvent(action, granularity, segmentStart, segmentEnd); 14024 return true; 14025 } 14026 14027 /** 14028 * Gets the text reported for accessibility purposes. 14029 * 14030 * @return The accessibility text. 14031 * 14032 * @hide 14033 */ 14034 @UnsupportedAppUsage 14035 public CharSequence getIterableTextForAccessibility() { 14036 return getContentDescription(); 14037 } 14038 14039 /** 14040 * Gets whether accessibility selection can be extended. 14041 * 14042 * @return If selection is extensible. 14043 * 14044 * @hide 14045 */ 14046 public boolean isAccessibilitySelectionExtendable() { 14047 return false; 14048 } 14049 14050 /** 14051 * @hide 14052 */ 14053 public int getAccessibilitySelectionStart() { 14054 return mAccessibilityCursorPosition; 14055 } 14056 14057 /** 14058 * @hide 14059 */ 14060 public int getAccessibilitySelectionEnd() { 14061 return getAccessibilitySelectionStart(); 14062 } 14063 14064 /** 14065 * @hide 14066 */ 14067 public void setAccessibilitySelection(int start, int end) { 14068 if (start == end && end == mAccessibilityCursorPosition) { 14069 return; 14070 } 14071 if (start >= 0 && start == end && end <= getIterableTextForAccessibility().length()) { 14072 mAccessibilityCursorPosition = start; 14073 } else { 14074 mAccessibilityCursorPosition = ACCESSIBILITY_CURSOR_POSITION_UNDEFINED; 14075 } 14076 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED); 14077 } 14078 14079 private void sendViewTextTraversedAtGranularityEvent(int action, int granularity, 14080 int fromIndex, int toIndex) { 14081 if (mParent == null) { 14082 return; 14083 } 14084 AccessibilityEvent event = AccessibilityEvent.obtain( 14085 AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY); 14086 onInitializeAccessibilityEvent(event); 14087 onPopulateAccessibilityEvent(event); 14088 event.setFromIndex(fromIndex); 14089 event.setToIndex(toIndex); 14090 event.setAction(action); 14091 event.setMovementGranularity(granularity); 14092 mParent.requestSendAccessibilityEvent(this, event); 14093 } 14094 14095 /** 14096 * @hide 14097 */ 14098 @UnsupportedAppUsage 14099 public TextSegmentIterator getIteratorForGranularity(int granularity) { 14100 switch (granularity) { 14101 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER: { 14102 CharSequence text = getIterableTextForAccessibility(); 14103 if (text != null && text.length() > 0) { 14104 CharacterTextSegmentIterator iterator = 14105 CharacterTextSegmentIterator.getInstance( 14106 mContext.getResources().getConfiguration().locale); 14107 iterator.initialize(text.toString()); 14108 return iterator; 14109 } 14110 } break; 14111 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_WORD: { 14112 CharSequence text = getIterableTextForAccessibility(); 14113 if (text != null && text.length() > 0) { 14114 WordTextSegmentIterator iterator = 14115 WordTextSegmentIterator.getInstance( 14116 mContext.getResources().getConfiguration().locale); 14117 iterator.initialize(text.toString()); 14118 return iterator; 14119 } 14120 } break; 14121 case AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH: { 14122 CharSequence text = getIterableTextForAccessibility(); 14123 if (text != null && text.length() > 0) { 14124 ParagraphTextSegmentIterator iterator = 14125 ParagraphTextSegmentIterator.getInstance(); 14126 iterator.initialize(text.toString()); 14127 return iterator; 14128 } 14129 } break; 14130 } 14131 return null; 14132 } 14133 14134 /** 14135 * Tells whether the {@link View} is in the state between {@link #onStartTemporaryDetach()} 14136 * and {@link #onFinishTemporaryDetach()}. 14137 * 14138 * <p>This method always returns {@code true} when called directly or indirectly from 14139 * {@link #onStartTemporaryDetach()}. The return value when called directly or indirectly from 14140 * {@link #onFinishTemporaryDetach()}, however, depends on the OS version. 14141 * <ul> 14142 * <li>{@code true} on {@link android.os.Build.VERSION_CODES#N API 24}</li> 14143 * <li>{@code false} on {@link android.os.Build.VERSION_CODES#N_MR1 API 25}} and later</li> 14144 * </ul> 14145 * </p> 14146 * 14147 * @return {@code true} when the View is in the state between {@link #onStartTemporaryDetach()} 14148 * and {@link #onFinishTemporaryDetach()}. 14149 */ 14150 public final boolean isTemporarilyDetached() { 14151 return (mPrivateFlags3 & PFLAG3_TEMPORARY_DETACH) != 0; 14152 } 14153 14154 /** 14155 * Dispatch {@link #onStartTemporaryDetach()} to this View and its direct children if this is 14156 * a container View. 14157 */ 14158 @CallSuper 14159 public void dispatchStartTemporaryDetach() { 14160 mPrivateFlags3 |= PFLAG3_TEMPORARY_DETACH; 14161 notifyEnterOrExitForAutoFillIfNeeded(false); 14162 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 14163 onStartTemporaryDetach(); 14164 } 14165 14166 /** 14167 * This is called when a container is going to temporarily detach a child, with 14168 * {@link ViewGroup#detachViewFromParent(View) ViewGroup.detachViewFromParent}. 14169 * It will either be followed by {@link #onFinishTemporaryDetach()} or 14170 * {@link #onDetachedFromWindow()} when the container is done. 14171 */ 14172 public void onStartTemporaryDetach() { 14173 removeUnsetPressCallback(); 14174 mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT; 14175 } 14176 14177 /** 14178 * Dispatch {@link #onFinishTemporaryDetach()} to this View and its direct children if this is 14179 * a container View. 14180 */ 14181 @CallSuper 14182 public void dispatchFinishTemporaryDetach() { 14183 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 14184 onFinishTemporaryDetach(); 14185 if (hasWindowFocus() && hasFocus()) { 14186 notifyFocusChangeToImeFocusController(true /* hasFocus */); 14187 } 14188 notifyEnterOrExitForAutoFillIfNeeded(true); 14189 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 14190 } 14191 14192 /** 14193 * Called after {@link #onStartTemporaryDetach} when the container is done 14194 * changing the view. 14195 */ 14196 public void onFinishTemporaryDetach() { 14197 } 14198 14199 /** 14200 * Return the global {@link KeyEvent.DispatcherState KeyEvent.DispatcherState} 14201 * for this view's window. Returns null if the view is not currently attached 14202 * to the window. Normally you will not need to use this directly, but 14203 * just use the standard high-level event callbacks like 14204 * {@link #onKeyDown(int, KeyEvent)}. 14205 */ 14206 public KeyEvent.DispatcherState getKeyDispatcherState() { 14207 return mAttachInfo != null ? mAttachInfo.mKeyDispatchState : null; 14208 } 14209 14210 /** 14211 * Dispatch a key event before it is processed by any input method 14212 * associated with the view hierarchy. This can be used to intercept 14213 * key events in special situations before the IME consumes them; a 14214 * typical example would be handling the BACK key to update the application's 14215 * UI instead of allowing the IME to see it and close itself. 14216 * 14217 * @param event The key event to be dispatched. 14218 * @return True if the event was handled, false otherwise. 14219 */ 14220 public boolean dispatchKeyEventPreIme(KeyEvent event) { 14221 return onKeyPreIme(event.getKeyCode(), event); 14222 } 14223 14224 /** 14225 * Dispatch a key event to the next view on the focus path. This path runs 14226 * from the top of the view tree down to the currently focused view. If this 14227 * view has focus, it will dispatch to itself. Otherwise it will dispatch 14228 * the next node down the focus path. This method also fires any key 14229 * listeners. 14230 * 14231 * @param event The key event to be dispatched. 14232 * @return True if the event was handled, false otherwise. 14233 */ 14234 public boolean dispatchKeyEvent(KeyEvent event) { 14235 if (mInputEventConsistencyVerifier != null) { 14236 mInputEventConsistencyVerifier.onKeyEvent(event, 0); 14237 } 14238 14239 // Give any attached key listener a first crack at the event. 14240 //noinspection SimplifiableIfStatement 14241 ListenerInfo li = mListenerInfo; 14242 if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 14243 && li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) { 14244 return true; 14245 } 14246 14247 if (event.dispatch(this, mAttachInfo != null 14248 ? mAttachInfo.mKeyDispatchState : null, this)) { 14249 return true; 14250 } 14251 14252 if (mInputEventConsistencyVerifier != null) { 14253 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 14254 } 14255 return false; 14256 } 14257 14258 /** 14259 * Dispatches a key shortcut event. 14260 * 14261 * @param event The key event to be dispatched. 14262 * @return True if the event was handled by the view, false otherwise. 14263 */ 14264 public boolean dispatchKeyShortcutEvent(KeyEvent event) { 14265 return onKeyShortcut(event.getKeyCode(), event); 14266 } 14267 14268 /** 14269 * Pass the touch screen motion event down to the target view, or this 14270 * view if it is the target. 14271 * 14272 * @param event The motion event to be dispatched. 14273 * @return True if the event was handled by the view, false otherwise. 14274 */ 14275 public boolean dispatchTouchEvent(MotionEvent event) { 14276 // If the event should be handled by accessibility focus first. 14277 if (event.isTargetAccessibilityFocus()) { 14278 // We don't have focus or no virtual descendant has it, do not handle the event. 14279 if (!isAccessibilityFocusedViewOrHost()) { 14280 return false; 14281 } 14282 // We have focus and got the event, then use normal event dispatch. 14283 event.setTargetAccessibilityFocus(false); 14284 } 14285 boolean result = false; 14286 14287 if (mInputEventConsistencyVerifier != null) { 14288 mInputEventConsistencyVerifier.onTouchEvent(event, 0); 14289 } 14290 14291 final int actionMasked = event.getActionMasked(); 14292 if (actionMasked == MotionEvent.ACTION_DOWN) { 14293 // Defensive cleanup for new gesture 14294 stopNestedScroll(); 14295 } 14296 14297 if (onFilterTouchEventForSecurity(event)) { 14298 if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) { 14299 result = true; 14300 } 14301 //noinspection SimplifiableIfStatement 14302 ListenerInfo li = mListenerInfo; 14303 if (li != null && li.mOnTouchListener != null 14304 && (mViewFlags & ENABLED_MASK) == ENABLED 14305 && li.mOnTouchListener.onTouch(this, event)) { 14306 result = true; 14307 } 14308 14309 if (!result && onTouchEvent(event)) { 14310 result = true; 14311 } 14312 } 14313 14314 if (!result && mInputEventConsistencyVerifier != null) { 14315 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 14316 } 14317 14318 // Clean up after nested scrolls if this is the end of a gesture; 14319 // also cancel it if we tried an ACTION_DOWN but we didn't want the rest 14320 // of the gesture. 14321 if (actionMasked == MotionEvent.ACTION_UP || 14322 actionMasked == MotionEvent.ACTION_CANCEL || 14323 (actionMasked == MotionEvent.ACTION_DOWN && !result)) { 14324 stopNestedScroll(); 14325 } 14326 14327 return result; 14328 } 14329 14330 boolean isAccessibilityFocusedViewOrHost() { 14331 return isAccessibilityFocused() || (getViewRootImpl() != null && getViewRootImpl() 14332 .getAccessibilityFocusedHost() == this); 14333 } 14334 14335 /** 14336 * Returns whether this view can receive pointer events. 14337 * 14338 * @return {@code true} if this view can receive pointer events. 14339 * @hide 14340 */ 14341 protected boolean canReceivePointerEvents() { 14342 return (mViewFlags & VISIBILITY_MASK) == VISIBLE || getAnimation() != null; 14343 } 14344 14345 /** 14346 * Filter the touch event to apply security policies. 14347 * 14348 * @param event The motion event to be filtered. 14349 * @return True if the event should be dispatched, false if the event should be dropped. 14350 * 14351 * @see #getFilterTouchesWhenObscured 14352 */ 14353 public boolean onFilterTouchEventForSecurity(MotionEvent event) { 14354 //noinspection RedundantIfStatement 14355 if ((mViewFlags & FILTER_TOUCHES_WHEN_OBSCURED) != 0 14356 && (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0) { 14357 // Window is obscured, drop this touch. 14358 return false; 14359 } 14360 return true; 14361 } 14362 14363 /** 14364 * Pass a trackball motion event down to the focused view. 14365 * 14366 * @param event The motion event to be dispatched. 14367 * @return True if the event was handled by the view, false otherwise. 14368 */ 14369 public boolean dispatchTrackballEvent(MotionEvent event) { 14370 if (mInputEventConsistencyVerifier != null) { 14371 mInputEventConsistencyVerifier.onTrackballEvent(event, 0); 14372 } 14373 14374 return onTrackballEvent(event); 14375 } 14376 14377 /** 14378 * Pass a captured pointer event down to the focused view. 14379 * 14380 * @param event The motion event to be dispatched. 14381 * @return True if the event was handled by the view, false otherwise. 14382 */ 14383 public boolean dispatchCapturedPointerEvent(MotionEvent event) { 14384 if (!hasPointerCapture()) { 14385 return false; 14386 } 14387 //noinspection SimplifiableIfStatement 14388 ListenerInfo li = mListenerInfo; 14389 if (li != null && li.mOnCapturedPointerListener != null 14390 && li.mOnCapturedPointerListener.onCapturedPointer(this, event)) { 14391 return true; 14392 } 14393 return onCapturedPointerEvent(event); 14394 } 14395 14396 /** 14397 * Dispatch a generic motion event. 14398 * <p> 14399 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 14400 * are delivered to the view under the pointer. All other generic motion events are 14401 * delivered to the focused view. Hover events are handled specially and are delivered 14402 * to {@link #onHoverEvent(MotionEvent)}. 14403 * </p> 14404 * 14405 * @param event The motion event to be dispatched. 14406 * @return True if the event was handled by the view, false otherwise. 14407 */ 14408 public boolean dispatchGenericMotionEvent(MotionEvent event) { 14409 if (mInputEventConsistencyVerifier != null) { 14410 mInputEventConsistencyVerifier.onGenericMotionEvent(event, 0); 14411 } 14412 14413 final int source = event.getSource(); 14414 if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) { 14415 final int action = event.getAction(); 14416 if (action == MotionEvent.ACTION_HOVER_ENTER 14417 || action == MotionEvent.ACTION_HOVER_MOVE 14418 || action == MotionEvent.ACTION_HOVER_EXIT) { 14419 if (dispatchHoverEvent(event)) { 14420 return true; 14421 } 14422 } else if (dispatchGenericPointerEvent(event)) { 14423 return true; 14424 } 14425 } else if (dispatchGenericFocusedEvent(event)) { 14426 return true; 14427 } 14428 14429 if (dispatchGenericMotionEventInternal(event)) { 14430 return true; 14431 } 14432 14433 if (mInputEventConsistencyVerifier != null) { 14434 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 14435 } 14436 return false; 14437 } 14438 14439 private boolean dispatchGenericMotionEventInternal(MotionEvent event) { 14440 //noinspection SimplifiableIfStatement 14441 ListenerInfo li = mListenerInfo; 14442 if (li != null && li.mOnGenericMotionListener != null 14443 && (mViewFlags & ENABLED_MASK) == ENABLED 14444 && li.mOnGenericMotionListener.onGenericMotion(this, event)) { 14445 return true; 14446 } 14447 14448 if (onGenericMotionEvent(event)) { 14449 return true; 14450 } 14451 14452 final int actionButton = event.getActionButton(); 14453 switch (event.getActionMasked()) { 14454 case MotionEvent.ACTION_BUTTON_PRESS: 14455 if (isContextClickable() && !mInContextButtonPress && !mHasPerformedLongPress 14456 && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 14457 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 14458 if (performContextClick(event.getX(), event.getY())) { 14459 mInContextButtonPress = true; 14460 setPressed(true, event.getX(), event.getY()); 14461 removeTapCallback(); 14462 removeLongPressCallback(); 14463 return true; 14464 } 14465 } 14466 break; 14467 14468 case MotionEvent.ACTION_BUTTON_RELEASE: 14469 if (mInContextButtonPress && (actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY 14470 || actionButton == MotionEvent.BUTTON_SECONDARY)) { 14471 mInContextButtonPress = false; 14472 mIgnoreNextUpEvent = true; 14473 } 14474 break; 14475 } 14476 14477 if (mInputEventConsistencyVerifier != null) { 14478 mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 14479 } 14480 return false; 14481 } 14482 14483 /** 14484 * Dispatch a hover event. 14485 * <p> 14486 * Do not call this method directly. 14487 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 14488 * </p> 14489 * 14490 * @param event The motion event to be dispatched. 14491 * @return True if the event was handled by the view, false otherwise. 14492 */ 14493 protected boolean dispatchHoverEvent(MotionEvent event) { 14494 ListenerInfo li = mListenerInfo; 14495 //noinspection SimplifiableIfStatement 14496 if (li != null && li.mOnHoverListener != null 14497 && (mViewFlags & ENABLED_MASK) == ENABLED 14498 && li.mOnHoverListener.onHover(this, event)) { 14499 return true; 14500 } 14501 14502 return onHoverEvent(event); 14503 } 14504 14505 /** 14506 * Returns true if the view has a child to which it has recently sent 14507 * {@link MotionEvent#ACTION_HOVER_ENTER}. If this view is hovered and 14508 * it does not have a hovered child, then it must be the innermost hovered view. 14509 * @hide 14510 */ 14511 protected boolean hasHoveredChild() { 14512 return false; 14513 } 14514 14515 /** 14516 * Returns true if the given point, in local coordinates, is inside the hovered child. 14517 * 14518 * @hide 14519 */ 14520 protected boolean pointInHoveredChild(MotionEvent event) { 14521 return false; 14522 } 14523 14524 /** 14525 * Dispatch a generic motion event to the view under the first pointer. 14526 * <p> 14527 * Do not call this method directly. 14528 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 14529 * </p> 14530 * 14531 * @param event The motion event to be dispatched. 14532 * @return True if the event was handled by the view, false otherwise. 14533 */ 14534 protected boolean dispatchGenericPointerEvent(MotionEvent event) { 14535 return false; 14536 } 14537 14538 /** 14539 * Dispatch a generic motion event to the currently focused view. 14540 * <p> 14541 * Do not call this method directly. 14542 * Call {@link #dispatchGenericMotionEvent(MotionEvent)} instead. 14543 * </p> 14544 * 14545 * @param event The motion event to be dispatched. 14546 * @return True if the event was handled by the view, false otherwise. 14547 */ 14548 protected boolean dispatchGenericFocusedEvent(MotionEvent event) { 14549 return false; 14550 } 14551 14552 /** 14553 * Dispatch a pointer event. 14554 * <p> 14555 * Dispatches touch related pointer events to {@link #onTouchEvent(MotionEvent)} and all 14556 * other events to {@link #onGenericMotionEvent(MotionEvent)}. This separation of concerns 14557 * reinforces the invariant that {@link #onTouchEvent(MotionEvent)} is really about touches 14558 * and should not be expected to handle other pointing device features. 14559 * </p> 14560 * 14561 * @param event The motion event to be dispatched. 14562 * @return True if the event was handled by the view, false otherwise. 14563 * @hide 14564 */ 14565 @UnsupportedAppUsage 14566 public final boolean dispatchPointerEvent(MotionEvent event) { 14567 if (event.isTouchEvent()) { 14568 return dispatchTouchEvent(event); 14569 } else { 14570 return dispatchGenericMotionEvent(event); 14571 } 14572 } 14573 14574 /** 14575 * Called when the window containing this view gains or loses window focus. 14576 * ViewGroups should override to route to their children. 14577 * 14578 * @param hasFocus True if the window containing this view now has focus, 14579 * false otherwise. 14580 */ 14581 public void dispatchWindowFocusChanged(boolean hasFocus) { 14582 onWindowFocusChanged(hasFocus); 14583 } 14584 14585 /** 14586 * Called when the window containing this view gains or loses focus. Note 14587 * that this is separate from view focus: to receive key events, both 14588 * your view and its window must have focus. If a window is displayed 14589 * on top of yours that takes input focus, then your own window will lose 14590 * focus but the view focus will remain unchanged. 14591 * 14592 * @param hasWindowFocus True if the window containing this view now has 14593 * focus, false otherwise. 14594 */ 14595 public void onWindowFocusChanged(boolean hasWindowFocus) { 14596 if (!hasWindowFocus) { 14597 if (isPressed()) { 14598 setPressed(false); 14599 } 14600 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 14601 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 14602 notifyFocusChangeToImeFocusController(false /* hasFocus */); 14603 } 14604 removeLongPressCallback(); 14605 removeTapCallback(); 14606 onFocusLost(); 14607 } else if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 14608 notifyFocusChangeToImeFocusController(true /* hasFocus */); 14609 } 14610 14611 refreshDrawableState(); 14612 } 14613 14614 /** 14615 * Returns true if this view is in a window that currently has window focus. 14616 * Note that this is not the same as the view itself having focus. 14617 * 14618 * @return True if this view is in a window that currently has window focus. 14619 */ 14620 public boolean hasWindowFocus() { 14621 return mAttachInfo != null && mAttachInfo.mHasWindowFocus; 14622 } 14623 14624 /** 14625 * @return {@code true} if this view is in a window that currently has IME focusable state. 14626 * @hide 14627 */ 14628 public boolean hasImeFocus() { 14629 return getViewRootImpl() != null && getViewRootImpl().getImeFocusController().hasImeFocus(); 14630 } 14631 14632 /** 14633 * Dispatch a view visibility change down the view hierarchy. 14634 * ViewGroups should override to route to their children. 14635 * @param changedView The view whose visibility changed. Could be 'this' or 14636 * an ancestor view. 14637 * @param visibility The new visibility of changedView: {@link #VISIBLE}, 14638 * {@link #INVISIBLE} or {@link #GONE}. 14639 */ 14640 protected void dispatchVisibilityChanged(@NonNull View changedView, 14641 @Visibility int visibility) { 14642 onVisibilityChanged(changedView, visibility); 14643 } 14644 14645 /** 14646 * Called when the visibility of the view or an ancestor of the view has 14647 * changed. 14648 * 14649 * @param changedView The view whose visibility changed. May be 14650 * {@code this} or an ancestor view. 14651 * @param visibility The new visibility, one of {@link #VISIBLE}, 14652 * {@link #INVISIBLE} or {@link #GONE}. 14653 */ 14654 protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { 14655 } 14656 14657 /** 14658 * Dispatch a hint about whether this view is displayed. For instance, when 14659 * a View moves out of the screen, it might receives a display hint indicating 14660 * the view is not displayed. Applications should not <em>rely</em> on this hint 14661 * as there is no guarantee that they will receive one. 14662 * 14663 * @param hint A hint about whether or not this view is displayed: 14664 * {@link #VISIBLE} or {@link #INVISIBLE}. 14665 */ 14666 public void dispatchDisplayHint(@Visibility int hint) { 14667 onDisplayHint(hint); 14668 } 14669 14670 /** 14671 * Gives this view a hint about whether is displayed or not. For instance, when 14672 * a View moves out of the screen, it might receives a display hint indicating 14673 * the view is not displayed. Applications should not <em>rely</em> on this hint 14674 * as there is no guarantee that they will receive one. 14675 * 14676 * @param hint A hint about whether or not this view is displayed: 14677 * {@link #VISIBLE} or {@link #INVISIBLE}. 14678 */ 14679 protected void onDisplayHint(@Visibility int hint) { 14680 } 14681 14682 /** 14683 * Dispatch a window visibility change down the view hierarchy. 14684 * ViewGroups should override to route to their children. 14685 * 14686 * @param visibility The new visibility of the window. 14687 * 14688 * @see #onWindowVisibilityChanged(int) 14689 */ 14690 public void dispatchWindowVisibilityChanged(@Visibility int visibility) { 14691 onWindowVisibilityChanged(visibility); 14692 } 14693 14694 /** 14695 * Called when the window containing has change its visibility 14696 * (between {@link #GONE}, {@link #INVISIBLE}, and {@link #VISIBLE}). Note 14697 * that this tells you whether or not your window is being made visible 14698 * to the window manager; this does <em>not</em> tell you whether or not 14699 * your window is obscured by other windows on the screen, even if it 14700 * is itself visible. 14701 * 14702 * @param visibility The new visibility of the window. 14703 */ 14704 protected void onWindowVisibilityChanged(@Visibility int visibility) { 14705 if (visibility == VISIBLE) { 14706 initialAwakenScrollBars(); 14707 } 14708 } 14709 14710 /** 14711 * @return true if this view and all ancestors are visible as of the last 14712 * {@link #onVisibilityAggregated(boolean)} call. 14713 */ 14714 boolean isAggregatedVisible() { 14715 return (mPrivateFlags3 & PFLAG3_AGGREGATED_VISIBLE) != 0; 14716 } 14717 14718 /** 14719 * Internal dispatching method for {@link #onVisibilityAggregated}. Overridden by 14720 * ViewGroup. Intended to only be called when {@link #isAttachedToWindow()}, 14721 * {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}. 14722 * 14723 * @param isVisible true if this view's visibility to the user is uninterrupted by its 14724 * ancestors or by window visibility 14725 * @return true if this view is visible to the user, not counting clipping or overlapping 14726 */ 14727 boolean dispatchVisibilityAggregated(boolean isVisible) { 14728 final boolean thisVisible = getVisibility() == VISIBLE; 14729 // If we're not visible but something is telling us we are, ignore it. 14730 if (thisVisible || !isVisible) { 14731 onVisibilityAggregated(isVisible); 14732 } 14733 return thisVisible && isVisible; 14734 } 14735 14736 /** 14737 * Called when the user-visibility of this View is potentially affected by a change 14738 * to this view itself, an ancestor view or the window this view is attached to. 14739 * 14740 * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE} 14741 * and this view's window is also visible 14742 */ 14743 @CallSuper 14744 public void onVisibilityAggregated(boolean isVisible) { 14745 // Update our internal visibility tracking so we can detect changes 14746 boolean oldVisible = isAggregatedVisible(); 14747 mPrivateFlags3 = isVisible ? (mPrivateFlags3 | PFLAG3_AGGREGATED_VISIBLE) 14748 : (mPrivateFlags3 & ~PFLAG3_AGGREGATED_VISIBLE); 14749 if (isVisible && mAttachInfo != null) { 14750 initialAwakenScrollBars(); 14751 } 14752 14753 final Drawable dr = mBackground; 14754 if (dr != null && isVisible != dr.isVisible()) { 14755 dr.setVisible(isVisible, false); 14756 } 14757 final Drawable hl = mDefaultFocusHighlight; 14758 if (hl != null && isVisible != hl.isVisible()) { 14759 hl.setVisible(isVisible, false); 14760 } 14761 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 14762 if (fg != null && isVisible != fg.isVisible()) { 14763 fg.setVisible(isVisible, false); 14764 } 14765 14766 if (isAutofillable()) { 14767 AutofillManager afm = getAutofillManager(); 14768 14769 if (afm != null && getAutofillViewId() > LAST_APP_AUTOFILL_ID) { 14770 if (mVisibilityChangeForAutofillHandler != null) { 14771 mVisibilityChangeForAutofillHandler.removeMessages(0); 14772 } 14773 14774 // If the view is in the background but still part of the hierarchy this is called 14775 // with isVisible=false. Hence visibility==false requires further checks 14776 if (isVisible) { 14777 afm.notifyViewVisibilityChanged(this, true); 14778 } else { 14779 if (mVisibilityChangeForAutofillHandler == null) { 14780 mVisibilityChangeForAutofillHandler = 14781 new VisibilityChangeForAutofillHandler(afm, this); 14782 } 14783 // Let current operation (e.g. removal of the view from the hierarchy) 14784 // finish before checking state 14785 mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget(); 14786 } 14787 } 14788 } 14789 14790 if (isVisible != oldVisible) { 14791 if (isAccessibilityPane()) { 14792 notifyViewAccessibilityStateChangedIfNeeded(isVisible 14793 ? AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_APPEARED 14794 : AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED); 14795 } 14796 14797 notifyAppearedOrDisappearedForContentCaptureIfNeeded(isVisible); 14798 14799 if (!getSystemGestureExclusionRects().isEmpty()) { 14800 postUpdateSystemGestureExclusionRects(); 14801 } 14802 } 14803 } 14804 14805 /** 14806 * Returns the current visibility of the window this view is attached to 14807 * (either {@link #GONE}, {@link #INVISIBLE}, or {@link #VISIBLE}). 14808 * 14809 * @return Returns the current visibility of the view's window. 14810 */ 14811 @Visibility 14812 public int getWindowVisibility() { 14813 return mAttachInfo != null ? mAttachInfo.mWindowVisibility : GONE; 14814 } 14815 14816 /** 14817 * Retrieve the overall visible display size in which the window this view is 14818 * attached to has been positioned in. This takes into account screen 14819 * decorations above the window, for both cases where the window itself 14820 * is being position inside of them or the window is being placed under 14821 * then and covered insets are used for the window to position its content 14822 * inside. In effect, this tells you the available area where content can 14823 * be placed and remain visible to users. 14824 * 14825 * <p>This function requires an IPC back to the window manager to retrieve 14826 * the requested information, so should not be used in performance critical 14827 * code like drawing. 14828 * 14829 * @param outRect Filled in with the visible display frame. If the view 14830 * is not attached to a window, this is simply the raw display size. 14831 */ 14832 public void getWindowVisibleDisplayFrame(Rect outRect) { 14833 if (mAttachInfo != null) { 14834 try { 14835 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 14836 } catch (RemoteException e) { 14837 return; 14838 } 14839 // XXX This is really broken, and probably all needs to be done 14840 // in the window manager, and we need to know more about whether 14841 // we want the area behind or in front of the IME. 14842 final Rect insets = mAttachInfo.mVisibleInsets; 14843 outRect.left += insets.left; 14844 outRect.top += insets.top; 14845 outRect.right -= insets.right; 14846 outRect.bottom -= insets.bottom; 14847 return; 14848 } 14849 // The view is not attached to a display so we don't have a context. 14850 // Make a best guess about the display size. 14851 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 14852 d.getRectSize(outRect); 14853 } 14854 14855 /** 14856 * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window 14857 * is currently in without any insets. 14858 * 14859 * @hide 14860 */ 14861 @UnsupportedAppUsage 14862 public void getWindowDisplayFrame(Rect outRect) { 14863 if (mAttachInfo != null) { 14864 try { 14865 mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect); 14866 } catch (RemoteException e) { 14867 return; 14868 } 14869 return; 14870 } 14871 // The view is not attached to a display so we don't have a context. 14872 // Make a best guess about the display size. 14873 Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY); 14874 d.getRectSize(outRect); 14875 } 14876 14877 /** 14878 * Dispatch a notification about a resource configuration change down 14879 * the view hierarchy. 14880 * ViewGroups should override to route to their children. 14881 * 14882 * @param newConfig The new resource configuration. 14883 * 14884 * @see #onConfigurationChanged(android.content.res.Configuration) 14885 */ 14886 public void dispatchConfigurationChanged(Configuration newConfig) { 14887 onConfigurationChanged(newConfig); 14888 } 14889 14890 /** 14891 * Called when the current configuration of the resources being used 14892 * by the application have changed. You can use this to decide when 14893 * to reload resources that can changed based on orientation and other 14894 * configuration characteristics. You only need to use this if you are 14895 * not relying on the normal {@link android.app.Activity} mechanism of 14896 * recreating the activity instance upon a configuration change. 14897 * 14898 * @param newConfig The new resource configuration. 14899 */ 14900 protected void onConfigurationChanged(Configuration newConfig) { 14901 } 14902 14903 /** 14904 * Private function to aggregate all per-view attributes in to the view 14905 * root. 14906 */ 14907 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) { 14908 performCollectViewAttributes(attachInfo, visibility); 14909 } 14910 14911 void performCollectViewAttributes(AttachInfo attachInfo, int visibility) { 14912 if ((visibility & VISIBILITY_MASK) == VISIBLE) { 14913 if ((mViewFlags & KEEP_SCREEN_ON) == KEEP_SCREEN_ON) { 14914 attachInfo.mKeepScreenOn = true; 14915 } 14916 attachInfo.mSystemUiVisibility |= mSystemUiVisibility; 14917 ListenerInfo li = mListenerInfo; 14918 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 14919 attachInfo.mHasSystemUiListeners = true; 14920 } 14921 } 14922 } 14923 14924 void needGlobalAttributesUpdate(boolean force) { 14925 final AttachInfo ai = mAttachInfo; 14926 if (ai != null && !ai.mRecomputeGlobalAttributes) { 14927 if (force || ai.mKeepScreenOn || (ai.mSystemUiVisibility != 0) 14928 || ai.mHasSystemUiListeners) { 14929 ai.mRecomputeGlobalAttributes = true; 14930 } 14931 } 14932 } 14933 14934 /** 14935 * Returns whether the device is currently in touch mode. Touch mode is entered 14936 * once the user begins interacting with the device by touch, and affects various 14937 * things like whether focus is always visible to the user. 14938 * 14939 * @return Whether the device is in touch mode. 14940 */ 14941 @ViewDebug.ExportedProperty 14942 public boolean isInTouchMode() { 14943 if (mAttachInfo != null) { 14944 return mAttachInfo.mInTouchMode; 14945 } else { 14946 return ViewRootImpl.isInTouchMode(); 14947 } 14948 } 14949 14950 /** 14951 * Returns the context the view is running in, through which it can 14952 * access the current theme, resources, etc. 14953 * 14954 * @return The view's Context. 14955 */ 14956 @ViewDebug.CapturedViewProperty 14957 public final Context getContext() { 14958 return mContext; 14959 } 14960 14961 /** 14962 * Handle a key event before it is processed by any input method 14963 * associated with the view hierarchy. This can be used to intercept 14964 * key events in special situations before the IME consumes them; a 14965 * typical example would be handling the BACK key to update the application's 14966 * UI instead of allowing the IME to see it and close itself. 14967 * 14968 * @param keyCode The value in event.getKeyCode(). 14969 * @param event Description of the key event. 14970 * @return If you handled the event, return true. If you want to allow the 14971 * event to be handled by the next receiver, return false. 14972 */ 14973 public boolean onKeyPreIme(int keyCode, KeyEvent event) { 14974 return false; 14975 } 14976 14977 /** 14978 * Default implementation of {@link KeyEvent.Callback#onKeyDown(int, KeyEvent) 14979 * KeyEvent.Callback.onKeyDown()}: perform press of the view 14980 * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER} 14981 * is released, if the view is enabled and clickable. 14982 * <p> 14983 * Key presses in software keyboards will generally NOT trigger this 14984 * listener, although some may elect to do so in some situations. Do not 14985 * rely on this to catch software key presses. 14986 * 14987 * @param keyCode a key code that represents the button pressed, from 14988 * {@link android.view.KeyEvent} 14989 * @param event the KeyEvent object that defines the button action 14990 */ 14991 public boolean onKeyDown(int keyCode, KeyEvent event) { 14992 if (KeyEvent.isConfirmKey(keyCode)) { 14993 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 14994 return true; 14995 } 14996 14997 if (event.getRepeatCount() == 0) { 14998 // Long clickable items don't necessarily have to be clickable. 14999 final boolean clickable = (mViewFlags & CLICKABLE) == CLICKABLE 15000 || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE; 15001 if (clickable || (mViewFlags & TOOLTIP) == TOOLTIP) { 15002 // For the purposes of menu anchoring and drawable hotspots, 15003 // key events are considered to be at the center of the view. 15004 final float x = getWidth() / 2f; 15005 final float y = getHeight() / 2f; 15006 if (clickable) { 15007 setPressed(true, x, y); 15008 } 15009 checkForLongClick( 15010 ViewConfiguration.getLongPressTimeout(), 15011 x, 15012 y, 15013 // This is not a touch gesture -- do not classify it as one. 15014 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION); 15015 return true; 15016 } 15017 } 15018 } 15019 15020 return false; 15021 } 15022 15023 /** 15024 * Default implementation of {@link KeyEvent.Callback#onKeyLongPress(int, KeyEvent) 15025 * KeyEvent.Callback.onKeyLongPress()}: always returns false (doesn't handle 15026 * the event). 15027 * <p>Key presses in software keyboards will generally NOT trigger this listener, 15028 * although some may elect to do so in some situations. Do not rely on this to 15029 * catch software key presses. 15030 */ 15031 public boolean onKeyLongPress(int keyCode, KeyEvent event) { 15032 return false; 15033 } 15034 15035 /** 15036 * Default implementation of {@link KeyEvent.Callback#onKeyUp(int, KeyEvent) 15037 * KeyEvent.Callback.onKeyUp()}: perform clicking of the view 15038 * when {@link KeyEvent#KEYCODE_DPAD_CENTER}, {@link KeyEvent#KEYCODE_ENTER} 15039 * or {@link KeyEvent#KEYCODE_SPACE} is released. 15040 * <p>Key presses in software keyboards will generally NOT trigger this listener, 15041 * although some may elect to do so in some situations. Do not rely on this to 15042 * catch software key presses. 15043 * 15044 * @param keyCode A key code that represents the button pressed, from 15045 * {@link android.view.KeyEvent}. 15046 * @param event The KeyEvent object that defines the button action. 15047 */ 15048 public boolean onKeyUp(int keyCode, KeyEvent event) { 15049 if (KeyEvent.isConfirmKey(keyCode)) { 15050 if ((mViewFlags & ENABLED_MASK) == DISABLED) { 15051 return true; 15052 } 15053 if ((mViewFlags & CLICKABLE) == CLICKABLE && isPressed()) { 15054 setPressed(false); 15055 15056 if (!mHasPerformedLongPress) { 15057 // This is a tap, so remove the longpress check 15058 removeLongPressCallback(); 15059 if (!event.isCanceled()) { 15060 return performClickInternal(); 15061 } 15062 } 15063 } 15064 } 15065 return false; 15066 } 15067 15068 /** 15069 * Default implementation of {@link KeyEvent.Callback#onKeyMultiple(int, int, KeyEvent) 15070 * KeyEvent.Callback.onKeyMultiple()}: always returns false (doesn't handle 15071 * the event). 15072 * <p>Key presses in software keyboards will generally NOT trigger this listener, 15073 * although some may elect to do so in some situations. Do not rely on this to 15074 * catch software key presses. 15075 * 15076 * @param keyCode A key code that represents the button pressed, from 15077 * {@link android.view.KeyEvent}. 15078 * @param repeatCount The number of times the action was made. 15079 * @param event The KeyEvent object that defines the button action. 15080 */ 15081 public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) { 15082 return false; 15083 } 15084 15085 /** 15086 * Called on the focused view when a key shortcut event is not handled. 15087 * Override this method to implement local key shortcuts for the View. 15088 * Key shortcuts can also be implemented by setting the 15089 * {@link MenuItem#setShortcut(char, char) shortcut} property of menu items. 15090 * 15091 * @param keyCode The value in event.getKeyCode(). 15092 * @param event Description of the key event. 15093 * @return If you handled the event, return true. If you want to allow the 15094 * event to be handled by the next receiver, return false. 15095 */ 15096 public boolean onKeyShortcut(int keyCode, KeyEvent event) { 15097 return false; 15098 } 15099 15100 /** 15101 * Check whether the called view is a text editor, in which case it 15102 * would make sense to automatically display a soft input window for 15103 * it. Subclasses should override this if they implement 15104 * {@link #onCreateInputConnection(EditorInfo)} to return true if 15105 * a call on that method would return a non-null InputConnection, and 15106 * they are really a first-class editor that the user would normally 15107 * start typing on when the go into a window containing your view. 15108 * 15109 * <p>The default implementation always returns false. This does 15110 * <em>not</em> mean that its {@link #onCreateInputConnection(EditorInfo)} 15111 * will not be called or the user can not otherwise perform edits on your 15112 * view; it is just a hint to the system that this is not the primary 15113 * purpose of this view. 15114 * 15115 * @return Returns true if this view is a text editor, else false. 15116 */ 15117 public boolean onCheckIsTextEditor() { 15118 return false; 15119 } 15120 15121 /** 15122 * Create a new InputConnection for an InputMethod to interact 15123 * with the view. The default implementation returns null, since it doesn't 15124 * support input methods. You can override this to implement such support. 15125 * This is only needed for views that take focus and text input. 15126 * 15127 * <p>When implementing this, you probably also want to implement 15128 * {@link #onCheckIsTextEditor()} to indicate you will return a 15129 * non-null InputConnection.</p> 15130 * 15131 * <p>Also, take good care to fill in the {@link android.view.inputmethod.EditorInfo} 15132 * object correctly and in its entirety, so that the connected IME can rely 15133 * on its values. For example, {@link android.view.inputmethod.EditorInfo#initialSelStart} 15134 * and {@link android.view.inputmethod.EditorInfo#initialSelEnd} members 15135 * must be filled in with the correct cursor position for IMEs to work correctly 15136 * with your application.</p> 15137 * 15138 * @param outAttrs Fill in with attribute information about the connection. 15139 */ 15140 public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 15141 return null; 15142 } 15143 15144 /** 15145 * Called by the {@link android.view.inputmethod.InputMethodManager} 15146 * when a view who is not the current 15147 * input connection target is trying to make a call on the manager. The 15148 * default implementation returns false; you can override this to return 15149 * true for certain views if you are performing InputConnection proxying 15150 * to them. 15151 * @param view The View that is making the InputMethodManager call. 15152 * @return Return true to allow the call, false to reject. 15153 */ 15154 public boolean checkInputConnectionProxy(View view) { 15155 return false; 15156 } 15157 15158 /** 15159 * Show the context menu for this view. It is not safe to hold on to the 15160 * menu after returning from this method. 15161 * 15162 * You should normally not overload this method. Overload 15163 * {@link #onCreateContextMenu(ContextMenu)} or define an 15164 * {@link OnCreateContextMenuListener} to add items to the context menu. 15165 * 15166 * @param menu The context menu to populate 15167 */ 15168 public void createContextMenu(ContextMenu menu) { 15169 ContextMenuInfo menuInfo = getContextMenuInfo(); 15170 15171 // Sets the current menu info so all items added to menu will have 15172 // my extra info set. 15173 ((MenuBuilder)menu).setCurrentMenuInfo(menuInfo); 15174 15175 onCreateContextMenu(menu); 15176 ListenerInfo li = mListenerInfo; 15177 if (li != null && li.mOnCreateContextMenuListener != null) { 15178 li.mOnCreateContextMenuListener.onCreateContextMenu(menu, this, menuInfo); 15179 } 15180 15181 // Clear the extra information so subsequent items that aren't mine don't 15182 // have my extra info. 15183 ((MenuBuilder)menu).setCurrentMenuInfo(null); 15184 15185 if (mParent != null) { 15186 mParent.createContextMenu(menu); 15187 } 15188 } 15189 15190 /** 15191 * Views should implement this if they have extra information to associate 15192 * with the context menu. The return result is supplied as a parameter to 15193 * the {@link OnCreateContextMenuListener#onCreateContextMenu(ContextMenu, View, ContextMenuInfo)} 15194 * callback. 15195 * 15196 * @return Extra information about the item for which the context menu 15197 * should be shown. This information will vary across different 15198 * subclasses of View. 15199 */ 15200 protected ContextMenuInfo getContextMenuInfo() { 15201 return null; 15202 } 15203 15204 /** 15205 * Views should implement this if the view itself is going to add items to 15206 * the context menu. 15207 * 15208 * @param menu the context menu to populate 15209 */ 15210 protected void onCreateContextMenu(ContextMenu menu) { 15211 } 15212 15213 /** 15214 * Implement this method to handle trackball motion events. The 15215 * <em>relative</em> movement of the trackball since the last event 15216 * can be retrieve with {@link MotionEvent#getX MotionEvent.getX()} and 15217 * {@link MotionEvent#getY MotionEvent.getY()}. These are normalized so 15218 * that a movement of 1 corresponds to the user pressing one DPAD key (so 15219 * they will often be fractional values, representing the more fine-grained 15220 * movement information available from a trackball). 15221 * 15222 * @param event The motion event. 15223 * @return True if the event was handled, false otherwise. 15224 */ 15225 public boolean onTrackballEvent(MotionEvent event) { 15226 return false; 15227 } 15228 15229 /** 15230 * Implement this method to handle generic motion events. 15231 * <p> 15232 * Generic motion events describe joystick movements, mouse hovers, track pad 15233 * touches, scroll wheel movements and other input events. The 15234 * {@link MotionEvent#getSource() source} of the motion event specifies 15235 * the class of input that was received. Implementations of this method 15236 * must examine the bits in the source before processing the event. 15237 * The following code example shows how this is done. 15238 * </p><p> 15239 * Generic motion events with source class {@link InputDevice#SOURCE_CLASS_POINTER} 15240 * are delivered to the view under the pointer. All other generic motion events are 15241 * delivered to the focused view. 15242 * </p> 15243 * <pre> public boolean onGenericMotionEvent(MotionEvent event) { 15244 * if (event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK)) { 15245 * if (event.getAction() == MotionEvent.ACTION_MOVE) { 15246 * // process the joystick movement... 15247 * return true; 15248 * } 15249 * } 15250 * if (event.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) { 15251 * switch (event.getAction()) { 15252 * case MotionEvent.ACTION_HOVER_MOVE: 15253 * // process the mouse hover movement... 15254 * return true; 15255 * case MotionEvent.ACTION_SCROLL: 15256 * // process the scroll wheel movement... 15257 * return true; 15258 * } 15259 * } 15260 * return super.onGenericMotionEvent(event); 15261 * }</pre> 15262 * 15263 * @param event The generic motion event being processed. 15264 * @return True if the event was handled, false otherwise. 15265 */ 15266 public boolean onGenericMotionEvent(MotionEvent event) { 15267 return false; 15268 } 15269 15270 /** 15271 * Dispatching hover events to {@link TouchDelegate} to improve accessibility. 15272 * <p> 15273 * This method is dispatching hover events to the delegate target to support explore by touch. 15274 * Similar to {@link ViewGroup#dispatchTouchEvent}, this method send proper hover events to 15275 * the delegate target according to the pointer and the touch area of the delegate while touch 15276 * exploration enabled. 15277 * </p> 15278 * 15279 * @param event The motion event dispatch to the delegate target. 15280 * @return True if the event was handled, false otherwise. 15281 * 15282 * @see #onHoverEvent 15283 */ 15284 private boolean dispatchTouchExplorationHoverEvent(MotionEvent event) { 15285 final AccessibilityManager manager = AccessibilityManager.getInstance(mContext); 15286 if (!manager.isEnabled() || !manager.isTouchExplorationEnabled()) { 15287 return false; 15288 } 15289 15290 final boolean oldHoveringTouchDelegate = mHoveringTouchDelegate; 15291 final int action = event.getActionMasked(); 15292 boolean pointInDelegateRegion = false; 15293 boolean handled = false; 15294 15295 final AccessibilityNodeInfo.TouchDelegateInfo info = mTouchDelegate.getTouchDelegateInfo(); 15296 for (int i = 0; i < info.getRegionCount(); i++) { 15297 Region r = info.getRegionAt(i); 15298 if (r.contains((int) event.getX(), (int) event.getY())) { 15299 pointInDelegateRegion = true; 15300 } 15301 } 15302 15303 // Explore by touch should dispatch events to children under the pointer first if any 15304 // before dispatching to TouchDelegate. For non-hoverable views that do not consume 15305 // hover events but receive accessibility focus, it should also not delegate to these 15306 // views when hovered. 15307 if (!oldHoveringTouchDelegate) { 15308 if ((action == MotionEvent.ACTION_HOVER_ENTER 15309 || action == MotionEvent.ACTION_HOVER_MOVE) 15310 && !pointInHoveredChild(event) 15311 && pointInDelegateRegion) { 15312 mHoveringTouchDelegate = true; 15313 } 15314 } else { 15315 if (action == MotionEvent.ACTION_HOVER_EXIT 15316 || (action == MotionEvent.ACTION_HOVER_MOVE 15317 && (pointInHoveredChild(event) || !pointInDelegateRegion))) { 15318 mHoveringTouchDelegate = false; 15319 } 15320 } 15321 switch (action) { 15322 case MotionEvent.ACTION_HOVER_MOVE: 15323 if (oldHoveringTouchDelegate && mHoveringTouchDelegate) { 15324 // Inside bounds, dispatch as is. 15325 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 15326 } else if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 15327 // Moving inbound, synthesize hover enter. 15328 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 15329 ? event : MotionEvent.obtainNoHistory(event); 15330 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER); 15331 handled = mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 15332 eventNoHistory.setAction(action); 15333 handled |= mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 15334 } else if (oldHoveringTouchDelegate && !mHoveringTouchDelegate) { 15335 // Moving outbound, synthesize hover exit. 15336 final boolean hoverExitPending = event.isHoverExitPending(); 15337 event.setHoverExitPending(true); 15338 mTouchDelegate.onTouchExplorationHoverEvent(event); 15339 MotionEvent eventNoHistory = (event.getHistorySize() == 0) 15340 ? event : MotionEvent.obtainNoHistory(event); 15341 eventNoHistory.setHoverExitPending(hoverExitPending); 15342 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT); 15343 mTouchDelegate.onTouchExplorationHoverEvent(eventNoHistory); 15344 } // else: outside bounds, do nothing. 15345 break; 15346 case MotionEvent.ACTION_HOVER_ENTER: 15347 if (!oldHoveringTouchDelegate && mHoveringTouchDelegate) { 15348 handled = mTouchDelegate.onTouchExplorationHoverEvent(event); 15349 } 15350 break; 15351 case MotionEvent.ACTION_HOVER_EXIT: 15352 if (oldHoveringTouchDelegate) { 15353 mTouchDelegate.onTouchExplorationHoverEvent(event); 15354 } 15355 break; 15356 } 15357 return handled; 15358 } 15359 15360 /** 15361 * Implement this method to handle hover events. 15362 * <p> 15363 * This method is called whenever a pointer is hovering into, over, or out of the 15364 * bounds of a view and the view is not currently being touched. 15365 * Hover events are represented as pointer events with action 15366 * {@link MotionEvent#ACTION_HOVER_ENTER}, {@link MotionEvent#ACTION_HOVER_MOVE}, 15367 * or {@link MotionEvent#ACTION_HOVER_EXIT}. 15368 * </p> 15369 * <ul> 15370 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_ENTER} 15371 * when the pointer enters the bounds of the view.</li> 15372 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_MOVE} 15373 * when the pointer has already entered the bounds of the view and has moved.</li> 15374 * <li>The view receives a hover event with action {@link MotionEvent#ACTION_HOVER_EXIT} 15375 * when the pointer has exited the bounds of the view or when the pointer is 15376 * about to go down due to a button click, tap, or similar user action that 15377 * causes the view to be touched.</li> 15378 * </ul> 15379 * <p> 15380 * The view should implement this method to return true to indicate that it is 15381 * handling the hover event, such as by changing its drawable state. 15382 * </p><p> 15383 * The default implementation calls {@link #setHovered} to update the hovered state 15384 * of the view when a hover enter or hover exit event is received, if the view 15385 * is enabled and is clickable. The default implementation also sends hover 15386 * accessibility events. 15387 * </p> 15388 * 15389 * @param event The motion event that describes the hover. 15390 * @return True if the view handled the hover event. 15391 * 15392 * @see #isHovered 15393 * @see #setHovered 15394 * @see #onHoverChanged 15395 */ 15396 public boolean onHoverEvent(MotionEvent event) { 15397 if (mTouchDelegate != null && dispatchTouchExplorationHoverEvent(event)) { 15398 return true; 15399 } 15400 15401 // The root view may receive hover (or touch) events that are outside the bounds of 15402 // the window. This code ensures that we only send accessibility events for 15403 // hovers that are actually within the bounds of the root view. 15404 final int action = event.getActionMasked(); 15405 if (!mSendingHoverAccessibilityEvents) { 15406 if ((action == MotionEvent.ACTION_HOVER_ENTER 15407 || action == MotionEvent.ACTION_HOVER_MOVE) 15408 && !hasHoveredChild() 15409 && pointInView(event.getX(), event.getY())) { 15410 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_ENTER); 15411 mSendingHoverAccessibilityEvents = true; 15412 } 15413 } else { 15414 if (action == MotionEvent.ACTION_HOVER_EXIT 15415 || (action == MotionEvent.ACTION_HOVER_MOVE 15416 && !pointInView(event.getX(), event.getY()))) { 15417 mSendingHoverAccessibilityEvents = false; 15418 sendAccessibilityHoverEvent(AccessibilityEvent.TYPE_VIEW_HOVER_EXIT); 15419 } 15420 } 15421 15422 if ((action == MotionEvent.ACTION_HOVER_ENTER || action == MotionEvent.ACTION_HOVER_MOVE) 15423 && event.isFromSource(InputDevice.SOURCE_MOUSE) 15424 && isOnScrollbar(event.getX(), event.getY())) { 15425 awakenScrollBars(); 15426 } 15427 15428 // If we consider ourself hoverable, or if we we're already hovered, 15429 // handle changing state in response to ENTER and EXIT events. 15430 if (isHoverable() || isHovered()) { 15431 switch (action) { 15432 case MotionEvent.ACTION_HOVER_ENTER: 15433 setHovered(true); 15434 break; 15435 case MotionEvent.ACTION_HOVER_EXIT: 15436 setHovered(false); 15437 break; 15438 } 15439 15440 // Dispatch the event to onGenericMotionEvent before returning true. 15441 // This is to provide compatibility with existing applications that 15442 // handled HOVER_MOVE events in onGenericMotionEvent and that would 15443 // break because of the new default handling for hoverable views 15444 // in onHoverEvent. 15445 // Note that onGenericMotionEvent will be called by default when 15446 // onHoverEvent returns false (refer to dispatchGenericMotionEvent). 15447 dispatchGenericMotionEventInternal(event); 15448 // The event was already handled by calling setHovered(), so always 15449 // return true. 15450 return true; 15451 } 15452 15453 return false; 15454 } 15455 15456 /** 15457 * Returns true if the view should handle {@link #onHoverEvent} 15458 * by calling {@link #setHovered} to change its hovered state. 15459 * 15460 * @return True if the view is hoverable. 15461 */ 15462 private boolean isHoverable() { 15463 final int viewFlags = mViewFlags; 15464 if ((viewFlags & ENABLED_MASK) == DISABLED) { 15465 return false; 15466 } 15467 15468 return (viewFlags & CLICKABLE) == CLICKABLE 15469 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE 15470 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 15471 } 15472 15473 /** 15474 * Returns true if the view is currently hovered. 15475 * 15476 * @return True if the view is currently hovered. 15477 * 15478 * @see #setHovered 15479 * @see #onHoverChanged 15480 */ 15481 @ViewDebug.ExportedProperty 15482 public boolean isHovered() { 15483 return (mPrivateFlags & PFLAG_HOVERED) != 0; 15484 } 15485 15486 /** 15487 * Sets whether the view is currently hovered. 15488 * <p> 15489 * Calling this method also changes the drawable state of the view. This 15490 * enables the view to react to hover by using different drawable resources 15491 * to change its appearance. 15492 * </p><p> 15493 * The {@link #onHoverChanged} method is called when the hovered state changes. 15494 * </p> 15495 * 15496 * @param hovered True if the view is hovered. 15497 * 15498 * @see #isHovered 15499 * @see #onHoverChanged 15500 */ 15501 public void setHovered(boolean hovered) { 15502 if (hovered) { 15503 if ((mPrivateFlags & PFLAG_HOVERED) == 0) { 15504 mPrivateFlags |= PFLAG_HOVERED; 15505 refreshDrawableState(); 15506 onHoverChanged(true); 15507 } 15508 } else { 15509 if ((mPrivateFlags & PFLAG_HOVERED) != 0) { 15510 mPrivateFlags &= ~PFLAG_HOVERED; 15511 refreshDrawableState(); 15512 onHoverChanged(false); 15513 } 15514 } 15515 } 15516 15517 /** 15518 * Implement this method to handle hover state changes. 15519 * <p> 15520 * This method is called whenever the hover state changes as a result of a 15521 * call to {@link #setHovered}. 15522 * </p> 15523 * 15524 * @param hovered The current hover state, as returned by {@link #isHovered}. 15525 * 15526 * @see #isHovered 15527 * @see #setHovered 15528 */ 15529 public void onHoverChanged(boolean hovered) { 15530 } 15531 15532 /** 15533 * Handles scroll bar dragging by mouse input. 15534 * 15535 * @hide 15536 * @param event The motion event. 15537 * 15538 * @return true if the event was handled as a scroll bar dragging, false otherwise. 15539 */ 15540 protected boolean handleScrollBarDragging(MotionEvent event) { 15541 if (mScrollCache == null) { 15542 return false; 15543 } 15544 final float x = event.getX(); 15545 final float y = event.getY(); 15546 final int action = event.getAction(); 15547 if ((mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING 15548 && action != MotionEvent.ACTION_DOWN) 15549 || !event.isFromSource(InputDevice.SOURCE_MOUSE) 15550 || !event.isButtonPressed(MotionEvent.BUTTON_PRIMARY)) { 15551 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 15552 return false; 15553 } 15554 15555 switch (action) { 15556 case MotionEvent.ACTION_MOVE: 15557 if (mScrollCache.mScrollBarDraggingState == ScrollabilityCache.NOT_DRAGGING) { 15558 return false; 15559 } 15560 if (mScrollCache.mScrollBarDraggingState 15561 == ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR) { 15562 final Rect bounds = mScrollCache.mScrollBarBounds; 15563 getVerticalScrollBarBounds(bounds, null); 15564 final int range = computeVerticalScrollRange(); 15565 final int offset = computeVerticalScrollOffset(); 15566 final int extent = computeVerticalScrollExtent(); 15567 15568 final int thumbLength = ScrollBarUtils.getThumbLength( 15569 bounds.height(), bounds.width(), extent, range); 15570 final int thumbOffset = ScrollBarUtils.getThumbOffset( 15571 bounds.height(), thumbLength, extent, range, offset); 15572 15573 final float diff = y - mScrollCache.mScrollBarDraggingPos; 15574 final float maxThumbOffset = bounds.height() - thumbLength; 15575 final float newThumbOffset = 15576 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 15577 final int height = getHeight(); 15578 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 15579 && height > 0 && extent > 0) { 15580 final int newY = Math.round((range - extent) 15581 / ((float)extent / height) * (newThumbOffset / maxThumbOffset)); 15582 if (newY != getScrollY()) { 15583 mScrollCache.mScrollBarDraggingPos = y; 15584 setScrollY(newY); 15585 } 15586 } 15587 return true; 15588 } 15589 if (mScrollCache.mScrollBarDraggingState 15590 == ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR) { 15591 final Rect bounds = mScrollCache.mScrollBarBounds; 15592 getHorizontalScrollBarBounds(bounds, null); 15593 final int range = computeHorizontalScrollRange(); 15594 final int offset = computeHorizontalScrollOffset(); 15595 final int extent = computeHorizontalScrollExtent(); 15596 15597 final int thumbLength = ScrollBarUtils.getThumbLength( 15598 bounds.width(), bounds.height(), extent, range); 15599 final int thumbOffset = ScrollBarUtils.getThumbOffset( 15600 bounds.width(), thumbLength, extent, range, offset); 15601 15602 final float diff = x - mScrollCache.mScrollBarDraggingPos; 15603 final float maxThumbOffset = bounds.width() - thumbLength; 15604 final float newThumbOffset = 15605 Math.min(Math.max(thumbOffset + diff, 0.0f), maxThumbOffset); 15606 final int width = getWidth(); 15607 if (Math.round(newThumbOffset) != thumbOffset && maxThumbOffset > 0 15608 && width > 0 && extent > 0) { 15609 final int newX = Math.round((range - extent) 15610 / ((float)extent / width) * (newThumbOffset / maxThumbOffset)); 15611 if (newX != getScrollX()) { 15612 mScrollCache.mScrollBarDraggingPos = x; 15613 setScrollX(newX); 15614 } 15615 } 15616 return true; 15617 } 15618 case MotionEvent.ACTION_DOWN: 15619 if (mScrollCache.state == ScrollabilityCache.OFF) { 15620 return false; 15621 } 15622 if (isOnVerticalScrollbarThumb(x, y)) { 15623 mScrollCache.mScrollBarDraggingState = 15624 ScrollabilityCache.DRAGGING_VERTICAL_SCROLL_BAR; 15625 mScrollCache.mScrollBarDraggingPos = y; 15626 return true; 15627 } 15628 if (isOnHorizontalScrollbarThumb(x, y)) { 15629 mScrollCache.mScrollBarDraggingState = 15630 ScrollabilityCache.DRAGGING_HORIZONTAL_SCROLL_BAR; 15631 mScrollCache.mScrollBarDraggingPos = x; 15632 return true; 15633 } 15634 } 15635 mScrollCache.mScrollBarDraggingState = ScrollabilityCache.NOT_DRAGGING; 15636 return false; 15637 } 15638 15639 /** 15640 * Implement this method to handle touch screen motion events. 15641 * <p> 15642 * If this method is used to detect click actions, it is recommended that 15643 * the actions be performed by implementing and calling 15644 * {@link #performClick()}. This will ensure consistent system behavior, 15645 * including: 15646 * <ul> 15647 * <li>obeying click sound preferences 15648 * <li>dispatching OnClickListener calls 15649 * <li>handling {@link AccessibilityNodeInfo#ACTION_CLICK ACTION_CLICK} when 15650 * accessibility features are enabled 15651 * </ul> 15652 * 15653 * @param event The motion event. 15654 * @return True if the event was handled, false otherwise. 15655 */ 15656 public boolean onTouchEvent(MotionEvent event) { 15657 final float x = event.getX(); 15658 final float y = event.getY(); 15659 final int viewFlags = mViewFlags; 15660 final int action = event.getAction(); 15661 15662 final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE 15663 || (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) 15664 || (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE; 15665 15666 if ((viewFlags & ENABLED_MASK) == DISABLED) { 15667 if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) { 15668 setPressed(false); 15669 } 15670 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 15671 // A disabled view that is clickable still consumes the touch 15672 // events, it just doesn't respond to them. 15673 return clickable; 15674 } 15675 if (mTouchDelegate != null) { 15676 if (mTouchDelegate.onTouchEvent(event)) { 15677 return true; 15678 } 15679 } 15680 15681 if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) { 15682 switch (action) { 15683 case MotionEvent.ACTION_UP: 15684 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 15685 if ((viewFlags & TOOLTIP) == TOOLTIP) { 15686 handleTooltipUp(); 15687 } 15688 if (!clickable) { 15689 removeTapCallback(); 15690 removeLongPressCallback(); 15691 mInContextButtonPress = false; 15692 mHasPerformedLongPress = false; 15693 mIgnoreNextUpEvent = false; 15694 break; 15695 } 15696 boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0; 15697 if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) { 15698 // take focus if we don't have it already and we should in 15699 // touch mode. 15700 boolean focusTaken = false; 15701 if (isFocusable() && isFocusableInTouchMode() && !isFocused()) { 15702 focusTaken = requestFocus(); 15703 } 15704 15705 if (prepressed) { 15706 // The button is being released before we actually 15707 // showed it as pressed. Make it show the pressed 15708 // state now (before scheduling the click) to ensure 15709 // the user sees it. 15710 setPressed(true, x, y); 15711 } 15712 15713 if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) { 15714 // This is a tap, so remove the longpress check 15715 removeLongPressCallback(); 15716 15717 // Only perform take click actions if we were in the pressed state 15718 if (!focusTaken) { 15719 // Use a Runnable and post this rather than calling 15720 // performClick directly. This lets other visual state 15721 // of the view update before click actions start. 15722 if (mPerformClick == null) { 15723 mPerformClick = new PerformClick(); 15724 } 15725 if (!post(mPerformClick)) { 15726 performClickInternal(); 15727 } 15728 } 15729 } 15730 15731 if (mUnsetPressedState == null) { 15732 mUnsetPressedState = new UnsetPressedState(); 15733 } 15734 15735 if (prepressed) { 15736 postDelayed(mUnsetPressedState, 15737 ViewConfiguration.getPressedStateDuration()); 15738 } else if (!post(mUnsetPressedState)) { 15739 // If the post failed, unpress right now 15740 mUnsetPressedState.run(); 15741 } 15742 15743 removeTapCallback(); 15744 } 15745 mIgnoreNextUpEvent = false; 15746 break; 15747 15748 case MotionEvent.ACTION_DOWN: 15749 if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) { 15750 mPrivateFlags3 |= PFLAG3_FINGER_DOWN; 15751 } 15752 mHasPerformedLongPress = false; 15753 15754 if (!clickable) { 15755 checkForLongClick( 15756 ViewConfiguration.getLongPressTimeout(), 15757 x, 15758 y, 15759 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 15760 break; 15761 } 15762 15763 if (performButtonActionOnTouchDown(event)) { 15764 break; 15765 } 15766 15767 // Walk up the hierarchy to determine if we're inside a scrolling container. 15768 boolean isInScrollingContainer = isInScrollingContainer(); 15769 15770 // For views inside a scrolling container, delay the pressed feedback for 15771 // a short period in case this is a scroll. 15772 if (isInScrollingContainer) { 15773 mPrivateFlags |= PFLAG_PREPRESSED; 15774 if (mPendingCheckForTap == null) { 15775 mPendingCheckForTap = new CheckForTap(); 15776 } 15777 mPendingCheckForTap.x = event.getX(); 15778 mPendingCheckForTap.y = event.getY(); 15779 postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout()); 15780 } else { 15781 // Not inside a scrolling container, so show the feedback right away 15782 setPressed(true, x, y); 15783 checkForLongClick( 15784 ViewConfiguration.getLongPressTimeout(), 15785 x, 15786 y, 15787 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 15788 } 15789 break; 15790 15791 case MotionEvent.ACTION_CANCEL: 15792 if (clickable) { 15793 setPressed(false); 15794 } 15795 removeTapCallback(); 15796 removeLongPressCallback(); 15797 mInContextButtonPress = false; 15798 mHasPerformedLongPress = false; 15799 mIgnoreNextUpEvent = false; 15800 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 15801 break; 15802 15803 case MotionEvent.ACTION_MOVE: 15804 if (clickable) { 15805 drawableHotspotChanged(x, y); 15806 } 15807 15808 final int motionClassification = event.getClassification(); 15809 final boolean ambiguousGesture = 15810 motionClassification == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE; 15811 int touchSlop = mTouchSlop; 15812 if (ambiguousGesture && hasPendingLongPressCallback()) { 15813 if (!pointInView(x, y, touchSlop)) { 15814 // The default action here is to cancel long press. But instead, we 15815 // just extend the timeout here, in case the classification 15816 // stays ambiguous. 15817 removeLongPressCallback(); 15818 long delay = (long) (ViewConfiguration.getLongPressTimeout() 15819 * mAmbiguousGestureMultiplier); 15820 // Subtract the time already spent 15821 delay -= event.getEventTime() - event.getDownTime(); 15822 checkForLongClick( 15823 delay, 15824 x, 15825 y, 15826 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 15827 } 15828 touchSlop *= mAmbiguousGestureMultiplier; 15829 } 15830 15831 // Be lenient about moving outside of buttons 15832 if (!pointInView(x, y, touchSlop)) { 15833 // Outside button 15834 // Remove any future long press/tap checks 15835 removeTapCallback(); 15836 removeLongPressCallback(); 15837 if ((mPrivateFlags & PFLAG_PRESSED) != 0) { 15838 setPressed(false); 15839 } 15840 mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN; 15841 } 15842 15843 final boolean deepPress = 15844 motionClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS; 15845 if (deepPress && hasPendingLongPressCallback()) { 15846 // process the long click action immediately 15847 removeLongPressCallback(); 15848 checkForLongClick( 15849 0 /* send immediately */, 15850 x, 15851 y, 15852 TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__DEEP_PRESS); 15853 } 15854 15855 break; 15856 } 15857 15858 return true; 15859 } 15860 15861 return false; 15862 } 15863 15864 /** 15865 * @hide 15866 */ 15867 @UnsupportedAppUsage 15868 public boolean isInScrollingContainer() { 15869 ViewParent p = getParent(); 15870 while (p != null && p instanceof ViewGroup) { 15871 if (((ViewGroup) p).shouldDelayChildPressedState()) { 15872 return true; 15873 } 15874 p = p.getParent(); 15875 } 15876 return false; 15877 } 15878 15879 /** 15880 * Remove the longpress detection timer. 15881 */ 15882 private void removeLongPressCallback() { 15883 if (mPendingCheckForLongPress != null) { 15884 removeCallbacks(mPendingCheckForLongPress); 15885 } 15886 } 15887 15888 /** 15889 * Return true if the long press callback is scheduled to run sometime in the future. 15890 * Return false if there is no scheduled long press callback at the moment. 15891 */ 15892 private boolean hasPendingLongPressCallback() { 15893 if (mPendingCheckForLongPress == null) { 15894 return false; 15895 } 15896 final AttachInfo attachInfo = mAttachInfo; 15897 if (attachInfo == null) { 15898 return false; 15899 } 15900 return attachInfo.mHandler.hasCallbacks(mPendingCheckForLongPress); 15901 } 15902 15903 /** 15904 * Remove the pending click action 15905 */ 15906 @UnsupportedAppUsage 15907 private void removePerformClickCallback() { 15908 if (mPerformClick != null) { 15909 removeCallbacks(mPerformClick); 15910 } 15911 } 15912 15913 /** 15914 * Remove the prepress detection timer. 15915 */ 15916 private void removeUnsetPressCallback() { 15917 if ((mPrivateFlags & PFLAG_PRESSED) != 0 && mUnsetPressedState != null) { 15918 setPressed(false); 15919 removeCallbacks(mUnsetPressedState); 15920 } 15921 } 15922 15923 /** 15924 * Remove the tap detection timer. 15925 */ 15926 private void removeTapCallback() { 15927 if (mPendingCheckForTap != null) { 15928 mPrivateFlags &= ~PFLAG_PREPRESSED; 15929 removeCallbacks(mPendingCheckForTap); 15930 } 15931 } 15932 15933 /** 15934 * Cancels a pending long press. Your subclass can use this if you 15935 * want the context menu to come up if the user presses and holds 15936 * at the same place, but you don't want it to come up if they press 15937 * and then move around enough to cause scrolling. 15938 */ 15939 public void cancelLongPress() { 15940 removeLongPressCallback(); 15941 15942 /* 15943 * The prepressed state handled by the tap callback is a display 15944 * construct, but the tap callback will post a long press callback 15945 * less its own timeout. Remove it here. 15946 */ 15947 removeTapCallback(); 15948 } 15949 15950 /** 15951 * Sets the TouchDelegate for this View. 15952 */ 15953 public void setTouchDelegate(TouchDelegate delegate) { 15954 mTouchDelegate = delegate; 15955 } 15956 15957 /** 15958 * Gets the TouchDelegate for this View. 15959 */ 15960 public TouchDelegate getTouchDelegate() { 15961 return mTouchDelegate; 15962 } 15963 15964 /** 15965 * Request unbuffered dispatch of the given stream of MotionEvents to this View. 15966 * 15967 * Until this View receives a corresponding {@link MotionEvent#ACTION_UP}, ask that the input 15968 * system not batch {@link MotionEvent}s but instead deliver them as soon as they're 15969 * available. This method should only be called for touch events. 15970 * 15971 * <p class="note">This API is not intended for most applications. Buffered dispatch 15972 * provides many of benefits, and just requesting unbuffered dispatch on most MotionEvent 15973 * streams will not improve your input latency. Side effects include: increased latency, 15974 * jittery scrolls and inability to take advantage of system resampling. Talk to your input 15975 * professional to see if {@link #requestUnbufferedDispatch(MotionEvent)} is right for 15976 * you.</p> 15977 * 15978 * To receive unbuffered events for arbitrary input device source classes, use 15979 * {@link #requestUnbufferedDispatch(int)}, 15980 * 15981 * @see View#requestUnbufferedDispatch(int) 15982 */ 15983 public final void requestUnbufferedDispatch(MotionEvent event) { 15984 final int action = event.getAction(); 15985 if (mAttachInfo == null 15986 || action != MotionEvent.ACTION_DOWN && action != MotionEvent.ACTION_MOVE 15987 || !event.isTouchEvent()) { 15988 return; 15989 } 15990 mAttachInfo.mUnbufferedDispatchRequested = true; 15991 } 15992 15993 /** 15994 * Request unbuffered dispatch of the given event source class to this view. 15995 * This is similar to {@link View#requestUnbufferedDispatch(MotionEvent)}, but does not 15996 * automatically terminate, and allows the specification of arbitrary input source classes. 15997 * 15998 * @param source The combined input source class to request unbuffered dispatch for. All 15999 * events coming from these source classes will not be buffered. Set to 16000 * {@link InputDevice#SOURCE_CLASS_NONE} in order to return to default behaviour. 16001 * 16002 * @see View#requestUnbufferedDispatch(MotionEvent) 16003 */ 16004 public final void requestUnbufferedDispatch(@InputSourceClass int source) { 16005 if (mUnbufferedInputSource == source) { 16006 return; 16007 } 16008 mUnbufferedInputSource = source; 16009 if (mParent != null) { 16010 mParent.onDescendantUnbufferedRequested(); 16011 } 16012 } 16013 16014 private boolean hasSize() { 16015 return (mBottom > mTop) && (mRight > mLeft); 16016 } 16017 16018 private boolean canTakeFocus() { 16019 return ((mViewFlags & VISIBILITY_MASK) == VISIBLE) 16020 && ((mViewFlags & FOCUSABLE) == FOCUSABLE) 16021 && ((mViewFlags & ENABLED_MASK) == ENABLED) 16022 && (sCanFocusZeroSized || !isLayoutValid() || hasSize()); 16023 } 16024 16025 /** 16026 * Set flags controlling behavior of this view. 16027 * 16028 * @param flags Constant indicating the value which should be set 16029 * @param mask Constant indicating the bit range that should be changed 16030 */ 16031 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) 16032 void setFlags(int flags, int mask) { 16033 final boolean accessibilityEnabled = 16034 AccessibilityManager.getInstance(mContext).isEnabled(); 16035 final boolean oldIncludeForAccessibility = accessibilityEnabled && includeForAccessibility(); 16036 16037 int old = mViewFlags; 16038 mViewFlags = (mViewFlags & ~mask) | (flags & mask); 16039 16040 int changed = mViewFlags ^ old; 16041 if (changed == 0) { 16042 return; 16043 } 16044 int privateFlags = mPrivateFlags; 16045 boolean shouldNotifyFocusableAvailable = false; 16046 16047 // If focusable is auto, update the FOCUSABLE bit. 16048 int focusableChangedByAuto = 0; 16049 if (((mViewFlags & FOCUSABLE_AUTO) != 0) 16050 && (changed & (FOCUSABLE_MASK | CLICKABLE)) != 0) { 16051 // Heuristic only takes into account whether view is clickable. 16052 final int newFocus; 16053 if ((mViewFlags & CLICKABLE) != 0) { 16054 newFocus = FOCUSABLE; 16055 } else { 16056 newFocus = NOT_FOCUSABLE; 16057 } 16058 mViewFlags = (mViewFlags & ~FOCUSABLE) | newFocus; 16059 focusableChangedByAuto = (old & FOCUSABLE) ^ (newFocus & FOCUSABLE); 16060 changed = (changed & ~FOCUSABLE) | focusableChangedByAuto; 16061 } 16062 16063 /* Check if the FOCUSABLE bit has changed */ 16064 if (((changed & FOCUSABLE) != 0) && ((privateFlags & PFLAG_HAS_BOUNDS) != 0)) { 16065 if (((old & FOCUSABLE) == FOCUSABLE) 16066 && ((privateFlags & PFLAG_FOCUSED) != 0)) { 16067 /* Give up focus if we are no longer focusable */ 16068 clearFocus(); 16069 if (mParent instanceof ViewGroup) { 16070 ((ViewGroup) mParent).clearFocusedInCluster(); 16071 } 16072 } else if (((old & FOCUSABLE) == NOT_FOCUSABLE) 16073 && ((privateFlags & PFLAG_FOCUSED) == 0)) { 16074 /* 16075 * Tell the view system that we are now available to take focus 16076 * if no one else already has it. 16077 */ 16078 if (mParent != null) { 16079 ViewRootImpl viewRootImpl = getViewRootImpl(); 16080 if (!sAutoFocusableOffUIThreadWontNotifyParents 16081 || focusableChangedByAuto == 0 16082 || viewRootImpl == null 16083 || viewRootImpl.mThread == Thread.currentThread()) { 16084 shouldNotifyFocusableAvailable = canTakeFocus(); 16085 } 16086 } 16087 } 16088 } 16089 16090 final int newVisibility = flags & VISIBILITY_MASK; 16091 if (newVisibility == VISIBLE) { 16092 if ((changed & VISIBILITY_MASK) != 0) { 16093 /* 16094 * If this view is becoming visible, invalidate it in case it changed while 16095 * it was not visible. Marking it drawn ensures that the invalidation will 16096 * go through. 16097 */ 16098 mPrivateFlags |= PFLAG_DRAWN; 16099 invalidate(true); 16100 16101 needGlobalAttributesUpdate(true); 16102 16103 // a view becoming visible is worth notifying the parent about in case nothing has 16104 // focus. Even if this specific view isn't focusable, it may contain something that 16105 // is, so let the root view try to give this focus if nothing else does. 16106 shouldNotifyFocusableAvailable = hasSize(); 16107 } 16108 } 16109 16110 if ((changed & ENABLED_MASK) != 0) { 16111 if ((mViewFlags & ENABLED_MASK) == ENABLED) { 16112 // a view becoming enabled should notify the parent as long as the view is also 16113 // visible and the parent wasn't already notified by becoming visible during this 16114 // setFlags invocation. 16115 shouldNotifyFocusableAvailable = canTakeFocus(); 16116 } else { 16117 if (isFocused()) clearFocus(); 16118 } 16119 } 16120 16121 if (shouldNotifyFocusableAvailable && mParent != null) { 16122 mParent.focusableViewAvailable(this); 16123 } 16124 16125 /* Check if the GONE bit has changed */ 16126 if ((changed & GONE) != 0) { 16127 needGlobalAttributesUpdate(false); 16128 requestLayout(); 16129 16130 if (((mViewFlags & VISIBILITY_MASK) == GONE)) { 16131 if (hasFocus()) { 16132 clearFocus(); 16133 if (mParent instanceof ViewGroup) { 16134 ((ViewGroup) mParent).clearFocusedInCluster(); 16135 } 16136 } 16137 clearAccessibilityFocus(); 16138 destroyDrawingCache(); 16139 if (mParent instanceof View) { 16140 // GONE views noop invalidation, so invalidate the parent 16141 ((View) mParent).invalidate(true); 16142 } 16143 // Mark the view drawn to ensure that it gets invalidated properly the next 16144 // time it is visible and gets invalidated 16145 mPrivateFlags |= PFLAG_DRAWN; 16146 } 16147 if (mAttachInfo != null) { 16148 mAttachInfo.mViewVisibilityChanged = true; 16149 } 16150 } 16151 16152 /* Check if the VISIBLE bit has changed */ 16153 if ((changed & INVISIBLE) != 0) { 16154 needGlobalAttributesUpdate(false); 16155 /* 16156 * If this view is becoming invisible, set the DRAWN flag so that 16157 * the next invalidate() will not be skipped. 16158 */ 16159 mPrivateFlags |= PFLAG_DRAWN; 16160 16161 if (((mViewFlags & VISIBILITY_MASK) == INVISIBLE)) { 16162 // root view becoming invisible shouldn't clear focus and accessibility focus 16163 if (getRootView() != this) { 16164 if (hasFocus()) { 16165 clearFocus(); 16166 if (mParent instanceof ViewGroup) { 16167 ((ViewGroup) mParent).clearFocusedInCluster(); 16168 } 16169 } 16170 clearAccessibilityFocus(); 16171 } 16172 } 16173 if (mAttachInfo != null) { 16174 mAttachInfo.mViewVisibilityChanged = true; 16175 } 16176 } 16177 16178 if ((changed & VISIBILITY_MASK) != 0) { 16179 // If the view is invisible, cleanup its display list to free up resources 16180 if (newVisibility != VISIBLE && mAttachInfo != null) { 16181 cleanupDraw(); 16182 } 16183 16184 if (mParent instanceof ViewGroup) { 16185 ViewGroup parent = (ViewGroup) mParent; 16186 parent.onChildVisibilityChanged(this, (changed & VISIBILITY_MASK), 16187 newVisibility); 16188 parent.invalidate(true); 16189 } else if (mParent != null) { 16190 mParent.invalidateChild(this, null); 16191 } 16192 16193 if (mAttachInfo != null) { 16194 dispatchVisibilityChanged(this, newVisibility); 16195 16196 // Aggregated visibility changes are dispatched to attached views 16197 // in visible windows where the parent is currently shown/drawn 16198 // or the parent is not a ViewGroup (and therefore assumed to be a ViewRoot), 16199 // discounting clipping or overlapping. This makes it a good place 16200 // to change animation states. 16201 if (mParent != null && getWindowVisibility() == VISIBLE && 16202 ((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) { 16203 dispatchVisibilityAggregated(newVisibility == VISIBLE); 16204 } 16205 notifySubtreeAccessibilityStateChangedIfNeeded(); 16206 } 16207 } 16208 16209 if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { 16210 destroyDrawingCache(); 16211 } 16212 16213 if ((changed & DRAWING_CACHE_ENABLED) != 0) { 16214 destroyDrawingCache(); 16215 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 16216 invalidateParentCaches(); 16217 } 16218 16219 if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { 16220 destroyDrawingCache(); 16221 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 16222 } 16223 16224 if ((changed & DRAW_MASK) != 0) { 16225 if ((mViewFlags & WILL_NOT_DRAW) != 0) { 16226 if (mBackground != null 16227 || mDefaultFocusHighlight != null 16228 || (mForegroundInfo != null && mForegroundInfo.mDrawable != null)) { 16229 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 16230 } else { 16231 mPrivateFlags |= PFLAG_SKIP_DRAW; 16232 } 16233 } else { 16234 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 16235 } 16236 requestLayout(); 16237 invalidate(true); 16238 } 16239 16240 if ((changed & KEEP_SCREEN_ON) != 0) { 16241 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 16242 mParent.recomputeViewAttributes(this); 16243 } 16244 } 16245 16246 if (accessibilityEnabled) { 16247 // If we're an accessibility pane and the visibility changed, we already have sent 16248 // a state change, so we really don't need to report other changes. 16249 if (isAccessibilityPane()) { 16250 changed &= ~VISIBILITY_MASK; 16251 } 16252 if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0 16253 || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0 16254 || (changed & CONTEXT_CLICKABLE) != 0) { 16255 if (oldIncludeForAccessibility != includeForAccessibility()) { 16256 notifySubtreeAccessibilityStateChangedIfNeeded(); 16257 } else { 16258 notifyViewAccessibilityStateChangedIfNeeded( 16259 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 16260 } 16261 } else if ((changed & ENABLED_MASK) != 0) { 16262 notifyViewAccessibilityStateChangedIfNeeded( 16263 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 16264 } 16265 } 16266 } 16267 16268 /** 16269 * Change the view's z order in the tree, so it's on top of other sibling 16270 * views. This ordering change may affect layout, if the parent container 16271 * uses an order-dependent layout scheme (e.g., LinearLayout). Prior 16272 * to {@link android.os.Build.VERSION_CODES#KITKAT} this 16273 * method should be followed by calls to {@link #requestLayout()} and 16274 * {@link View#invalidate()} on the view's parent to force the parent to redraw 16275 * with the new child ordering. 16276 * 16277 * @see ViewGroup#bringChildToFront(View) 16278 */ 16279 public void bringToFront() { 16280 if (mParent != null) { 16281 mParent.bringChildToFront(this); 16282 } 16283 } 16284 16285 /** 16286 * This is called in response to an internal scroll in this view (i.e., the 16287 * view scrolled its own contents). This is typically as a result of 16288 * {@link #scrollBy(int, int)} or {@link #scrollTo(int, int)} having been 16289 * called. 16290 * 16291 * @param l Current horizontal scroll origin. 16292 * @param t Current vertical scroll origin. 16293 * @param oldl Previous horizontal scroll origin. 16294 * @param oldt Previous vertical scroll origin. 16295 */ 16296 protected void onScrollChanged(int l, int t, int oldl, int oldt) { 16297 notifySubtreeAccessibilityStateChangedIfNeeded(); 16298 postSendViewScrolledAccessibilityEventCallback(l - oldl, t - oldt); 16299 16300 mBackgroundSizeChanged = true; 16301 mDefaultFocusHighlightSizeChanged = true; 16302 if (mForegroundInfo != null) { 16303 mForegroundInfo.mBoundsChanged = true; 16304 } 16305 16306 final AttachInfo ai = mAttachInfo; 16307 if (ai != null) { 16308 ai.mViewScrollChanged = true; 16309 } 16310 16311 if (mListenerInfo != null && mListenerInfo.mOnScrollChangeListener != null) { 16312 mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt); 16313 } 16314 } 16315 16316 /** 16317 * Interface definition for a callback to be invoked when the scroll 16318 * X or Y positions of a view change. 16319 * <p> 16320 * <b>Note:</b> Some views handle scrolling independently from View and may 16321 * have their own separate listeners for scroll-type events. For example, 16322 * {@link android.widget.ListView ListView} allows clients to register an 16323 * {@link android.widget.ListView#setOnScrollListener(android.widget.AbsListView.OnScrollListener) AbsListView.OnScrollListener} 16324 * to listen for changes in list scroll position. 16325 * 16326 * @see #setOnScrollChangeListener(View.OnScrollChangeListener) 16327 */ 16328 public interface OnScrollChangeListener { 16329 /** 16330 * Called when the scroll position of a view changes. 16331 * 16332 * @param v The view whose scroll position has changed. 16333 * @param scrollX Current horizontal scroll origin. 16334 * @param scrollY Current vertical scroll origin. 16335 * @param oldScrollX Previous horizontal scroll origin. 16336 * @param oldScrollY Previous vertical scroll origin. 16337 */ 16338 void onScrollChange(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY); 16339 } 16340 16341 /** 16342 * Interface definition for a callback to be invoked when the layout bounds of a view 16343 * changes due to layout processing. 16344 */ 16345 public interface OnLayoutChangeListener { 16346 /** 16347 * Called when the layout bounds of a view changes due to layout processing. 16348 * 16349 * @param v The view whose bounds have changed. 16350 * @param left The new value of the view's left property. 16351 * @param top The new value of the view's top property. 16352 * @param right The new value of the view's right property. 16353 * @param bottom The new value of the view's bottom property. 16354 * @param oldLeft The previous value of the view's left property. 16355 * @param oldTop The previous value of the view's top property. 16356 * @param oldRight The previous value of the view's right property. 16357 * @param oldBottom The previous value of the view's bottom property. 16358 */ 16359 void onLayoutChange(View v, int left, int top, int right, int bottom, 16360 int oldLeft, int oldTop, int oldRight, int oldBottom); 16361 } 16362 16363 /** 16364 * This is called during layout when the size of this view has changed. If 16365 * you were just added to the view hierarchy, you're called with the old 16366 * values of 0. 16367 * 16368 * @param w Current width of this view. 16369 * @param h Current height of this view. 16370 * @param oldw Old width of this view. 16371 * @param oldh Old height of this view. 16372 */ 16373 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 16374 } 16375 16376 /** 16377 * Called by draw to draw the child views. This may be overridden 16378 * by derived classes to gain control just before its children are drawn 16379 * (but after its own view has been drawn). 16380 * @param canvas the canvas on which to draw the view 16381 */ 16382 protected void dispatchDraw(Canvas canvas) { 16383 16384 } 16385 16386 /** 16387 * Gets the parent of this view. Note that the parent is a 16388 * ViewParent and not necessarily a View. 16389 * 16390 * @return Parent of this view. 16391 */ 16392 public final ViewParent getParent() { 16393 return mParent; 16394 } 16395 16396 /** 16397 * Set the horizontal scrolled position of your view. This will cause a call to 16398 * {@link #onScrollChanged(int, int, int, int)} and the view will be 16399 * invalidated. 16400 * @param value the x position to scroll to 16401 */ 16402 public void setScrollX(int value) { 16403 scrollTo(value, mScrollY); 16404 } 16405 16406 /** 16407 * Set the vertical scrolled position of your view. This will cause a call to 16408 * {@link #onScrollChanged(int, int, int, int)} and the view will be 16409 * invalidated. 16410 * @param value the y position to scroll to 16411 */ 16412 public void setScrollY(int value) { 16413 scrollTo(mScrollX, value); 16414 } 16415 16416 /** 16417 * Return the scrolled left position of this view. This is the left edge of 16418 * the displayed part of your view. You do not need to draw any pixels 16419 * farther left, since those are outside of the frame of your view on 16420 * screen. 16421 * 16422 * @return The left edge of the displayed part of your view, in pixels. 16423 */ 16424 @InspectableProperty 16425 public final int getScrollX() { 16426 return mScrollX; 16427 } 16428 16429 /** 16430 * Return the scrolled top position of this view. This is the top edge of 16431 * the displayed part of your view. You do not need to draw any pixels above 16432 * it, since those are outside of the frame of your view on screen. 16433 * 16434 * @return The top edge of the displayed part of your view, in pixels. 16435 */ 16436 @InspectableProperty 16437 public final int getScrollY() { 16438 return mScrollY; 16439 } 16440 16441 /** 16442 * Return the width of your view. 16443 * 16444 * @return The width of your view, in pixels. 16445 */ 16446 @ViewDebug.ExportedProperty(category = "layout") 16447 public final int getWidth() { 16448 return mRight - mLeft; 16449 } 16450 16451 /** 16452 * Return the height of your view. 16453 * 16454 * @return The height of your view, in pixels. 16455 */ 16456 @ViewDebug.ExportedProperty(category = "layout") 16457 public final int getHeight() { 16458 return mBottom - mTop; 16459 } 16460 16461 /** 16462 * Return the visible drawing bounds of your view. Fills in the output 16463 * rectangle with the values from getScrollX(), getScrollY(), 16464 * getWidth(), and getHeight(). These bounds do not account for any 16465 * transformation properties currently set on the view, such as 16466 * {@link #setScaleX(float)} or {@link #setRotation(float)}. 16467 * 16468 * @param outRect The (scrolled) drawing bounds of the view. 16469 */ 16470 public void getDrawingRect(Rect outRect) { 16471 outRect.left = mScrollX; 16472 outRect.top = mScrollY; 16473 outRect.right = mScrollX + (mRight - mLeft); 16474 outRect.bottom = mScrollY + (mBottom - mTop); 16475 } 16476 16477 /** 16478 * Like {@link #getMeasuredWidthAndState()}, but only returns the 16479 * raw width component (that is the result is masked by 16480 * {@link #MEASURED_SIZE_MASK}). 16481 * 16482 * @return The raw measured width of this view. 16483 */ 16484 public final int getMeasuredWidth() { 16485 return mMeasuredWidth & MEASURED_SIZE_MASK; 16486 } 16487 16488 /** 16489 * Return the full width measurement information for this view as computed 16490 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 16491 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 16492 * This should be used during measurement and layout calculations only. Use 16493 * {@link #getWidth()} to see how wide a view is after layout. 16494 * 16495 * @return The measured width of this view as a bit mask. 16496 */ 16497 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 16498 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 16499 name = "MEASURED_STATE_TOO_SMALL"), 16500 }) 16501 public final int getMeasuredWidthAndState() { 16502 return mMeasuredWidth; 16503 } 16504 16505 /** 16506 * Like {@link #getMeasuredHeightAndState()}, but only returns the 16507 * raw height component (that is the result is masked by 16508 * {@link #MEASURED_SIZE_MASK}). 16509 * 16510 * @return The raw measured height of this view. 16511 */ 16512 public final int getMeasuredHeight() { 16513 return mMeasuredHeight & MEASURED_SIZE_MASK; 16514 } 16515 16516 /** 16517 * Return the full height measurement information for this view as computed 16518 * by the most recent call to {@link #measure(int, int)}. This result is a bit mask 16519 * as defined by {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}. 16520 * This should be used during measurement and layout calculations only. Use 16521 * {@link #getHeight()} to see how high a view is after layout. 16522 * 16523 * @return The measured height of this view as a bit mask. 16524 */ 16525 @ViewDebug.ExportedProperty(category = "measurement", flagMapping = { 16526 @ViewDebug.FlagToString(mask = MEASURED_STATE_MASK, equals = MEASURED_STATE_TOO_SMALL, 16527 name = "MEASURED_STATE_TOO_SMALL"), 16528 }) 16529 public final int getMeasuredHeightAndState() { 16530 return mMeasuredHeight; 16531 } 16532 16533 /** 16534 * Return only the state bits of {@link #getMeasuredWidthAndState()} 16535 * and {@link #getMeasuredHeightAndState()}, combined into one integer. 16536 * The width component is in the regular bits {@link #MEASURED_STATE_MASK} 16537 * and the height component is at the shifted bits 16538 * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}. 16539 */ 16540 public final int getMeasuredState() { 16541 return (mMeasuredWidth&MEASURED_STATE_MASK) 16542 | ((mMeasuredHeight>>MEASURED_HEIGHT_STATE_SHIFT) 16543 & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT)); 16544 } 16545 16546 /** 16547 * The transform matrix of this view, which is calculated based on the current 16548 * rotation, scale, and pivot properties. 16549 * 16550 * @see #getRotation() 16551 * @see #getScaleX() 16552 * @see #getScaleY() 16553 * @see #getPivotX() 16554 * @see #getPivotY() 16555 * @return The current transform matrix for the view 16556 */ 16557 public Matrix getMatrix() { 16558 ensureTransformationInfo(); 16559 final Matrix matrix = mTransformationInfo.mMatrix; 16560 mRenderNode.getMatrix(matrix); 16561 return matrix; 16562 } 16563 16564 /** 16565 * Returns true if the transform matrix is the identity matrix. 16566 * Recomputes the matrix if necessary. 16567 * 16568 * @return True if the transform matrix is the identity matrix, false otherwise. 16569 * @hide 16570 */ 16571 @UnsupportedAppUsage 16572 public final boolean hasIdentityMatrix() { 16573 return mRenderNode.hasIdentityMatrix(); 16574 } 16575 16576 @UnsupportedAppUsage 16577 void ensureTransformationInfo() { 16578 if (mTransformationInfo == null) { 16579 mTransformationInfo = new TransformationInfo(); 16580 } 16581 } 16582 16583 /** 16584 * Utility method to retrieve the inverse of the current mMatrix property. 16585 * We cache the matrix to avoid recalculating it when transform properties 16586 * have not changed. 16587 * 16588 * @return The inverse of the current matrix of this view. 16589 * @hide 16590 */ 16591 @UnsupportedAppUsage 16592 public final Matrix getInverseMatrix() { 16593 ensureTransformationInfo(); 16594 if (mTransformationInfo.mInverseMatrix == null) { 16595 mTransformationInfo.mInverseMatrix = new Matrix(); 16596 } 16597 final Matrix matrix = mTransformationInfo.mInverseMatrix; 16598 mRenderNode.getInverseMatrix(matrix); 16599 return matrix; 16600 } 16601 16602 /** 16603 * Gets the distance along the Z axis from the camera to this view. 16604 * 16605 * @see #setCameraDistance(float) 16606 * 16607 * @return The distance along the Z axis. 16608 */ 16609 public float getCameraDistance() { 16610 final float dpi = mResources.getDisplayMetrics().densityDpi; 16611 return mRenderNode.getCameraDistance() * dpi; 16612 } 16613 16614 /** 16615 * <p>Sets the distance along the Z axis (orthogonal to the X/Y plane on which 16616 * views are drawn) from the camera to this view. The camera's distance 16617 * affects 3D transformations, for instance rotations around the X and Y 16618 * axis. If the rotationX or rotationY properties are changed and this view is 16619 * large (more than half the size of the screen), it is recommended to always 16620 * use a camera distance that's greater than the height (X axis rotation) or 16621 * the width (Y axis rotation) of this view.</p> 16622 * 16623 * <p>The distance of the camera from the view plane can have an affect on the 16624 * perspective distortion of the view when it is rotated around the x or y axis. 16625 * For example, a large distance will result in a large viewing angle, and there 16626 * will not be much perspective distortion of the view as it rotates. A short 16627 * distance may cause much more perspective distortion upon rotation, and can 16628 * also result in some drawing artifacts if the rotated view ends up partially 16629 * behind the camera (which is why the recommendation is to use a distance at 16630 * least as far as the size of the view, if the view is to be rotated.)</p> 16631 * 16632 * <p>The distance is expressed in "depth pixels." The default distance depends 16633 * on the screen density. For instance, on a medium density display, the 16634 * default distance is 1280. On a high density display, the default distance 16635 * is 1920.</p> 16636 * 16637 * <p>If you want to specify a distance that leads to visually consistent 16638 * results across various densities, use the following formula:</p> 16639 * <pre> 16640 * float scale = context.getResources().getDisplayMetrics().density; 16641 * view.setCameraDistance(distance * scale); 16642 * </pre> 16643 * 16644 * <p>The density scale factor of a high density display is 1.5, 16645 * and 1920 = 1280 * 1.5.</p> 16646 * 16647 * @param distance The distance in "depth pixels", if negative the opposite 16648 * value is used 16649 * 16650 * @see #setRotationX(float) 16651 * @see #setRotationY(float) 16652 */ 16653 public void setCameraDistance(float distance) { 16654 final float dpi = mResources.getDisplayMetrics().densityDpi; 16655 16656 invalidateViewProperty(true, false); 16657 mRenderNode.setCameraDistance(Math.abs(distance) / dpi); 16658 invalidateViewProperty(false, false); 16659 16660 invalidateParentIfNeededAndWasQuickRejected(); 16661 } 16662 16663 /** 16664 * The degrees that the view is rotated around the pivot point. 16665 * 16666 * @see #setRotation(float) 16667 * @see #getPivotX() 16668 * @see #getPivotY() 16669 * 16670 * @return The degrees of rotation. 16671 */ 16672 @ViewDebug.ExportedProperty(category = "drawing") 16673 @InspectableProperty 16674 public float getRotation() { 16675 return mRenderNode.getRotationZ(); 16676 } 16677 16678 /** 16679 * Sets the degrees that the view is rotated around the pivot point. Increasing values 16680 * result in clockwise rotation. 16681 * 16682 * @param rotation The degrees of rotation. 16683 * 16684 * @see #getRotation() 16685 * @see #getPivotX() 16686 * @see #getPivotY() 16687 * @see #setRotationX(float) 16688 * @see #setRotationY(float) 16689 * 16690 * @attr ref android.R.styleable#View_rotation 16691 */ 16692 public void setRotation(float rotation) { 16693 if (rotation != getRotation()) { 16694 // Double-invalidation is necessary to capture view's old and new areas 16695 invalidateViewProperty(true, false); 16696 mRenderNode.setRotationZ(rotation); 16697 invalidateViewProperty(false, true); 16698 16699 invalidateParentIfNeededAndWasQuickRejected(); 16700 notifySubtreeAccessibilityStateChangedIfNeeded(); 16701 } 16702 } 16703 16704 /** 16705 * The degrees that the view is rotated around the vertical axis through the pivot point. 16706 * 16707 * @see #getPivotX() 16708 * @see #getPivotY() 16709 * @see #setRotationY(float) 16710 * 16711 * @return The degrees of Y rotation. 16712 */ 16713 @ViewDebug.ExportedProperty(category = "drawing") 16714 @InspectableProperty 16715 public float getRotationY() { 16716 return mRenderNode.getRotationY(); 16717 } 16718 16719 /** 16720 * Sets the degrees that the view is rotated around the vertical axis through the pivot point. 16721 * Increasing values result in counter-clockwise rotation from the viewpoint of looking 16722 * down the y axis. 16723 * 16724 * When rotating large views, it is recommended to adjust the camera distance 16725 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 16726 * 16727 * @param rotationY The degrees of Y rotation. 16728 * 16729 * @see #getRotationY() 16730 * @see #getPivotX() 16731 * @see #getPivotY() 16732 * @see #setRotation(float) 16733 * @see #setRotationX(float) 16734 * @see #setCameraDistance(float) 16735 * 16736 * @attr ref android.R.styleable#View_rotationY 16737 */ 16738 public void setRotationY(float rotationY) { 16739 if (rotationY != getRotationY()) { 16740 invalidateViewProperty(true, false); 16741 mRenderNode.setRotationY(rotationY); 16742 invalidateViewProperty(false, true); 16743 16744 invalidateParentIfNeededAndWasQuickRejected(); 16745 notifySubtreeAccessibilityStateChangedIfNeeded(); 16746 } 16747 } 16748 16749 /** 16750 * The degrees that the view is rotated around the horizontal axis through the pivot point. 16751 * 16752 * @see #getPivotX() 16753 * @see #getPivotY() 16754 * @see #setRotationX(float) 16755 * 16756 * @return The degrees of X rotation. 16757 */ 16758 @ViewDebug.ExportedProperty(category = "drawing") 16759 @InspectableProperty 16760 public float getRotationX() { 16761 return mRenderNode.getRotationX(); 16762 } 16763 16764 /** 16765 * Sets the degrees that the view is rotated around the horizontal axis through the pivot point. 16766 * Increasing values result in clockwise rotation from the viewpoint of looking down the 16767 * x axis. 16768 * 16769 * When rotating large views, it is recommended to adjust the camera distance 16770 * accordingly. Refer to {@link #setCameraDistance(float)} for more information. 16771 * 16772 * @param rotationX The degrees of X rotation. 16773 * 16774 * @see #getRotationX() 16775 * @see #getPivotX() 16776 * @see #getPivotY() 16777 * @see #setRotation(float) 16778 * @see #setRotationY(float) 16779 * @see #setCameraDistance(float) 16780 * 16781 * @attr ref android.R.styleable#View_rotationX 16782 */ 16783 public void setRotationX(float rotationX) { 16784 if (rotationX != getRotationX()) { 16785 invalidateViewProperty(true, false); 16786 mRenderNode.setRotationX(rotationX); 16787 invalidateViewProperty(false, true); 16788 16789 invalidateParentIfNeededAndWasQuickRejected(); 16790 notifySubtreeAccessibilityStateChangedIfNeeded(); 16791 } 16792 } 16793 16794 /** 16795 * The amount that the view is scaled in x around the pivot point, as a proportion of 16796 * the view's unscaled width. A value of 1, the default, means that no scaling is applied. 16797 * 16798 * <p>By default, this is 1.0f. 16799 * 16800 * @see #getPivotX() 16801 * @see #getPivotY() 16802 * @return The scaling factor. 16803 */ 16804 @ViewDebug.ExportedProperty(category = "drawing") 16805 @InspectableProperty 16806 public float getScaleX() { 16807 return mRenderNode.getScaleX(); 16808 } 16809 16810 /** 16811 * Sets the amount that the view is scaled in x around the pivot point, as a proportion of 16812 * the view's unscaled width. A value of 1 means that no scaling is applied. 16813 * 16814 * @param scaleX The scaling factor. 16815 * @see #getPivotX() 16816 * @see #getPivotY() 16817 * 16818 * @attr ref android.R.styleable#View_scaleX 16819 */ 16820 public void setScaleX(float scaleX) { 16821 if (scaleX != getScaleX()) { 16822 scaleX = sanitizeFloatPropertyValue(scaleX, "scaleX"); 16823 invalidateViewProperty(true, false); 16824 mRenderNode.setScaleX(scaleX); 16825 invalidateViewProperty(false, true); 16826 16827 invalidateParentIfNeededAndWasQuickRejected(); 16828 notifySubtreeAccessibilityStateChangedIfNeeded(); 16829 } 16830 } 16831 16832 /** 16833 * The amount that the view is scaled in y around the pivot point, as a proportion of 16834 * the view's unscaled height. A value of 1, the default, means that no scaling is applied. 16835 * 16836 * <p>By default, this is 1.0f. 16837 * 16838 * @see #getPivotX() 16839 * @see #getPivotY() 16840 * @return The scaling factor. 16841 */ 16842 @ViewDebug.ExportedProperty(category = "drawing") 16843 @InspectableProperty 16844 public float getScaleY() { 16845 return mRenderNode.getScaleY(); 16846 } 16847 16848 /** 16849 * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of 16850 * the view's unscaled width. A value of 1 means that no scaling is applied. 16851 * 16852 * @param scaleY The scaling factor. 16853 * @see #getPivotX() 16854 * @see #getPivotY() 16855 * 16856 * @attr ref android.R.styleable#View_scaleY 16857 */ 16858 public void setScaleY(float scaleY) { 16859 if (scaleY != getScaleY()) { 16860 scaleY = sanitizeFloatPropertyValue(scaleY, "scaleY"); 16861 invalidateViewProperty(true, false); 16862 mRenderNode.setScaleY(scaleY); 16863 invalidateViewProperty(false, true); 16864 16865 invalidateParentIfNeededAndWasQuickRejected(); 16866 notifySubtreeAccessibilityStateChangedIfNeeded(); 16867 } 16868 } 16869 16870 /** 16871 * The x location of the point around which the view is {@link #setRotation(float) rotated} 16872 * and {@link #setScaleX(float) scaled}. 16873 * 16874 * @see #getRotation() 16875 * @see #getScaleX() 16876 * @see #getScaleY() 16877 * @see #getPivotY() 16878 * @return The x location of the pivot point. 16879 * 16880 * @attr ref android.R.styleable#View_transformPivotX 16881 */ 16882 @ViewDebug.ExportedProperty(category = "drawing") 16883 @InspectableProperty(name = "transformPivotX") 16884 public float getPivotX() { 16885 return mRenderNode.getPivotX(); 16886 } 16887 16888 /** 16889 * Sets the x location of the point around which the view is 16890 * {@link #setRotation(float) rotated} and {@link #setScaleX(float) scaled}. 16891 * By default, the pivot point is centered on the object. 16892 * Setting this property disables this behavior and causes the view to use only the 16893 * explicitly set pivotX and pivotY values. 16894 * 16895 * @param pivotX The x location of the pivot point. 16896 * @see #getRotation() 16897 * @see #getScaleX() 16898 * @see #getScaleY() 16899 * @see #getPivotY() 16900 * 16901 * @attr ref android.R.styleable#View_transformPivotX 16902 */ 16903 public void setPivotX(float pivotX) { 16904 if (!mRenderNode.isPivotExplicitlySet() || pivotX != getPivotX()) { 16905 invalidateViewProperty(true, false); 16906 mRenderNode.setPivotX(pivotX); 16907 invalidateViewProperty(false, true); 16908 16909 invalidateParentIfNeededAndWasQuickRejected(); 16910 } 16911 } 16912 16913 /** 16914 * The y location of the point around which the view is {@link #setRotation(float) rotated} 16915 * and {@link #setScaleY(float) scaled}. 16916 * 16917 * @see #getRotation() 16918 * @see #getScaleX() 16919 * @see #getScaleY() 16920 * @see #getPivotY() 16921 * @return The y location of the pivot point. 16922 * 16923 * @attr ref android.R.styleable#View_transformPivotY 16924 */ 16925 @ViewDebug.ExportedProperty(category = "drawing") 16926 @InspectableProperty(name = "transformPivotY") 16927 public float getPivotY() { 16928 return mRenderNode.getPivotY(); 16929 } 16930 16931 /** 16932 * Sets the y location of the point around which the view is {@link #setRotation(float) rotated} 16933 * and {@link #setScaleY(float) scaled}. By default, the pivot point is centered on the object. 16934 * Setting this property disables this behavior and causes the view to use only the 16935 * explicitly set pivotX and pivotY values. 16936 * 16937 * @param pivotY The y location of the pivot point. 16938 * @see #getRotation() 16939 * @see #getScaleX() 16940 * @see #getScaleY() 16941 * @see #getPivotY() 16942 * 16943 * @attr ref android.R.styleable#View_transformPivotY 16944 */ 16945 public void setPivotY(float pivotY) { 16946 if (!mRenderNode.isPivotExplicitlySet() || pivotY != getPivotY()) { 16947 invalidateViewProperty(true, false); 16948 mRenderNode.setPivotY(pivotY); 16949 invalidateViewProperty(false, true); 16950 16951 invalidateParentIfNeededAndWasQuickRejected(); 16952 } 16953 } 16954 16955 /** 16956 * Returns whether or not a pivot has been set by a call to {@link #setPivotX(float)} or 16957 * {@link #setPivotY(float)}. If no pivot has been set then the pivot will be the center 16958 * of the view. 16959 * 16960 * @return True if a pivot has been set, false if the default pivot is being used 16961 */ 16962 public boolean isPivotSet() { 16963 return mRenderNode.isPivotExplicitlySet(); 16964 } 16965 16966 /** 16967 * Clears any pivot previously set by a call to {@link #setPivotX(float)} or 16968 * {@link #setPivotY(float)}. After calling this {@link #isPivotSet()} will be false 16969 * and the pivot used for rotation will return to default of being centered on the view. 16970 */ 16971 public void resetPivot() { 16972 if (mRenderNode.resetPivot()) { 16973 invalidateViewProperty(false, false); 16974 } 16975 } 16976 16977 /** 16978 * The opacity of the view. This is a value from 0 to 1, where 0 means the view is 16979 * completely transparent and 1 means the view is completely opaque. 16980 * 16981 * <p>By default this is 1.0f. 16982 * @return The opacity of the view. 16983 */ 16984 @ViewDebug.ExportedProperty(category = "drawing") 16985 @InspectableProperty 16986 public float getAlpha() { 16987 return mTransformationInfo != null ? mTransformationInfo.mAlpha : 1; 16988 } 16989 16990 /** 16991 * Sets the behavior for overlapping rendering for this view (see {@link 16992 * #hasOverlappingRendering()} for more details on this behavior). Calling this method 16993 * is an alternative to overriding {@link #hasOverlappingRendering()} in a subclass, 16994 * providing the value which is then used internally. That is, when {@link 16995 * #forceHasOverlappingRendering(boolean)} is called, the value of {@link 16996 * #hasOverlappingRendering()} is ignored and the value passed into this method is used 16997 * instead. 16998 * 16999 * @param hasOverlappingRendering The value for overlapping rendering to be used internally 17000 * instead of that returned by {@link #hasOverlappingRendering()}. 17001 * 17002 * @attr ref android.R.styleable#View_forceHasOverlappingRendering 17003 */ 17004 public void forceHasOverlappingRendering(boolean hasOverlappingRendering) { 17005 mPrivateFlags3 |= PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED; 17006 if (hasOverlappingRendering) { 17007 mPrivateFlags3 |= PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 17008 } else { 17009 mPrivateFlags3 &= ~PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE; 17010 } 17011 } 17012 17013 /** 17014 * Returns the value for overlapping rendering that is used internally. This is either 17015 * the value passed into {@link #forceHasOverlappingRendering(boolean)}, if called, or 17016 * the return value of {@link #hasOverlappingRendering()}, otherwise. 17017 * 17018 * @return The value for overlapping rendering being used internally. 17019 */ 17020 public final boolean getHasOverlappingRendering() { 17021 return (mPrivateFlags3 & PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED) != 0 ? 17022 (mPrivateFlags3 & PFLAG3_OVERLAPPING_RENDERING_FORCED_VALUE) != 0 : 17023 hasOverlappingRendering(); 17024 } 17025 17026 /** 17027 * Returns whether this View has content which overlaps. 17028 * 17029 * <p>This function, intended to be overridden by specific View types, is an optimization when 17030 * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to 17031 * an offscreen buffer and then composited into place, which can be expensive. If the view has 17032 * no overlapping rendering, the view can draw each primitive with the appropriate alpha value 17033 * directly. An example of overlapping rendering is a TextView with a background image, such as 17034 * a Button. An example of non-overlapping rendering is a TextView with no background, or an 17035 * ImageView with only the foreground image. The default implementation returns true; subclasses 17036 * should override if they have cases which can be optimized.</p> 17037 * 17038 * <p><strong>Note:</strong> The return value of this method is ignored if {@link 17039 * #forceHasOverlappingRendering(boolean)} has been called on this view.</p> 17040 * 17041 * @return true if the content in this view might overlap, false otherwise. 17042 */ 17043 @ViewDebug.ExportedProperty(category = "drawing") 17044 public boolean hasOverlappingRendering() { 17045 return true; 17046 } 17047 17048 /** 17049 * Sets the opacity of the view to a value from 0 to 1, where 0 means the view is 17050 * completely transparent and 1 means the view is completely opaque. 17051 * 17052 * <p class="note"><strong>Note:</strong> setting alpha to a translucent value (0 < alpha < 1) 17053 * can have significant performance implications, especially for large views. It is best to use 17054 * the alpha property sparingly and transiently, as in the case of fading animations.</p> 17055 * 17056 * <p>For a view with a frequently changing alpha, such as during a fading animation, it is 17057 * strongly recommended for performance reasons to either override 17058 * {@link #hasOverlappingRendering()} to return <code>false</code> if appropriate, or setting a 17059 * {@link #setLayerType(int, android.graphics.Paint) layer type} on the view for the duration 17060 * of the animation. On versions {@link android.os.Build.VERSION_CODES#M} and below, 17061 * the default path for rendering an unlayered View with alpha could add multiple milliseconds 17062 * of rendering cost, even for simple or small views. Starting with 17063 * {@link android.os.Build.VERSION_CODES#M}, {@link #LAYER_TYPE_HARDWARE} is automatically 17064 * applied to the view at the rendering level.</p> 17065 * 17066 * <p>If this view overrides {@link #onSetAlpha(int)} to return true, then this view is 17067 * responsible for applying the opacity itself.</p> 17068 * 17069 * <p>On versions {@link android.os.Build.VERSION_CODES#LOLLIPOP_MR1} and below, note that if 17070 * the view is backed by a {@link #setLayerType(int, android.graphics.Paint) layer} and is 17071 * associated with a {@link #setLayerPaint(android.graphics.Paint) layer paint}, setting an 17072 * alpha value less than 1.0 will supersede the alpha of the layer paint.</p> 17073 * 17074 * <p>Starting with {@link android.os.Build.VERSION_CODES#M}, setting a translucent alpha 17075 * value will clip a View to its bounds, unless the View returns <code>false</code> from 17076 * {@link #hasOverlappingRendering}.</p> 17077 * 17078 * @param alpha The opacity of the view. 17079 * 17080 * @see #hasOverlappingRendering() 17081 * @see #setLayerType(int, android.graphics.Paint) 17082 * 17083 * @attr ref android.R.styleable#View_alpha 17084 */ 17085 public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) { 17086 ensureTransformationInfo(); 17087 if (mTransformationInfo.mAlpha != alpha) { 17088 setAlphaInternal(alpha); 17089 if (onSetAlpha((int) (alpha * 255))) { 17090 mPrivateFlags |= PFLAG_ALPHA_SET; 17091 // subclass is handling alpha - don't optimize rendering cache invalidation 17092 invalidateParentCaches(); 17093 invalidate(true); 17094 } else { 17095 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17096 invalidateViewProperty(true, false); 17097 mRenderNode.setAlpha(getFinalAlpha()); 17098 } 17099 } 17100 } 17101 17102 /** 17103 * Faster version of setAlpha() which performs the same steps except there are 17104 * no calls to invalidate(). The caller of this function should perform proper invalidation 17105 * on the parent and this object. The return value indicates whether the subclass handles 17106 * alpha (the return value for onSetAlpha()). 17107 * 17108 * @param alpha The new value for the alpha property 17109 * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and 17110 * the new value for the alpha property is different from the old value 17111 */ 17112 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768435) 17113 boolean setAlphaNoInvalidation(float alpha) { 17114 ensureTransformationInfo(); 17115 if (mTransformationInfo.mAlpha != alpha) { 17116 setAlphaInternal(alpha); 17117 boolean subclassHandlesAlpha = onSetAlpha((int) (alpha * 255)); 17118 if (subclassHandlesAlpha) { 17119 mPrivateFlags |= PFLAG_ALPHA_SET; 17120 return true; 17121 } else { 17122 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17123 mRenderNode.setAlpha(getFinalAlpha()); 17124 } 17125 } 17126 return false; 17127 } 17128 17129 void setAlphaInternal(float alpha) { 17130 float oldAlpha = mTransformationInfo.mAlpha; 17131 mTransformationInfo.mAlpha = alpha; 17132 // Report visibility changes, which can affect children, to accessibility 17133 if ((alpha == 0) ^ (oldAlpha == 0)) { 17134 notifySubtreeAccessibilityStateChangedIfNeeded(); 17135 } 17136 } 17137 17138 /** 17139 * This property is intended only for use by the Fade transition, which animates it 17140 * to produce a visual translucency that does not side-effect (or get affected by) 17141 * the real alpha property. This value is composited with the other alpha value 17142 * (and the AlphaAnimation value, when that is present) to produce a final visual 17143 * translucency result, which is what is passed into the DisplayList. 17144 */ 17145 public void setTransitionAlpha(float alpha) { 17146 ensureTransformationInfo(); 17147 if (mTransformationInfo.mTransitionAlpha != alpha) { 17148 mTransformationInfo.mTransitionAlpha = alpha; 17149 mPrivateFlags &= ~PFLAG_ALPHA_SET; 17150 invalidateViewProperty(true, false); 17151 mRenderNode.setAlpha(getFinalAlpha()); 17152 } 17153 } 17154 17155 /** 17156 * Calculates the visual alpha of this view, which is a combination of the actual 17157 * alpha value and the transitionAlpha value (if set). 17158 */ 17159 private float getFinalAlpha() { 17160 if (mTransformationInfo != null) { 17161 return mTransformationInfo.mAlpha * mTransformationInfo.mTransitionAlpha; 17162 } 17163 return 1; 17164 } 17165 17166 /** 17167 * This property is intended only for use by the Fade transition, which animates 17168 * it to produce a visual translucency that does not side-effect (or get affected 17169 * by) the real alpha property. This value is composited with the other alpha 17170 * value (and the AlphaAnimation value, when that is present) to produce a final 17171 * visual translucency result, which is what is passed into the DisplayList. 17172 */ 17173 @ViewDebug.ExportedProperty(category = "drawing") 17174 public float getTransitionAlpha() { 17175 return mTransformationInfo != null ? mTransformationInfo.mTransitionAlpha : 1; 17176 } 17177 17178 /** 17179 * Sets whether or not to allow force dark to apply to this view. 17180 * 17181 * Setting this to false will disable the auto-dark feature on everything this view 17182 * draws, including any descendants. 17183 * 17184 * Setting this to true will allow this view to be automatically made dark, however 17185 * a value of 'true' will not override any 'false' value in its parent chain nor will 17186 * it prevent any 'false' in any of its children. 17187 * 17188 * The default behavior of force dark is also influenced by the Theme's 17189 * {@link android.R.styleable#Theme_isLightTheme isLightTheme} attribute. 17190 * If a theme is isLightTheme="false", then force dark is globally disabled for that theme. 17191 * 17192 * @param allow Whether or not to allow force dark. 17193 */ 17194 public void setForceDarkAllowed(boolean allow) { 17195 if (mRenderNode.setForceDarkAllowed(allow)) { 17196 // Currently toggling force-dark requires a new display list push to apply 17197 // TODO: Make it not clobber the display list so this is just a damageSelf() instead 17198 invalidate(); 17199 } 17200 } 17201 17202 /** 17203 * See {@link #setForceDarkAllowed(boolean)} 17204 * 17205 * @return true if force dark is allowed (default), false if it is disabled 17206 */ 17207 @ViewDebug.ExportedProperty(category = "drawing") 17208 @InspectableProperty 17209 public boolean isForceDarkAllowed() { 17210 return mRenderNode.isForceDarkAllowed(); 17211 } 17212 17213 /** 17214 * Top position of this view relative to its parent. 17215 * 17216 * @return The top of this view, in pixels. 17217 */ 17218 @ViewDebug.CapturedViewProperty 17219 public final int getTop() { 17220 return mTop; 17221 } 17222 17223 /** 17224 * Sets the top position of this view relative to its parent. This method is meant to be called 17225 * by the layout system and should not generally be called otherwise, because the property 17226 * may be changed at any time by the layout. 17227 * 17228 * @param top The top of this view, in pixels. 17229 */ 17230 public final void setTop(int top) { 17231 if (top != mTop) { 17232 final boolean matrixIsIdentity = hasIdentityMatrix(); 17233 if (matrixIsIdentity) { 17234 if (mAttachInfo != null) { 17235 int minTop; 17236 int yLoc; 17237 if (top < mTop) { 17238 minTop = top; 17239 yLoc = top - mTop; 17240 } else { 17241 minTop = mTop; 17242 yLoc = 0; 17243 } 17244 invalidate(0, yLoc, mRight - mLeft, mBottom - minTop); 17245 } 17246 } else { 17247 // Double-invalidation is necessary to capture view's old and new areas 17248 invalidate(true); 17249 } 17250 17251 int width = mRight - mLeft; 17252 int oldHeight = mBottom - mTop; 17253 17254 mTop = top; 17255 mRenderNode.setTop(mTop); 17256 17257 sizeChange(width, mBottom - mTop, width, oldHeight); 17258 17259 if (!matrixIsIdentity) { 17260 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 17261 invalidate(true); 17262 } 17263 mBackgroundSizeChanged = true; 17264 mDefaultFocusHighlightSizeChanged = true; 17265 if (mForegroundInfo != null) { 17266 mForegroundInfo.mBoundsChanged = true; 17267 } 17268 invalidateParentIfNeeded(); 17269 } 17270 } 17271 17272 /** 17273 * Bottom position of this view relative to its parent. 17274 * 17275 * @return The bottom of this view, in pixels. 17276 */ 17277 @ViewDebug.CapturedViewProperty 17278 public final int getBottom() { 17279 return mBottom; 17280 } 17281 17282 /** 17283 * True if this view has changed since the last time being drawn. 17284 * 17285 * @return The dirty state of this view. 17286 */ 17287 public boolean isDirty() { 17288 return (mPrivateFlags & PFLAG_DIRTY_MASK) != 0; 17289 } 17290 17291 /** 17292 * Sets the bottom position of this view relative to its parent. This method is meant to be 17293 * called by the layout system and should not generally be called otherwise, because the 17294 * property may be changed at any time by the layout. 17295 * 17296 * @param bottom The bottom of this view, in pixels. 17297 */ 17298 public final void setBottom(int bottom) { 17299 if (bottom != mBottom) { 17300 final boolean matrixIsIdentity = hasIdentityMatrix(); 17301 if (matrixIsIdentity) { 17302 if (mAttachInfo != null) { 17303 int maxBottom; 17304 if (bottom < mBottom) { 17305 maxBottom = mBottom; 17306 } else { 17307 maxBottom = bottom; 17308 } 17309 invalidate(0, 0, mRight - mLeft, maxBottom - mTop); 17310 } 17311 } else { 17312 // Double-invalidation is necessary to capture view's old and new areas 17313 invalidate(true); 17314 } 17315 17316 int width = mRight - mLeft; 17317 int oldHeight = mBottom - mTop; 17318 17319 mBottom = bottom; 17320 mRenderNode.setBottom(mBottom); 17321 17322 sizeChange(width, mBottom - mTop, width, oldHeight); 17323 17324 if (!matrixIsIdentity) { 17325 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 17326 invalidate(true); 17327 } 17328 mBackgroundSizeChanged = true; 17329 mDefaultFocusHighlightSizeChanged = true; 17330 if (mForegroundInfo != null) { 17331 mForegroundInfo.mBoundsChanged = true; 17332 } 17333 invalidateParentIfNeeded(); 17334 } 17335 } 17336 17337 /** 17338 * Left position of this view relative to its parent. 17339 * 17340 * @return The left edge of this view, in pixels. 17341 */ 17342 @ViewDebug.CapturedViewProperty 17343 public final int getLeft() { 17344 return mLeft; 17345 } 17346 17347 /** 17348 * Sets the left position of this view relative to its parent. This method is meant to be called 17349 * by the layout system and should not generally be called otherwise, because the property 17350 * may be changed at any time by the layout. 17351 * 17352 * @param left The left of this view, in pixels. 17353 */ 17354 public final void setLeft(int left) { 17355 if (left != mLeft) { 17356 final boolean matrixIsIdentity = hasIdentityMatrix(); 17357 if (matrixIsIdentity) { 17358 if (mAttachInfo != null) { 17359 int minLeft; 17360 int xLoc; 17361 if (left < mLeft) { 17362 minLeft = left; 17363 xLoc = left - mLeft; 17364 } else { 17365 minLeft = mLeft; 17366 xLoc = 0; 17367 } 17368 invalidate(xLoc, 0, mRight - minLeft, mBottom - mTop); 17369 } 17370 } else { 17371 // Double-invalidation is necessary to capture view's old and new areas 17372 invalidate(true); 17373 } 17374 17375 int oldWidth = mRight - mLeft; 17376 int height = mBottom - mTop; 17377 17378 mLeft = left; 17379 mRenderNode.setLeft(left); 17380 17381 sizeChange(mRight - mLeft, height, oldWidth, height); 17382 17383 if (!matrixIsIdentity) { 17384 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 17385 invalidate(true); 17386 } 17387 mBackgroundSizeChanged = true; 17388 mDefaultFocusHighlightSizeChanged = true; 17389 if (mForegroundInfo != null) { 17390 mForegroundInfo.mBoundsChanged = true; 17391 } 17392 invalidateParentIfNeeded(); 17393 } 17394 } 17395 17396 /** 17397 * Right position of this view relative to its parent. 17398 * 17399 * @return The right edge of this view, in pixels. 17400 */ 17401 @ViewDebug.CapturedViewProperty 17402 public final int getRight() { 17403 return mRight; 17404 } 17405 17406 /** 17407 * Sets the right position of this view relative to its parent. This method is meant to be called 17408 * by the layout system and should not generally be called otherwise, because the property 17409 * may be changed at any time by the layout. 17410 * 17411 * @param right The right of this view, in pixels. 17412 */ 17413 public final void setRight(int right) { 17414 if (right != mRight) { 17415 final boolean matrixIsIdentity = hasIdentityMatrix(); 17416 if (matrixIsIdentity) { 17417 if (mAttachInfo != null) { 17418 int maxRight; 17419 if (right < mRight) { 17420 maxRight = mRight; 17421 } else { 17422 maxRight = right; 17423 } 17424 invalidate(0, 0, maxRight - mLeft, mBottom - mTop); 17425 } 17426 } else { 17427 // Double-invalidation is necessary to capture view's old and new areas 17428 invalidate(true); 17429 } 17430 17431 int oldWidth = mRight - mLeft; 17432 int height = mBottom - mTop; 17433 17434 mRight = right; 17435 mRenderNode.setRight(mRight); 17436 17437 sizeChange(mRight - mLeft, height, oldWidth, height); 17438 17439 if (!matrixIsIdentity) { 17440 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 17441 invalidate(true); 17442 } 17443 mBackgroundSizeChanged = true; 17444 mDefaultFocusHighlightSizeChanged = true; 17445 if (mForegroundInfo != null) { 17446 mForegroundInfo.mBoundsChanged = true; 17447 } 17448 invalidateParentIfNeeded(); 17449 } 17450 } 17451 17452 private static float sanitizeFloatPropertyValue(float value, String propertyName) { 17453 return sanitizeFloatPropertyValue(value, propertyName, -Float.MAX_VALUE, Float.MAX_VALUE); 17454 } 17455 17456 private static float sanitizeFloatPropertyValue(float value, String propertyName, 17457 float min, float max) { 17458 // The expected "nothing bad happened" path 17459 if (value >= min && value <= max) return value; 17460 17461 if (value < min || value == Float.NEGATIVE_INFINITY) { 17462 if (sThrowOnInvalidFloatProperties) { 17463 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 17464 + value + ", the value must be >= " + min); 17465 } 17466 return min; 17467 } 17468 17469 if (value > max || value == Float.POSITIVE_INFINITY) { 17470 if (sThrowOnInvalidFloatProperties) { 17471 throw new IllegalArgumentException("Cannot set '" + propertyName + "' to " 17472 + value + ", the value must be <= " + max); 17473 } 17474 return max; 17475 } 17476 17477 if (Float.isNaN(value)) { 17478 if (sThrowOnInvalidFloatProperties) { 17479 throw new IllegalArgumentException( 17480 "Cannot set '" + propertyName + "' to Float.NaN"); 17481 } 17482 return 0; // Unclear which direction this NaN went so... 0? 17483 } 17484 17485 // Shouldn't be possible to reach this. 17486 throw new IllegalStateException("How do you get here?? " + value); 17487 } 17488 17489 /** 17490 * The visual x position of this view, in pixels. This is equivalent to the 17491 * {@link #setTranslationX(float) translationX} property plus the current 17492 * {@link #getLeft() left} property. 17493 * 17494 * @return The visual x position of this view, in pixels. 17495 */ 17496 @ViewDebug.ExportedProperty(category = "drawing") 17497 public float getX() { 17498 return mLeft + getTranslationX(); 17499 } 17500 17501 /** 17502 * Sets the visual x position of this view, in pixels. This is equivalent to setting the 17503 * {@link #setTranslationX(float) translationX} property to be the difference between 17504 * the x value passed in and the current {@link #getLeft() left} property. 17505 * 17506 * @param x The visual x position of this view, in pixels. 17507 */ 17508 public void setX(float x) { 17509 setTranslationX(x - mLeft); 17510 } 17511 17512 /** 17513 * The visual y position of this view, in pixels. This is equivalent to the 17514 * {@link #setTranslationY(float) translationY} property plus the current 17515 * {@link #getTop() top} property. 17516 * 17517 * @return The visual y position of this view, in pixels. 17518 */ 17519 @ViewDebug.ExportedProperty(category = "drawing") 17520 public float getY() { 17521 return mTop + getTranslationY(); 17522 } 17523 17524 /** 17525 * Sets the visual y position of this view, in pixels. This is equivalent to setting the 17526 * {@link #setTranslationY(float) translationY} property to be the difference between 17527 * the y value passed in and the current {@link #getTop() top} property. 17528 * 17529 * @param y The visual y position of this view, in pixels. 17530 */ 17531 public void setY(float y) { 17532 setTranslationY(y - mTop); 17533 } 17534 17535 /** 17536 * The visual z position of this view, in pixels. This is equivalent to the 17537 * {@link #setTranslationZ(float) translationZ} property plus the current 17538 * {@link #getElevation() elevation} property. 17539 * 17540 * @return The visual z position of this view, in pixels. 17541 */ 17542 @ViewDebug.ExportedProperty(category = "drawing") 17543 public float getZ() { 17544 return getElevation() + getTranslationZ(); 17545 } 17546 17547 /** 17548 * Sets the visual z position of this view, in pixels. This is equivalent to setting the 17549 * {@link #setTranslationZ(float) translationZ} property to be the difference between 17550 * the z value passed in and the current {@link #getElevation() elevation} property. 17551 * 17552 * @param z The visual z position of this view, in pixels. 17553 */ 17554 public void setZ(float z) { 17555 setTranslationZ(z - getElevation()); 17556 } 17557 17558 /** 17559 * The base elevation of this view relative to its parent, in pixels. 17560 * 17561 * @return The base depth position of the view, in pixels. 17562 */ 17563 @ViewDebug.ExportedProperty(category = "drawing") 17564 @InspectableProperty 17565 public float getElevation() { 17566 return mRenderNode.getElevation(); 17567 } 17568 17569 /** 17570 * Sets the base elevation of this view, in pixels. 17571 * 17572 * @attr ref android.R.styleable#View_elevation 17573 */ 17574 public void setElevation(float elevation) { 17575 if (elevation != getElevation()) { 17576 elevation = sanitizeFloatPropertyValue(elevation, "elevation"); 17577 invalidateViewProperty(true, false); 17578 mRenderNode.setElevation(elevation); 17579 invalidateViewProperty(false, true); 17580 17581 invalidateParentIfNeededAndWasQuickRejected(); 17582 } 17583 } 17584 17585 /** 17586 * The horizontal location of this view relative to its {@link #getLeft() left} position. 17587 * This position is post-layout, in addition to wherever the object's 17588 * layout placed it. 17589 * 17590 * @return The horizontal position of this view relative to its left position, in pixels. 17591 */ 17592 @ViewDebug.ExportedProperty(category = "drawing") 17593 @InspectableProperty 17594 public float getTranslationX() { 17595 return mRenderNode.getTranslationX(); 17596 } 17597 17598 /** 17599 * Sets the horizontal location of this view relative to its {@link #getLeft() left} position. 17600 * This effectively positions the object post-layout, in addition to wherever the object's 17601 * layout placed it. 17602 * 17603 * @param translationX The horizontal position of this view relative to its left position, 17604 * in pixels. 17605 * 17606 * @attr ref android.R.styleable#View_translationX 17607 */ 17608 public void setTranslationX(float translationX) { 17609 if (translationX != getTranslationX()) { 17610 invalidateViewProperty(true, false); 17611 mRenderNode.setTranslationX(translationX); 17612 invalidateViewProperty(false, true); 17613 17614 invalidateParentIfNeededAndWasQuickRejected(); 17615 notifySubtreeAccessibilityStateChangedIfNeeded(); 17616 } 17617 } 17618 17619 /** 17620 * The vertical location of this view relative to its {@link #getTop() top} position. 17621 * This position is post-layout, in addition to wherever the object's 17622 * layout placed it. 17623 * 17624 * @return The vertical position of this view relative to its top position, 17625 * in pixels. 17626 */ 17627 @ViewDebug.ExportedProperty(category = "drawing") 17628 @InspectableProperty 17629 public float getTranslationY() { 17630 return mRenderNode.getTranslationY(); 17631 } 17632 17633 /** 17634 * Sets the vertical location of this view relative to its {@link #getTop() top} position. 17635 * This effectively positions the object post-layout, in addition to wherever the object's 17636 * layout placed it. 17637 * 17638 * @param translationY The vertical position of this view relative to its top position, 17639 * in pixels. 17640 * 17641 * @attr ref android.R.styleable#View_translationY 17642 */ 17643 public void setTranslationY(float translationY) { 17644 if (translationY != getTranslationY()) { 17645 invalidateViewProperty(true, false); 17646 mRenderNode.setTranslationY(translationY); 17647 invalidateViewProperty(false, true); 17648 17649 invalidateParentIfNeededAndWasQuickRejected(); 17650 notifySubtreeAccessibilityStateChangedIfNeeded(); 17651 } 17652 } 17653 17654 /** 17655 * The depth location of this view relative to its {@link #getElevation() elevation}. 17656 * 17657 * @return The depth of this view relative to its elevation. 17658 */ 17659 @ViewDebug.ExportedProperty(category = "drawing") 17660 @InspectableProperty 17661 public float getTranslationZ() { 17662 return mRenderNode.getTranslationZ(); 17663 } 17664 17665 /** 17666 * Sets the depth location of this view relative to its {@link #getElevation() elevation}. 17667 * 17668 * @attr ref android.R.styleable#View_translationZ 17669 */ 17670 public void setTranslationZ(float translationZ) { 17671 if (translationZ != getTranslationZ()) { 17672 translationZ = sanitizeFloatPropertyValue(translationZ, "translationZ"); 17673 invalidateViewProperty(true, false); 17674 mRenderNode.setTranslationZ(translationZ); 17675 invalidateViewProperty(false, true); 17676 17677 invalidateParentIfNeededAndWasQuickRejected(); 17678 } 17679 } 17680 17681 /** 17682 * Changes the transformation matrix on the view. This is used in animation frameworks, 17683 * such as {@link android.transition.Transition}. When the animation finishes, the matrix 17684 * should be cleared by calling this method with <code>null</code> as the matrix parameter. 17685 * Application developers should use transformation methods like {@link #setRotation(float)}, 17686 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 17687 * and {@link #setTranslationY(float)} (float)}} instead. 17688 * 17689 * @param matrix The matrix, null indicates that the matrix should be cleared. 17690 * @see #getAnimationMatrix() 17691 */ 17692 public void setAnimationMatrix(@Nullable Matrix matrix) { 17693 invalidateViewProperty(true, false); 17694 mRenderNode.setAnimationMatrix(matrix); 17695 invalidateViewProperty(false, true); 17696 17697 invalidateParentIfNeededAndWasQuickRejected(); 17698 } 17699 17700 /** 17701 * Return the current transformation matrix of the view. This is used in animation frameworks, 17702 * such as {@link android.transition.Transition}. Returns <code>null</code> when there is no 17703 * transformation provided by {@link #setAnimationMatrix(Matrix)}. 17704 * Application developers should use transformation methods like {@link #setRotation(float)}, 17705 * {@link #setScaleX(float)}, {@link #setScaleX(float)}, {@link #setTranslationX(float)}} 17706 * and {@link #setTranslationY(float)} (float)}} instead. 17707 * 17708 * @return the Matrix, null indicates there is no transformation 17709 * @see #setAnimationMatrix(Matrix) 17710 */ 17711 @Nullable 17712 public Matrix getAnimationMatrix() { 17713 return mRenderNode.getAnimationMatrix(); 17714 } 17715 17716 /** 17717 * Returns the current StateListAnimator if exists. 17718 * 17719 * @return StateListAnimator or null if it does not exists 17720 * @see #setStateListAnimator(android.animation.StateListAnimator) 17721 */ 17722 @InspectableProperty 17723 public StateListAnimator getStateListAnimator() { 17724 return mStateListAnimator; 17725 } 17726 17727 /** 17728 * Attaches the provided StateListAnimator to this View. 17729 * <p> 17730 * Any previously attached StateListAnimator will be detached. 17731 * 17732 * @param stateListAnimator The StateListAnimator to update the view 17733 * @see android.animation.StateListAnimator 17734 */ 17735 public void setStateListAnimator(StateListAnimator stateListAnimator) { 17736 if (mStateListAnimator == stateListAnimator) { 17737 return; 17738 } 17739 if (mStateListAnimator != null) { 17740 mStateListAnimator.setTarget(null); 17741 } 17742 mStateListAnimator = stateListAnimator; 17743 if (stateListAnimator != null) { 17744 stateListAnimator.setTarget(this); 17745 if (isAttachedToWindow()) { 17746 stateListAnimator.setState(getDrawableState()); 17747 } 17748 } 17749 } 17750 17751 /** 17752 * Returns whether the Outline should be used to clip the contents of the View. 17753 * <p> 17754 * Note that this flag will only be respected if the View's Outline returns true from 17755 * {@link Outline#canClip()}. 17756 * 17757 * @see #setOutlineProvider(ViewOutlineProvider) 17758 * @see #setClipToOutline(boolean) 17759 */ 17760 public final boolean getClipToOutline() { 17761 return mRenderNode.getClipToOutline(); 17762 } 17763 17764 /** 17765 * Sets whether the View's Outline should be used to clip the contents of the View. 17766 * <p> 17767 * Only a single non-rectangular clip can be applied on a View at any time. 17768 * Circular clips from a {@link ViewAnimationUtils#createCircularReveal(View, int, int, float, float) 17769 * circular reveal} animation take priority over Outline clipping, and 17770 * child Outline clipping takes priority over Outline clipping done by a 17771 * parent. 17772 * <p> 17773 * Note that this flag will only be respected if the View's Outline returns true from 17774 * {@link Outline#canClip()}. 17775 * 17776 * @see #setOutlineProvider(ViewOutlineProvider) 17777 * @see #getClipToOutline() 17778 */ 17779 public void setClipToOutline(boolean clipToOutline) { 17780 damageInParent(); 17781 if (getClipToOutline() != clipToOutline) { 17782 mRenderNode.setClipToOutline(clipToOutline); 17783 } 17784 } 17785 17786 // correspond to the enum values of View_outlineProvider 17787 private static final int PROVIDER_BACKGROUND = 0; 17788 private static final int PROVIDER_NONE = 1; 17789 private static final int PROVIDER_BOUNDS = 2; 17790 private static final int PROVIDER_PADDED_BOUNDS = 3; setOutlineProviderFromAttribute(int providerInt)17791 private void setOutlineProviderFromAttribute(int providerInt) { 17792 switch (providerInt) { 17793 case PROVIDER_BACKGROUND: 17794 setOutlineProvider(ViewOutlineProvider.BACKGROUND); 17795 break; 17796 case PROVIDER_NONE: 17797 setOutlineProvider(null); 17798 break; 17799 case PROVIDER_BOUNDS: 17800 setOutlineProvider(ViewOutlineProvider.BOUNDS); 17801 break; 17802 case PROVIDER_PADDED_BOUNDS: 17803 setOutlineProvider(ViewOutlineProvider.PADDED_BOUNDS); 17804 break; 17805 } 17806 } 17807 17808 /** 17809 * Sets the {@link ViewOutlineProvider} of the view, which generates the Outline that defines 17810 * the shape of the shadow it casts, and enables outline clipping. 17811 * <p> 17812 * The default ViewOutlineProvider, {@link ViewOutlineProvider#BACKGROUND}, queries the Outline 17813 * from the View's background drawable, via {@link Drawable#getOutline(Outline)}. Changing the 17814 * outline provider with this method allows this behavior to be overridden. 17815 * <p> 17816 * If the ViewOutlineProvider is null, if querying it for an outline returns false, 17817 * or if the produced Outline is {@link Outline#isEmpty()}, shadows will not be cast. 17818 * <p> 17819 * Only outlines that return true from {@link Outline#canClip()} may be used for clipping. 17820 * 17821 * @see #setClipToOutline(boolean) 17822 * @see #getClipToOutline() 17823 * @see #getOutlineProvider() 17824 */ setOutlineProvider(ViewOutlineProvider provider)17825 public void setOutlineProvider(ViewOutlineProvider provider) { 17826 mOutlineProvider = provider; 17827 invalidateOutline(); 17828 } 17829 17830 /** 17831 * Returns the current {@link ViewOutlineProvider} of the view, which generates the Outline 17832 * that defines the shape of the shadow it casts, and enables outline clipping. 17833 * 17834 * @see #setOutlineProvider(ViewOutlineProvider) 17835 */ 17836 @InspectableProperty getOutlineProvider()17837 public ViewOutlineProvider getOutlineProvider() { 17838 return mOutlineProvider; 17839 } 17840 17841 /** 17842 * Called to rebuild this View's Outline from its {@link ViewOutlineProvider outline provider} 17843 * 17844 * @see #setOutlineProvider(ViewOutlineProvider) 17845 */ invalidateOutline()17846 public void invalidateOutline() { 17847 rebuildOutline(); 17848 17849 notifySubtreeAccessibilityStateChangedIfNeeded(); 17850 invalidateViewProperty(false, false); 17851 } 17852 17853 /** 17854 * Internal version of {@link #invalidateOutline()} which invalidates the 17855 * outline without invalidating the view itself. This is intended to be called from 17856 * within methods in the View class itself which are the result of the view being 17857 * invalidated already. For example, when we are drawing the background of a View, 17858 * we invalidate the outline in case it changed in the meantime, but we do not 17859 * need to invalidate the view because we're already drawing the background as part 17860 * of drawing the view in response to an earlier invalidation of the view. 17861 */ rebuildOutline()17862 private void rebuildOutline() { 17863 // Unattached views ignore this signal, and outline is recomputed in onAttachedToWindow() 17864 if (mAttachInfo == null) return; 17865 17866 if (mOutlineProvider == null) { 17867 // no provider, remove outline 17868 mRenderNode.setOutline(null); 17869 } else { 17870 final Outline outline = mAttachInfo.mTmpOutline; 17871 outline.setEmpty(); 17872 outline.setAlpha(1.0f); 17873 17874 mOutlineProvider.getOutline(this, outline); 17875 mRenderNode.setOutline(outline); 17876 } 17877 } 17878 17879 /** 17880 * HierarchyViewer only 17881 * 17882 * @hide 17883 */ 17884 @ViewDebug.ExportedProperty(category = "drawing") hasShadow()17885 public boolean hasShadow() { 17886 return mRenderNode.hasShadow(); 17887 } 17888 17889 /** 17890 * Sets the color of the spot shadow that is drawn when the view has a positive Z or 17891 * elevation value. 17892 * <p> 17893 * By default the shadow color is black. Generally, this color will be opaque so the intensity 17894 * of the shadow is consistent between different views with different colors. 17895 * <p> 17896 * The opacity of the final spot shadow is a function of the shadow caster height, the 17897 * alpha channel of the outlineSpotShadowColor (typically opaque), and the 17898 * {@link android.R.attr#spotShadowAlpha} theme attribute. 17899 * 17900 * @attr ref android.R.styleable#View_outlineSpotShadowColor 17901 * @param color The color this View will cast for its elevation spot shadow. 17902 */ setOutlineSpotShadowColor(@olorInt int color)17903 public void setOutlineSpotShadowColor(@ColorInt int color) { 17904 if (mRenderNode.setSpotShadowColor(color)) { 17905 invalidateViewProperty(true, true); 17906 } 17907 } 17908 17909 /** 17910 * @return The shadow color set by {@link #setOutlineSpotShadowColor(int)}, or black if nothing 17911 * was set 17912 */ 17913 @InspectableProperty getOutlineSpotShadowColor()17914 public @ColorInt int getOutlineSpotShadowColor() { 17915 return mRenderNode.getSpotShadowColor(); 17916 } 17917 17918 /** 17919 * Sets the color of the ambient shadow that is drawn when the view has a positive Z or 17920 * elevation value. 17921 * <p> 17922 * By default the shadow color is black. Generally, this color will be opaque so the intensity 17923 * of the shadow is consistent between different views with different colors. 17924 * <p> 17925 * The opacity of the final ambient shadow is a function of the shadow caster height, the 17926 * alpha channel of the outlineAmbientShadowColor (typically opaque), and the 17927 * {@link android.R.attr#ambientShadowAlpha} theme attribute. 17928 * 17929 * @attr ref android.R.styleable#View_outlineAmbientShadowColor 17930 * @param color The color this View will cast for its elevation shadow. 17931 */ setOutlineAmbientShadowColor(@olorInt int color)17932 public void setOutlineAmbientShadowColor(@ColorInt int color) { 17933 if (mRenderNode.setAmbientShadowColor(color)) { 17934 invalidateViewProperty(true, true); 17935 } 17936 } 17937 17938 /** 17939 * @return The shadow color set by {@link #setOutlineAmbientShadowColor(int)}, or black if 17940 * nothing was set 17941 */ 17942 @InspectableProperty getOutlineAmbientShadowColor()17943 public @ColorInt int getOutlineAmbientShadowColor() { 17944 return mRenderNode.getAmbientShadowColor(); 17945 } 17946 17947 17948 /** @hide */ setRevealClip(boolean shouldClip, float x, float y, float radius)17949 public void setRevealClip(boolean shouldClip, float x, float y, float radius) { 17950 mRenderNode.setRevealClip(shouldClip, x, y, radius); 17951 invalidateViewProperty(false, false); 17952 } 17953 17954 /** 17955 * Hit rectangle in parent's coordinates 17956 * 17957 * @param outRect The hit rectangle of the view. 17958 */ getHitRect(Rect outRect)17959 public void getHitRect(Rect outRect) { 17960 if (hasIdentityMatrix() || mAttachInfo == null) { 17961 outRect.set(mLeft, mTop, mRight, mBottom); 17962 } else { 17963 final RectF tmpRect = mAttachInfo.mTmpTransformRect; 17964 tmpRect.set(0, 0, getWidth(), getHeight()); 17965 getMatrix().mapRect(tmpRect); // TODO: mRenderNode.mapRect(tmpRect) 17966 outRect.set((int) tmpRect.left + mLeft, (int) tmpRect.top + mTop, 17967 (int) tmpRect.right + mLeft, (int) tmpRect.bottom + mTop); 17968 } 17969 } 17970 17971 /** 17972 * Determines whether the given point, in local coordinates is inside the view. 17973 */ pointInView(float localX, float localY)17974 /*package*/ final boolean pointInView(float localX, float localY) { 17975 return pointInView(localX, localY, 0); 17976 } 17977 17978 /** 17979 * Utility method to determine whether the given point, in local coordinates, 17980 * is inside the view, where the area of the view is expanded by the slop factor. 17981 * This method is called while processing touch-move events to determine if the event 17982 * is still within the view. 17983 * 17984 * @hide 17985 */ 17986 @UnsupportedAppUsage pointInView(float localX, float localY, float slop)17987 public boolean pointInView(float localX, float localY, float slop) { 17988 return localX >= -slop && localY >= -slop && localX < ((mRight - mLeft) + slop) && 17989 localY < ((mBottom - mTop) + slop); 17990 } 17991 17992 /** 17993 * When a view has focus and the user navigates away from it, the next view is searched for 17994 * starting from the rectangle filled in by this method. 17995 * 17996 * By default, the rectangle is the {@link #getDrawingRect(android.graphics.Rect)}) 17997 * of the view. However, if your view maintains some idea of internal selection, 17998 * such as a cursor, or a selected row or column, you should override this method and 17999 * fill in a more specific rectangle. 18000 * 18001 * @param r The rectangle to fill in, in this view's coordinates. 18002 */ getFocusedRect(Rect r)18003 public void getFocusedRect(Rect r) { 18004 getDrawingRect(r); 18005 } 18006 18007 /** 18008 * If some part of this view is not clipped by any of its parents, then 18009 * return that area in r in global (root) coordinates. To convert r to local 18010 * coordinates (without taking possible View rotations into account), offset 18011 * it by -globalOffset (e.g. r.offset(-globalOffset.x, -globalOffset.y)). 18012 * If the view is completely clipped or translated out, return false. 18013 * 18014 * @param r If true is returned, r holds the global coordinates of the 18015 * visible portion of this view. 18016 * @param globalOffset If true is returned, globalOffset holds the dx,dy 18017 * between this view and its root. globalOffet may be null. 18018 * @return true if r is non-empty (i.e. part of the view is visible at the 18019 * root level. 18020 */ getGlobalVisibleRect(Rect r, Point globalOffset)18021 public boolean getGlobalVisibleRect(Rect r, Point globalOffset) { 18022 int width = mRight - mLeft; 18023 int height = mBottom - mTop; 18024 if (width > 0 && height > 0) { 18025 r.set(0, 0, width, height); 18026 if (globalOffset != null) { 18027 globalOffset.set(-mScrollX, -mScrollY); 18028 } 18029 return mParent == null || mParent.getChildVisibleRect(this, r, globalOffset); 18030 } 18031 return false; 18032 } 18033 getGlobalVisibleRect(Rect r)18034 public final boolean getGlobalVisibleRect(Rect r) { 18035 return getGlobalVisibleRect(r, null); 18036 } 18037 getLocalVisibleRect(Rect r)18038 public final boolean getLocalVisibleRect(Rect r) { 18039 final Point offset = mAttachInfo != null ? mAttachInfo.mPoint : new Point(); 18040 if (getGlobalVisibleRect(r, offset)) { 18041 r.offset(-offset.x, -offset.y); // make r local 18042 return true; 18043 } 18044 return false; 18045 } 18046 18047 /** 18048 * Offset this view's vertical location by the specified number of pixels. 18049 * 18050 * @param offset the number of pixels to offset the view by 18051 */ offsetTopAndBottom(int offset)18052 public void offsetTopAndBottom(int offset) { 18053 if (offset != 0) { 18054 final boolean matrixIsIdentity = hasIdentityMatrix(); 18055 if (matrixIsIdentity) { 18056 if (isHardwareAccelerated()) { 18057 invalidateViewProperty(false, false); 18058 } else { 18059 final ViewParent p = mParent; 18060 if (p != null && mAttachInfo != null) { 18061 final Rect r = mAttachInfo.mTmpInvalRect; 18062 int minTop; 18063 int maxBottom; 18064 int yLoc; 18065 if (offset < 0) { 18066 minTop = mTop + offset; 18067 maxBottom = mBottom; 18068 yLoc = offset; 18069 } else { 18070 minTop = mTop; 18071 maxBottom = mBottom + offset; 18072 yLoc = 0; 18073 } 18074 r.set(0, yLoc, mRight - mLeft, maxBottom - minTop); 18075 p.invalidateChild(this, r); 18076 } 18077 } 18078 } else { 18079 invalidateViewProperty(false, false); 18080 } 18081 18082 mTop += offset; 18083 mBottom += offset; 18084 mRenderNode.offsetTopAndBottom(offset); 18085 if (isHardwareAccelerated()) { 18086 invalidateViewProperty(false, false); 18087 invalidateParentIfNeededAndWasQuickRejected(); 18088 } else { 18089 if (!matrixIsIdentity) { 18090 invalidateViewProperty(false, true); 18091 } 18092 invalidateParentIfNeeded(); 18093 } 18094 notifySubtreeAccessibilityStateChangedIfNeeded(); 18095 } 18096 } 18097 18098 /** 18099 * Offset this view's horizontal location by the specified amount of pixels. 18100 * 18101 * @param offset the number of pixels to offset the view by 18102 */ offsetLeftAndRight(int offset)18103 public void offsetLeftAndRight(int offset) { 18104 if (offset != 0) { 18105 final boolean matrixIsIdentity = hasIdentityMatrix(); 18106 if (matrixIsIdentity) { 18107 if (isHardwareAccelerated()) { 18108 invalidateViewProperty(false, false); 18109 } else { 18110 final ViewParent p = mParent; 18111 if (p != null && mAttachInfo != null) { 18112 final Rect r = mAttachInfo.mTmpInvalRect; 18113 int minLeft; 18114 int maxRight; 18115 if (offset < 0) { 18116 minLeft = mLeft + offset; 18117 maxRight = mRight; 18118 } else { 18119 minLeft = mLeft; 18120 maxRight = mRight + offset; 18121 } 18122 r.set(0, 0, maxRight - minLeft, mBottom - mTop); 18123 p.invalidateChild(this, r); 18124 } 18125 } 18126 } else { 18127 invalidateViewProperty(false, false); 18128 } 18129 18130 mLeft += offset; 18131 mRight += offset; 18132 mRenderNode.offsetLeftAndRight(offset); 18133 if (isHardwareAccelerated()) { 18134 invalidateViewProperty(false, false); 18135 invalidateParentIfNeededAndWasQuickRejected(); 18136 } else { 18137 if (!matrixIsIdentity) { 18138 invalidateViewProperty(false, true); 18139 } 18140 invalidateParentIfNeeded(); 18141 } 18142 notifySubtreeAccessibilityStateChangedIfNeeded(); 18143 } 18144 } 18145 18146 /** 18147 * Get the LayoutParams associated with this view. All views should have 18148 * layout parameters. These supply parameters to the <i>parent</i> of this 18149 * view specifying how it should be arranged. There are many subclasses of 18150 * ViewGroup.LayoutParams, and these correspond to the different subclasses 18151 * of ViewGroup that are responsible for arranging their children. 18152 * 18153 * This method may return null if this View is not attached to a parent 18154 * ViewGroup or {@link #setLayoutParams(android.view.ViewGroup.LayoutParams)} 18155 * was not invoked successfully. When a View is attached to a parent 18156 * ViewGroup, this method must not return null. 18157 * 18158 * @return The LayoutParams associated with this view, or null if no 18159 * parameters have been set yet 18160 */ 18161 @ViewDebug.ExportedProperty(deepExport = true, prefix = "layout_") getLayoutParams()18162 public ViewGroup.LayoutParams getLayoutParams() { 18163 return mLayoutParams; 18164 } 18165 18166 /** 18167 * Set the layout parameters associated with this view. These supply 18168 * parameters to the <i>parent</i> of this view specifying how it should be 18169 * arranged. There are many subclasses of ViewGroup.LayoutParams, and these 18170 * correspond to the different subclasses of ViewGroup that are responsible 18171 * for arranging their children. 18172 * 18173 * @param params The layout parameters for this view, cannot be null 18174 */ setLayoutParams(ViewGroup.LayoutParams params)18175 public void setLayoutParams(ViewGroup.LayoutParams params) { 18176 if (params == null) { 18177 throw new NullPointerException("Layout parameters cannot be null"); 18178 } 18179 mLayoutParams = params; 18180 resolveLayoutParams(); 18181 if (mParent instanceof ViewGroup) { 18182 ((ViewGroup) mParent).onSetLayoutParams(this, params); 18183 } 18184 requestLayout(); 18185 } 18186 18187 /** 18188 * Resolve the layout parameters depending on the resolved layout direction 18189 * 18190 * @hide 18191 */ resolveLayoutParams()18192 public void resolveLayoutParams() { 18193 if (mLayoutParams != null) { 18194 mLayoutParams.resolveLayoutDirection(getLayoutDirection()); 18195 } 18196 } 18197 18198 /** 18199 * Set the scrolled position of your view. This will cause a call to 18200 * {@link #onScrollChanged(int, int, int, int)} and the view will be 18201 * invalidated. 18202 * @param x the x position to scroll to 18203 * @param y the y position to scroll to 18204 */ scrollTo(int x, int y)18205 public void scrollTo(int x, int y) { 18206 if (mScrollX != x || mScrollY != y) { 18207 int oldX = mScrollX; 18208 int oldY = mScrollY; 18209 mScrollX = x; 18210 mScrollY = y; 18211 invalidateParentCaches(); 18212 onScrollChanged(mScrollX, mScrollY, oldX, oldY); 18213 if (!awakenScrollBars()) { 18214 postInvalidateOnAnimation(); 18215 } 18216 } 18217 } 18218 18219 /** 18220 * Move the scrolled position of your view. This will cause a call to 18221 * {@link #onScrollChanged(int, int, int, int)} and the view will be 18222 * invalidated. 18223 * @param x the amount of pixels to scroll by horizontally 18224 * @param y the amount of pixels to scroll by vertically 18225 */ scrollBy(int x, int y)18226 public void scrollBy(int x, int y) { 18227 scrollTo(mScrollX + x, mScrollY + y); 18228 } 18229 18230 /** 18231 * <p>Trigger the scrollbars to draw. When invoked this method starts an 18232 * animation to fade the scrollbars out after a default delay. If a subclass 18233 * provides animated scrolling, the start delay should equal the duration 18234 * of the scrolling animation.</p> 18235 * 18236 * <p>The animation starts only if at least one of the scrollbars is 18237 * enabled, as specified by {@link #isHorizontalScrollBarEnabled()} and 18238 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 18239 * this method returns true, and false otherwise. If the animation is 18240 * started, this method calls {@link #invalidate()}; in that case the 18241 * caller should not call {@link #invalidate()}.</p> 18242 * 18243 * <p>This method should be invoked every time a subclass directly updates 18244 * the scroll parameters.</p> 18245 * 18246 * <p>This method is automatically invoked by {@link #scrollBy(int, int)} 18247 * and {@link #scrollTo(int, int)}.</p> 18248 * 18249 * @return true if the animation is played, false otherwise 18250 * 18251 * @see #awakenScrollBars(int) 18252 * @see #scrollBy(int, int) 18253 * @see #scrollTo(int, int) 18254 * @see #isHorizontalScrollBarEnabled() 18255 * @see #isVerticalScrollBarEnabled() 18256 * @see #setHorizontalScrollBarEnabled(boolean) 18257 * @see #setVerticalScrollBarEnabled(boolean) 18258 */ awakenScrollBars()18259 protected boolean awakenScrollBars() { 18260 return mScrollCache != null && 18261 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true); 18262 } 18263 18264 /** 18265 * Trigger the scrollbars to draw. 18266 * This method differs from awakenScrollBars() only in its default duration. 18267 * initialAwakenScrollBars() will show the scroll bars for longer than 18268 * usual to give the user more of a chance to notice them. 18269 * 18270 * @return true if the animation is played, false otherwise. 18271 */ initialAwakenScrollBars()18272 private boolean initialAwakenScrollBars() { 18273 return mScrollCache != null && 18274 awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true); 18275 } 18276 18277 /** 18278 * <p> 18279 * Trigger the scrollbars to draw. When invoked this method starts an 18280 * animation to fade the scrollbars out after a fixed delay. If a subclass 18281 * provides animated scrolling, the start delay should equal the duration of 18282 * the scrolling animation. 18283 * </p> 18284 * 18285 * <p> 18286 * The animation starts only if at least one of the scrollbars is enabled, 18287 * as specified by {@link #isHorizontalScrollBarEnabled()} and 18288 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 18289 * this method returns true, and false otherwise. If the animation is 18290 * started, this method calls {@link #invalidate()}; in that case the caller 18291 * should not call {@link #invalidate()}. 18292 * </p> 18293 * 18294 * <p> 18295 * This method should be invoked every time a subclass directly updates the 18296 * scroll parameters. 18297 * </p> 18298 * 18299 * @param startDelay the delay, in milliseconds, after which the animation 18300 * should start; when the delay is 0, the animation starts 18301 * immediately 18302 * @return true if the animation is played, false otherwise 18303 * 18304 * @see #scrollBy(int, int) 18305 * @see #scrollTo(int, int) 18306 * @see #isHorizontalScrollBarEnabled() 18307 * @see #isVerticalScrollBarEnabled() 18308 * @see #setHorizontalScrollBarEnabled(boolean) 18309 * @see #setVerticalScrollBarEnabled(boolean) 18310 */ awakenScrollBars(int startDelay)18311 protected boolean awakenScrollBars(int startDelay) { 18312 return awakenScrollBars(startDelay, true); 18313 } 18314 18315 /** 18316 * <p> 18317 * Trigger the scrollbars to draw. When invoked this method starts an 18318 * animation to fade the scrollbars out after a fixed delay. If a subclass 18319 * provides animated scrolling, the start delay should equal the duration of 18320 * the scrolling animation. 18321 * </p> 18322 * 18323 * <p> 18324 * The animation starts only if at least one of the scrollbars is enabled, 18325 * as specified by {@link #isHorizontalScrollBarEnabled()} and 18326 * {@link #isVerticalScrollBarEnabled()}. When the animation is started, 18327 * this method returns true, and false otherwise. If the animation is 18328 * started, this method calls {@link #invalidate()} if the invalidate parameter 18329 * is set to true; in that case the caller 18330 * should not call {@link #invalidate()}. 18331 * </p> 18332 * 18333 * <p> 18334 * This method should be invoked every time a subclass directly updates the 18335 * scroll parameters. 18336 * </p> 18337 * 18338 * @param startDelay the delay, in milliseconds, after which the animation 18339 * should start; when the delay is 0, the animation starts 18340 * immediately 18341 * 18342 * @param invalidate Whether this method should call invalidate 18343 * 18344 * @return true if the animation is played, false otherwise 18345 * 18346 * @see #scrollBy(int, int) 18347 * @see #scrollTo(int, int) 18348 * @see #isHorizontalScrollBarEnabled() 18349 * @see #isVerticalScrollBarEnabled() 18350 * @see #setHorizontalScrollBarEnabled(boolean) 18351 * @see #setVerticalScrollBarEnabled(boolean) 18352 */ awakenScrollBars(int startDelay, boolean invalidate)18353 protected boolean awakenScrollBars(int startDelay, boolean invalidate) { 18354 final ScrollabilityCache scrollCache = mScrollCache; 18355 18356 if (scrollCache == null || !scrollCache.fadeScrollBars) { 18357 return false; 18358 } 18359 18360 if (scrollCache.scrollBar == null) { 18361 scrollCache.scrollBar = new ScrollBarDrawable(); 18362 scrollCache.scrollBar.setState(getDrawableState()); 18363 scrollCache.scrollBar.setCallback(this); 18364 } 18365 18366 if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) { 18367 18368 if (invalidate) { 18369 // Invalidate to show the scrollbars 18370 postInvalidateOnAnimation(); 18371 } 18372 18373 if (scrollCache.state == ScrollabilityCache.OFF) { 18374 // FIXME: this is copied from WindowManagerService. 18375 // We should get this value from the system when it 18376 // is possible to do so. 18377 final int KEY_REPEAT_FIRST_DELAY = 750; 18378 startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay); 18379 } 18380 18381 // Tell mScrollCache when we should start fading. This may 18382 // extend the fade start time if one was already scheduled 18383 long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay; 18384 scrollCache.fadeStartTime = fadeStartTime; 18385 scrollCache.state = ScrollabilityCache.ON; 18386 18387 // Schedule our fader to run, unscheduling any old ones first 18388 if (mAttachInfo != null) { 18389 mAttachInfo.mHandler.removeCallbacks(scrollCache); 18390 mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime); 18391 } 18392 18393 return true; 18394 } 18395 18396 return false; 18397 } 18398 18399 /** 18400 * Do not invalidate views which are not visible and which are not running an animation. They 18401 * will not get drawn and they should not set dirty flags as if they will be drawn 18402 */ skipInvalidate()18403 private boolean skipInvalidate() { 18404 return (mViewFlags & VISIBILITY_MASK) != VISIBLE && mCurrentAnimation == null && 18405 (!(mParent instanceof ViewGroup) || 18406 !((ViewGroup) mParent).isViewTransitioning(this)); 18407 } 18408 18409 /** 18410 * Mark the area defined by dirty as needing to be drawn. If the view is 18411 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 18412 * point in the future. 18413 * <p> 18414 * This must be called from a UI thread. To call from a non-UI thread, call 18415 * {@link #postInvalidate()}. 18416 * <p> 18417 * <b>WARNING:</b> In API 19 and below, this method may be destructive to 18418 * {@code dirty}. 18419 * 18420 * @param dirty the rectangle representing the bounds of the dirty region 18421 * 18422 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 18423 * the importance of the dirty rectangle. In API 21 the given rectangle is 18424 * ignored entirely in favor of an internally-calculated area instead. 18425 * Because of this, clients are encouraged to just call {@link #invalidate()}. 18426 */ 18427 @Deprecated invalidate(Rect dirty)18428 public void invalidate(Rect dirty) { 18429 final int scrollX = mScrollX; 18430 final int scrollY = mScrollY; 18431 invalidateInternal(dirty.left - scrollX, dirty.top - scrollY, 18432 dirty.right - scrollX, dirty.bottom - scrollY, true, false); 18433 } 18434 18435 /** 18436 * Mark the area defined by the rect (l,t,r,b) as needing to be drawn. The 18437 * coordinates of the dirty rect are relative to the view. If the view is 18438 * visible, {@link #onDraw(android.graphics.Canvas)} will be called at some 18439 * point in the future. 18440 * <p> 18441 * This must be called from a UI thread. To call from a non-UI thread, call 18442 * {@link #postInvalidate()}. 18443 * 18444 * @param l the left position of the dirty region 18445 * @param t the top position of the dirty region 18446 * @param r the right position of the dirty region 18447 * @param b the bottom position of the dirty region 18448 * 18449 * @deprecated The switch to hardware accelerated rendering in API 14 reduced 18450 * the importance of the dirty rectangle. In API 21 the given rectangle is 18451 * ignored entirely in favor of an internally-calculated area instead. 18452 * Because of this, clients are encouraged to just call {@link #invalidate()}. 18453 */ 18454 @Deprecated invalidate(int l, int t, int r, int b)18455 public void invalidate(int l, int t, int r, int b) { 18456 final int scrollX = mScrollX; 18457 final int scrollY = mScrollY; 18458 invalidateInternal(l - scrollX, t - scrollY, r - scrollX, b - scrollY, true, false); 18459 } 18460 18461 /** 18462 * Invalidate the whole view. If the view is visible, 18463 * {@link #onDraw(android.graphics.Canvas)} will be called at some point in 18464 * the future. 18465 * <p> 18466 * This must be called from a UI thread. To call from a non-UI thread, call 18467 * {@link #postInvalidate()}. 18468 */ invalidate()18469 public void invalidate() { 18470 invalidate(true); 18471 } 18472 18473 /** 18474 * This is where the invalidate() work actually happens. A full invalidate() 18475 * causes the drawing cache to be invalidated, but this function can be 18476 * called with invalidateCache set to false to skip that invalidation step 18477 * for cases that do not need it (for example, a component that remains at 18478 * the same dimensions with the same content). 18479 * 18480 * @param invalidateCache Whether the drawing cache for this view should be 18481 * invalidated as well. This is usually true for a full 18482 * invalidate, but may be set to false if the View's contents or 18483 * dimensions have not changed. 18484 * @hide 18485 */ 18486 @UnsupportedAppUsage invalidate(boolean invalidateCache)18487 public void invalidate(boolean invalidateCache) { 18488 invalidateInternal(0, 0, mRight - mLeft, mBottom - mTop, invalidateCache, true); 18489 } 18490 invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, boolean fullInvalidate)18491 void invalidateInternal(int l, int t, int r, int b, boolean invalidateCache, 18492 boolean fullInvalidate) { 18493 if (mGhostView != null) { 18494 mGhostView.invalidate(true); 18495 return; 18496 } 18497 18498 if (skipInvalidate()) { 18499 return; 18500 } 18501 18502 // Reset content capture caches 18503 mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK; 18504 mContentCaptureSessionCached = false; 18505 18506 if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) 18507 || (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) 18508 || (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED 18509 || (fullInvalidate && isOpaque() != mLastIsOpaque)) { 18510 if (fullInvalidate) { 18511 mLastIsOpaque = isOpaque(); 18512 mPrivateFlags &= ~PFLAG_DRAWN; 18513 } 18514 18515 mPrivateFlags |= PFLAG_DIRTY; 18516 18517 if (invalidateCache) { 18518 mPrivateFlags |= PFLAG_INVALIDATED; 18519 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 18520 } 18521 18522 // Propagate the damage rectangle to the parent view. 18523 final AttachInfo ai = mAttachInfo; 18524 final ViewParent p = mParent; 18525 if (p != null && ai != null && l < r && t < b) { 18526 final Rect damage = ai.mTmpInvalRect; 18527 damage.set(l, t, r, b); 18528 p.invalidateChild(this, damage); 18529 } 18530 18531 // Damage the entire projection receiver, if necessary. 18532 if (mBackground != null && mBackground.isProjected()) { 18533 final View receiver = getProjectionReceiver(); 18534 if (receiver != null) { 18535 receiver.damageInParent(); 18536 } 18537 } 18538 } 18539 } 18540 18541 /** 18542 * @return this view's projection receiver, or {@code null} if none exists 18543 */ getProjectionReceiver()18544 private View getProjectionReceiver() { 18545 ViewParent p = getParent(); 18546 while (p != null && p instanceof View) { 18547 final View v = (View) p; 18548 if (v.isProjectionReceiver()) { 18549 return v; 18550 } 18551 p = p.getParent(); 18552 } 18553 18554 return null; 18555 } 18556 18557 /** 18558 * @return whether the view is a projection receiver 18559 */ isProjectionReceiver()18560 private boolean isProjectionReceiver() { 18561 return mBackground != null; 18562 } 18563 18564 /** 18565 * Quick invalidation for View property changes (alpha, translationXY, etc.). We don't want to 18566 * set any flags or handle all of the cases handled by the default invalidation methods. 18567 * Instead, we just want to schedule a traversal in ViewRootImpl with the appropriate 18568 * dirty rect. This method calls into fast invalidation methods in ViewGroup that 18569 * walk up the hierarchy, transforming the dirty rect as necessary. 18570 * 18571 * The method also handles normal invalidation logic if display list properties are not 18572 * being used in this view. The invalidateParent and forceRedraw flags are used by that 18573 * backup approach, to handle these cases used in the various property-setting methods. 18574 * 18575 * @param invalidateParent Force a call to invalidateParentCaches() if display list properties 18576 * are not being used in this view 18577 * @param forceRedraw Mark the view as DRAWN to force the invalidation to propagate, if display 18578 * list properties are not being used in this view 18579 */ 18580 @UnsupportedAppUsage invalidateViewProperty(boolean invalidateParent, boolean forceRedraw)18581 void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) { 18582 if (!isHardwareAccelerated() 18583 || !mRenderNode.hasDisplayList() 18584 || (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) { 18585 if (invalidateParent) { 18586 invalidateParentCaches(); 18587 } 18588 if (forceRedraw) { 18589 mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation 18590 } 18591 invalidate(false); 18592 } else { 18593 damageInParent(); 18594 } 18595 } 18596 18597 /** 18598 * Tells the parent view to damage this view's bounds. 18599 * 18600 * @hide 18601 */ damageInParent()18602 protected void damageInParent() { 18603 if (mParent != null && mAttachInfo != null) { 18604 mParent.onDescendantInvalidated(this, this); 18605 } 18606 } 18607 18608 /** 18609 * Used to indicate that the parent of this view should clear its caches. This functionality 18610 * is used to force the parent to rebuild its display list (when hardware-accelerated), 18611 * which is necessary when various parent-managed properties of the view change, such as 18612 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method only 18613 * clears the parent caches and does not causes an invalidate event. 18614 * 18615 * @hide 18616 */ 18617 @UnsupportedAppUsage invalidateParentCaches()18618 protected void invalidateParentCaches() { 18619 if (mParent instanceof View) { 18620 ((View) mParent).mPrivateFlags |= PFLAG_INVALIDATED; 18621 } 18622 } 18623 18624 /** 18625 * Used to indicate that the parent of this view should be invalidated. This functionality 18626 * is used to force the parent to rebuild its display list (when hardware-accelerated), 18627 * which is necessary when various parent-managed properties of the view change, such as 18628 * alpha, translationX/Y, scrollX/Y, scaleX/Y, and rotation/X/Y. This method will propagate 18629 * an invalidation event to the parent. 18630 * 18631 * @hide 18632 */ 18633 @UnsupportedAppUsage invalidateParentIfNeeded()18634 protected void invalidateParentIfNeeded() { 18635 if (isHardwareAccelerated() && mParent instanceof View) { 18636 ((View) mParent).invalidate(true); 18637 } 18638 } 18639 18640 /** 18641 * @hide 18642 */ invalidateParentIfNeededAndWasQuickRejected()18643 protected void invalidateParentIfNeededAndWasQuickRejected() { 18644 if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) != 0) { 18645 // View was rejected last time it was drawn by its parent; this may have changed 18646 invalidateParentIfNeeded(); 18647 } 18648 } 18649 18650 /** 18651 * Indicates whether this View is opaque. An opaque View guarantees that it will 18652 * draw all the pixels overlapping its bounds using a fully opaque color. 18653 * 18654 * Subclasses of View should override this method whenever possible to indicate 18655 * whether an instance is opaque. Opaque Views are treated in a special way by 18656 * the View hierarchy, possibly allowing it to perform optimizations during 18657 * invalidate/draw passes. 18658 * 18659 * @return True if this View is guaranteed to be fully opaque, false otherwise. 18660 */ 18661 @ViewDebug.ExportedProperty(category = "drawing") isOpaque()18662 public boolean isOpaque() { 18663 return (mPrivateFlags & PFLAG_OPAQUE_MASK) == PFLAG_OPAQUE_MASK && 18664 getFinalAlpha() >= 1.0f; 18665 } 18666 18667 /** 18668 * @hide 18669 */ 18670 @UnsupportedAppUsage computeOpaqueFlags()18671 protected void computeOpaqueFlags() { 18672 // Opaque if: 18673 // - Has a background 18674 // - Background is opaque 18675 // - Doesn't have scrollbars or scrollbars overlay 18676 18677 if (mBackground != null && mBackground.getOpacity() == PixelFormat.OPAQUE) { 18678 mPrivateFlags |= PFLAG_OPAQUE_BACKGROUND; 18679 } else { 18680 mPrivateFlags &= ~PFLAG_OPAQUE_BACKGROUND; 18681 } 18682 18683 final int flags = mViewFlags; 18684 if (((flags & SCROLLBARS_VERTICAL) == 0 && (flags & SCROLLBARS_HORIZONTAL) == 0) || 18685 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_INSIDE_OVERLAY || 18686 (flags & SCROLLBARS_STYLE_MASK) == SCROLLBARS_OUTSIDE_OVERLAY) { 18687 mPrivateFlags |= PFLAG_OPAQUE_SCROLLBARS; 18688 } else { 18689 mPrivateFlags &= ~PFLAG_OPAQUE_SCROLLBARS; 18690 } 18691 } 18692 18693 /** 18694 * @hide 18695 */ hasOpaqueScrollbars()18696 protected boolean hasOpaqueScrollbars() { 18697 return (mPrivateFlags & PFLAG_OPAQUE_SCROLLBARS) == PFLAG_OPAQUE_SCROLLBARS; 18698 } 18699 18700 /** 18701 * @return A handler associated with the thread running the View. This 18702 * handler can be used to pump events in the UI events queue. 18703 */ getHandler()18704 public Handler getHandler() { 18705 final AttachInfo attachInfo = mAttachInfo; 18706 if (attachInfo != null) { 18707 return attachInfo.mHandler; 18708 } 18709 return null; 18710 } 18711 18712 /** 18713 * Returns the queue of runnable for this view. 18714 * 18715 * @return the queue of runnables for this view 18716 */ getRunQueue()18717 private HandlerActionQueue getRunQueue() { 18718 if (mRunQueue == null) { 18719 mRunQueue = new HandlerActionQueue(); 18720 } 18721 return mRunQueue; 18722 } 18723 18724 /** 18725 * Gets the view root associated with the View. 18726 * @return The view root, or null if none. 18727 * @hide 18728 */ 18729 @UnsupportedAppUsage getViewRootImpl()18730 public ViewRootImpl getViewRootImpl() { 18731 if (mAttachInfo != null) { 18732 return mAttachInfo.mViewRootImpl; 18733 } 18734 return null; 18735 } 18736 18737 /** 18738 * @hide 18739 */ 18740 @UnsupportedAppUsage getThreadedRenderer()18741 public ThreadedRenderer getThreadedRenderer() { 18742 return mAttachInfo != null ? mAttachInfo.mThreadedRenderer : null; 18743 } 18744 18745 /** 18746 * <p>Causes the Runnable to be added to the message queue. 18747 * The runnable will be run on the user interface thread.</p> 18748 * 18749 * @param action The Runnable that will be executed. 18750 * 18751 * @return Returns true if the Runnable was successfully placed in to the 18752 * message queue. Returns false on failure, usually because the 18753 * looper processing the message queue is exiting. 18754 * 18755 * @see #postDelayed 18756 * @see #removeCallbacks 18757 */ post(Runnable action)18758 public boolean post(Runnable action) { 18759 final AttachInfo attachInfo = mAttachInfo; 18760 if (attachInfo != null) { 18761 return attachInfo.mHandler.post(action); 18762 } 18763 18764 // Postpone the runnable until we know on which thread it needs to run. 18765 // Assume that the runnable will be successfully placed after attach. 18766 getRunQueue().post(action); 18767 return true; 18768 } 18769 18770 /** 18771 * <p>Causes the Runnable to be added to the message queue, to be run 18772 * after the specified amount of time elapses. 18773 * The runnable will be run on the user interface thread.</p> 18774 * 18775 * @param action The Runnable that will be executed. 18776 * @param delayMillis The delay (in milliseconds) until the Runnable 18777 * will be executed. 18778 * 18779 * @return true if the Runnable was successfully placed in to the 18780 * message queue. Returns false on failure, usually because the 18781 * looper processing the message queue is exiting. Note that a 18782 * result of true does not mean the Runnable will be processed -- 18783 * if the looper is quit before the delivery time of the message 18784 * occurs then the message will be dropped. 18785 * 18786 * @see #post 18787 * @see #removeCallbacks 18788 */ postDelayed(Runnable action, long delayMillis)18789 public boolean postDelayed(Runnable action, long delayMillis) { 18790 final AttachInfo attachInfo = mAttachInfo; 18791 if (attachInfo != null) { 18792 return attachInfo.mHandler.postDelayed(action, delayMillis); 18793 } 18794 18795 // Postpone the runnable until we know on which thread it needs to run. 18796 // Assume that the runnable will be successfully placed after attach. 18797 getRunQueue().postDelayed(action, delayMillis); 18798 return true; 18799 } 18800 18801 /** 18802 * <p>Causes the Runnable to execute on the next animation time step. 18803 * The runnable will be run on the user interface thread.</p> 18804 * 18805 * @param action The Runnable that will be executed. 18806 * 18807 * @see #postOnAnimationDelayed 18808 * @see #removeCallbacks 18809 */ postOnAnimation(Runnable action)18810 public void postOnAnimation(Runnable action) { 18811 final AttachInfo attachInfo = mAttachInfo; 18812 if (attachInfo != null) { 18813 attachInfo.mViewRootImpl.mChoreographer.postCallback( 18814 Choreographer.CALLBACK_ANIMATION, action, null); 18815 } else { 18816 // Postpone the runnable until we know 18817 // on which thread it needs to run. 18818 getRunQueue().post(action); 18819 } 18820 } 18821 18822 /** 18823 * <p>Causes the Runnable to execute on the next animation time step, 18824 * after the specified amount of time elapses. 18825 * The runnable will be run on the user interface thread.</p> 18826 * 18827 * @param action The Runnable that will be executed. 18828 * @param delayMillis The delay (in milliseconds) until the Runnable 18829 * will be executed. 18830 * 18831 * @see #postOnAnimation 18832 * @see #removeCallbacks 18833 */ postOnAnimationDelayed(Runnable action, long delayMillis)18834 public void postOnAnimationDelayed(Runnable action, long delayMillis) { 18835 final AttachInfo attachInfo = mAttachInfo; 18836 if (attachInfo != null) { 18837 attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 18838 Choreographer.CALLBACK_ANIMATION, action, null, delayMillis); 18839 } else { 18840 // Postpone the runnable until we know 18841 // on which thread it needs to run. 18842 getRunQueue().postDelayed(action, delayMillis); 18843 } 18844 } 18845 18846 /** 18847 * <p>Removes the specified Runnable from the message queue.</p> 18848 * 18849 * @param action The Runnable to remove from the message handling queue 18850 * 18851 * @return true if this view could ask the Handler to remove the Runnable, 18852 * false otherwise. When the returned value is true, the Runnable 18853 * may or may not have been actually removed from the message queue 18854 * (for instance, if the Runnable was not in the queue already.) 18855 * 18856 * @see #post 18857 * @see #postDelayed 18858 * @see #postOnAnimation 18859 * @see #postOnAnimationDelayed 18860 */ removeCallbacks(Runnable action)18861 public boolean removeCallbacks(Runnable action) { 18862 if (action != null) { 18863 final AttachInfo attachInfo = mAttachInfo; 18864 if (attachInfo != null) { 18865 attachInfo.mHandler.removeCallbacks(action); 18866 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 18867 Choreographer.CALLBACK_ANIMATION, action, null); 18868 } 18869 getRunQueue().removeCallbacks(action); 18870 } 18871 return true; 18872 } 18873 18874 /** 18875 * <p>Cause an invalidate to happen on a subsequent cycle through the event loop. 18876 * Use this to invalidate the View from a non-UI thread.</p> 18877 * 18878 * <p>This method can be invoked from outside of the UI thread 18879 * only when this View is attached to a window.</p> 18880 * 18881 * @see #invalidate() 18882 * @see #postInvalidateDelayed(long) 18883 */ postInvalidate()18884 public void postInvalidate() { 18885 postInvalidateDelayed(0); 18886 } 18887 18888 /** 18889 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 18890 * through the event loop. Use this to invalidate the View from a non-UI thread.</p> 18891 * 18892 * <p>This method can be invoked from outside of the UI thread 18893 * only when this View is attached to a window.</p> 18894 * 18895 * @param left The left coordinate of the rectangle to invalidate. 18896 * @param top The top coordinate of the rectangle to invalidate. 18897 * @param right The right coordinate of the rectangle to invalidate. 18898 * @param bottom The bottom coordinate of the rectangle to invalidate. 18899 * 18900 * @see #invalidate(int, int, int, int) 18901 * @see #invalidate(Rect) 18902 * @see #postInvalidateDelayed(long, int, int, int, int) 18903 */ postInvalidate(int left, int top, int right, int bottom)18904 public void postInvalidate(int left, int top, int right, int bottom) { 18905 postInvalidateDelayed(0, left, top, right, bottom); 18906 } 18907 18908 /** 18909 * <p>Cause an invalidate to happen on a subsequent cycle through the event 18910 * loop. Waits for the specified amount of time.</p> 18911 * 18912 * <p>This method can be invoked from outside of the UI thread 18913 * only when this View is attached to a window.</p> 18914 * 18915 * @param delayMilliseconds the duration in milliseconds to delay the 18916 * invalidation by 18917 * 18918 * @see #invalidate() 18919 * @see #postInvalidate() 18920 */ postInvalidateDelayed(long delayMilliseconds)18921 public void postInvalidateDelayed(long delayMilliseconds) { 18922 // We try only with the AttachInfo because there's no point in invalidating 18923 // if we are not attached to our window 18924 final AttachInfo attachInfo = mAttachInfo; 18925 if (attachInfo != null) { 18926 attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds); 18927 } 18928 } 18929 18930 /** 18931 * <p>Cause an invalidate of the specified area to happen on a subsequent cycle 18932 * through the event loop. Waits for the specified amount of time.</p> 18933 * 18934 * <p>This method can be invoked from outside of the UI thread 18935 * only when this View is attached to a window.</p> 18936 * 18937 * @param delayMilliseconds the duration in milliseconds to delay the 18938 * invalidation by 18939 * @param left The left coordinate of the rectangle to invalidate. 18940 * @param top The top coordinate of the rectangle to invalidate. 18941 * @param right The right coordinate of the rectangle to invalidate. 18942 * @param bottom The bottom coordinate of the rectangle to invalidate. 18943 * 18944 * @see #invalidate(int, int, int, int) 18945 * @see #invalidate(Rect) 18946 * @see #postInvalidate(int, int, int, int) 18947 */ postInvalidateDelayed(long delayMilliseconds, int left, int top, int right, int bottom)18948 public void postInvalidateDelayed(long delayMilliseconds, int left, int top, 18949 int right, int bottom) { 18950 18951 // We try only with the AttachInfo because there's no point in invalidating 18952 // if we are not attached to our window 18953 final AttachInfo attachInfo = mAttachInfo; 18954 if (attachInfo != null) { 18955 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 18956 info.target = this; 18957 info.left = left; 18958 info.top = top; 18959 info.right = right; 18960 info.bottom = bottom; 18961 18962 attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds); 18963 } 18964 } 18965 18966 /** 18967 * <p>Cause an invalidate to happen on the next animation time step, typically the 18968 * next display frame.</p> 18969 * 18970 * <p>This method can be invoked from outside of the UI thread 18971 * only when this View is attached to a window.</p> 18972 * 18973 * @see #invalidate() 18974 */ postInvalidateOnAnimation()18975 public void postInvalidateOnAnimation() { 18976 // We try only with the AttachInfo because there's no point in invalidating 18977 // if we are not attached to our window 18978 final AttachInfo attachInfo = mAttachInfo; 18979 if (attachInfo != null) { 18980 attachInfo.mViewRootImpl.dispatchInvalidateOnAnimation(this); 18981 } 18982 } 18983 18984 /** 18985 * <p>Cause an invalidate of the specified area to happen on the next animation 18986 * time step, typically the next display frame.</p> 18987 * 18988 * <p>This method can be invoked from outside of the UI thread 18989 * only when this View is attached to a window.</p> 18990 * 18991 * @param left The left coordinate of the rectangle to invalidate. 18992 * @param top The top coordinate of the rectangle to invalidate. 18993 * @param right The right coordinate of the rectangle to invalidate. 18994 * @param bottom The bottom coordinate of the rectangle to invalidate. 18995 * 18996 * @see #invalidate(int, int, int, int) 18997 * @see #invalidate(Rect) 18998 */ postInvalidateOnAnimation(int left, int top, int right, int bottom)18999 public void postInvalidateOnAnimation(int left, int top, int right, int bottom) { 19000 // We try only with the AttachInfo because there's no point in invalidating 19001 // if we are not attached to our window 19002 final AttachInfo attachInfo = mAttachInfo; 19003 if (attachInfo != null) { 19004 final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.obtain(); 19005 info.target = this; 19006 info.left = left; 19007 info.top = top; 19008 info.right = right; 19009 info.bottom = bottom; 19010 19011 attachInfo.mViewRootImpl.dispatchInvalidateRectOnAnimation(info); 19012 } 19013 } 19014 19015 /** 19016 * Post a callback to send a {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event. 19017 * This event is sent at most once every 19018 * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval()}. 19019 */ postSendViewScrolledAccessibilityEventCallback(int dx, int dy)19020 private void postSendViewScrolledAccessibilityEventCallback(int dx, int dy) { 19021 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 19022 AccessibilityEvent event = 19023 AccessibilityEvent.obtain(AccessibilityEvent.TYPE_VIEW_SCROLLED); 19024 event.setScrollDeltaX(dx); 19025 event.setScrollDeltaY(dy); 19026 sendAccessibilityEventUnchecked(event); 19027 } 19028 } 19029 19030 /** 19031 * Called by a parent to request that a child update its values for mScrollX 19032 * and mScrollY if necessary. This will typically be done if the child is 19033 * animating a scroll using a {@link android.widget.Scroller Scroller} 19034 * object. 19035 */ computeScroll()19036 public void computeScroll() { 19037 } 19038 19039 /** 19040 * <p>Indicate whether the horizontal edges are faded when the view is 19041 * scrolled horizontally.</p> 19042 * 19043 * @return true if the horizontal edges should are faded on scroll, false 19044 * otherwise 19045 * 19046 * @see #setHorizontalFadingEdgeEnabled(boolean) 19047 * 19048 * @attr ref android.R.styleable#View_requiresFadingEdge 19049 */ isHorizontalFadingEdgeEnabled()19050 public boolean isHorizontalFadingEdgeEnabled() { 19051 return (mViewFlags & FADING_EDGE_HORIZONTAL) == FADING_EDGE_HORIZONTAL; 19052 } 19053 19054 /** 19055 * <p>Define whether the horizontal edges should be faded when this view 19056 * is scrolled horizontally.</p> 19057 * 19058 * @param horizontalFadingEdgeEnabled true if the horizontal edges should 19059 * be faded when the view is scrolled 19060 * horizontally 19061 * 19062 * @see #isHorizontalFadingEdgeEnabled() 19063 * 19064 * @attr ref android.R.styleable#View_requiresFadingEdge 19065 */ setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled)19066 public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) { 19067 if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) { 19068 if (horizontalFadingEdgeEnabled) { 19069 initScrollCache(); 19070 } 19071 19072 mViewFlags ^= FADING_EDGE_HORIZONTAL; 19073 } 19074 } 19075 19076 /** 19077 * <p>Indicate whether the vertical edges are faded when the view is 19078 * scrolled horizontally.</p> 19079 * 19080 * @return true if the vertical edges should are faded on scroll, false 19081 * otherwise 19082 * 19083 * @see #setVerticalFadingEdgeEnabled(boolean) 19084 * 19085 * @attr ref android.R.styleable#View_requiresFadingEdge 19086 */ isVerticalFadingEdgeEnabled()19087 public boolean isVerticalFadingEdgeEnabled() { 19088 return (mViewFlags & FADING_EDGE_VERTICAL) == FADING_EDGE_VERTICAL; 19089 } 19090 19091 /** 19092 * <p>Define whether the vertical edges should be faded when this view 19093 * is scrolled vertically.</p> 19094 * 19095 * @param verticalFadingEdgeEnabled true if the vertical edges should 19096 * be faded when the view is scrolled 19097 * vertically 19098 * 19099 * @see #isVerticalFadingEdgeEnabled() 19100 * 19101 * @attr ref android.R.styleable#View_requiresFadingEdge 19102 */ setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled)19103 public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) { 19104 if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) { 19105 if (verticalFadingEdgeEnabled) { 19106 initScrollCache(); 19107 } 19108 19109 mViewFlags ^= FADING_EDGE_VERTICAL; 19110 } 19111 } 19112 19113 /** 19114 * Get the fading edge flags, used for inspection. 19115 * 19116 * @return One of {@link #FADING_EDGE_NONE}, {@link #FADING_EDGE_VERTICAL}, 19117 * or {@link #FADING_EDGE_HORIZONTAL} 19118 * @hide 19119 */ 19120 @InspectableProperty(name = "requiresFadingEdge", flagMapping = { 19121 @FlagEntry(target = FADING_EDGE_NONE, mask = FADING_EDGE_MASK, name = "none"), 19122 @FlagEntry(target = FADING_EDGE_VERTICAL, name = "vertical"), 19123 @FlagEntry(target = FADING_EDGE_HORIZONTAL, name = "horizontal") 19124 }) getFadingEdge()19125 public int getFadingEdge() { 19126 return mViewFlags & FADING_EDGE_MASK; 19127 } 19128 19129 /** 19130 * Get the fading edge length, used for inspection 19131 * 19132 * @return The fading edge length or 0 19133 * @hide 19134 */ 19135 @InspectableProperty getFadingEdgeLength()19136 public int getFadingEdgeLength() { 19137 if (mScrollCache != null && (mViewFlags & FADING_EDGE_MASK) != FADING_EDGE_NONE) { 19138 return mScrollCache.fadingEdgeLength; 19139 } 19140 return 0; 19141 } 19142 19143 /** 19144 * Returns the strength, or intensity, of the top faded edge. The strength is 19145 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 19146 * returns 0.0 or 1.0 but no value in between. 19147 * 19148 * Subclasses should override this method to provide a smoother fade transition 19149 * when scrolling occurs. 19150 * 19151 * @return the intensity of the top fade as a float between 0.0f and 1.0f 19152 */ getTopFadingEdgeStrength()19153 protected float getTopFadingEdgeStrength() { 19154 return computeVerticalScrollOffset() > 0 ? 1.0f : 0.0f; 19155 } 19156 19157 /** 19158 * Returns the strength, or intensity, of the bottom faded edge. The strength is 19159 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 19160 * returns 0.0 or 1.0 but no value in between. 19161 * 19162 * Subclasses should override this method to provide a smoother fade transition 19163 * when scrolling occurs. 19164 * 19165 * @return the intensity of the bottom fade as a float between 0.0f and 1.0f 19166 */ getBottomFadingEdgeStrength()19167 protected float getBottomFadingEdgeStrength() { 19168 return computeVerticalScrollOffset() + computeVerticalScrollExtent() < 19169 computeVerticalScrollRange() ? 1.0f : 0.0f; 19170 } 19171 19172 /** 19173 * Returns the strength, or intensity, of the left faded edge. The strength is 19174 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 19175 * returns 0.0 or 1.0 but no value in between. 19176 * 19177 * Subclasses should override this method to provide a smoother fade transition 19178 * when scrolling occurs. 19179 * 19180 * @return the intensity of the left fade as a float between 0.0f and 1.0f 19181 */ getLeftFadingEdgeStrength()19182 protected float getLeftFadingEdgeStrength() { 19183 return computeHorizontalScrollOffset() > 0 ? 1.0f : 0.0f; 19184 } 19185 19186 /** 19187 * Returns the strength, or intensity, of the right faded edge. The strength is 19188 * a value between 0.0 (no fade) and 1.0 (full fade). The default implementation 19189 * returns 0.0 or 1.0 but no value in between. 19190 * 19191 * Subclasses should override this method to provide a smoother fade transition 19192 * when scrolling occurs. 19193 * 19194 * @return the intensity of the right fade as a float between 0.0f and 1.0f 19195 */ getRightFadingEdgeStrength()19196 protected float getRightFadingEdgeStrength() { 19197 return computeHorizontalScrollOffset() + computeHorizontalScrollExtent() < 19198 computeHorizontalScrollRange() ? 1.0f : 0.0f; 19199 } 19200 19201 /** 19202 * <p>Indicate whether the horizontal scrollbar should be drawn or not. The 19203 * scrollbar is not drawn by default.</p> 19204 * 19205 * @return true if the horizontal scrollbar should be painted, false 19206 * otherwise 19207 * 19208 * @see #setHorizontalScrollBarEnabled(boolean) 19209 */ isHorizontalScrollBarEnabled()19210 public boolean isHorizontalScrollBarEnabled() { 19211 return (mViewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL; 19212 } 19213 19214 /** 19215 * <p>Define whether the horizontal scrollbar should be drawn or not. The 19216 * scrollbar is not drawn by default.</p> 19217 * 19218 * @param horizontalScrollBarEnabled true if the horizontal scrollbar should 19219 * be painted 19220 * 19221 * @see #isHorizontalScrollBarEnabled() 19222 */ setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled)19223 public void setHorizontalScrollBarEnabled(boolean horizontalScrollBarEnabled) { 19224 if (isHorizontalScrollBarEnabled() != horizontalScrollBarEnabled) { 19225 mViewFlags ^= SCROLLBARS_HORIZONTAL; 19226 computeOpaqueFlags(); 19227 resolvePadding(); 19228 } 19229 } 19230 19231 /** 19232 * <p>Indicate whether the vertical scrollbar should be drawn or not. The 19233 * scrollbar is not drawn by default.</p> 19234 * 19235 * @return true if the vertical scrollbar should be painted, false 19236 * otherwise 19237 * 19238 * @see #setVerticalScrollBarEnabled(boolean) 19239 */ isVerticalScrollBarEnabled()19240 public boolean isVerticalScrollBarEnabled() { 19241 return (mViewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL; 19242 } 19243 19244 /** 19245 * <p>Define whether the vertical scrollbar should be drawn or not. The 19246 * scrollbar is not drawn by default.</p> 19247 * 19248 * @param verticalScrollBarEnabled true if the vertical scrollbar should 19249 * be painted 19250 * 19251 * @see #isVerticalScrollBarEnabled() 19252 */ setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled)19253 public void setVerticalScrollBarEnabled(boolean verticalScrollBarEnabled) { 19254 if (isVerticalScrollBarEnabled() != verticalScrollBarEnabled) { 19255 mViewFlags ^= SCROLLBARS_VERTICAL; 19256 computeOpaqueFlags(); 19257 resolvePadding(); 19258 } 19259 } 19260 19261 /** 19262 * @hide 19263 */ 19264 @UnsupportedAppUsage recomputePadding()19265 protected void recomputePadding() { 19266 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 19267 } 19268 19269 /** 19270 * Define whether scrollbars will fade when the view is not scrolling. 19271 * 19272 * @param fadeScrollbars whether to enable fading 19273 * 19274 * @attr ref android.R.styleable#View_fadeScrollbars 19275 */ setScrollbarFadingEnabled(boolean fadeScrollbars)19276 public void setScrollbarFadingEnabled(boolean fadeScrollbars) { 19277 initScrollCache(); 19278 final ScrollabilityCache scrollabilityCache = mScrollCache; 19279 scrollabilityCache.fadeScrollBars = fadeScrollbars; 19280 if (fadeScrollbars) { 19281 scrollabilityCache.state = ScrollabilityCache.OFF; 19282 } else { 19283 scrollabilityCache.state = ScrollabilityCache.ON; 19284 } 19285 } 19286 19287 /** 19288 * 19289 * Returns true if scrollbars will fade when this view is not scrolling 19290 * 19291 * @return true if scrollbar fading is enabled 19292 * 19293 * @attr ref android.R.styleable#View_fadeScrollbars 19294 */ isScrollbarFadingEnabled()19295 public boolean isScrollbarFadingEnabled() { 19296 return mScrollCache != null && mScrollCache.fadeScrollBars; 19297 } 19298 19299 /** 19300 * 19301 * Returns the delay before scrollbars fade. 19302 * 19303 * @return the delay before scrollbars fade 19304 * 19305 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 19306 */ 19307 @InspectableProperty(name = "scrollbarDefaultDelayBeforeFade") getScrollBarDefaultDelayBeforeFade()19308 public int getScrollBarDefaultDelayBeforeFade() { 19309 return mScrollCache == null ? ViewConfiguration.getScrollDefaultDelay() : 19310 mScrollCache.scrollBarDefaultDelayBeforeFade; 19311 } 19312 19313 /** 19314 * Define the delay before scrollbars fade. 19315 * 19316 * @param scrollBarDefaultDelayBeforeFade - the delay before scrollbars fade 19317 * 19318 * @attr ref android.R.styleable#View_scrollbarDefaultDelayBeforeFade 19319 */ setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade)19320 public void setScrollBarDefaultDelayBeforeFade(int scrollBarDefaultDelayBeforeFade) { 19321 getScrollCache().scrollBarDefaultDelayBeforeFade = scrollBarDefaultDelayBeforeFade; 19322 } 19323 19324 /** 19325 * 19326 * Returns the scrollbar fade duration. 19327 * 19328 * @return the scrollbar fade duration, in milliseconds 19329 * 19330 * @attr ref android.R.styleable#View_scrollbarFadeDuration 19331 */ 19332 @InspectableProperty(name = "scrollbarFadeDuration") getScrollBarFadeDuration()19333 public int getScrollBarFadeDuration() { 19334 return mScrollCache == null ? ViewConfiguration.getScrollBarFadeDuration() : 19335 mScrollCache.scrollBarFadeDuration; 19336 } 19337 19338 /** 19339 * Define the scrollbar fade duration. 19340 * 19341 * @param scrollBarFadeDuration - the scrollbar fade duration, in milliseconds 19342 * 19343 * @attr ref android.R.styleable#View_scrollbarFadeDuration 19344 */ setScrollBarFadeDuration(int scrollBarFadeDuration)19345 public void setScrollBarFadeDuration(int scrollBarFadeDuration) { 19346 getScrollCache().scrollBarFadeDuration = scrollBarFadeDuration; 19347 } 19348 19349 /** 19350 * 19351 * Returns the scrollbar size. 19352 * 19353 * @return the scrollbar size 19354 * 19355 * @attr ref android.R.styleable#View_scrollbarSize 19356 */ 19357 @InspectableProperty(name = "scrollbarSize") getScrollBarSize()19358 public int getScrollBarSize() { 19359 return mScrollCache == null ? ViewConfiguration.get(mContext).getScaledScrollBarSize() : 19360 mScrollCache.scrollBarSize; 19361 } 19362 19363 /** 19364 * Define the scrollbar size. 19365 * 19366 * @param scrollBarSize - the scrollbar size 19367 * 19368 * @attr ref android.R.styleable#View_scrollbarSize 19369 */ setScrollBarSize(int scrollBarSize)19370 public void setScrollBarSize(int scrollBarSize) { 19371 getScrollCache().scrollBarSize = scrollBarSize; 19372 } 19373 19374 /** 19375 * <p>Specify the style of the scrollbars. The scrollbars can be overlaid or 19376 * inset. When inset, they add to the padding of the view. And the scrollbars 19377 * can be drawn inside the padding area or on the edge of the view. For example, 19378 * if a view has a background drawable and you want to draw the scrollbars 19379 * inside the padding specified by the drawable, you can use 19380 * SCROLLBARS_INSIDE_OVERLAY or SCROLLBARS_INSIDE_INSET. If you want them to 19381 * appear at the edge of the view, ignoring the padding, then you can use 19382 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET.</p> 19383 * @param style the style of the scrollbars. Should be one of 19384 * SCROLLBARS_INSIDE_OVERLAY, SCROLLBARS_INSIDE_INSET, 19385 * SCROLLBARS_OUTSIDE_OVERLAY or SCROLLBARS_OUTSIDE_INSET. 19386 * @see #SCROLLBARS_INSIDE_OVERLAY 19387 * @see #SCROLLBARS_INSIDE_INSET 19388 * @see #SCROLLBARS_OUTSIDE_OVERLAY 19389 * @see #SCROLLBARS_OUTSIDE_INSET 19390 * 19391 * @attr ref android.R.styleable#View_scrollbarStyle 19392 */ setScrollBarStyle(@crollBarStyle int style)19393 public void setScrollBarStyle(@ScrollBarStyle int style) { 19394 if (style != (mViewFlags & SCROLLBARS_STYLE_MASK)) { 19395 mViewFlags = (mViewFlags & ~SCROLLBARS_STYLE_MASK) | (style & SCROLLBARS_STYLE_MASK); 19396 computeOpaqueFlags(); 19397 resolvePadding(); 19398 } 19399 } 19400 19401 /** 19402 * <p>Returns the current scrollbar style.</p> 19403 * @return the current scrollbar style 19404 * @see #SCROLLBARS_INSIDE_OVERLAY 19405 * @see #SCROLLBARS_INSIDE_INSET 19406 * @see #SCROLLBARS_OUTSIDE_OVERLAY 19407 * @see #SCROLLBARS_OUTSIDE_INSET 19408 * 19409 * @attr ref android.R.styleable#View_scrollbarStyle 19410 */ 19411 @ViewDebug.ExportedProperty(mapping = { 19412 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_OVERLAY, to = "INSIDE_OVERLAY"), 19413 @ViewDebug.IntToString(from = SCROLLBARS_INSIDE_INSET, to = "INSIDE_INSET"), 19414 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_OVERLAY, to = "OUTSIDE_OVERLAY"), 19415 @ViewDebug.IntToString(from = SCROLLBARS_OUTSIDE_INSET, to = "OUTSIDE_INSET") 19416 }) 19417 @InspectableProperty(name = "scrollbarStyle", enumMapping = { 19418 @EnumEntry(value = SCROLLBARS_INSIDE_OVERLAY, name = "insideOverlay"), 19419 @EnumEntry(value = SCROLLBARS_INSIDE_INSET, name = "insideInset"), 19420 @EnumEntry(value = SCROLLBARS_OUTSIDE_OVERLAY, name = "outsideOverlay"), 19421 @EnumEntry(value = SCROLLBARS_OUTSIDE_INSET, name = "outsideInset") 19422 }) 19423 @ScrollBarStyle getScrollBarStyle()19424 public int getScrollBarStyle() { 19425 return mViewFlags & SCROLLBARS_STYLE_MASK; 19426 } 19427 19428 /** 19429 * <p>Compute the horizontal range that the horizontal scrollbar 19430 * represents.</p> 19431 * 19432 * <p>The range is expressed in arbitrary units that must be the same as the 19433 * units used by {@link #computeHorizontalScrollExtent()} and 19434 * {@link #computeHorizontalScrollOffset()}.</p> 19435 * 19436 * <p>The default range is the drawing width of this view.</p> 19437 * 19438 * @return the total horizontal range represented by the horizontal 19439 * scrollbar 19440 * 19441 * @see #computeHorizontalScrollExtent() 19442 * @see #computeHorizontalScrollOffset() 19443 */ computeHorizontalScrollRange()19444 protected int computeHorizontalScrollRange() { 19445 return getWidth(); 19446 } 19447 19448 /** 19449 * <p>Compute the horizontal offset of the horizontal scrollbar's thumb 19450 * within the horizontal range. This value is used to compute the position 19451 * of the thumb within the scrollbar's track.</p> 19452 * 19453 * <p>The range is expressed in arbitrary units that must be the same as the 19454 * units used by {@link #computeHorizontalScrollRange()} and 19455 * {@link #computeHorizontalScrollExtent()}.</p> 19456 * 19457 * <p>The default offset is the scroll offset of this view.</p> 19458 * 19459 * @return the horizontal offset of the scrollbar's thumb 19460 * 19461 * @see #computeHorizontalScrollRange() 19462 * @see #computeHorizontalScrollExtent() 19463 */ computeHorizontalScrollOffset()19464 protected int computeHorizontalScrollOffset() { 19465 return mScrollX; 19466 } 19467 19468 /** 19469 * <p>Compute the horizontal extent of the horizontal scrollbar's thumb 19470 * within the horizontal range. This value is used to compute the length 19471 * of the thumb within the scrollbar's track.</p> 19472 * 19473 * <p>The range is expressed in arbitrary units that must be the same as the 19474 * units used by {@link #computeHorizontalScrollRange()} and 19475 * {@link #computeHorizontalScrollOffset()}.</p> 19476 * 19477 * <p>The default extent is the drawing width of this view.</p> 19478 * 19479 * @return the horizontal extent of the scrollbar's thumb 19480 * 19481 * @see #computeHorizontalScrollRange() 19482 * @see #computeHorizontalScrollOffset() 19483 */ computeHorizontalScrollExtent()19484 protected int computeHorizontalScrollExtent() { 19485 return getWidth(); 19486 } 19487 19488 /** 19489 * <p>Compute the vertical range that the vertical scrollbar represents.</p> 19490 * 19491 * <p>The range is expressed in arbitrary units that must be the same as the 19492 * units used by {@link #computeVerticalScrollExtent()} and 19493 * {@link #computeVerticalScrollOffset()}.</p> 19494 * 19495 * @return the total vertical range represented by the vertical scrollbar 19496 * 19497 * <p>The default range is the drawing height of this view.</p> 19498 * 19499 * @see #computeVerticalScrollExtent() 19500 * @see #computeVerticalScrollOffset() 19501 */ computeVerticalScrollRange()19502 protected int computeVerticalScrollRange() { 19503 return getHeight(); 19504 } 19505 19506 /** 19507 * <p>Compute the vertical offset of the vertical scrollbar's thumb 19508 * within the horizontal range. This value is used to compute the position 19509 * of the thumb within the scrollbar's track.</p> 19510 * 19511 * <p>The range is expressed in arbitrary units that must be the same as the 19512 * units used by {@link #computeVerticalScrollRange()} and 19513 * {@link #computeVerticalScrollExtent()}.</p> 19514 * 19515 * <p>The default offset is the scroll offset of this view.</p> 19516 * 19517 * @return the vertical offset of the scrollbar's thumb 19518 * 19519 * @see #computeVerticalScrollRange() 19520 * @see #computeVerticalScrollExtent() 19521 */ computeVerticalScrollOffset()19522 protected int computeVerticalScrollOffset() { 19523 return mScrollY; 19524 } 19525 19526 /** 19527 * <p>Compute the vertical extent of the vertical scrollbar's thumb 19528 * within the vertical range. This value is used to compute the length 19529 * of the thumb within the scrollbar's track.</p> 19530 * 19531 * <p>The range is expressed in arbitrary units that must be the same as the 19532 * units used by {@link #computeVerticalScrollRange()} and 19533 * {@link #computeVerticalScrollOffset()}.</p> 19534 * 19535 * <p>The default extent is the drawing height of this view.</p> 19536 * 19537 * @return the vertical extent of the scrollbar's thumb 19538 * 19539 * @see #computeVerticalScrollRange() 19540 * @see #computeVerticalScrollOffset() 19541 */ computeVerticalScrollExtent()19542 protected int computeVerticalScrollExtent() { 19543 return getHeight(); 19544 } 19545 19546 /** 19547 * Check if this view can be scrolled horizontally in a certain direction. 19548 * 19549 * @param direction Negative to check scrolling left, positive to check scrolling right. 19550 * @return true if this view can be scrolled in the specified direction, false otherwise. 19551 */ canScrollHorizontally(int direction)19552 public boolean canScrollHorizontally(int direction) { 19553 final int offset = computeHorizontalScrollOffset(); 19554 final int range = computeHorizontalScrollRange() - computeHorizontalScrollExtent(); 19555 if (range == 0) return false; 19556 if (direction < 0) { 19557 return offset > 0; 19558 } else { 19559 return offset < range - 1; 19560 } 19561 } 19562 19563 /** 19564 * Check if this view can be scrolled vertically in a certain direction. 19565 * 19566 * @param direction Negative to check scrolling up, positive to check scrolling down. 19567 * @return true if this view can be scrolled in the specified direction, false otherwise. 19568 */ canScrollVertically(int direction)19569 public boolean canScrollVertically(int direction) { 19570 final int offset = computeVerticalScrollOffset(); 19571 final int range = computeVerticalScrollRange() - computeVerticalScrollExtent(); 19572 if (range == 0) return false; 19573 if (direction < 0) { 19574 return offset > 0; 19575 } else { 19576 return offset < range - 1; 19577 } 19578 } 19579 getScrollIndicatorBounds(@onNull Rect out)19580 void getScrollIndicatorBounds(@NonNull Rect out) { 19581 out.left = mScrollX; 19582 out.right = mScrollX + mRight - mLeft; 19583 out.top = mScrollY; 19584 out.bottom = mScrollY + mBottom - mTop; 19585 } 19586 onDrawScrollIndicators(Canvas c)19587 private void onDrawScrollIndicators(Canvas c) { 19588 if ((mPrivateFlags3 & SCROLL_INDICATORS_PFLAG3_MASK) == 0) { 19589 // No scroll indicators enabled. 19590 return; 19591 } 19592 19593 final Drawable dr = mScrollIndicatorDrawable; 19594 if (dr == null) { 19595 // Scroll indicators aren't supported here. 19596 return; 19597 } 19598 19599 final int h = dr.getIntrinsicHeight(); 19600 final int w = dr.getIntrinsicWidth(); 19601 final Rect rect = mAttachInfo.mTmpInvalRect; 19602 getScrollIndicatorBounds(rect); 19603 19604 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_TOP) != 0) { 19605 final boolean canScrollUp = canScrollVertically(-1); 19606 if (canScrollUp) { 19607 dr.setBounds(rect.left, rect.top, rect.right, rect.top + h); 19608 dr.draw(c); 19609 } 19610 } 19611 19612 if ((mPrivateFlags3 & PFLAG3_SCROLL_INDICATOR_BOTTOM) != 0) { 19613 final boolean canScrollDown = canScrollVertically(1); 19614 if (canScrollDown) { 19615 dr.setBounds(rect.left, rect.bottom - h, rect.right, rect.bottom); 19616 dr.draw(c); 19617 } 19618 } 19619 19620 final int leftRtl; 19621 final int rightRtl; 19622 if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 19623 leftRtl = PFLAG3_SCROLL_INDICATOR_END; 19624 rightRtl = PFLAG3_SCROLL_INDICATOR_START; 19625 } else { 19626 leftRtl = PFLAG3_SCROLL_INDICATOR_START; 19627 rightRtl = PFLAG3_SCROLL_INDICATOR_END; 19628 } 19629 19630 final int leftMask = PFLAG3_SCROLL_INDICATOR_LEFT | leftRtl; 19631 if ((mPrivateFlags3 & leftMask) != 0) { 19632 final boolean canScrollLeft = canScrollHorizontally(-1); 19633 if (canScrollLeft) { 19634 dr.setBounds(rect.left, rect.top, rect.left + w, rect.bottom); 19635 dr.draw(c); 19636 } 19637 } 19638 19639 final int rightMask = PFLAG3_SCROLL_INDICATOR_RIGHT | rightRtl; 19640 if ((mPrivateFlags3 & rightMask) != 0) { 19641 final boolean canScrollRight = canScrollHorizontally(1); 19642 if (canScrollRight) { 19643 dr.setBounds(rect.right - w, rect.top, rect.right, rect.bottom); 19644 dr.draw(c); 19645 } 19646 } 19647 } 19648 getHorizontalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)19649 private void getHorizontalScrollBarBounds(@Nullable Rect drawBounds, 19650 @Nullable Rect touchBounds) { 19651 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 19652 if (bounds == null) { 19653 return; 19654 } 19655 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 19656 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 19657 && !isVerticalScrollBarHidden(); 19658 final int size = getHorizontalScrollbarHeight(); 19659 final int verticalScrollBarGap = drawVerticalScrollBar ? 19660 getVerticalScrollbarWidth() : 0; 19661 final int width = mRight - mLeft; 19662 final int height = mBottom - mTop; 19663 bounds.top = mScrollY + height - size - (mUserPaddingBottom & inside); 19664 bounds.left = mScrollX + (mPaddingLeft & inside); 19665 bounds.right = mScrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap; 19666 bounds.bottom = bounds.top + size; 19667 19668 if (touchBounds == null) { 19669 return; 19670 } 19671 if (touchBounds != bounds) { 19672 touchBounds.set(bounds); 19673 } 19674 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 19675 if (touchBounds.height() < minTouchTarget) { 19676 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 19677 touchBounds.bottom = Math.min(touchBounds.bottom + adjust, mScrollY + height); 19678 touchBounds.top = touchBounds.bottom - minTouchTarget; 19679 } 19680 if (touchBounds.width() < minTouchTarget) { 19681 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 19682 touchBounds.left -= adjust; 19683 touchBounds.right = touchBounds.left + minTouchTarget; 19684 } 19685 } 19686 getVerticalScrollBarBounds(@ullable Rect bounds, @Nullable Rect touchBounds)19687 private void getVerticalScrollBarBounds(@Nullable Rect bounds, @Nullable Rect touchBounds) { 19688 if (mRoundScrollbarRenderer == null) { 19689 getStraightVerticalScrollBarBounds(bounds, touchBounds); 19690 } else { 19691 getRoundVerticalScrollBarBounds(bounds != null ? bounds : touchBounds); 19692 } 19693 } 19694 getRoundVerticalScrollBarBounds(Rect bounds)19695 private void getRoundVerticalScrollBarBounds(Rect bounds) { 19696 final int width = mRight - mLeft; 19697 final int height = mBottom - mTop; 19698 // Do not take padding into account as we always want the scrollbars 19699 // to hug the screen for round wearable devices. 19700 bounds.left = mScrollX; 19701 bounds.top = mScrollY; 19702 bounds.right = bounds.left + width; 19703 bounds.bottom = mScrollY + height; 19704 } 19705 getStraightVerticalScrollBarBounds(@ullable Rect drawBounds, @Nullable Rect touchBounds)19706 private void getStraightVerticalScrollBarBounds(@Nullable Rect drawBounds, 19707 @Nullable Rect touchBounds) { 19708 final Rect bounds = drawBounds != null ? drawBounds : touchBounds; 19709 if (bounds == null) { 19710 return; 19711 } 19712 final int inside = (mViewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0; 19713 final int size = getVerticalScrollbarWidth(); 19714 int verticalScrollbarPosition = mVerticalScrollbarPosition; 19715 if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) { 19716 verticalScrollbarPosition = isLayoutRtl() ? 19717 SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT; 19718 } 19719 final int width = mRight - mLeft; 19720 final int height = mBottom - mTop; 19721 switch (verticalScrollbarPosition) { 19722 default: 19723 case SCROLLBAR_POSITION_RIGHT: 19724 bounds.left = mScrollX + width - size - (mUserPaddingRight & inside); 19725 break; 19726 case SCROLLBAR_POSITION_LEFT: 19727 bounds.left = mScrollX + (mUserPaddingLeft & inside); 19728 break; 19729 } 19730 bounds.top = mScrollY + (mPaddingTop & inside); 19731 bounds.right = bounds.left + size; 19732 bounds.bottom = mScrollY + height - (mUserPaddingBottom & inside); 19733 19734 if (touchBounds == null) { 19735 return; 19736 } 19737 if (touchBounds != bounds) { 19738 touchBounds.set(bounds); 19739 } 19740 final int minTouchTarget = mScrollCache.scrollBarMinTouchTarget; 19741 if (touchBounds.width() < minTouchTarget) { 19742 final int adjust = (minTouchTarget - touchBounds.width()) / 2; 19743 if (verticalScrollbarPosition == SCROLLBAR_POSITION_RIGHT) { 19744 touchBounds.right = Math.min(touchBounds.right + adjust, mScrollX + width); 19745 touchBounds.left = touchBounds.right - minTouchTarget; 19746 } else { 19747 touchBounds.left = Math.max(touchBounds.left + adjust, mScrollX); 19748 touchBounds.right = touchBounds.left + minTouchTarget; 19749 } 19750 } 19751 if (touchBounds.height() < minTouchTarget) { 19752 final int adjust = (minTouchTarget - touchBounds.height()) / 2; 19753 touchBounds.top -= adjust; 19754 touchBounds.bottom = touchBounds.top + minTouchTarget; 19755 } 19756 } 19757 19758 /** 19759 * <p>Request the drawing of the horizontal and the vertical scrollbar. The 19760 * scrollbars are painted only if they have been awakened first.</p> 19761 * 19762 * @param canvas the canvas on which to draw the scrollbars 19763 * 19764 * @see #awakenScrollBars(int) 19765 */ onDrawScrollBars(Canvas canvas)19766 protected final void onDrawScrollBars(Canvas canvas) { 19767 // scrollbars are drawn only when the animation is running 19768 final ScrollabilityCache cache = mScrollCache; 19769 19770 if (cache != null) { 19771 19772 int state = cache.state; 19773 19774 if (state == ScrollabilityCache.OFF) { 19775 return; 19776 } 19777 19778 boolean invalidate = false; 19779 19780 if (state == ScrollabilityCache.FADING) { 19781 // We're fading -- get our fade interpolation 19782 if (cache.interpolatorValues == null) { 19783 cache.interpolatorValues = new float[1]; 19784 } 19785 19786 float[] values = cache.interpolatorValues; 19787 19788 // Stops the animation if we're done 19789 if (cache.scrollBarInterpolator.timeToValues(values) == 19790 Interpolator.Result.FREEZE_END) { 19791 cache.state = ScrollabilityCache.OFF; 19792 } else { 19793 cache.scrollBar.mutate().setAlpha(Math.round(values[0])); 19794 } 19795 19796 // This will make the scroll bars inval themselves after 19797 // drawing. We only want this when we're fading so that 19798 // we prevent excessive redraws 19799 invalidate = true; 19800 } else { 19801 // We're just on -- but we may have been fading before so 19802 // reset alpha 19803 cache.scrollBar.mutate().setAlpha(255); 19804 } 19805 19806 final boolean drawHorizontalScrollBar = isHorizontalScrollBarEnabled(); 19807 final boolean drawVerticalScrollBar = isVerticalScrollBarEnabled() 19808 && !isVerticalScrollBarHidden(); 19809 19810 // Fork out the scroll bar drawing for round wearable devices. 19811 if (mRoundScrollbarRenderer != null) { 19812 if (drawVerticalScrollBar) { 19813 final Rect bounds = cache.mScrollBarBounds; 19814 getVerticalScrollBarBounds(bounds, null); 19815 mRoundScrollbarRenderer.drawRoundScrollbars( 19816 canvas, (float) cache.scrollBar.getAlpha() / 255f, bounds); 19817 if (invalidate) { 19818 invalidate(); 19819 } 19820 } 19821 // Do not draw horizontal scroll bars for round wearable devices. 19822 } else if (drawVerticalScrollBar || drawHorizontalScrollBar) { 19823 final ScrollBarDrawable scrollBar = cache.scrollBar; 19824 19825 if (drawHorizontalScrollBar) { 19826 scrollBar.setParameters(computeHorizontalScrollRange(), 19827 computeHorizontalScrollOffset(), 19828 computeHorizontalScrollExtent(), false); 19829 final Rect bounds = cache.mScrollBarBounds; 19830 getHorizontalScrollBarBounds(bounds, null); 19831 onDrawHorizontalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 19832 bounds.right, bounds.bottom); 19833 if (invalidate) { 19834 invalidate(bounds); 19835 } 19836 } 19837 19838 if (drawVerticalScrollBar) { 19839 scrollBar.setParameters(computeVerticalScrollRange(), 19840 computeVerticalScrollOffset(), 19841 computeVerticalScrollExtent(), true); 19842 final Rect bounds = cache.mScrollBarBounds; 19843 getVerticalScrollBarBounds(bounds, null); 19844 onDrawVerticalScrollBar(canvas, scrollBar, bounds.left, bounds.top, 19845 bounds.right, bounds.bottom); 19846 if (invalidate) { 19847 invalidate(bounds); 19848 } 19849 } 19850 } 19851 } 19852 } 19853 19854 /** 19855 * Override this if the vertical scrollbar needs to be hidden in a subclass, like when 19856 * FastScroller is visible. 19857 * @return whether to temporarily hide the vertical scrollbar 19858 * @hide 19859 */ isVerticalScrollBarHidden()19860 protected boolean isVerticalScrollBarHidden() { 19861 return false; 19862 } 19863 19864 /** 19865 * <p>Draw the horizontal scrollbar if 19866 * {@link #isHorizontalScrollBarEnabled()} returns true.</p> 19867 * 19868 * @param canvas the canvas on which to draw the scrollbar 19869 * @param scrollBar the scrollbar's drawable 19870 * 19871 * @see #isHorizontalScrollBarEnabled() 19872 * @see #computeHorizontalScrollRange() 19873 * @see #computeHorizontalScrollExtent() 19874 * @see #computeHorizontalScrollOffset() 19875 * @hide 19876 */ 19877 @UnsupportedAppUsage onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)19878 protected void onDrawHorizontalScrollBar(Canvas canvas, Drawable scrollBar, 19879 int l, int t, int r, int b) { 19880 scrollBar.setBounds(l, t, r, b); 19881 scrollBar.draw(canvas); 19882 } 19883 19884 /** 19885 * <p>Draw the vertical scrollbar if {@link #isVerticalScrollBarEnabled()} 19886 * returns true.</p> 19887 * 19888 * @param canvas the canvas on which to draw the scrollbar 19889 * @param scrollBar the scrollbar's drawable 19890 * 19891 * @see #isVerticalScrollBarEnabled() 19892 * @see #computeVerticalScrollRange() 19893 * @see #computeVerticalScrollExtent() 19894 * @see #computeVerticalScrollOffset() 19895 * @hide 19896 */ 19897 @UnsupportedAppUsage onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, int l, int t, int r, int b)19898 protected void onDrawVerticalScrollBar(Canvas canvas, Drawable scrollBar, 19899 int l, int t, int r, int b) { 19900 scrollBar.setBounds(l, t, r, b); 19901 scrollBar.draw(canvas); 19902 } 19903 19904 /** 19905 * Implement this to do your drawing. 19906 * 19907 * @param canvas the canvas on which the background will be drawn 19908 */ onDraw(Canvas canvas)19909 protected void onDraw(Canvas canvas) { 19910 } 19911 19912 /* 19913 * Caller is responsible for calling requestLayout if necessary. 19914 * (This allows addViewInLayout to not request a new layout.) 19915 */ 19916 @UnsupportedAppUsage assignParent(ViewParent parent)19917 void assignParent(ViewParent parent) { 19918 if (mParent == null) { 19919 mParent = parent; 19920 } else if (parent == null) { 19921 mParent = null; 19922 } else { 19923 throw new RuntimeException("view " + this + " being added, but" 19924 + " it already has a parent"); 19925 } 19926 } 19927 19928 /** 19929 * This is called when the view is attached to a window. At this point it 19930 * has a Surface and will start drawing. Note that this function is 19931 * guaranteed to be called before {@link #onDraw(android.graphics.Canvas)}, 19932 * however it may be called any time before the first onDraw -- including 19933 * before or after {@link #onMeasure(int, int)}. 19934 * 19935 * @see #onDetachedFromWindow() 19936 */ 19937 @CallSuper onAttachedToWindow()19938 protected void onAttachedToWindow() { 19939 if ((mPrivateFlags & PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) { 19940 mParent.requestTransparentRegion(this); 19941 } 19942 19943 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 19944 19945 jumpDrawablesToCurrentState(); 19946 19947 AccessibilityNodeIdManager.getInstance().registerViewWithId(this, getAccessibilityViewId()); 19948 resetSubtreeAccessibilityStateChanged(); 19949 19950 // rebuild, since Outline not maintained while View is detached 19951 rebuildOutline(); 19952 19953 if (isFocused()) { 19954 notifyFocusChangeToImeFocusController(true /* hasFocus */); 19955 } 19956 } 19957 19958 /** 19959 * Resolve all RTL related properties. 19960 * 19961 * @return true if resolution of RTL properties has been done 19962 * 19963 * @hide 19964 */ resolveRtlPropertiesIfNeeded()19965 public boolean resolveRtlPropertiesIfNeeded() { 19966 if (!needRtlPropertiesResolution()) return false; 19967 19968 // Order is important here: LayoutDirection MUST be resolved first 19969 if (!isLayoutDirectionResolved()) { 19970 resolveLayoutDirection(); 19971 resolveLayoutParams(); 19972 } 19973 // ... then we can resolve the others properties depending on the resolved LayoutDirection. 19974 if (!isTextDirectionResolved()) { 19975 resolveTextDirection(); 19976 } 19977 if (!isTextAlignmentResolved()) { 19978 resolveTextAlignment(); 19979 } 19980 // Should resolve Drawables before Padding because we need the layout direction of the 19981 // Drawable to correctly resolve Padding. 19982 if (!areDrawablesResolved()) { 19983 resolveDrawables(); 19984 } 19985 if (!isPaddingResolved()) { 19986 resolvePadding(); 19987 } 19988 onRtlPropertiesChanged(getLayoutDirection()); 19989 return true; 19990 } 19991 19992 /** 19993 * Reset resolution of all RTL related properties. 19994 * 19995 * @hide 19996 */ 19997 @TestApi resetRtlProperties()19998 public void resetRtlProperties() { 19999 resetResolvedLayoutDirection(); 20000 resetResolvedTextDirection(); 20001 resetResolvedTextAlignment(); 20002 resetResolvedPadding(); 20003 resetResolvedDrawables(); 20004 } 20005 20006 /** 20007 * @see #onScreenStateChanged(int) 20008 */ dispatchScreenStateChanged(int screenState)20009 void dispatchScreenStateChanged(int screenState) { 20010 onScreenStateChanged(screenState); 20011 } 20012 20013 /** 20014 * This method is called whenever the state of the screen this view is 20015 * attached to changes. A state change will usually occurs when the screen 20016 * turns on or off (whether it happens automatically or the user does it 20017 * manually.) 20018 * 20019 * @param screenState The new state of the screen. Can be either 20020 * {@link #SCREEN_STATE_ON} or {@link #SCREEN_STATE_OFF} 20021 */ onScreenStateChanged(int screenState)20022 public void onScreenStateChanged(int screenState) { 20023 } 20024 20025 /** 20026 * @see #onMovedToDisplay(int, Configuration) 20027 */ dispatchMovedToDisplay(Display display, Configuration config)20028 void dispatchMovedToDisplay(Display display, Configuration config) { 20029 mAttachInfo.mDisplay = display; 20030 mAttachInfo.mDisplayState = display.getState(); 20031 onMovedToDisplay(display.getDisplayId(), config); 20032 } 20033 20034 /** 20035 * Called by the system when the hosting activity is moved from one display to another without 20036 * recreation. This means that the activity is declared to handle all changes to configuration 20037 * that happened when it was switched to another display, so it wasn't destroyed and created 20038 * again. 20039 * 20040 * <p>This call will be followed by {@link #onConfigurationChanged(Configuration)} if the 20041 * applied configuration actually changed. It is up to app developer to choose whether to handle 20042 * the change in this method or in the following {@link #onConfigurationChanged(Configuration)} 20043 * call. 20044 * 20045 * <p>Use this callback to track changes to the displays if some functionality relies on an 20046 * association with some display properties. 20047 * 20048 * @param displayId The id of the display to which the view was moved. 20049 * @param config Configuration of the resources on new display after move. 20050 * 20051 * @see #onConfigurationChanged(Configuration) 20052 * @hide 20053 */ onMovedToDisplay(int displayId, Configuration config)20054 public void onMovedToDisplay(int displayId, Configuration config) { 20055 } 20056 20057 /** 20058 * Return true if the application tag in the AndroidManifest has set "supportRtl" to true 20059 */ 20060 @UnsupportedAppUsage hasRtlSupport()20061 private boolean hasRtlSupport() { 20062 return mContext.getApplicationInfo().hasRtlSupport(); 20063 } 20064 20065 /** 20066 * Return true if we are in RTL compatibility mode (either before Jelly Bean MR1 or 20067 * RTL not supported) 20068 */ isRtlCompatibilityMode()20069 private boolean isRtlCompatibilityMode() { 20070 final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion; 20071 return targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR1 || !hasRtlSupport(); 20072 } 20073 20074 /** 20075 * @return true if RTL properties need resolution. 20076 * 20077 */ needRtlPropertiesResolution()20078 private boolean needRtlPropertiesResolution() { 20079 return (mPrivateFlags2 & ALL_RTL_PROPERTIES_RESOLVED) != ALL_RTL_PROPERTIES_RESOLVED; 20080 } 20081 20082 /** 20083 * Called when any RTL property (layout direction or text direction or text alignment) has 20084 * been changed. 20085 * 20086 * Subclasses need to override this method to take care of cached information that depends on the 20087 * resolved layout direction, or to inform child views that inherit their layout direction. 20088 * 20089 * The default implementation does nothing. 20090 * 20091 * @param layoutDirection the direction of the layout 20092 * 20093 * @see #LAYOUT_DIRECTION_LTR 20094 * @see #LAYOUT_DIRECTION_RTL 20095 */ onRtlPropertiesChanged(@esolvedLayoutDir int layoutDirection)20096 public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) { 20097 } 20098 20099 /** 20100 * Resolve and cache the layout direction. LTR is set initially. This is implicitly supposing 20101 * that the parent directionality can and will be resolved before its children. 20102 * 20103 * @return true if resolution has been done, false otherwise. 20104 * 20105 * @hide 20106 */ resolveLayoutDirection()20107 public boolean resolveLayoutDirection() { 20108 // Clear any previous layout direction resolution 20109 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 20110 20111 if (hasRtlSupport()) { 20112 // Set resolved depending on layout direction 20113 switch ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_MASK) >> 20114 PFLAG2_LAYOUT_DIRECTION_MASK_SHIFT) { 20115 case LAYOUT_DIRECTION_INHERIT: 20116 // We cannot resolve yet. LTR is by default and let the resolution happen again 20117 // later to get the correct resolved value 20118 if (!canResolveLayoutDirection()) return false; 20119 20120 // Parent has not yet resolved, LTR is still the default 20121 try { 20122 if (!mParent.isLayoutDirectionResolved()) return false; 20123 20124 if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) { 20125 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 20126 } 20127 } catch (AbstractMethodError e) { 20128 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 20129 " does not fully implement ViewParent", e); 20130 } 20131 break; 20132 case LAYOUT_DIRECTION_RTL: 20133 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 20134 break; 20135 case LAYOUT_DIRECTION_LOCALE: 20136 if((LAYOUT_DIRECTION_RTL == 20137 TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()))) { 20138 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL; 20139 } 20140 break; 20141 default: 20142 // Nothing to do, LTR by default 20143 } 20144 } 20145 20146 // Set to resolved 20147 mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED; 20148 return true; 20149 } 20150 20151 /** 20152 * Check if layout direction resolution can be done. 20153 * 20154 * @return true if layout direction resolution can be done otherwise return false. 20155 */ canResolveLayoutDirection()20156 public boolean canResolveLayoutDirection() { 20157 switch (getRawLayoutDirection()) { 20158 case LAYOUT_DIRECTION_INHERIT: 20159 if (mParent != null) { 20160 try { 20161 return mParent.canResolveLayoutDirection(); 20162 } catch (AbstractMethodError e) { 20163 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 20164 " does not fully implement ViewParent", e); 20165 } 20166 } 20167 return false; 20168 20169 default: 20170 return true; 20171 } 20172 } 20173 20174 /** 20175 * Reset the resolved layout direction. Layout direction will be resolved during a call to 20176 * {@link #onMeasure(int, int)}. 20177 * 20178 * @hide 20179 */ 20180 @TestApi resetResolvedLayoutDirection()20181 public void resetResolvedLayoutDirection() { 20182 // Reset the current resolved bits 20183 mPrivateFlags2 &= ~PFLAG2_LAYOUT_DIRECTION_RESOLVED_MASK; 20184 } 20185 20186 /** 20187 * @return true if the layout direction is inherited. 20188 * 20189 * @hide 20190 */ isLayoutDirectionInherited()20191 public boolean isLayoutDirectionInherited() { 20192 return (getRawLayoutDirection() == LAYOUT_DIRECTION_INHERIT); 20193 } 20194 20195 /** 20196 * @return true if layout direction has been resolved. 20197 */ isLayoutDirectionResolved()20198 public boolean isLayoutDirectionResolved() { 20199 return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED; 20200 } 20201 20202 /** 20203 * Return if padding has been resolved 20204 * 20205 * @hide 20206 */ 20207 @UnsupportedAppUsage isPaddingResolved()20208 boolean isPaddingResolved() { 20209 return (mPrivateFlags2 & PFLAG2_PADDING_RESOLVED) == PFLAG2_PADDING_RESOLVED; 20210 } 20211 20212 /** 20213 * Resolves padding depending on layout direction, if applicable, and 20214 * recomputes internal padding values to adjust for scroll bars. 20215 * 20216 * @hide 20217 */ 20218 @UnsupportedAppUsage resolvePadding()20219 public void resolvePadding() { 20220 final int resolvedLayoutDirection = getLayoutDirection(); 20221 20222 if (!isRtlCompatibilityMode()) { 20223 // Post Jelly Bean MR1 case: we need to take the resolved layout direction into account. 20224 // If start / end padding are defined, they will be resolved (hence overriding) to 20225 // left / right or right / left depending on the resolved layout direction. 20226 // If start / end padding are not defined, use the left / right ones. 20227 if (mBackground != null && (!mLeftPaddingDefined || !mRightPaddingDefined)) { 20228 Rect padding = sThreadLocal.get(); 20229 if (padding == null) { 20230 padding = new Rect(); 20231 sThreadLocal.set(padding); 20232 } 20233 mBackground.getPadding(padding); 20234 if (!mLeftPaddingDefined) { 20235 mUserPaddingLeftInitial = padding.left; 20236 } 20237 if (!mRightPaddingDefined) { 20238 mUserPaddingRightInitial = padding.right; 20239 } 20240 } 20241 switch (resolvedLayoutDirection) { 20242 case LAYOUT_DIRECTION_RTL: 20243 if (mUserPaddingStart != UNDEFINED_PADDING) { 20244 mUserPaddingRight = mUserPaddingStart; 20245 } else { 20246 mUserPaddingRight = mUserPaddingRightInitial; 20247 } 20248 if (mUserPaddingEnd != UNDEFINED_PADDING) { 20249 mUserPaddingLeft = mUserPaddingEnd; 20250 } else { 20251 mUserPaddingLeft = mUserPaddingLeftInitial; 20252 } 20253 break; 20254 case LAYOUT_DIRECTION_LTR: 20255 default: 20256 if (mUserPaddingStart != UNDEFINED_PADDING) { 20257 mUserPaddingLeft = mUserPaddingStart; 20258 } else { 20259 mUserPaddingLeft = mUserPaddingLeftInitial; 20260 } 20261 if (mUserPaddingEnd != UNDEFINED_PADDING) { 20262 mUserPaddingRight = mUserPaddingEnd; 20263 } else { 20264 mUserPaddingRight = mUserPaddingRightInitial; 20265 } 20266 } 20267 20268 mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom; 20269 } 20270 20271 internalSetPadding(mUserPaddingLeft, mPaddingTop, mUserPaddingRight, mUserPaddingBottom); 20272 onRtlPropertiesChanged(resolvedLayoutDirection); 20273 20274 mPrivateFlags2 |= PFLAG2_PADDING_RESOLVED; 20275 } 20276 20277 /** 20278 * Reset the resolved layout direction. 20279 * 20280 * @hide 20281 */ 20282 @TestApi resetResolvedPadding()20283 public void resetResolvedPadding() { 20284 resetResolvedPaddingInternal(); 20285 } 20286 20287 /** 20288 * Used when we only want to reset *this* view's padding and not trigger overrides 20289 * in ViewGroup that reset children too. 20290 */ resetResolvedPaddingInternal()20291 void resetResolvedPaddingInternal() { 20292 mPrivateFlags2 &= ~PFLAG2_PADDING_RESOLVED; 20293 } 20294 20295 /** 20296 * This is called when the view is detached from a window. At this point it 20297 * no longer has a surface for drawing. 20298 * 20299 * @see #onAttachedToWindow() 20300 */ 20301 @CallSuper onDetachedFromWindow()20302 protected void onDetachedFromWindow() { 20303 } 20304 20305 /** 20306 * This is a framework-internal mirror of onDetachedFromWindow() that's called 20307 * after onDetachedFromWindow(). 20308 * 20309 * If you override this you *MUST* call super.onDetachedFromWindowInternal()! 20310 * The super method should be called at the end of the overridden method to ensure 20311 * subclasses are destroyed first 20312 * 20313 * @hide 20314 */ 20315 @CallSuper 20316 @UnsupportedAppUsage onDetachedFromWindowInternal()20317 protected void onDetachedFromWindowInternal() { 20318 mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT; 20319 mPrivateFlags3 &= ~PFLAG3_IS_LAID_OUT; 20320 mPrivateFlags3 &= ~PFLAG3_TEMPORARY_DETACH; 20321 20322 removeUnsetPressCallback(); 20323 removeLongPressCallback(); 20324 removePerformClickCallback(); 20325 clearAccessibilityThrottles(); 20326 stopNestedScroll(); 20327 20328 // Anything that started animating right before detach should already 20329 // be in its final state when re-attached. 20330 jumpDrawablesToCurrentState(); 20331 20332 destroyDrawingCache(); 20333 20334 cleanupDraw(); 20335 mCurrentAnimation = null; 20336 20337 if ((mViewFlags & TOOLTIP) == TOOLTIP) { 20338 hideTooltip(); 20339 } 20340 20341 AccessibilityNodeIdManager.getInstance().unregisterViewWithId(getAccessibilityViewId()); 20342 } 20343 cleanupDraw()20344 private void cleanupDraw() { 20345 resetDisplayList(); 20346 if (mAttachInfo != null) { 20347 mAttachInfo.mViewRootImpl.cancelInvalidate(this); 20348 } 20349 } 20350 invalidateInheritedLayoutMode(int layoutModeOfRoot)20351 void invalidateInheritedLayoutMode(int layoutModeOfRoot) { 20352 } 20353 20354 /** 20355 * @return The number of times this view has been attached to a window 20356 */ getWindowAttachCount()20357 protected int getWindowAttachCount() { 20358 return mWindowAttachCount; 20359 } 20360 20361 /** 20362 * Retrieve a unique token identifying the window this view is attached to. 20363 * @return Return the window's token for use in 20364 * {@link WindowManager.LayoutParams#token WindowManager.LayoutParams.token}. 20365 */ getWindowToken()20366 public IBinder getWindowToken() { 20367 return mAttachInfo != null ? mAttachInfo.mWindowToken : null; 20368 } 20369 20370 /** 20371 * Retrieve the {@link WindowId} for the window this view is 20372 * currently attached to. 20373 */ getWindowId()20374 public WindowId getWindowId() { 20375 AttachInfo ai = mAttachInfo; 20376 if (ai == null) { 20377 return null; 20378 } 20379 if (ai.mWindowId == null) { 20380 try { 20381 ai.mIWindowId = ai.mSession.getWindowId(ai.mWindowToken); 20382 if (ai.mIWindowId != null) { 20383 ai.mWindowId = new WindowId(ai.mIWindowId); 20384 } 20385 } catch (RemoteException e) { 20386 } 20387 } 20388 return ai.mWindowId; 20389 } 20390 20391 /** 20392 * Retrieve a unique token identifying the top-level "real" window of 20393 * the window that this view is attached to. That is, this is like 20394 * {@link #getWindowToken}, except if the window this view in is a panel 20395 * window (attached to another containing window), then the token of 20396 * the containing window is returned instead. 20397 * 20398 * @return Returns the associated window token, either 20399 * {@link #getWindowToken()} or the containing window's token. 20400 */ getApplicationWindowToken()20401 public IBinder getApplicationWindowToken() { 20402 AttachInfo ai = mAttachInfo; 20403 if (ai != null) { 20404 IBinder appWindowToken = ai.mPanelParentWindowToken; 20405 if (appWindowToken == null) { 20406 appWindowToken = ai.mWindowToken; 20407 } 20408 return appWindowToken; 20409 } 20410 return null; 20411 } 20412 20413 /** 20414 * Gets the logical display to which the view's window has been attached. 20415 * 20416 * @return The logical display, or null if the view is not currently attached to a window. 20417 */ getDisplay()20418 public Display getDisplay() { 20419 return mAttachInfo != null ? mAttachInfo.mDisplay : null; 20420 } 20421 20422 /** 20423 * Retrieve private session object this view hierarchy is using to 20424 * communicate with the window manager. 20425 * @return the session object to communicate with the window manager 20426 */ 20427 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) getWindowSession()20428 /*package*/ IWindowSession getWindowSession() { 20429 return mAttachInfo != null ? mAttachInfo.mSession : null; 20430 } 20431 20432 /** 20433 * Return the window this view is currently attached to. Used in 20434 * {@link android.app.ActivityView} to communicate with WM. 20435 * @hide 20436 */ getWindow()20437 protected IWindow getWindow() { 20438 return mAttachInfo != null ? mAttachInfo.mWindow : null; 20439 } 20440 20441 /** 20442 * Return the visibility value of the least visible component passed. 20443 */ combineVisibility(int vis1, int vis2)20444 int combineVisibility(int vis1, int vis2) { 20445 // This works because VISIBLE < INVISIBLE < GONE. 20446 return Math.max(vis1, vis2); 20447 } 20448 20449 /** 20450 * @param info the {@link android.view.View.AttachInfo} to associated with 20451 * this view 20452 */ 20453 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchAttachedToWindow(AttachInfo info, int visibility)20454 void dispatchAttachedToWindow(AttachInfo info, int visibility) { 20455 mAttachInfo = info; 20456 if (mOverlay != null) { 20457 mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility); 20458 } 20459 mWindowAttachCount++; 20460 // We will need to evaluate the drawable state at least once. 20461 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 20462 if (mFloatingTreeObserver != null) { 20463 info.mTreeObserver.merge(mFloatingTreeObserver); 20464 mFloatingTreeObserver = null; 20465 } 20466 20467 registerPendingFrameMetricsObservers(); 20468 20469 if ((mPrivateFlags&PFLAG_SCROLL_CONTAINER) != 0) { 20470 mAttachInfo.mScrollContainers.add(this); 20471 mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED; 20472 } 20473 // Transfer all pending runnables. 20474 if (mRunQueue != null) { 20475 mRunQueue.executeActions(info.mHandler); 20476 mRunQueue = null; 20477 } 20478 performCollectViewAttributes(mAttachInfo, visibility); 20479 onAttachedToWindow(); 20480 20481 ListenerInfo li = mListenerInfo; 20482 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 20483 li != null ? li.mOnAttachStateChangeListeners : null; 20484 if (listeners != null && listeners.size() > 0) { 20485 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 20486 // perform the dispatching. The iterator is a safe guard against listeners that 20487 // could mutate the list by calling the various add/remove methods. This prevents 20488 // the array from being modified while we iterate it. 20489 for (OnAttachStateChangeListener listener : listeners) { 20490 listener.onViewAttachedToWindow(this); 20491 } 20492 } 20493 20494 int vis = info.mWindowVisibility; 20495 if (vis != GONE) { 20496 onWindowVisibilityChanged(vis); 20497 if (isShown()) { 20498 // Calling onVisibilityAggregated directly here since the subtree will also 20499 // receive dispatchAttachedToWindow and this same call 20500 onVisibilityAggregated(vis == VISIBLE); 20501 } 20502 } 20503 20504 // Send onVisibilityChanged directly instead of dispatchVisibilityChanged. 20505 // As all views in the subtree will already receive dispatchAttachedToWindow 20506 // traversing the subtree again here is not desired. 20507 onVisibilityChanged(this, visibility); 20508 20509 if ((mPrivateFlags&PFLAG_DRAWABLE_STATE_DIRTY) != 0) { 20510 // If nobody has evaluated the drawable state yet, then do it now. 20511 refreshDrawableState(); 20512 } 20513 needGlobalAttributesUpdate(false); 20514 20515 notifyEnterOrExitForAutoFillIfNeeded(true); 20516 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 20517 } 20518 20519 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) dispatchDetachedFromWindow()20520 void dispatchDetachedFromWindow() { 20521 AttachInfo info = mAttachInfo; 20522 if (info != null) { 20523 int vis = info.mWindowVisibility; 20524 if (vis != GONE) { 20525 onWindowVisibilityChanged(GONE); 20526 if (isShown()) { 20527 // Invoking onVisibilityAggregated directly here since the subtree 20528 // will also receive detached from window 20529 onVisibilityAggregated(false); 20530 } 20531 } 20532 } 20533 20534 onDetachedFromWindow(); 20535 onDetachedFromWindowInternal(); 20536 20537 if (info != null) { 20538 info.mViewRootImpl.getImeFocusController().onViewDetachedFromWindow(this); 20539 } 20540 20541 ListenerInfo li = mListenerInfo; 20542 final CopyOnWriteArrayList<OnAttachStateChangeListener> listeners = 20543 li != null ? li.mOnAttachStateChangeListeners : null; 20544 if (listeners != null && listeners.size() > 0) { 20545 // NOTE: because of the use of CopyOnWriteArrayList, we *must* use an iterator to 20546 // perform the dispatching. The iterator is a safe guard against listeners that 20547 // could mutate the list by calling the various add/remove methods. This prevents 20548 // the array from being modified while we iterate it. 20549 for (OnAttachStateChangeListener listener : listeners) { 20550 listener.onViewDetachedFromWindow(this); 20551 } 20552 } 20553 20554 if ((mPrivateFlags & PFLAG_SCROLL_CONTAINER_ADDED) != 0) { 20555 mAttachInfo.mScrollContainers.remove(this); 20556 mPrivateFlags &= ~PFLAG_SCROLL_CONTAINER_ADDED; 20557 } 20558 20559 mAttachInfo = null; 20560 if (mOverlay != null) { 20561 mOverlay.getOverlayView().dispatchDetachedFromWindow(); 20562 } 20563 20564 notifyEnterOrExitForAutoFillIfNeeded(false); 20565 notifyAppearedOrDisappearedForContentCaptureIfNeeded(false); 20566 } 20567 20568 /** 20569 * Cancel any deferred high-level input events that were previously posted to the event queue. 20570 * 20571 * <p>Many views post high-level events such as click handlers to the event queue 20572 * to run deferred in order to preserve a desired user experience - clearing visible 20573 * pressed states before executing, etc. This method will abort any events of this nature 20574 * that are currently in flight.</p> 20575 * 20576 * <p>Custom views that generate their own high-level deferred input events should override 20577 * {@link #onCancelPendingInputEvents()} and remove those pending events from the queue.</p> 20578 * 20579 * <p>This will also cancel pending input events for any child views.</p> 20580 * 20581 * <p>Note that this may not be sufficient as a debouncing strategy for clicks in all cases. 20582 * This will not impact newer events posted after this call that may occur as a result of 20583 * lower-level input events still waiting in the queue. If you are trying to prevent 20584 * double-submitted events for the duration of some sort of asynchronous transaction 20585 * you should also take other steps to protect against unexpected double inputs e.g. calling 20586 * {@link #setEnabled(boolean) setEnabled(false)} and re-enabling the view when 20587 * the transaction completes, tracking already submitted transaction IDs, etc.</p> 20588 */ cancelPendingInputEvents()20589 public final void cancelPendingInputEvents() { 20590 dispatchCancelPendingInputEvents(); 20591 } 20592 20593 /** 20594 * Called by {@link #cancelPendingInputEvents()} to cancel input events in flight. 20595 * Overridden by ViewGroup to dispatch. Package scoped to prevent app-side meddling. 20596 */ dispatchCancelPendingInputEvents()20597 void dispatchCancelPendingInputEvents() { 20598 mPrivateFlags3 &= ~PFLAG3_CALLED_SUPER; 20599 onCancelPendingInputEvents(); 20600 if ((mPrivateFlags3 & PFLAG3_CALLED_SUPER) != PFLAG3_CALLED_SUPER) { 20601 throw new SuperNotCalledException("View " + getClass().getSimpleName() + 20602 " did not call through to super.onCancelPendingInputEvents()"); 20603 } 20604 } 20605 20606 /** 20607 * Called as the result of a call to {@link #cancelPendingInputEvents()} on this view or 20608 * a parent view. 20609 * 20610 * <p>This method is responsible for removing any pending high-level input events that were 20611 * posted to the event queue to run later. Custom view classes that post their own deferred 20612 * high-level events via {@link #post(Runnable)}, {@link #postDelayed(Runnable, long)} or 20613 * {@link android.os.Handler} should override this method, call 20614 * <code>super.onCancelPendingInputEvents()</code> and remove those callbacks as appropriate. 20615 * </p> 20616 */ onCancelPendingInputEvents()20617 public void onCancelPendingInputEvents() { 20618 removePerformClickCallback(); 20619 cancelLongPress(); 20620 mPrivateFlags3 |= PFLAG3_CALLED_SUPER; 20621 } 20622 20623 /** 20624 * Store this view hierarchy's frozen state into the given container. 20625 * 20626 * @param container The SparseArray in which to save the view's state. 20627 * 20628 * @see #restoreHierarchyState(android.util.SparseArray) 20629 * @see #dispatchSaveInstanceState(android.util.SparseArray) 20630 * @see #onSaveInstanceState() 20631 */ saveHierarchyState(SparseArray<Parcelable> container)20632 public void saveHierarchyState(SparseArray<Parcelable> container) { 20633 dispatchSaveInstanceState(container); 20634 } 20635 20636 /** 20637 * Called by {@link #saveHierarchyState(android.util.SparseArray)} to store the state for 20638 * this view and its children. May be overridden to modify how freezing happens to a 20639 * view's children; for example, some views may want to not store state for their children. 20640 * 20641 * @param container The SparseArray in which to save the view's state. 20642 * 20643 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 20644 * @see #saveHierarchyState(android.util.SparseArray) 20645 * @see #onSaveInstanceState() 20646 */ dispatchSaveInstanceState(SparseArray<Parcelable> container)20647 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 20648 if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) { 20649 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 20650 Parcelable state = onSaveInstanceState(); 20651 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 20652 throw new IllegalStateException( 20653 "Derived class did not call super.onSaveInstanceState()"); 20654 } 20655 if (state != null) { 20656 // Log.i("View", "Freezing #" + Integer.toHexString(mID) 20657 // + ": " + state); 20658 container.put(mID, state); 20659 } 20660 } 20661 } 20662 20663 /** 20664 * Hook allowing a view to generate a representation of its internal state 20665 * that can later be used to create a new instance with that same state. 20666 * This state should only contain information that is not persistent or can 20667 * not be reconstructed later. For example, you will never store your 20668 * current position on screen because that will be computed again when a 20669 * new instance of the view is placed in its view hierarchy. 20670 * <p> 20671 * Some examples of things you may store here: the current cursor position 20672 * in a text view (but usually not the text itself since that is stored in a 20673 * content provider or other persistent storage), the currently selected 20674 * item in a list view. 20675 * 20676 * @return Returns a Parcelable object containing the view's current dynamic 20677 * state, or null if there is nothing interesting to save. 20678 * @see #onRestoreInstanceState(Parcelable) 20679 * @see #saveHierarchyState(SparseArray) 20680 * @see #dispatchSaveInstanceState(SparseArray) 20681 * @see #setSaveEnabled(boolean) 20682 */ 20683 @CallSuper onSaveInstanceState()20684 @Nullable protected Parcelable onSaveInstanceState() { 20685 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 20686 if (mStartActivityRequestWho != null || isAutofilled() 20687 || mAutofillViewId > LAST_APP_AUTOFILL_ID) { 20688 BaseSavedState state = new BaseSavedState(AbsSavedState.EMPTY_STATE); 20689 20690 if (mStartActivityRequestWho != null) { 20691 state.mSavedData |= BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED; 20692 } 20693 20694 if (isAutofilled()) { 20695 state.mSavedData |= BaseSavedState.IS_AUTOFILLED; 20696 } 20697 20698 if (mAutofillViewId > LAST_APP_AUTOFILL_ID) { 20699 state.mSavedData |= BaseSavedState.AUTOFILL_ID; 20700 } 20701 20702 state.mStartActivityRequestWhoSaved = mStartActivityRequestWho; 20703 state.mIsAutofilled = isAutofilled(); 20704 state.mHideHighlight = hideAutofillHighlight(); 20705 state.mAutofillViewId = mAutofillViewId; 20706 return state; 20707 } 20708 return BaseSavedState.EMPTY_STATE; 20709 } 20710 20711 /** 20712 * Restore this view hierarchy's frozen state from the given container. 20713 * 20714 * @param container The SparseArray which holds previously frozen states. 20715 * 20716 * @see #saveHierarchyState(android.util.SparseArray) 20717 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 20718 * @see #onRestoreInstanceState(android.os.Parcelable) 20719 */ restoreHierarchyState(SparseArray<Parcelable> container)20720 public void restoreHierarchyState(SparseArray<Parcelable> container) { 20721 dispatchRestoreInstanceState(container); 20722 } 20723 20724 /** 20725 * Called by {@link #restoreHierarchyState(android.util.SparseArray)} to retrieve the 20726 * state for this view and its children. May be overridden to modify how restoring 20727 * happens to a view's children; for example, some views may want to not store state 20728 * for their children. 20729 * 20730 * @param container The SparseArray which holds previously saved state. 20731 * 20732 * @see #dispatchSaveInstanceState(android.util.SparseArray) 20733 * @see #restoreHierarchyState(android.util.SparseArray) 20734 * @see #onRestoreInstanceState(android.os.Parcelable) 20735 */ dispatchRestoreInstanceState(SparseArray<Parcelable> container)20736 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 20737 if (mID != NO_ID) { 20738 Parcelable state = container.get(mID); 20739 if (state != null) { 20740 // Log.i("View", "Restoreing #" + Integer.toHexString(mID) 20741 // + ": " + state); 20742 mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED; 20743 onRestoreInstanceState(state); 20744 if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) { 20745 throw new IllegalStateException( 20746 "Derived class did not call super.onRestoreInstanceState()"); 20747 } 20748 } 20749 } 20750 } 20751 20752 /** 20753 * Hook allowing a view to re-apply a representation of its internal state that had previously 20754 * been generated by {@link #onSaveInstanceState}. This function will never be called with a 20755 * null state. 20756 * 20757 * @param state The frozen state that had previously been returned by 20758 * {@link #onSaveInstanceState}. 20759 * 20760 * @see #onSaveInstanceState() 20761 * @see #restoreHierarchyState(android.util.SparseArray) 20762 * @see #dispatchRestoreInstanceState(android.util.SparseArray) 20763 */ 20764 @CallSuper onRestoreInstanceState(Parcelable state)20765 protected void onRestoreInstanceState(Parcelable state) { 20766 mPrivateFlags |= PFLAG_SAVE_STATE_CALLED; 20767 if (state != null && !(state instanceof AbsSavedState)) { 20768 throw new IllegalArgumentException("Wrong state class, expecting View State but " 20769 + "received " + state.getClass().toString() + " instead. This usually happens " 20770 + "when two views of different type have the same id in the same hierarchy. " 20771 + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure " 20772 + "other views do not use the same id."); 20773 } 20774 if (state != null && state instanceof BaseSavedState) { 20775 BaseSavedState baseState = (BaseSavedState) state; 20776 20777 if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) { 20778 mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved; 20779 } 20780 if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) { 20781 setAutofilled(baseState.mIsAutofilled, baseState.mHideHighlight); 20782 } 20783 if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) { 20784 // It can happen that views have the same view id and the restoration path will not 20785 // be able to distinguish between them. The autofill id needs to be unique though. 20786 // Hence prevent the same autofill view id from being restored multiple times. 20787 ((BaseSavedState) state).mSavedData &= ~BaseSavedState.AUTOFILL_ID; 20788 20789 if ((mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) != 0) { 20790 // Ignore when view already set it through setAutofillId(); 20791 if (Log.isLoggable(AUTOFILL_LOG_TAG, Log.DEBUG)) { 20792 Log.d(AUTOFILL_LOG_TAG, "onRestoreInstanceState(): not setting autofillId " 20793 + "to " + baseState.mAutofillViewId + " because view explicitly set" 20794 + " it to " + mAutofillId); 20795 } 20796 } else { 20797 mAutofillViewId = baseState.mAutofillViewId; 20798 mAutofillId = null; // will be set on demand by getAutofillId() 20799 } 20800 } 20801 } 20802 } 20803 20804 /** 20805 * <p>Return the time at which the drawing of the view hierarchy started.</p> 20806 * 20807 * @return the drawing start time in milliseconds 20808 */ getDrawingTime()20809 public long getDrawingTime() { 20810 return mAttachInfo != null ? mAttachInfo.mDrawingTime : 0; 20811 } 20812 20813 /** 20814 * <p>Enables or disables the duplication of the parent's state into this view. When 20815 * duplication is enabled, this view gets its drawable state from its parent rather 20816 * than from its own internal properties.</p> 20817 * 20818 * <p>Note: in the current implementation, setting this property to true after the 20819 * view was added to a ViewGroup might have no effect at all. This property should 20820 * always be used from XML or set to true before adding this view to a ViewGroup.</p> 20821 * 20822 * <p>Note: if this view's parent addStateFromChildren property is enabled and this 20823 * property is enabled, an exception will be thrown.</p> 20824 * 20825 * <p>Note: if the child view uses and updates additional states which are unknown to the 20826 * parent, these states should not be affected by this method.</p> 20827 * 20828 * @param enabled True to enable duplication of the parent's drawable state, false 20829 * to disable it. 20830 * 20831 * @see #getDrawableState() 20832 * @see #isDuplicateParentStateEnabled() 20833 */ setDuplicateParentStateEnabled(boolean enabled)20834 public void setDuplicateParentStateEnabled(boolean enabled) { 20835 setFlags(enabled ? DUPLICATE_PARENT_STATE : 0, DUPLICATE_PARENT_STATE); 20836 } 20837 20838 /** 20839 * <p>Indicates whether this duplicates its drawable state from its parent.</p> 20840 * 20841 * @return True if this view's drawable state is duplicated from the parent, 20842 * false otherwise 20843 * 20844 * @see #getDrawableState() 20845 * @see #setDuplicateParentStateEnabled(boolean) 20846 */ 20847 @InspectableProperty(name = "duplicateParentState") isDuplicateParentStateEnabled()20848 public boolean isDuplicateParentStateEnabled() { 20849 return (mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE; 20850 } 20851 20852 /** 20853 * <p>Specifies the type of layer backing this view. The layer can be 20854 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 20855 * {@link #LAYER_TYPE_HARDWARE}.</p> 20856 * 20857 * <p>A layer is associated with an optional {@link android.graphics.Paint} 20858 * instance that controls how the layer is composed on screen. The following 20859 * properties of the paint are taken into account when composing the layer:</p> 20860 * <ul> 20861 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 20862 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 20863 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 20864 * </ul> 20865 * 20866 * <p>If this view has an alpha value set to < 1.0 by calling 20867 * {@link #setAlpha(float)}, the alpha value of the layer's paint is superseded 20868 * by this view's alpha value.</p> 20869 * 20870 * <p>Refer to the documentation of {@link #LAYER_TYPE_NONE}, 20871 * {@link #LAYER_TYPE_SOFTWARE} and {@link #LAYER_TYPE_HARDWARE} 20872 * for more information on when and how to use layers.</p> 20873 * 20874 * @param layerType The type of layer to use with this view, must be one of 20875 * {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 20876 * {@link #LAYER_TYPE_HARDWARE} 20877 * @param paint The paint used to compose the layer. This argument is optional 20878 * and can be null. It is ignored when the layer type is 20879 * {@link #LAYER_TYPE_NONE} 20880 * 20881 * @see #getLayerType() 20882 * @see #LAYER_TYPE_NONE 20883 * @see #LAYER_TYPE_SOFTWARE 20884 * @see #LAYER_TYPE_HARDWARE 20885 * @see #setAlpha(float) 20886 * 20887 * @attr ref android.R.styleable#View_layerType 20888 */ setLayerType(@ayerType int layerType, @Nullable Paint paint)20889 public void setLayerType(@LayerType int layerType, @Nullable Paint paint) { 20890 if (layerType < LAYER_TYPE_NONE || layerType > LAYER_TYPE_HARDWARE) { 20891 throw new IllegalArgumentException("Layer type can only be one of: LAYER_TYPE_NONE, " 20892 + "LAYER_TYPE_SOFTWARE or LAYER_TYPE_HARDWARE"); 20893 } 20894 20895 boolean typeChanged = mRenderNode.setLayerType(layerType); 20896 20897 if (!typeChanged) { 20898 setLayerPaint(paint); 20899 return; 20900 } 20901 20902 if (layerType != LAYER_TYPE_SOFTWARE) { 20903 // Destroy any previous software drawing cache if present 20904 // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up 20905 // drawing cache created in View#draw when drawing to a SW canvas. 20906 destroyDrawingCache(); 20907 } 20908 20909 mLayerType = layerType; 20910 mLayerPaint = mLayerType == LAYER_TYPE_NONE ? null : paint; 20911 mRenderNode.setLayerPaint(mLayerPaint); 20912 20913 // draw() behaves differently if we are on a layer, so we need to 20914 // invalidate() here 20915 invalidateParentCaches(); 20916 invalidate(true); 20917 } 20918 20919 /** 20920 * Updates the {@link Paint} object used with the current layer (used only if the current 20921 * layer type is not set to {@link #LAYER_TYPE_NONE}). Changed properties of the Paint 20922 * provided to {@link #setLayerType(int, android.graphics.Paint)} will be used the next time 20923 * the View is redrawn, but {@link #setLayerPaint(android.graphics.Paint)} must be called to 20924 * ensure that the view gets redrawn immediately. 20925 * 20926 * <p>A layer is associated with an optional {@link android.graphics.Paint} 20927 * instance that controls how the layer is composed on screen. The following 20928 * properties of the paint are taken into account when composing the layer:</p> 20929 * <ul> 20930 * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li> 20931 * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li> 20932 * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li> 20933 * </ul> 20934 * 20935 * <p>If this view has an alpha value set to < 1.0 by calling {@link #setAlpha(float)}, the 20936 * alpha value of the layer's paint is superseded by this view's alpha value.</p> 20937 * 20938 * @param paint The paint used to compose the layer. This argument is optional 20939 * and can be null. It is ignored when the layer type is 20940 * {@link #LAYER_TYPE_NONE} 20941 * 20942 * @see #setLayerType(int, android.graphics.Paint) 20943 */ setLayerPaint(@ullable Paint paint)20944 public void setLayerPaint(@Nullable Paint paint) { 20945 int layerType = getLayerType(); 20946 if (layerType != LAYER_TYPE_NONE) { 20947 mLayerPaint = paint; 20948 if (layerType == LAYER_TYPE_HARDWARE) { 20949 if (mRenderNode.setLayerPaint(paint)) { 20950 invalidateViewProperty(false, false); 20951 } 20952 } else { 20953 invalidate(); 20954 } 20955 } 20956 } 20957 20958 /** 20959 * Indicates what type of layer is currently associated with this view. By default 20960 * a view does not have a layer, and the layer type is {@link #LAYER_TYPE_NONE}. 20961 * Refer to the documentation of {@link #setLayerType(int, android.graphics.Paint)} 20962 * for more information on the different types of layers. 20963 * 20964 * @return {@link #LAYER_TYPE_NONE}, {@link #LAYER_TYPE_SOFTWARE} or 20965 * {@link #LAYER_TYPE_HARDWARE} 20966 * 20967 * @see #setLayerType(int, android.graphics.Paint) 20968 * @see #buildLayer() 20969 * @see #LAYER_TYPE_NONE 20970 * @see #LAYER_TYPE_SOFTWARE 20971 * @see #LAYER_TYPE_HARDWARE 20972 */ 20973 @InspectableProperty(enumMapping = { 20974 @EnumEntry(value = LAYER_TYPE_NONE, name = "none"), 20975 @EnumEntry(value = LAYER_TYPE_SOFTWARE, name = "software"), 20976 @EnumEntry(value = LAYER_TYPE_HARDWARE, name = "hardware") 20977 }) 20978 @LayerType getLayerType()20979 public int getLayerType() { 20980 return mLayerType; 20981 } 20982 20983 /** 20984 * Forces this view's layer to be created and this view to be rendered 20985 * into its layer. If this view's layer type is set to {@link #LAYER_TYPE_NONE}, 20986 * invoking this method will have no effect. 20987 * 20988 * This method can for instance be used to render a view into its layer before 20989 * starting an animation. If this view is complex, rendering into the layer 20990 * before starting the animation will avoid skipping frames. 20991 * 20992 * @throws IllegalStateException If this view is not attached to a window 20993 * 20994 * @see #setLayerType(int, android.graphics.Paint) 20995 */ buildLayer()20996 public void buildLayer() { 20997 if (mLayerType == LAYER_TYPE_NONE) return; 20998 20999 final AttachInfo attachInfo = mAttachInfo; 21000 if (attachInfo == null) { 21001 throw new IllegalStateException("This view must be attached to a window first"); 21002 } 21003 21004 if (getWidth() == 0 || getHeight() == 0) { 21005 return; 21006 } 21007 21008 switch (mLayerType) { 21009 case LAYER_TYPE_HARDWARE: 21010 updateDisplayListIfDirty(); 21011 if (attachInfo.mThreadedRenderer != null && mRenderNode.hasDisplayList()) { 21012 attachInfo.mThreadedRenderer.buildLayer(mRenderNode); 21013 } 21014 break; 21015 case LAYER_TYPE_SOFTWARE: 21016 buildDrawingCache(true); 21017 break; 21018 } 21019 } 21020 21021 /** 21022 * Destroys all hardware rendering resources. This method is invoked 21023 * when the system needs to reclaim resources. Upon execution of this 21024 * method, you should free any OpenGL resources created by the view. 21025 * 21026 * Note: you <strong>must</strong> call 21027 * <code>super.destroyHardwareResources()</code> when overriding 21028 * this method. 21029 * 21030 * @hide 21031 */ 21032 @CallSuper 21033 @UnsupportedAppUsage destroyHardwareResources()21034 protected void destroyHardwareResources() { 21035 if (mOverlay != null) { 21036 mOverlay.getOverlayView().destroyHardwareResources(); 21037 } 21038 if (mGhostView != null) { 21039 mGhostView.destroyHardwareResources(); 21040 } 21041 } 21042 21043 /** 21044 * <p>Enables or disables the drawing cache. When the drawing cache is enabled, the next call 21045 * to {@link #getDrawingCache()} or {@link #buildDrawingCache()} will draw the view in a 21046 * bitmap. Calling {@link #draw(android.graphics.Canvas)} will not draw from the cache when 21047 * the cache is enabled. To benefit from the cache, you must request the drawing cache by 21048 * calling {@link #getDrawingCache()} and draw it on screen if the returned bitmap is not 21049 * null.</p> 21050 * 21051 * <p>Enabling the drawing cache is similar to 21052 * {@link #setLayerType(int, android.graphics.Paint) setting a layer} when hardware 21053 * acceleration is turned off. When hardware acceleration is turned on, enabling the 21054 * drawing cache has no effect on rendering because the system uses a different mechanism 21055 * for acceleration which ignores the flag. If you want to use a Bitmap for the view, even 21056 * when hardware acceleration is enabled, see {@link #setLayerType(int, android.graphics.Paint)} 21057 * for information on how to enable software and hardware layers.</p> 21058 * 21059 * <p>This API can be used to manually generate 21060 * a bitmap copy of this view, by setting the flag to <code>true</code> and calling 21061 * {@link #getDrawingCache()}.</p> 21062 * 21063 * @param enabled true to enable the drawing cache, false otherwise 21064 * 21065 * @see #isDrawingCacheEnabled() 21066 * @see #getDrawingCache() 21067 * @see #buildDrawingCache() 21068 * @see #setLayerType(int, android.graphics.Paint) 21069 * 21070 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21071 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21072 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21073 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21074 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21075 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21076 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21077 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21078 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21079 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21080 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21081 * reports or unit testing the {@link PixelCopy} API is recommended. 21082 */ 21083 @Deprecated setDrawingCacheEnabled(boolean enabled)21084 public void setDrawingCacheEnabled(boolean enabled) { 21085 mCachingFailed = false; 21086 setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED); 21087 } 21088 21089 /** 21090 * <p>Indicates whether the drawing cache is enabled for this view.</p> 21091 * 21092 * @return true if the drawing cache is enabled 21093 * 21094 * @see #setDrawingCacheEnabled(boolean) 21095 * @see #getDrawingCache() 21096 * 21097 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21098 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21099 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21100 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21101 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21102 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21103 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21104 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21105 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21106 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21107 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21108 * reports or unit testing the {@link PixelCopy} API is recommended. 21109 */ 21110 @Deprecated 21111 @ViewDebug.ExportedProperty(category = "drawing") isDrawingCacheEnabled()21112 public boolean isDrawingCacheEnabled() { 21113 return (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED; 21114 } 21115 21116 /** 21117 * Debugging utility which recursively outputs the dirty state of a view and its 21118 * descendants. 21119 * 21120 * @hide 21121 */ 21122 @SuppressWarnings({"UnusedDeclaration"}) outputDirtyFlags(String indent, boolean clear, int clearMask)21123 public void outputDirtyFlags(String indent, boolean clear, int clearMask) { 21124 Log.d(VIEW_LOG_TAG, indent + this + " DIRTY(" 21125 + (mPrivateFlags & View.PFLAG_DIRTY_MASK) 21126 + ") DRAWN(" + (mPrivateFlags & PFLAG_DRAWN) + ")" + " CACHE_VALID(" 21127 + (mPrivateFlags & View.PFLAG_DRAWING_CACHE_VALID) 21128 + ") INVALIDATED(" + (mPrivateFlags & PFLAG_INVALIDATED) + ")"); 21129 if (clear) { 21130 mPrivateFlags &= clearMask; 21131 } 21132 if (this instanceof ViewGroup) { 21133 ViewGroup parent = (ViewGroup) this; 21134 final int count = parent.getChildCount(); 21135 for (int i = 0; i < count; i++) { 21136 final View child = parent.getChildAt(i); 21137 child.outputDirtyFlags(indent + " ", clear, clearMask); 21138 } 21139 } 21140 } 21141 21142 /** 21143 * This method is used by ViewGroup to cause its children to restore or recreate their 21144 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need 21145 * to recreate its own display list, which would happen if it went through the normal 21146 * draw/dispatchDraw mechanisms. 21147 * 21148 * @hide 21149 */ dispatchGetDisplayList()21150 protected void dispatchGetDisplayList() {} 21151 21152 /** 21153 * A view that is not attached or hardware accelerated cannot create a display list. 21154 * This method checks these conditions and returns the appropriate result. 21155 * 21156 * @return true if view has the ability to create a display list, false otherwise. 21157 * 21158 * @hide 21159 */ canHaveDisplayList()21160 public boolean canHaveDisplayList() { 21161 return !(mAttachInfo == null || mAttachInfo.mThreadedRenderer == null); 21162 } 21163 21164 /** 21165 * Gets the RenderNode for the view, and updates its DisplayList (if needed and supported) 21166 * @hide 21167 */ 21168 @NonNull 21169 @UnsupportedAppUsage updateDisplayListIfDirty()21170 public RenderNode updateDisplayListIfDirty() { 21171 final RenderNode renderNode = mRenderNode; 21172 if (!canHaveDisplayList()) { 21173 // can't populate RenderNode, don't try 21174 return renderNode; 21175 } 21176 21177 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 21178 || !renderNode.hasDisplayList() 21179 || (mRecreateDisplayList)) { 21180 // Don't need to recreate the display list, just need to tell our 21181 // children to restore/recreate theirs 21182 if (renderNode.hasDisplayList() 21183 && !mRecreateDisplayList) { 21184 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 21185 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21186 dispatchGetDisplayList(); 21187 21188 return renderNode; // no work needed 21189 } 21190 21191 // If we got here, we're recreating it. Mark it as such to ensure that 21192 // we copy in child display lists into ours in drawChild() 21193 mRecreateDisplayList = true; 21194 21195 int width = mRight - mLeft; 21196 int height = mBottom - mTop; 21197 int layerType = getLayerType(); 21198 21199 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 21200 21201 try { 21202 if (layerType == LAYER_TYPE_SOFTWARE) { 21203 buildDrawingCache(true); 21204 Bitmap cache = getDrawingCache(true); 21205 if (cache != null) { 21206 canvas.drawBitmap(cache, 0, 0, mLayerPaint); 21207 } 21208 } else { 21209 computeScroll(); 21210 21211 canvas.translate(-mScrollX, -mScrollY); 21212 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 21213 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21214 21215 // Fast path for layouts with no backgrounds 21216 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 21217 dispatchDraw(canvas); 21218 drawAutofilledHighlight(canvas); 21219 if (mOverlay != null && !mOverlay.isEmpty()) { 21220 mOverlay.getOverlayView().draw(canvas); 21221 } 21222 if (isShowingLayoutBounds()) { 21223 debugDrawFocus(canvas); 21224 } 21225 } else { 21226 draw(canvas); 21227 } 21228 } 21229 } finally { 21230 renderNode.endRecording(); 21231 setDisplayListProperties(renderNode); 21232 } 21233 } else { 21234 mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID; 21235 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21236 } 21237 return renderNode; 21238 } 21239 21240 @UnsupportedAppUsage resetDisplayList()21241 private void resetDisplayList() { 21242 mRenderNode.discardDisplayList(); 21243 if (mBackgroundRenderNode != null) { 21244 mBackgroundRenderNode.discardDisplayList(); 21245 } 21246 } 21247 21248 /** 21249 * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p> 21250 * 21251 * @return A non-scaled bitmap representing this view or null if cache is disabled. 21252 * 21253 * @see #getDrawingCache(boolean) 21254 * 21255 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21256 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21257 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21258 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21259 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21260 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21261 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21262 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21263 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21264 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21265 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21266 * reports or unit testing the {@link PixelCopy} API is recommended. 21267 */ 21268 @Deprecated getDrawingCache()21269 public Bitmap getDrawingCache() { 21270 return getDrawingCache(false); 21271 } 21272 21273 /** 21274 * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap 21275 * is null when caching is disabled. If caching is enabled and the cache is not ready, 21276 * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not 21277 * draw from the cache when the cache is enabled. To benefit from the cache, you must 21278 * request the drawing cache by calling this method and draw it on screen if the 21279 * returned bitmap is not null.</p> 21280 * 21281 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 21282 * this method will create a bitmap of the same size as this view. Because this bitmap 21283 * will be drawn scaled by the parent ViewGroup, the result on screen might show 21284 * scaling artifacts. To avoid such artifacts, you should call this method by setting 21285 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 21286 * size than the view. This implies that your application must be able to handle this 21287 * size.</p> 21288 * 21289 * @param autoScale Indicates whether the generated bitmap should be scaled based on 21290 * the current density of the screen when the application is in compatibility 21291 * mode. 21292 * 21293 * @return A bitmap representing this view or null if cache is disabled. 21294 * 21295 * @see #setDrawingCacheEnabled(boolean) 21296 * @see #isDrawingCacheEnabled() 21297 * @see #buildDrawingCache(boolean) 21298 * @see #destroyDrawingCache() 21299 * 21300 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21301 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21302 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21303 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21304 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21305 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21306 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21307 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21308 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21309 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21310 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21311 * reports or unit testing the {@link PixelCopy} API is recommended. 21312 */ 21313 @Deprecated getDrawingCache(boolean autoScale)21314 public Bitmap getDrawingCache(boolean autoScale) { 21315 if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { 21316 return null; 21317 } 21318 if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { 21319 buildDrawingCache(autoScale); 21320 } 21321 return autoScale ? mDrawingCache : mUnscaledDrawingCache; 21322 } 21323 21324 /** 21325 * <p>Frees the resources used by the drawing cache. If you call 21326 * {@link #buildDrawingCache()} manually without calling 21327 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 21328 * should cleanup the cache with this method afterwards.</p> 21329 * 21330 * @see #setDrawingCacheEnabled(boolean) 21331 * @see #buildDrawingCache() 21332 * @see #getDrawingCache() 21333 * 21334 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21335 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21336 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21337 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21338 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21339 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21340 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21341 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21342 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21343 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21344 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21345 * reports or unit testing the {@link PixelCopy} API is recommended. 21346 */ 21347 @Deprecated destroyDrawingCache()21348 public void destroyDrawingCache() { 21349 if (mDrawingCache != null) { 21350 mDrawingCache.recycle(); 21351 mDrawingCache = null; 21352 } 21353 if (mUnscaledDrawingCache != null) { 21354 mUnscaledDrawingCache.recycle(); 21355 mUnscaledDrawingCache = null; 21356 } 21357 } 21358 21359 /** 21360 * Setting a solid background color for the drawing cache's bitmaps will improve 21361 * performance and memory usage. Note, though that this should only be used if this 21362 * view will always be drawn on top of a solid color. 21363 * 21364 * @param color The background color to use for the drawing cache's bitmap 21365 * 21366 * @see #setDrawingCacheEnabled(boolean) 21367 * @see #buildDrawingCache() 21368 * @see #getDrawingCache() 21369 * 21370 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21371 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21372 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21373 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21374 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21375 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21376 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21377 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21378 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21379 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21380 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21381 * reports or unit testing the {@link PixelCopy} API is recommended. 21382 */ 21383 @Deprecated setDrawingCacheBackgroundColor(@olorInt int color)21384 public void setDrawingCacheBackgroundColor(@ColorInt int color) { 21385 if (color != mDrawingCacheBackgroundColor) { 21386 mDrawingCacheBackgroundColor = color; 21387 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID; 21388 } 21389 } 21390 21391 /** 21392 * @see #setDrawingCacheBackgroundColor(int) 21393 * 21394 * @return The background color to used for the drawing cache's bitmap 21395 * 21396 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21397 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21398 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21399 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21400 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21401 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21402 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21403 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21404 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21405 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21406 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21407 * reports or unit testing the {@link PixelCopy} API is recommended. 21408 */ 21409 @Deprecated 21410 @ColorInt getDrawingCacheBackgroundColor()21411 public int getDrawingCacheBackgroundColor() { 21412 return mDrawingCacheBackgroundColor; 21413 } 21414 21415 /** 21416 * <p>Calling this method is equivalent to calling <code>buildDrawingCache(false)</code>.</p> 21417 * 21418 * @see #buildDrawingCache(boolean) 21419 * 21420 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21421 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21422 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21423 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21424 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21425 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21426 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21427 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21428 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21429 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21430 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21431 * reports or unit testing the {@link PixelCopy} API is recommended. 21432 */ 21433 @Deprecated buildDrawingCache()21434 public void buildDrawingCache() { 21435 buildDrawingCache(false); 21436 } 21437 21438 /** 21439 * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p> 21440 * 21441 * <p>If you call {@link #buildDrawingCache()} manually without calling 21442 * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you 21443 * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p> 21444 * 21445 * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled, 21446 * this method will create a bitmap of the same size as this view. Because this bitmap 21447 * will be drawn scaled by the parent ViewGroup, the result on screen might show 21448 * scaling artifacts. To avoid such artifacts, you should call this method by setting 21449 * the auto scaling to true. Doing so, however, will generate a bitmap of a different 21450 * size than the view. This implies that your application must be able to handle this 21451 * size.</p> 21452 * 21453 * <p>You should avoid calling this method when hardware acceleration is enabled. If 21454 * you do not need the drawing cache bitmap, calling this method will increase memory 21455 * usage and cause the view to be rendered in software once, thus negatively impacting 21456 * performance.</p> 21457 * 21458 * @see #getDrawingCache() 21459 * @see #destroyDrawingCache() 21460 * 21461 * @deprecated The view drawing cache was largely made obsolete with the introduction of 21462 * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache 21463 * layers are largely unnecessary and can easily result in a net loss in performance due to the 21464 * cost of creating and updating the layer. In the rare cases where caching layers are useful, 21465 * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware 21466 * rendering. For software-rendered snapshots of a small part of the View hierarchy or 21467 * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or 21468 * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these 21469 * software-rendered usages are discouraged and have compatibility issues with hardware-only 21470 * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE} 21471 * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback 21472 * reports or unit testing the {@link PixelCopy} API is recommended. 21473 */ 21474 @Deprecated buildDrawingCache(boolean autoScale)21475 public void buildDrawingCache(boolean autoScale) { 21476 if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ? 21477 mDrawingCache == null : mUnscaledDrawingCache == null)) { 21478 if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) { 21479 Trace.traceBegin(Trace.TRACE_TAG_VIEW, 21480 "buildDrawingCache/SW Layer for " + getClass().getSimpleName()); 21481 } 21482 try { 21483 buildDrawingCacheImpl(autoScale); 21484 } finally { 21485 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 21486 } 21487 } 21488 } 21489 21490 /** 21491 * private, internal implementation of buildDrawingCache, used to enable tracing 21492 */ buildDrawingCacheImpl(boolean autoScale)21493 private void buildDrawingCacheImpl(boolean autoScale) { 21494 mCachingFailed = false; 21495 21496 int width = mRight - mLeft; 21497 int height = mBottom - mTop; 21498 21499 final AttachInfo attachInfo = mAttachInfo; 21500 final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired; 21501 21502 if (autoScale && scalingRequired) { 21503 width = (int) ((width * attachInfo.mApplicationScale) + 0.5f); 21504 height = (int) ((height * attachInfo.mApplicationScale) + 0.5f); 21505 } 21506 21507 final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor; 21508 final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque(); 21509 final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache; 21510 21511 final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4); 21512 final long drawingCacheSize = 21513 ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); 21514 if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) { 21515 if (width > 0 && height > 0) { 21516 Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is" 21517 + " too large to fit into a software layer (or drawing cache), needs " 21518 + projectedBitmapSize + " bytes, only " 21519 + drawingCacheSize + " available"); 21520 } 21521 destroyDrawingCache(); 21522 mCachingFailed = true; 21523 return; 21524 } 21525 21526 boolean clear = true; 21527 Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache; 21528 21529 if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { 21530 Bitmap.Config quality; 21531 if (!opaque) { 21532 // Never pick ARGB_4444 because it looks awful 21533 // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case 21534 switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) { 21535 case DRAWING_CACHE_QUALITY_AUTO: 21536 case DRAWING_CACHE_QUALITY_LOW: 21537 case DRAWING_CACHE_QUALITY_HIGH: 21538 default: 21539 quality = Bitmap.Config.ARGB_8888; 21540 break; 21541 } 21542 } else { 21543 // Optimization for translucent windows 21544 // If the window is translucent, use a 32 bits bitmap to benefit from memcpy() 21545 quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; 21546 } 21547 21548 // Try to cleanup memory 21549 if (bitmap != null) bitmap.recycle(); 21550 21551 try { 21552 bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(), 21553 width, height, quality); 21554 bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 21555 if (autoScale) { 21556 mDrawingCache = bitmap; 21557 } else { 21558 mUnscaledDrawingCache = bitmap; 21559 } 21560 if (opaque && use32BitCache) bitmap.setHasAlpha(false); 21561 } catch (OutOfMemoryError e) { 21562 // If there is not enough memory to create the bitmap cache, just 21563 // ignore the issue as bitmap caches are not required to draw the 21564 // view hierarchy 21565 if (autoScale) { 21566 mDrawingCache = null; 21567 } else { 21568 mUnscaledDrawingCache = null; 21569 } 21570 mCachingFailed = true; 21571 return; 21572 } 21573 21574 clear = drawingCacheBackgroundColor != 0; 21575 } 21576 21577 Canvas canvas; 21578 if (attachInfo != null) { 21579 canvas = attachInfo.mCanvas; 21580 if (canvas == null) { 21581 canvas = new Canvas(); 21582 } 21583 canvas.setBitmap(bitmap); 21584 // Temporarily clobber the cached Canvas in case one of our children 21585 // is also using a drawing cache. Without this, the children would 21586 // steal the canvas by attaching their own bitmap to it and bad, bad 21587 // thing would happen (invisible views, corrupted drawings, etc.) 21588 attachInfo.mCanvas = null; 21589 } else { 21590 // This case should hopefully never or seldom happen 21591 canvas = new Canvas(bitmap); 21592 } 21593 21594 if (clear) { 21595 bitmap.eraseColor(drawingCacheBackgroundColor); 21596 } 21597 21598 computeScroll(); 21599 final int restoreCount = canvas.save(); 21600 21601 if (autoScale && scalingRequired) { 21602 final float scale = attachInfo.mApplicationScale; 21603 canvas.scale(scale, scale); 21604 } 21605 21606 canvas.translate(-mScrollX, -mScrollY); 21607 21608 mPrivateFlags |= PFLAG_DRAWN; 21609 if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated || 21610 mLayerType != LAYER_TYPE_NONE) { 21611 mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID; 21612 } 21613 21614 // Fast path for layouts with no backgrounds 21615 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 21616 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21617 dispatchDraw(canvas); 21618 drawAutofilledHighlight(canvas); 21619 if (mOverlay != null && !mOverlay.isEmpty()) { 21620 mOverlay.getOverlayView().draw(canvas); 21621 } 21622 } else { 21623 draw(canvas); 21624 } 21625 21626 canvas.restoreToCount(restoreCount); 21627 canvas.setBitmap(null); 21628 21629 if (attachInfo != null) { 21630 // Restore the cached Canvas for our siblings 21631 attachInfo.mCanvas = canvas; 21632 } 21633 } 21634 21635 /** 21636 * Create a snapshot of the view into a bitmap. We should probably make 21637 * some form of this public, but should think about the API. 21638 * 21639 * @hide 21640 */ 21641 @UnsupportedAppUsage createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren)21642 public Bitmap createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren) { 21643 int width = mRight - mLeft; 21644 int height = mBottom - mTop; 21645 21646 final AttachInfo attachInfo = mAttachInfo; 21647 final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f; 21648 width = (int) ((width * scale) + 0.5f); 21649 height = (int) ((height * scale) + 0.5f); 21650 21651 Canvas oldCanvas = null; 21652 try { 21653 Canvas canvas = canvasProvider.getCanvas(this, 21654 width > 0 ? width : 1, height > 0 ? height : 1); 21655 21656 if (attachInfo != null) { 21657 oldCanvas = attachInfo.mCanvas; 21658 // Temporarily clobber the cached Canvas in case one of our children 21659 // is also using a drawing cache. Without this, the children would 21660 // steal the canvas by attaching their own bitmap to it and bad, bad 21661 // things would happen (invisible views, corrupted drawings, etc.) 21662 attachInfo.mCanvas = null; 21663 } 21664 21665 computeScroll(); 21666 final int restoreCount = canvas.save(); 21667 canvas.scale(scale, scale); 21668 canvas.translate(-mScrollX, -mScrollY); 21669 21670 // Temporarily remove the dirty mask 21671 int flags = mPrivateFlags; 21672 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 21673 21674 // Fast path for layouts with no backgrounds 21675 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 21676 dispatchDraw(canvas); 21677 drawAutofilledHighlight(canvas); 21678 if (mOverlay != null && !mOverlay.isEmpty()) { 21679 mOverlay.getOverlayView().draw(canvas); 21680 } 21681 } else { 21682 draw(canvas); 21683 } 21684 21685 mPrivateFlags = flags; 21686 canvas.restoreToCount(restoreCount); 21687 return canvasProvider.createBitmap(); 21688 } finally { 21689 if (oldCanvas != null) { 21690 attachInfo.mCanvas = oldCanvas; 21691 } 21692 } 21693 } 21694 21695 /** 21696 * Indicates whether this View is currently in edit mode. A View is usually 21697 * in edit mode when displayed within a developer tool. For instance, if 21698 * this View is being drawn by a visual user interface builder, this method 21699 * should return true. 21700 * 21701 * Subclasses should check the return value of this method to provide 21702 * different behaviors if their normal behavior might interfere with the 21703 * host environment. For instance: the class spawns a thread in its 21704 * constructor, the drawing code relies on device-specific features, etc. 21705 * 21706 * This method is usually checked in the drawing code of custom widgets. 21707 * 21708 * @return True if this View is in edit mode, false otherwise. 21709 */ isInEditMode()21710 public boolean isInEditMode() { 21711 return false; 21712 } 21713 21714 /** 21715 * If the View draws content inside its padding and enables fading edges, 21716 * it needs to support padding offsets. Padding offsets are added to the 21717 * fading edges to extend the length of the fade so that it covers pixels 21718 * drawn inside the padding. 21719 * 21720 * Subclasses of this class should override this method if they need 21721 * to draw content inside the padding. 21722 * 21723 * @return True if padding offset must be applied, false otherwise. 21724 * 21725 * @see #getLeftPaddingOffset() 21726 * @see #getRightPaddingOffset() 21727 * @see #getTopPaddingOffset() 21728 * @see #getBottomPaddingOffset() 21729 * 21730 * @since CURRENT 21731 */ isPaddingOffsetRequired()21732 protected boolean isPaddingOffsetRequired() { 21733 return false; 21734 } 21735 21736 /** 21737 * Amount by which to extend the left fading region. Called only when 21738 * {@link #isPaddingOffsetRequired()} returns true. 21739 * 21740 * @return The left padding offset in pixels. 21741 * 21742 * @see #isPaddingOffsetRequired() 21743 * 21744 * @since CURRENT 21745 */ getLeftPaddingOffset()21746 protected int getLeftPaddingOffset() { 21747 return 0; 21748 } 21749 21750 /** 21751 * Amount by which to extend the right fading region. Called only when 21752 * {@link #isPaddingOffsetRequired()} returns true. 21753 * 21754 * @return The right padding offset in pixels. 21755 * 21756 * @see #isPaddingOffsetRequired() 21757 * 21758 * @since CURRENT 21759 */ getRightPaddingOffset()21760 protected int getRightPaddingOffset() { 21761 return 0; 21762 } 21763 21764 /** 21765 * Amount by which to extend the top fading region. Called only when 21766 * {@link #isPaddingOffsetRequired()} returns true. 21767 * 21768 * @return The top padding offset in pixels. 21769 * 21770 * @see #isPaddingOffsetRequired() 21771 * 21772 * @since CURRENT 21773 */ getTopPaddingOffset()21774 protected int getTopPaddingOffset() { 21775 return 0; 21776 } 21777 21778 /** 21779 * Amount by which to extend the bottom fading region. Called only when 21780 * {@link #isPaddingOffsetRequired()} returns true. 21781 * 21782 * @return The bottom padding offset in pixels. 21783 * 21784 * @see #isPaddingOffsetRequired() 21785 * 21786 * @since CURRENT 21787 */ getBottomPaddingOffset()21788 protected int getBottomPaddingOffset() { 21789 return 0; 21790 } 21791 21792 /** 21793 * @hide 21794 * @param offsetRequired 21795 */ getFadeTop(boolean offsetRequired)21796 protected int getFadeTop(boolean offsetRequired) { 21797 int top = mPaddingTop; 21798 if (offsetRequired) top += getTopPaddingOffset(); 21799 return top; 21800 } 21801 21802 /** 21803 * @hide 21804 * @param offsetRequired 21805 */ getFadeHeight(boolean offsetRequired)21806 protected int getFadeHeight(boolean offsetRequired) { 21807 int padding = mPaddingTop; 21808 if (offsetRequired) padding += getTopPaddingOffset(); 21809 return mBottom - mTop - mPaddingBottom - padding; 21810 } 21811 21812 /** 21813 * <p>Indicates whether this view is attached to a hardware accelerated 21814 * window or not.</p> 21815 * 21816 * <p>Even if this method returns true, it does not mean that every call 21817 * to {@link #draw(android.graphics.Canvas)} will be made with an hardware 21818 * accelerated {@link android.graphics.Canvas}. For instance, if this view 21819 * is drawn onto an offscreen {@link android.graphics.Bitmap} and its 21820 * window is hardware accelerated, 21821 * {@link android.graphics.Canvas#isHardwareAccelerated()} will likely 21822 * return false, and this method will return true.</p> 21823 * 21824 * @return True if the view is attached to a window and the window is 21825 * hardware accelerated; false in any other case. 21826 */ 21827 @ViewDebug.ExportedProperty(category = "drawing") isHardwareAccelerated()21828 public boolean isHardwareAccelerated() { 21829 return mAttachInfo != null && mAttachInfo.mHardwareAccelerated; 21830 } 21831 21832 /** 21833 * Sets a rectangular area on this view to which the view will be clipped 21834 * when it is drawn. Setting the value to null will remove the clip bounds 21835 * and the view will draw normally, using its full bounds. 21836 * 21837 * @param clipBounds The rectangular area, in the local coordinates of 21838 * this view, to which future drawing operations will be clipped. 21839 */ setClipBounds(Rect clipBounds)21840 public void setClipBounds(Rect clipBounds) { 21841 if (clipBounds == mClipBounds 21842 || (clipBounds != null && clipBounds.equals(mClipBounds))) { 21843 return; 21844 } 21845 if (clipBounds != null) { 21846 if (mClipBounds == null) { 21847 mClipBounds = new Rect(clipBounds); 21848 } else { 21849 mClipBounds.set(clipBounds); 21850 } 21851 } else { 21852 mClipBounds = null; 21853 } 21854 mRenderNode.setClipRect(mClipBounds); 21855 invalidateViewProperty(false, false); 21856 } 21857 21858 /** 21859 * Returns a copy of the current {@link #setClipBounds(Rect) clipBounds}. 21860 * 21861 * @return A copy of the current clip bounds if clip bounds are set, 21862 * otherwise null. 21863 */ getClipBounds()21864 public Rect getClipBounds() { 21865 return (mClipBounds != null) ? new Rect(mClipBounds) : null; 21866 } 21867 21868 21869 /** 21870 * Populates an output rectangle with the clip bounds of the view, 21871 * returning {@code true} if successful or {@code false} if the view's 21872 * clip bounds are {@code null}. 21873 * 21874 * @param outRect rectangle in which to place the clip bounds of the view 21875 * @return {@code true} if successful or {@code false} if the view's 21876 * clip bounds are {@code null} 21877 */ getClipBounds(Rect outRect)21878 public boolean getClipBounds(Rect outRect) { 21879 if (mClipBounds != null) { 21880 outRect.set(mClipBounds); 21881 return true; 21882 } 21883 return false; 21884 } 21885 21886 /** 21887 * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common 21888 * case of an active Animation being run on the view. 21889 */ applyLegacyAnimation(ViewGroup parent, long drawingTime, Animation a, boolean scalingRequired)21890 private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime, 21891 Animation a, boolean scalingRequired) { 21892 Transformation invalidationTransform; 21893 final int flags = parent.mGroupFlags; 21894 final boolean initialized = a.isInitialized(); 21895 if (!initialized) { 21896 a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight()); 21897 a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop); 21898 if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler); 21899 onAnimationStart(); 21900 } 21901 21902 final Transformation t = parent.getChildTransformation(); 21903 boolean more = a.getTransformation(drawingTime, t, 1f); 21904 if (scalingRequired && mAttachInfo.mApplicationScale != 1f) { 21905 if (parent.mInvalidationTransformation == null) { 21906 parent.mInvalidationTransformation = new Transformation(); 21907 } 21908 invalidationTransform = parent.mInvalidationTransformation; 21909 a.getTransformation(drawingTime, invalidationTransform, 1f); 21910 } else { 21911 invalidationTransform = t; 21912 } 21913 21914 if (more) { 21915 if (!a.willChangeBounds()) { 21916 if ((flags & (ViewGroup.FLAG_OPTIMIZE_INVALIDATE | ViewGroup.FLAG_ANIMATION_DONE)) == 21917 ViewGroup.FLAG_OPTIMIZE_INVALIDATE) { 21918 parent.mGroupFlags |= ViewGroup.FLAG_INVALIDATE_REQUIRED; 21919 } else if ((flags & ViewGroup.FLAG_INVALIDATE_REQUIRED) == 0) { 21920 // The child need to draw an animation, potentially offscreen, so 21921 // make sure we do not cancel invalidate requests 21922 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 21923 parent.invalidate(mLeft, mTop, mRight, mBottom); 21924 } 21925 } else { 21926 if (parent.mInvalidateRegion == null) { 21927 parent.mInvalidateRegion = new RectF(); 21928 } 21929 final RectF region = parent.mInvalidateRegion; 21930 a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region, 21931 invalidationTransform); 21932 21933 // The child need to draw an animation, potentially offscreen, so 21934 // make sure we do not cancel invalidate requests 21935 parent.mPrivateFlags |= PFLAG_DRAW_ANIMATION; 21936 21937 final int left = mLeft + (int) region.left; 21938 final int top = mTop + (int) region.top; 21939 parent.invalidate(left, top, left + (int) (region.width() + .5f), 21940 top + (int) (region.height() + .5f)); 21941 } 21942 } 21943 return more; 21944 } 21945 21946 /** 21947 * This method is called by getDisplayList() when a display list is recorded for a View. 21948 * It pushes any properties to the RenderNode that aren't managed by the RenderNode. 21949 */ setDisplayListProperties(RenderNode renderNode)21950 void setDisplayListProperties(RenderNode renderNode) { 21951 if (renderNode != null) { 21952 renderNode.setHasOverlappingRendering(getHasOverlappingRendering()); 21953 renderNode.setClipToBounds(mParent instanceof ViewGroup 21954 && ((ViewGroup) mParent).getClipChildren()); 21955 21956 float alpha = 1; 21957 if (mParent instanceof ViewGroup && (((ViewGroup) mParent).mGroupFlags & 21958 ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 21959 ViewGroup parentVG = (ViewGroup) mParent; 21960 final Transformation t = parentVG.getChildTransformation(); 21961 if (parentVG.getChildStaticTransformation(this, t)) { 21962 final int transformType = t.getTransformationType(); 21963 if (transformType != Transformation.TYPE_IDENTITY) { 21964 if ((transformType & Transformation.TYPE_ALPHA) != 0) { 21965 alpha = t.getAlpha(); 21966 } 21967 if ((transformType & Transformation.TYPE_MATRIX) != 0) { 21968 renderNode.setStaticMatrix(t.getMatrix()); 21969 } 21970 } 21971 } 21972 } 21973 if (mTransformationInfo != null) { 21974 alpha *= getFinalAlpha(); 21975 if (alpha < 1) { 21976 final int multipliedAlpha = (int) (255 * alpha); 21977 if (onSetAlpha(multipliedAlpha)) { 21978 alpha = 1; 21979 } 21980 } 21981 renderNode.setAlpha(alpha); 21982 } else if (alpha < 1) { 21983 renderNode.setAlpha(alpha); 21984 } 21985 } 21986 } 21987 21988 /** 21989 * This method is called by ViewGroup.drawChild() to have each child view draw itself. 21990 * 21991 * This is where the View specializes rendering behavior based on layer type, 21992 * and hardware acceleration. 21993 */ draw(Canvas canvas, ViewGroup parent, long drawingTime)21994 boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) { 21995 final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated(); 21996 /* If an attached view draws to a HW canvas, it may use its RenderNode + DisplayList. 21997 * 21998 * If a view is dettached, its DisplayList shouldn't exist. If the canvas isn't 21999 * HW accelerated, it can't handle drawing RenderNodes. 22000 */ 22001 boolean drawingWithRenderNode = mAttachInfo != null 22002 && mAttachInfo.mHardwareAccelerated 22003 && hardwareAcceleratedCanvas; 22004 22005 boolean more = false; 22006 final boolean childHasIdentityMatrix = hasIdentityMatrix(); 22007 final int parentFlags = parent.mGroupFlags; 22008 22009 if ((parentFlags & ViewGroup.FLAG_CLEAR_TRANSFORMATION) != 0) { 22010 parent.getChildTransformation().clear(); 22011 parent.mGroupFlags &= ~ViewGroup.FLAG_CLEAR_TRANSFORMATION; 22012 } 22013 22014 Transformation transformToApply = null; 22015 boolean concatMatrix = false; 22016 final boolean scalingRequired = mAttachInfo != null && mAttachInfo.mScalingRequired; 22017 final Animation a = getAnimation(); 22018 if (a != null) { 22019 more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired); 22020 concatMatrix = a.willChangeTransformationMatrix(); 22021 if (concatMatrix) { 22022 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 22023 } 22024 transformToApply = parent.getChildTransformation(); 22025 } else { 22026 if ((mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_TRANSFORM) != 0) { 22027 // No longer animating: clear out old animation matrix 22028 mRenderNode.setAnimationMatrix(null); 22029 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_TRANSFORM; 22030 } 22031 if (!drawingWithRenderNode 22032 && (parentFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) { 22033 final Transformation t = parent.getChildTransformation(); 22034 final boolean hasTransform = parent.getChildStaticTransformation(this, t); 22035 if (hasTransform) { 22036 final int transformType = t.getTransformationType(); 22037 transformToApply = transformType != Transformation.TYPE_IDENTITY ? t : null; 22038 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0; 22039 } 22040 } 22041 } 22042 22043 concatMatrix |= !childHasIdentityMatrix; 22044 22045 // Sets the flag as early as possible to allow draw() implementations 22046 // to call invalidate() successfully when doing animations 22047 mPrivateFlags |= PFLAG_DRAWN; 22048 22049 if (!concatMatrix && 22050 (parentFlags & (ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS | 22051 ViewGroup.FLAG_CLIP_CHILDREN)) == ViewGroup.FLAG_CLIP_CHILDREN && 22052 canvas.quickReject(mLeft, mTop, mRight, mBottom) && 22053 (mPrivateFlags & PFLAG_DRAW_ANIMATION) == 0) { 22054 mPrivateFlags2 |= PFLAG2_VIEW_QUICK_REJECTED; 22055 return more; 22056 } 22057 mPrivateFlags2 &= ~PFLAG2_VIEW_QUICK_REJECTED; 22058 22059 if (hardwareAcceleratedCanvas) { 22060 // Clear INVALIDATED flag to allow invalidation to occur during rendering, but 22061 // retain the flag's value temporarily in the mRecreateDisplayList flag 22062 mRecreateDisplayList = (mPrivateFlags & PFLAG_INVALIDATED) != 0; 22063 mPrivateFlags &= ~PFLAG_INVALIDATED; 22064 } 22065 22066 RenderNode renderNode = null; 22067 Bitmap cache = null; 22068 int layerType = getLayerType(); // TODO: signify cache state with just 'cache' local 22069 if (layerType == LAYER_TYPE_SOFTWARE || !drawingWithRenderNode) { 22070 if (layerType != LAYER_TYPE_NONE) { 22071 // If not drawing with RenderNode, treat HW layers as SW 22072 layerType = LAYER_TYPE_SOFTWARE; 22073 buildDrawingCache(true); 22074 } 22075 cache = getDrawingCache(true); 22076 } 22077 22078 if (drawingWithRenderNode) { 22079 // Delay getting the display list until animation-driven alpha values are 22080 // set up and possibly passed on to the view 22081 renderNode = updateDisplayListIfDirty(); 22082 if (!renderNode.hasDisplayList()) { 22083 // Uncommon, but possible. If a view is removed from the hierarchy during the call 22084 // to getDisplayList(), the display list will be marked invalid and we should not 22085 // try to use it again. 22086 renderNode = null; 22087 drawingWithRenderNode = false; 22088 } 22089 } 22090 22091 int sx = 0; 22092 int sy = 0; 22093 if (!drawingWithRenderNode) { 22094 computeScroll(); 22095 sx = mScrollX; 22096 sy = mScrollY; 22097 } 22098 22099 final boolean drawingWithDrawingCache = cache != null && !drawingWithRenderNode; 22100 final boolean offsetForScroll = cache == null && !drawingWithRenderNode; 22101 22102 int restoreTo = -1; 22103 if (!drawingWithRenderNode || transformToApply != null) { 22104 restoreTo = canvas.save(); 22105 } 22106 if (offsetForScroll) { 22107 canvas.translate(mLeft - sx, mTop - sy); 22108 } else { 22109 if (!drawingWithRenderNode) { 22110 canvas.translate(mLeft, mTop); 22111 } 22112 if (scalingRequired) { 22113 if (drawingWithRenderNode) { 22114 // TODO: Might not need this if we put everything inside the DL 22115 restoreTo = canvas.save(); 22116 } 22117 // mAttachInfo cannot be null, otherwise scalingRequired == false 22118 final float scale = 1.0f / mAttachInfo.mApplicationScale; 22119 canvas.scale(scale, scale); 22120 } 22121 } 22122 22123 float alpha = drawingWithRenderNode ? 1 : (getAlpha() * getTransitionAlpha()); 22124 if (transformToApply != null 22125 || alpha < 1 22126 || !hasIdentityMatrix() 22127 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 22128 if (transformToApply != null || !childHasIdentityMatrix) { 22129 int transX = 0; 22130 int transY = 0; 22131 22132 if (offsetForScroll) { 22133 transX = -sx; 22134 transY = -sy; 22135 } 22136 22137 if (transformToApply != null) { 22138 if (concatMatrix) { 22139 if (drawingWithRenderNode) { 22140 renderNode.setAnimationMatrix(transformToApply.getMatrix()); 22141 } else { 22142 // Undo the scroll translation, apply the transformation matrix, 22143 // then redo the scroll translate to get the correct result. 22144 canvas.translate(-transX, -transY); 22145 canvas.concat(transformToApply.getMatrix()); 22146 canvas.translate(transX, transY); 22147 } 22148 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 22149 } 22150 22151 float transformAlpha = transformToApply.getAlpha(); 22152 if (transformAlpha < 1) { 22153 alpha *= transformAlpha; 22154 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 22155 } 22156 } 22157 22158 if (!childHasIdentityMatrix && !drawingWithRenderNode) { 22159 canvas.translate(-transX, -transY); 22160 canvas.concat(getMatrix()); 22161 canvas.translate(transX, transY); 22162 } 22163 } 22164 22165 // Deal with alpha if it is or used to be <1 22166 if (alpha < 1 || (mPrivateFlags3 & PFLAG3_VIEW_IS_ANIMATING_ALPHA) != 0) { 22167 if (alpha < 1) { 22168 mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_ALPHA; 22169 } else { 22170 mPrivateFlags3 &= ~PFLAG3_VIEW_IS_ANIMATING_ALPHA; 22171 } 22172 parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; 22173 if (!drawingWithDrawingCache) { 22174 final int multipliedAlpha = (int) (255 * alpha); 22175 if (!onSetAlpha(multipliedAlpha)) { 22176 if (drawingWithRenderNode) { 22177 renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha()); 22178 } else if (layerType == LAYER_TYPE_NONE) { 22179 canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(), 22180 multipliedAlpha); 22181 } 22182 } else { 22183 // Alpha is handled by the child directly, clobber the layer's alpha 22184 mPrivateFlags |= PFLAG_ALPHA_SET; 22185 } 22186 } 22187 } 22188 } else if ((mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 22189 onSetAlpha(255); 22190 mPrivateFlags &= ~PFLAG_ALPHA_SET; 22191 } 22192 22193 if (!drawingWithRenderNode) { 22194 // apply clips directly, since RenderNode won't do it for this draw 22195 if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0 && cache == null) { 22196 if (offsetForScroll) { 22197 canvas.clipRect(sx, sy, sx + getWidth(), sy + getHeight()); 22198 } else { 22199 if (!scalingRequired || cache == null) { 22200 canvas.clipRect(0, 0, getWidth(), getHeight()); 22201 } else { 22202 canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight()); 22203 } 22204 } 22205 } 22206 22207 if (mClipBounds != null) { 22208 // clip bounds ignore scroll 22209 canvas.clipRect(mClipBounds); 22210 } 22211 } 22212 22213 if (!drawingWithDrawingCache) { 22214 if (drawingWithRenderNode) { 22215 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22216 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 22217 } else { 22218 // Fast path for layouts with no backgrounds 22219 if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) { 22220 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22221 dispatchDraw(canvas); 22222 } else { 22223 draw(canvas); 22224 } 22225 } 22226 } else if (cache != null) { 22227 mPrivateFlags &= ~PFLAG_DIRTY_MASK; 22228 if (layerType == LAYER_TYPE_NONE || mLayerPaint == null) { 22229 // no layer paint, use temporary paint to draw bitmap 22230 Paint cachePaint = parent.mCachePaint; 22231 if (cachePaint == null) { 22232 cachePaint = new Paint(); 22233 cachePaint.setDither(false); 22234 parent.mCachePaint = cachePaint; 22235 } 22236 cachePaint.setAlpha((int) (alpha * 255)); 22237 canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint); 22238 } else { 22239 // use layer paint to draw the bitmap, merging the two alphas, but also restore 22240 int layerPaintAlpha = mLayerPaint.getAlpha(); 22241 if (alpha < 1) { 22242 mLayerPaint.setAlpha((int) (alpha * layerPaintAlpha)); 22243 } 22244 canvas.drawBitmap(cache, 0.0f, 0.0f, mLayerPaint); 22245 if (alpha < 1) { 22246 mLayerPaint.setAlpha(layerPaintAlpha); 22247 } 22248 } 22249 } 22250 22251 if (restoreTo >= 0) { 22252 canvas.restoreToCount(restoreTo); 22253 } 22254 22255 if (a != null && !more) { 22256 if (!hardwareAcceleratedCanvas && !a.getFillAfter()) { 22257 onSetAlpha(255); 22258 } 22259 parent.finishAnimatingView(this, a); 22260 } 22261 22262 if (more && hardwareAcceleratedCanvas) { 22263 if (a.hasAlpha() && (mPrivateFlags & PFLAG_ALPHA_SET) == PFLAG_ALPHA_SET) { 22264 // alpha animations should cause the child to recreate its display list 22265 invalidate(true); 22266 } 22267 } 22268 22269 mRecreateDisplayList = false; 22270 22271 return more; 22272 } 22273 getDebugPaint()22274 static Paint getDebugPaint() { 22275 if (sDebugPaint == null) { 22276 sDebugPaint = new Paint(); 22277 sDebugPaint.setAntiAlias(false); 22278 } 22279 return sDebugPaint; 22280 } 22281 dipsToPixels(int dips)22282 final int dipsToPixels(int dips) { 22283 float scale = getContext().getResources().getDisplayMetrics().density; 22284 return (int) (dips * scale + 0.5f); 22285 } 22286 debugDrawFocus(Canvas canvas)22287 final private void debugDrawFocus(Canvas canvas) { 22288 if (isFocused()) { 22289 final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP); 22290 final int l = mScrollX; 22291 final int r = l + mRight - mLeft; 22292 final int t = mScrollY; 22293 final int b = t + mBottom - mTop; 22294 22295 final Paint paint = getDebugPaint(); 22296 paint.setColor(DEBUG_CORNERS_COLOR); 22297 22298 // Draw squares in corners. 22299 paint.setStyle(Paint.Style.FILL); 22300 canvas.drawRect(l, t, l + cornerSquareSize, t + cornerSquareSize, paint); 22301 canvas.drawRect(r - cornerSquareSize, t, r, t + cornerSquareSize, paint); 22302 canvas.drawRect(l, b - cornerSquareSize, l + cornerSquareSize, b, paint); 22303 canvas.drawRect(r - cornerSquareSize, b - cornerSquareSize, r, b, paint); 22304 22305 // Draw big X across the view. 22306 paint.setStyle(Paint.Style.STROKE); 22307 canvas.drawLine(l, t, r, b, paint); 22308 canvas.drawLine(l, b, r, t, paint); 22309 } 22310 } 22311 22312 /** 22313 * Manually render this view (and all of its children) to the given Canvas. 22314 * The view must have already done a full layout before this function is 22315 * called. When implementing a view, implement 22316 * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 22317 * If you do need to override this method, call the superclass version. 22318 * 22319 * @param canvas The Canvas to which the View is rendered. 22320 */ 22321 @CallSuper draw(Canvas canvas)22322 public void draw(Canvas canvas) { 22323 final int privateFlags = mPrivateFlags; 22324 mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; 22325 22326 /* 22327 * Draw traversal performs several drawing steps which must be executed 22328 * in the appropriate order: 22329 * 22330 * 1. Draw the background 22331 * 2. If necessary, save the canvas' layers to prepare for fading 22332 * 3. Draw view's content 22333 * 4. Draw children 22334 * 5. If necessary, draw the fading edges and restore layers 22335 * 6. Draw decorations (scrollbars for instance) 22336 * 7. If necessary, draw the default focus highlight 22337 */ 22338 22339 // Step 1, draw the background, if needed 22340 int saveCount; 22341 22342 drawBackground(canvas); 22343 22344 // skip step 2 & 5 if possible (common case) 22345 final int viewFlags = mViewFlags; 22346 boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0; 22347 boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0; 22348 if (!verticalEdges && !horizontalEdges) { 22349 // Step 3, draw the content 22350 onDraw(canvas); 22351 22352 // Step 4, draw the children 22353 dispatchDraw(canvas); 22354 22355 drawAutofilledHighlight(canvas); 22356 22357 // Overlay is part of the content and draws beneath Foreground 22358 if (mOverlay != null && !mOverlay.isEmpty()) { 22359 mOverlay.getOverlayView().dispatchDraw(canvas); 22360 } 22361 22362 // Step 6, draw decorations (foreground, scrollbars) 22363 onDrawForeground(canvas); 22364 22365 // Step 7, draw the default focus highlight 22366 drawDefaultFocusHighlight(canvas); 22367 22368 if (isShowingLayoutBounds()) { 22369 debugDrawFocus(canvas); 22370 } 22371 22372 // we're done... 22373 return; 22374 } 22375 22376 /* 22377 * Here we do the full fledged routine... 22378 * (this is an uncommon case where speed matters less, 22379 * this is why we repeat some of the tests that have been 22380 * done above) 22381 */ 22382 22383 boolean drawTop = false; 22384 boolean drawBottom = false; 22385 boolean drawLeft = false; 22386 boolean drawRight = false; 22387 22388 float topFadeStrength = 0.0f; 22389 float bottomFadeStrength = 0.0f; 22390 float leftFadeStrength = 0.0f; 22391 float rightFadeStrength = 0.0f; 22392 22393 // Step 2, save the canvas' layers 22394 int paddingLeft = mPaddingLeft; 22395 22396 final boolean offsetRequired = isPaddingOffsetRequired(); 22397 if (offsetRequired) { 22398 paddingLeft += getLeftPaddingOffset(); 22399 } 22400 22401 int left = mScrollX + paddingLeft; 22402 int right = left + mRight - mLeft - mPaddingRight - paddingLeft; 22403 int top = mScrollY + getFadeTop(offsetRequired); 22404 int bottom = top + getFadeHeight(offsetRequired); 22405 22406 if (offsetRequired) { 22407 right += getRightPaddingOffset(); 22408 bottom += getBottomPaddingOffset(); 22409 } 22410 22411 final ScrollabilityCache scrollabilityCache = mScrollCache; 22412 final float fadeHeight = scrollabilityCache.fadingEdgeLength; 22413 int length = (int) fadeHeight; 22414 22415 // clip the fade length if top and bottom fades overlap 22416 // overlapping fades produce odd-looking artifacts 22417 if (verticalEdges && (top + length > bottom - length)) { 22418 length = (bottom - top) / 2; 22419 } 22420 22421 // also clip horizontal fades if necessary 22422 if (horizontalEdges && (left + length > right - length)) { 22423 length = (right - left) / 2; 22424 } 22425 22426 if (verticalEdges) { 22427 topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength())); 22428 drawTop = topFadeStrength * fadeHeight > 1.0f; 22429 bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength())); 22430 drawBottom = bottomFadeStrength * fadeHeight > 1.0f; 22431 } 22432 22433 if (horizontalEdges) { 22434 leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength())); 22435 drawLeft = leftFadeStrength * fadeHeight > 1.0f; 22436 rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength())); 22437 drawRight = rightFadeStrength * fadeHeight > 1.0f; 22438 } 22439 22440 saveCount = canvas.getSaveCount(); 22441 int topSaveCount = -1; 22442 int bottomSaveCount = -1; 22443 int leftSaveCount = -1; 22444 int rightSaveCount = -1; 22445 22446 int solidColor = getSolidColor(); 22447 if (solidColor == 0) { 22448 if (drawTop) { 22449 topSaveCount = canvas.saveUnclippedLayer(left, top, right, top + length); 22450 } 22451 22452 if (drawBottom) { 22453 bottomSaveCount = canvas.saveUnclippedLayer(left, bottom - length, right, bottom); 22454 } 22455 22456 if (drawLeft) { 22457 leftSaveCount = canvas.saveUnclippedLayer(left, top, left + length, bottom); 22458 } 22459 22460 if (drawRight) { 22461 rightSaveCount = canvas.saveUnclippedLayer(right - length, top, right, bottom); 22462 } 22463 } else { 22464 scrollabilityCache.setFadeColor(solidColor); 22465 } 22466 22467 // Step 3, draw the content 22468 onDraw(canvas); 22469 22470 // Step 4, draw the children 22471 dispatchDraw(canvas); 22472 22473 // Step 5, draw the fade effect and restore layers 22474 final Paint p = scrollabilityCache.paint; 22475 final Matrix matrix = scrollabilityCache.matrix; 22476 final Shader fade = scrollabilityCache.shader; 22477 22478 // must be restored in the reverse order that they were saved 22479 if (drawRight) { 22480 matrix.setScale(1, fadeHeight * rightFadeStrength); 22481 matrix.postRotate(90); 22482 matrix.postTranslate(right, top); 22483 fade.setLocalMatrix(matrix); 22484 p.setShader(fade); 22485 if (solidColor == 0) { 22486 canvas.restoreUnclippedLayer(rightSaveCount, p); 22487 22488 } else { 22489 canvas.drawRect(right - length, top, right, bottom, p); 22490 } 22491 } 22492 22493 if (drawLeft) { 22494 matrix.setScale(1, fadeHeight * leftFadeStrength); 22495 matrix.postRotate(-90); 22496 matrix.postTranslate(left, top); 22497 fade.setLocalMatrix(matrix); 22498 p.setShader(fade); 22499 if (solidColor == 0) { 22500 canvas.restoreUnclippedLayer(leftSaveCount, p); 22501 } else { 22502 canvas.drawRect(left, top, left + length, bottom, p); 22503 } 22504 } 22505 22506 if (drawBottom) { 22507 matrix.setScale(1, fadeHeight * bottomFadeStrength); 22508 matrix.postRotate(180); 22509 matrix.postTranslate(left, bottom); 22510 fade.setLocalMatrix(matrix); 22511 p.setShader(fade); 22512 if (solidColor == 0) { 22513 canvas.restoreUnclippedLayer(bottomSaveCount, p); 22514 } else { 22515 canvas.drawRect(left, bottom - length, right, bottom, p); 22516 } 22517 } 22518 22519 if (drawTop) { 22520 matrix.setScale(1, fadeHeight * topFadeStrength); 22521 matrix.postTranslate(left, top); 22522 fade.setLocalMatrix(matrix); 22523 p.setShader(fade); 22524 if (solidColor == 0) { 22525 canvas.restoreUnclippedLayer(topSaveCount, p); 22526 } else { 22527 canvas.drawRect(left, top, right, top + length, p); 22528 } 22529 } 22530 22531 canvas.restoreToCount(saveCount); 22532 22533 drawAutofilledHighlight(canvas); 22534 22535 // Overlay is part of the content and draws beneath Foreground 22536 if (mOverlay != null && !mOverlay.isEmpty()) { 22537 mOverlay.getOverlayView().dispatchDraw(canvas); 22538 } 22539 22540 // Step 6, draw decorations (foreground, scrollbars) 22541 onDrawForeground(canvas); 22542 22543 // Step 7, draw the default focus highlight 22544 drawDefaultFocusHighlight(canvas); 22545 22546 if (isShowingLayoutBounds()) { 22547 debugDrawFocus(canvas); 22548 } 22549 } 22550 22551 /** 22552 * Draws the background onto the specified canvas. 22553 * 22554 * @param canvas Canvas on which to draw the background 22555 */ 22556 @UnsupportedAppUsage drawBackground(Canvas canvas)22557 private void drawBackground(Canvas canvas) { 22558 final Drawable background = mBackground; 22559 if (background == null) { 22560 return; 22561 } 22562 22563 setBackgroundBounds(); 22564 22565 // Attempt to use a display list if requested. 22566 if (canvas.isHardwareAccelerated() && mAttachInfo != null 22567 && mAttachInfo.mThreadedRenderer != null) { 22568 mBackgroundRenderNode = getDrawableRenderNode(background, mBackgroundRenderNode); 22569 22570 final RenderNode renderNode = mBackgroundRenderNode; 22571 if (renderNode != null && renderNode.hasDisplayList()) { 22572 setBackgroundRenderNodeProperties(renderNode); 22573 ((RecordingCanvas) canvas).drawRenderNode(renderNode); 22574 return; 22575 } 22576 } 22577 22578 final int scrollX = mScrollX; 22579 final int scrollY = mScrollY; 22580 if ((scrollX | scrollY) == 0) { 22581 background.draw(canvas); 22582 } else { 22583 canvas.translate(scrollX, scrollY); 22584 background.draw(canvas); 22585 canvas.translate(-scrollX, -scrollY); 22586 } 22587 } 22588 22589 /** 22590 * Sets the correct background bounds and rebuilds the outline, if needed. 22591 * <p/> 22592 * This is called by LayoutLib. 22593 */ setBackgroundBounds()22594 void setBackgroundBounds() { 22595 if (mBackgroundSizeChanged && mBackground != null) { 22596 mBackground.setBounds(0, 0, mRight - mLeft, mBottom - mTop); 22597 mBackgroundSizeChanged = false; 22598 rebuildOutline(); 22599 } 22600 } 22601 setBackgroundRenderNodeProperties(RenderNode renderNode)22602 private void setBackgroundRenderNodeProperties(RenderNode renderNode) { 22603 renderNode.setTranslationX(mScrollX); 22604 renderNode.setTranslationY(mScrollY); 22605 } 22606 22607 /** 22608 * Creates a new display list or updates the existing display list for the 22609 * specified Drawable. 22610 * 22611 * @param drawable Drawable for which to create a display list 22612 * @param renderNode Existing RenderNode, or {@code null} 22613 * @return A valid display list for the specified drawable 22614 */ getDrawableRenderNode(Drawable drawable, RenderNode renderNode)22615 private RenderNode getDrawableRenderNode(Drawable drawable, RenderNode renderNode) { 22616 if (renderNode == null) { 22617 renderNode = RenderNode.create(drawable.getClass().getName(), 22618 new ViewAnimationHostBridge(this)); 22619 renderNode.setUsageHint(RenderNode.USAGE_BACKGROUND); 22620 } 22621 22622 final Rect bounds = drawable.getBounds(); 22623 final int width = bounds.width(); 22624 final int height = bounds.height(); 22625 final RecordingCanvas canvas = renderNode.beginRecording(width, height); 22626 22627 // Reverse left/top translation done by drawable canvas, which will 22628 // instead be applied by rendernode's LTRB bounds below. This way, the 22629 // drawable's bounds match with its rendernode bounds and its content 22630 // will lie within those bounds in the rendernode tree. 22631 canvas.translate(-bounds.left, -bounds.top); 22632 22633 try { 22634 drawable.draw(canvas); 22635 } finally { 22636 renderNode.endRecording(); 22637 } 22638 22639 // Set up drawable properties that are view-independent. 22640 renderNode.setLeftTopRightBottom(bounds.left, bounds.top, bounds.right, bounds.bottom); 22641 renderNode.setProjectBackwards(drawable.isProjected()); 22642 renderNode.setProjectionReceiver(true); 22643 renderNode.setClipToBounds(false); 22644 return renderNode; 22645 } 22646 22647 /** 22648 * Returns the overlay for this view, creating it if it does not yet exist. 22649 * Adding drawables to the overlay will cause them to be displayed whenever 22650 * the view itself is redrawn. Objects in the overlay should be actively 22651 * managed: remove them when they should not be displayed anymore. The 22652 * overlay will always have the same size as its host view. 22653 * 22654 * <p>Note: Overlays do not currently work correctly with {@link 22655 * SurfaceView} or {@link TextureView}; contents in overlays for these 22656 * types of views may not display correctly.</p> 22657 * 22658 * @return The ViewOverlay object for this view. 22659 * @see ViewOverlay 22660 */ getOverlay()22661 public ViewOverlay getOverlay() { 22662 if (mOverlay == null) { 22663 mOverlay = new ViewOverlay(mContext, this); 22664 } 22665 return mOverlay; 22666 } 22667 22668 /** 22669 * Override this if your view is known to always be drawn on top of a solid color background, 22670 * and needs to draw fading edges. Returning a non-zero color enables the view system to 22671 * optimize the drawing of the fading edges. If you do return a non-zero color, the alpha 22672 * should be set to 0xFF. 22673 * 22674 * @see #setVerticalFadingEdgeEnabled(boolean) 22675 * @see #setHorizontalFadingEdgeEnabled(boolean) 22676 * 22677 * @return The known solid color background for this view, or 0 if the color may vary 22678 */ 22679 @ViewDebug.ExportedProperty(category = "drawing") 22680 @InspectableProperty 22681 @ColorInt getSolidColor()22682 public int getSolidColor() { 22683 return 0; 22684 } 22685 22686 /** 22687 * Build a human readable string representation of the specified view flags. 22688 * 22689 * @param flags the view flags to convert to a string 22690 * @return a String representing the supplied flags 22691 */ printFlags(int flags)22692 private static String printFlags(int flags) { 22693 String output = ""; 22694 int numFlags = 0; 22695 if ((flags & FOCUSABLE) == FOCUSABLE) { 22696 output += "TAKES_FOCUS"; 22697 numFlags++; 22698 } 22699 22700 switch (flags & VISIBILITY_MASK) { 22701 case INVISIBLE: 22702 if (numFlags > 0) { 22703 output += " "; 22704 } 22705 output += "INVISIBLE"; 22706 // USELESS HERE numFlags++; 22707 break; 22708 case GONE: 22709 if (numFlags > 0) { 22710 output += " "; 22711 } 22712 output += "GONE"; 22713 // USELESS HERE numFlags++; 22714 break; 22715 default: 22716 break; 22717 } 22718 return output; 22719 } 22720 22721 /** 22722 * Build a human readable string representation of the specified private 22723 * view flags. 22724 * 22725 * @param privateFlags the private view flags to convert to a string 22726 * @return a String representing the supplied flags 22727 */ printPrivateFlags(int privateFlags)22728 private static String printPrivateFlags(int privateFlags) { 22729 String output = ""; 22730 int numFlags = 0; 22731 22732 if ((privateFlags & PFLAG_WANTS_FOCUS) == PFLAG_WANTS_FOCUS) { 22733 output += "WANTS_FOCUS"; 22734 numFlags++; 22735 } 22736 22737 if ((privateFlags & PFLAG_FOCUSED) == PFLAG_FOCUSED) { 22738 if (numFlags > 0) { 22739 output += " "; 22740 } 22741 output += "FOCUSED"; 22742 numFlags++; 22743 } 22744 22745 if ((privateFlags & PFLAG_SELECTED) == PFLAG_SELECTED) { 22746 if (numFlags > 0) { 22747 output += " "; 22748 } 22749 output += "SELECTED"; 22750 numFlags++; 22751 } 22752 22753 if ((privateFlags & PFLAG_IS_ROOT_NAMESPACE) == PFLAG_IS_ROOT_NAMESPACE) { 22754 if (numFlags > 0) { 22755 output += " "; 22756 } 22757 output += "IS_ROOT_NAMESPACE"; 22758 numFlags++; 22759 } 22760 22761 if ((privateFlags & PFLAG_HAS_BOUNDS) == PFLAG_HAS_BOUNDS) { 22762 if (numFlags > 0) { 22763 output += " "; 22764 } 22765 output += "HAS_BOUNDS"; 22766 numFlags++; 22767 } 22768 22769 if ((privateFlags & PFLAG_DRAWN) == PFLAG_DRAWN) { 22770 if (numFlags > 0) { 22771 output += " "; 22772 } 22773 output += "DRAWN"; 22774 // USELESS HERE numFlags++; 22775 } 22776 return output; 22777 } 22778 22779 /** 22780 * <p>Indicates whether or not this view's layout will be requested during 22781 * the next hierarchy layout pass.</p> 22782 * 22783 * @return true if the layout will be forced during next layout pass 22784 */ isLayoutRequested()22785 public boolean isLayoutRequested() { 22786 return (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 22787 } 22788 22789 /** 22790 * Return true if o is a ViewGroup that is laying out using optical bounds. 22791 * @hide 22792 */ isLayoutModeOptical(Object o)22793 public static boolean isLayoutModeOptical(Object o) { 22794 return o instanceof ViewGroup && ((ViewGroup) o).isLayoutModeOptical(); 22795 } 22796 setOpticalFrame(int left, int top, int right, int bottom)22797 private boolean setOpticalFrame(int left, int top, int right, int bottom) { 22798 Insets parentInsets = mParent instanceof View ? 22799 ((View) mParent).getOpticalInsets() : Insets.NONE; 22800 Insets childInsets = getOpticalInsets(); 22801 return setFrame( 22802 left + parentInsets.left - childInsets.left, 22803 top + parentInsets.top - childInsets.top, 22804 right + parentInsets.left + childInsets.right, 22805 bottom + parentInsets.top + childInsets.bottom); 22806 } 22807 22808 /** 22809 * Assign a size and position to a view and all of its 22810 * descendants 22811 * 22812 * <p>This is the second phase of the layout mechanism. 22813 * (The first is measuring). In this phase, each parent calls 22814 * layout on all of its children to position them. 22815 * This is typically done using the child measurements 22816 * that were stored in the measure pass().</p> 22817 * 22818 * <p>Derived classes should not override this method. 22819 * Derived classes with children should override 22820 * onLayout. In that method, they should 22821 * call layout on each of their children.</p> 22822 * 22823 * @param l Left position, relative to parent 22824 * @param t Top position, relative to parent 22825 * @param r Right position, relative to parent 22826 * @param b Bottom position, relative to parent 22827 */ 22828 @SuppressWarnings({"unchecked"}) layout(int l, int t, int r, int b)22829 public void layout(int l, int t, int r, int b) { 22830 if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) { 22831 onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec); 22832 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 22833 } 22834 22835 int oldL = mLeft; 22836 int oldT = mTop; 22837 int oldB = mBottom; 22838 int oldR = mRight; 22839 22840 boolean changed = isLayoutModeOptical(mParent) ? 22841 setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b); 22842 22843 if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) { 22844 onLayout(changed, l, t, r, b); 22845 22846 if (shouldDrawRoundScrollbar()) { 22847 if(mRoundScrollbarRenderer == null) { 22848 mRoundScrollbarRenderer = new RoundScrollbarRenderer(this); 22849 } 22850 } else { 22851 mRoundScrollbarRenderer = null; 22852 } 22853 22854 mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED; 22855 22856 ListenerInfo li = mListenerInfo; 22857 if (li != null && li.mOnLayoutChangeListeners != null) { 22858 ArrayList<OnLayoutChangeListener> listenersCopy = 22859 (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone(); 22860 int numListeners = listenersCopy.size(); 22861 for (int i = 0; i < numListeners; ++i) { 22862 listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB); 22863 } 22864 } 22865 } 22866 22867 final boolean wasLayoutValid = isLayoutValid(); 22868 22869 mPrivateFlags &= ~PFLAG_FORCE_LAYOUT; 22870 mPrivateFlags3 |= PFLAG3_IS_LAID_OUT; 22871 22872 if (!wasLayoutValid && isFocused()) { 22873 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 22874 if (canTakeFocus()) { 22875 // We have a robust focus, so parents should no longer be wanting focus. 22876 clearParentsWantFocus(); 22877 } else if (getViewRootImpl() == null || !getViewRootImpl().isInLayout()) { 22878 // This is a weird case. Most-likely the user, rather than ViewRootImpl, called 22879 // layout. In this case, there's no guarantee that parent layouts will be evaluated 22880 // and thus the safest action is to clear focus here. 22881 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 22882 clearParentsWantFocus(); 22883 } else if (!hasParentWantsFocus()) { 22884 // original requestFocus was likely on this view directly, so just clear focus 22885 clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 22886 } 22887 // otherwise, we let parents handle re-assigning focus during their layout passes. 22888 } else if ((mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 22889 mPrivateFlags &= ~PFLAG_WANTS_FOCUS; 22890 View focused = findFocus(); 22891 if (focused != null) { 22892 // Try to restore focus as close as possible to our starting focus. 22893 if (!restoreDefaultFocus() && !hasParentWantsFocus()) { 22894 // Give up and clear focus once we've reached the top-most parent which wants 22895 // focus. 22896 focused.clearFocusInternal(null, /* propagate */ true, /* refocus */ false); 22897 } 22898 } 22899 } 22900 22901 if ((mPrivateFlags3 & PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT) != 0) { 22902 mPrivateFlags3 &= ~PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT; 22903 notifyEnterOrExitForAutoFillIfNeeded(true); 22904 } 22905 22906 notifyAppearedOrDisappearedForContentCaptureIfNeeded(true); 22907 } 22908 hasParentWantsFocus()22909 private boolean hasParentWantsFocus() { 22910 ViewParent parent = mParent; 22911 while (parent instanceof ViewGroup) { 22912 ViewGroup pv = (ViewGroup) parent; 22913 if ((pv.mPrivateFlags & PFLAG_WANTS_FOCUS) != 0) { 22914 return true; 22915 } 22916 parent = pv.mParent; 22917 } 22918 return false; 22919 } 22920 22921 /** 22922 * Called from layout when this view should 22923 * assign a size and position to each of its children. 22924 * 22925 * Derived classes with children should override 22926 * this method and call layout on each of 22927 * their children. 22928 * @param changed This is a new size or position for this view 22929 * @param left Left position, relative to parent 22930 * @param top Top position, relative to parent 22931 * @param right Right position, relative to parent 22932 * @param bottom Bottom position, relative to parent 22933 */ onLayout(boolean changed, int left, int top, int right, int bottom)22934 protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 22935 } 22936 22937 /** 22938 * Assign a size and position to this view. 22939 * 22940 * This is called from layout. 22941 * 22942 * @param left Left position, relative to parent 22943 * @param top Top position, relative to parent 22944 * @param right Right position, relative to parent 22945 * @param bottom Bottom position, relative to parent 22946 * @return true if the new size and position are different than the 22947 * previous ones 22948 * {@hide} 22949 */ 22950 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) setFrame(int left, int top, int right, int bottom)22951 protected boolean setFrame(int left, int top, int right, int bottom) { 22952 boolean changed = false; 22953 22954 if (DBG) { 22955 Log.d(VIEW_LOG_TAG, this + " View.setFrame(" + left + "," + top + "," 22956 + right + "," + bottom + ")"); 22957 } 22958 22959 if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) { 22960 changed = true; 22961 22962 // Remember our drawn bit 22963 int drawn = mPrivateFlags & PFLAG_DRAWN; 22964 22965 int oldWidth = mRight - mLeft; 22966 int oldHeight = mBottom - mTop; 22967 int newWidth = right - left; 22968 int newHeight = bottom - top; 22969 boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight); 22970 22971 // Invalidate our old position 22972 invalidate(sizeChanged); 22973 22974 mLeft = left; 22975 mTop = top; 22976 mRight = right; 22977 mBottom = bottom; 22978 mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); 22979 22980 mPrivateFlags |= PFLAG_HAS_BOUNDS; 22981 22982 22983 if (sizeChanged) { 22984 sizeChange(newWidth, newHeight, oldWidth, oldHeight); 22985 } 22986 22987 if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { 22988 // If we are visible, force the DRAWN bit to on so that 22989 // this invalidate will go through (at least to our parent). 22990 // This is because someone may have invalidated this view 22991 // before this call to setFrame came in, thereby clearing 22992 // the DRAWN bit. 22993 mPrivateFlags |= PFLAG_DRAWN; 22994 invalidate(sizeChanged); 22995 // parent display list may need to be recreated based on a change in the bounds 22996 // of any child 22997 invalidateParentCaches(); 22998 } 22999 23000 // Reset drawn bit to original value (invalidate turns it off) 23001 mPrivateFlags |= drawn; 23002 23003 mBackgroundSizeChanged = true; 23004 mDefaultFocusHighlightSizeChanged = true; 23005 if (mForegroundInfo != null) { 23006 mForegroundInfo.mBoundsChanged = true; 23007 } 23008 23009 notifySubtreeAccessibilityStateChangedIfNeeded(); 23010 } 23011 return changed; 23012 } 23013 23014 /** 23015 * Assign a size and position to this view. 23016 * 23017 * This method is meant to be used in animations only as it applies this position and size 23018 * for the view only temporary and it can be changed back at any time by the layout. 23019 * 23020 * @param left Left position, relative to parent 23021 * @param top Top position, relative to parent 23022 * @param right Right position, relative to parent 23023 * @param bottom Bottom position, relative to parent 23024 * 23025 * @see #setLeft(int), #setRight(int), #setTop(int), #setBottom(int) 23026 */ setLeftTopRightBottom(int left, int top, int right, int bottom)23027 public final void setLeftTopRightBottom(int left, int top, int right, int bottom) { 23028 setFrame(left, top, right, bottom); 23029 } 23030 sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight)23031 private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { 23032 onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); 23033 if (mOverlay != null) { 23034 mOverlay.getOverlayView().setRight(newWidth); 23035 mOverlay.getOverlayView().setBottom(newHeight); 23036 } 23037 // If this isn't laid out yet, focus assignment will be handled during the "deferment/ 23038 // backtracking" of requestFocus during layout, so don't touch focus here. 23039 if (!sCanFocusZeroSized && isLayoutValid() 23040 // Don't touch focus if animating 23041 && !(mParent instanceof ViewGroup && ((ViewGroup) mParent).isLayoutSuppressed())) { 23042 if (newWidth <= 0 || newHeight <= 0) { 23043 if (hasFocus()) { 23044 clearFocus(); 23045 if (mParent instanceof ViewGroup) { 23046 ((ViewGroup) mParent).clearFocusedInCluster(); 23047 } 23048 } 23049 clearAccessibilityFocus(); 23050 } else if (oldWidth <= 0 || oldHeight <= 0) { 23051 if (mParent != null && canTakeFocus()) { 23052 mParent.focusableViewAvailable(this); 23053 } 23054 } 23055 } 23056 rebuildOutline(); 23057 } 23058 23059 /** 23060 * Finalize inflating a view from XML. This is called as the last phase 23061 * of inflation, after all child views have been added. 23062 * 23063 * <p>Even if the subclass overrides onFinishInflate, they should always be 23064 * sure to call the super method, so that we get called. 23065 */ 23066 @CallSuper onFinishInflate()23067 protected void onFinishInflate() { 23068 } 23069 23070 /** 23071 * Returns the resources associated with this view. 23072 * 23073 * @return Resources object. 23074 */ getResources()23075 public Resources getResources() { 23076 return mResources; 23077 } 23078 23079 /** 23080 * Invalidates the specified Drawable. 23081 * 23082 * @param drawable the drawable to invalidate 23083 */ 23084 @Override invalidateDrawable(@onNull Drawable drawable)23085 public void invalidateDrawable(@NonNull Drawable drawable) { 23086 if (verifyDrawable(drawable)) { 23087 final Rect dirty = drawable.getDirtyBounds(); 23088 final int scrollX = mScrollX; 23089 final int scrollY = mScrollY; 23090 23091 invalidate(dirty.left + scrollX, dirty.top + scrollY, 23092 dirty.right + scrollX, dirty.bottom + scrollY); 23093 rebuildOutline(); 23094 } 23095 } 23096 23097 /** 23098 * Schedules an action on a drawable to occur at a specified time. 23099 * 23100 * @param who the recipient of the action 23101 * @param what the action to run on the drawable 23102 * @param when the time at which the action must occur. Uses the 23103 * {@link SystemClock#uptimeMillis} timebase. 23104 */ 23105 @Override scheduleDrawable(@onNull Drawable who, @NonNull Runnable what, long when)23106 public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when) { 23107 if (verifyDrawable(who) && what != null) { 23108 final long delay = when - SystemClock.uptimeMillis(); 23109 if (mAttachInfo != null) { 23110 mAttachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed( 23111 Choreographer.CALLBACK_ANIMATION, what, who, 23112 Choreographer.subtractFrameDelay(delay)); 23113 } else { 23114 // Postpone the runnable until we know 23115 // on which thread it needs to run. 23116 getRunQueue().postDelayed(what, delay); 23117 } 23118 } 23119 } 23120 23121 /** 23122 * Cancels a scheduled action on a drawable. 23123 * 23124 * @param who the recipient of the action 23125 * @param what the action to cancel 23126 */ 23127 @Override unscheduleDrawable(@onNull Drawable who, @NonNull Runnable what)23128 public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what) { 23129 if (verifyDrawable(who) && what != null) { 23130 if (mAttachInfo != null) { 23131 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 23132 Choreographer.CALLBACK_ANIMATION, what, who); 23133 } 23134 getRunQueue().removeCallbacks(what); 23135 } 23136 } 23137 23138 /** 23139 * Unschedule any events associated with the given Drawable. This can be 23140 * used when selecting a new Drawable into a view, so that the previous 23141 * one is completely unscheduled. 23142 * 23143 * @param who The Drawable to unschedule. 23144 * 23145 * @see #drawableStateChanged 23146 */ unscheduleDrawable(Drawable who)23147 public void unscheduleDrawable(Drawable who) { 23148 if (mAttachInfo != null && who != null) { 23149 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks( 23150 Choreographer.CALLBACK_ANIMATION, null, who); 23151 } 23152 } 23153 23154 /** 23155 * Resolve the Drawables depending on the layout direction. This is implicitly supposing 23156 * that the View directionality can and will be resolved before its Drawables. 23157 * 23158 * Will call {@link View#onResolveDrawables} when resolution is done. 23159 * 23160 * @hide 23161 */ resolveDrawables()23162 protected void resolveDrawables() { 23163 // Drawables resolution may need to happen before resolving the layout direction (which is 23164 // done only during the measure() call). 23165 // If the layout direction is not resolved yet, we cannot resolve the Drawables except in 23166 // one case: when the raw layout direction has not been defined as LAYOUT_DIRECTION_INHERIT. 23167 // So, if the raw layout direction is LAYOUT_DIRECTION_LTR or LAYOUT_DIRECTION_RTL or 23168 // LAYOUT_DIRECTION_LOCALE, we can "cheat" and we don't need to wait for the layout 23169 // direction to be resolved as its resolved value will be the same as its raw value. 23170 if (!isLayoutDirectionResolved() && 23171 getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT) { 23172 return; 23173 } 23174 23175 final int layoutDirection = isLayoutDirectionResolved() ? 23176 getLayoutDirection() : getRawLayoutDirection(); 23177 23178 if (mBackground != null) { 23179 mBackground.setLayoutDirection(layoutDirection); 23180 } 23181 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 23182 mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); 23183 } 23184 if (mDefaultFocusHighlight != null) { 23185 mDefaultFocusHighlight.setLayoutDirection(layoutDirection); 23186 } 23187 mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; 23188 onResolveDrawables(layoutDirection); 23189 } 23190 areDrawablesResolved()23191 boolean areDrawablesResolved() { 23192 return (mPrivateFlags2 & PFLAG2_DRAWABLE_RESOLVED) == PFLAG2_DRAWABLE_RESOLVED; 23193 } 23194 23195 /** 23196 * Called when layout direction has been resolved. 23197 * 23198 * The default implementation does nothing. 23199 * 23200 * @param layoutDirection The resolved layout direction. 23201 * 23202 * @see #LAYOUT_DIRECTION_LTR 23203 * @see #LAYOUT_DIRECTION_RTL 23204 * 23205 * @hide 23206 */ onResolveDrawables(@esolvedLayoutDir int layoutDirection)23207 public void onResolveDrawables(@ResolvedLayoutDir int layoutDirection) { 23208 } 23209 23210 /** 23211 * @hide 23212 */ 23213 @TestApi resetResolvedDrawables()23214 protected void resetResolvedDrawables() { 23215 resetResolvedDrawablesInternal(); 23216 } 23217 resetResolvedDrawablesInternal()23218 void resetResolvedDrawablesInternal() { 23219 mPrivateFlags2 &= ~PFLAG2_DRAWABLE_RESOLVED; 23220 } 23221 23222 /** 23223 * If your view subclass is displaying its own Drawable objects, it should 23224 * override this function and return true for any Drawable it is 23225 * displaying. This allows animations for those drawables to be 23226 * scheduled. 23227 * 23228 * <p>Be sure to call through to the super class when overriding this 23229 * function. 23230 * 23231 * @param who The Drawable to verify. Return true if it is one you are 23232 * displaying, else return the result of calling through to the 23233 * super class. 23234 * 23235 * @return boolean If true than the Drawable is being displayed in the 23236 * view; else false and it is not allowed to animate. 23237 * 23238 * @see #unscheduleDrawable(android.graphics.drawable.Drawable) 23239 * @see #drawableStateChanged() 23240 */ 23241 @CallSuper verifyDrawable(@onNull Drawable who)23242 protected boolean verifyDrawable(@NonNull Drawable who) { 23243 // Avoid verifying the scroll bar drawable so that we don't end up in 23244 // an invalidation loop. This effectively prevents the scroll bar 23245 // drawable from triggering invalidations and scheduling runnables. 23246 return who == mBackground || (mForegroundInfo != null && mForegroundInfo.mDrawable == who) 23247 || (mDefaultFocusHighlight == who); 23248 } 23249 23250 /** 23251 * This function is called whenever the state of the view changes in such 23252 * a way that it impacts the state of drawables being shown. 23253 * <p> 23254 * If the View has a StateListAnimator, it will also be called to run necessary state 23255 * change animations. 23256 * <p> 23257 * Be sure to call through to the superclass when overriding this function. 23258 * 23259 * @see Drawable#setState(int[]) 23260 */ 23261 @CallSuper drawableStateChanged()23262 protected void drawableStateChanged() { 23263 final int[] state = getDrawableState(); 23264 boolean changed = false; 23265 23266 final Drawable bg = mBackground; 23267 if (bg != null && bg.isStateful()) { 23268 changed |= bg.setState(state); 23269 } 23270 23271 final Drawable hl = mDefaultFocusHighlight; 23272 if (hl != null && hl.isStateful()) { 23273 changed |= hl.setState(state); 23274 } 23275 23276 final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 23277 if (fg != null && fg.isStateful()) { 23278 changed |= fg.setState(state); 23279 } 23280 23281 if (mScrollCache != null) { 23282 final Drawable scrollBar = mScrollCache.scrollBar; 23283 if (scrollBar != null && scrollBar.isStateful()) { 23284 changed |= scrollBar.setState(state) 23285 && mScrollCache.state != ScrollabilityCache.OFF; 23286 } 23287 } 23288 23289 if (mStateListAnimator != null) { 23290 mStateListAnimator.setState(state); 23291 } 23292 23293 if (changed) { 23294 invalidate(); 23295 } 23296 } 23297 23298 /** 23299 * This function is called whenever the view hotspot changes and needs to 23300 * be propagated to drawables or child views managed by the view. 23301 * <p> 23302 * Dispatching to child views is handled by 23303 * {@link #dispatchDrawableHotspotChanged(float, float)}. 23304 * <p> 23305 * Be sure to call through to the superclass when overriding this function. 23306 * 23307 * @param x hotspot x coordinate 23308 * @param y hotspot y coordinate 23309 */ 23310 @CallSuper drawableHotspotChanged(float x, float y)23311 public void drawableHotspotChanged(float x, float y) { 23312 if (mBackground != null) { 23313 mBackground.setHotspot(x, y); 23314 } 23315 if (mDefaultFocusHighlight != null) { 23316 mDefaultFocusHighlight.setHotspot(x, y); 23317 } 23318 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 23319 mForegroundInfo.mDrawable.setHotspot(x, y); 23320 } 23321 23322 dispatchDrawableHotspotChanged(x, y); 23323 } 23324 23325 /** 23326 * Dispatches drawableHotspotChanged to all of this View's children. 23327 * 23328 * @param x hotspot x coordinate 23329 * @param y hotspot y coordinate 23330 * @see #drawableHotspotChanged(float, float) 23331 */ dispatchDrawableHotspotChanged(float x, float y)23332 public void dispatchDrawableHotspotChanged(float x, float y) { 23333 } 23334 23335 /** 23336 * Call this to force a view to update its drawable state. This will cause 23337 * drawableStateChanged to be called on this view. Views that are interested 23338 * in the new state should call getDrawableState. 23339 * 23340 * @see #drawableStateChanged 23341 * @see #getDrawableState 23342 */ refreshDrawableState()23343 public void refreshDrawableState() { 23344 mPrivateFlags |= PFLAG_DRAWABLE_STATE_DIRTY; 23345 drawableStateChanged(); 23346 23347 ViewParent parent = mParent; 23348 if (parent != null) { 23349 parent.childDrawableStateChanged(this); 23350 } 23351 } 23352 23353 /** 23354 * Create a default focus highlight if it doesn't exist. 23355 * @return a default focus highlight. 23356 */ getDefaultFocusHighlightDrawable()23357 private Drawable getDefaultFocusHighlightDrawable() { 23358 if (mDefaultFocusHighlightCache == null) { 23359 if (mContext != null) { 23360 final int[] attrs = new int[] { android.R.attr.selectableItemBackground }; 23361 final TypedArray ta = mContext.obtainStyledAttributes(attrs); 23362 mDefaultFocusHighlightCache = ta.getDrawable(0); 23363 ta.recycle(); 23364 } 23365 } 23366 return mDefaultFocusHighlightCache; 23367 } 23368 23369 /** 23370 * Set the current default focus highlight. 23371 * @param highlight the highlight drawable, or {@code null} if it's no longer needed. 23372 */ setDefaultFocusHighlight(Drawable highlight)23373 private void setDefaultFocusHighlight(Drawable highlight) { 23374 mDefaultFocusHighlight = highlight; 23375 mDefaultFocusHighlightSizeChanged = true; 23376 if (highlight != null) { 23377 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 23378 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 23379 } 23380 highlight.setLayoutDirection(getLayoutDirection()); 23381 if (highlight.isStateful()) { 23382 highlight.setState(getDrawableState()); 23383 } 23384 if (isAttachedToWindow()) { 23385 highlight.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 23386 } 23387 // Set callback last, since the view may still be initializing. 23388 highlight.setCallback(this); 23389 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 23390 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 23391 mPrivateFlags |= PFLAG_SKIP_DRAW; 23392 } 23393 invalidate(); 23394 } 23395 23396 /** 23397 * Check whether we need to draw a default focus highlight when this view gets focused, 23398 * which requires: 23399 * <ul> 23400 * <li>In both background and foreground, {@link android.R.attr#state_focused} 23401 * is not defined.</li> 23402 * <li>This view is not in touch mode.</li> 23403 * <li>This view doesn't opt out for a default focus highlight, via 23404 * {@link #setDefaultFocusHighlightEnabled(boolean)}.</li> 23405 * <li>This view is attached to window.</li> 23406 * </ul> 23407 * @return {@code true} if a default focus highlight is needed. 23408 * @hide 23409 */ 23410 @TestApi isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground)23411 public boolean isDefaultFocusHighlightNeeded(Drawable background, Drawable foreground) { 23412 final boolean lackFocusState = (background == null || !background.isStateful() 23413 || !background.hasFocusStateSpecified()) 23414 && (foreground == null || !foreground.isStateful() 23415 || !foreground.hasFocusStateSpecified()); 23416 return !isInTouchMode() && getDefaultFocusHighlightEnabled() && lackFocusState 23417 && isAttachedToWindow() && sUseDefaultFocusHighlight; 23418 } 23419 23420 /** 23421 * When this view is focused, switches on/off the default focused highlight. 23422 * <p> 23423 * This always happens when this view is focused, and only at this moment the default focus 23424 * highlight can be visible. 23425 */ switchDefaultFocusHighlight()23426 private void switchDefaultFocusHighlight() { 23427 if (isFocused()) { 23428 final boolean needed = isDefaultFocusHighlightNeeded(mBackground, 23429 mForegroundInfo == null ? null : mForegroundInfo.mDrawable); 23430 final boolean active = mDefaultFocusHighlight != null; 23431 if (needed && !active) { 23432 setDefaultFocusHighlight(getDefaultFocusHighlightDrawable()); 23433 } else if (!needed && active) { 23434 // The highlight is no longer needed, so tear it down. 23435 setDefaultFocusHighlight(null); 23436 } 23437 } 23438 } 23439 23440 /** 23441 * Draw the default focus highlight onto the canvas if there is one and this view is focused. 23442 * @param canvas the canvas where we're drawing the highlight. 23443 */ drawDefaultFocusHighlight(Canvas canvas)23444 private void drawDefaultFocusHighlight(Canvas canvas) { 23445 if (mDefaultFocusHighlight != null && isFocused()) { 23446 if (mDefaultFocusHighlightSizeChanged) { 23447 mDefaultFocusHighlightSizeChanged = false; 23448 final int l = mScrollX; 23449 final int r = l + mRight - mLeft; 23450 final int t = mScrollY; 23451 final int b = t + mBottom - mTop; 23452 mDefaultFocusHighlight.setBounds(l, t, r, b); 23453 } 23454 mDefaultFocusHighlight.draw(canvas); 23455 } 23456 } 23457 23458 /** 23459 * Return an array of resource IDs of the drawable states representing the 23460 * current state of the view. 23461 * 23462 * @return The current drawable state 23463 * 23464 * @see Drawable#setState(int[]) 23465 * @see #drawableStateChanged() 23466 * @see #onCreateDrawableState(int) 23467 */ getDrawableState()23468 public final int[] getDrawableState() { 23469 if ((mDrawableState != null) && ((mPrivateFlags & PFLAG_DRAWABLE_STATE_DIRTY) == 0)) { 23470 return mDrawableState; 23471 } else { 23472 mDrawableState = onCreateDrawableState(0); 23473 mPrivateFlags &= ~PFLAG_DRAWABLE_STATE_DIRTY; 23474 return mDrawableState; 23475 } 23476 } 23477 23478 /** 23479 * Generate the new {@link android.graphics.drawable.Drawable} state for 23480 * this view. This is called by the view 23481 * system when the cached Drawable state is determined to be invalid. To 23482 * retrieve the current state, you should use {@link #getDrawableState}. 23483 * 23484 * @param extraSpace if non-zero, this is the number of extra entries you 23485 * would like in the returned array in which you can place your own 23486 * states. 23487 * 23488 * @return Returns an array holding the current {@link Drawable} state of 23489 * the view. 23490 * 23491 * @see #mergeDrawableStates(int[], int[]) 23492 */ onCreateDrawableState(int extraSpace)23493 protected int[] onCreateDrawableState(int extraSpace) { 23494 if ((mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE && 23495 mParent instanceof View) { 23496 return ((View) mParent).onCreateDrawableState(extraSpace); 23497 } 23498 23499 int[] drawableState; 23500 23501 int privateFlags = mPrivateFlags; 23502 23503 int viewStateIndex = 0; 23504 if ((privateFlags & PFLAG_PRESSED) != 0) viewStateIndex |= StateSet.VIEW_STATE_PRESSED; 23505 if ((mViewFlags & ENABLED_MASK) == ENABLED) viewStateIndex |= StateSet.VIEW_STATE_ENABLED; 23506 if (isFocused()) viewStateIndex |= StateSet.VIEW_STATE_FOCUSED; 23507 if ((privateFlags & PFLAG_SELECTED) != 0) viewStateIndex |= StateSet.VIEW_STATE_SELECTED; 23508 if (hasWindowFocus()) viewStateIndex |= StateSet.VIEW_STATE_WINDOW_FOCUSED; 23509 if ((privateFlags & PFLAG_ACTIVATED) != 0) viewStateIndex |= StateSet.VIEW_STATE_ACTIVATED; 23510 if (mAttachInfo != null && mAttachInfo.mHardwareAccelerationRequested && 23511 ThreadedRenderer.isAvailable()) { 23512 // This is set if HW acceleration is requested, even if the current 23513 // process doesn't allow it. This is just to allow app preview 23514 // windows to better match their app. 23515 viewStateIndex |= StateSet.VIEW_STATE_ACCELERATED; 23516 } 23517 if ((privateFlags & PFLAG_HOVERED) != 0) viewStateIndex |= StateSet.VIEW_STATE_HOVERED; 23518 23519 final int privateFlags2 = mPrivateFlags2; 23520 if ((privateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0) { 23521 viewStateIndex |= StateSet.VIEW_STATE_DRAG_CAN_ACCEPT; 23522 } 23523 if ((privateFlags2 & PFLAG2_DRAG_HOVERED) != 0) { 23524 viewStateIndex |= StateSet.VIEW_STATE_DRAG_HOVERED; 23525 } 23526 23527 drawableState = StateSet.get(viewStateIndex); 23528 23529 //noinspection ConstantIfStatement 23530 if (false) { 23531 Log.i("View", "drawableStateIndex=" + viewStateIndex); 23532 Log.i("View", toString() 23533 + " pressed=" + ((privateFlags & PFLAG_PRESSED) != 0) 23534 + " en=" + ((mViewFlags & ENABLED_MASK) == ENABLED) 23535 + " fo=" + hasFocus() 23536 + " sl=" + ((privateFlags & PFLAG_SELECTED) != 0) 23537 + " wf=" + hasWindowFocus() 23538 + ": " + Arrays.toString(drawableState)); 23539 } 23540 23541 if (extraSpace == 0) { 23542 return drawableState; 23543 } 23544 23545 final int[] fullState; 23546 if (drawableState != null) { 23547 fullState = new int[drawableState.length + extraSpace]; 23548 System.arraycopy(drawableState, 0, fullState, 0, drawableState.length); 23549 } else { 23550 fullState = new int[extraSpace]; 23551 } 23552 23553 return fullState; 23554 } 23555 23556 /** 23557 * Merge your own state values in <var>additionalState</var> into the base 23558 * state values <var>baseState</var> that were returned by 23559 * {@link #onCreateDrawableState(int)}. 23560 * 23561 * @param baseState The base state values returned by 23562 * {@link #onCreateDrawableState(int)}, which will be modified to also hold your 23563 * own additional state values. 23564 * 23565 * @param additionalState The additional state values you would like 23566 * added to <var>baseState</var>; this array is not modified. 23567 * 23568 * @return As a convenience, the <var>baseState</var> array you originally 23569 * passed into the function is returned. 23570 * 23571 * @see #onCreateDrawableState(int) 23572 */ mergeDrawableStates(int[] baseState, int[] additionalState)23573 protected static int[] mergeDrawableStates(int[] baseState, int[] additionalState) { 23574 final int N = baseState.length; 23575 int i = N - 1; 23576 while (i >= 0 && baseState[i] == 0) { 23577 i--; 23578 } 23579 System.arraycopy(additionalState, 0, baseState, i + 1, additionalState.length); 23580 return baseState; 23581 } 23582 23583 /** 23584 * Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()} 23585 * on all Drawable objects associated with this view. 23586 * <p> 23587 * Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator 23588 * attached to this view. 23589 */ 23590 @CallSuper jumpDrawablesToCurrentState()23591 public void jumpDrawablesToCurrentState() { 23592 if (mBackground != null) { 23593 mBackground.jumpToCurrentState(); 23594 } 23595 if (mStateListAnimator != null) { 23596 mStateListAnimator.jumpToCurrentState(); 23597 } 23598 if (mDefaultFocusHighlight != null) { 23599 mDefaultFocusHighlight.jumpToCurrentState(); 23600 } 23601 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { 23602 mForegroundInfo.mDrawable.jumpToCurrentState(); 23603 } 23604 } 23605 23606 /** 23607 * Sets the background color for this view. 23608 * @param color the color of the background 23609 */ 23610 @RemotableViewMethod setBackgroundColor(@olorInt int color)23611 public void setBackgroundColor(@ColorInt int color) { 23612 if (mBackground instanceof ColorDrawable) { 23613 ((ColorDrawable) mBackground.mutate()).setColor(color); 23614 computeOpaqueFlags(); 23615 mBackgroundResource = 0; 23616 } else { 23617 setBackground(new ColorDrawable(color)); 23618 } 23619 } 23620 23621 /** 23622 * Set the background to a given resource. The resource should refer to 23623 * a Drawable object or 0 to remove the background. 23624 * @param resid The identifier of the resource. 23625 * 23626 * @attr ref android.R.styleable#View_background 23627 */ 23628 @RemotableViewMethod setBackgroundResource(@rawableRes int resid)23629 public void setBackgroundResource(@DrawableRes int resid) { 23630 if (resid != 0 && resid == mBackgroundResource) { 23631 return; 23632 } 23633 23634 Drawable d = null; 23635 if (resid != 0) { 23636 d = mContext.getDrawable(resid); 23637 } 23638 setBackground(d); 23639 23640 mBackgroundResource = resid; 23641 } 23642 23643 /** 23644 * Set the background to a given Drawable, or remove the background. If the 23645 * background has padding, this View's padding is set to the background's 23646 * padding. However, when a background is removed, this View's padding isn't 23647 * touched. If setting the padding is desired, please use 23648 * {@link #setPadding(int, int, int, int)}. 23649 * 23650 * @param background The Drawable to use as the background, or null to remove the 23651 * background 23652 */ setBackground(Drawable background)23653 public void setBackground(Drawable background) { 23654 //noinspection deprecation 23655 setBackgroundDrawable(background); 23656 } 23657 23658 /** 23659 * @deprecated use {@link #setBackground(Drawable)} instead 23660 */ 23661 @Deprecated setBackgroundDrawable(Drawable background)23662 public void setBackgroundDrawable(Drawable background) { 23663 computeOpaqueFlags(); 23664 23665 if (background == mBackground) { 23666 return; 23667 } 23668 23669 boolean requestLayout = false; 23670 23671 mBackgroundResource = 0; 23672 23673 /* 23674 * Regardless of whether we're setting a new background or not, we want 23675 * to clear the previous drawable. setVisible first while we still have the callback set. 23676 */ 23677 if (mBackground != null) { 23678 if (isAttachedToWindow()) { 23679 mBackground.setVisible(false, false); 23680 } 23681 mBackground.setCallback(null); 23682 unscheduleDrawable(mBackground); 23683 } 23684 23685 if (background != null) { 23686 Rect padding = sThreadLocal.get(); 23687 if (padding == null) { 23688 padding = new Rect(); 23689 sThreadLocal.set(padding); 23690 } 23691 resetResolvedDrawablesInternal(); 23692 background.setLayoutDirection(getLayoutDirection()); 23693 if (background.getPadding(padding)) { 23694 resetResolvedPaddingInternal(); 23695 switch (background.getLayoutDirection()) { 23696 case LAYOUT_DIRECTION_RTL: 23697 mUserPaddingLeftInitial = padding.right; 23698 mUserPaddingRightInitial = padding.left; 23699 internalSetPadding(padding.right, padding.top, padding.left, padding.bottom); 23700 break; 23701 case LAYOUT_DIRECTION_LTR: 23702 default: 23703 mUserPaddingLeftInitial = padding.left; 23704 mUserPaddingRightInitial = padding.right; 23705 internalSetPadding(padding.left, padding.top, padding.right, padding.bottom); 23706 } 23707 mLeftPaddingDefined = false; 23708 mRightPaddingDefined = false; 23709 } 23710 23711 // Compare the minimum sizes of the old Drawable and the new. If there isn't an old or 23712 // if it has a different minimum size, we should layout again 23713 if (mBackground == null 23714 || mBackground.getMinimumHeight() != background.getMinimumHeight() 23715 || mBackground.getMinimumWidth() != background.getMinimumWidth()) { 23716 requestLayout = true; 23717 } 23718 23719 // Set mBackground before we set this as the callback and start making other 23720 // background drawable state change calls. In particular, the setVisible call below 23721 // can result in drawables attempting to start animations or otherwise invalidate, 23722 // which requires the view set as the callback (us) to recognize the drawable as 23723 // belonging to it as per verifyDrawable. 23724 mBackground = background; 23725 if (background.isStateful()) { 23726 background.setState(getDrawableState()); 23727 } 23728 if (isAttachedToWindow()) { 23729 background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 23730 } 23731 23732 applyBackgroundTint(); 23733 23734 // Set callback last, since the view may still be initializing. 23735 background.setCallback(this); 23736 23737 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 23738 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 23739 requestLayout = true; 23740 } 23741 } else { 23742 /* Remove the background */ 23743 mBackground = null; 23744 if ((mViewFlags & WILL_NOT_DRAW) != 0 23745 && (mDefaultFocusHighlight == null) 23746 && (mForegroundInfo == null || mForegroundInfo.mDrawable == null)) { 23747 mPrivateFlags |= PFLAG_SKIP_DRAW; 23748 } 23749 23750 /* 23751 * When the background is set, we try to apply its padding to this 23752 * View. When the background is removed, we don't touch this View's 23753 * padding. This is noted in the Javadocs. Hence, we don't need to 23754 * requestLayout(), the invalidate() below is sufficient. 23755 */ 23756 23757 // The old background's minimum size could have affected this 23758 // View's layout, so let's requestLayout 23759 requestLayout = true; 23760 } 23761 23762 computeOpaqueFlags(); 23763 23764 if (requestLayout) { 23765 requestLayout(); 23766 } 23767 23768 mBackgroundSizeChanged = true; 23769 invalidate(true); 23770 invalidateOutline(); 23771 } 23772 23773 /** 23774 * Gets the background drawable 23775 * 23776 * @return The drawable used as the background for this view, if any. 23777 * 23778 * @see #setBackground(Drawable) 23779 * 23780 * @attr ref android.R.styleable#View_background 23781 */ 23782 @InspectableProperty getBackground()23783 public Drawable getBackground() { 23784 return mBackground; 23785 } 23786 23787 /** 23788 * Applies a tint to the background drawable. Does not modify the current tint 23789 * mode, which is {@link BlendMode#SRC_IN} by default. 23790 * <p> 23791 * Subsequent calls to {@link #setBackground(Drawable)} will automatically 23792 * mutate the drawable and apply the specified tint and tint mode using 23793 * {@link Drawable#setTintList(ColorStateList)}. 23794 * 23795 * @param tint the tint to apply, may be {@code null} to clear tint 23796 * 23797 * @attr ref android.R.styleable#View_backgroundTint 23798 * @see #getBackgroundTintList() 23799 * @see Drawable#setTintList(ColorStateList) 23800 */ setBackgroundTintList(@ullable ColorStateList tint)23801 public void setBackgroundTintList(@Nullable ColorStateList tint) { 23802 if (mBackgroundTint == null) { 23803 mBackgroundTint = new TintInfo(); 23804 } 23805 mBackgroundTint.mTintList = tint; 23806 mBackgroundTint.mHasTintList = true; 23807 23808 applyBackgroundTint(); 23809 } 23810 23811 /** 23812 * Return the tint applied to the background drawable, if specified. 23813 * 23814 * @return the tint applied to the background drawable 23815 * @attr ref android.R.styleable#View_backgroundTint 23816 * @see #setBackgroundTintList(ColorStateList) 23817 */ 23818 @InspectableProperty(name = "backgroundTint") 23819 @Nullable getBackgroundTintList()23820 public ColorStateList getBackgroundTintList() { 23821 return mBackgroundTint != null ? mBackgroundTint.mTintList : null; 23822 } 23823 23824 /** 23825 * Specifies the blending mode used to apply the tint specified by 23826 * {@link #setBackgroundTintList(ColorStateList)}} to the background 23827 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 23828 * 23829 * @param tintMode the blending mode used to apply the tint, may be 23830 * {@code null} to clear tint 23831 * @attr ref android.R.styleable#View_backgroundTintMode 23832 * @see #getBackgroundTintMode() 23833 * @see Drawable#setTintMode(PorterDuff.Mode) 23834 */ setBackgroundTintMode(@ullable PorterDuff.Mode tintMode)23835 public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) { 23836 BlendMode mode = null; 23837 if (tintMode != null) { 23838 mode = BlendMode.fromValue(tintMode.nativeInt); 23839 } 23840 23841 setBackgroundTintBlendMode(mode); 23842 } 23843 23844 /** 23845 * Specifies the blending mode used to apply the tint specified by 23846 * {@link #setBackgroundTintList(ColorStateList)}} to the background 23847 * drawable. The default mode is {@link BlendMode#SRC_IN}. 23848 * 23849 * @param blendMode the blending mode used to apply the tint, may be 23850 * {@code null} to clear tint 23851 * @attr ref android.R.styleable#View_backgroundTintMode 23852 * @see #getBackgroundTintMode() 23853 * @see Drawable#setTintBlendMode(BlendMode) 23854 */ setBackgroundTintBlendMode(@ullable BlendMode blendMode)23855 public void setBackgroundTintBlendMode(@Nullable BlendMode blendMode) { 23856 if (mBackgroundTint == null) { 23857 mBackgroundTint = new TintInfo(); 23858 } 23859 23860 mBackgroundTint.mBlendMode = blendMode; 23861 mBackgroundTint.mHasTintMode = true; 23862 23863 applyBackgroundTint(); 23864 } 23865 23866 /** 23867 * Return the blending mode used to apply the tint to the background 23868 * drawable, if specified. 23869 * 23870 * @return the blending mode used to apply the tint to the background 23871 * drawable 23872 * @attr ref android.R.styleable#View_backgroundTintMode 23873 * @see #setBackgroundTintBlendMode(BlendMode) 23874 * 23875 */ 23876 @Nullable 23877 @InspectableProperty getBackgroundTintMode()23878 public PorterDuff.Mode getBackgroundTintMode() { 23879 PorterDuff.Mode porterDuffMode; 23880 if (mBackgroundTint != null && mBackgroundTint.mBlendMode != null) { 23881 porterDuffMode = BlendMode.blendModeToPorterDuffMode(mBackgroundTint.mBlendMode); 23882 } else { 23883 porterDuffMode = null; 23884 } 23885 return porterDuffMode; 23886 } 23887 23888 /** 23889 * Return the blending mode used to apply the tint to the background 23890 * drawable, if specified. 23891 * 23892 * @return the blending mode used to apply the tint to the background 23893 * drawable, null if no blend has previously been configured 23894 * @attr ref android.R.styleable#View_backgroundTintMode 23895 * @see #setBackgroundTintBlendMode(BlendMode) 23896 */ getBackgroundTintBlendMode()23897 public @Nullable BlendMode getBackgroundTintBlendMode() { 23898 return mBackgroundTint != null ? mBackgroundTint.mBlendMode : null; 23899 } 23900 applyBackgroundTint()23901 private void applyBackgroundTint() { 23902 if (mBackground != null && mBackgroundTint != null) { 23903 final TintInfo tintInfo = mBackgroundTint; 23904 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 23905 mBackground = mBackground.mutate(); 23906 23907 if (tintInfo.mHasTintList) { 23908 mBackground.setTintList(tintInfo.mTintList); 23909 } 23910 23911 if (tintInfo.mHasTintMode) { 23912 mBackground.setTintBlendMode(tintInfo.mBlendMode); 23913 } 23914 23915 // The drawable (or one of its children) may not have been 23916 // stateful before applying the tint, so let's try again. 23917 if (mBackground.isStateful()) { 23918 mBackground.setState(getDrawableState()); 23919 } 23920 } 23921 } 23922 } 23923 23924 /** 23925 * Returns the drawable used as the foreground of this View. The 23926 * foreground drawable, if non-null, is always drawn on top of the view's content. 23927 * 23928 * @return a Drawable or null if no foreground was set 23929 * 23930 * @see #onDrawForeground(Canvas) 23931 */ 23932 @InspectableProperty getForeground()23933 public Drawable getForeground() { 23934 return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 23935 } 23936 23937 /** 23938 * Supply a Drawable that is to be rendered on top of all of the content in the view. 23939 * 23940 * @param foreground the Drawable to be drawn on top of the children 23941 * 23942 * @attr ref android.R.styleable#View_foreground 23943 */ setForeground(Drawable foreground)23944 public void setForeground(Drawable foreground) { 23945 if (mForegroundInfo == null) { 23946 if (foreground == null) { 23947 // Nothing to do. 23948 return; 23949 } 23950 mForegroundInfo = new ForegroundInfo(); 23951 } 23952 23953 if (foreground == mForegroundInfo.mDrawable) { 23954 // Nothing to do 23955 return; 23956 } 23957 23958 if (mForegroundInfo.mDrawable != null) { 23959 if (isAttachedToWindow()) { 23960 mForegroundInfo.mDrawable.setVisible(false, false); 23961 } 23962 mForegroundInfo.mDrawable.setCallback(null); 23963 unscheduleDrawable(mForegroundInfo.mDrawable); 23964 } 23965 23966 mForegroundInfo.mDrawable = foreground; 23967 mForegroundInfo.mBoundsChanged = true; 23968 if (foreground != null) { 23969 if ((mPrivateFlags & PFLAG_SKIP_DRAW) != 0) { 23970 mPrivateFlags &= ~PFLAG_SKIP_DRAW; 23971 } 23972 foreground.setLayoutDirection(getLayoutDirection()); 23973 if (foreground.isStateful()) { 23974 foreground.setState(getDrawableState()); 23975 } 23976 applyForegroundTint(); 23977 if (isAttachedToWindow()) { 23978 foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false); 23979 } 23980 // Set callback last, since the view may still be initializing. 23981 foreground.setCallback(this); 23982 } else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null 23983 && (mDefaultFocusHighlight == null)) { 23984 mPrivateFlags |= PFLAG_SKIP_DRAW; 23985 } 23986 requestLayout(); 23987 invalidate(); 23988 } 23989 23990 /** 23991 * Magic bit used to support features of framework-internal window decor implementation details. 23992 * This used to live exclusively in FrameLayout. 23993 * 23994 * @return true if the foreground should draw inside the padding region or false 23995 * if it should draw inset by the view's padding 23996 * @hide internal use only; only used by FrameLayout and internal screen layouts. 23997 */ isForegroundInsidePadding()23998 public boolean isForegroundInsidePadding() { 23999 return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; 24000 } 24001 24002 /** 24003 * Describes how the foreground is positioned. 24004 * 24005 * @return foreground gravity. 24006 * 24007 * @see #setForegroundGravity(int) 24008 * 24009 * @attr ref android.R.styleable#View_foregroundGravity 24010 */ 24011 @InspectableProperty(valueType = InspectableProperty.ValueType.GRAVITY) getForegroundGravity()24012 public int getForegroundGravity() { 24013 return mForegroundInfo != null ? mForegroundInfo.mGravity 24014 : Gravity.START | Gravity.TOP; 24015 } 24016 24017 /** 24018 * Describes how the foreground is positioned. Defaults to START and TOP. 24019 * 24020 * @param gravity see {@link android.view.Gravity} 24021 * 24022 * @see #getForegroundGravity() 24023 * 24024 * @attr ref android.R.styleable#View_foregroundGravity 24025 */ setForegroundGravity(int gravity)24026 public void setForegroundGravity(int gravity) { 24027 if (mForegroundInfo == null) { 24028 mForegroundInfo = new ForegroundInfo(); 24029 } 24030 24031 if (mForegroundInfo.mGravity != gravity) { 24032 if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { 24033 gravity |= Gravity.START; 24034 } 24035 24036 if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { 24037 gravity |= Gravity.TOP; 24038 } 24039 24040 mForegroundInfo.mGravity = gravity; 24041 requestLayout(); 24042 } 24043 } 24044 24045 /** 24046 * Applies a tint to the foreground drawable. Does not modify the current tint 24047 * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. 24048 * <p> 24049 * Subsequent calls to {@link #setForeground(Drawable)} will automatically 24050 * mutate the drawable and apply the specified tint and tint mode using 24051 * {@link Drawable#setTintList(ColorStateList)}. 24052 * 24053 * @param tint the tint to apply, may be {@code null} to clear tint 24054 * 24055 * @attr ref android.R.styleable#View_foregroundTint 24056 * @see #getForegroundTintList() 24057 * @see Drawable#setTintList(ColorStateList) 24058 */ setForegroundTintList(@ullable ColorStateList tint)24059 public void setForegroundTintList(@Nullable ColorStateList tint) { 24060 if (mForegroundInfo == null) { 24061 mForegroundInfo = new ForegroundInfo(); 24062 } 24063 if (mForegroundInfo.mTintInfo == null) { 24064 mForegroundInfo.mTintInfo = new TintInfo(); 24065 } 24066 mForegroundInfo.mTintInfo.mTintList = tint; 24067 mForegroundInfo.mTintInfo.mHasTintList = true; 24068 24069 applyForegroundTint(); 24070 } 24071 24072 /** 24073 * Return the tint applied to the foreground drawable, if specified. 24074 * 24075 * @return the tint applied to the foreground drawable 24076 * @attr ref android.R.styleable#View_foregroundTint 24077 * @see #setForegroundTintList(ColorStateList) 24078 */ 24079 @InspectableProperty(name = "foregroundTint") 24080 @Nullable getForegroundTintList()24081 public ColorStateList getForegroundTintList() { 24082 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 24083 ? mForegroundInfo.mTintInfo.mTintList : null; 24084 } 24085 24086 /** 24087 * Specifies the blending mode used to apply the tint specified by 24088 * {@link #setForegroundTintList(ColorStateList)}} to the background 24089 * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. 24090 * 24091 * @param tintMode the blending mode used to apply the tint, may be 24092 * {@code null} to clear tint 24093 * @attr ref android.R.styleable#View_foregroundTintMode 24094 * @see #getForegroundTintMode() 24095 * @see Drawable#setTintMode(PorterDuff.Mode) 24096 * 24097 */ setForegroundTintMode(@ullable PorterDuff.Mode tintMode)24098 public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { 24099 BlendMode mode = null; 24100 if (tintMode != null) { 24101 mode = BlendMode.fromValue(tintMode.nativeInt); 24102 } 24103 setForegroundTintBlendMode(mode); 24104 } 24105 24106 /** 24107 * Specifies the blending mode used to apply the tint specified by 24108 * {@link #setForegroundTintList(ColorStateList)}} to the background 24109 * drawable. The default mode is {@link BlendMode#SRC_IN}. 24110 * 24111 * @param blendMode the blending mode used to apply the tint, may be 24112 * {@code null} to clear tint 24113 * @attr ref android.R.styleable#View_foregroundTintMode 24114 * @see #getForegroundTintMode() 24115 * @see Drawable#setTintBlendMode(BlendMode) 24116 */ setForegroundTintBlendMode(@ullable BlendMode blendMode)24117 public void setForegroundTintBlendMode(@Nullable BlendMode blendMode) { 24118 if (mForegroundInfo == null) { 24119 mForegroundInfo = new ForegroundInfo(); 24120 } 24121 if (mForegroundInfo.mTintInfo == null) { 24122 mForegroundInfo.mTintInfo = new TintInfo(); 24123 } 24124 mForegroundInfo.mTintInfo.mBlendMode = blendMode; 24125 mForegroundInfo.mTintInfo.mHasTintMode = true; 24126 24127 applyForegroundTint(); 24128 } 24129 24130 /** 24131 * Return the blending mode used to apply the tint to the foreground 24132 * drawable, if specified. 24133 * 24134 * @return the blending mode used to apply the tint to the foreground 24135 * drawable 24136 * @attr ref android.R.styleable#View_foregroundTintMode 24137 * @see #setForegroundTintMode(PorterDuff.Mode) 24138 */ 24139 @InspectableProperty 24140 @Nullable getForegroundTintMode()24141 public PorterDuff.Mode getForegroundTintMode() { 24142 BlendMode blendMode = mForegroundInfo != null && mForegroundInfo.mTintInfo != null 24143 ? mForegroundInfo.mTintInfo.mBlendMode : null; 24144 if (blendMode != null) { 24145 return BlendMode.blendModeToPorterDuffMode(blendMode); 24146 } else { 24147 return null; 24148 } 24149 } 24150 24151 /** 24152 * Return the blending mode used to apply the tint to the foreground 24153 * drawable, if specified. 24154 * 24155 * @return the blending mode used to apply the tint to the foreground 24156 * drawable 24157 * @attr ref android.R.styleable#View_foregroundTintMode 24158 * @see #setForegroundTintBlendMode(BlendMode) 24159 * 24160 */ getForegroundTintBlendMode()24161 public @Nullable BlendMode getForegroundTintBlendMode() { 24162 return mForegroundInfo != null && mForegroundInfo.mTintInfo != null 24163 ? mForegroundInfo.mTintInfo.mBlendMode : null; 24164 } 24165 applyForegroundTint()24166 private void applyForegroundTint() { 24167 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 24168 && mForegroundInfo.mTintInfo != null) { 24169 final TintInfo tintInfo = mForegroundInfo.mTintInfo; 24170 if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { 24171 mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); 24172 24173 if (tintInfo.mHasTintList) { 24174 mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); 24175 } 24176 24177 if (tintInfo.mHasTintMode) { 24178 mForegroundInfo.mDrawable.setTintBlendMode(tintInfo.mBlendMode); 24179 } 24180 24181 // The drawable (or one of its children) may not have been 24182 // stateful before applying the tint, so let's try again. 24183 if (mForegroundInfo.mDrawable.isStateful()) { 24184 mForegroundInfo.mDrawable.setState(getDrawableState()); 24185 } 24186 } 24187 } 24188 } 24189 24190 /** 24191 * Get the drawable to be overlayed when a view is autofilled 24192 * 24193 * @return The drawable 24194 * 24195 * @throws IllegalStateException if the drawable could not be found. 24196 */ getAutofilledDrawable()24197 @Nullable private Drawable getAutofilledDrawable() { 24198 if (mAttachInfo == null) { 24199 return null; 24200 } 24201 // Lazily load the isAutofilled drawable. 24202 if (mAttachInfo.mAutofilledDrawable == null) { 24203 Context rootContext = getRootView().getContext(); 24204 TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR); 24205 int attributeResourceId = a.getResourceId(0, 0); 24206 mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId); 24207 a.recycle(); 24208 } 24209 24210 return mAttachInfo.mAutofilledDrawable; 24211 } 24212 24213 /** 24214 * Draw {@link View#isAutofilled()} highlight over view if the view is autofilled, unless 24215 * {@link #PFLAG4_AUTOFILL_HIDE_HIGHLIGHT} is enabled. 24216 * 24217 * @param canvas The canvas to draw on 24218 */ drawAutofilledHighlight(@onNull Canvas canvas)24219 private void drawAutofilledHighlight(@NonNull Canvas canvas) { 24220 if (isAutofilled() && !hideAutofillHighlight()) { 24221 Drawable autofilledHighlight = getAutofilledDrawable(); 24222 24223 if (autofilledHighlight != null) { 24224 autofilledHighlight.setBounds(0, 0, getWidth(), getHeight()); 24225 autofilledHighlight.draw(canvas); 24226 } 24227 } 24228 } 24229 24230 /** 24231 * Draw any foreground content for this view. 24232 * 24233 * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} 24234 * drawable or other view-specific decorations. The foreground is drawn on top of the 24235 * primary view content.</p> 24236 * 24237 * @param canvas canvas to draw into 24238 */ onDrawForeground(Canvas canvas)24239 public void onDrawForeground(Canvas canvas) { 24240 onDrawScrollIndicators(canvas); 24241 onDrawScrollBars(canvas); 24242 24243 final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; 24244 if (foreground != null) { 24245 if (mForegroundInfo.mBoundsChanged) { 24246 mForegroundInfo.mBoundsChanged = false; 24247 final Rect selfBounds = mForegroundInfo.mSelfBounds; 24248 final Rect overlayBounds = mForegroundInfo.mOverlayBounds; 24249 24250 if (mForegroundInfo.mInsidePadding) { 24251 selfBounds.set(0, 0, getWidth(), getHeight()); 24252 } else { 24253 selfBounds.set(getPaddingLeft(), getPaddingTop(), 24254 getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); 24255 } 24256 24257 final int ld = getLayoutDirection(); 24258 Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), 24259 foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); 24260 foreground.setBounds(overlayBounds); 24261 } 24262 24263 foreground.draw(canvas); 24264 } 24265 } 24266 24267 /** 24268 * Sets the padding. The view may add on the space required to display 24269 * the scrollbars, depending on the style and visibility of the scrollbars. 24270 * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, 24271 * {@link #getPaddingRight} and {@link #getPaddingBottom} may be different 24272 * from the values set in this call. 24273 * 24274 * @attr ref android.R.styleable#View_padding 24275 * @attr ref android.R.styleable#View_paddingBottom 24276 * @attr ref android.R.styleable#View_paddingLeft 24277 * @attr ref android.R.styleable#View_paddingRight 24278 * @attr ref android.R.styleable#View_paddingTop 24279 * @param left the left padding in pixels 24280 * @param top the top padding in pixels 24281 * @param right the right padding in pixels 24282 * @param bottom the bottom padding in pixels 24283 */ setPadding(int left, int top, int right, int bottom)24284 public void setPadding(int left, int top, int right, int bottom) { 24285 resetResolvedPaddingInternal(); 24286 24287 mUserPaddingStart = UNDEFINED_PADDING; 24288 mUserPaddingEnd = UNDEFINED_PADDING; 24289 24290 mUserPaddingLeftInitial = left; 24291 mUserPaddingRightInitial = right; 24292 24293 mLeftPaddingDefined = true; 24294 mRightPaddingDefined = true; 24295 24296 internalSetPadding(left, top, right, bottom); 24297 } 24298 24299 /** 24300 * @hide 24301 */ 24302 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768420) internalSetPadding(int left, int top, int right, int bottom)24303 protected void internalSetPadding(int left, int top, int right, int bottom) { 24304 mUserPaddingLeft = left; 24305 mUserPaddingRight = right; 24306 mUserPaddingBottom = bottom; 24307 24308 final int viewFlags = mViewFlags; 24309 boolean changed = false; 24310 24311 // Common case is there are no scroll bars. 24312 if ((viewFlags & (SCROLLBARS_VERTICAL|SCROLLBARS_HORIZONTAL)) != 0) { 24313 if ((viewFlags & SCROLLBARS_VERTICAL) != 0) { 24314 final int offset = (viewFlags & SCROLLBARS_INSET_MASK) == 0 24315 ? 0 : getVerticalScrollbarWidth(); 24316 switch (mVerticalScrollbarPosition) { 24317 case SCROLLBAR_POSITION_DEFAULT: 24318 if (isLayoutRtl()) { 24319 left += offset; 24320 } else { 24321 right += offset; 24322 } 24323 break; 24324 case SCROLLBAR_POSITION_RIGHT: 24325 right += offset; 24326 break; 24327 case SCROLLBAR_POSITION_LEFT: 24328 left += offset; 24329 break; 24330 } 24331 } 24332 if ((viewFlags & SCROLLBARS_HORIZONTAL) != 0) { 24333 bottom += (viewFlags & SCROLLBARS_INSET_MASK) == 0 24334 ? 0 : getHorizontalScrollbarHeight(); 24335 } 24336 } 24337 24338 if (mPaddingLeft != left) { 24339 changed = true; 24340 mPaddingLeft = left; 24341 } 24342 if (mPaddingTop != top) { 24343 changed = true; 24344 mPaddingTop = top; 24345 } 24346 if (mPaddingRight != right) { 24347 changed = true; 24348 mPaddingRight = right; 24349 } 24350 if (mPaddingBottom != bottom) { 24351 changed = true; 24352 mPaddingBottom = bottom; 24353 } 24354 24355 if (changed) { 24356 requestLayout(); 24357 invalidateOutline(); 24358 } 24359 } 24360 24361 /** 24362 * Sets the relative padding. The view may add on the space required to display 24363 * the scrollbars, depending on the style and visibility of the scrollbars. 24364 * So the values returned from {@link #getPaddingStart}, {@link #getPaddingTop}, 24365 * {@link #getPaddingEnd} and {@link #getPaddingBottom} may be different 24366 * from the values set in this call. 24367 * 24368 * @attr ref android.R.styleable#View_padding 24369 * @attr ref android.R.styleable#View_paddingBottom 24370 * @attr ref android.R.styleable#View_paddingStart 24371 * @attr ref android.R.styleable#View_paddingEnd 24372 * @attr ref android.R.styleable#View_paddingTop 24373 * @param start the start padding in pixels 24374 * @param top the top padding in pixels 24375 * @param end the end padding in pixels 24376 * @param bottom the bottom padding in pixels 24377 */ setPaddingRelative(int start, int top, int end, int bottom)24378 public void setPaddingRelative(int start, int top, int end, int bottom) { 24379 resetResolvedPaddingInternal(); 24380 24381 mUserPaddingStart = start; 24382 mUserPaddingEnd = end; 24383 mLeftPaddingDefined = true; 24384 mRightPaddingDefined = true; 24385 24386 switch(getLayoutDirection()) { 24387 case LAYOUT_DIRECTION_RTL: 24388 mUserPaddingLeftInitial = end; 24389 mUserPaddingRightInitial = start; 24390 internalSetPadding(end, top, start, bottom); 24391 break; 24392 case LAYOUT_DIRECTION_LTR: 24393 default: 24394 mUserPaddingLeftInitial = start; 24395 mUserPaddingRightInitial = end; 24396 internalSetPadding(start, top, end, bottom); 24397 } 24398 } 24399 24400 /** 24401 * A {@link View} can be inflated from an XML layout. For such Views this method returns the 24402 * resource ID of the source layout. 24403 * 24404 * @return The layout resource id if this view was inflated from XML, otherwise 24405 * {@link Resources#ID_NULL}. 24406 */ 24407 @LayoutRes getSourceLayoutResId()24408 public int getSourceLayoutResId() { 24409 return mSourceLayoutId; 24410 } 24411 24412 /** 24413 * Returns the top padding of this view. 24414 * 24415 * @return the top padding in pixels 24416 */ 24417 @InspectableProperty getPaddingTop()24418 public int getPaddingTop() { 24419 return mPaddingTop; 24420 } 24421 24422 /** 24423 * Returns the bottom padding of this view. If there are inset and enabled 24424 * scrollbars, this value may include the space required to display the 24425 * scrollbars as well. 24426 * 24427 * @return the bottom padding in pixels 24428 */ 24429 @InspectableProperty getPaddingBottom()24430 public int getPaddingBottom() { 24431 return mPaddingBottom; 24432 } 24433 24434 /** 24435 * Returns the left padding of this view. If there are inset and enabled 24436 * scrollbars, this value may include the space required to display the 24437 * scrollbars as well. 24438 * 24439 * @return the left padding in pixels 24440 */ 24441 @InspectableProperty getPaddingLeft()24442 public int getPaddingLeft() { 24443 if (!isPaddingResolved()) { 24444 resolvePadding(); 24445 } 24446 return mPaddingLeft; 24447 } 24448 24449 /** 24450 * Returns the start padding of this view depending on its resolved layout direction. 24451 * If there are inset and enabled scrollbars, this value may include the space 24452 * required to display the scrollbars as well. 24453 * 24454 * @return the start padding in pixels 24455 */ getPaddingStart()24456 public int getPaddingStart() { 24457 if (!isPaddingResolved()) { 24458 resolvePadding(); 24459 } 24460 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 24461 mPaddingRight : mPaddingLeft; 24462 } 24463 24464 /** 24465 * Returns the right padding of this view. If there are inset and enabled 24466 * scrollbars, this value may include the space required to display the 24467 * scrollbars as well. 24468 * 24469 * @return the right padding in pixels 24470 */ 24471 @InspectableProperty getPaddingRight()24472 public int getPaddingRight() { 24473 if (!isPaddingResolved()) { 24474 resolvePadding(); 24475 } 24476 return mPaddingRight; 24477 } 24478 24479 /** 24480 * Returns the end padding of this view depending on its resolved layout direction. 24481 * If there are inset and enabled scrollbars, this value may include the space 24482 * required to display the scrollbars as well. 24483 * 24484 * @return the end padding in pixels 24485 */ getPaddingEnd()24486 public int getPaddingEnd() { 24487 if (!isPaddingResolved()) { 24488 resolvePadding(); 24489 } 24490 return (getLayoutDirection() == LAYOUT_DIRECTION_RTL) ? 24491 mPaddingLeft : mPaddingRight; 24492 } 24493 24494 /** 24495 * Return if the padding has been set through relative values 24496 * {@link #setPaddingRelative(int, int, int, int)} or through 24497 * @attr ref android.R.styleable#View_paddingStart or 24498 * @attr ref android.R.styleable#View_paddingEnd 24499 * 24500 * @return true if the padding is relative or false if it is not. 24501 */ isPaddingRelative()24502 public boolean isPaddingRelative() { 24503 return (mUserPaddingStart != UNDEFINED_PADDING || mUserPaddingEnd != UNDEFINED_PADDING); 24504 } 24505 computeOpticalInsets()24506 Insets computeOpticalInsets() { 24507 return (mBackground == null) ? Insets.NONE : mBackground.getOpticalInsets(); 24508 } 24509 24510 /** 24511 * @hide 24512 */ 24513 @UnsupportedAppUsage resetPaddingToInitialValues()24514 public void resetPaddingToInitialValues() { 24515 if (isRtlCompatibilityMode()) { 24516 mPaddingLeft = mUserPaddingLeftInitial; 24517 mPaddingRight = mUserPaddingRightInitial; 24518 return; 24519 } 24520 if (isLayoutRtl()) { 24521 mPaddingLeft = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingLeftInitial; 24522 mPaddingRight = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingRightInitial; 24523 } else { 24524 mPaddingLeft = (mUserPaddingStart >= 0) ? mUserPaddingStart : mUserPaddingLeftInitial; 24525 mPaddingRight = (mUserPaddingEnd >= 0) ? mUserPaddingEnd : mUserPaddingRightInitial; 24526 } 24527 } 24528 24529 /** 24530 * @hide 24531 */ getOpticalInsets()24532 public Insets getOpticalInsets() { 24533 if (mLayoutInsets == null) { 24534 mLayoutInsets = computeOpticalInsets(); 24535 } 24536 return mLayoutInsets; 24537 } 24538 24539 /** 24540 * Set this view's optical insets. 24541 * 24542 * <p>This method should be treated similarly to setMeasuredDimension and not as a general 24543 * property. Views that compute their own optical insets should call it as part of measurement. 24544 * This method does not request layout. If you are setting optical insets outside of 24545 * measure/layout itself you will want to call requestLayout() yourself. 24546 * </p> 24547 * @hide 24548 */ setOpticalInsets(Insets insets)24549 public void setOpticalInsets(Insets insets) { 24550 mLayoutInsets = insets; 24551 } 24552 24553 /** 24554 * Changes the selection state of this view. A view can be selected or not. 24555 * Note that selection is not the same as focus. Views are typically 24556 * selected in the context of an AdapterView like ListView or GridView; 24557 * the selected view is the view that is highlighted. 24558 * 24559 * @param selected true if the view must be selected, false otherwise 24560 */ setSelected(boolean selected)24561 public void setSelected(boolean selected) { 24562 //noinspection DoubleNegation 24563 if (((mPrivateFlags & PFLAG_SELECTED) != 0) != selected) { 24564 mPrivateFlags = (mPrivateFlags & ~PFLAG_SELECTED) | (selected ? PFLAG_SELECTED : 0); 24565 if (!selected) resetPressedState(); 24566 invalidate(true); 24567 refreshDrawableState(); 24568 dispatchSetSelected(selected); 24569 if (selected) { 24570 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); 24571 } else { 24572 notifyViewAccessibilityStateChangedIfNeeded( 24573 AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); 24574 } 24575 } 24576 } 24577 24578 /** 24579 * Dispatch setSelected to all of this View's children. 24580 * 24581 * @see #setSelected(boolean) 24582 * 24583 * @param selected The new selected state 24584 */ dispatchSetSelected(boolean selected)24585 protected void dispatchSetSelected(boolean selected) { 24586 } 24587 24588 /** 24589 * Indicates the selection state of this view. 24590 * 24591 * @return true if the view is selected, false otherwise 24592 */ 24593 @ViewDebug.ExportedProperty 24594 @InspectableProperty(hasAttributeId = false) isSelected()24595 public boolean isSelected() { 24596 return (mPrivateFlags & PFLAG_SELECTED) != 0; 24597 } 24598 24599 /** 24600 * Changes the activated state of this view. A view can be activated or not. 24601 * Note that activation is not the same as selection. Selection is 24602 * a transient property, representing the view (hierarchy) the user is 24603 * currently interacting with. Activation is a longer-term state that the 24604 * user can move views in and out of. For example, in a list view with 24605 * single or multiple selection enabled, the views in the current selection 24606 * set are activated. (Um, yeah, we are deeply sorry about the terminology 24607 * here.) The activated state is propagated down to children of the view it 24608 * is set on. 24609 * 24610 * @param activated true if the view must be activated, false otherwise 24611 */ setActivated(boolean activated)24612 public void setActivated(boolean activated) { 24613 //noinspection DoubleNegation 24614 if (((mPrivateFlags & PFLAG_ACTIVATED) != 0) != activated) { 24615 mPrivateFlags = (mPrivateFlags & ~PFLAG_ACTIVATED) | (activated ? PFLAG_ACTIVATED : 0); 24616 invalidate(true); 24617 refreshDrawableState(); 24618 dispatchSetActivated(activated); 24619 } 24620 } 24621 24622 /** 24623 * Dispatch setActivated to all of this View's children. 24624 * 24625 * @see #setActivated(boolean) 24626 * 24627 * @param activated The new activated state 24628 */ dispatchSetActivated(boolean activated)24629 protected void dispatchSetActivated(boolean activated) { 24630 } 24631 24632 /** 24633 * Indicates the activation state of this view. 24634 * 24635 * @return true if the view is activated, false otherwise 24636 */ 24637 @ViewDebug.ExportedProperty 24638 @InspectableProperty(hasAttributeId = false) isActivated()24639 public boolean isActivated() { 24640 return (mPrivateFlags & PFLAG_ACTIVATED) != 0; 24641 } 24642 24643 /** 24644 * Returns the ViewTreeObserver for this view's hierarchy. The view tree 24645 * observer can be used to get notifications when global events, like 24646 * layout, happen. 24647 * 24648 * The returned ViewTreeObserver observer is not guaranteed to remain 24649 * valid for the lifetime of this View. If the caller of this method keeps 24650 * a long-lived reference to ViewTreeObserver, it should always check for 24651 * the return value of {@link ViewTreeObserver#isAlive()}. 24652 * 24653 * @return The ViewTreeObserver for this view's hierarchy. 24654 */ getViewTreeObserver()24655 public ViewTreeObserver getViewTreeObserver() { 24656 if (mAttachInfo != null) { 24657 return mAttachInfo.mTreeObserver; 24658 } 24659 if (mFloatingTreeObserver == null) { 24660 mFloatingTreeObserver = new ViewTreeObserver(mContext); 24661 } 24662 return mFloatingTreeObserver; 24663 } 24664 24665 /** 24666 * <p>Finds the topmost view in the current view hierarchy.</p> 24667 * 24668 * @return the topmost view containing this view 24669 */ getRootView()24670 public View getRootView() { 24671 if (mAttachInfo != null) { 24672 final View v = mAttachInfo.mRootView; 24673 if (v != null) { 24674 return v; 24675 } 24676 } 24677 24678 View parent = this; 24679 24680 while (parent.mParent != null && parent.mParent instanceof View) { 24681 parent = (View) parent.mParent; 24682 } 24683 24684 return parent; 24685 } 24686 24687 /** 24688 * Transforms a motion event from view-local coordinates to on-screen 24689 * coordinates. 24690 * 24691 * @param ev the view-local motion event 24692 * @return false if the transformation could not be applied 24693 * @hide 24694 */ 24695 @UnsupportedAppUsage toGlobalMotionEvent(MotionEvent ev)24696 public boolean toGlobalMotionEvent(MotionEvent ev) { 24697 final AttachInfo info = mAttachInfo; 24698 if (info == null) { 24699 return false; 24700 } 24701 24702 final Matrix m = info.mTmpMatrix; 24703 m.set(Matrix.IDENTITY_MATRIX); 24704 transformMatrixToGlobal(m); 24705 ev.transform(m); 24706 return true; 24707 } 24708 24709 /** 24710 * Transforms a motion event from on-screen coordinates to view-local 24711 * coordinates. 24712 * 24713 * @param ev the on-screen motion event 24714 * @return false if the transformation could not be applied 24715 * @hide 24716 */ 24717 @UnsupportedAppUsage toLocalMotionEvent(MotionEvent ev)24718 public boolean toLocalMotionEvent(MotionEvent ev) { 24719 final AttachInfo info = mAttachInfo; 24720 if (info == null) { 24721 return false; 24722 } 24723 24724 final Matrix m = info.mTmpMatrix; 24725 m.set(Matrix.IDENTITY_MATRIX); 24726 transformMatrixToLocal(m); 24727 ev.transform(m); 24728 return true; 24729 } 24730 24731 /** 24732 * Modifies the input matrix such that it maps view-local coordinates to 24733 * on-screen coordinates. 24734 * 24735 * @param matrix input matrix to modify 24736 */ transformMatrixToGlobal(@onNull Matrix matrix)24737 public void transformMatrixToGlobal(@NonNull Matrix matrix) { 24738 final ViewParent parent = mParent; 24739 if (parent instanceof View) { 24740 final View vp = (View) parent; 24741 vp.transformMatrixToGlobal(matrix); 24742 matrix.preTranslate(-vp.mScrollX, -vp.mScrollY); 24743 } else if (parent instanceof ViewRootImpl) { 24744 final ViewRootImpl vr = (ViewRootImpl) parent; 24745 vr.transformMatrixToGlobal(matrix); 24746 matrix.preTranslate(0, -vr.mCurScrollY); 24747 } 24748 24749 matrix.preTranslate(mLeft, mTop); 24750 24751 if (!hasIdentityMatrix()) { 24752 matrix.preConcat(getMatrix()); 24753 } 24754 } 24755 24756 /** 24757 * Modifies the input matrix such that it maps on-screen coordinates to 24758 * view-local coordinates. 24759 * 24760 * @param matrix input matrix to modify 24761 */ transformMatrixToLocal(@onNull Matrix matrix)24762 public void transformMatrixToLocal(@NonNull Matrix matrix) { 24763 final ViewParent parent = mParent; 24764 if (parent instanceof View) { 24765 final View vp = (View) parent; 24766 vp.transformMatrixToLocal(matrix); 24767 matrix.postTranslate(vp.mScrollX, vp.mScrollY); 24768 } else if (parent instanceof ViewRootImpl) { 24769 final ViewRootImpl vr = (ViewRootImpl) parent; 24770 vr.transformMatrixToLocal(matrix); 24771 matrix.postTranslate(0, vr.mCurScrollY); 24772 } 24773 24774 matrix.postTranslate(-mLeft, -mTop); 24775 24776 if (!hasIdentityMatrix()) { 24777 matrix.postConcat(getInverseMatrix()); 24778 } 24779 } 24780 24781 /** 24782 * @hide 24783 */ 24784 @ViewDebug.ExportedProperty(category = "layout", indexMapping = { 24785 @ViewDebug.IntToString(from = 0, to = "x"), 24786 @ViewDebug.IntToString(from = 1, to = "y") 24787 }) 24788 @UnsupportedAppUsage getLocationOnScreen()24789 public int[] getLocationOnScreen() { 24790 int[] location = new int[2]; 24791 getLocationOnScreen(location); 24792 return location; 24793 } 24794 24795 /** 24796 * <p>Computes the coordinates of this view on the screen. The argument 24797 * must be an array of two integers. After the method returns, the array 24798 * contains the x and y location in that order.</p> 24799 * 24800 * @param outLocation an array of two integers in which to hold the coordinates 24801 */ getLocationOnScreen(@ize2) int[] outLocation)24802 public void getLocationOnScreen(@Size(2) int[] outLocation) { 24803 getLocationInWindow(outLocation); 24804 24805 final AttachInfo info = mAttachInfo; 24806 if (info != null) { 24807 outLocation[0] += info.mWindowLeft; 24808 outLocation[1] += info.mWindowTop; 24809 } 24810 } 24811 24812 /** 24813 * <p>Computes the coordinates of this view in its window. The argument 24814 * must be an array of two integers. After the method returns, the array 24815 * contains the x and y location in that order.</p> 24816 * 24817 * @param outLocation an array of two integers in which to hold the coordinates 24818 */ getLocationInWindow(@ize2) int[] outLocation)24819 public void getLocationInWindow(@Size(2) int[] outLocation) { 24820 if (outLocation == null || outLocation.length < 2) { 24821 throw new IllegalArgumentException("outLocation must be an array of two integers"); 24822 } 24823 24824 outLocation[0] = 0; 24825 outLocation[1] = 0; 24826 24827 transformFromViewToWindowSpace(outLocation); 24828 } 24829 24830 /** @hide */ transformFromViewToWindowSpace(@ize2) int[] inOutLocation)24831 public void transformFromViewToWindowSpace(@Size(2) int[] inOutLocation) { 24832 if (inOutLocation == null || inOutLocation.length < 2) { 24833 throw new IllegalArgumentException("inOutLocation must be an array of two integers"); 24834 } 24835 24836 if (mAttachInfo == null) { 24837 // When the view is not attached to a window, this method does not make sense 24838 inOutLocation[0] = inOutLocation[1] = 0; 24839 return; 24840 } 24841 24842 float position[] = mAttachInfo.mTmpTransformLocation; 24843 position[0] = inOutLocation[0]; 24844 position[1] = inOutLocation[1]; 24845 24846 if (!hasIdentityMatrix()) { 24847 getMatrix().mapPoints(position); 24848 } 24849 24850 position[0] += mLeft; 24851 position[1] += mTop; 24852 24853 ViewParent viewParent = mParent; 24854 while (viewParent instanceof View) { 24855 final View view = (View) viewParent; 24856 24857 position[0] -= view.mScrollX; 24858 position[1] -= view.mScrollY; 24859 24860 if (!view.hasIdentityMatrix()) { 24861 view.getMatrix().mapPoints(position); 24862 } 24863 24864 position[0] += view.mLeft; 24865 position[1] += view.mTop; 24866 24867 viewParent = view.mParent; 24868 } 24869 24870 if (viewParent instanceof ViewRootImpl) { 24871 // *cough* 24872 final ViewRootImpl vr = (ViewRootImpl) viewParent; 24873 position[1] -= vr.mCurScrollY; 24874 } 24875 24876 inOutLocation[0] = Math.round(position[0]); 24877 inOutLocation[1] = Math.round(position[1]); 24878 } 24879 24880 /** 24881 * @param id the id of the view to be found 24882 * @return the view of the specified id, null if cannot be found 24883 * @hide 24884 */ findViewTraversal(@dRes int id)24885 protected <T extends View> T findViewTraversal(@IdRes int id) { 24886 if (id == mID) { 24887 return (T) this; 24888 } 24889 return null; 24890 } 24891 24892 /** 24893 * @param tag the tag of the view to be found 24894 * @return the view of specified tag, null if cannot be found 24895 * @hide 24896 */ findViewWithTagTraversal(Object tag)24897 protected <T extends View> T findViewWithTagTraversal(Object tag) { 24898 if (tag != null && tag.equals(mTag)) { 24899 return (T) this; 24900 } 24901 return null; 24902 } 24903 24904 /** 24905 * @param predicate The predicate to evaluate. 24906 * @param childToSkip If not null, ignores this child during the recursive traversal. 24907 * @return The first view that matches the predicate or null. 24908 * @hide 24909 */ findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip)24910 protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate, 24911 View childToSkip) { 24912 if (predicate.test(this)) { 24913 return (T) this; 24914 } 24915 return null; 24916 } 24917 24918 /** 24919 * Finds the first descendant view with the given ID, the view itself if 24920 * the ID matches {@link #getId()}, or {@code null} if the ID is invalid 24921 * (< 0) or there is no matching view in the hierarchy. 24922 * <p> 24923 * <strong>Note:</strong> In most cases -- depending on compiler support -- 24924 * the resulting view is automatically cast to the target class type. If 24925 * the target class type is unconstrained, an explicit cast may be 24926 * necessary. 24927 * 24928 * @param id the ID to search for 24929 * @return a view with given ID if found, or {@code null} otherwise 24930 * @see View#requireViewById(int) 24931 */ 24932 @Nullable findViewById(@dRes int id)24933 public final <T extends View> T findViewById(@IdRes int id) { 24934 if (id == NO_ID) { 24935 return null; 24936 } 24937 return findViewTraversal(id); 24938 } 24939 24940 /** 24941 * Finds the first descendant view with the given ID, the view itself if the ID matches 24942 * {@link #getId()}, or throws an IllegalArgumentException if the ID is invalid or there is no 24943 * matching view in the hierarchy. 24944 * <p> 24945 * <strong>Note:</strong> In most cases -- depending on compiler support -- 24946 * the resulting view is automatically cast to the target class type. If 24947 * the target class type is unconstrained, an explicit cast may be 24948 * necessary. 24949 * 24950 * @param id the ID to search for 24951 * @return a view with given ID 24952 * @see View#findViewById(int) 24953 */ 24954 @NonNull requireViewById(@dRes int id)24955 public final <T extends View> T requireViewById(@IdRes int id) { 24956 T view = findViewById(id); 24957 if (view == null) { 24958 throw new IllegalArgumentException("ID does not reference a View inside this View"); 24959 } 24960 return view; 24961 } 24962 24963 /** 24964 * Performs the traversal to find a view by its unique and stable accessibility id. 24965 * 24966 * <strong>Note:</strong>This method does not stop at the root namespace 24967 * boundary since the user can touch the screen at an arbitrary location 24968 * potentially crossing the root namespace boundary which will send an 24969 * accessibility event to accessibility services and they should be able 24970 * to obtain the event source. Also accessibility ids are guaranteed to be 24971 * unique in the window. 24972 * 24973 * @param accessibilityId The accessibility id. 24974 * @return The found view. 24975 * @hide 24976 */ findViewByAccessibilityIdTraversal(int accessibilityId)24977 public <T extends View> T findViewByAccessibilityIdTraversal(int accessibilityId) { 24978 if (getAccessibilityViewId() == accessibilityId) { 24979 return (T) this; 24980 } 24981 return null; 24982 } 24983 24984 /** 24985 * Performs the traversal to find a view by its autofill id. 24986 * 24987 * <strong>Note:</strong>This method does not stop at the root namespace 24988 * boundary. 24989 * 24990 * @param autofillId The autofill id. 24991 * @return The found view. 24992 * @hide 24993 */ findViewByAutofillIdTraversal(int autofillId)24994 public <T extends View> T findViewByAutofillIdTraversal(int autofillId) { 24995 if (getAutofillViewId() == autofillId) { 24996 return (T) this; 24997 } 24998 return null; 24999 } 25000 25001 /** 25002 * Look for a child view with the given tag. If this view has the given 25003 * tag, return this view. 25004 * 25005 * @param tag The tag to search for, using "tag.equals(getTag())". 25006 * @return The View that has the given tag in the hierarchy or null 25007 */ findViewWithTag(Object tag)25008 public final <T extends View> T findViewWithTag(Object tag) { 25009 if (tag == null) { 25010 return null; 25011 } 25012 return findViewWithTagTraversal(tag); 25013 } 25014 25015 /** 25016 * Look for a child view that matches the specified predicate. 25017 * If this view matches the predicate, return this view. 25018 * 25019 * @param predicate The predicate to evaluate. 25020 * @return The first view that matches the predicate or null. 25021 * @hide 25022 */ findViewByPredicate(Predicate<View> predicate)25023 public final <T extends View> T findViewByPredicate(Predicate<View> predicate) { 25024 return findViewByPredicateTraversal(predicate, null); 25025 } 25026 25027 /** 25028 * Look for a child view that matches the specified predicate, 25029 * starting with the specified view and its descendents and then 25030 * recusively searching the ancestors and siblings of that view 25031 * until this view is reached. 25032 * 25033 * This method is useful in cases where the predicate does not match 25034 * a single unique view (perhaps multiple views use the same id) 25035 * and we are trying to find the view that is "closest" in scope to the 25036 * starting view. 25037 * 25038 * @param start The view to start from. 25039 * @param predicate The predicate to evaluate. 25040 * @return The first view that matches the predicate or null. 25041 * @hide 25042 */ findViewByPredicateInsideOut( View start, Predicate<View> predicate)25043 public final <T extends View> T findViewByPredicateInsideOut( 25044 View start, Predicate<View> predicate) { 25045 View childToSkip = null; 25046 for (;;) { 25047 T view = start.findViewByPredicateTraversal(predicate, childToSkip); 25048 if (view != null || start == this) { 25049 return view; 25050 } 25051 25052 ViewParent parent = start.getParent(); 25053 if (parent == null || !(parent instanceof View)) { 25054 return null; 25055 } 25056 25057 childToSkip = start; 25058 start = (View) parent; 25059 } 25060 } 25061 25062 /** 25063 * Sets the identifier for this view. The identifier does not have to be 25064 * unique in this view's hierarchy. The identifier should be a positive 25065 * number. 25066 * 25067 * @see #NO_ID 25068 * @see #getId() 25069 * @see #findViewById(int) 25070 * 25071 * @param id a number used to identify the view 25072 * 25073 * @attr ref android.R.styleable#View_id 25074 */ setId(@dRes int id)25075 public void setId(@IdRes int id) { 25076 mID = id; 25077 if (mID == View.NO_ID && mLabelForId != View.NO_ID) { 25078 mID = generateViewId(); 25079 } 25080 } 25081 25082 /** 25083 * {@hide} 25084 * 25085 * @param isRoot true if the view belongs to the root namespace, false 25086 * otherwise 25087 */ 25088 @UnsupportedAppUsage 25089 @TestApi setIsRootNamespace(boolean isRoot)25090 public void setIsRootNamespace(boolean isRoot) { 25091 if (isRoot) { 25092 mPrivateFlags |= PFLAG_IS_ROOT_NAMESPACE; 25093 } else { 25094 mPrivateFlags &= ~PFLAG_IS_ROOT_NAMESPACE; 25095 } 25096 } 25097 25098 /** 25099 * {@hide} 25100 * 25101 * @return true if the view belongs to the root namespace, false otherwise 25102 */ 25103 @UnsupportedAppUsage isRootNamespace()25104 public boolean isRootNamespace() { 25105 return (mPrivateFlags&PFLAG_IS_ROOT_NAMESPACE) != 0; 25106 } 25107 25108 /** 25109 * Returns this view's identifier. 25110 * 25111 * @return a positive integer used to identify the view or {@link #NO_ID} 25112 * if the view has no ID 25113 * 25114 * @see #setId(int) 25115 * @see #findViewById(int) 25116 * @attr ref android.R.styleable#View_id 25117 */ 25118 @IdRes 25119 @ViewDebug.CapturedViewProperty 25120 @InspectableProperty getId()25121 public int getId() { 25122 return mID; 25123 } 25124 25125 /** 25126 * Get the identifier used for this view by the drawing system. 25127 * 25128 * @see RenderNode#getUniqueId() 25129 * @return A long that uniquely identifies this view's drawing component 25130 */ getUniqueDrawingId()25131 public long getUniqueDrawingId() { 25132 return mRenderNode.getUniqueId(); 25133 } 25134 25135 /** 25136 * Returns this view's tag. 25137 * 25138 * @return the Object stored in this view as a tag, or {@code null} if not 25139 * set 25140 * 25141 * @see #setTag(Object) 25142 * @see #getTag(int) 25143 */ 25144 @ViewDebug.ExportedProperty 25145 @InspectableProperty getTag()25146 public Object getTag() { 25147 return mTag; 25148 } 25149 25150 /** 25151 * Sets the tag associated with this view. A tag can be used to mark 25152 * a view in its hierarchy and does not have to be unique within the 25153 * hierarchy. Tags can also be used to store data within a view without 25154 * resorting to another data structure. 25155 * 25156 * @param tag an Object to tag the view with 25157 * 25158 * @see #getTag() 25159 * @see #setTag(int, Object) 25160 */ setTag(final Object tag)25161 public void setTag(final Object tag) { 25162 mTag = tag; 25163 } 25164 25165 /** 25166 * Returns the tag associated with this view and the specified key. 25167 * 25168 * @param key The key identifying the tag 25169 * 25170 * @return the Object stored in this view as a tag, or {@code null} if not 25171 * set 25172 * 25173 * @see #setTag(int, Object) 25174 * @see #getTag() 25175 */ getTag(int key)25176 public Object getTag(int key) { 25177 if (mKeyedTags != null) return mKeyedTags.get(key); 25178 return null; 25179 } 25180 25181 /** 25182 * Sets a tag associated with this view and a key. A tag can be used 25183 * to mark a view in its hierarchy and does not have to be unique within 25184 * the hierarchy. Tags can also be used to store data within a view 25185 * without resorting to another data structure. 25186 * 25187 * The specified key should be an id declared in the resources of the 25188 * application to ensure it is unique (see the <a 25189 * href="{@docRoot}guide/topics/resources/more-resources.html#Id">ID resource type</a>). 25190 * Keys identified as belonging to 25191 * the Android framework or not associated with any package will cause 25192 * an {@link IllegalArgumentException} to be thrown. 25193 * 25194 * @param key The key identifying the tag 25195 * @param tag An Object to tag the view with 25196 * 25197 * @throws IllegalArgumentException If they specified key is not valid 25198 * 25199 * @see #setTag(Object) 25200 * @see #getTag(int) 25201 */ setTag(int key, final Object tag)25202 public void setTag(int key, final Object tag) { 25203 // If the package id is 0x00 or 0x01, it's either an undefined package 25204 // or a framework id 25205 if ((key >>> 24) < 2) { 25206 throw new IllegalArgumentException("The key must be an application-specific " 25207 + "resource id."); 25208 } 25209 25210 setKeyedTag(key, tag); 25211 } 25212 25213 /** 25214 * Variation of {@link #setTag(int, Object)} that enforces the key to be a 25215 * framework id. 25216 * 25217 * @hide 25218 */ 25219 @UnsupportedAppUsage setTagInternal(int key, Object tag)25220 public void setTagInternal(int key, Object tag) { 25221 if ((key >>> 24) != 0x1) { 25222 throw new IllegalArgumentException("The key must be a framework-specific " 25223 + "resource id."); 25224 } 25225 25226 setKeyedTag(key, tag); 25227 } 25228 setKeyedTag(int key, Object tag)25229 private void setKeyedTag(int key, Object tag) { 25230 if (mKeyedTags == null) { 25231 mKeyedTags = new SparseArray<Object>(2); 25232 } 25233 25234 mKeyedTags.put(key, tag); 25235 } 25236 25237 /** 25238 * Prints information about this view in the log output, with the tag 25239 * {@link #VIEW_LOG_TAG}. 25240 * 25241 * @hide 25242 */ 25243 @UnsupportedAppUsage debug()25244 public void debug() { 25245 debug(0); 25246 } 25247 25248 /** 25249 * Prints information about this view in the log output, with the tag 25250 * {@link #VIEW_LOG_TAG}. Each line in the output is preceded with an 25251 * indentation defined by the <code>depth</code>. 25252 * 25253 * @param depth the indentation level 25254 * 25255 * @hide 25256 */ 25257 @UnsupportedAppUsage debug(int depth)25258 protected void debug(int depth) { 25259 String output = debugIndent(depth - 1); 25260 25261 output += "+ " + this; 25262 int id = getId(); 25263 if (id != -1) { 25264 output += " (id=" + id + ")"; 25265 } 25266 Object tag = getTag(); 25267 if (tag != null) { 25268 output += " (tag=" + tag + ")"; 25269 } 25270 Log.d(VIEW_LOG_TAG, output); 25271 25272 if ((mPrivateFlags & PFLAG_FOCUSED) != 0) { 25273 output = debugIndent(depth) + " FOCUSED"; 25274 Log.d(VIEW_LOG_TAG, output); 25275 } 25276 25277 output = debugIndent(depth); 25278 output += "frame={" + mLeft + ", " + mTop + ", " + mRight 25279 + ", " + mBottom + "} scroll={" + mScrollX + ", " + mScrollY 25280 + "} "; 25281 Log.d(VIEW_LOG_TAG, output); 25282 25283 if (mPaddingLeft != 0 || mPaddingTop != 0 || mPaddingRight != 0 25284 || mPaddingBottom != 0) { 25285 output = debugIndent(depth); 25286 output += "padding={" + mPaddingLeft + ", " + mPaddingTop 25287 + ", " + mPaddingRight + ", " + mPaddingBottom + "}"; 25288 Log.d(VIEW_LOG_TAG, output); 25289 } 25290 25291 output = debugIndent(depth); 25292 output += "mMeasureWidth=" + mMeasuredWidth + 25293 " mMeasureHeight=" + mMeasuredHeight; 25294 Log.d(VIEW_LOG_TAG, output); 25295 25296 output = debugIndent(depth); 25297 if (mLayoutParams == null) { 25298 output += "BAD! no layout params"; 25299 } else { 25300 output = mLayoutParams.debug(output); 25301 } 25302 Log.d(VIEW_LOG_TAG, output); 25303 25304 output = debugIndent(depth); 25305 output += "flags={"; 25306 output += View.printFlags(mViewFlags); 25307 output += "}"; 25308 Log.d(VIEW_LOG_TAG, output); 25309 25310 output = debugIndent(depth); 25311 output += "privateFlags={"; 25312 output += View.printPrivateFlags(mPrivateFlags); 25313 output += "}"; 25314 Log.d(VIEW_LOG_TAG, output); 25315 } 25316 25317 /** 25318 * Creates a string of whitespaces used for indentation. 25319 * 25320 * @param depth the indentation level 25321 * @return a String containing (depth * 2 + 3) * 2 white spaces 25322 * 25323 * @hide 25324 */ debugIndent(int depth)25325 protected static String debugIndent(int depth) { 25326 StringBuilder spaces = new StringBuilder((depth * 2 + 3) * 2); 25327 for (int i = 0; i < (depth * 2) + 3; i++) { 25328 spaces.append(' ').append(' '); 25329 } 25330 return spaces.toString(); 25331 } 25332 25333 /** 25334 * <p>Return the offset of the widget's text baseline from the widget's top 25335 * boundary. If this widget does not support baseline alignment, this 25336 * method returns -1. </p> 25337 * 25338 * @return the offset of the baseline within the widget's bounds or -1 25339 * if baseline alignment is not supported 25340 */ 25341 @ViewDebug.ExportedProperty(category = "layout") 25342 @InspectableProperty getBaseline()25343 public int getBaseline() { 25344 return -1; 25345 } 25346 25347 /** 25348 * Returns whether the view hierarchy is currently undergoing a layout pass. This 25349 * information is useful to avoid situations such as calling {@link #requestLayout()} during 25350 * a layout pass. 25351 * 25352 * @return whether the view hierarchy is currently undergoing a layout pass 25353 */ isInLayout()25354 public boolean isInLayout() { 25355 ViewRootImpl viewRoot = getViewRootImpl(); 25356 return (viewRoot != null && viewRoot.isInLayout()); 25357 } 25358 25359 /** 25360 * Call this when something has changed which has invalidated the 25361 * layout of this view. This will schedule a layout pass of the view 25362 * tree. This should not be called while the view hierarchy is currently in a layout 25363 * pass ({@link #isInLayout()}. If layout is happening, the request may be honored at the 25364 * end of the current layout pass (and then layout will run again) or after the current 25365 * frame is drawn and the next layout occurs. 25366 * 25367 * <p>Subclasses which override this method should call the superclass method to 25368 * handle possible request-during-layout errors correctly.</p> 25369 */ 25370 @CallSuper requestLayout()25371 public void requestLayout() { 25372 if (mMeasureCache != null) mMeasureCache.clear(); 25373 25374 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == null) { 25375 // Only trigger request-during-layout logic if this is the view requesting it, 25376 // not the views in its parent hierarchy 25377 ViewRootImpl viewRoot = getViewRootImpl(); 25378 if (viewRoot != null && viewRoot.isInLayout()) { 25379 if (!viewRoot.requestLayoutDuringLayout(this)) { 25380 return; 25381 } 25382 } 25383 mAttachInfo.mViewRequestingLayout = this; 25384 } 25385 25386 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 25387 mPrivateFlags |= PFLAG_INVALIDATED; 25388 25389 if (mParent != null && !mParent.isLayoutRequested()) { 25390 mParent.requestLayout(); 25391 } 25392 if (mAttachInfo != null && mAttachInfo.mViewRequestingLayout == this) { 25393 mAttachInfo.mViewRequestingLayout = null; 25394 } 25395 } 25396 25397 /** 25398 * Forces this view to be laid out during the next layout pass. 25399 * This method does not call requestLayout() or forceLayout() 25400 * on the parent. 25401 */ forceLayout()25402 public void forceLayout() { 25403 if (mMeasureCache != null) mMeasureCache.clear(); 25404 25405 mPrivateFlags |= PFLAG_FORCE_LAYOUT; 25406 mPrivateFlags |= PFLAG_INVALIDATED; 25407 } 25408 25409 /** 25410 * <p> 25411 * This is called to find out how big a view should be. The parent 25412 * supplies constraint information in the width and height parameters. 25413 * </p> 25414 * 25415 * <p> 25416 * The actual measurement work of a view is performed in 25417 * {@link #onMeasure(int, int)}, called by this method. Therefore, only 25418 * {@link #onMeasure(int, int)} can and must be overridden by subclasses. 25419 * </p> 25420 * 25421 * 25422 * @param widthMeasureSpec Horizontal space requirements as imposed by the 25423 * parent 25424 * @param heightMeasureSpec Vertical space requirements as imposed by the 25425 * parent 25426 * 25427 * @see #onMeasure(int, int) 25428 */ measure(int widthMeasureSpec, int heightMeasureSpec)25429 public final void measure(int widthMeasureSpec, int heightMeasureSpec) { 25430 boolean optical = isLayoutModeOptical(this); 25431 if (optical != isLayoutModeOptical(mParent)) { 25432 Insets insets = getOpticalInsets(); 25433 int oWidth = insets.left + insets.right; 25434 int oHeight = insets.top + insets.bottom; 25435 widthMeasureSpec = MeasureSpec.adjust(widthMeasureSpec, optical ? -oWidth : oWidth); 25436 heightMeasureSpec = MeasureSpec.adjust(heightMeasureSpec, optical ? -oHeight : oHeight); 25437 } 25438 25439 // Suppress sign extension for the low bytes 25440 long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; 25441 if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); 25442 25443 final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; 25444 25445 // Optimize layout by avoiding an extra EXACTLY pass when the view is 25446 // already measured as the correct size. In API 23 and below, this 25447 // extra pass is required to make LinearLayout re-distribute weight. 25448 final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec 25449 || heightMeasureSpec != mOldHeightMeasureSpec; 25450 final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY 25451 && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; 25452 final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) 25453 && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); 25454 final boolean needsLayout = specChanged 25455 && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize); 25456 25457 if (forceLayout || needsLayout) { 25458 // first clears the measured dimension flag 25459 mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; 25460 25461 resolveRtlPropertiesIfNeeded(); 25462 25463 int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); 25464 if (cacheIndex < 0 || sIgnoreMeasureCache) { 25465 // measure ourselves, this should set the measured dimension flag back 25466 onMeasure(widthMeasureSpec, heightMeasureSpec); 25467 mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 25468 } else { 25469 long value = mMeasureCache.valueAt(cacheIndex); 25470 // Casting a long to int drops the high 32 bits, no mask needed 25471 setMeasuredDimensionRaw((int) (value >> 32), (int) value); 25472 mPrivateFlags3 |= PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT; 25473 } 25474 25475 // flag not set, setMeasuredDimension() was not invoked, we raise 25476 // an exception to warn the developer 25477 if ((mPrivateFlags & PFLAG_MEASURED_DIMENSION_SET) != PFLAG_MEASURED_DIMENSION_SET) { 25478 throw new IllegalStateException("View with id " + getId() + ": " 25479 + getClass().getName() + "#onMeasure() did not set the" 25480 + " measured dimension by calling" 25481 + " setMeasuredDimension()"); 25482 } 25483 25484 mPrivateFlags |= PFLAG_LAYOUT_REQUIRED; 25485 } 25486 25487 mOldWidthMeasureSpec = widthMeasureSpec; 25488 mOldHeightMeasureSpec = heightMeasureSpec; 25489 25490 mMeasureCache.put(key, ((long) mMeasuredWidth) << 32 | 25491 (long) mMeasuredHeight & 0xffffffffL); // suppress sign extension 25492 } 25493 25494 /** 25495 * <p> 25496 * Measure the view and its content to determine the measured width and the 25497 * measured height. This method is invoked by {@link #measure(int, int)} and 25498 * should be overridden by subclasses to provide accurate and efficient 25499 * measurement of their contents. 25500 * </p> 25501 * 25502 * <p> 25503 * <strong>CONTRACT:</strong> When overriding this method, you 25504 * <em>must</em> call {@link #setMeasuredDimension(int, int)} to store the 25505 * measured width and height of this view. Failure to do so will trigger an 25506 * <code>IllegalStateException</code>, thrown by 25507 * {@link #measure(int, int)}. Calling the superclass' 25508 * {@link #onMeasure(int, int)} is a valid use. 25509 * </p> 25510 * 25511 * <p> 25512 * The base class implementation of measure defaults to the background size, 25513 * unless a larger size is allowed by the MeasureSpec. Subclasses should 25514 * override {@link #onMeasure(int, int)} to provide better measurements of 25515 * their content. 25516 * </p> 25517 * 25518 * <p> 25519 * If this method is overridden, it is the subclass's responsibility to make 25520 * sure the measured height and width are at least the view's minimum height 25521 * and width ({@link #getSuggestedMinimumHeight()} and 25522 * {@link #getSuggestedMinimumWidth()}). 25523 * </p> 25524 * 25525 * @param widthMeasureSpec horizontal space requirements as imposed by the parent. 25526 * The requirements are encoded with 25527 * {@link android.view.View.MeasureSpec}. 25528 * @param heightMeasureSpec vertical space requirements as imposed by the parent. 25529 * The requirements are encoded with 25530 * {@link android.view.View.MeasureSpec}. 25531 * 25532 * @see #getMeasuredWidth() 25533 * @see #getMeasuredHeight() 25534 * @see #setMeasuredDimension(int, int) 25535 * @see #getSuggestedMinimumHeight() 25536 * @see #getSuggestedMinimumWidth() 25537 * @see android.view.View.MeasureSpec#getMode(int) 25538 * @see android.view.View.MeasureSpec#getSize(int) 25539 */ onMeasure(int widthMeasureSpec, int heightMeasureSpec)25540 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 25541 setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), 25542 getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); 25543 } 25544 25545 /** 25546 * <p>This method must be called by {@link #onMeasure(int, int)} to store the 25547 * measured width and measured height. Failing to do so will trigger an 25548 * exception at measurement time.</p> 25549 * 25550 * @param measuredWidth The measured width of this view. May be a complex 25551 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25552 * {@link #MEASURED_STATE_TOO_SMALL}. 25553 * @param measuredHeight The measured height of this view. May be a complex 25554 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25555 * {@link #MEASURED_STATE_TOO_SMALL}. 25556 */ setMeasuredDimension(int measuredWidth, int measuredHeight)25557 protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { 25558 boolean optical = isLayoutModeOptical(this); 25559 if (optical != isLayoutModeOptical(mParent)) { 25560 Insets insets = getOpticalInsets(); 25561 int opticalWidth = insets.left + insets.right; 25562 int opticalHeight = insets.top + insets.bottom; 25563 25564 measuredWidth += optical ? opticalWidth : -opticalWidth; 25565 measuredHeight += optical ? opticalHeight : -opticalHeight; 25566 } 25567 setMeasuredDimensionRaw(measuredWidth, measuredHeight); 25568 } 25569 25570 /** 25571 * Sets the measured dimension without extra processing for things like optical bounds. 25572 * Useful for reapplying consistent values that have already been cooked with adjustments 25573 * for optical bounds, etc. such as those from the measurement cache. 25574 * 25575 * @param measuredWidth The measured width of this view. May be a complex 25576 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25577 * {@link #MEASURED_STATE_TOO_SMALL}. 25578 * @param measuredHeight The measured height of this view. May be a complex 25579 * bit mask as defined by {@link #MEASURED_SIZE_MASK} and 25580 * {@link #MEASURED_STATE_TOO_SMALL}. 25581 */ setMeasuredDimensionRaw(int measuredWidth, int measuredHeight)25582 private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { 25583 mMeasuredWidth = measuredWidth; 25584 mMeasuredHeight = measuredHeight; 25585 25586 mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; 25587 } 25588 25589 /** 25590 * Merge two states as returned by {@link #getMeasuredState()}. 25591 * @param curState The current state as returned from a view or the result 25592 * of combining multiple views. 25593 * @param newState The new view state to combine. 25594 * @return Returns a new integer reflecting the combination of the two 25595 * states. 25596 */ combineMeasuredStates(int curState, int newState)25597 public static int combineMeasuredStates(int curState, int newState) { 25598 return curState | newState; 25599 } 25600 25601 /** 25602 * Version of {@link #resolveSizeAndState(int, int, int)} 25603 * returning only the {@link #MEASURED_SIZE_MASK} bits of the result. 25604 */ resolveSize(int size, int measureSpec)25605 public static int resolveSize(int size, int measureSpec) { 25606 return resolveSizeAndState(size, measureSpec, 0) & MEASURED_SIZE_MASK; 25607 } 25608 25609 /** 25610 * Utility to reconcile a desired size and state, with constraints imposed 25611 * by a MeasureSpec. Will take the desired size, unless a different size 25612 * is imposed by the constraints. The returned value is a compound integer, 25613 * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and 25614 * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the 25615 * resulting size is smaller than the size the view wants to be. 25616 * 25617 * @param size How big the view wants to be. 25618 * @param measureSpec Constraints imposed by the parent. 25619 * @param childMeasuredState Size information bit mask for the view's 25620 * children. 25621 * @return Size information bit mask as defined by 25622 * {@link #MEASURED_SIZE_MASK} and 25623 * {@link #MEASURED_STATE_TOO_SMALL}. 25624 */ resolveSizeAndState(int size, int measureSpec, int childMeasuredState)25625 public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) { 25626 final int specMode = MeasureSpec.getMode(measureSpec); 25627 final int specSize = MeasureSpec.getSize(measureSpec); 25628 final int result; 25629 switch (specMode) { 25630 case MeasureSpec.AT_MOST: 25631 if (specSize < size) { 25632 result = specSize | MEASURED_STATE_TOO_SMALL; 25633 } else { 25634 result = size; 25635 } 25636 break; 25637 case MeasureSpec.EXACTLY: 25638 result = specSize; 25639 break; 25640 case MeasureSpec.UNSPECIFIED: 25641 default: 25642 result = size; 25643 } 25644 return result | (childMeasuredState & MEASURED_STATE_MASK); 25645 } 25646 25647 /** 25648 * Utility to return a default size. Uses the supplied size if the 25649 * MeasureSpec imposed no constraints. Will get larger if allowed 25650 * by the MeasureSpec. 25651 * 25652 * @param size Default size for this view 25653 * @param measureSpec Constraints imposed by the parent 25654 * @return The size this view should be. 25655 */ getDefaultSize(int size, int measureSpec)25656 public static int getDefaultSize(int size, int measureSpec) { 25657 int result = size; 25658 int specMode = MeasureSpec.getMode(measureSpec); 25659 int specSize = MeasureSpec.getSize(measureSpec); 25660 25661 switch (specMode) { 25662 case MeasureSpec.UNSPECIFIED: 25663 result = size; 25664 break; 25665 case MeasureSpec.AT_MOST: 25666 case MeasureSpec.EXACTLY: 25667 result = specSize; 25668 break; 25669 } 25670 return result; 25671 } 25672 25673 /** 25674 * Returns the suggested minimum height that the view should use. This 25675 * returns the maximum of the view's minimum height 25676 * and the background's minimum height 25677 * ({@link android.graphics.drawable.Drawable#getMinimumHeight()}). 25678 * <p> 25679 * When being used in {@link #onMeasure(int, int)}, the caller should still 25680 * ensure the returned height is within the requirements of the parent. 25681 * 25682 * @return The suggested minimum height of the view. 25683 */ getSuggestedMinimumHeight()25684 protected int getSuggestedMinimumHeight() { 25685 return (mBackground == null) ? mMinHeight : max(mMinHeight, mBackground.getMinimumHeight()); 25686 25687 } 25688 25689 /** 25690 * Returns the suggested minimum width that the view should use. This 25691 * returns the maximum of the view's minimum width 25692 * and the background's minimum width 25693 * ({@link android.graphics.drawable.Drawable#getMinimumWidth()}). 25694 * <p> 25695 * When being used in {@link #onMeasure(int, int)}, the caller should still 25696 * ensure the returned width is within the requirements of the parent. 25697 * 25698 * @return The suggested minimum width of the view. 25699 */ getSuggestedMinimumWidth()25700 protected int getSuggestedMinimumWidth() { 25701 return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); 25702 } 25703 25704 /** 25705 * Returns the minimum height of the view. 25706 * 25707 * @return the minimum height the view will try to be, in pixels 25708 * 25709 * @see #setMinimumHeight(int) 25710 * 25711 * @attr ref android.R.styleable#View_minHeight 25712 */ 25713 @InspectableProperty(name = "minHeight") getMinimumHeight()25714 public int getMinimumHeight() { 25715 return mMinHeight; 25716 } 25717 25718 /** 25719 * Sets the minimum height of the view. It is not guaranteed the view will 25720 * be able to achieve this minimum height (for example, if its parent layout 25721 * constrains it with less available height). 25722 * 25723 * @param minHeight The minimum height the view will try to be, in pixels 25724 * 25725 * @see #getMinimumHeight() 25726 * 25727 * @attr ref android.R.styleable#View_minHeight 25728 */ 25729 @RemotableViewMethod setMinimumHeight(int minHeight)25730 public void setMinimumHeight(int minHeight) { 25731 mMinHeight = minHeight; 25732 requestLayout(); 25733 } 25734 25735 /** 25736 * Returns the minimum width of the view. 25737 * 25738 * @return the minimum width the view will try to be, in pixels 25739 * 25740 * @see #setMinimumWidth(int) 25741 * 25742 * @attr ref android.R.styleable#View_minWidth 25743 */ 25744 @InspectableProperty(name = "minWidth") getMinimumWidth()25745 public int getMinimumWidth() { 25746 return mMinWidth; 25747 } 25748 25749 /** 25750 * Sets the minimum width of the view. It is not guaranteed the view will 25751 * be able to achieve this minimum width (for example, if its parent layout 25752 * constrains it with less available width). 25753 * 25754 * @param minWidth The minimum width the view will try to be, in pixels 25755 * 25756 * @see #getMinimumWidth() 25757 * 25758 * @attr ref android.R.styleable#View_minWidth 25759 */ setMinimumWidth(int minWidth)25760 public void setMinimumWidth(int minWidth) { 25761 mMinWidth = minWidth; 25762 requestLayout(); 25763 25764 } 25765 25766 /** 25767 * Get the animation currently associated with this view. 25768 * 25769 * @return The animation that is currently playing or 25770 * scheduled to play for this view. 25771 */ getAnimation()25772 public Animation getAnimation() { 25773 return mCurrentAnimation; 25774 } 25775 25776 /** 25777 * Start the specified animation now. 25778 * 25779 * @param animation the animation to start now 25780 */ startAnimation(Animation animation)25781 public void startAnimation(Animation animation) { 25782 animation.setStartTime(Animation.START_ON_FIRST_FRAME); 25783 setAnimation(animation); 25784 invalidateParentCaches(); 25785 invalidate(true); 25786 } 25787 25788 /** 25789 * Cancels any animations for this view. 25790 */ clearAnimation()25791 public void clearAnimation() { 25792 if (mCurrentAnimation != null) { 25793 mCurrentAnimation.detach(); 25794 } 25795 mCurrentAnimation = null; 25796 invalidateParentIfNeeded(); 25797 } 25798 25799 /** 25800 * Sets the next animation to play for this view. 25801 * If you want the animation to play immediately, use 25802 * {@link #startAnimation(android.view.animation.Animation)} instead. 25803 * This method provides allows fine-grained 25804 * control over the start time and invalidation, but you 25805 * must make sure that 1) the animation has a start time set, and 25806 * 2) the view's parent (which controls animations on its children) 25807 * will be invalidated when the animation is supposed to 25808 * start. 25809 * 25810 * @param animation The next animation, or null. 25811 */ setAnimation(Animation animation)25812 public void setAnimation(Animation animation) { 25813 mCurrentAnimation = animation; 25814 25815 if (animation != null) { 25816 // If the screen is off assume the animation start time is now instead of 25817 // the next frame we draw. Keeping the START_ON_FIRST_FRAME start time 25818 // would cause the animation to start when the screen turns back on 25819 if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF 25820 && animation.getStartTime() == Animation.START_ON_FIRST_FRAME) { 25821 animation.setStartTime(AnimationUtils.currentAnimationTimeMillis()); 25822 } 25823 animation.reset(); 25824 } 25825 } 25826 25827 /** 25828 * Invoked by a parent ViewGroup to notify the start of the animation 25829 * currently associated with this view. If you override this method, 25830 * always call super.onAnimationStart(); 25831 * 25832 * @see #setAnimation(android.view.animation.Animation) 25833 * @see #getAnimation() 25834 */ 25835 @CallSuper onAnimationStart()25836 protected void onAnimationStart() { 25837 mPrivateFlags |= PFLAG_ANIMATION_STARTED; 25838 } 25839 25840 /** 25841 * Invoked by a parent ViewGroup to notify the end of the animation 25842 * currently associated with this view. If you override this method, 25843 * always call super.onAnimationEnd(); 25844 * 25845 * @see #setAnimation(android.view.animation.Animation) 25846 * @see #getAnimation() 25847 */ 25848 @CallSuper onAnimationEnd()25849 protected void onAnimationEnd() { 25850 mPrivateFlags &= ~PFLAG_ANIMATION_STARTED; 25851 } 25852 25853 /** 25854 * Invoked if there is a Transform that involves alpha. Subclass that can 25855 * draw themselves with the specified alpha should return true, and then 25856 * respect that alpha when their onDraw() is called. If this returns false 25857 * then the view may be redirected to draw into an offscreen buffer to 25858 * fulfill the request, which will look fine, but may be slower than if the 25859 * subclass handles it internally. The default implementation returns false. 25860 * 25861 * @param alpha The alpha (0..255) to apply to the view's drawing 25862 * @return true if the view can draw with the specified alpha. 25863 */ onSetAlpha(int alpha)25864 protected boolean onSetAlpha(int alpha) { 25865 return false; 25866 } 25867 25868 /** 25869 * This is used by the RootView to perform an optimization when 25870 * the view hierarchy contains one or several SurfaceView. 25871 * SurfaceView is always considered transparent, but its children are not, 25872 * therefore all View objects remove themselves from the global transparent 25873 * region (passed as a parameter to this function). 25874 * 25875 * @param region The transparent region for this ViewAncestor (window). 25876 * 25877 * @return Returns true if the effective visibility of the view at this 25878 * point is opaque, regardless of the transparent region; returns false 25879 * if it is possible for underlying windows to be seen behind the view. 25880 * 25881 * {@hide} 25882 */ 25883 @UnsupportedAppUsage gatherTransparentRegion(Region region)25884 public boolean gatherTransparentRegion(Region region) { 25885 final AttachInfo attachInfo = mAttachInfo; 25886 if (region != null && attachInfo != null) { 25887 final int pflags = mPrivateFlags; 25888 if ((pflags & PFLAG_SKIP_DRAW) == 0) { 25889 // The SKIP_DRAW flag IS NOT set, so this view draws. We need to 25890 // remove it from the transparent region. 25891 final int[] location = attachInfo.mTransparentLocation; 25892 getLocationInWindow(location); 25893 // When a view has Z value, then it will be better to leave some area below the view 25894 // for drawing shadow. The shadow outset is proportional to the Z value. Note that 25895 // the bottom part needs more offset than the left, top and right parts due to the 25896 // spot light effects. 25897 int shadowOffset = getZ() > 0 ? (int) getZ() : 0; 25898 region.op(location[0] - shadowOffset, location[1] - shadowOffset, 25899 location[0] + mRight - mLeft + shadowOffset, 25900 location[1] + mBottom - mTop + (shadowOffset * 3), Region.Op.DIFFERENCE); 25901 } else { 25902 if (mBackground != null && mBackground.getOpacity() != PixelFormat.TRANSPARENT) { 25903 // The SKIP_DRAW flag IS set and the background drawable exists, we remove 25904 // the background drawable's non-transparent parts from this transparent region. 25905 applyDrawableToTransparentRegion(mBackground, region); 25906 } 25907 if (mForegroundInfo != null && mForegroundInfo.mDrawable != null 25908 && mForegroundInfo.mDrawable.getOpacity() != PixelFormat.TRANSPARENT) { 25909 // Similarly, we remove the foreground drawable's non-transparent parts. 25910 applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); 25911 } 25912 if (mDefaultFocusHighlight != null 25913 && mDefaultFocusHighlight.getOpacity() != PixelFormat.TRANSPARENT) { 25914 // Similarly, we remove the default focus highlight's non-transparent parts. 25915 applyDrawableToTransparentRegion(mDefaultFocusHighlight, region); 25916 } 25917 } 25918 } 25919 return true; 25920 } 25921 25922 /** 25923 * Play a sound effect for this view. 25924 * 25925 * <p>The framework will play sound effects for some built in actions, such as 25926 * clicking, but you may wish to play these effects in your widget, 25927 * for instance, for internal navigation. 25928 * 25929 * <p>The sound effect will only be played if sound effects are enabled by the user, and 25930 * {@link #isSoundEffectsEnabled()} is true. 25931 * 25932 * @param soundConstant One of the constants defined in {@link SoundEffectConstants} 25933 */ playSoundEffect(int soundConstant)25934 public void playSoundEffect(int soundConstant) { 25935 if (mAttachInfo == null || mAttachInfo.mRootCallbacks == null || !isSoundEffectsEnabled()) { 25936 return; 25937 } 25938 mAttachInfo.mRootCallbacks.playSoundEffect(soundConstant); 25939 } 25940 25941 /** 25942 * BZZZTT!!1! 25943 * 25944 * <p>Provide haptic feedback to the user for this view. 25945 * 25946 * <p>The framework will provide haptic feedback for some built in actions, 25947 * such as long presses, but you may wish to provide feedback for your 25948 * own widget. 25949 * 25950 * <p>The feedback will only be performed if 25951 * {@link #isHapticFeedbackEnabled()} is true. 25952 * 25953 * @param feedbackConstant One of the constants defined in 25954 * {@link HapticFeedbackConstants} 25955 */ performHapticFeedback(int feedbackConstant)25956 public boolean performHapticFeedback(int feedbackConstant) { 25957 return performHapticFeedback(feedbackConstant, 0); 25958 } 25959 25960 /** 25961 * BZZZTT!!1! 25962 * 25963 * <p>Like {@link #performHapticFeedback(int)}, with additional options. 25964 * 25965 * @param feedbackConstant One of the constants defined in 25966 * {@link HapticFeedbackConstants} 25967 * @param flags Additional flags as per {@link HapticFeedbackConstants}. 25968 */ performHapticFeedback(int feedbackConstant, int flags)25969 public boolean performHapticFeedback(int feedbackConstant, int flags) { 25970 if (mAttachInfo == null) { 25971 return false; 25972 } 25973 //noinspection SimplifiableIfStatement 25974 if ((flags & HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING) == 0 25975 && !isHapticFeedbackEnabled()) { 25976 return false; 25977 } 25978 return mAttachInfo.mRootCallbacks.performHapticFeedback(feedbackConstant, 25979 (flags & HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING) != 0); 25980 } 25981 25982 /** 25983 * Request that the visibility of the status bar or other screen/window 25984 * decorations be changed. 25985 * 25986 * <p>This method is used to put the over device UI into temporary modes 25987 * where the user's attention is focused more on the application content, 25988 * by dimming or hiding surrounding system affordances. This is typically 25989 * used in conjunction with {@link Window#FEATURE_ACTION_BAR_OVERLAY 25990 * Window.FEATURE_ACTION_BAR_OVERLAY}, allowing the applications content 25991 * to be placed behind the action bar (and with these flags other system 25992 * affordances) so that smooth transitions between hiding and showing them 25993 * can be done. 25994 * 25995 * <p>Two representative examples of the use of system UI visibility is 25996 * implementing a content browsing application (like a magazine reader) 25997 * and a video playing application. 25998 * 25999 * <p>The first code shows a typical implementation of a View in a content 26000 * browsing application. In this implementation, the application goes 26001 * into a content-oriented mode by hiding the status bar and action bar, 26002 * and putting the navigation elements into lights out mode. The user can 26003 * then interact with content while in this mode. Such an application should 26004 * provide an easy way for the user to toggle out of the mode (such as to 26005 * check information in the status bar or access notifications). In the 26006 * implementation here, this is done simply by tapping on the content. 26007 * 26008 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/ContentBrowserActivity.java 26009 * content} 26010 * 26011 * <p>This second code sample shows a typical implementation of a View 26012 * in a video playing application. In this situation, while the video is 26013 * playing the application would like to go into a complete full-screen mode, 26014 * to use as much of the display as possible for the video. When in this state 26015 * the user can not interact with the application; the system intercepts 26016 * touching on the screen to pop the UI out of full screen mode. See 26017 * {@link #fitSystemWindows(Rect)} for a sample layout that goes with this code. 26018 * 26019 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/VideoPlayerActivity.java 26020 * content} 26021 * 26022 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 26023 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 26024 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 26025 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 26026 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 26027 * 26028 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 26029 * instead. 26030 */ 26031 @Deprecated setSystemUiVisibility(int visibility)26032 public void setSystemUiVisibility(int visibility) { 26033 if (visibility != mSystemUiVisibility) { 26034 mSystemUiVisibility = visibility; 26035 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 26036 mParent.recomputeViewAttributes(this); 26037 } 26038 } 26039 } 26040 26041 /** 26042 * Returns the last {@link #setSystemUiVisibility(int)} that this view has requested. 26043 * @return Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 26044 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, {@link #SYSTEM_UI_FLAG_FULLSCREEN}, 26045 * {@link #SYSTEM_UI_FLAG_LAYOUT_STABLE}, {@link #SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION}, 26046 * {@link #SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN}, {@link #SYSTEM_UI_FLAG_IMMERSIVE}, 26047 * and {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY}. 26048 * 26049 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 26050 * instead. 26051 */ 26052 @Deprecated getSystemUiVisibility()26053 public int getSystemUiVisibility() { 26054 return mSystemUiVisibility; 26055 } 26056 26057 /** 26058 * Returns the current system UI visibility that is currently set for 26059 * the entire window. This is the combination of the 26060 * {@link #setSystemUiVisibility(int)} values supplied by all of the 26061 * views in the window. 26062 * 26063 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 26064 * instead. 26065 */ 26066 @Deprecated getWindowSystemUiVisibility()26067 public int getWindowSystemUiVisibility() { 26068 return mAttachInfo != null ? mAttachInfo.mSystemUiVisibility : 0; 26069 } 26070 26071 /** 26072 * Override to find out when the window's requested system UI visibility 26073 * has changed, that is the value returned by {@link #getWindowSystemUiVisibility()}. 26074 * This is different from the callbacks received through 26075 * {@link #setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener)} 26076 * in that this is only telling you about the local request of the window, 26077 * not the actual values applied by the system. 26078 * 26079 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 26080 * instead. 26081 */ 26082 @Deprecated onWindowSystemUiVisibilityChanged(int visible)26083 public void onWindowSystemUiVisibilityChanged(int visible) { 26084 } 26085 26086 /** 26087 * Dispatch callbacks to {@link #onWindowSystemUiVisibilityChanged(int)} down 26088 * the view hierarchy. 26089 * 26090 * @deprecated SystemUiVisibility flags are deprecated. Use {@link WindowInsetsController} 26091 * instead. 26092 */ 26093 @Deprecated dispatchWindowSystemUiVisiblityChanged(int visible)26094 public void dispatchWindowSystemUiVisiblityChanged(int visible) { 26095 onWindowSystemUiVisibilityChanged(visible); 26096 } 26097 26098 /** 26099 * Set a listener to receive callbacks when the visibility of the system bar changes. 26100 * @param l The {@link OnSystemUiVisibilityChangeListener} to receive callbacks. 26101 * 26102 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 26103 * by setting a {@link OnApplyWindowInsetsListener} on this view. 26104 */ 26105 @Deprecated setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l)26106 public void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) { 26107 getListenerInfo().mOnSystemUiVisibilityChangeListener = l; 26108 if (mParent != null && mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) { 26109 mParent.recomputeViewAttributes(this); 26110 } 26111 } 26112 26113 /** 26114 * Dispatch callbacks to {@link #setOnSystemUiVisibilityChangeListener} down 26115 * the view hierarchy. 26116 * 26117 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 26118 * by setting a {@link OnApplyWindowInsetsListener} on this view. 26119 */ 26120 @Deprecated dispatchSystemUiVisibilityChanged(int visibility)26121 public void dispatchSystemUiVisibilityChanged(int visibility) { 26122 ListenerInfo li = mListenerInfo; 26123 if (li != null && li.mOnSystemUiVisibilityChangeListener != null) { 26124 li.mOnSystemUiVisibilityChangeListener.onSystemUiVisibilityChange( 26125 visibility & PUBLIC_STATUS_BAR_VISIBILITY_MASK); 26126 } 26127 } 26128 updateLocalSystemUiVisibility(int localValue, int localChanges)26129 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) { 26130 int val = (mSystemUiVisibility&~localChanges) | (localValue&localChanges); 26131 if (val != mSystemUiVisibility) { 26132 setSystemUiVisibility(val); 26133 return true; 26134 } 26135 return false; 26136 } 26137 26138 /** @hide */ 26139 @UnsupportedAppUsage setDisabledSystemUiVisibility(int flags)26140 public void setDisabledSystemUiVisibility(int flags) { 26141 if (mAttachInfo != null) { 26142 if (mAttachInfo.mDisabledSystemUiVisibility != flags) { 26143 mAttachInfo.mDisabledSystemUiVisibility = flags; 26144 if (mParent != null) { 26145 mParent.recomputeViewAttributes(this); 26146 } 26147 } 26148 } 26149 } 26150 26151 /** 26152 * Creates an image that the system displays during the drag and drop 26153 * operation. This is called a "drag shadow". The default implementation 26154 * for a DragShadowBuilder based on a View returns an image that has exactly the same 26155 * appearance as the given View. The default also positions the center of the drag shadow 26156 * directly under the touch point. If no View is provided (the constructor with no parameters 26157 * is used), and {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} and 26158 * {@link #onDrawShadow(Canvas) onDrawShadow()} are not overridden, then the 26159 * default is an invisible drag shadow. 26160 * <p> 26161 * You are not required to use the View you provide to the constructor as the basis of the 26162 * drag shadow. The {@link #onDrawShadow(Canvas) onDrawShadow()} method allows you to draw 26163 * anything you want as the drag shadow. 26164 * </p> 26165 * <p> 26166 * You pass a DragShadowBuilder object to the system when you start the drag. The system 26167 * calls {@link #onProvideShadowMetrics(Point,Point) onProvideShadowMetrics()} to get the 26168 * size and position of the drag shadow. It uses this data to construct a 26169 * {@link android.graphics.Canvas} object, then it calls {@link #onDrawShadow(Canvas) onDrawShadow()} 26170 * so that your application can draw the shadow image in the Canvas. 26171 * </p> 26172 * 26173 * <div class="special reference"> 26174 * <h3>Developer Guides</h3> 26175 * <p>For a guide to implementing drag and drop features, read the 26176 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 26177 * </div> 26178 */ 26179 public static class DragShadowBuilder { 26180 @UnsupportedAppUsage 26181 private final WeakReference<View> mView; 26182 26183 /** 26184 * Constructs a shadow image builder based on a View. By default, the resulting drag 26185 * shadow will have the same appearance and dimensions as the View, with the touch point 26186 * over the center of the View. 26187 * @param view A View. Any View in scope can be used. 26188 */ DragShadowBuilder(View view)26189 public DragShadowBuilder(View view) { 26190 mView = new WeakReference<View>(view); 26191 } 26192 26193 /** 26194 * Construct a shadow builder object with no associated View. This 26195 * constructor variant is only useful when the {@link #onProvideShadowMetrics(Point, Point)} 26196 * and {@link #onDrawShadow(Canvas)} methods are also overridden in order 26197 * to supply the drag shadow's dimensions and appearance without 26198 * reference to any View object. 26199 */ DragShadowBuilder()26200 public DragShadowBuilder() { 26201 mView = new WeakReference<View>(null); 26202 } 26203 26204 /** 26205 * Returns the View object that had been passed to the 26206 * {@link #DragShadowBuilder(View)} 26207 * constructor. If that View parameter was {@code null} or if the 26208 * {@link #DragShadowBuilder()} 26209 * constructor was used to instantiate the builder object, this method will return 26210 * null. 26211 * 26212 * @return The View object associate with this builder object. 26213 */ 26214 @SuppressWarnings({"JavadocReference"}) getView()26215 final public View getView() { 26216 return mView.get(); 26217 } 26218 26219 /** 26220 * Provides the metrics for the shadow image. These include the dimensions of 26221 * the shadow image, and the point within that shadow that should 26222 * be centered under the touch location while dragging. 26223 * <p> 26224 * The default implementation sets the dimensions of the shadow to be the 26225 * same as the dimensions of the View itself and centers the shadow under 26226 * the touch point. 26227 * </p> 26228 * 26229 * @param outShadowSize A {@link android.graphics.Point} containing the width and height 26230 * of the shadow image. Your application must set {@link android.graphics.Point#x} to the 26231 * desired width and must set {@link android.graphics.Point#y} to the desired height of the 26232 * image. Since Android P, the width and height must be positive values. 26233 * 26234 * @param outShadowTouchPoint A {@link android.graphics.Point} for the position within the 26235 * shadow image that should be underneath the touch point during the drag and drop 26236 * operation. Your application must set {@link android.graphics.Point#x} to the 26237 * X coordinate and {@link android.graphics.Point#y} to the Y coordinate of this position. 26238 */ onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint)26239 public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) { 26240 final View view = mView.get(); 26241 if (view != null) { 26242 outShadowSize.set(view.getWidth(), view.getHeight()); 26243 outShadowTouchPoint.set(outShadowSize.x / 2, outShadowSize.y / 2); 26244 } else { 26245 Log.e(View.VIEW_LOG_TAG, "Asked for drag thumb metrics but no view"); 26246 } 26247 } 26248 26249 /** 26250 * Draws the shadow image. The system creates the {@link android.graphics.Canvas} object 26251 * based on the dimensions it received from the 26252 * {@link #onProvideShadowMetrics(Point, Point)} callback. 26253 * 26254 * @param canvas A {@link android.graphics.Canvas} object in which to draw the shadow image. 26255 */ onDrawShadow(Canvas canvas)26256 public void onDrawShadow(Canvas canvas) { 26257 final View view = mView.get(); 26258 if (view != null) { 26259 view.draw(canvas); 26260 } else { 26261 Log.e(View.VIEW_LOG_TAG, "Asked to draw drag shadow but no view"); 26262 } 26263 } 26264 } 26265 26266 /** 26267 * @deprecated Use {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) 26268 * startDragAndDrop()} for newer platform versions. 26269 */ 26270 @Deprecated startDrag(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)26271 public final boolean startDrag(ClipData data, DragShadowBuilder shadowBuilder, 26272 Object myLocalState, int flags) { 26273 return startDragAndDrop(data, shadowBuilder, myLocalState, flags); 26274 } 26275 26276 /** 26277 * Starts a drag and drop operation. When your application calls this method, it passes a 26278 * {@link android.view.View.DragShadowBuilder} object to the system. The 26279 * system calls this object's {@link DragShadowBuilder#onProvideShadowMetrics(Point, Point)} 26280 * to get metrics for the drag shadow, and then calls the object's 26281 * {@link DragShadowBuilder#onDrawShadow(Canvas)} to draw the drag shadow itself. 26282 * <p> 26283 * Once the system has the drag shadow, it begins the drag and drop operation by sending 26284 * drag events to all the View objects in your application that are currently visible. It does 26285 * this either by calling the View object's drag listener (an implementation of 26286 * {@link android.view.View.OnDragListener#onDrag(View,DragEvent) onDrag()} or by calling the 26287 * View object's {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} method. 26288 * Both are passed a {@link android.view.DragEvent} object that has a 26289 * {@link android.view.DragEvent#getAction()} value of 26290 * {@link android.view.DragEvent#ACTION_DRAG_STARTED}. 26291 * </p> 26292 * <p> 26293 * Your application can invoke {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, 26294 * int) startDragAndDrop()} on any attached View object. The View object does not need to be 26295 * the one used in {@link android.view.View.DragShadowBuilder}, nor does it need to be related 26296 * to the View the user selected for dragging. 26297 * </p> 26298 * @param data A {@link android.content.ClipData} object pointing to the data to be 26299 * transferred by the drag and drop operation. 26300 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 26301 * drag shadow. 26302 * @param myLocalState An {@link java.lang.Object} containing local data about the drag and 26303 * drop operation. When dispatching drag events to views in the same activity this object 26304 * will be available through {@link android.view.DragEvent#getLocalState()}. Views in other 26305 * activities will not have access to this data ({@link android.view.DragEvent#getLocalState()} 26306 * will return null). 26307 * <p> 26308 * myLocalState is a lightweight mechanism for the sending information from the dragged View 26309 * to the target Views. For example, it can contain flags that differentiate between a 26310 * a copy operation and a move operation. 26311 * </p> 26312 * @param flags Flags that control the drag and drop operation. This can be set to 0 for no 26313 * flags, or any combination of the following: 26314 * <ul> 26315 * <li>{@link #DRAG_FLAG_GLOBAL}</li> 26316 * <li>{@link #DRAG_FLAG_GLOBAL_PERSISTABLE_URI_PERMISSION}</li> 26317 * <li>{@link #DRAG_FLAG_GLOBAL_PREFIX_URI_PERMISSION}</li> 26318 * <li>{@link #DRAG_FLAG_GLOBAL_URI_READ}</li> 26319 * <li>{@link #DRAG_FLAG_GLOBAL_URI_WRITE}</li> 26320 * <li>{@link #DRAG_FLAG_OPAQUE}</li> 26321 * </ul> 26322 * @return {@code true} if the method completes successfully, or 26323 * {@code false} if it fails anywhere. Returning {@code false} means the system was unable to 26324 * do a drag because of another ongoing operation or some other reasons. 26325 */ startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, Object myLocalState, int flags)26326 public final boolean startDragAndDrop(ClipData data, DragShadowBuilder shadowBuilder, 26327 Object myLocalState, int flags) { 26328 if (ViewDebug.DEBUG_DRAG) { 26329 Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags); 26330 } 26331 if (mAttachInfo == null) { 26332 Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view."); 26333 return false; 26334 } 26335 if (!mAttachInfo.mViewRootImpl.mSurface.isValid()) { 26336 Log.w(VIEW_LOG_TAG, "startDragAndDrop called with an invalid surface."); 26337 return false; 26338 } 26339 26340 if (data != null) { 26341 data.prepareToLeaveProcess((flags & View.DRAG_FLAG_GLOBAL) != 0); 26342 } 26343 26344 Point shadowSize = new Point(); 26345 Point shadowTouchPoint = new Point(); 26346 shadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint); 26347 26348 if ((shadowSize.x < 0) || (shadowSize.y < 0) 26349 || (shadowTouchPoint.x < 0) || (shadowTouchPoint.y < 0)) { 26350 throw new IllegalStateException("Drag shadow dimensions must not be negative"); 26351 } 26352 26353 // Create 1x1 surface when zero surface size is specified because SurfaceControl.Builder 26354 // does not accept zero size surface. 26355 if (shadowSize.x == 0 || shadowSize.y == 0) { 26356 if (!sAcceptZeroSizeDragShadow) { 26357 throw new IllegalStateException("Drag shadow dimensions must be positive"); 26358 } 26359 shadowSize.x = 1; 26360 shadowSize.y = 1; 26361 } 26362 26363 if (ViewDebug.DEBUG_DRAG) { 26364 Log.d(VIEW_LOG_TAG, "drag shadow: width=" + shadowSize.x + " height=" + shadowSize.y 26365 + " shadowX=" + shadowTouchPoint.x + " shadowY=" + shadowTouchPoint.y); 26366 } 26367 26368 final ViewRootImpl root = mAttachInfo.mViewRootImpl; 26369 final SurfaceSession session = new SurfaceSession(); 26370 final SurfaceControl surfaceControl = new SurfaceControl.Builder(session) 26371 .setName("drag surface") 26372 .setParent(root.getSurfaceControl()) 26373 .setBufferSize(shadowSize.x, shadowSize.y) 26374 .setFormat(PixelFormat.TRANSLUCENT) 26375 .setCallsite("View.startDragAndDrop") 26376 .build(); 26377 final Surface surface = new Surface(); 26378 surface.copyFrom(surfaceControl); 26379 IBinder token = null; 26380 try { 26381 final Canvas canvas = surface.lockCanvas(null); 26382 try { 26383 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 26384 shadowBuilder.onDrawShadow(canvas); 26385 } finally { 26386 surface.unlockCanvasAndPost(canvas); 26387 } 26388 26389 // repurpose 'shadowSize' for the last touch point 26390 root.getLastTouchPoint(shadowSize); 26391 26392 token = mAttachInfo.mSession.performDrag( 26393 mAttachInfo.mWindow, flags, surfaceControl, root.getLastTouchSource(), 26394 shadowSize.x, shadowSize.y, shadowTouchPoint.x, shadowTouchPoint.y, data); 26395 if (ViewDebug.DEBUG_DRAG) { 26396 Log.d(VIEW_LOG_TAG, "performDrag returned " + token); 26397 } 26398 if (token != null) { 26399 if (mAttachInfo.mDragSurface != null) { 26400 mAttachInfo.mDragSurface.release(); 26401 } 26402 mAttachInfo.mDragSurface = surface; 26403 mAttachInfo.mDragToken = token; 26404 // Cache the local state object for delivery with DragEvents 26405 root.setLocalDragState(myLocalState); 26406 } 26407 return token != null; 26408 } catch (Exception e) { 26409 Log.e(VIEW_LOG_TAG, "Unable to initiate drag", e); 26410 return false; 26411 } finally { 26412 if (token == null) { 26413 surface.destroy(); 26414 } 26415 session.kill(); 26416 } 26417 } 26418 26419 /** 26420 * Cancels an ongoing drag and drop operation. 26421 * <p> 26422 * A {@link android.view.DragEvent} object with 26423 * {@link android.view.DragEvent#getAction()} value of 26424 * {@link android.view.DragEvent#ACTION_DRAG_ENDED} and 26425 * {@link android.view.DragEvent#getResult()} value of {@code false} 26426 * will be sent to every 26427 * View that received {@link android.view.DragEvent#ACTION_DRAG_STARTED} 26428 * even if they are not currently visible. 26429 * </p> 26430 * <p> 26431 * This method can be called on any View in the same window as the View on which 26432 * {@link #startDragAndDrop(ClipData, DragShadowBuilder, Object, int) startDragAndDrop} 26433 * was called. 26434 * </p> 26435 */ cancelDragAndDrop()26436 public final void cancelDragAndDrop() { 26437 if (ViewDebug.DEBUG_DRAG) { 26438 Log.d(VIEW_LOG_TAG, "cancelDragAndDrop"); 26439 } 26440 if (mAttachInfo == null) { 26441 Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view."); 26442 return; 26443 } 26444 if (mAttachInfo.mDragToken != null) { 26445 try { 26446 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken, false); 26447 } catch (Exception e) { 26448 Log.e(VIEW_LOG_TAG, "Unable to cancel drag", e); 26449 } 26450 mAttachInfo.mDragToken = null; 26451 } else { 26452 Log.e(VIEW_LOG_TAG, "No active drag to cancel"); 26453 } 26454 } 26455 26456 /** 26457 * Updates the drag shadow for the ongoing drag and drop operation. 26458 * 26459 * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the 26460 * new drag shadow. 26461 */ updateDragShadow(DragShadowBuilder shadowBuilder)26462 public final void updateDragShadow(DragShadowBuilder shadowBuilder) { 26463 if (ViewDebug.DEBUG_DRAG) { 26464 Log.d(VIEW_LOG_TAG, "updateDragShadow"); 26465 } 26466 if (mAttachInfo == null) { 26467 Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view."); 26468 return; 26469 } 26470 if (mAttachInfo.mDragToken != null) { 26471 try { 26472 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null); 26473 try { 26474 canvas.drawColor(0, PorterDuff.Mode.CLEAR); 26475 shadowBuilder.onDrawShadow(canvas); 26476 } finally { 26477 mAttachInfo.mDragSurface.unlockCanvasAndPost(canvas); 26478 } 26479 } catch (Exception e) { 26480 Log.e(VIEW_LOG_TAG, "Unable to update drag shadow", e); 26481 } 26482 } else { 26483 Log.e(VIEW_LOG_TAG, "No active drag"); 26484 } 26485 } 26486 26487 /** 26488 * Starts a move from {startX, startY}, the amount of the movement will be the offset 26489 * between {startX, startY} and the new cursor positon. 26490 * @param startX horizontal coordinate where the move started. 26491 * @param startY vertical coordinate where the move started. 26492 * @return whether moving was started successfully. 26493 * @hide 26494 */ startMovingTask(float startX, float startY)26495 public final boolean startMovingTask(float startX, float startY) { 26496 if (ViewDebug.DEBUG_POSITIONING) { 26497 Log.d(VIEW_LOG_TAG, "startMovingTask: {" + startX + "," + startY + "}"); 26498 } 26499 try { 26500 return mAttachInfo.mSession.startMovingTask(mAttachInfo.mWindow, startX, startY); 26501 } catch (RemoteException e) { 26502 Log.e(VIEW_LOG_TAG, "Unable to start moving", e); 26503 } 26504 return false; 26505 } 26506 26507 /** 26508 * Finish a window move task. 26509 * @hide 26510 */ finishMovingTask()26511 public void finishMovingTask() { 26512 if (ViewDebug.DEBUG_POSITIONING) { 26513 Log.d(VIEW_LOG_TAG, "finishMovingTask"); 26514 } 26515 try { 26516 mAttachInfo.mSession.finishMovingTask(mAttachInfo.mWindow); 26517 } catch (RemoteException e) { 26518 Log.e(VIEW_LOG_TAG, "Unable to finish moving", e); 26519 } 26520 } 26521 26522 /** 26523 * Handles drag events sent by the system following a call to 26524 * {@link android.view.View#startDragAndDrop(ClipData,DragShadowBuilder,Object,int) 26525 * startDragAndDrop()}. 26526 *<p> 26527 * When the system calls this method, it passes a 26528 * {@link android.view.DragEvent} object. A call to 26529 * {@link android.view.DragEvent#getAction()} returns one of the action type constants defined 26530 * in DragEvent. The method uses these to determine what is happening in the drag and drop 26531 * operation. 26532 * @param event The {@link android.view.DragEvent} sent by the system. 26533 * The {@link android.view.DragEvent#getAction()} method returns an action type constant defined 26534 * in DragEvent, indicating the type of drag event represented by this object. 26535 * @return {@code true} if the method was successful, otherwise {@code false}. 26536 * <p> 26537 * The method should return {@code true} in response to an action type of 26538 * {@link android.view.DragEvent#ACTION_DRAG_STARTED} to receive drag events for the current 26539 * operation. 26540 * </p> 26541 * <p> 26542 * The method should also return {@code true} in response to an action type of 26543 * {@link android.view.DragEvent#ACTION_DROP} if it consumed the drop, or 26544 * {@code false} if it didn't. 26545 * </p> 26546 * <p> 26547 * For all other events, the return value is ignored. 26548 * </p> 26549 */ onDragEvent(DragEvent event)26550 public boolean onDragEvent(DragEvent event) { 26551 return false; 26552 } 26553 26554 // Dispatches ACTION_DRAG_ENTERED and ACTION_DRAG_EXITED events for pre-Nougat apps. dispatchDragEnterExitInPreN(DragEvent event)26555 boolean dispatchDragEnterExitInPreN(DragEvent event) { 26556 return callDragEventHandler(event); 26557 } 26558 26559 /** 26560 * Detects if this View is enabled and has a drag event listener. 26561 * If both are true, then it calls the drag event listener with the 26562 * {@link android.view.DragEvent} it received. If the drag event listener returns 26563 * {@code true}, then dispatchDragEvent() returns {@code true}. 26564 * <p> 26565 * For all other cases, the method calls the 26566 * {@link android.view.View#onDragEvent(DragEvent) onDragEvent()} drag event handler 26567 * method and returns its result. 26568 * </p> 26569 * <p> 26570 * This ensures that a drag event is always consumed, even if the View does not have a drag 26571 * event listener. However, if the View has a listener and the listener returns true, then 26572 * onDragEvent() is not called. 26573 * </p> 26574 */ dispatchDragEvent(DragEvent event)26575 public boolean dispatchDragEvent(DragEvent event) { 26576 event.mEventHandlerWasCalled = true; 26577 if (event.mAction == DragEvent.ACTION_DRAG_LOCATION || 26578 event.mAction == DragEvent.ACTION_DROP) { 26579 // About to deliver an event with coordinates to this view. Notify that now this view 26580 // has drag focus. This will send exit/enter events as needed. 26581 getViewRootImpl().setDragFocus(this, event); 26582 } 26583 return callDragEventHandler(event); 26584 } 26585 callDragEventHandler(DragEvent event)26586 final boolean callDragEventHandler(DragEvent event) { 26587 final boolean result; 26588 26589 ListenerInfo li = mListenerInfo; 26590 //noinspection SimplifiableIfStatement 26591 if (li != null && li.mOnDragListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 26592 && li.mOnDragListener.onDrag(this, event)) { 26593 result = true; 26594 } else { 26595 result = onDragEvent(event); 26596 } 26597 26598 switch (event.mAction) { 26599 case DragEvent.ACTION_DRAG_ENTERED: { 26600 mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED; 26601 refreshDrawableState(); 26602 } break; 26603 case DragEvent.ACTION_DRAG_EXITED: { 26604 mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED; 26605 refreshDrawableState(); 26606 } break; 26607 case DragEvent.ACTION_DRAG_ENDED: { 26608 mPrivateFlags2 &= ~View.DRAG_MASK; 26609 refreshDrawableState(); 26610 } break; 26611 } 26612 26613 return result; 26614 } 26615 canAcceptDrag()26616 boolean canAcceptDrag() { 26617 return (mPrivateFlags2 & PFLAG2_DRAG_CAN_ACCEPT) != 0; 26618 } 26619 26620 /** 26621 * This needs to be a better API (NOT ON VIEW) before it is exposed. If 26622 * it is ever exposed at all. 26623 * @hide 26624 */ 26625 @UnsupportedAppUsage onCloseSystemDialogs(String reason)26626 public void onCloseSystemDialogs(String reason) { 26627 } 26628 26629 /** 26630 * Given a Drawable whose bounds have been set to draw into this view, 26631 * update a Region being computed for 26632 * {@link #gatherTransparentRegion(android.graphics.Region)} so 26633 * that any non-transparent parts of the Drawable are removed from the 26634 * given transparent region. 26635 * 26636 * @param dr The Drawable whose transparency is to be applied to the region. 26637 * @param region A Region holding the current transparency information, 26638 * where any parts of the region that are set are considered to be 26639 * transparent. On return, this region will be modified to have the 26640 * transparency information reduced by the corresponding parts of the 26641 * Drawable that are not transparent. 26642 * {@hide} 26643 */ 26644 @UnsupportedAppUsage applyDrawableToTransparentRegion(Drawable dr, Region region)26645 public void applyDrawableToTransparentRegion(Drawable dr, Region region) { 26646 if (DBG) { 26647 Log.i("View", "Getting transparent region for: " + this); 26648 } 26649 final Region r = dr.getTransparentRegion(); 26650 final Rect db = dr.getBounds(); 26651 final AttachInfo attachInfo = mAttachInfo; 26652 if (r != null && attachInfo != null) { 26653 final int w = getRight()-getLeft(); 26654 final int h = getBottom()-getTop(); 26655 if (db.left > 0) { 26656 //Log.i("VIEW", "Drawable left " + db.left + " > view 0"); 26657 r.op(0, 0, db.left, h, Region.Op.UNION); 26658 } 26659 if (db.right < w) { 26660 //Log.i("VIEW", "Drawable right " + db.right + " < view " + w); 26661 r.op(db.right, 0, w, h, Region.Op.UNION); 26662 } 26663 if (db.top > 0) { 26664 //Log.i("VIEW", "Drawable top " + db.top + " > view 0"); 26665 r.op(0, 0, w, db.top, Region.Op.UNION); 26666 } 26667 if (db.bottom < h) { 26668 //Log.i("VIEW", "Drawable bottom " + db.bottom + " < view " + h); 26669 r.op(0, db.bottom, w, h, Region.Op.UNION); 26670 } 26671 final int[] location = attachInfo.mTransparentLocation; 26672 getLocationInWindow(location); 26673 r.translate(location[0], location[1]); 26674 region.op(r, Region.Op.INTERSECT); 26675 } else { 26676 region.op(db, Region.Op.DIFFERENCE); 26677 } 26678 } 26679 checkForLongClick(long delay, float x, float y, int classification)26680 private void checkForLongClick(long delay, float x, float y, int classification) { 26681 if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE || (mViewFlags & TOOLTIP) == TOOLTIP) { 26682 mHasPerformedLongPress = false; 26683 26684 if (mPendingCheckForLongPress == null) { 26685 mPendingCheckForLongPress = new CheckForLongPress(); 26686 } 26687 mPendingCheckForLongPress.setAnchor(x, y); 26688 mPendingCheckForLongPress.rememberWindowAttachCount(); 26689 mPendingCheckForLongPress.rememberPressedState(); 26690 mPendingCheckForLongPress.setClassification(classification); 26691 postDelayed(mPendingCheckForLongPress, delay); 26692 } 26693 } 26694 26695 /** 26696 * Inflate a view from an XML resource. This convenience method wraps the {@link 26697 * LayoutInflater} class, which provides a full range of options for view inflation. 26698 * 26699 * @param context The Context object for your activity or application. 26700 * @param resource The resource ID to inflate 26701 * @param root A view group that will be the parent. Used to properly inflate the 26702 * layout_* parameters. 26703 * @see LayoutInflater 26704 */ inflate(Context context, @LayoutRes int resource, ViewGroup root)26705 public static View inflate(Context context, @LayoutRes int resource, ViewGroup root) { 26706 LayoutInflater factory = LayoutInflater.from(context); 26707 return factory.inflate(resource, root); 26708 } 26709 26710 /** 26711 * Scroll the view with standard behavior for scrolling beyond the normal 26712 * content boundaries. Views that call this method should override 26713 * {@link #onOverScrolled(int, int, boolean, boolean)} to respond to the 26714 * results of an over-scroll operation. 26715 * 26716 * Views can use this method to handle any touch or fling-based scrolling. 26717 * 26718 * @param deltaX Change in X in pixels 26719 * @param deltaY Change in Y in pixels 26720 * @param scrollX Current X scroll value in pixels before applying deltaX 26721 * @param scrollY Current Y scroll value in pixels before applying deltaY 26722 * @param scrollRangeX Maximum content scroll range along the X axis 26723 * @param scrollRangeY Maximum content scroll range along the Y axis 26724 * @param maxOverScrollX Number of pixels to overscroll by in either direction 26725 * along the X axis. 26726 * @param maxOverScrollY Number of pixels to overscroll by in either direction 26727 * along the Y axis. 26728 * @param isTouchEvent true if this scroll operation is the result of a touch event. 26729 * @return true if scrolling was clamped to an over-scroll boundary along either 26730 * axis, false otherwise. 26731 */ 26732 @SuppressWarnings({"UnusedParameters"}) overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent)26733 protected boolean overScrollBy(int deltaX, int deltaY, 26734 int scrollX, int scrollY, 26735 int scrollRangeX, int scrollRangeY, 26736 int maxOverScrollX, int maxOverScrollY, 26737 boolean isTouchEvent) { 26738 final int overScrollMode = mOverScrollMode; 26739 final boolean canScrollHorizontal = 26740 computeHorizontalScrollRange() > computeHorizontalScrollExtent(); 26741 final boolean canScrollVertical = 26742 computeVerticalScrollRange() > computeVerticalScrollExtent(); 26743 final boolean overScrollHorizontal = overScrollMode == OVER_SCROLL_ALWAYS || 26744 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollHorizontal); 26745 final boolean overScrollVertical = overScrollMode == OVER_SCROLL_ALWAYS || 26746 (overScrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && canScrollVertical); 26747 26748 int newScrollX = scrollX + deltaX; 26749 if (!overScrollHorizontal) { 26750 maxOverScrollX = 0; 26751 } 26752 26753 int newScrollY = scrollY + deltaY; 26754 if (!overScrollVertical) { 26755 maxOverScrollY = 0; 26756 } 26757 26758 // Clamp values if at the limits and record 26759 final int left = -maxOverScrollX; 26760 final int right = maxOverScrollX + scrollRangeX; 26761 final int top = -maxOverScrollY; 26762 final int bottom = maxOverScrollY + scrollRangeY; 26763 26764 boolean clampedX = false; 26765 if (newScrollX > right) { 26766 newScrollX = right; 26767 clampedX = true; 26768 } else if (newScrollX < left) { 26769 newScrollX = left; 26770 clampedX = true; 26771 } 26772 26773 boolean clampedY = false; 26774 if (newScrollY > bottom) { 26775 newScrollY = bottom; 26776 clampedY = true; 26777 } else if (newScrollY < top) { 26778 newScrollY = top; 26779 clampedY = true; 26780 } 26781 26782 onOverScrolled(newScrollX, newScrollY, clampedX, clampedY); 26783 26784 return clampedX || clampedY; 26785 } 26786 26787 /** 26788 * Called by {@link #overScrollBy(int, int, int, int, int, int, int, int, boolean)} to 26789 * respond to the results of an over-scroll operation. 26790 * 26791 * @param scrollX New X scroll value in pixels 26792 * @param scrollY New Y scroll value in pixels 26793 * @param clampedX True if scrollX was clamped to an over-scroll boundary 26794 * @param clampedY True if scrollY was clamped to an over-scroll boundary 26795 */ onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY)26796 protected void onOverScrolled(int scrollX, int scrollY, 26797 boolean clampedX, boolean clampedY) { 26798 // Intentionally empty. 26799 } 26800 26801 /** 26802 * Returns the over-scroll mode for this view. The result will be 26803 * one of {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 26804 * (allow over-scrolling only if the view content is larger than the container), 26805 * or {@link #OVER_SCROLL_NEVER}. 26806 * 26807 * @return This view's over-scroll mode. 26808 */ 26809 @InspectableProperty(enumMapping = { 26810 @EnumEntry(value = OVER_SCROLL_ALWAYS, name = "always"), 26811 @EnumEntry(value = OVER_SCROLL_IF_CONTENT_SCROLLS, name = "ifContentScrolls"), 26812 @EnumEntry(value = OVER_SCROLL_NEVER, name = "never") 26813 }) getOverScrollMode()26814 public int getOverScrollMode() { 26815 return mOverScrollMode; 26816 } 26817 26818 /** 26819 * Set the over-scroll mode for this view. Valid over-scroll modes are 26820 * {@link #OVER_SCROLL_ALWAYS}, {@link #OVER_SCROLL_IF_CONTENT_SCROLLS} 26821 * (allow over-scrolling only if the view content is larger than the container), 26822 * or {@link #OVER_SCROLL_NEVER}. 26823 * 26824 * Setting the over-scroll mode of a view will have an effect only if the 26825 * view is capable of scrolling. 26826 * 26827 * @param overScrollMode The new over-scroll mode for this view. 26828 */ setOverScrollMode(int overScrollMode)26829 public void setOverScrollMode(int overScrollMode) { 26830 if (overScrollMode != OVER_SCROLL_ALWAYS && 26831 overScrollMode != OVER_SCROLL_IF_CONTENT_SCROLLS && 26832 overScrollMode != OVER_SCROLL_NEVER) { 26833 throw new IllegalArgumentException("Invalid overscroll mode " + overScrollMode); 26834 } 26835 mOverScrollMode = overScrollMode; 26836 } 26837 26838 /** 26839 * Enable or disable nested scrolling for this view. 26840 * 26841 * <p>If this property is set to true the view will be permitted to initiate nested 26842 * scrolling operations with a compatible parent view in the current hierarchy. If this 26843 * view does not implement nested scrolling this will have no effect. Disabling nested scrolling 26844 * while a nested scroll is in progress has the effect of {@link #stopNestedScroll() stopping} 26845 * the nested scroll.</p> 26846 * 26847 * @param enabled true to enable nested scrolling, false to disable 26848 * 26849 * @see #isNestedScrollingEnabled() 26850 */ setNestedScrollingEnabled(boolean enabled)26851 public void setNestedScrollingEnabled(boolean enabled) { 26852 if (enabled) { 26853 mPrivateFlags3 |= PFLAG3_NESTED_SCROLLING_ENABLED; 26854 } else { 26855 stopNestedScroll(); 26856 mPrivateFlags3 &= ~PFLAG3_NESTED_SCROLLING_ENABLED; 26857 } 26858 } 26859 26860 /** 26861 * Returns true if nested scrolling is enabled for this view. 26862 * 26863 * <p>If nested scrolling is enabled and this View class implementation supports it, 26864 * this view will act as a nested scrolling child view when applicable, forwarding data 26865 * about the scroll operation in progress to a compatible and cooperating nested scrolling 26866 * parent.</p> 26867 * 26868 * @return true if nested scrolling is enabled 26869 * 26870 * @see #setNestedScrollingEnabled(boolean) 26871 */ 26872 @InspectableProperty isNestedScrollingEnabled()26873 public boolean isNestedScrollingEnabled() { 26874 return (mPrivateFlags3 & PFLAG3_NESTED_SCROLLING_ENABLED) == 26875 PFLAG3_NESTED_SCROLLING_ENABLED; 26876 } 26877 26878 /** 26879 * Begin a nestable scroll operation along the given axes. 26880 * 26881 * <p>A view starting a nested scroll promises to abide by the following contract:</p> 26882 * 26883 * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case 26884 * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}. 26885 * In the case of touch scrolling the nested scroll will be terminated automatically in 26886 * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}. 26887 * In the event of programmatic scrolling the caller must explicitly call 26888 * {@link #stopNestedScroll()} to indicate the end of the nested scroll.</p> 26889 * 26890 * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found. 26891 * If it returns false the caller may ignore the rest of this contract until the next scroll. 26892 * Calling startNestedScroll while a nested scroll is already in progress will return true.</p> 26893 * 26894 * <p>At each incremental step of the scroll the caller should invoke 26895 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} 26896 * once it has calculated the requested scrolling delta. If it returns true the nested scrolling 26897 * parent at least partially consumed the scroll and the caller should adjust the amount it 26898 * scrolls by.</p> 26899 * 26900 * <p>After applying the remainder of the scroll delta the caller should invoke 26901 * {@link #dispatchNestedScroll(int, int, int, int, int[]) dispatchNestedScroll}, passing 26902 * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat 26903 * these values differently. See {@link ViewParent#onNestedScroll(View, int, int, int, int)}. 26904 * </p> 26905 * 26906 * @param axes Flags consisting of a combination of {@link #SCROLL_AXIS_HORIZONTAL} and/or 26907 * {@link #SCROLL_AXIS_VERTICAL}. 26908 * @return true if a cooperative parent was found and nested scrolling has been enabled for 26909 * the current gesture. 26910 * 26911 * @see #stopNestedScroll() 26912 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 26913 * @see #dispatchNestedScroll(int, int, int, int, int[]) 26914 */ startNestedScroll(int axes)26915 public boolean startNestedScroll(int axes) { 26916 if (hasNestedScrollingParent()) { 26917 // Already in progress 26918 return true; 26919 } 26920 if (isNestedScrollingEnabled()) { 26921 ViewParent p = getParent(); 26922 View child = this; 26923 while (p != null) { 26924 try { 26925 if (p.onStartNestedScroll(child, this, axes)) { 26926 mNestedScrollingParent = p; 26927 p.onNestedScrollAccepted(child, this, axes); 26928 return true; 26929 } 26930 } catch (AbstractMethodError e) { 26931 Log.e(VIEW_LOG_TAG, "ViewParent " + p + " does not implement interface " + 26932 "method onStartNestedScroll", e); 26933 // Allow the search upward to continue 26934 } 26935 if (p instanceof View) { 26936 child = (View) p; 26937 } 26938 p = p.getParent(); 26939 } 26940 } 26941 return false; 26942 } 26943 26944 /** 26945 * Stop a nested scroll in progress. 26946 * 26947 * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p> 26948 * 26949 * @see #startNestedScroll(int) 26950 */ stopNestedScroll()26951 public void stopNestedScroll() { 26952 if (mNestedScrollingParent != null) { 26953 mNestedScrollingParent.onStopNestedScroll(this); 26954 mNestedScrollingParent = null; 26955 } 26956 } 26957 26958 /** 26959 * Returns true if this view has a nested scrolling parent. 26960 * 26961 * <p>The presence of a nested scrolling parent indicates that this view has initiated 26962 * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p> 26963 * 26964 * @return whether this view has a nested scrolling parent 26965 */ hasNestedScrollingParent()26966 public boolean hasNestedScrollingParent() { 26967 return mNestedScrollingParent != null; 26968 } 26969 26970 /** 26971 * Dispatch one step of a nested scroll in progress. 26972 * 26973 * <p>Implementations of views that support nested scrolling should call this to report 26974 * info about a scroll in progress to the current nested scrolling parent. If a nested scroll 26975 * is not currently in progress or nested scrolling is not 26976 * {@link #isNestedScrollingEnabled() enabled} for this view this method does nothing.</p> 26977 * 26978 * <p>Compatible View implementations should also call 26979 * {@link #dispatchNestedPreScroll(int, int, int[], int[]) dispatchNestedPreScroll} before 26980 * consuming a component of the scroll event themselves.</p> 26981 * 26982 * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step 26983 * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step 26984 * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view 26985 * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view 26986 * @param offsetInWindow Optional. If not null, on return this will contain the offset 26987 * in local view coordinates of this view from before this operation 26988 * to after it completes. View implementations may use this to adjust 26989 * expected input coordinate tracking. 26990 * @return true if the event was dispatched, false if it could not be dispatched. 26991 * @see #dispatchNestedPreScroll(int, int, int[], int[]) 26992 */ dispatchNestedScroll(int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow)26993 public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed, 26994 int dxUnconsumed, int dyUnconsumed, @Nullable @Size(2) int[] offsetInWindow) { 26995 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 26996 if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) { 26997 int startX = 0; 26998 int startY = 0; 26999 if (offsetInWindow != null) { 27000 getLocationInWindow(offsetInWindow); 27001 startX = offsetInWindow[0]; 27002 startY = offsetInWindow[1]; 27003 } 27004 27005 mNestedScrollingParent.onNestedScroll(this, dxConsumed, dyConsumed, 27006 dxUnconsumed, dyUnconsumed); 27007 27008 if (offsetInWindow != null) { 27009 getLocationInWindow(offsetInWindow); 27010 offsetInWindow[0] -= startX; 27011 offsetInWindow[1] -= startY; 27012 } 27013 return true; 27014 } else if (offsetInWindow != null) { 27015 // No motion, no dispatch. Keep offsetInWindow up to date. 27016 offsetInWindow[0] = 0; 27017 offsetInWindow[1] = 0; 27018 } 27019 } 27020 return false; 27021 } 27022 27023 /** 27024 * Dispatch one step of a nested scroll in progress before this view consumes any portion of it. 27025 * 27026 * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch. 27027 * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested 27028 * scrolling operation to consume some or all of the scroll operation before the child view 27029 * consumes it.</p> 27030 * 27031 * @param dx Horizontal scroll distance in pixels 27032 * @param dy Vertical scroll distance in pixels 27033 * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx 27034 * and consumed[1] the consumed dy. 27035 * @param offsetInWindow Optional. If not null, on return this will contain the offset 27036 * in local view coordinates of this view from before this operation 27037 * to after it completes. View implementations may use this to adjust 27038 * expected input coordinate tracking. 27039 * @return true if the parent consumed some or all of the scroll delta 27040 * @see #dispatchNestedScroll(int, int, int, int, int[]) 27041 */ dispatchNestedPreScroll(int dx, int dy, @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow)27042 public boolean dispatchNestedPreScroll(int dx, int dy, 27043 @Nullable @Size(2) int[] consumed, @Nullable @Size(2) int[] offsetInWindow) { 27044 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 27045 if (dx != 0 || dy != 0) { 27046 int startX = 0; 27047 int startY = 0; 27048 if (offsetInWindow != null) { 27049 getLocationInWindow(offsetInWindow); 27050 startX = offsetInWindow[0]; 27051 startY = offsetInWindow[1]; 27052 } 27053 27054 if (consumed == null) { 27055 if (mTempNestedScrollConsumed == null) { 27056 mTempNestedScrollConsumed = new int[2]; 27057 } 27058 consumed = mTempNestedScrollConsumed; 27059 } 27060 consumed[0] = 0; 27061 consumed[1] = 0; 27062 mNestedScrollingParent.onNestedPreScroll(this, dx, dy, consumed); 27063 27064 if (offsetInWindow != null) { 27065 getLocationInWindow(offsetInWindow); 27066 offsetInWindow[0] -= startX; 27067 offsetInWindow[1] -= startY; 27068 } 27069 return consumed[0] != 0 || consumed[1] != 0; 27070 } else if (offsetInWindow != null) { 27071 offsetInWindow[0] = 0; 27072 offsetInWindow[1] = 0; 27073 } 27074 } 27075 return false; 27076 } 27077 27078 /** 27079 * Dispatch a fling to a nested scrolling parent. 27080 * 27081 * <p>This method should be used to indicate that a nested scrolling child has detected 27082 * suitable conditions for a fling. Generally this means that a touch scroll has ended with a 27083 * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds 27084 * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity} 27085 * along a scrollable axis.</p> 27086 * 27087 * <p>If a nested scrolling child view would normally fling but it is at the edge of 27088 * its own content, it can use this method to delegate the fling to its nested scrolling 27089 * parent instead. The parent may optionally consume the fling or observe a child fling.</p> 27090 * 27091 * @param velocityX Horizontal fling velocity in pixels per second 27092 * @param velocityY Vertical fling velocity in pixels per second 27093 * @param consumed true if the child consumed the fling, false otherwise 27094 * @return true if the nested scrolling parent consumed or otherwise reacted to the fling 27095 */ dispatchNestedFling(float velocityX, float velocityY, boolean consumed)27096 public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) { 27097 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 27098 return mNestedScrollingParent.onNestedFling(this, velocityX, velocityY, consumed); 27099 } 27100 return false; 27101 } 27102 27103 /** 27104 * Dispatch a fling to a nested scrolling parent before it is processed by this view. 27105 * 27106 * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch 27107 * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code> 27108 * offsets an opportunity for the parent view in a nested fling to fully consume the fling 27109 * before the child view consumes it. If this method returns <code>true</code>, a nested 27110 * parent view consumed the fling and this view should not scroll as a result.</p> 27111 * 27112 * <p>For a better user experience, only one view in a nested scrolling chain should consume 27113 * the fling at a time. If a parent view consumed the fling this method will return false. 27114 * Custom view implementations should account for this in two ways:</p> 27115 * 27116 * <ul> 27117 * <li>If a custom view is paged and needs to settle to a fixed page-point, do not 27118 * call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid 27119 * position regardless.</li> 27120 * <li>If a nested parent does consume the fling, this view should not scroll at all, 27121 * even to settle back to a valid idle position.</li> 27122 * </ul> 27123 * 27124 * <p>Views should also not offer fling velocities to nested parent views along an axis 27125 * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView} 27126 * should not offer a horizontal fling velocity to its parents since scrolling along that 27127 * axis is not permitted and carrying velocity along that motion does not make sense.</p> 27128 * 27129 * @param velocityX Horizontal fling velocity in pixels per second 27130 * @param velocityY Vertical fling velocity in pixels per second 27131 * @return true if a nested scrolling parent consumed the fling 27132 */ dispatchNestedPreFling(float velocityX, float velocityY)27133 public boolean dispatchNestedPreFling(float velocityX, float velocityY) { 27134 if (isNestedScrollingEnabled() && mNestedScrollingParent != null) { 27135 return mNestedScrollingParent.onNestedPreFling(this, velocityX, velocityY); 27136 } 27137 return false; 27138 } 27139 27140 /** 27141 * Gets a scale factor that determines the distance the view should scroll 27142 * vertically in response to {@link MotionEvent#ACTION_SCROLL}. 27143 * @return The vertical scroll scale factor. 27144 * @hide 27145 */ 27146 @UnsupportedAppUsage getVerticalScrollFactor()27147 protected float getVerticalScrollFactor() { 27148 if (mVerticalScrollFactor == 0) { 27149 TypedValue outValue = new TypedValue(); 27150 if (!mContext.getTheme().resolveAttribute( 27151 com.android.internal.R.attr.listPreferredItemHeight, outValue, true)) { 27152 throw new IllegalStateException( 27153 "Expected theme to define listPreferredItemHeight."); 27154 } 27155 mVerticalScrollFactor = outValue.getDimension( 27156 mContext.getResources().getDisplayMetrics()); 27157 } 27158 return mVerticalScrollFactor; 27159 } 27160 27161 /** 27162 * Gets a scale factor that determines the distance the view should scroll 27163 * horizontally in response to {@link MotionEvent#ACTION_SCROLL}. 27164 * @return The horizontal scroll scale factor. 27165 * @hide 27166 */ 27167 @UnsupportedAppUsage getHorizontalScrollFactor()27168 protected float getHorizontalScrollFactor() { 27169 // TODO: Should use something else. 27170 return getVerticalScrollFactor(); 27171 } 27172 27173 /** 27174 * Return the value specifying the text direction or policy that was set with 27175 * {@link #setTextDirection(int)}. 27176 * 27177 * @return the defined text direction. It can be one of: 27178 * 27179 * {@link #TEXT_DIRECTION_INHERIT}, 27180 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 27181 * {@link #TEXT_DIRECTION_ANY_RTL}, 27182 * {@link #TEXT_DIRECTION_LTR}, 27183 * {@link #TEXT_DIRECTION_RTL}, 27184 * {@link #TEXT_DIRECTION_LOCALE}, 27185 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 27186 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 27187 * 27188 * @attr ref android.R.styleable#View_textDirection 27189 * 27190 * @hide 27191 */ 27192 @ViewDebug.ExportedProperty(category = "text", mapping = { 27193 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 27194 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 27195 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 27196 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 27197 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 27198 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 27199 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 27200 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 27201 }) 27202 @InspectableProperty(hasAttributeId = false, enumMapping = { 27203 @EnumEntry(value = TEXT_DIRECTION_INHERIT, name = "inherit"), 27204 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 27205 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 27206 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 27207 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 27208 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 27209 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 27210 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 27211 }) 27212 @UnsupportedAppUsage getRawTextDirection()27213 public int getRawTextDirection() { 27214 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_MASK) >> PFLAG2_TEXT_DIRECTION_MASK_SHIFT; 27215 } 27216 27217 /** 27218 * Set the text direction. 27219 * 27220 * @param textDirection the direction to set. Should be one of: 27221 * 27222 * {@link #TEXT_DIRECTION_INHERIT}, 27223 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 27224 * {@link #TEXT_DIRECTION_ANY_RTL}, 27225 * {@link #TEXT_DIRECTION_LTR}, 27226 * {@link #TEXT_DIRECTION_RTL}, 27227 * {@link #TEXT_DIRECTION_LOCALE} 27228 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 27229 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL}, 27230 * 27231 * Resolution will be done if the value is set to TEXT_DIRECTION_INHERIT. The resolution 27232 * proceeds up the parent chain of the view to get the value. If there is no parent, then it will 27233 * return the default {@link #TEXT_DIRECTION_FIRST_STRONG}. 27234 * 27235 * @attr ref android.R.styleable#View_textDirection 27236 */ setTextDirection(int textDirection)27237 public void setTextDirection(int textDirection) { 27238 if (getRawTextDirection() != textDirection) { 27239 // Reset the current text direction and the resolved one 27240 mPrivateFlags2 &= ~PFLAG2_TEXT_DIRECTION_MASK; 27241 resetResolvedTextDirection(); 27242 // Set the new text direction 27243 mPrivateFlags2 |= ((textDirection << PFLAG2_TEXT_DIRECTION_MASK_SHIFT) & PFLAG2_TEXT_DIRECTION_MASK); 27244 // Do resolution 27245 resolveTextDirection(); 27246 // Notify change 27247 onRtlPropertiesChanged(getLayoutDirection()); 27248 // Refresh 27249 requestLayout(); 27250 invalidate(true); 27251 } 27252 } 27253 27254 /** 27255 * Return the resolved text direction. 27256 * 27257 * @return the resolved text direction. Returns one of: 27258 * 27259 * {@link #TEXT_DIRECTION_FIRST_STRONG}, 27260 * {@link #TEXT_DIRECTION_ANY_RTL}, 27261 * {@link #TEXT_DIRECTION_LTR}, 27262 * {@link #TEXT_DIRECTION_RTL}, 27263 * {@link #TEXT_DIRECTION_LOCALE}, 27264 * {@link #TEXT_DIRECTION_FIRST_STRONG_LTR}, 27265 * {@link #TEXT_DIRECTION_FIRST_STRONG_RTL} 27266 * 27267 * @attr ref android.R.styleable#View_textDirection 27268 */ 27269 @ViewDebug.ExportedProperty(category = "text", mapping = { 27270 @ViewDebug.IntToString(from = TEXT_DIRECTION_INHERIT, to = "INHERIT"), 27271 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG, to = "FIRST_STRONG"), 27272 @ViewDebug.IntToString(from = TEXT_DIRECTION_ANY_RTL, to = "ANY_RTL"), 27273 @ViewDebug.IntToString(from = TEXT_DIRECTION_LTR, to = "LTR"), 27274 @ViewDebug.IntToString(from = TEXT_DIRECTION_RTL, to = "RTL"), 27275 @ViewDebug.IntToString(from = TEXT_DIRECTION_LOCALE, to = "LOCALE"), 27276 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_LTR, to = "FIRST_STRONG_LTR"), 27277 @ViewDebug.IntToString(from = TEXT_DIRECTION_FIRST_STRONG_RTL, to = "FIRST_STRONG_RTL") 27278 }) 27279 @InspectableProperty(hasAttributeId = false, enumMapping = { 27280 @EnumEntry(value = TEXT_DIRECTION_LOCALE, name = "locale"), 27281 @EnumEntry(value = TEXT_DIRECTION_ANY_RTL, name = "anyRtl"), 27282 @EnumEntry(value = TEXT_DIRECTION_LTR, name = "ltr"), 27283 @EnumEntry(value = TEXT_DIRECTION_RTL, name = "rtl"), 27284 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG, name = "firstStrong"), 27285 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_LTR, name = "firstStrongLtr"), 27286 @EnumEntry(value = TEXT_DIRECTION_FIRST_STRONG_RTL, name = "firstStrongRtl"), 27287 }) getTextDirection()27288 public int getTextDirection() { 27289 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED_MASK) >> PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT; 27290 } 27291 27292 /** 27293 * Resolve the text direction. 27294 * 27295 * @return true if resolution has been done, false otherwise. 27296 * 27297 * @hide 27298 */ resolveTextDirection()27299 public boolean resolveTextDirection() { 27300 // Reset any previous text direction resolution 27301 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 27302 27303 if (hasRtlSupport()) { 27304 // Set resolved text direction flag depending on text direction flag 27305 final int textDirection = getRawTextDirection(); 27306 switch(textDirection) { 27307 case TEXT_DIRECTION_INHERIT: 27308 if (!canResolveTextDirection()) { 27309 // We cannot do the resolution if there is no parent, so use the default one 27310 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27311 // Resolution will need to happen again later 27312 return false; 27313 } 27314 27315 // Parent has not yet resolved, so we still return the default 27316 try { 27317 if (!mParent.isTextDirectionResolved()) { 27318 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27319 // Resolution will need to happen again later 27320 return false; 27321 } 27322 } catch (AbstractMethodError e) { 27323 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27324 " does not fully implement ViewParent", e); 27325 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED | 27326 PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27327 return true; 27328 } 27329 27330 // Set current resolved direction to the same value as the parent's one 27331 int parentResolvedDirection; 27332 try { 27333 parentResolvedDirection = mParent.getTextDirection(); 27334 } catch (AbstractMethodError e) { 27335 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27336 " does not fully implement ViewParent", e); 27337 parentResolvedDirection = TEXT_DIRECTION_LTR; 27338 } 27339 switch (parentResolvedDirection) { 27340 case TEXT_DIRECTION_FIRST_STRONG: 27341 case TEXT_DIRECTION_ANY_RTL: 27342 case TEXT_DIRECTION_LTR: 27343 case TEXT_DIRECTION_RTL: 27344 case TEXT_DIRECTION_LOCALE: 27345 case TEXT_DIRECTION_FIRST_STRONG_LTR: 27346 case TEXT_DIRECTION_FIRST_STRONG_RTL: 27347 mPrivateFlags2 |= 27348 (parentResolvedDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 27349 break; 27350 default: 27351 // Default resolved direction is "first strong" heuristic 27352 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27353 } 27354 break; 27355 case TEXT_DIRECTION_FIRST_STRONG: 27356 case TEXT_DIRECTION_ANY_RTL: 27357 case TEXT_DIRECTION_LTR: 27358 case TEXT_DIRECTION_RTL: 27359 case TEXT_DIRECTION_LOCALE: 27360 case TEXT_DIRECTION_FIRST_STRONG_LTR: 27361 case TEXT_DIRECTION_FIRST_STRONG_RTL: 27362 // Resolved direction is the same as text direction 27363 mPrivateFlags2 |= (textDirection << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT); 27364 break; 27365 default: 27366 // Default resolved direction is "first strong" heuristic 27367 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27368 } 27369 } else { 27370 // Default resolved direction is "first strong" heuristic 27371 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27372 } 27373 27374 // Set to resolved 27375 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED; 27376 return true; 27377 } 27378 27379 /** 27380 * Check if text direction resolution can be done. 27381 * 27382 * @return true if text direction resolution can be done otherwise return false. 27383 */ canResolveTextDirection()27384 public boolean canResolveTextDirection() { 27385 switch (getRawTextDirection()) { 27386 case TEXT_DIRECTION_INHERIT: 27387 if (mParent != null) { 27388 try { 27389 return mParent.canResolveTextDirection(); 27390 } catch (AbstractMethodError e) { 27391 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27392 " does not fully implement ViewParent", e); 27393 } 27394 } 27395 return false; 27396 27397 default: 27398 return true; 27399 } 27400 } 27401 27402 /** 27403 * Reset resolved text direction. Text direction will be resolved during a call to 27404 * {@link #onMeasure(int, int)}. 27405 * 27406 * @hide 27407 */ 27408 @TestApi resetResolvedTextDirection()27409 public void resetResolvedTextDirection() { 27410 // Reset any previous text direction resolution 27411 mPrivateFlags2 &= ~(PFLAG2_TEXT_DIRECTION_RESOLVED | PFLAG2_TEXT_DIRECTION_RESOLVED_MASK); 27412 // Set to default value 27413 mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT; 27414 } 27415 27416 /** 27417 * @return true if text direction is inherited. 27418 * 27419 * @hide 27420 */ isTextDirectionInherited()27421 public boolean isTextDirectionInherited() { 27422 return (getRawTextDirection() == TEXT_DIRECTION_INHERIT); 27423 } 27424 27425 /** 27426 * @return true if text direction is resolved. 27427 */ isTextDirectionResolved()27428 public boolean isTextDirectionResolved() { 27429 return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED; 27430 } 27431 27432 /** 27433 * Return the value specifying the text alignment or policy that was set with 27434 * {@link #setTextAlignment(int)}. 27435 * 27436 * @return the defined text alignment. It can be one of: 27437 * 27438 * {@link #TEXT_ALIGNMENT_INHERIT}, 27439 * {@link #TEXT_ALIGNMENT_GRAVITY}, 27440 * {@link #TEXT_ALIGNMENT_CENTER}, 27441 * {@link #TEXT_ALIGNMENT_TEXT_START}, 27442 * {@link #TEXT_ALIGNMENT_TEXT_END}, 27443 * {@link #TEXT_ALIGNMENT_VIEW_START}, 27444 * {@link #TEXT_ALIGNMENT_VIEW_END} 27445 * 27446 * @attr ref android.R.styleable#View_textAlignment 27447 * 27448 * @hide 27449 */ 27450 @ViewDebug.ExportedProperty(category = "text", mapping = { 27451 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 27452 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 27453 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 27454 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 27455 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 27456 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 27457 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 27458 }) 27459 @InspectableProperty(hasAttributeId = false, enumMapping = { 27460 @EnumEntry(value = TEXT_ALIGNMENT_INHERIT, name = "inherit"), 27461 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 27462 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 27463 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 27464 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 27465 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 27466 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 27467 }) 27468 @TextAlignment 27469 @UnsupportedAppUsage getRawTextAlignment()27470 public int getRawTextAlignment() { 27471 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_MASK) >> PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT; 27472 } 27473 27474 /** 27475 * Set the text alignment. 27476 * 27477 * @param textAlignment The text alignment to set. Should be one of 27478 * 27479 * {@link #TEXT_ALIGNMENT_INHERIT}, 27480 * {@link #TEXT_ALIGNMENT_GRAVITY}, 27481 * {@link #TEXT_ALIGNMENT_CENTER}, 27482 * {@link #TEXT_ALIGNMENT_TEXT_START}, 27483 * {@link #TEXT_ALIGNMENT_TEXT_END}, 27484 * {@link #TEXT_ALIGNMENT_VIEW_START}, 27485 * {@link #TEXT_ALIGNMENT_VIEW_END} 27486 * 27487 * Resolution will be done if the value is set to TEXT_ALIGNMENT_INHERIT. The resolution 27488 * proceeds up the parent chain of the view to get the value. If there is no parent, then it 27489 * will return the default {@link #TEXT_ALIGNMENT_GRAVITY}. 27490 * 27491 * @attr ref android.R.styleable#View_textAlignment 27492 */ setTextAlignment(@extAlignment int textAlignment)27493 public void setTextAlignment(@TextAlignment int textAlignment) { 27494 if (textAlignment != getRawTextAlignment()) { 27495 // Reset the current and resolved text alignment 27496 mPrivateFlags2 &= ~PFLAG2_TEXT_ALIGNMENT_MASK; 27497 resetResolvedTextAlignment(); 27498 // Set the new text alignment 27499 mPrivateFlags2 |= 27500 ((textAlignment << PFLAG2_TEXT_ALIGNMENT_MASK_SHIFT) & PFLAG2_TEXT_ALIGNMENT_MASK); 27501 // Do resolution 27502 resolveTextAlignment(); 27503 // Notify change 27504 onRtlPropertiesChanged(getLayoutDirection()); 27505 // Refresh 27506 requestLayout(); 27507 invalidate(true); 27508 } 27509 } 27510 27511 /** 27512 * Return the resolved text alignment. 27513 * 27514 * @return the resolved text alignment. Returns one of: 27515 * 27516 * {@link #TEXT_ALIGNMENT_GRAVITY}, 27517 * {@link #TEXT_ALIGNMENT_CENTER}, 27518 * {@link #TEXT_ALIGNMENT_TEXT_START}, 27519 * {@link #TEXT_ALIGNMENT_TEXT_END}, 27520 * {@link #TEXT_ALIGNMENT_VIEW_START}, 27521 * {@link #TEXT_ALIGNMENT_VIEW_END} 27522 * 27523 * @attr ref android.R.styleable#View_textAlignment 27524 */ 27525 @ViewDebug.ExportedProperty(category = "text", mapping = { 27526 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_INHERIT, to = "INHERIT"), 27527 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_GRAVITY, to = "GRAVITY"), 27528 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_START, to = "TEXT_START"), 27529 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_TEXT_END, to = "TEXT_END"), 27530 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_CENTER, to = "CENTER"), 27531 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_START, to = "VIEW_START"), 27532 @ViewDebug.IntToString(from = TEXT_ALIGNMENT_VIEW_END, to = "VIEW_END") 27533 }) 27534 @InspectableProperty(enumMapping = { 27535 @EnumEntry(value = TEXT_ALIGNMENT_GRAVITY, name = "gravity"), 27536 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_START, name = "textStart"), 27537 @EnumEntry(value = TEXT_ALIGNMENT_TEXT_END, name = "textEnd"), 27538 @EnumEntry(value = TEXT_ALIGNMENT_CENTER, name = "center"), 27539 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_START, name = "viewStart"), 27540 @EnumEntry(value = TEXT_ALIGNMENT_VIEW_END, name = "viewEnd") 27541 }) 27542 @TextAlignment getTextAlignment()27543 public int getTextAlignment() { 27544 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK) >> 27545 PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT; 27546 } 27547 27548 /** 27549 * Resolve the text alignment. 27550 * 27551 * @return true if resolution has been done, false otherwise. 27552 * 27553 * @hide 27554 */ resolveTextAlignment()27555 public boolean resolveTextAlignment() { 27556 // Reset any previous text alignment resolution 27557 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 27558 27559 if (hasRtlSupport()) { 27560 // Set resolved text alignment flag depending on text alignment flag 27561 final int textAlignment = getRawTextAlignment(); 27562 switch (textAlignment) { 27563 case TEXT_ALIGNMENT_INHERIT: 27564 // Check if we can resolve the text alignment 27565 if (!canResolveTextAlignment()) { 27566 // We cannot do the resolution if there is no parent so use the default 27567 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27568 // Resolution will need to happen again later 27569 return false; 27570 } 27571 27572 // Parent has not yet resolved, so we still return the default 27573 try { 27574 if (!mParent.isTextAlignmentResolved()) { 27575 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27576 // Resolution will need to happen again later 27577 return false; 27578 } 27579 } catch (AbstractMethodError e) { 27580 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27581 " does not fully implement ViewParent", e); 27582 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED | 27583 PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27584 return true; 27585 } 27586 27587 int parentResolvedTextAlignment; 27588 try { 27589 parentResolvedTextAlignment = mParent.getTextAlignment(); 27590 } catch (AbstractMethodError e) { 27591 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27592 " does not fully implement ViewParent", e); 27593 parentResolvedTextAlignment = TEXT_ALIGNMENT_GRAVITY; 27594 } 27595 switch (parentResolvedTextAlignment) { 27596 case TEXT_ALIGNMENT_GRAVITY: 27597 case TEXT_ALIGNMENT_TEXT_START: 27598 case TEXT_ALIGNMENT_TEXT_END: 27599 case TEXT_ALIGNMENT_CENTER: 27600 case TEXT_ALIGNMENT_VIEW_START: 27601 case TEXT_ALIGNMENT_VIEW_END: 27602 // Resolved text alignment is the same as the parent resolved 27603 // text alignment 27604 mPrivateFlags2 |= 27605 (parentResolvedTextAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 27606 break; 27607 default: 27608 // Use default resolved text alignment 27609 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27610 } 27611 break; 27612 case TEXT_ALIGNMENT_GRAVITY: 27613 case TEXT_ALIGNMENT_TEXT_START: 27614 case TEXT_ALIGNMENT_TEXT_END: 27615 case TEXT_ALIGNMENT_CENTER: 27616 case TEXT_ALIGNMENT_VIEW_START: 27617 case TEXT_ALIGNMENT_VIEW_END: 27618 // Resolved text alignment is the same as text alignment 27619 mPrivateFlags2 |= (textAlignment << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT); 27620 break; 27621 default: 27622 // Use default resolved text alignment 27623 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27624 } 27625 } else { 27626 // Use default resolved text alignment 27627 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27628 } 27629 27630 // Set the resolved 27631 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED; 27632 return true; 27633 } 27634 27635 /** 27636 * Check if text alignment resolution can be done. 27637 * 27638 * @return true if text alignment resolution can be done otherwise return false. 27639 */ canResolveTextAlignment()27640 public boolean canResolveTextAlignment() { 27641 switch (getRawTextAlignment()) { 27642 case TEXT_DIRECTION_INHERIT: 27643 if (mParent != null) { 27644 try { 27645 return mParent.canResolveTextAlignment(); 27646 } catch (AbstractMethodError e) { 27647 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() + 27648 " does not fully implement ViewParent", e); 27649 } 27650 } 27651 return false; 27652 27653 default: 27654 return true; 27655 } 27656 } 27657 27658 /** 27659 * Reset resolved text alignment. Text alignment will be resolved during a call to 27660 * {@link #onMeasure(int, int)}. 27661 * 27662 * @hide 27663 */ 27664 @TestApi resetResolvedTextAlignment()27665 public void resetResolvedTextAlignment() { 27666 // Reset any previous text alignment resolution 27667 mPrivateFlags2 &= ~(PFLAG2_TEXT_ALIGNMENT_RESOLVED | PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK); 27668 // Set to default 27669 mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT; 27670 } 27671 27672 /** 27673 * @return true if text alignment is inherited. 27674 * 27675 * @hide 27676 */ isTextAlignmentInherited()27677 public boolean isTextAlignmentInherited() { 27678 return (getRawTextAlignment() == TEXT_ALIGNMENT_INHERIT); 27679 } 27680 27681 /** 27682 * @return true if text alignment is resolved. 27683 */ isTextAlignmentResolved()27684 public boolean isTextAlignmentResolved() { 27685 return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED; 27686 } 27687 27688 /** 27689 * Generate a value suitable for use in {@link #setId(int)}. 27690 * This value will not collide with ID values generated at build time by aapt for R.id. 27691 * 27692 * @return a generated ID value 27693 */ generateViewId()27694 public static int generateViewId() { 27695 for (;;) { 27696 final int result = sNextGeneratedId.get(); 27697 // aapt-generated IDs have the high byte nonzero; clamp to the range under that. 27698 int newValue = result + 1; 27699 if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0. 27700 if (sNextGeneratedId.compareAndSet(result, newValue)) { 27701 return result; 27702 } 27703 } 27704 } 27705 isViewIdGenerated(int id)27706 private static boolean isViewIdGenerated(int id) { 27707 return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0; 27708 } 27709 27710 /** 27711 * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions. 27712 * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and 27713 * a normal View or a ViewGroup with 27714 * {@link android.view.ViewGroup#isTransitionGroup()} true. 27715 * @hide 27716 */ captureTransitioningViews(List<View> transitioningViews)27717 public void captureTransitioningViews(List<View> transitioningViews) { 27718 if (getVisibility() == View.VISIBLE) { 27719 transitioningViews.add(this); 27720 } 27721 } 27722 27723 /** 27724 * Adds all Views that have {@link #getTransitionName()} non-null to namedElements. 27725 * @param namedElements Will contain all Views in the hierarchy having a transitionName. 27726 * @hide 27727 */ findNamedViews(Map<String, View> namedElements)27728 public void findNamedViews(Map<String, View> namedElements) { 27729 if (getVisibility() == VISIBLE || mGhostView != null) { 27730 String transitionName = getTransitionName(); 27731 if (transitionName != null) { 27732 namedElements.put(transitionName, this); 27733 } 27734 } 27735 } 27736 27737 /** 27738 * Returns the pointer icon for the motion event, or null if it doesn't specify the icon. 27739 * The default implementation does not care the location or event types, but some subclasses 27740 * may use it (such as WebViews). 27741 * @param event The MotionEvent from a mouse 27742 * @param pointerIndex The index of the pointer for which to retrieve the {@link PointerIcon}. 27743 * This will be between 0 and {@link MotionEvent#getPointerCount()}. 27744 * @see PointerIcon 27745 */ onResolvePointerIcon(MotionEvent event, int pointerIndex)27746 public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) { 27747 final float x = event.getX(pointerIndex); 27748 final float y = event.getY(pointerIndex); 27749 if (isDraggingScrollBar() || isOnScrollbarThumb(x, y)) { 27750 return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW); 27751 } 27752 return mPointerIcon; 27753 } 27754 27755 /** 27756 * Set the pointer icon for the current view. 27757 * Passing {@code null} will restore the pointer icon to its default value. 27758 * @param pointerIcon A PointerIcon instance which will be shown when the mouse hovers. 27759 */ setPointerIcon(PointerIcon pointerIcon)27760 public void setPointerIcon(PointerIcon pointerIcon) { 27761 mPointerIcon = pointerIcon; 27762 if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) { 27763 return; 27764 } 27765 try { 27766 mAttachInfo.mSession.updatePointerIcon(mAttachInfo.mWindow); 27767 } catch (RemoteException e) { 27768 } 27769 } 27770 27771 /** 27772 * Gets the pointer icon for the current view. 27773 */ 27774 @InspectableProperty getPointerIcon()27775 public PointerIcon getPointerIcon() { 27776 return mPointerIcon; 27777 } 27778 27779 /** 27780 * Checks pointer capture status. 27781 * 27782 * @return true if the view has pointer capture. 27783 * @see #requestPointerCapture() 27784 * @see #hasPointerCapture() 27785 */ hasPointerCapture()27786 public boolean hasPointerCapture() { 27787 final ViewRootImpl viewRootImpl = getViewRootImpl(); 27788 if (viewRootImpl == null) { 27789 return false; 27790 } 27791 return viewRootImpl.hasPointerCapture(); 27792 } 27793 27794 /** 27795 * Requests pointer capture mode. 27796 * <p> 27797 * When the window has pointer capture, the mouse pointer icon will disappear and will not 27798 * change its position. Further mouse will be dispatched with the source 27799 * {@link InputDevice#SOURCE_MOUSE_RELATIVE}, and relative position changes will be available 27800 * through {@link MotionEvent#getX} and {@link MotionEvent#getY}. Non-mouse events 27801 * (touchscreens, or stylus) will not be affected. 27802 * <p> 27803 * If the window already has pointer capture, this call does nothing. 27804 * <p> 27805 * The capture may be released through {@link #releasePointerCapture()}, or will be lost 27806 * automatically when the window loses focus. 27807 * 27808 * @see #releasePointerCapture() 27809 * @see #hasPointerCapture() 27810 */ requestPointerCapture()27811 public void requestPointerCapture() { 27812 final ViewRootImpl viewRootImpl = getViewRootImpl(); 27813 if (viewRootImpl != null) { 27814 viewRootImpl.requestPointerCapture(true); 27815 } 27816 } 27817 27818 27819 /** 27820 * Releases the pointer capture. 27821 * <p> 27822 * If the window does not have pointer capture, this call will do nothing. 27823 * @see #requestPointerCapture() 27824 * @see #hasPointerCapture() 27825 */ releasePointerCapture()27826 public void releasePointerCapture() { 27827 final ViewRootImpl viewRootImpl = getViewRootImpl(); 27828 if (viewRootImpl != null) { 27829 viewRootImpl.requestPointerCapture(false); 27830 } 27831 } 27832 27833 /** 27834 * Called when the window has just acquired or lost pointer capture. 27835 * 27836 * @param hasCapture True if the view now has pointerCapture, false otherwise. 27837 */ 27838 @CallSuper onPointerCaptureChange(boolean hasCapture)27839 public void onPointerCaptureChange(boolean hasCapture) { 27840 } 27841 27842 /** 27843 * @see #onPointerCaptureChange 27844 */ dispatchPointerCaptureChanged(boolean hasCapture)27845 public void dispatchPointerCaptureChanged(boolean hasCapture) { 27846 onPointerCaptureChange(hasCapture); 27847 } 27848 27849 /** 27850 * Implement this method to handle captured pointer events 27851 * 27852 * @param event The captured pointer event. 27853 * @return True if the event was handled, false otherwise. 27854 * @see #requestPointerCapture() 27855 */ onCapturedPointerEvent(MotionEvent event)27856 public boolean onCapturedPointerEvent(MotionEvent event) { 27857 return false; 27858 } 27859 27860 /** 27861 * Interface definition for a callback to be invoked when a captured pointer event 27862 * is being dispatched this view. The callback will be invoked before the event is 27863 * given to the view. 27864 */ 27865 public interface OnCapturedPointerListener { 27866 /** 27867 * Called when a captured pointer event is dispatched to a view. 27868 * @param view The view this event has been dispatched to. 27869 * @param event The captured event. 27870 * @return True if the listener has consumed the event, false otherwise. 27871 */ 27872 boolean onCapturedPointer(View view, MotionEvent event); 27873 } 27874 27875 /** 27876 * Set a listener to receive callbacks when the pointer capture state of a view changes. 27877 * @param l The {@link OnCapturedPointerListener} to receive callbacks. 27878 */ setOnCapturedPointerListener(OnCapturedPointerListener l)27879 public void setOnCapturedPointerListener(OnCapturedPointerListener l) { 27880 getListenerInfo().mOnCapturedPointerListener = l; 27881 } 27882 27883 // Properties 27884 // 27885 /** 27886 * A Property wrapper around the <code>alpha</code> functionality handled by the 27887 * {@link View#setAlpha(float)} and {@link View#getAlpha()} methods. 27888 */ 27889 public static final Property<View, Float> ALPHA = new FloatProperty<View>("alpha") { 27890 @Override 27891 public void setValue(View object, float value) { 27892 object.setAlpha(value); 27893 } 27894 27895 @Override 27896 public Float get(View object) { 27897 return object.getAlpha(); 27898 } 27899 }; 27900 27901 /** 27902 * A Property wrapper around the <code>translationX</code> functionality handled by the 27903 * {@link View#setTranslationX(float)} and {@link View#getTranslationX()} methods. 27904 */ 27905 public static final Property<View, Float> TRANSLATION_X = new FloatProperty<View>("translationX") { 27906 @Override 27907 public void setValue(View object, float value) { 27908 object.setTranslationX(value); 27909 } 27910 27911 @Override 27912 public Float get(View object) { 27913 return object.getTranslationX(); 27914 } 27915 }; 27916 27917 /** 27918 * A Property wrapper around the <code>translationY</code> functionality handled by the 27919 * {@link View#setTranslationY(float)} and {@link View#getTranslationY()} methods. 27920 */ 27921 public static final Property<View, Float> TRANSLATION_Y = new FloatProperty<View>("translationY") { 27922 @Override 27923 public void setValue(View object, float value) { 27924 object.setTranslationY(value); 27925 } 27926 27927 @Override 27928 public Float get(View object) { 27929 return object.getTranslationY(); 27930 } 27931 }; 27932 27933 /** 27934 * A Property wrapper around the <code>translationZ</code> functionality handled by the 27935 * {@link View#setTranslationZ(float)} and {@link View#getTranslationZ()} methods. 27936 */ 27937 public static final Property<View, Float> TRANSLATION_Z = new FloatProperty<View>("translationZ") { 27938 @Override 27939 public void setValue(View object, float value) { 27940 object.setTranslationZ(value); 27941 } 27942 27943 @Override 27944 public Float get(View object) { 27945 return object.getTranslationZ(); 27946 } 27947 }; 27948 27949 /** 27950 * A Property wrapper around the <code>x</code> functionality handled by the 27951 * {@link View#setX(float)} and {@link View#getX()} methods. 27952 */ 27953 public static final Property<View, Float> X = new FloatProperty<View>("x") { 27954 @Override 27955 public void setValue(View object, float value) { 27956 object.setX(value); 27957 } 27958 27959 @Override 27960 public Float get(View object) { 27961 return object.getX(); 27962 } 27963 }; 27964 27965 /** 27966 * A Property wrapper around the <code>y</code> functionality handled by the 27967 * {@link View#setY(float)} and {@link View#getY()} methods. 27968 */ 27969 public static final Property<View, Float> Y = new FloatProperty<View>("y") { 27970 @Override 27971 public void setValue(View object, float value) { 27972 object.setY(value); 27973 } 27974 27975 @Override 27976 public Float get(View object) { 27977 return object.getY(); 27978 } 27979 }; 27980 27981 /** 27982 * A Property wrapper around the <code>z</code> functionality handled by the 27983 * {@link View#setZ(float)} and {@link View#getZ()} methods. 27984 */ 27985 public static final Property<View, Float> Z = new FloatProperty<View>("z") { 27986 @Override 27987 public void setValue(View object, float value) { 27988 object.setZ(value); 27989 } 27990 27991 @Override 27992 public Float get(View object) { 27993 return object.getZ(); 27994 } 27995 }; 27996 27997 /** 27998 * A Property wrapper around the <code>rotation</code> functionality handled by the 27999 * {@link View#setRotation(float)} and {@link View#getRotation()} methods. 28000 */ 28001 public static final Property<View, Float> ROTATION = new FloatProperty<View>("rotation") { 28002 @Override 28003 public void setValue(View object, float value) { 28004 object.setRotation(value); 28005 } 28006 28007 @Override 28008 public Float get(View object) { 28009 return object.getRotation(); 28010 } 28011 }; 28012 28013 /** 28014 * A Property wrapper around the <code>rotationX</code> functionality handled by the 28015 * {@link View#setRotationX(float)} and {@link View#getRotationX()} methods. 28016 */ 28017 public static final Property<View, Float> ROTATION_X = new FloatProperty<View>("rotationX") { 28018 @Override 28019 public void setValue(View object, float value) { 28020 object.setRotationX(value); 28021 } 28022 28023 @Override 28024 public Float get(View object) { 28025 return object.getRotationX(); 28026 } 28027 }; 28028 28029 /** 28030 * A Property wrapper around the <code>rotationY</code> functionality handled by the 28031 * {@link View#setRotationY(float)} and {@link View#getRotationY()} methods. 28032 */ 28033 public static final Property<View, Float> ROTATION_Y = new FloatProperty<View>("rotationY") { 28034 @Override 28035 public void setValue(View object, float value) { 28036 object.setRotationY(value); 28037 } 28038 28039 @Override 28040 public Float get(View object) { 28041 return object.getRotationY(); 28042 } 28043 }; 28044 28045 /** 28046 * A Property wrapper around the <code>scaleX</code> functionality handled by the 28047 * {@link View#setScaleX(float)} and {@link View#getScaleX()} methods. 28048 */ 28049 public static final Property<View, Float> SCALE_X = new FloatProperty<View>("scaleX") { 28050 @Override 28051 public void setValue(View object, float value) { 28052 object.setScaleX(value); 28053 } 28054 28055 @Override 28056 public Float get(View object) { 28057 return object.getScaleX(); 28058 } 28059 }; 28060 28061 /** 28062 * A Property wrapper around the <code>scaleY</code> functionality handled by the 28063 * {@link View#setScaleY(float)} and {@link View#getScaleY()} methods. 28064 */ 28065 public static final Property<View, Float> SCALE_Y = new FloatProperty<View>("scaleY") { 28066 @Override 28067 public void setValue(View object, float value) { 28068 object.setScaleY(value); 28069 } 28070 28071 @Override 28072 public Float get(View object) { 28073 return object.getScaleY(); 28074 } 28075 }; 28076 28077 /** 28078 * A MeasureSpec encapsulates the layout requirements passed from parent to child. 28079 * Each MeasureSpec represents a requirement for either the width or the height. 28080 * A MeasureSpec is comprised of a size and a mode. There are three possible 28081 * modes: 28082 * <dl> 28083 * <dt>UNSPECIFIED</dt> 28084 * <dd> 28085 * The parent has not imposed any constraint on the child. It can be whatever size 28086 * it wants. 28087 * </dd> 28088 * 28089 * <dt>EXACTLY</dt> 28090 * <dd> 28091 * The parent has determined an exact size for the child. The child is going to be 28092 * given those bounds regardless of how big it wants to be. 28093 * </dd> 28094 * 28095 * <dt>AT_MOST</dt> 28096 * <dd> 28097 * The child can be as large as it wants up to the specified size. 28098 * </dd> 28099 * </dl> 28100 * 28101 * MeasureSpecs are implemented as ints to reduce object allocation. This class 28102 * is provided to pack and unpack the <size, mode> tuple into the int. 28103 */ 28104 public static class MeasureSpec { 28105 private static final int MODE_SHIFT = 30; 28106 private static final int MODE_MASK = 0x3 << MODE_SHIFT; 28107 28108 /** @hide */ 28109 @IntDef({UNSPECIFIED, EXACTLY, AT_MOST}) 28110 @Retention(RetentionPolicy.SOURCE) 28111 public @interface MeasureSpecMode {} 28112 28113 /** 28114 * Measure specification mode: The parent has not imposed any constraint 28115 * on the child. It can be whatever size it wants. 28116 */ 28117 public static final int UNSPECIFIED = 0 << MODE_SHIFT; 28118 28119 /** 28120 * Measure specification mode: The parent has determined an exact size 28121 * for the child. The child is going to be given those bounds regardless 28122 * of how big it wants to be. 28123 */ 28124 public static final int EXACTLY = 1 << MODE_SHIFT; 28125 28126 /** 28127 * Measure specification mode: The child can be as large as it wants up 28128 * to the specified size. 28129 */ 28130 public static final int AT_MOST = 2 << MODE_SHIFT; 28131 28132 /** 28133 * Creates a measure specification based on the supplied size and mode. 28134 * 28135 * The mode must always be one of the following: 28136 * <ul> 28137 * <li>{@link android.view.View.MeasureSpec#UNSPECIFIED}</li> 28138 * <li>{@link android.view.View.MeasureSpec#EXACTLY}</li> 28139 * <li>{@link android.view.View.MeasureSpec#AT_MOST}</li> 28140 * </ul> 28141 * 28142 * <p><strong>Note:</strong> On API level 17 and lower, makeMeasureSpec's 28143 * implementation was such that the order of arguments did not matter 28144 * and overflow in either value could impact the resulting MeasureSpec. 28145 * {@link android.widget.RelativeLayout} was affected by this bug. 28146 * Apps targeting API levels greater than 17 will get the fixed, more strict 28147 * behavior.</p> 28148 * 28149 * @param size the size of the measure specification 28150 * @param mode the mode of the measure specification 28151 * @return the measure specification based on size and mode 28152 */ makeMeasureSpec(@ntRangefrom = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, @MeasureSpecMode int mode)28153 public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size, 28154 @MeasureSpecMode int mode) { 28155 if (sUseBrokenMakeMeasureSpec) { 28156 return size + mode; 28157 } else { 28158 return (size & ~MODE_MASK) | (mode & MODE_MASK); 28159 } 28160 } 28161 28162 /** 28163 * Like {@link #makeMeasureSpec(int, int)}, but any spec with a mode of UNSPECIFIED 28164 * will automatically get a size of 0. Older apps expect this. 28165 * 28166 * @hide internal use only for compatibility with system widgets and older apps 28167 */ 28168 @UnsupportedAppUsage makeSafeMeasureSpec(int size, int mode)28169 public static int makeSafeMeasureSpec(int size, int mode) { 28170 if (sUseZeroUnspecifiedMeasureSpec && mode == UNSPECIFIED) { 28171 return 0; 28172 } 28173 return makeMeasureSpec(size, mode); 28174 } 28175 28176 /** 28177 * Extracts the mode from the supplied measure specification. 28178 * 28179 * @param measureSpec the measure specification to extract the mode from 28180 * @return {@link android.view.View.MeasureSpec#UNSPECIFIED}, 28181 * {@link android.view.View.MeasureSpec#AT_MOST} or 28182 * {@link android.view.View.MeasureSpec#EXACTLY} 28183 */ 28184 @MeasureSpecMode getMode(int measureSpec)28185 public static int getMode(int measureSpec) { 28186 //noinspection ResourceType 28187 return (measureSpec & MODE_MASK); 28188 } 28189 28190 /** 28191 * Extracts the size from the supplied measure specification. 28192 * 28193 * @param measureSpec the measure specification to extract the size from 28194 * @return the size in pixels defined in the supplied measure specification 28195 */ getSize(int measureSpec)28196 public static int getSize(int measureSpec) { 28197 return (measureSpec & ~MODE_MASK); 28198 } 28199 adjust(int measureSpec, int delta)28200 static int adjust(int measureSpec, int delta) { 28201 final int mode = getMode(measureSpec); 28202 int size = getSize(measureSpec); 28203 if (mode == UNSPECIFIED) { 28204 // No need to adjust size for UNSPECIFIED mode. 28205 return makeMeasureSpec(size, UNSPECIFIED); 28206 } 28207 size += delta; 28208 if (size < 0) { 28209 Log.e(VIEW_LOG_TAG, "MeasureSpec.adjust: new size would be negative! (" + size + 28210 ") spec: " + toString(measureSpec) + " delta: " + delta); 28211 size = 0; 28212 } 28213 return makeMeasureSpec(size, mode); 28214 } 28215 28216 /** 28217 * Returns a String representation of the specified measure 28218 * specification. 28219 * 28220 * @param measureSpec the measure specification to convert to a String 28221 * @return a String with the following format: "MeasureSpec: MODE SIZE" 28222 */ toString(int measureSpec)28223 public static String toString(int measureSpec) { 28224 int mode = getMode(measureSpec); 28225 int size = getSize(measureSpec); 28226 28227 StringBuilder sb = new StringBuilder("MeasureSpec: "); 28228 28229 if (mode == UNSPECIFIED) 28230 sb.append("UNSPECIFIED "); 28231 else if (mode == EXACTLY) 28232 sb.append("EXACTLY "); 28233 else if (mode == AT_MOST) 28234 sb.append("AT_MOST "); 28235 else 28236 sb.append(mode).append(" "); 28237 28238 sb.append(size); 28239 return sb.toString(); 28240 } 28241 } 28242 28243 private final class CheckForLongPress implements Runnable { 28244 private int mOriginalWindowAttachCount; 28245 private float mX; 28246 private float mY; 28247 private boolean mOriginalPressedState; 28248 /** 28249 * The classification of the long click being checked: one of the 28250 * FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__* constants. 28251 */ 28252 private int mClassification; 28253 28254 @UnsupportedAppUsage CheckForLongPress()28255 private CheckForLongPress() { 28256 } 28257 28258 @Override run()28259 public void run() { 28260 if ((mOriginalPressedState == isPressed()) && (mParent != null) 28261 && mOriginalWindowAttachCount == mWindowAttachCount) { 28262 recordGestureClassification(mClassification); 28263 if (performLongClick(mX, mY)) { 28264 mHasPerformedLongPress = true; 28265 } 28266 } 28267 } 28268 setAnchor(float x, float y)28269 public void setAnchor(float x, float y) { 28270 mX = x; 28271 mY = y; 28272 } 28273 rememberWindowAttachCount()28274 public void rememberWindowAttachCount() { 28275 mOriginalWindowAttachCount = mWindowAttachCount; 28276 } 28277 rememberPressedState()28278 public void rememberPressedState() { 28279 mOriginalPressedState = isPressed(); 28280 } 28281 setClassification(int classification)28282 public void setClassification(int classification) { 28283 mClassification = classification; 28284 } 28285 } 28286 28287 private final class CheckForTap implements Runnable { 28288 public float x; 28289 public float y; 28290 28291 @Override run()28292 public void run() { 28293 mPrivateFlags &= ~PFLAG_PREPRESSED; 28294 setPressed(true, x, y); 28295 final long delay = 28296 ViewConfiguration.getLongPressTimeout() - ViewConfiguration.getTapTimeout(); 28297 checkForLongClick(delay, x, y, TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__LONG_PRESS); 28298 } 28299 } 28300 28301 private final class PerformClick implements Runnable { 28302 @Override run()28303 public void run() { 28304 recordGestureClassification(TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__SINGLE_TAP); 28305 performClickInternal(); 28306 } 28307 } 28308 28309 /** Records a classification for the current event stream. */ recordGestureClassification(int classification)28310 private void recordGestureClassification(int classification) { 28311 if (classification == TOUCH_GESTURE_CLASSIFIED__CLASSIFICATION__UNKNOWN_CLASSIFICATION) { 28312 return; 28313 } 28314 // To avoid negatively impacting View performance, the latency and displacement metrics 28315 // are omitted. 28316 FrameworkStatsLog.write(FrameworkStatsLog.TOUCH_GESTURE_CLASSIFIED, getClass().getName(), 28317 classification); 28318 } 28319 28320 /** 28321 * This method returns a ViewPropertyAnimator object, which can be used to animate 28322 * specific properties on this View. 28323 * 28324 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View. 28325 */ animate()28326 public ViewPropertyAnimator animate() { 28327 if (mAnimator == null) { 28328 mAnimator = new ViewPropertyAnimator(this); 28329 } 28330 return mAnimator; 28331 } 28332 28333 /** 28334 * Sets the name of the View to be used to identify Views in Transitions. 28335 * Names should be unique in the View hierarchy. 28336 * 28337 * @param transitionName The name of the View to uniquely identify it for Transitions. 28338 */ setTransitionName(String transitionName)28339 public final void setTransitionName(String transitionName) { 28340 mTransitionName = transitionName; 28341 } 28342 28343 /** 28344 * Returns the name of the View to be used to identify Views in Transitions. 28345 * Names should be unique in the View hierarchy. 28346 * 28347 * <p>This returns null if the View has not been given a name.</p> 28348 * 28349 * @return The name used of the View to be used to identify Views in Transitions or null 28350 * if no name has been given. 28351 */ 28352 @ViewDebug.ExportedProperty 28353 @InspectableProperty getTransitionName()28354 public String getTransitionName() { 28355 return mTransitionName; 28356 } 28357 28358 /** 28359 * @hide 28360 */ requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId)28361 public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> data, int deviceId) { 28362 // Do nothing. 28363 } 28364 28365 /** 28366 * Interface definition for a callback to be invoked when a hardware key event is 28367 * dispatched to this view. The callback will be invoked before the key event is 28368 * given to the view. This is only useful for hardware keyboards; a software input 28369 * method has no obligation to trigger this listener. 28370 */ 28371 public interface OnKeyListener { 28372 /** 28373 * Called when a hardware key is dispatched to a view. This allows listeners to 28374 * get a chance to respond before the target view. 28375 * <p>Key presses in software keyboards will generally NOT trigger this method, 28376 * although some may elect to do so in some situations. Do not assume a 28377 * software input method has to be key-based; even if it is, it may use key presses 28378 * in a different way than you expect, so there is no way to reliably catch soft 28379 * input key presses. 28380 * 28381 * @param v The view the key has been dispatched to. 28382 * @param keyCode The code for the physical key that was pressed 28383 * @param event The KeyEvent object containing full information about 28384 * the event. 28385 * @return True if the listener has consumed the event, false otherwise. 28386 */ 28387 boolean onKey(View v, int keyCode, KeyEvent event); 28388 } 28389 28390 /** 28391 * Interface definition for a callback to be invoked when a hardware key event hasn't 28392 * been handled by the view hierarchy. 28393 */ 28394 public interface OnUnhandledKeyEventListener { 28395 /** 28396 * Called when a hardware key is dispatched to a view after being unhandled during normal 28397 * {@link KeyEvent} dispatch. 28398 * 28399 * @param v The view the key has been dispatched to. 28400 * @param event The KeyEvent object containing information about the event. 28401 * @return {@code true} if the listener has consumed the event, {@code false} otherwise. 28402 */ 28403 boolean onUnhandledKeyEvent(View v, KeyEvent event); 28404 } 28405 28406 /** 28407 * Interface definition for a callback to be invoked when a touch event is 28408 * dispatched to this view. The callback will be invoked before the touch 28409 * event is given to the view. 28410 */ 28411 public interface OnTouchListener { 28412 /** 28413 * Called when a touch event is dispatched to a view. This allows listeners to 28414 * get a chance to respond before the target view. 28415 * 28416 * @param v The view the touch event has been dispatched to. 28417 * @param event The MotionEvent object containing full information about 28418 * the event. 28419 * @return True if the listener has consumed the event, false otherwise. 28420 */ 28421 boolean onTouch(View v, MotionEvent event); 28422 } 28423 28424 /** 28425 * Interface definition for a callback to be invoked when a hover event is 28426 * dispatched to this view. The callback will be invoked before the hover 28427 * event is given to the view. 28428 */ 28429 public interface OnHoverListener { 28430 /** 28431 * Called when a hover event is dispatched to a view. This allows listeners to 28432 * get a chance to respond before the target view. 28433 * 28434 * @param v The view the hover event has been dispatched to. 28435 * @param event The MotionEvent object containing full information about 28436 * the event. 28437 * @return True if the listener has consumed the event, false otherwise. 28438 */ 28439 boolean onHover(View v, MotionEvent event); 28440 } 28441 28442 /** 28443 * Interface definition for a callback to be invoked when a generic motion event is 28444 * dispatched to this view. The callback will be invoked before the generic motion 28445 * event is given to the view. 28446 */ 28447 public interface OnGenericMotionListener { 28448 /** 28449 * Called when a generic motion event is dispatched to a view. This allows listeners to 28450 * get a chance to respond before the target view. 28451 * 28452 * @param v The view the generic motion event has been dispatched to. 28453 * @param event The MotionEvent object containing full information about 28454 * the event. 28455 * @return True if the listener has consumed the event, false otherwise. 28456 */ 28457 boolean onGenericMotion(View v, MotionEvent event); 28458 } 28459 28460 /** 28461 * Interface definition for a callback to be invoked when a view has been clicked and held. 28462 */ 28463 public interface OnLongClickListener { 28464 /** 28465 * Called when a view has been clicked and held. 28466 * 28467 * @param v The view that was clicked and held. 28468 * 28469 * @return true if the callback consumed the long click, false otherwise. 28470 */ 28471 boolean onLongClick(View v); 28472 } 28473 28474 /** 28475 * Interface definition for a callback to be invoked when a drag is being dispatched 28476 * to this view. The callback will be invoked before the hosting view's own 28477 * onDrag(event) method. If the listener wants to fall back to the hosting view's 28478 * onDrag(event) behavior, it should return 'false' from this callback. 28479 * 28480 * <div class="special reference"> 28481 * <h3>Developer Guides</h3> 28482 * <p>For a guide to implementing drag and drop features, read the 28483 * <a href="{@docRoot}guide/topics/ui/drag-drop.html">Drag and Drop</a> developer guide.</p> 28484 * </div> 28485 */ 28486 public interface OnDragListener { 28487 /** 28488 * Called when a drag event is dispatched to a view. This allows listeners 28489 * to get a chance to override base View behavior. 28490 * 28491 * @param v The View that received the drag event. 28492 * @param event The {@link android.view.DragEvent} object for the drag event. 28493 * @return {@code true} if the drag event was handled successfully, or {@code false} 28494 * if the drag event was not handled. Note that {@code false} will trigger the View 28495 * to call its {@link #onDragEvent(DragEvent) onDragEvent()} handler. 28496 */ 28497 boolean onDrag(View v, DragEvent event); 28498 } 28499 28500 /** 28501 * Interface definition for a callback to be invoked when the focus state of 28502 * a view changed. 28503 */ 28504 public interface OnFocusChangeListener { 28505 /** 28506 * Called when the focus state of a view has changed. 28507 * 28508 * @param v The view whose state has changed. 28509 * @param hasFocus The new focus state of v. 28510 */ 28511 void onFocusChange(View v, boolean hasFocus); 28512 } 28513 28514 /** 28515 * Interface definition for a callback to be invoked when a view is clicked. 28516 */ 28517 public interface OnClickListener { 28518 /** 28519 * Called when a view has been clicked. 28520 * 28521 * @param v The view that was clicked. 28522 */ 28523 void onClick(View v); 28524 } 28525 28526 /** 28527 * Interface definition for a callback to be invoked when a view is context clicked. 28528 */ 28529 public interface OnContextClickListener { 28530 /** 28531 * Called when a view is context clicked. 28532 * 28533 * @param v The view that has been context clicked. 28534 * @return true if the callback consumed the context click, false otherwise. 28535 */ 28536 boolean onContextClick(View v); 28537 } 28538 28539 /** 28540 * Interface definition for a callback to be invoked when the context menu 28541 * for this view is being built. 28542 */ 28543 public interface OnCreateContextMenuListener { 28544 /** 28545 * Called when the context menu for this view is being built. It is not 28546 * safe to hold onto the menu after this method returns. 28547 * 28548 * @param menu The context menu that is being built 28549 * @param v The view for which the context menu is being built 28550 * @param menuInfo Extra information about the item for which the 28551 * context menu should be shown. This information will vary 28552 * depending on the class of v. 28553 */ 28554 void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo); 28555 } 28556 28557 /** 28558 * Interface definition for a callback to be invoked when the status bar changes 28559 * visibility. This reports <strong>global</strong> changes to the system UI 28560 * state, not what the application is requesting. 28561 * 28562 * @see View#setOnSystemUiVisibilityChangeListener(android.view.View.OnSystemUiVisibilityChangeListener) 28563 * 28564 * @deprecated Use {@link WindowInsets#isVisible(int)} to find out about system bar visibilities 28565 * by setting a {@link OnApplyWindowInsetsListener} on this view. 28566 */ 28567 @Deprecated 28568 public interface OnSystemUiVisibilityChangeListener { 28569 /** 28570 * Called when the status bar changes visibility because of a call to 28571 * {@link View#setSystemUiVisibility(int)}. 28572 * 28573 * @param visibility Bitwise-or of flags {@link #SYSTEM_UI_FLAG_LOW_PROFILE}, 28574 * {@link #SYSTEM_UI_FLAG_HIDE_NAVIGATION}, and {@link #SYSTEM_UI_FLAG_FULLSCREEN}. 28575 * This tells you the <strong>global</strong> state of these UI visibility 28576 * flags, not what your app is currently applying. 28577 */ 28578 public void onSystemUiVisibilityChange(int visibility); 28579 } 28580 28581 /** 28582 * Interface definition for a callback to be invoked when this view is attached 28583 * or detached from its window. 28584 */ 28585 public interface OnAttachStateChangeListener { 28586 /** 28587 * Called when the view is attached to a window. 28588 * @param v The view that was attached 28589 */ 28590 public void onViewAttachedToWindow(View v); 28591 /** 28592 * Called when the view is detached from a window. 28593 * @param v The view that was detached 28594 */ 28595 public void onViewDetachedFromWindow(View v); 28596 } 28597 28598 /** 28599 * Listener for applying window insets on a view in a custom way. 28600 * 28601 * <p>Apps may choose to implement this interface if they want to apply custom policy 28602 * to the way that window insets are treated for a view. If an OnApplyWindowInsetsListener 28603 * is set, its 28604 * {@link OnApplyWindowInsetsListener#onApplyWindowInsets(View, WindowInsets) onApplyWindowInsets} 28605 * method will be called instead of the View's own 28606 * {@link #onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. The listener 28607 * may optionally call the parameter View's <code>onApplyWindowInsets</code> method to apply 28608 * the View's normal behavior as part of its own.</p> 28609 */ 28610 public interface OnApplyWindowInsetsListener { 28611 /** 28612 * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} 28613 * on a View, this listener method will be called instead of the view's own 28614 * {@link View#onApplyWindowInsets(WindowInsets) onApplyWindowInsets} method. 28615 * 28616 * @param v The view applying window insets 28617 * @param insets The insets to apply 28618 * @return The insets supplied, minus any insets that were consumed 28619 */ 28620 public WindowInsets onApplyWindowInsets(View v, WindowInsets insets); 28621 } 28622 28623 private final class UnsetPressedState implements Runnable { 28624 @Override run()28625 public void run() { 28626 setPressed(false); 28627 } 28628 } 28629 28630 /** 28631 * When a view becomes invisible checks if autofill considers the view invisible too. This 28632 * happens after the regular removal operation to make sure the operation is finished by the 28633 * time this is called. 28634 */ 28635 private static class VisibilityChangeForAutofillHandler extends Handler { 28636 private final AutofillManager mAfm; 28637 private final View mView; 28638 VisibilityChangeForAutofillHandler(@onNull AutofillManager afm, @NonNull View view)28639 private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm, 28640 @NonNull View view) { 28641 mAfm = afm; 28642 mView = view; 28643 } 28644 28645 @Override handleMessage(Message msg)28646 public void handleMessage(Message msg) { 28647 mAfm.notifyViewVisibilityChanged(mView, mView.isShown()); 28648 } 28649 } 28650 28651 /** 28652 * Base class for derived classes that want to save and restore their own 28653 * state in {@link android.view.View#onSaveInstanceState()}. 28654 */ 28655 public static class BaseSavedState extends AbsSavedState { 28656 static final int START_ACTIVITY_REQUESTED_WHO_SAVED = 0b1; 28657 static final int IS_AUTOFILLED = 0b10; 28658 static final int AUTOFILL_ID = 0b100; 28659 28660 // Flags that describe what data in this state is valid 28661 int mSavedData; 28662 String mStartActivityRequestWhoSaved; 28663 boolean mIsAutofilled; 28664 boolean mHideHighlight; 28665 int mAutofillViewId; 28666 28667 /** 28668 * Constructor used when reading from a parcel. Reads the state of the superclass. 28669 * 28670 * @param source parcel to read from 28671 */ BaseSavedState(Parcel source)28672 public BaseSavedState(Parcel source) { 28673 this(source, null); 28674 } 28675 28676 /** 28677 * Constructor used when reading from a parcel using a given class loader. 28678 * Reads the state of the superclass. 28679 * 28680 * @param source parcel to read from 28681 * @param loader ClassLoader to use for reading 28682 */ BaseSavedState(Parcel source, ClassLoader loader)28683 public BaseSavedState(Parcel source, ClassLoader loader) { 28684 super(source, loader); 28685 mSavedData = source.readInt(); 28686 mStartActivityRequestWhoSaved = source.readString(); 28687 mIsAutofilled = source.readBoolean(); 28688 mHideHighlight = source.readBoolean(); 28689 mAutofillViewId = source.readInt(); 28690 } 28691 28692 /** 28693 * Constructor called by derived classes when creating their SavedState objects 28694 * 28695 * @param superState The state of the superclass of this view 28696 */ BaseSavedState(Parcelable superState)28697 public BaseSavedState(Parcelable superState) { 28698 super(superState); 28699 } 28700 28701 @Override writeToParcel(Parcel out, int flags)28702 public void writeToParcel(Parcel out, int flags) { 28703 super.writeToParcel(out, flags); 28704 28705 out.writeInt(mSavedData); 28706 out.writeString(mStartActivityRequestWhoSaved); 28707 out.writeBoolean(mIsAutofilled); 28708 out.writeBoolean(mHideHighlight); 28709 out.writeInt(mAutofillViewId); 28710 } 28711 28712 public static final @android.annotation.NonNull Parcelable.Creator<BaseSavedState> CREATOR 28713 = new Parcelable.ClassLoaderCreator<BaseSavedState>() { 28714 @Override 28715 public BaseSavedState createFromParcel(Parcel in) { 28716 return new BaseSavedState(in); 28717 } 28718 28719 @Override 28720 public BaseSavedState createFromParcel(Parcel in, ClassLoader loader) { 28721 return new BaseSavedState(in, loader); 28722 } 28723 28724 @Override 28725 public BaseSavedState[] newArray(int size) { 28726 return new BaseSavedState[size]; 28727 } 28728 }; 28729 } 28730 28731 /** 28732 * A set of information given to a view when it is attached to its parent 28733 * window. 28734 */ 28735 final static class AttachInfo { 28736 28737 interface Callbacks { 28738 void playSoundEffect(int effectId); 28739 boolean performHapticFeedback(int effectId, boolean always); 28740 } 28741 28742 /** 28743 * InvalidateInfo is used to post invalidate(int, int, int, int) messages 28744 * to a Handler. This class contains the target (View) to invalidate and 28745 * the coordinates of the dirty rectangle. 28746 * 28747 * For performance purposes, this class also implements a pool of up to 28748 * POOL_LIMIT objects that get reused. This reduces memory allocations 28749 * whenever possible. 28750 */ 28751 static class InvalidateInfo { 28752 28753 @UnsupportedAppUsage InvalidateInfo()28754 InvalidateInfo() { 28755 } 28756 28757 private static final int POOL_LIMIT = 10; 28758 28759 private static final SynchronizedPool<InvalidateInfo> sPool = 28760 new SynchronizedPool<InvalidateInfo>(POOL_LIMIT); 28761 28762 @UnsupportedAppUsage 28763 View target; 28764 28765 @UnsupportedAppUsage 28766 int left; 28767 @UnsupportedAppUsage 28768 int top; 28769 @UnsupportedAppUsage 28770 int right; 28771 @UnsupportedAppUsage 28772 int bottom; 28773 obtain()28774 public static InvalidateInfo obtain() { 28775 InvalidateInfo instance = sPool.acquire(); 28776 return (instance != null) ? instance : new InvalidateInfo(); 28777 } 28778 recycle()28779 public void recycle() { 28780 target = null; 28781 sPool.release(this); 28782 } 28783 } 28784 28785 @UnsupportedAppUsage 28786 final IWindowSession mSession; 28787 28788 @UnsupportedAppUsage 28789 final IWindow mWindow; 28790 28791 final IBinder mWindowToken; 28792 28793 Display mDisplay; 28794 28795 final Callbacks mRootCallbacks; 28796 28797 IWindowId mIWindowId; 28798 WindowId mWindowId; 28799 28800 /** 28801 * The top view of the hierarchy. 28802 */ 28803 View mRootView; 28804 28805 IBinder mPanelParentWindowToken; 28806 28807 boolean mHardwareAccelerated; 28808 boolean mHardwareAccelerationRequested; 28809 ThreadedRenderer mThreadedRenderer; 28810 List<RenderNode> mPendingAnimatingRenderNodes; 28811 28812 /** 28813 * The state of the display to which the window is attached, as reported 28814 * by {@link Display#getState()}. Note that the display state constants 28815 * declared by {@link Display} do not exactly line up with the screen state 28816 * constants declared by {@link View} (there are more display states than 28817 * screen states). 28818 */ 28819 @UnsupportedAppUsage 28820 int mDisplayState = Display.STATE_UNKNOWN; 28821 28822 /** 28823 * Scale factor used by the compatibility mode 28824 */ 28825 @UnsupportedAppUsage 28826 float mApplicationScale; 28827 28828 /** 28829 * Indicates whether the application is in compatibility mode 28830 */ 28831 @UnsupportedAppUsage 28832 boolean mScalingRequired; 28833 28834 /** 28835 * Left position of this view's window 28836 */ 28837 int mWindowLeft; 28838 28839 /** 28840 * Top position of this view's window 28841 */ 28842 int mWindowTop; 28843 28844 /** 28845 * Indicates whether views need to use 32-bit drawing caches 28846 */ 28847 boolean mUse32BitDrawingCache; 28848 28849 /** 28850 * For windows that are full-screen but using insets to layout inside 28851 * of the screen decorations, these are the current insets for the 28852 * content of the window. 28853 */ 28854 @UnsupportedAppUsage(maxTargetSdk = VERSION_CODES.Q, 28855 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 28856 final Rect mContentInsets = new Rect(); 28857 28858 /** 28859 * For windows that are full-screen but using insets to layout inside 28860 * of the screen decorations, these are the current insets for the 28861 * actual visible parts of the window. 28862 */ 28863 @UnsupportedAppUsage(maxTargetSdk = VERSION_CODES.Q, 28864 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 28865 final Rect mVisibleInsets = new Rect(); 28866 28867 /** 28868 * For windows that are full-screen but using insets to layout inside 28869 * of the screen decorations, these are the current insets for the 28870 * stable system windows. 28871 */ 28872 @UnsupportedAppUsage(maxTargetSdk = VERSION_CODES.Q, 28873 publicAlternatives = "Use {@link WindowInsets#getInsets(int)}") 28874 final Rect mStableInsets = new Rect(); 28875 28876 /** 28877 * Current caption insets to the display coordinate. 28878 */ 28879 final Rect mCaptionInsets = new Rect(); 28880 28881 final DisplayCutout.ParcelableWrapper mDisplayCutout = 28882 new DisplayCutout.ParcelableWrapper(DisplayCutout.NO_CUTOUT); 28883 28884 /** 28885 * In multi-window we force show the system bars. Because we don't want that the surface 28886 * size changes in this mode, we instead have a flag whether the system bars sizes should 28887 * always be consumed, so the app is treated like there are no virtual system bars at all. 28888 */ 28889 boolean mAlwaysConsumeSystemBars; 28890 28891 /** 28892 * The internal insets given by this window. This value is 28893 * supplied by the client (through 28894 * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will 28895 * be given to the window manager when changed to be used in laying 28896 * out windows behind it. 28897 */ 28898 @UnsupportedAppUsage 28899 final ViewTreeObserver.InternalInsetsInfo mGivenInternalInsets 28900 = new ViewTreeObserver.InternalInsetsInfo(); 28901 28902 /** 28903 * Set to true when mGivenInternalInsets is non-empty. 28904 */ 28905 boolean mHasNonEmptyGivenInternalInsets; 28906 28907 /** 28908 * All views in the window's hierarchy that serve as scroll containers, 28909 * used to determine if the window can be resized or must be panned 28910 * to adjust for a soft input area. 28911 */ 28912 @UnsupportedAppUsage 28913 final ArrayList<View> mScrollContainers = new ArrayList<View>(); 28914 28915 @UnsupportedAppUsage 28916 final KeyEvent.DispatcherState mKeyDispatchState 28917 = new KeyEvent.DispatcherState(); 28918 28919 /** 28920 * Indicates whether the view's window currently has the focus. 28921 */ 28922 @UnsupportedAppUsage 28923 boolean mHasWindowFocus; 28924 28925 /** 28926 * The current visibility of the window. 28927 */ 28928 int mWindowVisibility; 28929 28930 /** 28931 * Indicates the time at which drawing started to occur. 28932 */ 28933 @UnsupportedAppUsage 28934 long mDrawingTime; 28935 28936 /** 28937 * Indicates whether the view's window is currently in touch mode. 28938 */ 28939 @UnsupportedAppUsage 28940 boolean mInTouchMode; 28941 28942 /** 28943 * Indicates whether the view has requested unbuffered input dispatching for the current 28944 * event stream. 28945 */ 28946 boolean mUnbufferedDispatchRequested; 28947 28948 /** 28949 * Indicates that ViewAncestor should trigger a global layout change 28950 * the next time it performs a traversal 28951 */ 28952 @UnsupportedAppUsage 28953 boolean mRecomputeGlobalAttributes; 28954 28955 /** 28956 * Always report new attributes at next traversal. 28957 */ 28958 boolean mForceReportNewAttributes; 28959 28960 /** 28961 * Set during a traveral if any views want to keep the screen on. 28962 */ 28963 @UnsupportedAppUsage 28964 boolean mKeepScreenOn; 28965 28966 /** 28967 * Set during a traveral if the light center needs to be updated. 28968 */ 28969 boolean mNeedsUpdateLightCenter; 28970 28971 /** 28972 * Bitwise-or of all of the values that views have passed to setSystemUiVisibility(). 28973 */ 28974 int mSystemUiVisibility; 28975 28976 /** 28977 * Hack to force certain system UI visibility flags to be cleared. 28978 */ 28979 int mDisabledSystemUiVisibility; 28980 28981 /** 28982 * True if a view in this hierarchy has an OnSystemUiVisibilityChangeListener 28983 * attached. 28984 */ 28985 boolean mHasSystemUiListeners; 28986 28987 /** 28988 * Set if the visibility of any views has changed. 28989 */ 28990 @UnsupportedAppUsage 28991 boolean mViewVisibilityChanged; 28992 28993 /** 28994 * Set to true if a view has been scrolled. 28995 */ 28996 @UnsupportedAppUsage 28997 boolean mViewScrollChanged; 28998 28999 /** 29000 * Set to true if a pointer event is currently being handled. 29001 */ 29002 boolean mHandlingPointerEvent; 29003 29004 /** 29005 * The offset of this view's window when it's on an embedded display that is re-parented 29006 * to another window. 29007 */ 29008 final Point mLocationInParentDisplay = new Point(); 29009 29010 /** 29011 * The screen matrix of this view when it's on a {@link SurfaceControlViewHost} that is 29012 * embedded within a SurfaceView. 29013 */ 29014 Matrix mScreenMatrixInEmbeddedHierarchy; 29015 29016 /** 29017 * Global to the view hierarchy used as a temporary for dealing with 29018 * x/y points in the transparent region computations. 29019 */ 29020 final int[] mTransparentLocation = new int[2]; 29021 29022 /** 29023 * Global to the view hierarchy used as a temporary for dealing with 29024 * x/y points in the ViewGroup.invalidateChild implementation. 29025 */ 29026 final int[] mInvalidateChildLocation = new int[2]; 29027 29028 /** 29029 * Global to the view hierarchy used as a temporary for dealing with 29030 * computing absolute on-screen location. 29031 */ 29032 final int[] mTmpLocation = new int[2]; 29033 29034 /** 29035 * Global to the view hierarchy used as a temporary for dealing with 29036 * x/y location when view is transformed. 29037 */ 29038 final float[] mTmpTransformLocation = new float[2]; 29039 29040 /** 29041 * The view tree observer used to dispatch global events like 29042 * layout, pre-draw, touch mode change, etc. 29043 */ 29044 @UnsupportedAppUsage 29045 final ViewTreeObserver mTreeObserver; 29046 29047 /** 29048 * A Canvas used by the view hierarchy to perform bitmap caching. 29049 */ 29050 Canvas mCanvas; 29051 29052 /** 29053 * The view root impl. 29054 */ 29055 final ViewRootImpl mViewRootImpl; 29056 29057 /** 29058 * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This 29059 * handler can be used to pump events in the UI events queue. 29060 */ 29061 @UnsupportedAppUsage 29062 final Handler mHandler; 29063 29064 /** 29065 * Temporary for use in computing invalidate rectangles while 29066 * calling up the hierarchy. 29067 */ 29068 final Rect mTmpInvalRect = new Rect(); 29069 29070 /** 29071 * Temporary for use in computing hit areas with transformed views 29072 */ 29073 final RectF mTmpTransformRect = new RectF(); 29074 29075 /** 29076 * Temporary for use in computing hit areas with transformed views 29077 */ 29078 final RectF mTmpTransformRect1 = new RectF(); 29079 29080 /** 29081 * Temporary list of rectanges. 29082 */ 29083 final List<RectF> mTmpRectList = new ArrayList<>(); 29084 29085 /** 29086 * Temporary for use in transforming invalidation rect 29087 */ 29088 final Matrix mTmpMatrix = new Matrix(); 29089 29090 /** 29091 * Temporary for use in transforming invalidation rect 29092 */ 29093 final Transformation mTmpTransformation = new Transformation(); 29094 29095 /** 29096 * Temporary for use in querying outlines from OutlineProviders 29097 */ 29098 final Outline mTmpOutline = new Outline(); 29099 29100 /** 29101 * Temporary list for use in collecting focusable descendents of a view. 29102 */ 29103 final ArrayList<View> mTempArrayList = new ArrayList<View>(24); 29104 29105 /** 29106 * The id of the window for accessibility purposes. 29107 */ 29108 int mAccessibilityWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; 29109 29110 /** 29111 * Flags related to accessibility processing. 29112 * 29113 * @see AccessibilityNodeInfo#FLAG_INCLUDE_NOT_IMPORTANT_VIEWS 29114 * @see AccessibilityNodeInfo#FLAG_REPORT_VIEW_IDS 29115 */ 29116 int mAccessibilityFetchFlags; 29117 29118 /** 29119 * The drawable for highlighting accessibility focus. 29120 */ 29121 Drawable mAccessibilityFocusDrawable; 29122 29123 /** 29124 * The drawable for highlighting autofilled views. 29125 * 29126 * @see #isAutofilled() 29127 */ 29128 Drawable mAutofilledDrawable; 29129 29130 /** 29131 * Show where the margins, bounds and layout bounds are for each view. 29132 */ 29133 boolean mDebugLayout = DisplayProperties.debug_layout().orElse(false); 29134 29135 /** 29136 * Point used to compute visible regions. 29137 */ 29138 final Point mPoint = new Point(); 29139 29140 /** 29141 * Used to track which View originated a requestLayout() call, used when 29142 * requestLayout() is called during layout. 29143 */ 29144 View mViewRequestingLayout; 29145 29146 /** 29147 * Used to track the identity of the current drag operation. 29148 */ 29149 IBinder mDragToken; 29150 29151 /** 29152 * The drag shadow surface for the current drag operation. 29153 */ 29154 public Surface mDragSurface; 29155 29156 29157 /** 29158 * The view that currently has a tooltip displayed. 29159 */ 29160 View mTooltipHost; 29161 29162 /** 29163 * The initial structure has been reported so the view is ready to report updates. 29164 */ 29165 boolean mReadyForContentCaptureUpdates; 29166 29167 /** 29168 * Map(keyed by session) of content capture events that need to be notified after the view 29169 * hierarchy is traversed: value is either the view itself for appearead events, or its 29170 * autofill id for disappeared. 29171 */ 29172 SparseArray<ArrayList<Object>> mContentCaptureEvents; 29173 29174 /** 29175 * Cached reference to the {@link ContentCaptureManager}. 29176 */ 29177 ContentCaptureManager mContentCaptureManager; 29178 29179 /** 29180 * Listener used to fit content on window level. 29181 */ 29182 OnContentApplyWindowInsetsListener mContentOnApplyWindowInsetsListener; 29183 29184 /** 29185 * The leash token of this view's parent when it's in an embedded hierarchy that is 29186 * re-parented to another window. 29187 */ 29188 IBinder mLeashedParentToken; 29189 29190 /** 29191 * The accessibility view id of this view's parent when it's in an embedded 29192 * hierarchy that is re-parented to another window. 29193 */ 29194 int mLeashedParentAccessibilityViewId; 29195 29196 /** 29197 * 29198 */ 29199 ScrollCaptureInternal mScrollCaptureInternal; 29200 29201 /** 29202 * Creates a new set of attachment information with the specified 29203 * events handler and thread. 29204 * 29205 * @param handler the events handler the view must use 29206 */ AttachInfo(IWindowSession session, IWindow window, Display display, ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, Context context)29207 AttachInfo(IWindowSession session, IWindow window, Display display, 29208 ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer, 29209 Context context) { 29210 mSession = session; 29211 mWindow = window; 29212 mWindowToken = window.asBinder(); 29213 mDisplay = display; 29214 mViewRootImpl = viewRootImpl; 29215 mHandler = handler; 29216 mRootCallbacks = effectPlayer; 29217 mTreeObserver = new ViewTreeObserver(context); 29218 } 29219 29220 @Nullable getContentCaptureManager(@onNull Context context)29221 ContentCaptureManager getContentCaptureManager(@NonNull Context context) { 29222 if (mContentCaptureManager != null) { 29223 return mContentCaptureManager; 29224 } 29225 mContentCaptureManager = context.getSystemService(ContentCaptureManager.class); 29226 return mContentCaptureManager; 29227 } 29228 delayNotifyContentCaptureInsetsEvent(@onNull Insets insets)29229 void delayNotifyContentCaptureInsetsEvent(@NonNull Insets insets) { 29230 if (mContentCaptureManager == null) { 29231 return; 29232 } 29233 29234 ArrayList<Object> events = ensureEvents( 29235 mContentCaptureManager.getMainContentCaptureSession()); 29236 events.add(insets); 29237 } 29238 delayNotifyContentCaptureEvent(@onNull ContentCaptureSession session, @NonNull View view, boolean appeared)29239 private void delayNotifyContentCaptureEvent(@NonNull ContentCaptureSession session, 29240 @NonNull View view, boolean appeared) { 29241 ArrayList<Object> events = ensureEvents(session); 29242 events.add(appeared ? view : view.getAutofillId()); 29243 } 29244 29245 @NonNull ensureEvents(@onNull ContentCaptureSession session)29246 private ArrayList<Object> ensureEvents(@NonNull ContentCaptureSession session) { 29247 if (mContentCaptureEvents == null) { 29248 // Most of the time there will be just one session, so intial capacity is 1 29249 mContentCaptureEvents = new SparseArray<>(1); 29250 } 29251 int sessionId = session.getId(); 29252 // TODO: life would be much easier if we provided a MultiMap implementation somwhere... 29253 ArrayList<Object> events = mContentCaptureEvents.get(sessionId); 29254 if (events == null) { 29255 events = new ArrayList<>(); 29256 mContentCaptureEvents.put(sessionId, events); 29257 } 29258 29259 return events; 29260 } 29261 29262 @Nullable getScrollCaptureInternal()29263 ScrollCaptureInternal getScrollCaptureInternal() { 29264 if (mScrollCaptureInternal != null) { 29265 mScrollCaptureInternal = new ScrollCaptureInternal(); 29266 } 29267 return mScrollCaptureInternal; 29268 } 29269 } 29270 29271 /** 29272 * <p>ScrollabilityCache holds various fields used by a View when scrolling 29273 * is supported. This avoids keeping too many unused fields in most 29274 * instances of View.</p> 29275 */ 29276 private static class ScrollabilityCache implements Runnable { 29277 29278 /** 29279 * Scrollbars are not visible 29280 */ 29281 public static final int OFF = 0; 29282 29283 /** 29284 * Scrollbars are visible 29285 */ 29286 public static final int ON = 1; 29287 29288 /** 29289 * Scrollbars are fading away 29290 */ 29291 public static final int FADING = 2; 29292 29293 public boolean fadeScrollBars; 29294 29295 public int fadingEdgeLength; 29296 public int scrollBarDefaultDelayBeforeFade; 29297 public int scrollBarFadeDuration; 29298 29299 public int scrollBarSize; 29300 public int scrollBarMinTouchTarget; 29301 @UnsupportedAppUsage 29302 public ScrollBarDrawable scrollBar; 29303 public float[] interpolatorValues; 29304 @UnsupportedAppUsage 29305 public View host; 29306 29307 public final Paint paint; 29308 public final Matrix matrix; 29309 public Shader shader; 29310 29311 public final Interpolator scrollBarInterpolator = new Interpolator(1, 2); 29312 29313 private static final float[] OPAQUE = { 255 }; 29314 private static final float[] TRANSPARENT = { 0.0f }; 29315 29316 /** 29317 * When fading should start. This time moves into the future every time 29318 * a new scroll happens. Measured based on SystemClock.uptimeMillis() 29319 */ 29320 public long fadeStartTime; 29321 29322 29323 /** 29324 * The current state of the scrollbars: ON, OFF, or FADING 29325 */ 29326 @UnsupportedAppUsage 29327 public int state = OFF; 29328 29329 private int mLastColor; 29330 29331 public final Rect mScrollBarBounds = new Rect(); 29332 public final Rect mScrollBarTouchBounds = new Rect(); 29333 29334 public static final int NOT_DRAGGING = 0; 29335 public static final int DRAGGING_VERTICAL_SCROLL_BAR = 1; 29336 public static final int DRAGGING_HORIZONTAL_SCROLL_BAR = 2; 29337 public int mScrollBarDraggingState = NOT_DRAGGING; 29338 29339 public float mScrollBarDraggingPos = 0; 29340 ScrollabilityCache(ViewConfiguration configuration, View host)29341 public ScrollabilityCache(ViewConfiguration configuration, View host) { 29342 fadingEdgeLength = configuration.getScaledFadingEdgeLength(); 29343 scrollBarSize = configuration.getScaledScrollBarSize(); 29344 scrollBarMinTouchTarget = configuration.getScaledMinScrollbarTouchTarget(); 29345 scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay(); 29346 scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration(); 29347 29348 paint = new Paint(); 29349 matrix = new Matrix(); 29350 // use use a height of 1, and then wack the matrix each time we 29351 // actually use it. 29352 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 29353 paint.setShader(shader); 29354 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 29355 29356 this.host = host; 29357 } 29358 setFadeColor(int color)29359 public void setFadeColor(int color) { 29360 if (color != mLastColor) { 29361 mLastColor = color; 29362 29363 if (color != 0) { 29364 shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000, 29365 color & 0x00FFFFFF, Shader.TileMode.CLAMP); 29366 paint.setShader(shader); 29367 // Restore the default transfer mode (src_over) 29368 paint.setXfermode(null); 29369 } else { 29370 shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP); 29371 paint.setShader(shader); 29372 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); 29373 } 29374 } 29375 } 29376 run()29377 public void run() { 29378 long now = AnimationUtils.currentAnimationTimeMillis(); 29379 if (now >= fadeStartTime) { 29380 29381 // the animation fades the scrollbars out by changing 29382 // the opacity (alpha) from fully opaque to fully 29383 // transparent 29384 int nextFrame = (int) now; 29385 int framesCount = 0; 29386 29387 Interpolator interpolator = scrollBarInterpolator; 29388 29389 // Start opaque 29390 interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE); 29391 29392 // End transparent 29393 nextFrame += scrollBarFadeDuration; 29394 interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT); 29395 29396 state = FADING; 29397 29398 // Kick off the fade animation 29399 host.invalidate(true); 29400 } 29401 } 29402 } 29403 29404 private class SendAccessibilityEventThrottle implements Runnable { 29405 public volatile boolean mIsPending; 29406 private AccessibilityEvent mAccessibilityEvent; 29407 post(AccessibilityEvent accessibilityEvent)29408 public void post(AccessibilityEvent accessibilityEvent) { 29409 updateWithAccessibilityEvent(accessibilityEvent); 29410 if (!mIsPending) { 29411 mIsPending = true; 29412 postDelayed(this, 29413 ViewConfiguration.getSendRecurringAccessibilityEventsInterval()); 29414 } 29415 } 29416 29417 @Override run()29418 public void run() { 29419 if (AccessibilityManager.getInstance(mContext).isEnabled()) { 29420 requestParentSendAccessibilityEvent(mAccessibilityEvent); 29421 } 29422 reset(); 29423 } 29424 updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent)29425 public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { 29426 mAccessibilityEvent = accessibilityEvent; 29427 } 29428 reset()29429 public void reset() { 29430 mIsPending = false; 29431 mAccessibilityEvent = null; 29432 } 29433 29434 } 29435 29436 /** 29437 * Resuable callback for sending 29438 * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} accessibility event. 29439 */ 29440 private class SendViewScrolledAccessibilityEvent extends SendAccessibilityEventThrottle { 29441 public int mDeltaX; 29442 public int mDeltaY; 29443 29444 @Override updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent)29445 public void updateWithAccessibilityEvent(AccessibilityEvent accessibilityEvent) { 29446 super.updateWithAccessibilityEvent(accessibilityEvent); 29447 mDeltaX += accessibilityEvent.getScrollDeltaX(); 29448 mDeltaY += accessibilityEvent.getScrollDeltaY(); 29449 accessibilityEvent.setScrollDeltaX(mDeltaX); 29450 accessibilityEvent.setScrollDeltaY(mDeltaY); 29451 } 29452 29453 @Override reset()29454 public void reset() { 29455 super.reset(); 29456 mDeltaX = 0; 29457 mDeltaY = 0; 29458 } 29459 } 29460 /** 29461 * Remove the pending callback for sending a throttled accessibility event. 29462 */ 29463 @UnsupportedAppUsage cancel(@ullable SendAccessibilityEventThrottle callback)29464 private void cancel(@Nullable SendAccessibilityEventThrottle callback) { 29465 if (callback == null || !callback.mIsPending) return; 29466 removeCallbacks(callback); 29467 callback.reset(); 29468 } 29469 29470 /** 29471 * <p> 29472 * This class represents a delegate that can be registered in a {@link View} 29473 * to enhance accessibility support via composition rather via inheritance. 29474 * It is specifically targeted to widget developers that extend basic View 29475 * classes i.e. classes in package android.view, that would like their 29476 * applications to be backwards compatible. 29477 * </p> 29478 * <div class="special reference"> 29479 * <h3>Developer Guides</h3> 29480 * <p>For more information about making applications accessible, read the 29481 * <a href="{@docRoot}guide/topics/ui/accessibility/index.html">Accessibility</a> 29482 * developer guide.</p> 29483 * </div> 29484 * <p> 29485 * A scenario in which a developer would like to use an accessibility delegate 29486 * is overriding a method introduced in a later API version than the minimal API 29487 * version supported by the application. For example, the method 29488 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} is not available 29489 * in API version 4 when the accessibility APIs were first introduced. If a 29490 * developer would like their application to run on API version 4 devices (assuming 29491 * all other APIs used by the application are version 4 or lower) and take advantage 29492 * of this method, instead of overriding the method which would break the application's 29493 * backwards compatibility, they can override the corresponding method in this 29494 * delegate and register the delegate in the target View if the API version of 29495 * the system is high enough, i.e. the API version is the same as or higher than the API 29496 * version that introduced 29497 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)}. 29498 * </p> 29499 * <p> 29500 * Here is an example implementation: 29501 * </p> 29502 * <code><pre><p> 29503 * if (Build.VERSION.SDK_INT >= 14) { 29504 * // If the API version is equal of higher than the version in 29505 * // which onInitializeAccessibilityNodeInfo was introduced we 29506 * // register a delegate with a customized implementation. 29507 * View view = findViewById(R.id.view_id); 29508 * view.setAccessibilityDelegate(new AccessibilityDelegate() { 29509 * public void onInitializeAccessibilityNodeInfo(View host, 29510 * AccessibilityNodeInfo info) { 29511 * // Let the default implementation populate the info. 29512 * super.onInitializeAccessibilityNodeInfo(host, info); 29513 * // Set some other information. 29514 * info.setEnabled(host.isEnabled()); 29515 * } 29516 * }); 29517 * } 29518 * </code></pre></p> 29519 * <p> 29520 * This delegate contains methods that correspond to the accessibility methods 29521 * in View. If a delegate has been specified the implementation in View hands 29522 * off handling to the corresponding method in this delegate. The default 29523 * implementation the delegate methods behaves exactly as the corresponding 29524 * method in View for the case of no accessibility delegate been set. Hence, 29525 * to customize the behavior of a View method, clients can override only the 29526 * corresponding delegate method without altering the behavior of the rest 29527 * accessibility related methods of the host view. 29528 * </p> 29529 * <p> 29530 * <strong>Note:</strong> On platform versions prior to 29531 * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on 29532 * views in the {@code android.widget.*} package are called <i>before</i> 29533 * host methods. This prevents certain properties such as class name from 29534 * being modified by overriding 29535 * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)}, 29536 * as any changes will be overwritten by the host class. 29537 * <p> 29538 * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate 29539 * methods are called <i>after</i> host methods, which all properties to be 29540 * modified without being overwritten by the host class. 29541 */ 29542 public static class AccessibilityDelegate { 29543 29544 /** 29545 * Sends an accessibility event of the given type. If accessibility is not 29546 * enabled this method has no effect. 29547 * <p> 29548 * The default implementation behaves as {@link View#sendAccessibilityEvent(int) 29549 * View#sendAccessibilityEvent(int)} for the case of no accessibility delegate 29550 * been set. 29551 * </p> 29552 * 29553 * @param host The View hosting the delegate. 29554 * @param eventType The type of the event to send. 29555 * 29556 * @see View#sendAccessibilityEvent(int) View#sendAccessibilityEvent(int) 29557 */ sendAccessibilityEvent(View host, int eventType)29558 public void sendAccessibilityEvent(View host, int eventType) { 29559 host.sendAccessibilityEventInternal(eventType); 29560 } 29561 29562 /** 29563 * Performs the specified accessibility action on the view. For 29564 * possible accessibility actions look at {@link AccessibilityNodeInfo}. 29565 * <p> 29566 * The default implementation behaves as 29567 * {@link View#performAccessibilityAction(int, Bundle) 29568 * View#performAccessibilityAction(int, Bundle)} for the case of 29569 * no accessibility delegate been set. 29570 * </p> 29571 * 29572 * @param action The action to perform. 29573 * @return Whether the action was performed. 29574 * 29575 * @see View#performAccessibilityAction(int, Bundle) 29576 * View#performAccessibilityAction(int, Bundle) 29577 */ performAccessibilityAction(View host, int action, Bundle args)29578 public boolean performAccessibilityAction(View host, int action, Bundle args) { 29579 return host.performAccessibilityActionInternal(action, args); 29580 } 29581 29582 /** 29583 * Sends an accessibility event. This method behaves exactly as 29584 * {@link #sendAccessibilityEvent(View, int)} but takes as an argument an 29585 * empty {@link AccessibilityEvent} and does not perform a check whether 29586 * accessibility is enabled. 29587 * <p> 29588 * The default implementation behaves as 29589 * {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent) 29590 * View#sendAccessibilityEventUnchecked(AccessibilityEvent)} for 29591 * the case of no accessibility delegate been set. 29592 * </p> 29593 * 29594 * @param host The View hosting the delegate. 29595 * @param event The event to send. 29596 * 29597 * @see View#sendAccessibilityEventUnchecked(AccessibilityEvent) 29598 * View#sendAccessibilityEventUnchecked(AccessibilityEvent) 29599 */ sendAccessibilityEventUnchecked(View host, AccessibilityEvent event)29600 public void sendAccessibilityEventUnchecked(View host, AccessibilityEvent event) { 29601 host.sendAccessibilityEventUncheckedInternal(event); 29602 } 29603 29604 /** 29605 * Dispatches an {@link AccessibilityEvent} to the host {@link View} first and then 29606 * to its children for adding their text content to the event. 29607 * <p> 29608 * The default implementation behaves as 29609 * {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 29610 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)} for 29611 * the case of no accessibility delegate been set. 29612 * </p> 29613 * 29614 * @param host The View hosting the delegate. 29615 * @param event The event. 29616 * @return True if the event population was completed. 29617 * 29618 * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 29619 * View#dispatchPopulateAccessibilityEvent(AccessibilityEvent) 29620 */ dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event)29621 public boolean dispatchPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 29622 return host.dispatchPopulateAccessibilityEventInternal(event); 29623 } 29624 29625 /** 29626 * Gives a chance to the host View to populate the accessibility event with its 29627 * text content. 29628 * <p> 29629 * The default implementation behaves as 29630 * {@link View#onPopulateAccessibilityEvent(AccessibilityEvent) 29631 * View#onPopulateAccessibilityEvent(AccessibilityEvent)} for 29632 * the case of no accessibility delegate been set. 29633 * </p> 29634 * 29635 * @param host The View hosting the delegate. 29636 * @param event The accessibility event which to populate. 29637 * 29638 * @see View#onPopulateAccessibilityEvent(AccessibilityEvent) 29639 * View#onPopulateAccessibilityEvent(AccessibilityEvent) 29640 */ onPopulateAccessibilityEvent(View host, AccessibilityEvent event)29641 public void onPopulateAccessibilityEvent(View host, AccessibilityEvent event) { 29642 host.onPopulateAccessibilityEventInternal(event); 29643 } 29644 29645 /** 29646 * Initializes an {@link AccessibilityEvent} with information about the 29647 * the host View which is the event source. 29648 * <p> 29649 * The default implementation behaves as 29650 * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent) 29651 * View#onInitializeAccessibilityEvent(AccessibilityEvent)} for 29652 * the case of no accessibility delegate been set. 29653 * </p> 29654 * 29655 * @param host The View hosting the delegate. 29656 * @param event The event to initialize. 29657 * 29658 * @see View#onInitializeAccessibilityEvent(AccessibilityEvent) 29659 * View#onInitializeAccessibilityEvent(AccessibilityEvent) 29660 */ onInitializeAccessibilityEvent(View host, AccessibilityEvent event)29661 public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { 29662 host.onInitializeAccessibilityEventInternal(event); 29663 } 29664 29665 /** 29666 * Initializes an {@link AccessibilityNodeInfo} with information about the host view. 29667 * <p> 29668 * The default implementation behaves as 29669 * {@link View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 29670 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} for 29671 * the case of no accessibility delegate been set. 29672 * </p> 29673 * 29674 * @param host The View hosting the delegate. 29675 * @param info The instance to initialize. 29676 * 29677 * @see View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 29678 * View#onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo) 29679 */ onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info)29680 public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { 29681 host.onInitializeAccessibilityNodeInfoInternal(info); 29682 } 29683 29684 /** 29685 * Adds extra data to an {@link AccessibilityNodeInfo} based on an explicit request for the 29686 * additional data. 29687 * <p> 29688 * This method only needs to be implemented if the View offers to provide additional data. 29689 * </p> 29690 * <p> 29691 * The default implementation behaves as 29692 * {@link View#addExtraDataToAccessibilityNodeInfo(AccessibilityNodeInfo, String, Bundle) 29693 * for the case where no accessibility delegate is set. 29694 * </p> 29695 * 29696 * @param host The View hosting the delegate. Never {@code null}. 29697 * @param info The info to which to add the extra data. Never {@code null}. 29698 * @param extraDataKey A key specifying the type of extra data to add to the info. The 29699 * extra data should be added to the {@link Bundle} returned by 29700 * the info's {@link AccessibilityNodeInfo#getExtras} method. Never 29701 * {@code null}. 29702 * @param arguments A {@link Bundle} holding any arguments relevant for this request. 29703 * May be {@code null} if the if the service provided no arguments. 29704 * 29705 * @see AccessibilityNodeInfo#setAvailableExtraData(List) 29706 */ addExtraDataToAccessibilityNodeInfo(@onNull View host, @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, @Nullable Bundle arguments)29707 public void addExtraDataToAccessibilityNodeInfo(@NonNull View host, 29708 @NonNull AccessibilityNodeInfo info, @NonNull String extraDataKey, 29709 @Nullable Bundle arguments) { 29710 host.addExtraDataToAccessibilityNodeInfo(info, extraDataKey, arguments); 29711 } 29712 29713 /** 29714 * Called when a child of the host View has requested sending an 29715 * {@link AccessibilityEvent} and gives an opportunity to the parent (the host) 29716 * to augment the event. 29717 * <p> 29718 * The default implementation behaves as 29719 * {@link ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 29720 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent)} for 29721 * the case of no accessibility delegate been set. 29722 * </p> 29723 * 29724 * @param host The View hosting the delegate. 29725 * @param child The child which requests sending the event. 29726 * @param event The event to be sent. 29727 * @return True if the event should be sent 29728 * 29729 * @see ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 29730 * ViewGroup#onRequestSendAccessibilityEvent(View, AccessibilityEvent) 29731 */ onRequestSendAccessibilityEvent(ViewGroup host, View child, AccessibilityEvent event)29732 public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child, 29733 AccessibilityEvent event) { 29734 return host.onRequestSendAccessibilityEventInternal(child, event); 29735 } 29736 29737 /** 29738 * Gets the provider for managing a virtual view hierarchy rooted at this View 29739 * and reported to {@link android.accessibilityservice.AccessibilityService}s 29740 * that explore the window content. 29741 * <p> 29742 * The default implementation behaves as 29743 * {@link View#getAccessibilityNodeProvider() View#getAccessibilityNodeProvider()} for 29744 * the case of no accessibility delegate been set. 29745 * </p> 29746 * 29747 * @return The provider. 29748 * 29749 * @see AccessibilityNodeProvider 29750 */ getAccessibilityNodeProvider(View host)29751 public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { 29752 return null; 29753 } 29754 29755 /** 29756 * Returns an {@link AccessibilityNodeInfo} representing the host view from the 29757 * point of view of an {@link android.accessibilityservice.AccessibilityService}. 29758 * This method is responsible for obtaining an accessibility node info from a 29759 * pool of reusable instances and calling 29760 * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host 29761 * view to initialize the former. 29762 * <p> 29763 * <strong>Note:</strong> The client is responsible for recycling the obtained 29764 * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object 29765 * creation. 29766 * </p> 29767 * <p> 29768 * The default implementation behaves as 29769 * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for 29770 * the case of no accessibility delegate been set. 29771 * </p> 29772 * @return A populated {@link AccessibilityNodeInfo}. 29773 * 29774 * @see AccessibilityNodeInfo 29775 * 29776 * @hide 29777 */ 29778 @UnsupportedAppUsage createAccessibilityNodeInfo(View host)29779 public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { 29780 return host.createAccessibilityNodeInfoInternal(); 29781 } 29782 } 29783 29784 private static class MatchIdPredicate implements Predicate<View> { 29785 public int mId; 29786 29787 @Override test(View view)29788 public boolean test(View view) { 29789 return (view.mID == mId); 29790 } 29791 } 29792 29793 private static class MatchLabelForPredicate implements Predicate<View> { 29794 private int mLabeledId; 29795 29796 @Override test(View view)29797 public boolean test(View view) { 29798 return (view.mLabelForId == mLabeledId); 29799 } 29800 } 29801 29802 29803 /** 29804 * Returns the current scroll capture hint for this view. 29805 * 29806 * @return the current scroll capture hint 29807 * 29808 * @hide 29809 */ 29810 @ScrollCaptureHint getScrollCaptureHint()29811 public int getScrollCaptureHint() { 29812 return (mPrivateFlags4 & PFLAG4_SCROLL_CAPTURE_HINT_MASK) 29813 >> PFLAG4_SCROLL_CAPTURE_HINT_SHIFT; 29814 } 29815 29816 /** 29817 * Sets the scroll capture hint for this View. These flags affect the search for a potential 29818 * scroll capture targets. 29819 * 29820 * @param hint the scrollCaptureHint flags value to set 29821 * 29822 * @hide 29823 */ setScrollCaptureHint(@crollCaptureHint int hint)29824 public void setScrollCaptureHint(@ScrollCaptureHint int hint) { 29825 mPrivateFlags4 &= ~PFLAG4_SCROLL_CAPTURE_HINT_MASK; 29826 mPrivateFlags4 |= ((hint << PFLAG4_SCROLL_CAPTURE_HINT_SHIFT) 29827 & PFLAG4_SCROLL_CAPTURE_HINT_MASK); 29828 } 29829 29830 /** 29831 * Sets the callback to receive scroll capture requests. This component is the adapter between 29832 * the scroll capture API and application UI code. If no callback is set, the system may provide 29833 * an implementation. Any value provided here will take precedence over a system version. 29834 * <p> 29835 * This view will be ignored when {@link #SCROLL_CAPTURE_HINT_EXCLUDE} is set in its {@link 29836 * #setScrollCaptureHint(int) scrollCaptureHint}, regardless whether a callback has been set. 29837 * <p> 29838 * It is recommended to set the scroll capture hint {@link #SCROLL_CAPTURE_HINT_INCLUDE} when 29839 * setting a custom callback to help ensure it is selected as the target. 29840 * 29841 * @param callback the new callback to assign 29842 * 29843 * @hide 29844 */ setScrollCaptureCallback(@ullable ScrollCaptureCallback callback)29845 public void setScrollCaptureCallback(@Nullable ScrollCaptureCallback callback) { 29846 getListenerInfo().mScrollCaptureCallback = callback; 29847 } 29848 29849 /** {@hide} */ 29850 @Nullable createScrollCaptureCallbackInternal(@onNull Rect localVisibleRect, @NonNull Point windowOffset)29851 public ScrollCaptureCallback createScrollCaptureCallbackInternal(@NonNull Rect localVisibleRect, 29852 @NonNull Point windowOffset) { 29853 if (mAttachInfo == null) { 29854 return null; 29855 } 29856 if (mAttachInfo.mScrollCaptureInternal == null) { 29857 mAttachInfo.mScrollCaptureInternal = new ScrollCaptureInternal(); 29858 } 29859 return mAttachInfo.mScrollCaptureInternal.requestCallback(this, localVisibleRect, 29860 windowOffset); 29861 } 29862 29863 /** 29864 * Called when scroll capture is requested, to search for appropriate content to scroll. If 29865 * applicable, this view adds itself to the provided list for consideration, subject to the 29866 * flags set by {@link #setScrollCaptureHint}. 29867 * 29868 * @param localVisibleRect the local visible rect of this view 29869 * @param windowOffset the offset of localVisibleRect within the window 29870 * @param targets a queue which collects potential targets 29871 * 29872 * @throws IllegalStateException if this view is not attached to a window 29873 * @hide 29874 */ dispatchScrollCaptureSearch(@onNull Rect localVisibleRect, @NonNull Point windowOffset, @NonNull Queue<ScrollCaptureTarget> targets)29875 public void dispatchScrollCaptureSearch(@NonNull Rect localVisibleRect, 29876 @NonNull Point windowOffset, @NonNull Queue<ScrollCaptureTarget> targets) { 29877 int hint = getScrollCaptureHint(); 29878 if ((hint & SCROLL_CAPTURE_HINT_EXCLUDE) != 0) { 29879 return; 29880 } 29881 29882 // Get a callback provided by the framework, library or application. 29883 ScrollCaptureCallback callback = 29884 (mListenerInfo == null) ? null : mListenerInfo.mScrollCaptureCallback; 29885 29886 // Try internal support for standard scrolling containers. 29887 if (callback == null) { 29888 callback = createScrollCaptureCallbackInternal(localVisibleRect, windowOffset); 29889 } 29890 29891 // If found, then add it to the list. 29892 if (callback != null) { 29893 // Add to the list for consideration 29894 Point offset = new Point(windowOffset.x, windowOffset.y); 29895 Rect rect = new Rect(localVisibleRect); 29896 targets.add(new ScrollCaptureTarget(this, rect, offset, callback)); 29897 } 29898 } 29899 29900 /** 29901 * Dump all private flags in readable format, useful for documentation and 29902 * sanity checking. 29903 */ dumpFlags()29904 private static void dumpFlags() { 29905 final HashMap<String, String> found = Maps.newHashMap(); 29906 try { 29907 for (Field field : View.class.getDeclaredFields()) { 29908 final int modifiers = field.getModifiers(); 29909 if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) { 29910 if (field.getType().equals(int.class)) { 29911 final int value = field.getInt(null); 29912 dumpFlag(found, field.getName(), value); 29913 } else if (field.getType().equals(int[].class)) { 29914 final int[] values = (int[]) field.get(null); 29915 for (int i = 0; i < values.length; i++) { 29916 dumpFlag(found, field.getName() + "[" + i + "]", values[i]); 29917 } 29918 } 29919 } 29920 } 29921 } catch (IllegalAccessException e) { 29922 throw new RuntimeException(e); 29923 } 29924 29925 final ArrayList<String> keys = Lists.newArrayList(); 29926 keys.addAll(found.keySet()); 29927 Collections.sort(keys); 29928 for (String key : keys) { 29929 Log.d(VIEW_LOG_TAG, found.get(key)); 29930 } 29931 } 29932 dumpFlag(HashMap<String, String> found, String name, int value)29933 private static void dumpFlag(HashMap<String, String> found, String name, int value) { 29934 // Sort flags by prefix, then by bits, always keeping unique keys 29935 final String bits = String.format("%32s", Integer.toBinaryString(value)).replace('0', ' '); 29936 final int prefix = name.indexOf('_'); 29937 final String key = (prefix > 0 ? name.substring(0, prefix) : name) + bits + name; 29938 final String output = bits + " " + name; 29939 found.put(key, output); 29940 } 29941 29942 /** {@hide} */ encode(@onNull ViewHierarchyEncoder stream)29943 public void encode(@NonNull ViewHierarchyEncoder stream) { 29944 stream.beginObject(this); 29945 encodeProperties(stream); 29946 stream.endObject(); 29947 } 29948 29949 /** {@hide} */ 29950 @CallSuper encodeProperties(@onNull ViewHierarchyEncoder stream)29951 protected void encodeProperties(@NonNull ViewHierarchyEncoder stream) { 29952 Object resolveId = ViewDebug.resolveId(getContext(), mID); 29953 if (resolveId instanceof String) { 29954 stream.addProperty("id", (String) resolveId); 29955 } else { 29956 stream.addProperty("id", mID); 29957 } 29958 29959 stream.addProperty("misc:transformation.alpha", 29960 mTransformationInfo != null ? mTransformationInfo.mAlpha : 0); 29961 stream.addProperty("misc:transitionName", getTransitionName()); 29962 29963 // layout 29964 stream.addProperty("layout:left", mLeft); 29965 stream.addProperty("layout:right", mRight); 29966 stream.addProperty("layout:top", mTop); 29967 stream.addProperty("layout:bottom", mBottom); 29968 stream.addProperty("layout:width", getWidth()); 29969 stream.addProperty("layout:height", getHeight()); 29970 stream.addProperty("layout:layoutDirection", getLayoutDirection()); 29971 stream.addProperty("layout:layoutRtl", isLayoutRtl()); 29972 stream.addProperty("layout:hasTransientState", hasTransientState()); 29973 stream.addProperty("layout:baseline", getBaseline()); 29974 29975 // layout params 29976 ViewGroup.LayoutParams layoutParams = getLayoutParams(); 29977 if (layoutParams != null) { 29978 stream.addPropertyKey("layoutParams"); 29979 layoutParams.encode(stream); 29980 } 29981 29982 // scrolling 29983 stream.addProperty("scrolling:scrollX", mScrollX); 29984 stream.addProperty("scrolling:scrollY", mScrollY); 29985 29986 // padding 29987 stream.addProperty("padding:paddingLeft", mPaddingLeft); 29988 stream.addProperty("padding:paddingRight", mPaddingRight); 29989 stream.addProperty("padding:paddingTop", mPaddingTop); 29990 stream.addProperty("padding:paddingBottom", mPaddingBottom); 29991 stream.addProperty("padding:userPaddingRight", mUserPaddingRight); 29992 stream.addProperty("padding:userPaddingLeft", mUserPaddingLeft); 29993 stream.addProperty("padding:userPaddingBottom", mUserPaddingBottom); 29994 stream.addProperty("padding:userPaddingStart", mUserPaddingStart); 29995 stream.addProperty("padding:userPaddingEnd", mUserPaddingEnd); 29996 29997 // measurement 29998 stream.addProperty("measurement:minHeight", mMinHeight); 29999 stream.addProperty("measurement:minWidth", mMinWidth); 30000 stream.addProperty("measurement:measuredWidth", mMeasuredWidth); 30001 stream.addProperty("measurement:measuredHeight", mMeasuredHeight); 30002 30003 // drawing 30004 stream.addProperty("drawing:elevation", getElevation()); 30005 stream.addProperty("drawing:translationX", getTranslationX()); 30006 stream.addProperty("drawing:translationY", getTranslationY()); 30007 stream.addProperty("drawing:translationZ", getTranslationZ()); 30008 stream.addProperty("drawing:rotation", getRotation()); 30009 stream.addProperty("drawing:rotationX", getRotationX()); 30010 stream.addProperty("drawing:rotationY", getRotationY()); 30011 stream.addProperty("drawing:scaleX", getScaleX()); 30012 stream.addProperty("drawing:scaleY", getScaleY()); 30013 stream.addProperty("drawing:pivotX", getPivotX()); 30014 stream.addProperty("drawing:pivotY", getPivotY()); 30015 stream.addProperty("drawing:clipBounds", 30016 mClipBounds == null ? null : mClipBounds.toString()); 30017 stream.addProperty("drawing:opaque", isOpaque()); 30018 stream.addProperty("drawing:alpha", getAlpha()); 30019 stream.addProperty("drawing:transitionAlpha", getTransitionAlpha()); 30020 stream.addProperty("drawing:shadow", hasShadow()); 30021 stream.addProperty("drawing:solidColor", getSolidColor()); 30022 stream.addProperty("drawing:layerType", mLayerType); 30023 stream.addProperty("drawing:willNotDraw", willNotDraw()); 30024 stream.addProperty("drawing:hardwareAccelerated", isHardwareAccelerated()); 30025 stream.addProperty("drawing:willNotCacheDrawing", willNotCacheDrawing()); 30026 stream.addProperty("drawing:drawingCacheEnabled", isDrawingCacheEnabled()); 30027 stream.addProperty("drawing:overlappingRendering", hasOverlappingRendering()); 30028 stream.addProperty("drawing:outlineAmbientShadowColor", getOutlineAmbientShadowColor()); 30029 stream.addProperty("drawing:outlineSpotShadowColor", getOutlineSpotShadowColor()); 30030 30031 // focus 30032 stream.addProperty("focus:hasFocus", hasFocus()); 30033 stream.addProperty("focus:isFocused", isFocused()); 30034 stream.addProperty("focus:focusable", getFocusable()); 30035 stream.addProperty("focus:isFocusable", isFocusable()); 30036 stream.addProperty("focus:isFocusableInTouchMode", isFocusableInTouchMode()); 30037 30038 stream.addProperty("misc:clickable", isClickable()); 30039 stream.addProperty("misc:pressed", isPressed()); 30040 stream.addProperty("misc:selected", isSelected()); 30041 stream.addProperty("misc:touchMode", isInTouchMode()); 30042 stream.addProperty("misc:hovered", isHovered()); 30043 stream.addProperty("misc:activated", isActivated()); 30044 30045 stream.addProperty("misc:visibility", getVisibility()); 30046 stream.addProperty("misc:fitsSystemWindows", getFitsSystemWindows()); 30047 stream.addProperty("misc:filterTouchesWhenObscured", getFilterTouchesWhenObscured()); 30048 30049 stream.addProperty("misc:enabled", isEnabled()); 30050 stream.addProperty("misc:soundEffectsEnabled", isSoundEffectsEnabled()); 30051 stream.addProperty("misc:hapticFeedbackEnabled", isHapticFeedbackEnabled()); 30052 30053 // theme attributes 30054 Resources.Theme theme = getContext().getTheme(); 30055 if (theme != null) { 30056 stream.addPropertyKey("theme"); 30057 theme.encode(stream); 30058 } 30059 30060 // view attribute information 30061 int n = mAttributes != null ? mAttributes.length : 0; 30062 stream.addProperty("meta:__attrCount__", n/2); 30063 for (int i = 0; i < n; i += 2) { 30064 stream.addProperty("meta:__attr__" + mAttributes[i], mAttributes[i+1]); 30065 } 30066 30067 stream.addProperty("misc:scrollBarStyle", getScrollBarStyle()); 30068 30069 // text 30070 stream.addProperty("text:textDirection", getTextDirection()); 30071 stream.addProperty("text:textAlignment", getTextAlignment()); 30072 30073 // accessibility 30074 CharSequence contentDescription = getContentDescription(); 30075 stream.addUserProperty("accessibility:contentDescription", 30076 contentDescription == null ? "" : contentDescription.toString()); 30077 stream.addProperty("accessibility:labelFor", getLabelFor()); 30078 stream.addProperty("accessibility:importantForAccessibility", getImportantForAccessibility()); 30079 } 30080 30081 /** 30082 * Determine if this view is rendered on a round wearable device and is the main view 30083 * on the screen. 30084 */ shouldDrawRoundScrollbar()30085 boolean shouldDrawRoundScrollbar() { 30086 if (!mResources.getConfiguration().isScreenRound() || mAttachInfo == null) { 30087 return false; 30088 } 30089 30090 final View rootView = getRootView(); 30091 final WindowInsets insets = getRootWindowInsets(); 30092 30093 int height = getHeight(); 30094 int width = getWidth(); 30095 int displayHeight = rootView.getHeight(); 30096 int displayWidth = rootView.getWidth(); 30097 30098 if (height != displayHeight || width != displayWidth) { 30099 return false; 30100 } 30101 30102 getLocationInWindow(mAttachInfo.mTmpLocation); 30103 return mAttachInfo.mTmpLocation[0] == insets.getStableInsetLeft() 30104 && mAttachInfo.mTmpLocation[1] == insets.getStableInsetTop(); 30105 } 30106 30107 /** 30108 * Sets the tooltip text which will be displayed in a small popup next to the view. 30109 * <p> 30110 * The tooltip will be displayed: 30111 * <ul> 30112 * <li>On long click, unless it is handled otherwise (by OnLongClickListener or a context 30113 * menu). </li> 30114 * <li>On hover, after a brief delay since the pointer has stopped moving </li> 30115 * </ul> 30116 * <p> 30117 * <strong>Note:</strong> Do not override this method, as it will have no 30118 * effect on the text displayed in the tooltip. 30119 * 30120 * @param tooltipText the tooltip text, or null if no tooltip is required 30121 * @see #getTooltipText() 30122 * @attr ref android.R.styleable#View_tooltipText 30123 */ setTooltipText(@ullable CharSequence tooltipText)30124 public void setTooltipText(@Nullable CharSequence tooltipText) { 30125 if (TextUtils.isEmpty(tooltipText)) { 30126 setFlags(0, TOOLTIP); 30127 hideTooltip(); 30128 mTooltipInfo = null; 30129 } else { 30130 setFlags(TOOLTIP, TOOLTIP); 30131 if (mTooltipInfo == null) { 30132 mTooltipInfo = new TooltipInfo(); 30133 mTooltipInfo.mShowTooltipRunnable = this::showHoverTooltip; 30134 mTooltipInfo.mHideTooltipRunnable = this::hideTooltip; 30135 mTooltipInfo.mHoverSlop = ViewConfiguration.get(mContext).getScaledHoverSlop(); 30136 mTooltipInfo.clearAnchorPos(); 30137 } 30138 mTooltipInfo.mTooltipText = tooltipText; 30139 } 30140 } 30141 30142 /** 30143 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 30144 */ 30145 @UnsupportedAppUsage setTooltip(@ullable CharSequence tooltipText)30146 public void setTooltip(@Nullable CharSequence tooltipText) { 30147 setTooltipText(tooltipText); 30148 } 30149 30150 /** 30151 * Returns the view's tooltip text. 30152 * 30153 * <strong>Note:</strong> Do not override this method, as it will have no 30154 * effect on the text displayed in the tooltip. You must call 30155 * {@link #setTooltipText(CharSequence)} to modify the tooltip text. 30156 * 30157 * @return the tooltip text 30158 * @see #setTooltipText(CharSequence) 30159 * @attr ref android.R.styleable#View_tooltipText 30160 */ 30161 @InspectableProperty 30162 @Nullable getTooltipText()30163 public CharSequence getTooltipText() { 30164 return mTooltipInfo != null ? mTooltipInfo.mTooltipText : null; 30165 } 30166 30167 /** 30168 * @hide Binary compatibility stub. To be removed when we finalize O APIs. 30169 */ 30170 @Nullable getTooltip()30171 public CharSequence getTooltip() { 30172 return getTooltipText(); 30173 } 30174 showTooltip(int x, int y, boolean fromLongClick)30175 private boolean showTooltip(int x, int y, boolean fromLongClick) { 30176 if (mAttachInfo == null || mTooltipInfo == null) { 30177 return false; 30178 } 30179 if (fromLongClick && (mViewFlags & ENABLED_MASK) != ENABLED) { 30180 return false; 30181 } 30182 if (TextUtils.isEmpty(mTooltipInfo.mTooltipText)) { 30183 return false; 30184 } 30185 hideTooltip(); 30186 mTooltipInfo.mTooltipFromLongClick = fromLongClick; 30187 mTooltipInfo.mTooltipPopup = new TooltipPopup(getContext()); 30188 final boolean fromTouch = (mPrivateFlags3 & PFLAG3_FINGER_DOWN) == PFLAG3_FINGER_DOWN; 30189 mTooltipInfo.mTooltipPopup.show(this, x, y, fromTouch, mTooltipInfo.mTooltipText); 30190 mAttachInfo.mTooltipHost = this; 30191 // The available accessibility actions have changed 30192 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 30193 return true; 30194 } 30195 30196 @UnsupportedAppUsage hideTooltip()30197 void hideTooltip() { 30198 if (mTooltipInfo == null) { 30199 return; 30200 } 30201 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 30202 if (mTooltipInfo.mTooltipPopup == null) { 30203 return; 30204 } 30205 mTooltipInfo.mTooltipPopup.hide(); 30206 mTooltipInfo.mTooltipPopup = null; 30207 mTooltipInfo.mTooltipFromLongClick = false; 30208 mTooltipInfo.clearAnchorPos(); 30209 if (mAttachInfo != null) { 30210 mAttachInfo.mTooltipHost = null; 30211 } 30212 // The available accessibility actions have changed 30213 notifyViewAccessibilityStateChangedIfNeeded(CONTENT_CHANGE_TYPE_UNDEFINED); 30214 } 30215 showLongClickTooltip(int x, int y)30216 private boolean showLongClickTooltip(int x, int y) { 30217 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 30218 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 30219 return showTooltip(x, y, true); 30220 } 30221 showHoverTooltip()30222 private boolean showHoverTooltip() { 30223 return showTooltip(mTooltipInfo.mAnchorX, mTooltipInfo.mAnchorY, false); 30224 } 30225 dispatchTooltipHoverEvent(MotionEvent event)30226 boolean dispatchTooltipHoverEvent(MotionEvent event) { 30227 if (mTooltipInfo == null) { 30228 return false; 30229 } 30230 switch(event.getAction()) { 30231 case MotionEvent.ACTION_HOVER_MOVE: 30232 if ((mViewFlags & TOOLTIP) != TOOLTIP) { 30233 break; 30234 } 30235 if (!mTooltipInfo.mTooltipFromLongClick && mTooltipInfo.updateAnchorPos(event)) { 30236 if (mTooltipInfo.mTooltipPopup == null) { 30237 // Schedule showing the tooltip after a timeout. 30238 removeCallbacks(mTooltipInfo.mShowTooltipRunnable); 30239 postDelayed(mTooltipInfo.mShowTooltipRunnable, 30240 ViewConfiguration.getHoverTooltipShowTimeout()); 30241 } 30242 30243 // Hide hover-triggered tooltip after a period of inactivity. 30244 // Match the timeout used by NativeInputManager to hide the mouse pointer 30245 // (depends on SYSTEM_UI_FLAG_LOW_PROFILE being set). 30246 final int timeout; 30247 if ((getWindowSystemUiVisibility() & SYSTEM_UI_FLAG_LOW_PROFILE) 30248 == SYSTEM_UI_FLAG_LOW_PROFILE) { 30249 timeout = ViewConfiguration.getHoverTooltipHideShortTimeout(); 30250 } else { 30251 timeout = ViewConfiguration.getHoverTooltipHideTimeout(); 30252 } 30253 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 30254 postDelayed(mTooltipInfo.mHideTooltipRunnable, timeout); 30255 } 30256 return true; 30257 30258 case MotionEvent.ACTION_HOVER_EXIT: 30259 mTooltipInfo.clearAnchorPos(); 30260 if (!mTooltipInfo.mTooltipFromLongClick) { 30261 hideTooltip(); 30262 } 30263 break; 30264 } 30265 return false; 30266 } 30267 handleTooltipKey(KeyEvent event)30268 void handleTooltipKey(KeyEvent event) { 30269 switch (event.getAction()) { 30270 case KeyEvent.ACTION_DOWN: 30271 if (event.getRepeatCount() == 0) { 30272 hideTooltip(); 30273 } 30274 break; 30275 30276 case KeyEvent.ACTION_UP: 30277 handleTooltipUp(); 30278 break; 30279 } 30280 } 30281 handleTooltipUp()30282 private void handleTooltipUp() { 30283 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 30284 return; 30285 } 30286 removeCallbacks(mTooltipInfo.mHideTooltipRunnable); 30287 postDelayed(mTooltipInfo.mHideTooltipRunnable, 30288 ViewConfiguration.getLongPressTooltipHideTimeout()); 30289 } 30290 getFocusableAttribute(TypedArray attributes)30291 private int getFocusableAttribute(TypedArray attributes) { 30292 TypedValue val = new TypedValue(); 30293 if (attributes.getValue(com.android.internal.R.styleable.View_focusable, val)) { 30294 if (val.type == TypedValue.TYPE_INT_BOOLEAN) { 30295 return (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE); 30296 } else { 30297 return val.data; 30298 } 30299 } else { 30300 return FOCUSABLE_AUTO; 30301 } 30302 } 30303 30304 /** 30305 * @return The content view of the tooltip popup currently being shown, or null if the tooltip 30306 * is not showing. 30307 * @hide 30308 */ 30309 @TestApi getTooltipView()30310 public View getTooltipView() { 30311 if (mTooltipInfo == null || mTooltipInfo.mTooltipPopup == null) { 30312 return null; 30313 } 30314 return mTooltipInfo.mTooltipPopup.getContentView(); 30315 } 30316 30317 /** 30318 * @return {@code true} if the default focus highlight is enabled, {@code false} otherwies. 30319 * @hide 30320 */ 30321 @TestApi isDefaultFocusHighlightEnabled()30322 public static boolean isDefaultFocusHighlightEnabled() { 30323 return sUseDefaultFocusHighlight; 30324 } 30325 30326 /** 30327 * Dispatch a previously unhandled {@link KeyEvent} to this view. Unlike normal key dispatch, 30328 * this dispatches to ALL child views until it is consumed. The dispatch order is z-order 30329 * (visually on-top views first). 30330 * 30331 * @param evt the previously unhandled {@link KeyEvent}. 30332 * @return the {@link View} which consumed the event or {@code null} if not consumed. 30333 */ dispatchUnhandledKeyEvent(KeyEvent evt)30334 View dispatchUnhandledKeyEvent(KeyEvent evt) { 30335 if (onUnhandledKeyEvent(evt)) { 30336 return this; 30337 } 30338 return null; 30339 } 30340 30341 /** 30342 * Allows this view to handle {@link KeyEvent}s which weren't handled by normal dispatch. This 30343 * occurs after the normal view hierarchy dispatch, but before the window callback. By default, 30344 * this will dispatch into all the listeners registered via 30345 * {@link #addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener)} in last-in-first-out 30346 * order (most recently added will receive events first). 30347 * 30348 * @param event An unhandled event. 30349 * @return {@code true} if the event was handled, {@code false} otherwise. 30350 * @see #addOnUnhandledKeyEventListener 30351 */ onUnhandledKeyEvent(@onNull KeyEvent event)30352 boolean onUnhandledKeyEvent(@NonNull KeyEvent event) { 30353 if (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null) { 30354 for (int i = mListenerInfo.mUnhandledKeyListeners.size() - 1; i >= 0; --i) { 30355 if (mListenerInfo.mUnhandledKeyListeners.get(i).onUnhandledKeyEvent(this, event)) { 30356 return true; 30357 } 30358 } 30359 } 30360 return false; 30361 } 30362 hasUnhandledKeyListener()30363 boolean hasUnhandledKeyListener() { 30364 return (mListenerInfo != null && mListenerInfo.mUnhandledKeyListeners != null 30365 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()); 30366 } 30367 30368 /** 30369 * Adds a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 30370 * UI thread. 30371 * 30372 * @param listener a receiver of unhandled {@link KeyEvent}s. 30373 * @see #removeOnUnhandledKeyEventListener 30374 */ addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)30375 public void addOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 30376 ArrayList<OnUnhandledKeyEventListener> listeners = getListenerInfo().mUnhandledKeyListeners; 30377 if (listeners == null) { 30378 listeners = new ArrayList<>(); 30379 getListenerInfo().mUnhandledKeyListeners = listeners; 30380 } 30381 listeners.add(listener); 30382 if (listeners.size() == 1 && mParent instanceof ViewGroup) { 30383 ((ViewGroup) mParent).incrementChildUnhandledKeyListeners(); 30384 } 30385 } 30386 30387 /** 30388 * Removes a listener which will receive unhandled {@link KeyEvent}s. This must be called on the 30389 * UI thread. 30390 * 30391 * @param listener a receiver of unhandled {@link KeyEvent}s. 30392 * @see #addOnUnhandledKeyEventListener 30393 */ removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener)30394 public void removeOnUnhandledKeyEventListener(OnUnhandledKeyEventListener listener) { 30395 if (mListenerInfo != null) { 30396 if (mListenerInfo.mUnhandledKeyListeners != null 30397 && !mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 30398 mListenerInfo.mUnhandledKeyListeners.remove(listener); 30399 if (mListenerInfo.mUnhandledKeyListeners.isEmpty()) { 30400 mListenerInfo.mUnhandledKeyListeners = null; 30401 if (mParent instanceof ViewGroup) { 30402 ((ViewGroup) mParent).decrementChildUnhandledKeyListeners(); 30403 } 30404 } 30405 } 30406 } 30407 } 30408 } 30409